From 68e71a85eb1a7e3af7030834715449b6f9e3d474 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 14 Aug 2024 13:16:31 -0400 Subject: [PATCH 01/97] bare minimum wasm sqlite backend (#905) Functions Ported Co-authored-by: Ry Racherbaumer --- Cargo.toml | 3 +- diesel-wasm-sqlite/.gitignore | 8 + diesel-wasm-sqlite/.vscode/settings.json | 32 + diesel-wasm-sqlite/.yarnrc.yml | 7 + diesel-wasm-sqlite/Cargo.lock | 698 ++++ diesel-wasm-sqlite/Cargo.toml | 41 + diesel-wasm-sqlite/README.md | 25 + diesel-wasm-sqlite/build.rs | 17 + diesel-wasm-sqlite/package-lock.json | 756 ++++ diesel-wasm-sqlite/package.js | 355 ++ diesel-wasm-sqlite/package.json | 23 + diesel-wasm-sqlite/rollup.config.js | 18 + diesel-wasm-sqlite/src/backend.rs | 88 + .../src/connection/bind_collector.rs | 258 ++ .../connection/diesel_manage_updated_at.sql | 11 + .../src/connection/functions.rs | 239 ++ diesel-wasm-sqlite/src/connection/mod.rs | 292 ++ .../src/connection/owned_row.rs | 94 + diesel-wasm-sqlite/src/connection/raw.rs | 203 ++ diesel-wasm-sqlite/src/connection/row.rs | 412 +++ .../src/connection/serialized_database.rs | 42 + .../src/connection/sqlite_value.rs | 159 + .../src/connection/statement_iterator.rs | 172 + diesel-wasm-sqlite/src/connection/stmt.rs | 422 +++ diesel-wasm-sqlite/src/ffi.rs | 220 ++ diesel-wasm-sqlite/src/lib.rs | 59 + .../src/query_builder/limit_offset.rs | 127 + diesel-wasm-sqlite/src/query_builder/mod.rs | 44 + .../src/query_builder/query_fragment_impls.rs | 42 + .../src/query_builder/returning.rs | 16 + diesel-wasm-sqlite/src/sqlite_types.rs | 105 + diesel-wasm-sqlite/src/utils.rs | 10 + .../src/wa-sqlite-diesel-bundle.js | 3050 +++++++++++++++++ diesel-wasm-sqlite/tests/web.rs | 61 + diesel-wasm-sqlite/yarn.lock | 1640 +++++++++ 35 files changed, 9748 insertions(+), 1 deletion(-) create mode 100644 diesel-wasm-sqlite/.gitignore create mode 100644 diesel-wasm-sqlite/.vscode/settings.json create mode 100644 diesel-wasm-sqlite/.yarnrc.yml create mode 100644 diesel-wasm-sqlite/Cargo.lock create mode 100644 diesel-wasm-sqlite/Cargo.toml create mode 100644 diesel-wasm-sqlite/README.md create mode 100644 diesel-wasm-sqlite/build.rs create mode 100644 diesel-wasm-sqlite/package-lock.json create mode 100644 diesel-wasm-sqlite/package.js create mode 100644 diesel-wasm-sqlite/package.json create mode 100644 diesel-wasm-sqlite/rollup.config.js create mode 100644 diesel-wasm-sqlite/src/backend.rs create mode 100644 diesel-wasm-sqlite/src/connection/bind_collector.rs create mode 100644 diesel-wasm-sqlite/src/connection/diesel_manage_updated_at.sql create mode 100644 diesel-wasm-sqlite/src/connection/functions.rs create mode 100644 diesel-wasm-sqlite/src/connection/mod.rs create mode 100644 diesel-wasm-sqlite/src/connection/owned_row.rs create mode 100644 diesel-wasm-sqlite/src/connection/raw.rs create mode 100644 diesel-wasm-sqlite/src/connection/row.rs create mode 100644 diesel-wasm-sqlite/src/connection/serialized_database.rs create mode 100644 diesel-wasm-sqlite/src/connection/sqlite_value.rs create mode 100644 diesel-wasm-sqlite/src/connection/statement_iterator.rs create mode 100644 diesel-wasm-sqlite/src/connection/stmt.rs create mode 100644 diesel-wasm-sqlite/src/ffi.rs create mode 100755 diesel-wasm-sqlite/src/lib.rs create mode 100644 diesel-wasm-sqlite/src/query_builder/limit_offset.rs create mode 100644 diesel-wasm-sqlite/src/query_builder/mod.rs create mode 100644 diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs create mode 100644 diesel-wasm-sqlite/src/query_builder/returning.rs create mode 100644 diesel-wasm-sqlite/src/sqlite_types.rs create mode 100644 diesel-wasm-sqlite/src/utils.rs create mode 100644 diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js create mode 100755 diesel-wasm-sqlite/tests/web.rs create mode 100644 diesel-wasm-sqlite/yarn.lock diff --git a/Cargo.toml b/Cargo.toml index 9ad24599a..d37ec4bd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ members = [ "xmtp_user_preferences", "xmtp_v2", "xmtp_mls", - "xmtp_id", + "xmtp_id" ] exclude = [ @@ -18,6 +18,7 @@ exclude = [ "bindings_wasm", "xmtp_api_grpc_gateway", "bindings_node", + "diesel-wasm-sqlite" ] # Make the feature resolver explicit. diff --git a/diesel-wasm-sqlite/.gitignore b/diesel-wasm-sqlite/.gitignore new file mode 100644 index 000000000..f93dc9153 --- /dev/null +++ b/diesel-wasm-sqlite/.gitignore @@ -0,0 +1,8 @@ +# yarn +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions diff --git a/diesel-wasm-sqlite/.vscode/settings.json b/diesel-wasm-sqlite/.vscode/settings.json new file mode 100644 index 000000000..cb6099b62 --- /dev/null +++ b/diesel-wasm-sqlite/.vscode/settings.json @@ -0,0 +1,32 @@ +{ + "rust-analyzer": { + "cargo": { + "sysroot": "discover", + "allTargets": false, + "target": "wasm32-unknown-unknown" + }, + "procMacro": { + "enable": true, + "attributes.enable": true, + "ignored": { + "async-trait": ["async_trait"], + "napi-derive": ["napi"], + "async-recursion": ["async_recursion"], + "ctor": ["ctor"], + "tokio": ["test"] + } + } + }, + "[toml]": { + "editor.defaultFormatter": "tamasfe.even-better-toml" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/diesel-wasm-sqlite/.yarnrc.yml b/diesel-wasm-sqlite/.yarnrc.yml new file mode 100644 index 000000000..77ffe90a8 --- /dev/null +++ b/diesel-wasm-sqlite/.yarnrc.yml @@ -0,0 +1,7 @@ +compressionLevel: mixed + +enableGlobalCache: false + +enableTelemetry: false + +nodeLinker: node-modules diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock new file mode 100644 index 000000000..aadc60362 --- /dev/null +++ b/diesel-wasm-sqlite/Cargo.lock @@ -0,0 +1,698 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" + +[[package]] +name = "cc" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "diesel" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" +dependencies = [ + "diesel_derives", +] + +[[package]] +name = "diesel-async" +version = "0.5.0" +source = "git+https://github.com/insipx/diesel_async?branch=insipx/make-stmt-cache-public#86a24a38d9d841ef9e92022cd983bbd700286397" +dependencies = [ + "async-trait", + "diesel", + "futures-util", + "scoped-futures", +] + +[[package]] +name = "diesel-wasm-sqlite" +version = "0.1.1" +dependencies = [ + "async-trait", + "bitflags", + "console_error_panic_hook", + "diesel", + "diesel-async", + "futures", + "futures-util", + "getrandom", + "log", + "rand", + "serde", + "serde-wasm-bindgen", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test", + "web-sys", +] + +[[package]] +name = "diesel_derives" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" +dependencies = [ + "diesel_table_macro_syntax", + "dsl_auto_type", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" +dependencies = [ + "syn", +] + +[[package]] +name = "dsl_auto_type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "scoped-futures" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467" +dependencies = [ + "cfg-if", + "pin-utils", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +dependencies = [ + "backtrace", + "bytes", + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml new file mode 100644 index 000000000..737e6d77d --- /dev/null +++ b/diesel-wasm-sqlite/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "diesel-wasm-sqlite" +version = "0.1.1" +edition = "2021" + +[dependencies] +# diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/wasm-backend", default-features = false, features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } +diesel = "2.2" +diesel-async = { git = "https://github.com/insipx/diesel_async", branch = "insipx/make-stmt-cache-public", features = ["stmt-cache"] } +wasm-bindgen = "0.2.92" +wasm-bindgen-futures = "0.4.42" +log = "0.4" +rand = "0.8" +getrandom = { version = "0.2", features = ["js"] } +web-sys = { version = "0.3", features = ["console"] } +# wee_alloc = { version = "0.4.2", optional = true } +console_error_panic_hook = { version = "0.1", optional = true } +tokio = { version = "1.38", default-features = false, features = ["rt", "macros", "sync", "io-util", "time"] } +futures = "0.3" +futures-util = "0.3" +async-trait = "0.1" +bitflags = "2.6" +serde = { version = "1.0", features = ["derive"] } +serde-wasm-bindgen = "0.6" + +[dev-dependencies] +rand = "0.8" +getrandom = { version = "0.2", features = ["js"] } +wasm-bindgen-test = "0.3.42" +web-sys = { version = "0.3", features = ["console"] } + + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["console_error_panic_hook"] + +[build] +target = "wasm32-unknown-unknown" + diff --git a/diesel-wasm-sqlite/README.md b/diesel-wasm-sqlite/README.md new file mode 100644 index 000000000..77b146779 --- /dev/null +++ b/diesel-wasm-sqlite/README.md @@ -0,0 +1,25 @@ +# Custom Diesel Backend for Wasm wa-sqlite + +#### Bundle the javascript in `package.js` to rust + +`yarn run build` + +#### Build the JS WASM interface + +`wasm-pack build` + +#### Run the Wasm Tests + +wasm-pack test --chrome --headless + +# TODO + +- [ ] wa-sqlite should be included in `pkg` build w/o manual copy (wasm-pack + issue?) +- [ ] OPFS + +# Notes + +- rust-analyzer doesn't like crates with different targets in the same + workspace. If you want this to work well with your LSP, open + `diesel-wasm-sqlite` as it's own project. diff --git a/diesel-wasm-sqlite/build.rs b/diesel-wasm-sqlite/build.rs new file mode 100644 index 000000000..01bfc1044 --- /dev/null +++ b/diesel-wasm-sqlite/build.rs @@ -0,0 +1,17 @@ +use std::env; +use std::process::Command; + +fn main() { + println!("cargo::rerun-if-changed=package.js"); + + Command::new("yarn") + .args(["run", "build"]) + .status() + .unwrap(); + + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if target_arch != "wasm32" { + // Emit a compile error if the target is not wasm32-unknown-unknown + panic!("This crate only supports the wasm32 architecture"); + } +} diff --git a/diesel-wasm-sqlite/package-lock.json b/diesel-wasm-sqlite/package-lock.json new file mode 100644 index 000000000..e92a88e09 --- /dev/null +++ b/diesel-wasm-sqlite/package-lock.json @@ -0,0 +1,756 @@ +{ + "name": "diesel-wasm-sqlite", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "diesel-wasm-sqlite", + "version": "1.0.0", + "dependencies": { + "@xmtp/wa-sqlite": "^1.0.1" + }, + "devDependencies": { + "@rollup/plugin-node-resolve": "^15.2.3", + "rollup": "^4.19.0", + "rollup-plugin-base64": "^1.0.1", + "rollup-plugin-copy": "^3.5.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.19.0", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "8.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.14.11", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@xmtp/wa-sqlite": { + "version": "1.0.1" + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/colorette": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "10.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/globby/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "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/resolve": { + "version": "1.22.8", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.19.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.19.0", + "@rollup/rollup-android-arm64": "4.19.0", + "@rollup/rollup-darwin-arm64": "4.19.0", + "@rollup/rollup-darwin-x64": "4.19.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.19.0", + "@rollup/rollup-linux-arm-musleabihf": "4.19.0", + "@rollup/rollup-linux-arm64-gnu": "4.19.0", + "@rollup/rollup-linux-arm64-musl": "4.19.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.19.0", + "@rollup/rollup-linux-riscv64-gnu": "4.19.0", + "@rollup/rollup-linux-s390x-gnu": "4.19.0", + "@rollup/rollup-linux-x64-gnu": "4.19.0", + "@rollup/rollup-linux-x64-musl": "4.19.0", + "@rollup/rollup-win32-arm64-msvc": "4.19.0", + "@rollup/rollup-win32-ia32-msvc": "4.19.0", + "@rollup/rollup-win32-x64-msvc": "4.19.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-base64/-/rollup-plugin-base64-1.0.1.tgz", + "integrity": "sha512-IbdX8fjuXO/Op3hYmRPjVo0VwcSenwsQDaDTFdoe+70B5ZGoLMtr96L2yhHXCfxv7HwZVvxZqLsuWj6VwzRt3g==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0" + } + }, + "node_modules/rollup-plugin-base64/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/rollup-plugin-base64/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/rollup-plugin-base64/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "node_modules/rollup-plugin-base64/node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "peer": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-copy": { + "version": "3.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "engines": { + "node": ">=8.3" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "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": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + } + } +} diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js new file mode 100644 index 000000000..9b4459237 --- /dev/null +++ b/diesel-wasm-sqlite/package.js @@ -0,0 +1,355 @@ +import * as WasmSQLiteLibrary from "@xmtp/wa-sqlite"; +import { OPFSCoopSyncVFS } from "@xmtp/wa-sqlite/vfs/OPFSCoopSync"; +import SQLiteESMFactory from "./node_modules/@xmtp/wa-sqlite/dist/wa-sqlite.mjs"; +import base64Wasm from "./node_modules/@xmtp/wa-sqlite/dist/wa-sqlite.wasm"; + +function base64Decode(str) { + const binaryString = typeof atob === "function" + ? atob(str) + : Buffer.from(str, "base64").toString("binary"); + const len = binaryString.length; + const bytes = new Uint8Array(len); + for (let i = 0; i < len; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + return bytes.buffer; +} + +export class SQLite { + #module; + #sqlite3; + constructor(module) { + if (typeof module === "undefined") { + throw new Error("Cannot be called directly"); + } + this.module = module; + this.sqlite3 = WasmSQLiteLibrary.Factory(module); + } + + static async wasm_module() { + return await SQLiteESMFactory({ + "wasmBinary": base64Decode(base64Wasm), + }); + } + + static async build() { + const module = await SQLiteESMFactory({ + "wasmBinary": base64Decode(base64Wasm), + }); + return new WasmSQLiteLibrary(module); + } + + result_text(context, value) { + this.sqlite3.result_text(context, value); + } + + result_int(context, value) { + this.sqlite3.result_int(context, value); + } + + result_int64(context, value) { + this.sqlite3.result_int64(context, value); + } + + result_double(context, value) { + this.sqlite3.result_double(context, value); + } + + result_blob(context, value) { + this.sqlite3.result_blob(context, value); + } + + result_null(context) { + this.sqlite3.result_null(context); + } + + bind(stmt, i, value) { + try { + return this.sqlite3.bind(stmt, i, value); + } catch (error) { + console.log("bind err"); + throw error; + } + } + + bind_blob(stmt, i, value) { + try { + return this.sqlite3.bind_blob(stmt, i, value); + } catch (error) { + console.log("bind blob error"); + throw error; + } + } + + bind_collection(stmt, bindings) { + try { + return this.sqlite3.bind_collection(stmt, bindings); + } catch (error) { + console.log("bind collection error"); + throw error; + } + } + + bind_double(stmt, i, value) { + try { + return this.sqlite3.bind_double(stmt, i, value); + } catch (error) { + console.log("bind double error"); + throw error; + } + } + + bind_int(stmt, i, value) { + try { + return this.sqlite3.bind_int(stmt, i, value); + } catch (error) { + console.log("bind int error"); + throw error; + } + } + + bind_int64(stmt, i, value) { + try { + return this.sqlite3.bind_int64(stmt, i, value); + } catch (error) { + console.log("bind int644 error"); + throw error; + } + } + + bind_null(stmt, i) { + try { + return this.sqlite3.bind_null(stmt, i); + } catch (error) { + console.log("bind null error"); + throw error; + } + } + + bind_parameter_count(stmt) { + return this.sqlite3.bind_parameter_count(stmt); + } + + bind_parameter_name(stmt, i) { + return this.sqlite3.bind_paramater_name(stmt, it); + } + + bind_text(stmt, i, value) { + try { + this.sqlite3.bind_text(stmt, i, value); + } catch (error) { + console.log("bind text error"); + throw error; + } + } + + async reset(stmt) { + try { + return await this.sqlite3.reset(stmt); + } catch (error) { + console.log("reset err"); + throw error; + } + } + + value(pValue) { + this.sqlite3.value(pValue); + } + + value_dup(pValue) { + return this.module._sqlite3_value_dup(pValue); + } + + value_blob(pValue) { + this.sqlite3.value_blob(pValue); + } + + value_bytes(pValue) { + this.sqlite3.value_bytes(pValue); + } + + value_double(pValue) { + this.sqlite3.value_double(pValue); + } + + value_int(pValue) { + this.sqlite3.value_int(pValue); + } + + value_int64(pValue) { + this.sqlite3.value_int64(pValue); + } + + value_text(pValue) { + this.sqlite3.value_text(pValue); + } + + value_type(pValue) { + this.sqlite3.value_type(pValue); + } + + async open_v2(database_url, iflags) { + try { + console.log("Opening database!", database_url); + const vfs = await OPFSCoopSyncVFS.create(database_url, this.module); + this.sqlite3.vfs_register(vfs, true); + let db = await this.sqlite3.open_v2(database_url, iflags); + return db; + } catch (error) { + console.log("openv2 error", error); + throw error; + } + } + + async exec(db, query) { + try { + return await this.sqlite3.exec(db, query, (row, columns) => { + console.log(row); + }); + } catch (error) { + console.log("exec err"); + throw error; + } + } + + finalize(stmt) { + try { + return this.sqlite3.finalize(stmt); + } catch (error) { + console.log("stmt error"); + throw error; + } + } + + changes(db) { + return this.sqlite3.changes(db); + } + + clear_bindings(stmt) { + return this.sqlite3.clear_bindings(stmt); + } + + async close(db) { + try { + return this.sqlite3.close(db); + } catch (error) { + console.log("sqlite3.close error"); + throw error; + } + } + + column(stmt, i) { + return this.sqlite3.column(stmt, i); + } + + async prepare(database, sql, options) { + try { + return await this.sqlite3.statements(database, sql, options); + } catch (error) { + console.log("sqlite prepare error"); + throw error; + } + } + + async step(stmt) { + try { + return await this.sqlite3.step(stmt); + } catch (error) { + console.log("sqlite step error"); + throw error; + } + } + + column_name(stmt, idx) { + return this.sqlite3.column_name(stmt, idx); + } + + column_count(stmt) { + return this.sqlite3.column_count(stmt); + } + + batch_execute(database, query) { + try { + return this.sqlite3.exec(database, query); + console.log("Batch exec'ed"); + } catch (error) { + console.log("exec err"); + throw error; + } + } + + create_function( + database, + functionName, + nArg, + textRep, + pApp, + xFunc, + xStep, + xFinal, + ) { + try { + this.sqlite3.create_function( + database, + functionName, + nArg, + textRep, + pApp, // pApp is ignored + xFunc, + xStep, + xFinal, + ); + console.log("create function"); + } catch (error) { + console.log("create function err"); + throw error; + } + } + //TODO: At some point need a way to register functions from rust + //but for just libxmtp this is fine. + register_diesel_sql_functions(database) { + try { + this.sqlite3.create_function( + database, + "diesel_manage_updated_at", + 1, + WasmSQLiteLibrary.SQLITE_UTF8, + 0, + (context, values) => { + const table_name = this.sqlite3.value_text(values[0]); + + await this.sqlite3.exec( + context, + `CREATE TRIGGER __diesel_manage_updated_at_${table_name} + AFTER UPDATE ON ${table_name} + FOR EACH ROW WHEN + old.updated_at IS NULL AND + new.updated_at IS NULL OR + old.updated_at == new.updated_at + BEGIN + UPDATE ${table_name} + SET updated_at = CURRENT_TIMESTAMP + WHERE ROWID = new.ROWID; + END`, + (row, columns) => { + console.log(`------------------------------------`); + console.log(`Created trigger for ${table_name}`); + console.log(row); + console.log(columns); + console.log(`------------------------------------`); + }, + ); + }, + ); + } catch (error) { + console.log("error creating diesel trigger"); + throw error; + } + } + + /* + serialize(database, zSchema, size, flags) { + return this.module._sqlite3_serialize(database, zSchema, size, flags); + } + */ +} diff --git a/diesel-wasm-sqlite/package.json b/diesel-wasm-sqlite/package.json new file mode 100644 index 000000000..6f529c83e --- /dev/null +++ b/diesel-wasm-sqlite/package.json @@ -0,0 +1,23 @@ +{ + "name": "diesel-wasm-sqlite", + "type": "module", + "version": "1.0.0", + "description": "", + "main": "package.js", + "scripts": { + "build": "rollup -c" + }, + "dependencies": { + "@xmtp/wa-sqlite": "^1.0.1" + }, + "packageManager": "yarn@4.3.1", + "engines": { + "node": ">=20" + }, + "devDependencies": { + "@rollup/plugin-node-resolve": "^15.2.3", + "rollup": "^4.19.0", + "rollup-plugin-base64": "^1.0.1", + "rollup-plugin-copy": "^3.5.0" + } +} diff --git a/diesel-wasm-sqlite/rollup.config.js b/diesel-wasm-sqlite/rollup.config.js new file mode 100644 index 000000000..881eeadf5 --- /dev/null +++ b/diesel-wasm-sqlite/rollup.config.js @@ -0,0 +1,18 @@ +import { defineConfig } from "rollup"; +import resolve from "@rollup/plugin-node-resolve"; +import { base64 } from "rollup-plugin-base64"; + +export default defineConfig([ + { + input: "package.js", + output: { + file: "src/wa-sqlite-diesel-bundle.js", + format: "es", + }, + plugins: [ + resolve(), + base64({ include: "**/*.wasm" }), + ], + // external: ["@xmtp/wa-sqlite", "@xmtp/wa-sqlite/build"], + }, +]); diff --git a/diesel-wasm-sqlite/src/backend.rs b/diesel-wasm-sqlite/src/backend.rs new file mode 100644 index 000000000..4891c37e0 --- /dev/null +++ b/diesel-wasm-sqlite/src/backend.rs @@ -0,0 +1,88 @@ +//! The SQLite backend + +use super::connection::SqliteBindCollector; +use super::connection::SqliteValue; +use super::query_builder::SqliteQueryBuilder; +use diesel::backend::*; +use diesel::sql_types::TypeMetadata; + +/// The SQLite backend +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)] +pub struct WasmSqlite; + +/// Determines how a bind parameter is given to SQLite +/// +/// Diesel deals with bind parameters after serialization as opaque blobs of +/// bytes. However, SQLite instead has several functions where it expects the +/// relevant C types. +/// +/// The variants of this struct determine what bytes are expected from +/// `ToSql` impls. +#[allow(missing_debug_implementations)] +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +pub enum SqliteType { + /// Bind using `sqlite3_bind_blob` + Binary, + /// Bind using `sqlite3_bind_text` + Text, + /// `bytes` should contain an `f32` + Float, + /// `bytes` should contain an `f64` + Double, + /// `bytes` should contain an `i16` + SmallInt, + /// `bytes` should contain an `i32` + Integer, + /// `bytes` should contain an `i64` + Long, +} + +impl Backend for WasmSqlite { + type QueryBuilder = SqliteQueryBuilder; + type RawValue<'a> = SqliteValue<'a, 'a, 'a>; + type BindCollector<'a> = SqliteBindCollector<'a>; +} + +impl TypeMetadata for WasmSqlite { + type TypeMetadata = SqliteType; + type MetadataLookup = (); +} + +impl SqlDialect for WasmSqlite { + #[cfg(not(feature = "returning_clauses_for_sqlite_3_35"))] + type ReturningClause = sql_dialect::returning_clause::DoesNotSupportReturningClause; + #[cfg(feature = "returning_clauses_for_sqlite_3_35")] + type ReturningClause = SqliteReturningClause; + + type OnConflictClause = SqliteOnConflictClause; + + type InsertWithDefaultKeyword = + sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword; + type BatchInsertSupport = SqliteBatchInsert; + type ConcatClause = sql_dialect::concat_clause::ConcatWithPipesClause; + type DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause; + + type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax; + type SelectStatementSyntax = sql_dialect::select_statement_syntax::AnsiSqlSelectStatement; + + type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax; + type ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison; + type AliasSyntax = sql_dialect::alias_syntax::AsAliasSyntax; +} + +impl DieselReserveSpecialization for WasmSqlite {} +impl TrustedBackend for WasmSqlite {} + +#[derive(Debug, Copy, Clone)] +pub struct SqliteOnConflictClause; + +impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for SqliteOnConflictClause {} +impl sql_dialect::on_conflict_clause::PgLikeOnConflictClause for SqliteOnConflictClause {} + +#[derive(Debug, Copy, Clone)] +pub struct SqliteBatchInsert; + +#[derive(Debug, Copy, Clone)] +pub struct SqliteReturningClause; + +impl sql_dialect::returning_clause::SupportsReturningClause for SqliteReturningClause {} diff --git a/diesel-wasm-sqlite/src/connection/bind_collector.rs b/diesel-wasm-sqlite/src/connection/bind_collector.rs new file mode 100644 index 000000000..6eef85140 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/bind_collector.rs @@ -0,0 +1,258 @@ +use crate::{SqliteType, WasmSqlite}; +use diesel::{ + query_builder::{BindCollector, MoveableBindCollector}, + result::QueryResult, + serialize::{IsNull, Output}, + sql_types::HasSqlType, +}; +use serde::{Deserialize, Serialize}; +use wasm_bindgen::JsValue; + +// TODO:insipx this file remains largely unchanged other than the ffi::. Candidate for shared code? + +pub type BindValue = JsValue; + +#[derive(Debug, Default)] +pub struct SqliteBindCollector<'a> { + pub(crate) binds: Vec<(InternalSqliteBindValue<'a>, SqliteType)>, +} + +impl SqliteBindCollector<'_> { + pub(crate) fn new() -> Self { + Self { binds: Vec::new() } + } +} + +/// This type represents a value bound to +/// a sqlite prepared statement +/// +/// It can be constructed via the various `From` implementations +#[derive(Debug)] +pub struct SqliteBindValue<'a> { + pub(crate) inner: InternalSqliteBindValue<'a>, +} + +impl<'a> From for SqliteBindValue<'a> { + fn from(i: i32) -> Self { + Self { + inner: InternalSqliteBindValue::I32(i), + } + } +} + +impl<'a> From for SqliteBindValue<'a> { + fn from(i: i64) -> Self { + Self { + inner: InternalSqliteBindValue::I64(i), + } + } +} + +impl<'a> From for SqliteBindValue<'a> { + fn from(f: f64) -> Self { + Self { + inner: InternalSqliteBindValue::F64(f), + } + } +} + +impl<'a, T> From> for SqliteBindValue<'a> +where + T: Into>, +{ + fn from(o: Option) -> Self { + match o { + Some(v) => v.into(), + None => Self { + inner: InternalSqliteBindValue::Null, + }, + } + } +} + +impl<'a> From<&'a str> for SqliteBindValue<'a> { + fn from(s: &'a str) -> Self { + Self { + inner: InternalSqliteBindValue::BorrowedString(s), + } + } +} + +impl<'a> From for SqliteBindValue<'a> { + fn from(s: String) -> Self { + Self { + inner: InternalSqliteBindValue::String(s.into_boxed_str()), + } + } +} + +impl<'a> From> for SqliteBindValue<'a> { + fn from(b: Vec) -> Self { + Self { + inner: InternalSqliteBindValue::Binary(b.into_boxed_slice()), + } + } +} + +impl<'a> From<&'a [u8]> for SqliteBindValue<'a> { + fn from(b: &'a [u8]) -> Self { + Self { + inner: InternalSqliteBindValue::BorrowedBinary(b), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub(crate) enum InternalSqliteBindValue<'a> { + BorrowedString(&'a str), + String(Box), + BorrowedBinary(&'a [u8]), + Binary(Box<[u8]>), + I32(i32), + I64(i64), + F64(f64), + Null, +} + +impl std::fmt::Display for InternalSqliteBindValue<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let n = match self { + InternalSqliteBindValue::BorrowedString(_) | InternalSqliteBindValue::String(_) => { + "Text" + } + InternalSqliteBindValue::BorrowedBinary(_) | InternalSqliteBindValue::Binary(_) => { + "Binary" + } + InternalSqliteBindValue::I32(_) | InternalSqliteBindValue::I64(_) => "Integer", + InternalSqliteBindValue::F64(_) => "Float", + InternalSqliteBindValue::Null => "Null", + }; + f.write_str(n) + } +} + +impl InternalSqliteBindValue<'_> { + #[allow(unsafe_code)] // ffi function calls + pub(crate) fn result_of(self, ctx: &mut i32) { + let sqlite3 = crate::get_sqlite_unchecked(); + match self { + InternalSqliteBindValue::BorrowedString(s) => sqlite3.result_text(*ctx, s.to_string()), + InternalSqliteBindValue::String(s) => sqlite3.result_text(*ctx, s.to_string()), + InternalSqliteBindValue::Binary(b) => sqlite3.result_blob(*ctx, b.to_vec()), + InternalSqliteBindValue::BorrowedBinary(b) => sqlite3.result_blob(*ctx, b.to_vec()), + InternalSqliteBindValue::I32(i) => sqlite3.result_int(*ctx, i), + InternalSqliteBindValue::I64(l) => sqlite3.result_int64(*ctx, l), + InternalSqliteBindValue::F64(d) => sqlite3.result_double(*ctx, d), + InternalSqliteBindValue::Null => sqlite3.result_null(*ctx), + } + } +} + +impl<'a> BindCollector<'a, WasmSqlite> for SqliteBindCollector<'a> { + type Buffer = SqliteBindValue<'a>; + + fn push_bound_value(&mut self, bind: &'a U, metadata_lookup: &mut ()) -> QueryResult<()> + where + WasmSqlite: diesel::sql_types::HasSqlType, + U: diesel::serialize::ToSql + ?Sized, + { + let value = SqliteBindValue { + inner: InternalSqliteBindValue::Null, + }; + let mut to_sql_output = Output::new(value, metadata_lookup); + let is_null = bind + .to_sql(&mut to_sql_output) + .map_err(diesel::result::Error::SerializationError)?; + let bind = to_sql_output.into_inner(); + let metadata = WasmSqlite::metadata(metadata_lookup); + + self.binds.push(( + match is_null { + IsNull::No => bind.inner, + IsNull::Yes => InternalSqliteBindValue::Null, + }, + metadata, + )); + Ok(()) + } + + fn push_null_value(&mut self, metadata: SqliteType) -> QueryResult<()> { + self.binds.push((InternalSqliteBindValue::Null, metadata)); + Ok(()) + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +enum OwnedSqliteBindValue { + String(Box), + Binary(Box<[u8]>), + I32(i32), + I64(i64), + F64(f64), + Null, +} + +impl<'a> std::convert::From<&InternalSqliteBindValue<'a>> for OwnedSqliteBindValue { + fn from(value: &InternalSqliteBindValue<'a>) -> Self { + match value { + InternalSqliteBindValue::String(s) => Self::String(s.clone()), + InternalSqliteBindValue::BorrowedString(s) => { + Self::String(String::from(*s).into_boxed_str()) + } + InternalSqliteBindValue::Binary(b) => Self::Binary(b.clone()), + InternalSqliteBindValue::BorrowedBinary(s) => { + Self::Binary(Vec::from(*s).into_boxed_slice()) + } + InternalSqliteBindValue::I32(val) => Self::I32(*val), + InternalSqliteBindValue::I64(val) => Self::I64(*val), + InternalSqliteBindValue::F64(val) => Self::F64(*val), + InternalSqliteBindValue::Null => Self::Null, + } + } +} + +impl<'a> std::convert::From<&OwnedSqliteBindValue> for InternalSqliteBindValue<'a> { + fn from(value: &OwnedSqliteBindValue) -> Self { + match value { + OwnedSqliteBindValue::String(s) => Self::String(s.clone()), + OwnedSqliteBindValue::Binary(b) => Self::Binary(b.clone()), + OwnedSqliteBindValue::I32(val) => Self::I32(*val), + OwnedSqliteBindValue::I64(val) => Self::I64(*val), + OwnedSqliteBindValue::F64(val) => Self::F64(*val), + OwnedSqliteBindValue::Null => Self::Null, + } + } +} + +#[derive(Debug)] +/// Sqlite bind collector data that is movable across threads +pub struct SqliteBindCollectorData { + binds: Vec<(OwnedSqliteBindValue, SqliteType)>, +} + +impl MoveableBindCollector for SqliteBindCollector<'_> { + type BindData = SqliteBindCollectorData; + + fn moveable(&self) -> Self::BindData { + let mut binds = Vec::with_capacity(self.binds.len()); + for b in self + .binds + .iter() + .map(|(bind, tpe)| (OwnedSqliteBindValue::from(bind), *tpe)) + { + binds.push(b); + } + SqliteBindCollectorData { binds } + } + + fn append_bind_data(&mut self, from: &Self::BindData) { + self.binds.reserve_exact(from.binds.len()); + self.binds.extend( + from.binds + .iter() + .map(|(bind, tpe)| (InternalSqliteBindValue::from(bind), *tpe)), + ); + } +} diff --git a/diesel-wasm-sqlite/src/connection/diesel_manage_updated_at.sql b/diesel-wasm-sqlite/src/connection/diesel_manage_updated_at.sql new file mode 100644 index 000000000..83c3d33d4 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/diesel_manage_updated_at.sql @@ -0,0 +1,11 @@ +CREATE TRIGGER __diesel_manage_updated_at_{table_name} +AFTER UPDATE ON {table_name} +FOR EACH ROW WHEN + old.updated_at IS NULL AND + new.updated_at IS NULL OR + old.updated_at == new.updated_at +BEGIN + UPDATE {table_name} + SET updated_at = CURRENT_TIMESTAMP + WHERE ROWID = new.ROWID; +END diff --git a/diesel-wasm-sqlite/src/connection/functions.rs b/diesel-wasm-sqlite/src/connection/functions.rs new file mode 100644 index 000000000..b8d8f7538 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/functions.rs @@ -0,0 +1,239 @@ +use super::raw::RawConnection; +use super::row::PrivateSqliteRow; +use super::{/*SqliteAggregateFunction,*/ SqliteBindValue, WasmSqlite}; +use crate::connection::bind_collector::InternalSqliteBindValue; +use crate::connection::sqlite_value::OwnedSqliteValue; +use crate::connection::SqliteValue; +use diesel::backend::Backend; +use diesel::deserialize::{FromSqlRow, StaticallySizedRow}; +use diesel::result::{DatabaseErrorKind, Error, QueryResult}; +use diesel::row::{Field, PartialRow, Row, RowIndex, RowSealed}; +use diesel::serialize::{IsNull, Output, ToSql}; +use diesel::sql_types::HasSqlType; +use futures::future::BoxFuture; +use futures::FutureExt; +use std::cell::{Ref, RefCell}; +use std::marker::PhantomData; +use std::mem::ManuallyDrop; +use std::ops::DerefMut; +use std::rc::Rc; +use wasm_bindgen::JsValue; + +pub(super) fn register( + conn: &RawConnection, + fn_name: &str, + deterministic: bool, + mut f: F, +) -> QueryResult<()> +where + F: FnMut(&RawConnection, Args) -> BoxFuture<'static, Ret>, + Args: FromSqlRow + StaticallySizedRow, + Ret: ToSql, + WasmSqlite: HasSqlType, +{ + let fields_needed = Args::FIELD_COUNT; + if fields_needed > 127 { + return Err(Error::DatabaseError( + DatabaseErrorKind::UnableToSendCommand, + Box::new("SQLite functions cannot take more than 127 parameters".to_string()), + )); + } + + conn.register_sql_function(fn_name, fields_needed, deterministic, move |conn, args| { + async { + let args = build_sql_function_args::(args)?; + let conn = RawConnection { + internal_connection: conn, + }; + Ok(f(&conn, args).await) + } + .boxed() + })?; + Ok(()) +} + +/* +pub(super) fn register_noargs( + conn: &RawConnection, + fn_name: &str, + deterministic: bool, + mut f: F, +) -> QueryResult<()> +where + F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static, + Ret: ToSql, + WasmSqlite: HasSqlType, +{ + conn.register_sql_function(fn_name, 0, deterministic, move |_, _| Ok(f()))?; + Ok(()) +} + +pub(super) fn register_aggregate( + conn: &RawConnection, + fn_name: &str, +) -> QueryResult<()> +where + A: SqliteAggregateFunction + 'static + Send + std::panic::UnwindSafe, + Args: FromSqlRow + StaticallySizedRow, + Ret: ToSql, + WasmSqlite: HasSqlType, +{ + let fields_needed = Args::FIELD_COUNT; + if fields_needed > 127 { + return Err(Error::DatabaseError( + DatabaseErrorKind::UnableToSendCommand, + Box::new("SQLite functions cannot take more than 127 parameters".to_string()), + )); + } + + conn.register_aggregate_function::( + fn_name, + fields_needed, + )?; + + Ok(()) +} +*/ + +pub(super) fn build_sql_function_args(args: Vec) -> Result +where + Args: FromSqlRow, +{ + let row = FunctionRow::new(args); + Args::build_from_row(&row).map_err(Error::DeserializationError) +} + +// clippy is wrong here, the let binding is required +// for lifetime reasons +#[allow(clippy::let_unit_value)] +pub(super) fn process_sql_function_result( + result: &'_ Ret, +) -> QueryResult> +where + Ret: ToSql, + WasmSqlite: HasSqlType, +{ + let mut metadata_lookup = (); + let value = SqliteBindValue { + inner: InternalSqliteBindValue::Null, + }; + let mut buf = Output::new(value, &mut metadata_lookup); + let is_null = result.to_sql(&mut buf).map_err(Error::SerializationError)?; + + if let IsNull::Yes = is_null { + Ok(InternalSqliteBindValue::Null) + } else { + Ok(buf.into_inner().inner) + } +} + +struct FunctionRow<'a> { + // we use `ManuallyDrop` to prevent dropping the content of the internal vector + // as this buffer is owned by sqlite not by diesel + args: Rc>>>, + field_count: usize, + marker: PhantomData<&'a JsValue>, +} + +impl<'a> Drop for FunctionRow<'a> { + #[allow(unsafe_code)] // manual drop calls + fn drop(&mut self) { + if let Some(args) = Rc::get_mut(&mut self.args) { + if let PrivateSqliteRow::Duplicated { column_names, .. } = + DerefMut::deref_mut(RefCell::get_mut(args)) + { + if Rc::strong_count(column_names) == 1 { + // According the https://doc.rust-lang.org/std/mem/struct.ManuallyDrop.html#method.drop + // it's fine to just drop the values here + unsafe { std::ptr::drop_in_place(column_names as *mut _) } + } + } + } + } +} + +impl<'a> FunctionRow<'a> { + #[allow(unsafe_code)] // complicated ptr cast + fn new(args: Vec) -> Self { + let lengths = args.len(); + + Self { + field_count: lengths, + args: Rc::new(RefCell::new(ManuallyDrop::new( + PrivateSqliteRow::Duplicated { + values: args + .into_iter() + .map(|a| Some(OwnedSqliteValue { value: a.into() })) + .collect(), + column_names: Rc::from(vec![None; lengths]), + }, + ))), + marker: PhantomData, + } + } +} + +impl RowSealed for FunctionRow<'_> {} + +impl<'a> Row<'a, WasmSqlite> for FunctionRow<'a> { + type Field<'f> = FunctionArgument<'f> where 'a: 'f, Self: 'f; + type InnerPartialRow = Self; + + fn field_count(&self) -> usize { + self.field_count + } + + fn get<'b, I>(&'b self, idx: I) -> Option> + where + 'a: 'b, + Self: RowIndex, + { + let idx = self.idx(idx)?; + Some(FunctionArgument { + args: self.args.borrow(), + col_idx: idx as i32, + }) + } + + fn partial_row(&self, range: std::ops::Range) -> PartialRow<'_, Self::InnerPartialRow> { + PartialRow::new(self, range) + } +} + +impl<'a> RowIndex for FunctionRow<'a> { + fn idx(&self, idx: usize) -> Option { + if idx < self.field_count() { + Some(idx) + } else { + None + } + } +} + +impl<'a, 'b> RowIndex<&'a str> for FunctionRow<'b> { + fn idx(&self, _idx: &'a str) -> Option { + None + } +} + +struct FunctionArgument<'a> { + args: Ref<'a, ManuallyDrop>>, + col_idx: i32, +} + +impl<'a> Field<'a, WasmSqlite> for FunctionArgument<'a> { + fn field_name(&self) -> Option<&str> { + None + } + + fn is_null(&self) -> bool { + self.value().is_none() + } + + fn value(&self) -> Option<::RawValue<'_>> { + SqliteValue::new( + Ref::map(Ref::clone(&self.args), |drop| std::ops::Deref::deref(drop)), + self.col_idx, + ) + } +} diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs new file mode 100644 index 000000000..fac2bbe8b --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -0,0 +1,292 @@ +mod bind_collector; +// mod functions; +mod owned_row; +mod raw; +mod row; +// mod serialized_database; +mod sqlite_value; +// mod statement_iterator; +mod stmt; + +pub(crate) use self::bind_collector::SqliteBindCollector; +pub use self::bind_collector::SqliteBindValue; +pub use self::sqlite_value::SqliteValue; + // pub use self::serialized_database::SerializedDatabase; + +use self::raw::RawConnection; +// use self::statement_iterator::*; +use self::stmt::{Statement, StatementUse}; +use crate::query_builder::*; +use diesel::{connection::{statement_cache::StatementCacheKey, DefaultLoadingMode, LoadConnection}, deserialize::{FromSqlRow, StaticallySizedRow}, expression::QueryMetadata, query_builder::QueryBuilder as _, result::*, serialize::ToSql, sql_types::HasSqlType}; +use futures::{FutureExt, TryFutureExt}; +use std::sync::{Arc, Mutex}; + + +use diesel::{connection::{ConnectionSealed, Instrumentation, WithMetadataLookup}, query_builder::{AsQuery, QueryFragment, QueryId}, sql_types::TypeMetadata, QueryResult}; +pub use diesel_async::{AnsiTransactionManager, AsyncConnection, SimpleAsyncConnection, TransactionManager, stmt_cache::StmtCache}; +use futures::{future::BoxFuture, stream::BoxStream}; +use row::SqliteRow; + +use crate::{get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; + +pub struct WasmSqliteConnection { + // statement_cache needs to be before raw_connection + // otherwise we will get errors about open statements before closing the + // connection itself + statement_cache: StmtCache, + pub raw_connection: RawConnection, + transaction_state: AnsiTransactionManager, + // this exists for the sole purpose of implementing `WithMetadataLookup` trait + // and avoiding static mut which will be deprecated in 2024 edition + metadata_lookup: (), + instrumentation: Arc>>>, +} + + +// This relies on the invariant that RawConnection or Statement are never +// leaked. If a reference to one of those was held on a different thread, this +// would not be thread safe. +// Web is in one thread. Web workers can be used to hold a WasmSqliteConnection +// separately. + +#[allow(unsafe_code)] +unsafe impl Send for WasmSqliteConnection {} + + +impl ConnectionSealed for WasmSqliteConnection {} + + #[async_trait::async_trait(?Send)] +impl SimpleAsyncConnection for WasmSqliteConnection { + async fn batch_execute(&mut self, query: &str) -> diesel::prelude::QueryResult<()> { + get_sqlite_unchecked() + .batch_execute(&self.raw_connection.internal_connection, query) + .map_err(WasmSqliteError::from) + .map_err(Into::into) + } +} + +#[async_trait::async_trait(?Send)] +impl AsyncConnection for WasmSqliteConnection { + type Backend = WasmSqlite; + type TransactionManager = AnsiTransactionManager; + type ExecuteFuture<'conn, 'query> = BoxFuture<'query, QueryResult>; + type LoadFuture<'conn, 'query> = BoxFuture<'query, QueryResult>>; + type Stream<'conn, 'query> = BoxStream<'static, QueryResult>>; + type Row<'conn, 'query> = SqliteRow<'conn, 'query>; + + async fn establish(database_url: &str) -> diesel::prelude::ConnectionResult { + WasmSqliteConnection::establish_inner(database_url).await + } + + fn load<'conn, 'query, T>(&'conn mut self, _source: T) -> Self::LoadFuture<'conn, 'query> + where + T: AsQuery + 'query, + T::Query: QueryFragment + QueryId + 'query, + { + todo!() + } + + fn execute_returning_count<'conn, 'query, T>( + &'conn mut self, + _source: T, + ) -> Self::ExecuteFuture<'conn, 'query> + where + T: QueryFragment + QueryId + 'query, + { + todo!() + } + + fn transaction_state( + &mut self, + ) -> &mut >::TransactionStateData{ + todo!() + } + + fn instrumentation(&mut self) -> &mut dyn Instrumentation { + todo!() + } + + fn set_instrumentation(&mut self, _instrumentation: impl Instrumentation) { + todo!() + } +} + +/* +impl LoadConnection for WasmSqliteConnection { + type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>; + type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>; + + fn load<'conn, 'query, T>( + &'conn mut self, + source: T, + ) -> QueryResult> + where + T: Query + QueryFragment + QueryId + 'query, + Self::Backend: QueryMetadata, + { + let statement = self.prepared_query(source)?; + + Ok(StatementIterator::new(statement)) + } +} +*/ +/* +impl WithMetadataLookup for WasmSqliteConnection { + fn metadata_lookup(&mut self) -> &mut ::MetadataLookup { + &mut self.metadata_lookup + } +} + */ + +#[cfg(feature = "r2d2")] +impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection { + fn ping(&mut self) -> QueryResult<()> { + use crate::RunQueryDsl; + + crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ()) + } + + fn is_broken(&mut self) -> bool { + AnsiTransactionManager::is_broken_transaction_manager(self) + } +} + /* +impl MultiConnectionHelper for SqliteConnection { + fn to_any<'a>( + lookup: &mut ::MetadataLookup, + ) -> &mut (dyn std::any::Any + 'a) { + lookup + } + + fn from_any( + lookup: &mut dyn std::any::Any, + ) -> Option<&mut ::MetadataLookup> { + lookup.downcast_mut() + } +} +*/ + +impl WasmSqliteConnection { + /// Run a transaction with `BEGIN IMMEDIATE` + /// + /// This method will return an error if a transaction is already open. + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # run_test().unwrap(); + /// # } + /// # + /// # fn run_test() -> QueryResult<()> { + /// # let mut conn = SqliteConnection::establish(":memory:").unwrap(); + /// conn.immediate_transaction(|conn| { + /// // Do stuff in a transaction + /// Ok(()) + /// }) + /// # } + /// ``` + pub async fn immediate_transaction(&mut self, f: F) -> Result + where + F: FnOnce(&mut Self) -> Result, + E: From, + { + self.transaction_sql(f, "BEGIN IMMEDIATE").await + } + + /// Run a transaction with `BEGIN EXCLUSIVE` + /// + /// This method will return an error if a transaction is already open. + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # run_test().unwrap(); + /// # } + /// # + /// # fn run_test() -> QueryResult<()> { + /// # let mut conn = SqliteConnection::establish(":memory:").unwrap(); + /// conn.exclusive_transaction(|conn| { + /// // Do stuff in a transaction + /// Ok(()) + /// }) + /// # } + /// ``` + pub async fn exclusive_transaction(&mut self, f: F) -> Result + where + F: FnOnce(&mut Self) -> Result, + E: From, + { + self.transaction_sql(f, "BEGIN EXCLUSIVE").await + } + + async fn transaction_sql(&mut self, f: F, sql: &str) -> Result + where + F: FnOnce(&mut Self) -> Result, + E: From, + { + AnsiTransactionManager::begin_transaction_sql(&mut *self, sql).await?; + match f(&mut *self) { + Ok(value) => { + AnsiTransactionManager::commit_transaction(&mut *self).await?; + Ok(value) + } + Err(e) => { + AnsiTransactionManager::rollback_transaction(&mut *self).await?; + Err(e) + } + } + } + + async fn prepared_query<'conn, 'query, T>( + &'conn mut self, + source: T, + ) -> QueryResult> + where + T: QueryFragment + QueryId + 'query, + { + let raw_connection = &self.raw_connection; + let cache = &mut self.statement_cache; + let maybe_type_id = T::query_id(); + let cache_key = StatementCacheKey::for_source(maybe_type_id, &source, &[], &WasmSqlite)?; + + + let is_safe_to_cache_prepared = source.is_safe_to_cache_prepared(&WasmSqlite)?; + let mut qb = SqliteQueryBuilder::new(); + let sql = source.to_sql(&mut qb, &WasmSqlite).map(|()| qb.finish())?; + + let statement = cache.cached_prepared_statement( + cache_key, + sql, + is_safe_to_cache_prepared, + &[], + raw_connection.clone(), + &self.instrumentation, + ).await?.0; // Cloned RawConnection is dropped here + + + Ok(StatementUse::bind(statement, source, self.instrumentation.as_ref())?) + + } + + async fn establish_inner(database_url: &str) -> Result { + use diesel::result::ConnectionError::CouldntSetupConfiguration; + let raw_connection = RawConnection::establish(database_url).await.unwrap(); + let sqlite3 = crate::get_sqlite().await; + + sqlite3.register_diesel_sql_functions(&raw_connection.internal_connection).map_err(WasmSqliteError::from)?; + + Ok(Self { + statement_cache: StmtCache::new(), + raw_connection, + transaction_state: AnsiTransactionManager::default(), + metadata_lookup: (), + instrumentation: Arc::new(Mutex::new(None)), + }) + } +} diff --git a/diesel-wasm-sqlite/src/connection/owned_row.rs b/diesel-wasm-sqlite/src/connection/owned_row.rs new file mode 100644 index 000000000..f29dd8370 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/owned_row.rs @@ -0,0 +1,94 @@ +use std::sync::Arc; + +use super::sqlite_value::{OwnedSqliteValue, SqliteValue}; +use crate::WasmSqlite; +use diesel::{ + backend::Backend, + row::{Field, PartialRow, Row, RowIndex, RowSealed}, +}; + +#[derive(Debug)] +pub struct OwnedSqliteRow { + pub(super) values: Vec>, + column_names: Arc<[Option]>, +} + +impl OwnedSqliteRow { + pub(super) fn new( + values: Vec>, + column_names: Arc<[Option]>, + ) -> Self { + OwnedSqliteRow { + values, + column_names, + } + } +} + +impl RowSealed for OwnedSqliteRow {} + +impl<'a> Row<'a, WasmSqlite> for OwnedSqliteRow { + type Field<'field> = OwnedSqliteField<'field> where 'a: 'field, Self: 'field; + type InnerPartialRow = Self; + + fn field_count(&self) -> usize { + self.values.len() + } + + fn get<'field, I>(&'field self, idx: I) -> Option> + where + 'a: 'field, + Self: RowIndex, + { + let idx = self.idx(idx)?; + Some(OwnedSqliteField { + row: self, + col_idx: i32::try_from(idx).ok()?, + }) + } + + fn partial_row(&self, range: std::ops::Range) -> PartialRow<'_, Self::InnerPartialRow> { + PartialRow::new(self, range) + } +} + +impl RowIndex for OwnedSqliteRow { + fn idx(&self, idx: usize) -> Option { + if idx < self.field_count() { + Some(idx) + } else { + None + } + } +} + +impl<'idx> RowIndex<&'idx str> for OwnedSqliteRow { + fn idx(&self, field_name: &'idx str) -> Option { + self.column_names + .iter() + .position(|n| n.as_ref().map(|s| s as &str) == Some(field_name)) + } +} + +#[allow(missing_debug_implementations)] +pub struct OwnedSqliteField<'row> { + pub(super) row: &'row OwnedSqliteRow, + pub(super) col_idx: i32, +} + +impl<'row> Field<'row, WasmSqlite> for OwnedSqliteField<'row> { + fn field_name(&self) -> Option<&str> { + self.row + .column_names + .get(self.col_idx as usize) + .and_then(|o| o.as_ref().map(|s| s.as_ref())) + } + + fn is_null(&self) -> bool { + self.value().is_none() + } + + fn value(&self) -> Option<::RawValue<'row>> { + SqliteValue::from_owned_row(self.row, self.col_idx) + } +} diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs new file mode 100644 index 000000000..dd11abf25 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -0,0 +1,203 @@ +use crate::{ + sqlite_types::{SqliteFlags, SqliteOpenFlags}, + SqliteType, WasmSqlite, WasmSqliteError, +}; +use diesel::{ + connection::statement_cache::PrepareForCache, result::*, serialize::ToSql, + sql_types::HasSqlType, +}; +use tokio::sync::oneshot; +use wasm_bindgen::{closure::Closure, JsValue}; + +use super::stmt::Statement; + +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub(super) struct RawConnection { + pub(super) internal_connection: JsValue, + drop_signal: Option>, +} + +impl Clone for RawConnection { + fn clone(&self) -> Self { + Self { + internal_connection: self.internal_connection.clone(), + drop_signal: None, + } + } +} + +impl RawConnection { + pub(super) async fn establish(database_url: &str) -> ConnectionResult { + let sqlite3 = crate::get_sqlite().await; + let database_url = if database_url.starts_with("sqlite://") { + database_url.replacen("sqlite://", "file:", 1) + } else { + database_url.to_string() + }; + let flags = SqliteOpenFlags::SQLITE_OPEN_READWRITE + | SqliteOpenFlags::SQLITE_OPEN_CREATE + | SqliteOpenFlags::SQLITE_OPEN_URI; + + let (tx, rx) = oneshot::channel::(); + // TODO: can make this into function/macro + wasm_bindgen_futures::spawn_local(async move { + match rx.await { + Ok(conn) => { + let sqlite3 = crate::get_sqlite_unchecked(); + match sqlite3.close(&conn).await { + Ok(_) => log::debug!("db closed"), + Err(e) => { + log::error!("error during db close"); + web_sys::console::log_1(&e); + } + } + } + Err(_) => { + log::error!("RawConnection never dropped."); + } + } + }); + + Ok(RawConnection { + internal_connection: sqlite3 + .open_v2(&database_url, Some(flags.bits() as i32)) + .await + .map_err(WasmSqliteError::from) + .map_err(ConnectionError::from)?, + drop_signal: Some(tx), + }) + } + + pub(super) async fn exec(&self, query: &str) -> QueryResult<()> { + let sqlite3 = crate::get_sqlite().await; + let result = sqlite3 + .exec(&self.internal_connection, query) + .await + .unwrap(); + + Ok(result) + } + + pub(super) fn rows_affected_by_last_query(&self) -> usize { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.changes(&self.internal_connection) + } + + pub(super) fn register_sql_function( + &self, + fn_name: &str, + num_args: usize, + deterministic: bool, + f: F, + ) -> QueryResult<()> + where + F: FnMut(JsValue, Vec) -> JsValue + 'static, + Ret: ToSql, + WasmSqlite: HasSqlType, + { + let sqlite3 = crate::get_sqlite_unchecked(); + let flags = Self::get_flags(deterministic); + + let cb = Closure::new(f); + sqlite3 + .create_function( + &self.internal_connection, + fn_name, + num_args + .try_into() + .expect("usize to i32 panicked in register_sql_function"), + flags, + 0, + Some(&cb), + None, + None, + ) + .unwrap(); + Ok(()) + } + + fn get_flags(deterministic: bool) -> i32 { + let mut flags = SqliteFlags::SQLITE_UTF8; + if deterministic { + flags |= SqliteFlags::SQLITE_DETERMINISTIC; + } + flags.bits() as i32 + } + + /* possible to implement this, but would need to fill in the missing wa-sqlite functions + pub(super) fn serialize(&mut self) -> SerializedDatabase { + unsafe { + let mut size: ffi::sqlite3_int64 = 0; + let data_ptr = ffi::sqlite3_serialize( + self.internal_connection.as_ptr(), + std::ptr::null(), + &mut size as *mut _, + 0, + ); + SerializedDatabase::new(data_ptr, size as usize) + } + } + + pub(super) fn deserialize(&mut self, data: &[u8]) -> QueryResult<()> { + // the cast for `ffi::SQLITE_DESERIALIZE_READONLY` is required for old libsqlite3-sys versions + #[allow(clippy::unnecessary_cast)] + unsafe { + let result = ffi::sqlite3_deserialize( + self.internal_connection.as_ptr(), + std::ptr::null(), + data.as_ptr() as *mut u8, + data.len() as i64, + data.len() as i64, + ffi::SQLITE_DESERIALIZE_READONLY as u32, + ); + + ensure_sqlite_ok(result, self.internal_connection.as_ptr()) + } + } + */ +} + +#[async_trait::async_trait(?Send)] +impl diesel_async::stmt_cache::PrepareCallback for RawConnection { + async fn prepare( + self, + sql: &str, + _metadata: &[SqliteType], + is_for_cache: PrepareForCache, + ) -> QueryResult<(Statement, Self)> { + let stmt = Statement::prepare(&self, sql, is_for_cache).await; + Ok((stmt?, self)) + } +} + +impl Drop for RawConnection { + fn drop(&mut self) { + if let Some(s) = self.drop_signal.take() { + let _ = s.send(self.internal_connection.clone()); + } else { + log::warn!("RawConnection not dropped because drop_signal is empty"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::connection::{AsyncConnection, WasmSqliteConnection}; + use diesel::connection::Connection; + use wasm_bindgen_test::*; + use web_sys::console; + wasm_bindgen_test_configure!(run_in_dedicated_worker); + + #[wasm_bindgen_test] + async fn test_fn_registration() { + let mut result = WasmSqliteConnection::establish("test").await; + let mut conn = result.unwrap(); + console::log_1(&"CONNECTED".into()); + conn.raw + .register_sql_function("test", 0, true, |ctx, values| { + console::log_1(&"Inside Fn".into()); + }); + } +} diff --git a/diesel-wasm-sqlite/src/connection/row.rs b/diesel-wasm-sqlite/src/connection/row.rs new file mode 100644 index 000000000..41c2c132d --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/row.rs @@ -0,0 +1,412 @@ +use std::cell::{Ref, RefCell}; +use std::rc::Rc; +use std::sync::Arc; + +use super::owned_row::OwnedSqliteRow; +use super::sqlite_value::{OwnedSqliteValue, SqliteValue}; +use super::stmt::StatementUse; +use crate::WasmSqlite; +use diesel::{ + backend::Backend, + row::{Field, IntoOwnedRow, PartialRow, Row, RowIndex, RowSealed}, +}; + +#[allow(missing_debug_implementations)] +pub struct SqliteRow<'stmt, 'query> { + pub(super) inner: Rc>>, + pub(super) field_count: usize, +} + +pub(super) enum PrivateSqliteRow<'stmt, 'query> { + Direct(StatementUse<'stmt, 'query>), + Duplicated { + values: Vec>, + column_names: Rc<[Option]>, + }, +} + +impl<'stmt> IntoOwnedRow<'stmt, WasmSqlite> for SqliteRow<'stmt, '_> { + type OwnedRow = OwnedSqliteRow; + + type Cache = Option]>>; + + fn into_owned(self, column_name_cache: &mut Self::Cache) -> Self::OwnedRow { + self.inner.borrow().moveable(column_name_cache) + } +} + +impl<'stmt, 'query> PrivateSqliteRow<'stmt, 'query> { + pub(super) fn duplicate( + &mut self, + column_names: &mut Option]>>, + ) -> PrivateSqliteRow<'stmt, 'query> { + match self { + PrivateSqliteRow::Direct(stmt) => { + let column_names = if let Some(column_names) = column_names { + column_names.clone() + } else { + let c: Rc<[Option]> = Rc::from( + (0..stmt.column_count()) + .map(|idx| stmt.field_name(idx).map(|s| s.to_owned())) + .collect::>(), + ); + *column_names = Some(c.clone()); + c + }; + PrivateSqliteRow::Duplicated { + values: (0..stmt.column_count()) + .map(|idx| stmt.copy_value(idx)) + .collect(), + column_names, + } + } + PrivateSqliteRow::Duplicated { + values, + column_names, + } => PrivateSqliteRow::Duplicated { + values: values + .iter() + .map(|v| v.as_ref().map(|v| v.duplicate())) + .collect(), + column_names: column_names.clone(), + }, + } + } + + pub(super) fn moveable( + &self, + column_name_cache: &mut Option]>>, + ) -> OwnedSqliteRow { + match self { + PrivateSqliteRow::Direct(stmt) => { + if column_name_cache.is_none() { + *column_name_cache = Some( + (0..stmt.column_count()) + .map(|idx| stmt.field_name(idx).map(|s| s.to_owned())) + .collect::>() + .into(), + ); + } + let column_names = Arc::clone( + column_name_cache + .as_ref() + .expect("This is initialized above"), + ); + OwnedSqliteRow::new( + (0..stmt.column_count()) + .map(|idx| stmt.copy_value(idx)) + .collect(), + column_names, + ) + } + PrivateSqliteRow::Duplicated { + values, + column_names, + } => { + if column_name_cache.is_none() { + *column_name_cache = Some( + (*column_names) + .iter() + .map(|s| s.to_owned()) + .collect::>() + .into(), + ); + } + let column_names = Arc::clone( + column_name_cache + .as_ref() + .expect("This is initialized above"), + ); + OwnedSqliteRow::new( + values + .iter() + .map(|v| v.as_ref().map(|v| v.duplicate())) + .collect(), + column_names, + ) + } + } + } +} + +impl<'stmt, 'query> RowSealed for SqliteRow<'stmt, 'query> {} + +impl<'stmt, 'query> Row<'stmt, WasmSqlite> for SqliteRow<'stmt, 'query> { + type Field<'field> = SqliteField<'field, 'field> where 'stmt: 'field, Self: 'field; + type InnerPartialRow = Self; + + fn field_count(&self) -> usize { + self.field_count + } + + fn get<'field, I>(&'field self, idx: I) -> Option> + where + 'stmt: 'field, + Self: RowIndex, + { + let idx = self.idx(idx)?; + Some(SqliteField { + row: self.inner.borrow(), + col_idx: i32::try_from(idx).ok()?, + }) + } + + fn partial_row(&self, range: std::ops::Range) -> PartialRow<'_, Self::InnerPartialRow> { + PartialRow::new(self, range) + } +} + +impl<'stmt, 'query> RowIndex for SqliteRow<'stmt, 'query> { + fn idx(&self, idx: usize) -> Option { + if idx < self.field_count { + Some(idx) + } else { + None + } + } +} + +impl<'stmt, 'idx, 'query> RowIndex<&'idx str> for SqliteRow<'stmt, 'query> { + fn idx(&self, field_name: &'idx str) -> Option { + match &mut *self.inner.borrow_mut() { + PrivateSqliteRow::Direct(stmt) => stmt.index_for_column_name(field_name), + PrivateSqliteRow::Duplicated { column_names, .. } => column_names + .iter() + .position(|n| n.as_ref().map(|s| s as &str) == Some(field_name)), + } + } +} + +#[allow(missing_debug_implementations)] +pub struct SqliteField<'stmt, 'query> { + pub(super) row: Ref<'stmt, PrivateSqliteRow<'stmt, 'query>>, + pub(super) col_idx: i32, +} + +impl<'stmt, 'query> Field<'stmt, WasmSqlite> for SqliteField<'stmt, 'query> { + fn field_name(&self) -> Option<&str> { + match &*self.row { + PrivateSqliteRow::Direct(stmt) => stmt.field_name(self.col_idx), + PrivateSqliteRow::Duplicated { column_names, .. } => column_names + .get(self.col_idx as usize) + .and_then(|t| t.as_ref().map(|n| n as &str)), + } + } + + fn is_null(&self) -> bool { + self.value().is_none() + } + + fn value(&self) -> Option<::RawValue<'_>> { + SqliteValue::new(Ref::clone(&self.row), self.col_idx) + } +} + +/* +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fun_with_row_iters() { + crate::table! { + #[allow(unused_parens)] + users(id) { + id -> Integer, + name -> Text, + } + } + + use crate::connection::LoadConnection; + use crate::deserialize::{FromSql, FromSqlRow}; + use crate::prelude::*; + use crate::row::{Field, Row}; + use crate::sql_types; + + let conn = &mut crate::test_helpers::connection(); + + crate::sql_query("CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);") + .execute(conn) + .unwrap(); + + crate::insert_into(users::table) + .values(vec![ + (users::id.eq(1), users::name.eq("Sean")), + (users::id.eq(2), users::name.eq("Tess")), + ]) + .execute(conn) + .unwrap(); + + let query = users::table.select((users::id, users::name)); + + let expected = vec![(1, String::from("Sean")), (2, String::from("Tess"))]; + + let row_iter = conn.load(query).unwrap(); + for (row, expected) in row_iter.zip(&expected) { + let row = row.unwrap(); + + let deserialized = <(i32, String) as FromSqlRow< + (sql_types::Integer, sql_types::Text), + _, + >>::build_from_row(&row) + .unwrap(); + + assert_eq!(&deserialized, expected); + } + + { + let collected_rows = conn.load(query).unwrap().collect::>(); + + for (row, expected) in collected_rows.iter().zip(&expected) { + let deserialized = row + .as_ref() + .map(|row| { + <(i32, String) as FromSqlRow< + (sql_types::Integer, sql_types::Text), + _, + >>::build_from_row(row).unwrap() + }) + .unwrap(); + + assert_eq!(&deserialized, expected); + } + } + + let mut row_iter = conn.load(query).unwrap(); + + let first_row = row_iter.next().unwrap().unwrap(); + let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); + let first_values = (first_fields.0.value(), first_fields.1.value()); + + assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(first_values); + assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(first_fields); + + let second_row = row_iter.next().unwrap().unwrap(); + let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap()); + let second_values = (second_fields.0.value(), second_fields.1.value()); + + assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(second_values); + assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(second_fields); + + assert!(row_iter.next().is_none()); + + let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); + let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap()); + + let first_values = (first_fields.0.value(), first_fields.1.value()); + let second_values = (second_fields.0.value(), second_fields.1.value()); + + assert_eq!( + >::from_nullable_sql(first_values.0) + .unwrap(), + expected[0].0 + ); + assert_eq!( + >::from_nullable_sql(first_values.1) + .unwrap(), + expected[0].1 + ); + + assert_eq!( + >::from_nullable_sql(second_values.0) + .unwrap(), + expected[1].0 + ); + assert_eq!( + >::from_nullable_sql(second_values.1) + .unwrap(), + expected[1].1 + ); + + let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); + let first_values = (first_fields.0.value(), first_fields.1.value()); + + assert_eq!( + >::from_nullable_sql(first_values.0) + .unwrap(), + expected[0].0 + ); + assert_eq!( + >::from_nullable_sql(first_values.1) + .unwrap(), + expected[0].1 + ); + } + + #[cfg(feature = "returning_clauses_for_sqlite_3_35")] + crate::define_sql_function! {fn sleep(a: diesel::sql_types::Integer) -> diesel::sql_types::Integer} + + #[test] + #[cfg(feature = "returning_clauses_for_sqlite_3_35")] + fn parallel_iter_with_error() { + use crate::connection::Connection; + use crate::connection::LoadConnection; + use crate::connection::SimpleConnection; + use crate::expression_methods::ExpressionMethods; + use crate::SqliteConnection; + use std::sync::{Arc, Barrier}; + use std::time::Duration; + + let temp_dir = tempfile::tempdir().unwrap(); + let db_path = format!("{}/test.db", temp_dir.path().display()); + let mut conn1 = SqliteConnection::establish(&db_path).unwrap(); + let mut conn2 = SqliteConnection::establish(&db_path).unwrap(); + + crate::table! { + users { + id -> Integer, + name -> Text, + } + } + + conn1 + .batch_execute("CREATE TABLE users(id INTEGER NOT NULL PRIMARY KEY, name TEXT)") + .unwrap(); + + let barrier = Arc::new(Barrier::new(2)); + let barrier2 = barrier.clone(); + + // we unblock the main thread from the sleep function + sleep_utils::register_impl(&mut conn2, move |a: i32| { + barrier.wait(); + std::thread::sleep(Duration::from_secs(a as u64)); + a + }) + .unwrap(); + + // spawn a background thread that locks the database file + let handle = std::thread::spawn(move || { + use crate::query_dsl::RunQueryDsl; + + conn2 + .immediate_transaction(|conn| diesel::select(sleep(1)).execute(conn)) + .unwrap(); + }); + barrier2.wait(); + + // execute some action that also requires a lock + let mut iter = conn1 + .load( + diesel::insert_into(users::table) + .values((users::id.eq(1), users::name.eq("John"))) + .returning(users::id), + ) + .unwrap(); + + // get the first iterator result, that should return the lock error + let n = iter.next().unwrap(); + assert!(n.is_err()); + + // check that the iterator is now empty + let n = iter.next(); + assert!(n.is_none()); + + // join the background thread + handle.join().unwrap(); + } +} +*/ diff --git a/diesel-wasm-sqlite/src/connection/serialized_database.rs b/diesel-wasm-sqlite/src/connection/serialized_database.rs new file mode 100644 index 000000000..e302a097c --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/serialized_database.rs @@ -0,0 +1,42 @@ +use std::ops::Deref; + +/// `SerializedDatabase` is a wrapper for a serialized database that is dynamically allocated by calling `sqlite3_serialize`. +/// This RAII wrapper is necessary to deallocate the memory when it goes out of scope with `sqlite3_free`. +#[derive(Debug)] +pub struct SerializedDatabase { + data: JsValue, + len: usize, +} + +impl SerializedDatabase { + /// Creates a new `SerializedDatabase` with the given data pointer and length. + /// + /// SAFETY: The data pointer needs to be returned by sqlite + /// and the length must match the underlying buffer pointer + pub(crate) unsafe fn new(data: *mut u8, len: usize) -> Self { + Self { data, len } + } + + /// Returns a slice of the serialized database. + pub fn as_slice(&self) -> &[u8] { + // The pointer is never null because we don't pass the NO_COPY flag + unsafe { std::slice::from_raw_parts(self.data, self.len) } + } +} + +impl Deref for SerializedDatabase { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl Drop for SerializedDatabase { + /// Deallocates the memory of the serialized database when it goes out of scope. + fn drop(&mut self) { + unsafe { + ffi::sqlite3_free(self.data as _); + } + } +} diff --git a/diesel-wasm-sqlite/src/connection/sqlite_value.rs b/diesel-wasm-sqlite/src/connection/sqlite_value.rs new file mode 100644 index 000000000..e94e77217 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/sqlite_value.rs @@ -0,0 +1,159 @@ +#![allow(unsafe_code)] // ffi calls + +use std::cell::Ref; + +use crate::ffi::{self, SQLiteCompatibleType}; +use crate::{backend::SqliteType, sqlite_types}; +use wasm_bindgen::JsValue; + +use super::owned_row::OwnedSqliteRow; +use super::row::PrivateSqliteRow; + +/// Raw sqlite value as received from the database +/// +/// Use existing `FromSql` implementations to convert this into +/// rust values +#[allow(missing_debug_implementations, missing_copy_implementations)] +pub struct SqliteValue<'row, 'stmt, 'query> { + // This field exists to ensure that nobody + // can modify the underlying row while we are + // holding a reference to some row value here + _row: Option>>, + // we extract the raw value pointer as part of the constructor + // to safe the match statements for each method + // According to benchmarks this leads to a ~20-30% speedup + // + // + // This is sound as long as nobody calls `stmt.step()` + // while holding this value. We ensure this by including + // a reference to the row above. + value: SQLiteCompatibleType, +} + +#[derive(Debug, Clone)] +pub(super) struct OwnedSqliteValue { + pub(super) value: SQLiteCompatibleType, +} + +// Unsafe Send impl safe since sqlite3_value is built with sqlite3_value_dup +// see https://www.sqlite.org/c3ref/value.html +unsafe impl Send for OwnedSqliteValue {} + +impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { + pub(super) fn new( + row: Ref<'row, PrivateSqliteRow<'stmt, 'query>>, + col_idx: i32, + ) -> Option> { + let value = match &*row { + PrivateSqliteRow::Direct(stmt) => stmt.column_value(col_idx)?, + PrivateSqliteRow::Duplicated { values, .. } => values + .get(col_idx as usize) + .and_then(|v| v.as_ref())? + .value + .clone(), + }; + + let ret = Self { + _row: Some(row), + value, + }; + if ret.value_type().is_none() { + None + } else { + Some(ret) + } + } + + pub(super) fn from_owned_row( + row: &'row OwnedSqliteRow, + col_idx: i32, + ) -> Option> { + let value = row + .values + .get(col_idx as usize) + .and_then(|v| v.as_ref())? + .value + .clone(); + let ret = Self { _row: None, value }; + if ret.value_type().is_none() { + None + } else { + Some(ret) + } + } + + pub(crate) fn parse_string(&self, f: impl FnOnce(String) -> R) -> R { + let sqlite3 = crate::get_sqlite_unchecked(); + let s = sqlite3.value_text(&self.value); + f(s) + } + + // TODO: Wasm bindgen can't work with references yet + // not sure if this will effect perf + pub(crate) fn read_text(&self) -> String { + self.parse_string(|s| s) + } + + pub(crate) fn read_blob(&self) -> Vec { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_blob(&self.value) + } + + pub(crate) fn read_integer(&self) -> i32 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_int(&self.value) + } + + pub(crate) fn read_long(&self) -> i64 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_int64(&self.value) + } + + pub(crate) fn read_double(&self) -> f64 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_double(&self.value) + } + + /// Get the type of the value as returned by sqlite + pub fn value_type(&self) -> Option { + let sqlite3 = crate::get_sqlite_unchecked(); + let tpe = sqlite3.value_type(&self.value); + match tpe { + sqlite_types::SQLITE_TEXT => Some(SqliteType::Text), + sqlite_types::SQLITE_INTEGER => Some(SqliteType::Long), + sqlite_types::SQLITE_FLOAT => Some(SqliteType::Double), + sqlite_types::SQLITE_BLOB => Some(SqliteType::Binary), + sqlite_types::SQLITE_NULL => None, + _ => unreachable!( + "Sqlite's documentation state that this case ({}) is not reachable. \ + If you ever see this error message please open an issue at \ + https://github.com/diesel-rs/diesel.", + tpe + ), + } + } +} + +impl OwnedSqliteValue { + pub(super) fn copy_from_ptr(ptr: &JsValue) -> Option { + let sqlite3 = crate::get_sqlite_unchecked(); + let tpe = sqlite3.value_type(&ptr); + if sqlite_types::SQLITE_NULL == tpe { + return None; + } + + let value = sqlite3.value_dup(ptr); + + Some(Self { + value: value.into(), + }) + } + + pub(super) fn duplicate(&self) -> OwnedSqliteValue { + let sqlite3 = crate::get_sqlite_unchecked(); + let value = sqlite3.value_dup(&self.value); + OwnedSqliteValue { + value: value.into(), + } + } +} diff --git a/diesel-wasm-sqlite/src/connection/statement_iterator.rs b/diesel-wasm-sqlite/src/connection/statement_iterator.rs new file mode 100644 index 000000000..393ec9e47 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/statement_iterator.rs @@ -0,0 +1,172 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use super::row::{PrivateSqliteRow, SqliteRow}; +use super::stmt::StatementUse; +use crate::result::QueryResult; + +#[allow(missing_debug_implementations)] +pub struct StatementIterator<'stmt, 'query> { + inner: PrivateStatementIterator<'stmt, 'query>, + column_names: Option]>>, + field_count: usize, +} + +impl<'stmt, 'query> StatementIterator<'stmt, 'query> { + #[cold] + #[allow(unsafe_code)] // call to unsafe function + fn handle_duplicated_row_case( + outer_last_row: &mut Rc>>, + column_names: &mut Option]>>, + field_count: usize, + ) -> Option>> { + // We don't own the statement. There is another existing reference, likely because + // a user stored the row in some long time container before calling next another time + // In this case we copy out the current values into a temporary store and advance + // the statement iterator internally afterwards + let last_row = { + let mut last_row = match outer_last_row.try_borrow_mut() { + Ok(o) => o, + Err(_e) => { + return Some(Err(crate::result::Error::DeserializationError( + "Failed to reborrow row. Try to release any `SqliteField` or `SqliteValue` \ + that exists at this point" + .into(), + ))); + } + }; + let last_row = &mut *last_row; + let duplicated = last_row.duplicate(column_names); + std::mem::replace(last_row, duplicated) + }; + if let PrivateSqliteRow::Direct(mut stmt) = last_row { + let res = unsafe { + // This is actually safe here as we've already + // performed one step. For the first step we would have + // used `PrivateStatementIterator::NotStarted` where we don't + // have access to `PrivateSqliteRow` at all + stmt.step(false) + }; + *outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); + match res { + Err(e) => Some(Err(e)), + Ok(false) => None, + Ok(true) => Some(Ok(SqliteRow { + inner: Rc::clone(outer_last_row), + field_count, + })), + } + } else { + // any other state than `PrivateSqliteRow::Direct` is invalid here + // and should not happen. If this ever happens this is a logic error + // in the code above + unreachable!( + "You've reached an impossible internal state. \ + If you ever see this error message please open \ + an issue at https://github.com/diesel-rs/diesel \ + providing example code how to trigger this error." + ) + } + } +} + +enum PrivateStatementIterator<'stmt, 'query> { + NotStarted(Option>), + Started(Rc>>), +} + +impl<'stmt, 'query> StatementIterator<'stmt, 'query> { + pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> { + Self { + inner: PrivateStatementIterator::NotStarted(Some(stmt)), + column_names: None, + field_count: 0, + } + } +} + +impl<'stmt, 'query> Iterator for StatementIterator<'stmt, 'query> { + type Item = QueryResult>; + + #[allow(unsafe_code)] // call to unsafe function + fn next(&mut self) -> Option { + use PrivateStatementIterator::{NotStarted, Started}; + match &mut self.inner { + NotStarted(ref mut stmt @ Some(_)) => { + let mut stmt = stmt + .take() + .expect("It must be there because we checked that above"); + let step = unsafe { + // This is safe as we pass `first_step = true` to reset the cached column names + stmt.step(true) + }; + match step { + Err(e) => Some(Err(e)), + Ok(false) => None, + Ok(true) => { + let field_count = stmt.column_count() as usize; + self.field_count = field_count; + let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); + self.inner = Started(inner.clone()); + Some(Ok(SqliteRow { inner, field_count })) + } + } + } + Started(ref mut last_row) => { + // There was already at least one iteration step + // We check here if the caller already released the row value or not + // by checking if our Rc owns the data or not + if let Some(last_row_ref) = Rc::get_mut(last_row) { + // We own the statement, there is no other reference here. + // This means we don't need to copy out values from the sqlite provided + // datastructures for now + // We don't need to use the runtime borrowing system of the RefCell here + // as we have a mutable reference, so all of this below is checked at compile time + if let PrivateSqliteRow::Direct(ref mut stmt) = last_row_ref.get_mut() { + let step = unsafe { + // This is actually safe here as we've already + // performed one step. For the first step we would have + // used `PrivateStatementIterator::NotStarted` where we don't + // have access to `PrivateSqliteRow` at all + + stmt.step(false) + }; + match step { + Err(e) => Some(Err(e)), + Ok(false) => None, + Ok(true) => { + let field_count = self.field_count; + Some(Ok(SqliteRow { + inner: Rc::clone(last_row), + field_count, + })) + } + } + } else { + // any other state than `PrivateSqliteRow::Direct` is invalid here + // and should not happen. If this ever happens this is a logic error + // in the code above + unreachable!( + "You've reached an impossible internal state. \ + If you ever see this error message please open \ + an issue at https://github.com/diesel-rs/diesel \ + providing example code how to trigger this error." + ) + } + } else { + Self::handle_duplicated_row_case( + last_row, + &mut self.column_names, + self.field_count, + ) + } + } + NotStarted(_s) => { + // we likely got an error while executing the other + // `NotStarted` branch above. In this case we just want to stop + // iterating here + None + } + } + } +} diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs new file mode 100644 index 000000000..53fb5ba78 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -0,0 +1,422 @@ +#![allow(unsafe_code)] //TODO: can probably remove for wa-sqlite +use super::bind_collector::{InternalSqliteBindValue, SqliteBindCollector}; +use super::raw::RawConnection; +use super::sqlite_value::OwnedSqliteValue; +use crate::ffi::SQLiteCompatibleType; +use crate::{ + sqlite_types::{self, PrepareOptions, SqlitePrepareFlags}, + SqliteType, WasmSqlite, +}; +use diesel::{ + connection::{ + statement_cache::{MaybeCached, PrepareForCache}, + Instrumentation, + }, + query_builder::{QueryFragment, QueryId}, + result::{Error::DatabaseError, *}, +}; +use std::cell::OnceCell; +use std::sync::Mutex; + +use wasm_bindgen::JsValue; + +// this is OK b/c web runs in one thread +unsafe impl Send for Statement {} +pub(super) struct Statement { + inner_statement: JsValue, + drop_signal: Option>, +} + +impl Statement { + pub(super) async fn prepare( + raw_connection: &RawConnection, + sql: &str, + is_cached: PrepareForCache, + ) -> QueryResult { + let sqlite3 = crate::get_sqlite_unchecked(); + let flags = if matches!(is_cached, PrepareForCache::Yes) { + Some(SqlitePrepareFlags::SQLITE_PREPARE_PERSISTENT.bits()) + } else { + None + }; + + let options = PrepareOptions { + flags, + unscoped: None, + }; + + let stmt = sqlite3 + .prepare( + &raw_connection.internal_connection, + sql, + serde_wasm_bindgen::to_value(&options).unwrap(), + ) + .await + .unwrap(); + + let (tx, rx) = tokio::sync::oneshot::channel::(); + + // We don't have `AsyncDrop` in rust yet. + // instead, we `send` a signal on Drop for the destructor to run in an + // asynchronously-spawned task. + wasm_bindgen_futures::spawn_local(async move { + match rx.await { + Ok(inner_statement) => { + let this = Statement { + inner_statement, + drop_signal: None, + }; + + this.reset().await; + this.clear_bindings(); + } + Err(_) => { + log::error!("Statement never dropped"); + } + } + }); + + Ok(Statement { + inner_statement: stmt, + drop_signal: Some(tx), + }) + } + + // The caller of this function has to ensure that: + // * Any buffer provided as `SqliteBindValue::BorrowedBinary`, `SqliteBindValue::Binary` + // `SqliteBindValue::String` or `SqliteBindValue::BorrowedString` is valid + // till either a new value is bound to the same parameter or the underlying + // prepared statement is dropped. + fn bind( + &self, + _tpe: SqliteType, + value: InternalSqliteBindValue<'_>, + bind_index: i32, + ) -> QueryResult { + let sqlite3 = crate::get_sqlite_unchecked(); + let value = + serde_wasm_bindgen::to_value(&value).expect("Bind value failed to convert to JsValue"); + let result = sqlite3 + .bind(&self.inner_statement, bind_index, value.into()) + .unwrap(); + + // TODO:insipx Pretty sure we can have a simpler implementation here + // making use of `wa-sqlite` `bind` which abstracts over the individual bind functions in + // sqlite3. However, not sure how this will work further up the stack. + // This might not work because of differences in how serde_json recognizes js types + // and how wa-sqlite recogizes js types. In that case, need to resort to matching on + // individual types with bind_$type fns . + + Ok(result) + } + + async fn reset(&self) { + let sqlite3 = crate::get_sqlite_unchecked(); + let _ = sqlite3.reset(&self.inner_statement).await.unwrap(); + } + + fn clear_bindings(&self) { + let sqlite3 = crate::get_sqlite_unchecked(); + let _ = sqlite3.clear_bindings(&self.inner_statement).unwrap(); + } + + /* not sure if there is equivalent method or just cloning the stmt is enough + fn raw_connection(&self) -> *mut ffi::sqlite3 { + unsafe { ffi::sqlite3_db_handle(self.inner_statement.as_ptr()) } + } + */ +} + +/* TODO: Useful for converting JS Error messages to Rust +fn last_error(raw_connection: *mut ffi::sqlite3) -> Error { + let error_message = last_error_message(raw_connection); + let error_information = Box::new(error_message); + let error_kind = match last_error_code(raw_connection) { + ffi::SQLITE_CONSTRAINT_UNIQUE | ffi::SQLITE_CONSTRAINT_PRIMARYKEY => { + DatabaseErrorKind::UniqueViolation + } + ffi::SQLITE_CONSTRAINT_FOREIGNKEY => DatabaseErrorKind::ForeignKeyViolation, + ffi::SQLITE_CONSTRAINT_NOTNULL => DatabaseErrorKind::NotNullViolation, + ffi::SQLITE_CONSTRAINT_CHECK => DatabaseErrorKind::CheckViolation, + _ => DatabaseErrorKind::Unknown, + }; + DatabaseError(error_kind, error_information) +} + +fn last_error_message(conn: *mut ffi::sqlite3) -> String { + let c_str = unsafe { CStr::from_ptr(ffi::sqlite3_errmsg(conn)) }; + c_str.to_string_lossy().into_owned() +} + + +fn last_error_code(conn: *mut ffi::sqlite3) -> libc::c_int { + unsafe { ffi::sqlite3_extended_errcode(conn) } +} +*/ + +impl Drop for Statement { + fn drop(&mut self) { + let sqlite3 = crate::get_sqlite_unchecked(); + // TODO:insipx potential problems here. + // wa-sqlite does not throw an error if finalize fails: -- it might just crash + // doc: https://rhashimoto.github.io/wa-sqlite/docs/interfaces/SQLiteAPI.html#finalize.finalize-1 + // in that case we might not know if this errored or not + // maybe depends how wasm panic/errors work + // Worth unit testing the Drop implementation. + let _ = sqlite3 + .finalize(&self.inner_statement) + .expect("Error finalized SQLite prepared statement"); + } +} + +// A warning for future editors: +// Changing this code to something "simpler" may +// introduce undefined behaviour. Make sure you read +// the following discussions for details about +// the current version: +// +// * https://github.com/weiznich/diesel/pull/7 +// * https://users.rust-lang.org/t/code-review-for-unsafe-code-in-diesel/66798/ +// * https://github.com/rust-lang/unsafe-code-guidelines/issues/194 +struct BoundStatement<'stmt, 'query> { + statement: MaybeCached<'stmt, Statement>, + // we need to store the query here to ensure no one does + // drop it till the end of the statement + // We use a boxed queryfragment here just to erase the + // generic type, we use NonNull to communicate + // that this is a shared buffer + query: Option + 'query>>, + instrumentation: &'stmt Mutex, + has_error: bool, +} + +impl<'stmt, 'query> BoundStatement<'stmt, 'query> { + fn bind( + statement: MaybeCached<'stmt, Statement>, + query: T, + instrumentation: &'stmt Mutex, + ) -> QueryResult> + where + T: QueryFragment + QueryId + 'query, + { + // Don't use a trait object here to prevent using a virtual function call + // For sqlite this can introduce a measurable overhead + // Query is boxed here to make sure it won't move in memory anymore, so any bind + // it could output would stay valid. + let query = Box::new(query); + + let mut bind_collector = SqliteBindCollector::new(); + query.collect_binds(&mut bind_collector, &mut (), &WasmSqlite)?; + let SqliteBindCollector { binds } = bind_collector; + + let mut ret = BoundStatement { + statement, + query: None, + instrumentation, + has_error: false, + }; + + ret.bind_buffers(binds)?; + + let query = query as Box + 'query>; + ret.query = Some(query); + + Ok(ret) + } + + // This is a separated function so that + // not the whole constructor is generic over the query type T. + // This hopefully prevents binary bloat. + fn bind_buffers( + &mut self, + binds: Vec<(InternalSqliteBindValue<'_>, SqliteType)>, + ) -> QueryResult<()> { + for (bind_idx, (bind, tpe)) in (1..).zip(binds) { + // It's safe to call bind here as: + // * The type and value matches + // * We ensure that corresponding buffers lives long enough below + // * The statement is not used yet by `step` or anything else + let _ = self.statement.bind(tpe, bind, bind_idx)?; + + // we don't track binds to free like sqlite3 C bindings + // The assumption is that wa-sqlite, being WASM run in web browser that + // lies in the middle of rust -> sqlite, takes care of this for us. + // if we run into memory issues, especially memory leaks + // this should be the first place to pay attention to. + // + // The bindings shuold be collected/freed with JS once `clear_bindings` is + // run on `Drop` for `BoundStatement` + } + Ok(()) + } + + fn finish_query_with_error(mut self, _e: &Error) { + self.has_error = true; + /* + if let Some(q) = self.query { + // it's safe to get a reference from this ptr as it's guaranteed to not be null + let q = unsafe { q.as_ref() }; + self.instrumentation.on_connection_event( + diesel::connection::InstrumentationEvent::FinishQuery { + query: &crate::debug_query(&q), + error: Some(e), + }, + ); + } + */ + } + + // FIXME: [`AsyncDrop`](https://github.com/rust-lang/rust/issues/126482) is a missing feature in rust. + // Until then we need to manually reset the statement object. + pub async fn reset(&mut self) { + self.statement.reset().await; + self.statement.clear_bindings() + } +} + +// Eventually replace with `AsyncDrop`: https://github.com/rust-lang/rust/issues/126482 +impl<'stmt, 'query> Drop for BoundStatement<'stmt, 'query> { + fn drop(&mut self) { + let sender = self + .statement + .drop_signal + .take() + .expect("Drop may only be ran once"); + let _ = sender.send(self.statement.inner_statement.clone()); + self.query.take(); + } +} + +#[allow(missing_debug_implementations)] +pub struct StatementUse<'stmt, 'query> { + statement: BoundStatement<'stmt, 'query>, + column_names: OnceCell>, +} + +impl<'stmt, 'query> StatementUse<'stmt, 'query> { + pub(super) fn bind( + statement: MaybeCached<'stmt, Statement>, + query: T, + instrumentation: &'stmt Mutex, + ) -> QueryResult> + where + T: QueryFragment + QueryId + 'query, + { + Ok(Self { + statement: BoundStatement::bind(statement, query, instrumentation)?, + column_names: OnceCell::new(), + }) + } + + pub(super) async fn run(mut self) -> QueryResult<()> { + // This is safe as we pass `first_step = true` + // and we consume the statement so nobody could + // access the columns later on anyway. + let r = self.step(true).await.map(|_| ()); + + if let Err(ref e) = r { + self.statement.finish_query_with_error(e); + } + r + } + + // This function is marked as unsafe incorrectly passing `false` to `first_step` + // for a first call to this function could cause access to freed memory via + // the cached column names. + // + // It's always safe to call this function with `first_step = true` as this removes + // the cached column names + pub(super) async fn step(&mut self, first_step: bool) -> QueryResult { + let sqlite3 = crate::get_sqlite_unchecked(); + let res = match serde_wasm_bindgen::from_value::( + sqlite3 + .step(&self.statement.statement.inner_statement) + .await + .unwrap(), + ) + .unwrap() + { + sqlite_types::SQLITE_DONE => Ok(false), + sqlite_types::SQLITE_ROW => Ok(true), + _ => panic!("SQLite Step returned Unhandled Result Code. Turn into err message"), + }; + + if first_step { + self.column_names = OnceCell::new(); + } + res + } + + // The returned string pointer is valid until either the prepared statement is + // destroyed by sqlite3_finalize() or until the statement is automatically + // reprepared by the first call to sqlite3_step() for a particular run or + // until the next call to sqlite3_column_name() or sqlite3_column_name16() + // on the same column. + // + // https://sqlite.org/c3ref/column_name.html + // + // Note: This function is marked as unsafe, as calling it can invalidate + // other existing column name pointers on the same column. To prevent that, + // it should maximally be called once per column at all. + fn column_name(&self, idx: i32) -> String { + let sqlite3 = crate::get_sqlite_unchecked(); + + sqlite3.column_name(&self.statement.statement.inner_statement, idx) + } + + pub(super) fn column_count(&self) -> i32 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.column_count(&self.statement.statement.inner_statement) + } + + pub(super) fn index_for_column_name(&mut self, field_name: &str) -> Option { + (0..self.column_count()) + .find(|idx| self.field_name(*idx) == Some(field_name)) + .map(|v| v as usize) + } + + pub(super) fn field_name(&self, idx: i32) -> Option<&str> { + let column_names = self.column_names.get_or_init(|| { + let count = self.column_count(); + (0..count).map(|idx| self.column_name(idx)).collect() + }); + + column_names.get(idx as usize).map(AsRef::as_ref) + } + + pub(super) fn copy_value(&self, idx: i32) -> Option { + OwnedSqliteValue::copy_from_ptr(&self.column_value(idx)?.into()) + } + + pub(super) fn column_value(&self, idx: i32) -> Option { + let sqlite3 = crate::get_sqlite_unchecked(); + Some(sqlite3.column(&self.statement.statement.inner_statement, idx)) + } +} +/* +#[cfg(test)] +mod tests { + use crate::prelude::*; + use crate::sql_types::Text; + + // this is a regression test for + // https://github.com/diesel-rs/diesel/issues/3558 + #[test] + fn check_out_of_bounds_bind_does_not_panic_on_drop() { + let mut conn = SqliteConnection::establish(":memory:").unwrap(); + + let e = crate::sql_query("SELECT '?'") + .bind::("foo") + .execute(&mut conn); + + assert!(e.is_err()); + let e = e.unwrap_err(); + if let crate::result::Error::DatabaseError(crate::result::DatabaseErrorKind::Unknown, m) = e + { + assert_eq!(m.message(), "column index out of range"); + } else { + panic!("Wrong error returned"); + } + } +} +*/ diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs new file mode 100644 index 000000000..9b11e0c95 --- /dev/null +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -0,0 +1,220 @@ +use wasm_bindgen::{prelude::*, JsValue}; + +/* +/// Simple Connection +#[wasm_bindgen(module = "/src/package.js")] +extern "C" { + #[wasm_bindgen(catch)] + pub fn batch_execute(database: &JsValue, query: &str) -> Result<(), JsValue>; + + #[wasm_bindgen(catch)] + pub async fn establish(database_url: &str) -> Result; +} +*/ + +/* once https://github.com/rust-lang/rust/issues/128183 is merged this would work +pub mod consts { + pub const SQLITE_INTEGER: i32 = super::SQLITE_INTEGER; +} +*/ + +// Constants +#[wasm_bindgen(module = "/src/wa-sqlite-diesel-bundle.js")] +extern "C" { + pub static SQLITE_DONE: i32; + pub static SQLITE_ROW: i32; + + // Fundamental datatypes. + // https://www.sqlite.org/c3ref/c_blob.html + pub static SQLITE_INTEGER: i32; + pub static SQLITE_FLOAT: i32; + pub static SQLITE_TEXT: i32; + pub static SQLITE_BLOB: i32; + pub static SQLITE_NULL: i32; +} + +// WASM is ran in the browser `main thread`. Tokio is only a single-threaded runtime. +// We need SQLite available globally, so this should be ok until we get threads with WASI or +// something. At which point we can (hopefully) use multi-threaded async runtime to block the +// thread and get SQLite. +unsafe impl Send for SQLite {} +unsafe impl Sync for SQLite {} + +/// Direct Shim for wa-sqlite +#[wasm_bindgen(module = "/src/wa-sqlite-diesel-bundle.js")] +extern "C" { + pub type SQLite; + #[derive(Debug, Clone)] + pub type SQLiteCompatibleType; + // pub type SqlitePrepareOptions; + + #[wasm_bindgen(constructor)] + pub fn new(module: JsValue) -> SQLite; + + #[wasm_bindgen(static_method_of = SQLite)] + pub async fn wasm_module() -> JsValue; + + #[wasm_bindgen(method)] + pub fn result_text(this: &SQLite, context: i32, value: String); + + #[wasm_bindgen(method)] + pub fn result_int(this: &SQLite, context: i32, value: i32); + + #[wasm_bindgen(method)] + pub fn result_int64(this: &SQLite, context: i32, value: i64); + + #[wasm_bindgen(method)] + pub fn result_double(this: &SQLite, context: i32, value: f64); + + #[wasm_bindgen(method)] + pub fn result_blob(this: &SQLite, context: i32, value: Vec); + + #[wasm_bindgen(method)] + pub fn result_null(this: &SQLite, context: i32); + + #[wasm_bindgen(method, catch)] + pub fn bind( + this: &SQLite, + stmt: &JsValue, + idx: i32, + value: SQLiteCompatibleType, + ) -> Result; + /* + #[wasm_bindgen(method, catch)] + pub fn bind_blob( + this: &SQLite, + stmt: &JsValue, + idx: i32, + value: Vec, + ) -> Result; + + // JsValue here is an interesting type that needs to be ported in order to make use of this + // but not currently using it. + + #[wasm_bindgen(method, catch)] + pub fn bind_collection( + this: &SQLite, + stmt: &JsValue, + bindings: JsValue, + ) -> Result; + + #[wasm_bindgen(method, catch)] + pub fn bind_double(this: &SQLite, stmt: &JsValue, idx: i32, value: f64) + -> Result; + + #[wasm_bindgen(method, catch)] + pub fn bind_int(this: &SQLite, stmt: &JsValue, idx: i32, value: i32) -> Result; + + #[wasm_bindgen(method, catch)] + pub fn bind_int64(this: &SQLite, stmt: &JsValue, idx: i32, value: i64) -> Result; + + #[wasm_bindgen(method, catch)] + pub fn bind_null(this: &SQLite, stmt: &JsValue, idx: i32) -> Result; + */ + #[wasm_bindgen(method)] + pub fn bind_parameter_count(this: &SQLite, stmt: &JsValue) -> i32; + + #[wasm_bindgen(method)] + pub fn bind_parameter_name(this: &SQLite, stmt: &JsValue, idx: i32) -> String; + + #[wasm_bindgen(method, catch)] + pub fn bind_text(this: &SQLite, stmt: &JsValue, idx: i32, value: &str) -> Result; + + #[wasm_bindgen(method, catch)] + pub async fn reset(this: &SQLite, stmt: &JsValue) -> Result; + + #[wasm_bindgen(method)] + pub fn value(this: &SQLite, pValue: &JsValue) -> SQLiteCompatibleType; + + #[wasm_bindgen(method)] + pub fn value_dup(this: &SQLite, pValue: &JsValue) -> SQLiteCompatibleType; + + #[wasm_bindgen(method)] + pub fn value_blob(this: &SQLite, pValue: &JsValue) -> Vec; + + #[wasm_bindgen(method)] + pub fn value_bytes(this: &SQLite, pValue: &JsValue) -> i32; + + #[wasm_bindgen(method)] + pub fn value_double(this: &SQLite, pValue: &JsValue) -> f64; + + #[wasm_bindgen(method)] + pub fn value_int(this: &SQLite, pValue: &JsValue) -> i32; + + #[wasm_bindgen(method)] + pub fn value_int64(this: &SQLite, pValue: &JsValue) -> i64; + + // TODO: If wasm-bindgen allows returning references, could return &str + #[wasm_bindgen(method)] + pub fn value_text(this: &SQLite, pValue: &JsValue) -> String; + + #[wasm_bindgen(method)] + pub fn value_type(this: &SQLite, pValue: &JsValue) -> i32; + + #[wasm_bindgen(method, catch)] + pub async fn open_v2( + this: &SQLite, + database_url: &str, + iflags: Option, + ) -> Result; + + #[wasm_bindgen(method, catch)] + pub async fn exec(this: &SQLite, database: &JsValue, query: &str) -> Result<(), JsValue>; + + #[wasm_bindgen(method, catch)] + pub fn finalize(this: &SQLite, stmt: &JsValue) -> Result<(), JsValue>; + + #[wasm_bindgen(method)] + pub fn changes(this: &SQLite, database: &JsValue) -> usize; + + #[wasm_bindgen(method, catch)] + pub async fn step(this: &SQLite, stmt: &JsValue) -> Result; + + #[wasm_bindgen(method, catch)] + pub fn clear_bindings(this: &SQLite, stmt: &JsValue) -> Result; + + #[wasm_bindgen(method, catch)] + pub async fn close(this: &SQLite, database: &JsValue) -> Result<(), JsValue>; + + #[wasm_bindgen(method)] + pub fn column(this: &SQLite, stmt: &JsValue, idx: i32) -> SQLiteCompatibleType; + + #[wasm_bindgen(method, catch)] + pub async fn prepare( + this: &SQLite, + database: &JsValue, + sql: &str, + options: JsValue, + ) -> Result; + + #[wasm_bindgen(method)] + pub fn column_name(this: &SQLite, stmt: &JsValue, idx: i32) -> String; + + #[wasm_bindgen(method)] + pub fn column_count(this: &SQLite, stmt: &JsValue) -> i32; + + #[wasm_bindgen(method, catch)] + pub fn batch_execute(this: &SQLite, database: &JsValue, query: &str) -> Result<(), JsValue>; + + #[wasm_bindgen(method, catch)] + pub fn create_function( + this: &SQLite, + database: &JsValue, + functionName: &str, + n_arg: i32, + textRep: i32, + pApp: i32, //ignored + x_func: Option<&Closure) -> JsValue>>, + x_step: Option<&Closure) -> JsValue>>, + x_final: Option<&Closure>, + ) -> Result<(), JsValue>; + + #[wasm_bindgen(method, catch)] + pub fn register_diesel_sql_functions(this: &SQLite, database: &JsValue) -> Result<(), JsValue>; +} + +impl std::fmt::Debug for SQLite { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "SQLite WASM bridge") + } +} diff --git a/diesel-wasm-sqlite/src/lib.rs b/diesel-wasm-sqlite/src/lib.rs new file mode 100755 index 000000000..ffd6ad0f1 --- /dev/null +++ b/diesel-wasm-sqlite/src/lib.rs @@ -0,0 +1,59 @@ +//! Module for an SQLite backend accesible from the web. +pub mod backend; +pub mod connection; +pub mod ffi; +pub mod query_builder; +pub mod sqlite_types; +pub mod utils; + +#[cfg(not(target_arch = "wasm32"))] +compile_error!("This crate only suports the `wasm32-unknown-unknown` target"); + +use self::ffi::SQLite; +use tokio::sync::OnceCell; +use wasm_bindgen::JsValue; + +pub use backend::{SqliteType, WasmSqlite}; + +/// The SQLite Library +/// this global constant references the loaded SQLite WASM. +static SQLITE: OnceCell = OnceCell::const_new(); + +pub type SQLiteWasm = &'static JsValue; + +pub(crate) async fn get_sqlite() -> &'static SQLite { + SQLITE + .get_or_init(|| async { + let module = SQLite::wasm_module().await; + SQLite::new(module) + }) + .await +} + +pub(crate) fn get_sqlite_unchecked() -> &'static SQLite { + SQLITE.get().expect("SQLite is not initialized") +} + +#[derive(Debug)] +pub struct WasmSqliteError(JsValue); + +impl From for diesel::result::Error { + fn from(value: WasmSqliteError) -> diesel::result::Error { + log::error!("NOT IMPLEMENTED, {:?}", value); + diesel::result::Error::NotFound + } +} + +impl From for diesel::result::ConnectionError { + fn from(value: WasmSqliteError) -> diesel::result::ConnectionError { + log::error!("NOT IMPLEMENTED, {:?}", value); + web_sys::console::log_1(&value.0); + diesel::result::ConnectionError::BadConnection("Not implemented".to_string()) + } +} + +impl From for WasmSqliteError { + fn from(err: JsValue) -> WasmSqliteError { + WasmSqliteError(err) + } +} diff --git a/diesel-wasm-sqlite/src/query_builder/limit_offset.rs b/diesel-wasm-sqlite/src/query_builder/limit_offset.rs new file mode 100644 index 000000000..65740b9fd --- /dev/null +++ b/diesel-wasm-sqlite/src/query_builder/limit_offset.rs @@ -0,0 +1,127 @@ +use crate::WasmSqlite; +use diesel::query_builder::{AstPass, IntoBoxedClause, QueryFragment}; +use diesel::query_builder::{BoxedLimitOffsetClause, LimitOffsetClause}; +use diesel::query_builder::{LimitClause, NoLimitClause}; +use diesel::query_builder::{NoOffsetClause, OffsetClause}; +use diesel::result::QueryResult; + +impl QueryFragment for LimitOffsetClause { + fn walk_ast<'b>(&'b self, _out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + Ok(()) + } +} + +impl QueryFragment for LimitOffsetClause, NoOffsetClause> +where + LimitClause: QueryFragment, +{ + fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + self.limit_clause.walk_ast(out)?; + Ok(()) + } +} + +impl QueryFragment for LimitOffsetClause> +where + OffsetClause: QueryFragment, +{ + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + // Sqlite requires a limit clause in front of any offset clause + // using `LIMIT -1` is the same as not having any limit clause + // https://sqlite.org/lang_select.html + out.push_sql(" LIMIT -1 "); + self.offset_clause.walk_ast(out)?; + Ok(()) + } +} + +impl QueryFragment for LimitOffsetClause, OffsetClause> +where + LimitClause: QueryFragment, + OffsetClause: QueryFragment, +{ + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + self.limit_clause.walk_ast(out.reborrow())?; + self.offset_clause.walk_ast(out.reborrow())?; + Ok(()) + } +} + +impl<'a> QueryFragment for BoxedLimitOffsetClause<'a, WasmSqlite> { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + match (self.limit.as_ref(), self.offset.as_ref()) { + (Some(limit), Some(offset)) => { + limit.walk_ast(out.reborrow())?; + offset.walk_ast(out.reborrow())?; + } + (Some(limit), None) => { + limit.walk_ast(out.reborrow())?; + } + (None, Some(offset)) => { + // See the `QueryFragment` implementation for `LimitOffsetClause` for details. + out.push_sql(" LIMIT -1 "); + offset.walk_ast(out.reborrow())?; + } + (None, None) => {} + } + Ok(()) + } +} + +// Have explicit impls here because we need to set `Some`/`None` for the clauses +// correspondingly, otherwise we cannot match on it in the `QueryFragment` impl +// above +impl<'a> IntoBoxedClause<'a, WasmSqlite> for LimitOffsetClause { + type BoxedClause = BoxedLimitOffsetClause<'a, WasmSqlite>; + + fn into_boxed(self) -> Self::BoxedClause { + BoxedLimitOffsetClause { + limit: None, + offset: None, + } + } +} + +impl<'a, L> IntoBoxedClause<'a, WasmSqlite> for LimitOffsetClause, NoOffsetClause> +where + L: QueryFragment + Send + 'a, +{ + type BoxedClause = BoxedLimitOffsetClause<'a, WasmSqlite>; + + fn into_boxed(self) -> Self::BoxedClause { + BoxedLimitOffsetClause { + limit: Some(Box::new(self.limit_clause)), + offset: None, + } + } +} + +impl<'a, O> IntoBoxedClause<'a, WasmSqlite> for LimitOffsetClause> +where + O: QueryFragment + Send + 'a, +{ + type BoxedClause = BoxedLimitOffsetClause<'a, WasmSqlite>; + + fn into_boxed(self) -> Self::BoxedClause { + BoxedLimitOffsetClause { + limit: None, + offset: Some(Box::new(self.offset_clause)), + } + } +} + +impl<'a, L, O> IntoBoxedClause<'a, WasmSqlite> + for LimitOffsetClause, OffsetClause> +where + L: QueryFragment + Send + 'a, + O: QueryFragment + Send + 'a, +{ + type BoxedClause = BoxedLimitOffsetClause<'a, WasmSqlite>; + + fn into_boxed(self) -> Self::BoxedClause { + BoxedLimitOffsetClause { + limit: Some(Box::new(self.limit_clause)), + offset: Some(Box::new(self.offset_clause)), + } + } +} diff --git a/diesel-wasm-sqlite/src/query_builder/mod.rs b/diesel-wasm-sqlite/src/query_builder/mod.rs new file mode 100644 index 000000000..8bf48119b --- /dev/null +++ b/diesel-wasm-sqlite/src/query_builder/mod.rs @@ -0,0 +1,44 @@ +//! The SQLite query builder + +use super::backend::WasmSqlite; +use diesel::query_builder::QueryBuilder; +use diesel::result::QueryResult; + +mod limit_offset; +mod query_fragment_impls; +mod returning; + +/// Constructs SQL queries for use with the SQLite backend +#[allow(missing_debug_implementations)] +#[derive(Default)] +pub struct SqliteQueryBuilder { + sql: String, +} + +impl SqliteQueryBuilder { + /// Construct a new query builder with an empty query + pub fn new() -> Self { + SqliteQueryBuilder::default() + } +} + +impl QueryBuilder for SqliteQueryBuilder { + fn push_sql(&mut self, sql: &str) { + self.sql.push_str(sql); + } + + fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> { + self.push_sql("`"); + self.push_sql(&identifier.replace('`', "``")); + self.push_sql("`"); + Ok(()) + } + + fn push_bind_param(&mut self) { + self.push_sql("?"); + } + + fn finish(self) -> String { + self.sql + } +} diff --git a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs new file mode 100644 index 000000000..4d840529e --- /dev/null +++ b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs @@ -0,0 +1,42 @@ +/* +// use diesel::query_builder::into_conflict_clause::OnConflictSelectWrapper; +// use diesel::query_builder::where_clause::BoxedWhereClause; +use diesel::query_builder::AstPass; +use diesel::query_builder::BoxedSelectStatement; +use diesel::query_builder::QueryFragment; +use diesel::query_builder::SelectStatement; +// use diesel::query_builder::WhereClause; +use crate::storage::wasm_sqlite::WasmSqlite; +use diesel::result::QueryResult; + +// The corresponding impl for`NoWhereClause` is missing because of +// https://www.sqlite.org/lang_UPSERT.html (Parsing Ambiguity) +impl QueryFragment + for OnConflictSelectWrapper, O, LOf, G, H, LC>> +where + SelectStatement, O, LOf, G, H, LC>: QueryFragment, +{ + fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + self.0.walk_ast(out) + } +} + +// #[cfg(feature = "sqlite")] +impl<'a, ST, QS, GB> QueryFragment + for OnConflictSelectWrapper> +where + BoxedSelectStatement<'a, ST, QS, WasmSqlite, GB>: QueryFragment, + QS: QueryFragment, +{ + fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + // https://www.sqlite.org/lang_UPSERT.html (Parsing Ambiguity) + self.0.build_query(pass, |where_clause, mut pass| { + match where_clause { + BoxedWhereClause::None => pass.push_sql(" WHERE 1=1 "), + w => w.walk_ast(pass.reborrow())?, + } + Ok(()) + }) + } +} +*/ diff --git a/diesel-wasm-sqlite/src/query_builder/returning.rs b/diesel-wasm-sqlite/src/query_builder/returning.rs new file mode 100644 index 000000000..055cab509 --- /dev/null +++ b/diesel-wasm-sqlite/src/query_builder/returning.rs @@ -0,0 +1,16 @@ +use crate::backend::{SqliteReturningClause, WasmSqlite}; +use diesel::query_builder::ReturningClause; +use diesel::query_builder::{AstPass, QueryFragment}; +use diesel::result::QueryResult; +/* +impl QueryFragment for ReturningClause +where + Expr: QueryFragment, +{ + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + out.skip_from(true); + out.push_sql(" RETURNING "); + self.0.walk_ast(out.reborrow())?; + Ok(()) + } +}*/ diff --git a/diesel-wasm-sqlite/src/sqlite_types.rs b/diesel-wasm-sqlite/src/sqlite_types.rs new file mode 100644 index 000000000..1d2066976 --- /dev/null +++ b/diesel-wasm-sqlite/src/sqlite_types.rs @@ -0,0 +1,105 @@ +use super::backend::{SqliteType, WasmSqlite}; +use bitflags::bitflags; +use diesel::sql_types::*; +use serde::{Deserialize, Serialize}; + +//TODO These Database Types are defined in the wasm file and should be imported. +// this is easier for now because of quirks with converting from JsValue to integer within extern +// "C" declaration. + +// result codes +pub const SQLITE_DONE: i32 = 101; +pub const SQLITE_ROW: i32 = 100; + +// Fundamental datatypes. +// https://www.sqlite.org/c3ref/c_blob.html +pub const SQLITE_INTEGER: i32 = 1; +pub const SQLITE_FLOAT: i32 = 2; +pub const SQLITE_TEXT: i32 = 3; +pub const SQLITE_BLOB: i32 = 4; +pub const SQLITE_NULL: i32 = 5; + +/// `SqlitePrepareOptions` imported type +#[derive(Serialize, Deserialize, Default, Clone, Debug, Copy)] +pub struct PrepareOptions { + pub flags: Option, + pub unscoped: Option, +} + +macro_rules! impl_has_sql_type { + ($type:ty, $sql_type:expr) => { + impl HasSqlType<$type> for WasmSqlite { + fn metadata(_: &mut ()) -> SqliteType { + $sql_type + } + } + }; +} + +impl_has_sql_type!(Bool, SqliteType::Integer); +impl_has_sql_type!(SmallInt, SqliteType::SmallInt); +impl_has_sql_type!(Integer, SqliteType::Integer); +impl_has_sql_type!(BigInt, SqliteType::Long); +impl_has_sql_type!(Float, SqliteType::Float); +impl_has_sql_type!(Double, SqliteType::Double); +impl_has_sql_type!(Numeric, SqliteType::Double); +impl_has_sql_type!(Text, SqliteType::Text); +impl_has_sql_type!(Binary, SqliteType::Binary); +impl_has_sql_type!(Date, SqliteType::Text); +impl_has_sql_type!(Time, SqliteType::Text); +impl_has_sql_type!(Timestamp, SqliteType::Text); + +bitflags! { + pub struct SqliteOpenFlags: u32 { + const SQLITE_OPEN_READONLY = 0x00000001; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_READWRITE = 0x00000002; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_CREATE = 0x00000004; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_DELETEONCLOSE = 0x00000008; /* VFS only */ + const SQLITE_OPEN_EXCLUSIVE = 0x00000010; /* VFS only */ + const SQLITE_OPEN_AUTOPROXY = 0x00000020; /* VFS only */ + const SQLITE_OPEN_URI = 0x00000040; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_MEMORY = 0x00000080; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_MAIN_DB = 0x00000100; /* VFS only */ + const SQLITE_OPEN_TEMP_DB = 0x00000200; /* VFS only */ + const SQLITE_OPEN_TRANSIENT_DB = 0x00000400; /* VFS only */ + const SQLITE_OPEN_MAIN_JOURNAL = 0x00000800; /* VFS only */ + const SQLITE_OPEN_TEMP_JOURNAL = 0x00001000; /* VFS only */ + const SQLITE_OPEN_SUBJOURNAL = 0x00002000; /* VFS only */ + const SQLITE_OPEN_SUPER_JOURNAL = 0x00004000; /* VFS only */ + const SQLITE_OPEN_NOMUTEX = 0x00008000; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_FULLMUTEX = 0x00010000; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_SHAREDCACHE = 0x00020000; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_PRIVATECACHE = 0x00040000; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_WAL = 0x00080000; /* VFS only */ + const SQLITE_OPEN_NOFOLLOW = 0x01000000; /* Ok for sqlite3_open_v2() */ + const SQLITE_OPEN_EXRESCODE = 0x02000000; /* Extended result codes */ + } +} + +// SQLite Text Encodings https://www.sqlite.org/capi3ref.html#SQLITE_ANY +bitflags! { + pub struct SqliteFlags: u32 { + const SQLITE_UTF8 = 1; /* IMP: R-37514-35566 */ + const SQLITE_UTF16LE = 2; /* IMP: R-03371-37637 */ + const SQLITE_UTF16BE = 3; /* IMP: R-51971-34154 */ + const SQLITE_UTF16 = 4; /* Use native byte order */ + const SQLITE_ANY = 5; /* Deprecated */ + const SQLITE_UTF16_ALIGNED = 8; /* sqlite3_create_collation only */ + + /// SQLite Function Flags https://www.sqlite.org/capi3ref.html#sqlitedeterministic + const SQLITE_DETERMINISTIC = 0x000000800; + const SQLITE_DIRECTONLY = 0x000080000; + const SQLITE_SUBTYPE = 0x000100000; + const SQLITE_INNOCUOUS = 0x000200000; + const SQLITE_RESULT_SUBTYPE = 0x001000000; + } +} + +// SQLite Prepare Flags https://www.sqlite.org/c3ref/c_prepare_normalize.html#sqlitepreparepersistent +bitflags! { + pub struct SqlitePrepareFlags: i32 { + const SQLITE_PREPARE_PERSISTENT = 0x01; + const SQLITE_PREPARE_NORMALIZE = 0x02; + const SQLITE_PREPARE_NO_VTAB = 0x04; + } +} diff --git a/diesel-wasm-sqlite/src/utils.rs b/diesel-wasm-sqlite/src/utils.rs new file mode 100644 index 000000000..b1d7929dc --- /dev/null +++ b/diesel-wasm-sqlite/src/utils.rs @@ -0,0 +1,10 @@ +pub fn set_panic_hook() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); +} diff --git a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js new file mode 100644 index 000000000..2e16221b9 --- /dev/null +++ b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js @@ -0,0 +1,3050 @@ +// Primary result codes. +// https://www.sqlite.org/rescode.html +const SQLITE_OK = 0; +const SQLITE_ERROR = 1; +const SQLITE_INTERNAL = 2; +const SQLITE_PERM = 3; +const SQLITE_ABORT = 4; +const SQLITE_BUSY = 5; +const SQLITE_LOCKED = 6; +const SQLITE_NOMEM = 7; +const SQLITE_READONLY = 8; +const SQLITE_INTERRUPT = 9; +const SQLITE_IOERR = 10; +const SQLITE_CORRUPT = 11; +const SQLITE_NOTFOUND = 12; +const SQLITE_FULL = 13; +const SQLITE_CANTOPEN = 14; +const SQLITE_PROTOCOL = 15; +const SQLITE_EMPTY = 16; +const SQLITE_SCHEMA = 17; +const SQLITE_TOOBIG = 18; +const SQLITE_CONSTRAINT = 19; +const SQLITE_MISMATCH = 20; +const SQLITE_MISUSE = 21; +const SQLITE_NOLFS = 22; +const SQLITE_AUTH = 23; +const SQLITE_FORMAT = 24; +const SQLITE_RANGE = 25; +const SQLITE_NOTADB = 26; +const SQLITE_NOTICE = 27; +const SQLITE_WARNING = 28; +const SQLITE_ROW = 100; +const SQLITE_DONE = 101; + +// Extended error codes. +const SQLITE_IOERR_ACCESS = 3338; +const SQLITE_IOERR_CHECKRESERVEDLOCK = 3594; +const SQLITE_IOERR_CLOSE = 4106; +const SQLITE_IOERR_DATA = 8202; +const SQLITE_IOERR_DELETE = 2570; +const SQLITE_IOERR_DELETE_NOENT = 5898; +const SQLITE_IOERR_DIR_FSYNC = 1290; +const SQLITE_IOERR_FSTAT = 1802; +const SQLITE_IOERR_FSYNC = 1034; +const SQLITE_IOERR_GETTEMPPATH = 6410; +const SQLITE_IOERR_LOCK = 3850; +const SQLITE_IOERR_NOMEM = 3082; +const SQLITE_IOERR_READ = 266; +const SQLITE_IOERR_RDLOCK = 2314; +const SQLITE_IOERR_SEEK = 5642; +const SQLITE_IOERR_SHORT_READ = 522; +const SQLITE_IOERR_TRUNCATE = 1546; +const SQLITE_IOERR_UNLOCK = 2058; +const SQLITE_IOERR_VNODE = 6922; +const SQLITE_IOERR_WRITE = 778; +const SQLITE_IOERR_BEGIN_ATOMIC = 7434; +const SQLITE_IOERR_COMMIT_ATOMIC = 7690; +const SQLITE_IOERR_ROLLBACK_ATOMIC = 7946; + +// Other extended result codes. +const SQLITE_CONSTRAINT_CHECK = 275; +const SQLITE_CONSTRAINT_COMMITHOOK = 531; +const SQLITE_CONSTRAINT_FOREIGNKEY = 787; +const SQLITE_CONSTRAINT_FUNCTION = 1043; +const SQLITE_CONSTRAINT_NOTNULL = 1299; +const SQLITE_CONSTRAINT_PINNED = 2835; +const SQLITE_CONSTRAINT_PRIMARYKEY = 1555; +const SQLITE_CONSTRAINT_ROWID = 2579; +const SQLITE_CONSTRAINT_TRIGGER = 1811; +const SQLITE_CONSTRAINT_UNIQUE = 2067; +const SQLITE_CONSTRAINT_VTAB = 2323; + +// Open flags. +// https://www.sqlite.org/c3ref/c_open_autoproxy.html +const SQLITE_OPEN_READONLY = 0x00000001; +const SQLITE_OPEN_READWRITE = 0x00000002; +const SQLITE_OPEN_CREATE = 0x00000004; +const SQLITE_OPEN_DELETEONCLOSE = 0x00000008; +const SQLITE_OPEN_EXCLUSIVE = 0x00000010; +const SQLITE_OPEN_AUTOPROXY = 0x00000020; +const SQLITE_OPEN_URI = 0x00000040; +const SQLITE_OPEN_MEMORY = 0x00000080; +const SQLITE_OPEN_MAIN_DB = 0x00000100; +const SQLITE_OPEN_TEMP_DB = 0x00000200; +const SQLITE_OPEN_TRANSIENT_DB = 0x00000400; +const SQLITE_OPEN_MAIN_JOURNAL = 0x00000800; +const SQLITE_OPEN_TEMP_JOURNAL = 0x00001000; +const SQLITE_OPEN_SUBJOURNAL = 0x00002000; +const SQLITE_OPEN_SUPER_JOURNAL = 0x00004000; +const SQLITE_OPEN_NOMUTEX = 0x00008000; +const SQLITE_OPEN_FULLMUTEX = 0x00010000; +const SQLITE_OPEN_SHAREDCACHE = 0x00020000; +const SQLITE_OPEN_PRIVATECACHE = 0x00040000; +const SQLITE_OPEN_WAL = 0x00080000; +const SQLITE_OPEN_NOFOLLOW = 0x01000000; + +// Locking levels. +// https://www.sqlite.org/c3ref/c_lock_exclusive.html +const SQLITE_LOCK_NONE = 0; +const SQLITE_LOCK_SHARED = 1; +const SQLITE_LOCK_RESERVED = 2; +const SQLITE_LOCK_PENDING = 3; +const SQLITE_LOCK_EXCLUSIVE = 4; + +// Device characteristics. +// https://www.sqlite.org/c3ref/c_iocap_atomic.html +const SQLITE_IOCAP_ATOMIC = 0x00000001; +const SQLITE_IOCAP_ATOMIC512 = 0x00000002; +const SQLITE_IOCAP_ATOMIC1K = 0x00000004; +const SQLITE_IOCAP_ATOMIC2K = 0x00000008; +const SQLITE_IOCAP_ATOMIC4K = 0x00000010; +const SQLITE_IOCAP_ATOMIC8K = 0x00000020; +const SQLITE_IOCAP_ATOMIC16K = 0x00000040; +const SQLITE_IOCAP_ATOMIC32K = 0x00000080; +const SQLITE_IOCAP_ATOMIC64K = 0x00000100; +const SQLITE_IOCAP_SAFE_APPEND = 0x00000200; +const SQLITE_IOCAP_SEQUENTIAL = 0x00000400; +const SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN = 0x00000800; +const SQLITE_IOCAP_POWERSAFE_OVERWRITE = 0x00001000; +const SQLITE_IOCAP_IMMUTABLE = 0x00002000; +const SQLITE_IOCAP_BATCH_ATOMIC = 0x00004000; + +// xAccess flags. +// https://www.sqlite.org/c3ref/c_access_exists.html +const SQLITE_ACCESS_EXISTS = 0; +const SQLITE_ACCESS_READWRITE = 1; +const SQLITE_ACCESS_READ = 2; + +// File control opcodes +// https://www.sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlbeginatomicwrite +const SQLITE_FCNTL_LOCKSTATE = 1; +const SQLITE_FCNTL_GET_LOCKPROXYFILE = 2; +const SQLITE_FCNTL_SET_LOCKPROXYFILE = 3; +const SQLITE_FCNTL_LAST_ERRNO = 4; +const SQLITE_FCNTL_SIZE_HINT = 5; +const SQLITE_FCNTL_CHUNK_SIZE = 6; +const SQLITE_FCNTL_FILE_POINTER = 7; +const SQLITE_FCNTL_SYNC_OMITTED = 8; +const SQLITE_FCNTL_WIN32_AV_RETRY = 9; +const SQLITE_FCNTL_PERSIST_WAL = 10; +const SQLITE_FCNTL_OVERWRITE = 11; +const SQLITE_FCNTL_VFSNAME = 12; +const SQLITE_FCNTL_POWERSAFE_OVERWRITE = 13; +const SQLITE_FCNTL_PRAGMA = 14; +const SQLITE_FCNTL_BUSYHANDLER = 15; +const SQLITE_FCNTL_TEMPFILENAME = 16; +const SQLITE_FCNTL_MMAP_SIZE = 18; +const SQLITE_FCNTL_TRACE = 19; +const SQLITE_FCNTL_HAS_MOVED = 20; +const SQLITE_FCNTL_SYNC = 21; +const SQLITE_FCNTL_COMMIT_PHASETWO = 22; +const SQLITE_FCNTL_WIN32_SET_HANDLE = 23; +const SQLITE_FCNTL_WAL_BLOCK = 24; +const SQLITE_FCNTL_ZIPVFS = 25; +const SQLITE_FCNTL_RBU = 26; +const SQLITE_FCNTL_VFS_POINTER = 27; +const SQLITE_FCNTL_JOURNAL_POINTER = 28; +const SQLITE_FCNTL_WIN32_GET_HANDLE = 29; +const SQLITE_FCNTL_PDB = 30; +const SQLITE_FCNTL_BEGIN_ATOMIC_WRITE = 31; +const SQLITE_FCNTL_COMMIT_ATOMIC_WRITE = 32; +const SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE = 33; +const SQLITE_FCNTL_LOCK_TIMEOUT = 34; +const SQLITE_FCNTL_DATA_VERSION = 35; +const SQLITE_FCNTL_SIZE_LIMIT = 36; +const SQLITE_FCNTL_CKPT_DONE = 37; +const SQLITE_FCNTL_RESERVE_BYTES = 38; +const SQLITE_FCNTL_CKPT_START = 39; + +// Fundamental datatypes. +// https://www.sqlite.org/c3ref/c_blob.html +const SQLITE_INTEGER = 1; +const SQLITE_FLOAT = 2; +const SQLITE_TEXT = 3; +const SQLITE_BLOB = 4; +const SQLITE_NULL = 5; + +// Special destructor behavior. +// https://www.sqlite.org/c3ref/c_static.html +const SQLITE_STATIC = 0; +const SQLITE_TRANSIENT = -1; + +// Text encodings. +// https://sqlite.org/c3ref/c_any.html +const SQLITE_UTF8 = 1; /* IMP: R-37514-35566 */ +const SQLITE_UTF16LE = 2; /* IMP: R-03371-37637 */ +const SQLITE_UTF16BE = 3; /* IMP: R-51971-34154 */ +const SQLITE_UTF16 = 4; /* Use native byte order */ + +// Module constraint ops. +const SQLITE_INDEX_CONSTRAINT_EQ = 2; +const SQLITE_INDEX_CONSTRAINT_GT = 4; +const SQLITE_INDEX_CONSTRAINT_LE = 8; +const SQLITE_INDEX_CONSTRAINT_LT = 16; +const SQLITE_INDEX_CONSTRAINT_GE = 32; +const SQLITE_INDEX_CONSTRAINT_MATCH = 64; +const SQLITE_INDEX_CONSTRAINT_LIKE = 65; +const SQLITE_INDEX_CONSTRAINT_GLOB = 66; +const SQLITE_INDEX_CONSTRAINT_REGEXP = 67; +const SQLITE_INDEX_CONSTRAINT_NE = 68; +const SQLITE_INDEX_CONSTRAINT_ISNOT = 69; +const SQLITE_INDEX_CONSTRAINT_ISNOTNULL = 70; +const SQLITE_INDEX_CONSTRAINT_ISNULL = 71; +const SQLITE_INDEX_CONSTRAINT_IS = 72; +const SQLITE_INDEX_CONSTRAINT_FUNCTION = 150; +const SQLITE_INDEX_SCAN_UNIQUE = 1; /* Scan visits at most = 1 row */ + +// Function flags +const SQLITE_DETERMINISTIC = 0x000000800; +const SQLITE_DIRECTONLY = 0x000080000; +const SQLITE_SUBTYPE = 0x000100000; +const SQLITE_INNOCUOUS = 0x000200000; + +// Sync flags +const SQLITE_SYNC_NORMAL = 0x00002; +const SQLITE_SYNC_FULL = 0x00003; +const SQLITE_SYNC_DATAONLY = 0x00010; + +// Authorizer action codes +const SQLITE_CREATE_INDEX = 1; +const SQLITE_CREATE_TABLE = 2; +const SQLITE_CREATE_TEMP_INDEX = 3; +const SQLITE_CREATE_TEMP_TABLE = 4; +const SQLITE_CREATE_TEMP_TRIGGER = 5; +const SQLITE_CREATE_TEMP_VIEW = 6; +const SQLITE_CREATE_TRIGGER = 7; +const SQLITE_CREATE_VIEW = 8; +const SQLITE_DELETE = 9; +const SQLITE_DROP_INDEX = 10; +const SQLITE_DROP_TABLE = 11; +const SQLITE_DROP_TEMP_INDEX = 12; +const SQLITE_DROP_TEMP_TABLE = 13; +const SQLITE_DROP_TEMP_TRIGGER = 14; +const SQLITE_DROP_TEMP_VIEW = 15; +const SQLITE_DROP_TRIGGER = 16; +const SQLITE_DROP_VIEW = 17; +const SQLITE_INSERT = 18; +const SQLITE_PRAGMA = 19; +const SQLITE_READ = 20; +const SQLITE_SELECT = 21; +const SQLITE_TRANSACTION = 22; +const SQLITE_UPDATE = 23; +const SQLITE_ATTACH = 24; +const SQLITE_DETACH = 25; +const SQLITE_ALTER_TABLE = 26; +const SQLITE_REINDEX = 27; +const SQLITE_ANALYZE = 28; +const SQLITE_CREATE_VTABLE = 29; +const SQLITE_DROP_VTABLE = 30; +const SQLITE_FUNCTION = 31; +const SQLITE_SAVEPOINT = 32; +const SQLITE_COPY = 0; +const SQLITE_RECURSIVE = 33; + +// Authorizer return codes +const SQLITE_DENY = 1; +const SQLITE_IGNORE = 2; + +// Limit categories +const SQLITE_LIMIT_LENGTH = 0; +const SQLITE_LIMIT_SQL_LENGTH = 1; +const SQLITE_LIMIT_COLUMN = 2; +const SQLITE_LIMIT_EXPR_DEPTH = 3; +const SQLITE_LIMIT_COMPOUND_SELECT = 4; +const SQLITE_LIMIT_VDBE_OP = 5; +const SQLITE_LIMIT_FUNCTION_ARG = 6; +const SQLITE_LIMIT_ATTACHED = 7; +const SQLITE_LIMIT_LIKE_PATTERN_LENGTH = 8; +const SQLITE_LIMIT_VARIABLE_NUMBER = 9; +const SQLITE_LIMIT_TRIGGER_DEPTH = 10; +const SQLITE_LIMIT_WORKER_THREADS = 11; + +const SQLITE_PREPARE_PERSISTENT = 0x01; +const SQLITE_PREPARE_NORMALIZED = 0x02; +const SQLITE_PREPARE_NO_VTAB = 0x04; + +// Copyright 2021 Roy T. Hashimoto. All Rights Reserved. + + +const MAX_INT64 = 0x7fffffffffffffffn; +const MIN_INT64 = -0x8000000000000000n; + +const AsyncFunction$1 = Object.getPrototypeOf(async function(){}).constructor; + +class SQLiteError extends Error { + constructor(message, code) { + super(message); + this.code = code; + } +} + +const async = true; + +/** + * Builds a Javascript API from the Emscripten module. This API is still + * low-level and closely corresponds to the C API exported by the module, + * but differs in some specifics like throwing exceptions on errors. + * @param {*} Module SQLite Emscripten module + * @returns {SQLiteAPI} + */ +function Factory(Module) { + /** @type {SQLiteAPI} */ const sqlite3 = {}; + + Module.retryOps = []; + const sqliteFreeAddress = Module._getSqliteFree(); + + // Allocate some space for 32-bit returned values. + const tmp = Module._malloc(8); + const tmpPtr = [tmp, tmp + 4]; + + // Convert a JS string to a C string. sqlite3_malloc is used to allocate + // memory (use sqlite3_free to deallocate). + function createUTF8(s) { + if (typeof s !== 'string') return 0; + const utf8 = new TextEncoder().encode(s); + const zts = Module._sqlite3_malloc(utf8.byteLength + 1); + Module.HEAPU8.set(utf8, zts); + Module.HEAPU8[zts + utf8.byteLength] = 0; + return zts; + } + + /** + * Concatenate 32-bit numbers into a 64-bit (signed) BigInt. + * @param {number} lo32 + * @param {number} hi32 + * @returns {bigint} + */ + function cvt32x2ToBigInt(lo32, hi32) { + return (BigInt(hi32) << 32n) | (BigInt(lo32) & 0xffffffffn); + } + + /** + * Concatenate 32-bit numbers and return as number or BigInt, depending + * on the value. + * @param {number} lo32 + * @param {number} hi32 + * @returns {number|bigint} + */ + const cvt32x2AsSafe = (function() { + const hiMax = BigInt(Number.MAX_SAFE_INTEGER) >> 32n; + const hiMin = BigInt(Number.MIN_SAFE_INTEGER) >> 32n; + + return function(lo32, hi32) { + if (hi32 > hiMax || hi32 < hiMin) { + // Can't be expressed as a Number so use BigInt. + return cvt32x2ToBigInt(lo32, hi32); + } else { + // Combine the upper and lower 32-bit numbers. The complication is + // that lo32 is a signed integer which makes manipulating its bits + // a little tricky - the sign bit gets handled separately. + return (hi32 * 0x100000000) + (lo32 & 0x7fffffff) - (lo32 & 0x80000000); + } + } + })(); + + const databases = new Set(); + function verifyDatabase(db) { + if (!databases.has(db)) { + throw new SQLiteError('not a database', SQLITE_MISUSE); + } + } + + const mapStmtToDB = new Map(); + function verifyStatement(stmt) { + if (!mapStmtToDB.has(stmt)) { + throw new SQLiteError('not a statement', SQLITE_MISUSE); + } + } + + sqlite3.bind_collection = function(stmt, bindings) { + verifyStatement(stmt); + const isArray = Array.isArray(bindings); + const nBindings = sqlite3.bind_parameter_count(stmt); + for (let i = 1; i <= nBindings; ++i) { + const key = isArray ? i - 1 : sqlite3.bind_parameter_name(stmt, i); + const value = bindings[key]; + if (value !== undefined) { + sqlite3.bind(stmt, i, value); + } + } + return SQLITE_OK; + }; + + sqlite3.bind = function(stmt, i, value) { + verifyStatement(stmt); + switch (typeof value) { + case 'number': + if (value === (value | 0)) { + return sqlite3.bind_int(stmt, i, value); + } else { + return sqlite3.bind_double(stmt, i, value); + } + case 'string': + return sqlite3.bind_text(stmt, i, value); + default: + if (value instanceof Uint8Array || Array.isArray(value)) { + return sqlite3.bind_blob(stmt, i, value); + } else if (value === null) { + return sqlite3.bind_null(stmt, i); + } else if (typeof value === 'bigint') { + return sqlite3.bind_int64(stmt, i, value); + } else if (value === undefined) { + // Existing binding (or NULL) will be used. + return SQLITE_NOTICE; + } else { + console.warn('unknown binding converted to null', value); + return sqlite3.bind_null(stmt, i); + } + } + }; + + sqlite3.bind_blob = (function() { + const fname = 'sqlite3_bind_blob'; + const f = Module.cwrap(fname, ...decl('nnnnn:n')); + return function(stmt, i, value) { + verifyStatement(stmt); + // @ts-ignore + const byteLength = value.byteLength ?? value.length; + const ptr = Module._sqlite3_malloc(byteLength); + Module.HEAPU8.subarray(ptr).set(value); + const result = f(stmt, i, ptr, byteLength, sqliteFreeAddress); + return check(fname, result, mapStmtToDB.get(stmt)); + }; + })(); + + sqlite3.bind_parameter_count = (function() { + const fname = 'sqlite3_bind_parameter_count'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(stmt) { + verifyStatement(stmt); + const result = f(stmt); + return result; + }; + })(); + + sqlite3.bind_double = (function() { + const fname = 'sqlite3_bind_double'; + const f = Module.cwrap(fname, ...decl('nnn:n')); + return function(stmt, i, value) { + verifyStatement(stmt); + const result = f(stmt, i, value); + return check(fname, result, mapStmtToDB.get(stmt)); + }; + })(); + + sqlite3.bind_int = (function() { + const fname = 'sqlite3_bind_int'; + const f = Module.cwrap(fname, ...decl('nnn:n')); + return function(stmt, i, value) { + verifyStatement(stmt); + if (value > 0x7fffffff || value < -0x80000000) return SQLITE_RANGE; + + const result = f(stmt, i, value); + return check(fname, result, mapStmtToDB.get(stmt)); + }; + })(); + + sqlite3.bind_int64 = (function() { + const fname = 'sqlite3_bind_int64'; + const f = Module.cwrap(fname, ...decl('nnnn:n')); + return function(stmt, i, value) { + verifyStatement(stmt); + if (value > MAX_INT64 || value < MIN_INT64) return SQLITE_RANGE; + + const lo32 = value & 0xffffffffn; + const hi32 = value >> 32n; + const result = f(stmt, i, Number(lo32), Number(hi32)); + return check(fname, result, mapStmtToDB.get(stmt)); + }; + })(); + + sqlite3.bind_null = (function() { + const fname = 'sqlite3_bind_null'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(stmt, i) { + verifyStatement(stmt); + const result = f(stmt, i); + return check(fname, result, mapStmtToDB.get(stmt)); + }; + })(); + + sqlite3.bind_parameter_name = (function() { + const fname = 'sqlite3_bind_parameter_name'; + const f = Module.cwrap(fname, ...decl('n:s')); + return function(stmt, i) { + verifyStatement(stmt); + const result = f(stmt, i); + return result; + }; + })(); + + sqlite3.bind_text = (function() { + const fname = 'sqlite3_bind_text'; + const f = Module.cwrap(fname, ...decl('nnnnn:n')); + return function(stmt, i, value) { + verifyStatement(stmt); + const ptr = createUTF8(value); + const result = f(stmt, i, ptr, -1, sqliteFreeAddress); + return check(fname, result, mapStmtToDB.get(stmt)); + }; + })(); + + sqlite3.changes = (function() { + const fname = 'sqlite3_changes'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(db) { + verifyDatabase(db); + const result = f(db); + return result; + }; + })(); + + sqlite3.close = (function() { + const fname = 'sqlite3_close'; + const f = Module.cwrap(fname, ...decl('n:n'), { async }); + return async function(db) { + verifyDatabase(db); + const result = await f(db); + databases.delete(db); + return check(fname, result, db); + }; + })(); + + sqlite3.column = function(stmt, iCol) { + verifyStatement(stmt); + const type = sqlite3.column_type(stmt, iCol); + switch (type) { + case SQLITE_BLOB: + return sqlite3.column_blob(stmt, iCol); + case SQLITE_FLOAT: + return sqlite3.column_double(stmt, iCol); + case SQLITE_INTEGER: + const lo32 = sqlite3.column_int(stmt, iCol); + const hi32 = Module.getTempRet0(); + return cvt32x2AsSafe(lo32, hi32); + case SQLITE_NULL: + return null; + case SQLITE_TEXT: + return sqlite3.column_text(stmt, iCol); + default: + throw new SQLiteError('unknown type', type); + } + }; + + sqlite3.column_blob = (function() { + const fname = 'sqlite3_column_blob'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(stmt, iCol) { + verifyStatement(stmt); + const nBytes = sqlite3.column_bytes(stmt, iCol); + const address = f(stmt, iCol); + const result = Module.HEAPU8.subarray(address, address + nBytes); + return result; + }; + })(); + + sqlite3.column_bytes = (function() { + const fname = 'sqlite3_column_bytes'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(stmt, iCol) { + verifyStatement(stmt); + const result = f(stmt, iCol); + return result; + }; + })(); + + sqlite3.column_count = (function() { + const fname = 'sqlite3_column_count'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(stmt) { + verifyStatement(stmt); + const result = f(stmt); + return result; + }; + })(); + + sqlite3.column_double = (function() { + const fname = 'sqlite3_column_double'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(stmt, iCol) { + verifyStatement(stmt); + const result = f(stmt, iCol); + return result; + }; + })(); + + sqlite3.column_int = (function() { + // Retrieve int64 but use only the lower 32 bits. The upper 32-bits are + // accessible with Module.getTempRet0(). + const fname = 'sqlite3_column_int64'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(stmt, iCol) { + verifyStatement(stmt); + const result = f(stmt, iCol); + return result; + }; + })(); + + sqlite3.column_int64 = (function() { + const fname = 'sqlite3_column_int64'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(stmt, iCol) { + verifyStatement(stmt); + const lo32 = f(stmt, iCol); + const hi32 = Module.getTempRet0(); + const result = cvt32x2ToBigInt(lo32, hi32); + return result; + }; + })(); + + sqlite3.column_name = (function() { + const fname = 'sqlite3_column_name'; + const f = Module.cwrap(fname, ...decl('nn:s')); + return function(stmt, iCol) { + verifyStatement(stmt); + const result = f(stmt, iCol); + return result; + }; + })(); + + sqlite3.column_names = function(stmt) { + const columns = []; + const nColumns = sqlite3.column_count(stmt); + for (let i = 0; i < nColumns; ++i) { + columns.push(sqlite3.column_name(stmt, i)); + } + return columns; + }; + + sqlite3.column_text = (function() { + const fname = 'sqlite3_column_text'; + const f = Module.cwrap(fname, ...decl('nn:s')); + return function(stmt, iCol) { + verifyStatement(stmt); + const result = f(stmt, iCol); + return result; + }; + })(); + + sqlite3.column_type = (function() { + const fname = 'sqlite3_column_type'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(stmt, iCol) { + verifyStatement(stmt); + const result = f(stmt, iCol); + return result; + }; + })(); + + sqlite3.create_function = function(db, zFunctionName, nArg, eTextRep, pApp, xFunc, xStep, xFinal) { + verifyDatabase(db); + + // Convert SQLite callback arguments to JavaScript-friendly arguments. + function adapt(f) { + return f instanceof AsyncFunction$1 ? + (async (ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))) : + ((ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))); + } + + const result = Module.create_function( + db, + zFunctionName, + nArg, + eTextRep, + pApp, + xFunc && adapt(xFunc), + xStep && adapt(xStep), + xFinal); + return check('sqlite3_create_function', result, db); + }; + + sqlite3.data_count = (function() { + const fname = 'sqlite3_data_count'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(stmt) { + verifyStatement(stmt); + const result = f(stmt); + return result; + }; + })(); + + sqlite3.exec = async function(db, sql, callback) { + for await (const stmt of sqlite3.statements(db, sql)) { + let columns; + while (await sqlite3.step(stmt) === SQLITE_ROW) { + if (callback) { + columns = columns ?? sqlite3.column_names(stmt); + const row = sqlite3.row(stmt); + await callback(row, columns); + } + } + } + return SQLITE_OK; + }; + + sqlite3.finalize = (function() { + const fname = 'sqlite3_finalize'; + const f = Module.cwrap(fname, ...decl('n:n'), { async }); + return async function(stmt) { + const result = await f(stmt); + mapStmtToDB.delete(stmt); + + // Don't throw on error here. Typically the error has already been + // thrown and finalize() is part of the cleanup. + return result; + }; + })(); + + sqlite3.get_autocommit = (function() { + const fname = 'sqlite3_get_autocommit'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(db) { + const result = f(db); + return result; + }; + })(); + + sqlite3.libversion = (function() { + const fname = 'sqlite3_libversion'; + const f = Module.cwrap(fname, ...decl(':s')); + return function() { + const result = f(); + return result; + }; + })(); + + sqlite3.libversion_number = (function() { + const fname = 'sqlite3_libversion_number'; + const f = Module.cwrap(fname, ...decl(':n')); + return function() { + const result = f(); + return result; + }; + })(); + + sqlite3.limit = (function() { + const fname = 'sqlite3_limit'; + const f = Module.cwrap(fname, ...decl('nnn:n')); + return function(db, id, newVal) { + const result = f(db, id, newVal); + return result; + }; + })(); + + sqlite3.open_v2 = (function() { + const fname = 'sqlite3_open_v2'; + const f = Module.cwrap(fname, ...decl('snnn:n'), { async }); + return async function(zFilename, flags, zVfs) { + flags = flags || SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE; + zVfs = createUTF8(zVfs); + try { + // Allow retry operations. + const rc = await retry(() => f(zFilename, tmpPtr[0], flags, zVfs)); + + const db = Module.getValue(tmpPtr[0], '*'); + databases.add(db); + + Module.ccall('RegisterExtensionFunctions', 'void', ['number'], [db]); + check(fname, rc); + return db; + } finally { + Module._sqlite3_free(zVfs); + } + }; + })(); + + sqlite3.progress_handler = function(db, nProgressOps, handler, userData) { + verifyDatabase(db); + Module.progress_handler(db, nProgressOps, handler, userData); + }; + sqlite3.reset = (function() { + const fname = 'sqlite3_reset'; + const f = Module.cwrap(fname, ...decl('n:n'), { async }); + return async function(stmt) { + verifyStatement(stmt); + const result = await f(stmt); + return check(fname, result, mapStmtToDB.get(stmt)); + }; + })(); + + sqlite3.result = function(context, value) { + switch (typeof value) { + case 'number': + if (value === (value | 0)) { + sqlite3.result_int(context, value); + } else { + sqlite3.result_double(context, value); + } + break; + case 'string': + sqlite3.result_text(context, value); + break; + default: + if (value instanceof Uint8Array || Array.isArray(value)) { + sqlite3.result_blob(context, value); + } else if (value === null) { + sqlite3.result_null(context); + } else if (typeof value === 'bigint') { + return sqlite3.result_int64(context, value); + } else { + console.warn('unknown result converted to null', value); + sqlite3.result_null(context); + } + break; + } + + }; + + sqlite3.result_blob = (function() { + const fname = 'sqlite3_result_blob'; + const f = Module.cwrap(fname, ...decl('nnnn:n')); + return function(context, value) { + // @ts-ignore + const byteLength = value.byteLength ?? value.length; + const ptr = Module._sqlite3_malloc(byteLength); + Module.HEAPU8.subarray(ptr).set(value); + f(context, ptr, byteLength, sqliteFreeAddress); // void return + }; + })(); + + sqlite3.result_double = (function() { + const fname = 'sqlite3_result_double'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(context, value) { + f(context, value); // void return + }; + })(); + + sqlite3.result_int = (function() { + const fname = 'sqlite3_result_int'; + const f = Module.cwrap(fname, ...decl('nn:n')); + return function(context, value) { + f(context, value); // void return + }; + })(); + + sqlite3.result_int64 = (function() { + const fname = 'sqlite3_result_int64'; + const f = Module.cwrap(fname, ...decl('nnn:n')); + return function(context, value) { + if (value > MAX_INT64 || value < MIN_INT64) return SQLITE_RANGE; + + const lo32 = value & 0xffffffffn; + const hi32 = value >> 32n; + f(context, Number(lo32), Number(hi32)); // void return + }; + })(); + + sqlite3.result_null = (function() { + const fname = 'sqlite3_result_null'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(context) { + f(context); // void return + }; + })(); + + sqlite3.result_text = (function() { + const fname = 'sqlite3_result_text'; + const f = Module.cwrap(fname, ...decl('nnnn:n')); + return function(context, value) { + const ptr = createUTF8(value); + f(context, ptr, -1, sqliteFreeAddress); // void return + }; + })(); + + sqlite3.row = function(stmt) { + const row = []; + const nColumns = sqlite3.data_count(stmt); + for (let i = 0; i < nColumns; ++i) { + const value = sqlite3.column(stmt, i); + + // Copy blob if aliasing volatile WebAssembly memory. This avoids an + // unnecessary copy if users monkey patch column_blob to copy. + // @ts-ignore + row.push(value?.buffer === Module.HEAPU8.buffer ? value.slice() : value); + } + return row; + }; + + sqlite3.set_authorizer = function(db, xAuth, pApp) { + verifyDatabase(db); + + // Convert SQLite callback arguments to JavaScript-friendly arguments. + function cvtArgs(_, iAction, p3, p4, p5, p6) { + return [ + _, + iAction, + Module.UTF8ToString(p3), + Module.UTF8ToString(p4), + Module.UTF8ToString(p5), + Module.UTF8ToString(p6) + ]; + } function adapt(f) { + return f instanceof AsyncFunction$1 ? + (async (_, iAction, p3, p4, p5, p6) => f(cvtArgs(_, iAction, p3, p4, p5, p6))) : + ((_, iAction, p3, p4, p5, p6) => f(cvtArgs(_, iAction, p3, p4, p5, p6))); + } + + const result = Module.set_authorizer(db, adapt(xAuth), pApp); + return check('sqlite3_set_authorizer', result, db); + }; + sqlite3.sql = (function() { + const fname = 'sqlite3_sql'; + const f = Module.cwrap(fname, ...decl('n:s')); + return function(stmt) { + verifyStatement(stmt); + const result = f(stmt); + return result; + }; + })(); + + sqlite3.statements = function(db, sql, options = {}) { + const prepare = Module.cwrap( + 'sqlite3_prepare_v3', + 'number', + ['number', 'number', 'number', 'number', 'number', 'number'], + { async: true }); + + return (async function*() { + const onFinally = []; + try { + // Encode SQL string to UTF-8. + const utf8 = new TextEncoder().encode(sql); + + // Copy encoded string to WebAssembly memory. The SQLite docs say + // zero-termination is a minor optimization so add room for that. + // Also add space for the statement handle and SQL tail pointer. + const allocSize = utf8.byteLength - (utf8.byteLength % 4) + 12; + const pzHead = Module._sqlite3_malloc(allocSize); + const pzEnd = pzHead + utf8.byteLength + 1; + onFinally.push(() => Module._sqlite3_free(pzHead)); + Module.HEAPU8.set(utf8, pzHead); + Module.HEAPU8[pzEnd - 1] = 0; + + // Use extra space for the statement handle and SQL tail pointer. + const pStmt = pzHead + allocSize - 8; + const pzTail = pzHead + allocSize - 4; + + // Ensure that statement handles are not leaked. + let stmt; + function maybeFinalize() { + if (stmt && !options.unscoped) { + sqlite3.finalize(stmt); + } + stmt = 0; + } + onFinally.push(maybeFinalize); + + // Loop over statements. + Module.setValue(pzTail, pzHead, '*'); + do { + // Reclaim resources for the previous iteration. + maybeFinalize(); + + // Call sqlite3_prepare_v3() for the next statement. + // Allow retry operations. + const zTail = Module.getValue(pzTail, '*'); + const rc = await retry(() => { + return prepare( + db, + zTail, + pzEnd - pzTail, + options.flags || 0, + pStmt, + pzTail); + }); + + if (rc !== SQLITE_OK) { + check('sqlite3_prepare_v3', rc, db); + } + + stmt = Module.getValue(pStmt, '*'); + if (stmt) { + mapStmtToDB.set(stmt, db); + yield stmt; + } + } while (stmt); + } finally { + while (onFinally.length) { + onFinally.pop()(); + } + } + })(); + }; + + sqlite3.step = (function() { + const fname = 'sqlite3_step'; + const f = Module.cwrap(fname, ...decl('n:n'), { async }); + return async function(stmt) { + verifyStatement(stmt); + + // Allow retry operations. + const rc = await retry(() => f(stmt)); + + return check(fname, rc, mapStmtToDB.get(stmt), [SQLITE_ROW, SQLITE_DONE]); + }; + })(); + + sqlite3.value = function(pValue) { + const type = sqlite3.value_type(pValue); + switch (type) { + case SQLITE_BLOB: + return sqlite3.value_blob(pValue); + case SQLITE_FLOAT: + return sqlite3.value_double(pValue); + case SQLITE_INTEGER: + const lo32 = sqlite3.value_int(pValue); + const hi32 = Module.getTempRet0(); + return cvt32x2AsSafe(lo32, hi32); + case SQLITE_NULL: + return null; + case SQLITE_TEXT: + return sqlite3.value_text(pValue); + default: + throw new SQLiteError('unknown type', type); + } + }; + + sqlite3.value_blob = (function() { + const fname = 'sqlite3_value_blob'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(pValue) { + const nBytes = sqlite3.value_bytes(pValue); + const address = f(pValue); + const result = Module.HEAPU8.subarray(address, address + nBytes); + return result; + }; + })(); + + sqlite3.value_bytes = (function() { + const fname = 'sqlite3_value_bytes'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(pValue) { + const result = f(pValue); + return result; + }; + })(); + + sqlite3.value_double = (function() { + const fname = 'sqlite3_value_double'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(pValue) { + const result = f(pValue); + return result; + }; + })(); + + sqlite3.value_int = (function() { + const fname = 'sqlite3_value_int64'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(pValue) { + const result = f(pValue); + return result; + }; + })(); + + sqlite3.value_int64 = (function() { + const fname = 'sqlite3_value_int64'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(pValue) { + const lo32 = f(pValue); + const hi32 = Module.getTempRet0(); + const result = cvt32x2ToBigInt(lo32, hi32); + return result; + }; + })(); + + sqlite3.value_text = (function() { + const fname = 'sqlite3_value_text'; + const f = Module.cwrap(fname, ...decl('n:s')); + return function(pValue) { + const result = f(pValue); + return result; + }; + })(); + + sqlite3.value_type = (function() { + const fname = 'sqlite3_value_type'; + const f = Module.cwrap(fname, ...decl('n:n')); + return function(pValue) { + const result = f(pValue); + return result; + }; + })(); + + sqlite3.vfs_register = function(vfs, makeDefault) { + const result = Module.vfs_register(vfs, makeDefault); + return check('sqlite3_vfs_register', result); + }; + + function check(fname, result, db = null, allowed = [SQLITE_OK]) { + if (allowed.includes(result)) return result; + const message = db ? + Module.ccall('sqlite3_errmsg', 'string', ['number'], [db]) : + fname; + throw new SQLiteError(message, result); + } + + // This function is used to automatically retry failed calls that + // have pending retry operations that should allow the retry to + // succeed. + async function retry(f) { + let rc; + do { + // Wait for all pending retry operations to complete. This is + // normally empty on the first loop iteration. + if (Module.retryOps.length) { + await Promise.all(Module.retryOps); + Module.retryOps = []; + } + + rc = await f(); + + // Retry on failure with new pending retry operations. + } while (rc && Module.retryOps.length); + return rc; + } + + return sqlite3; +} + +// Helper function to use a more compact signature specification. +function decl(s) { + const result = []; + const m = s.match(/([ns@]*):([nsv@])/); + switch (m[2]) { + case 'n': result.push('number'); break; + case 's': result.push('string'); break; + case 'v': result.push(null); break; + } + + const args = []; + for (let c of m[1]) { + switch (c) { + case 'n': args.push('number'); break; + case 's': args.push('string'); break; + } + } + result.push(args); + return result; +} + +var WasmSQLiteLibrary = /*#__PURE__*/Object.freeze({ + __proto__: null, + Factory: Factory, + SQLITE_ABORT: SQLITE_ABORT, + SQLITE_ACCESS_EXISTS: SQLITE_ACCESS_EXISTS, + SQLITE_ACCESS_READ: SQLITE_ACCESS_READ, + SQLITE_ACCESS_READWRITE: SQLITE_ACCESS_READWRITE, + SQLITE_ALTER_TABLE: SQLITE_ALTER_TABLE, + SQLITE_ANALYZE: SQLITE_ANALYZE, + SQLITE_ATTACH: SQLITE_ATTACH, + SQLITE_AUTH: SQLITE_AUTH, + SQLITE_BLOB: SQLITE_BLOB, + SQLITE_BUSY: SQLITE_BUSY, + SQLITE_CANTOPEN: SQLITE_CANTOPEN, + SQLITE_CONSTRAINT: SQLITE_CONSTRAINT, + SQLITE_CONSTRAINT_CHECK: SQLITE_CONSTRAINT_CHECK, + SQLITE_CONSTRAINT_COMMITHOOK: SQLITE_CONSTRAINT_COMMITHOOK, + SQLITE_CONSTRAINT_FOREIGNKEY: SQLITE_CONSTRAINT_FOREIGNKEY, + SQLITE_CONSTRAINT_FUNCTION: SQLITE_CONSTRAINT_FUNCTION, + SQLITE_CONSTRAINT_NOTNULL: SQLITE_CONSTRAINT_NOTNULL, + SQLITE_CONSTRAINT_PINNED: SQLITE_CONSTRAINT_PINNED, + SQLITE_CONSTRAINT_PRIMARYKEY: SQLITE_CONSTRAINT_PRIMARYKEY, + SQLITE_CONSTRAINT_ROWID: SQLITE_CONSTRAINT_ROWID, + SQLITE_CONSTRAINT_TRIGGER: SQLITE_CONSTRAINT_TRIGGER, + SQLITE_CONSTRAINT_UNIQUE: SQLITE_CONSTRAINT_UNIQUE, + SQLITE_CONSTRAINT_VTAB: SQLITE_CONSTRAINT_VTAB, + SQLITE_COPY: SQLITE_COPY, + SQLITE_CORRUPT: SQLITE_CORRUPT, + SQLITE_CREATE_INDEX: SQLITE_CREATE_INDEX, + SQLITE_CREATE_TABLE: SQLITE_CREATE_TABLE, + SQLITE_CREATE_TEMP_INDEX: SQLITE_CREATE_TEMP_INDEX, + SQLITE_CREATE_TEMP_TABLE: SQLITE_CREATE_TEMP_TABLE, + SQLITE_CREATE_TEMP_TRIGGER: SQLITE_CREATE_TEMP_TRIGGER, + SQLITE_CREATE_TEMP_VIEW: SQLITE_CREATE_TEMP_VIEW, + SQLITE_CREATE_TRIGGER: SQLITE_CREATE_TRIGGER, + SQLITE_CREATE_VIEW: SQLITE_CREATE_VIEW, + SQLITE_CREATE_VTABLE: SQLITE_CREATE_VTABLE, + SQLITE_DELETE: SQLITE_DELETE, + SQLITE_DENY: SQLITE_DENY, + SQLITE_DETACH: SQLITE_DETACH, + SQLITE_DETERMINISTIC: SQLITE_DETERMINISTIC, + SQLITE_DIRECTONLY: SQLITE_DIRECTONLY, + SQLITE_DONE: SQLITE_DONE, + SQLITE_DROP_INDEX: SQLITE_DROP_INDEX, + SQLITE_DROP_TABLE: SQLITE_DROP_TABLE, + SQLITE_DROP_TEMP_INDEX: SQLITE_DROP_TEMP_INDEX, + SQLITE_DROP_TEMP_TABLE: SQLITE_DROP_TEMP_TABLE, + SQLITE_DROP_TEMP_TRIGGER: SQLITE_DROP_TEMP_TRIGGER, + SQLITE_DROP_TEMP_VIEW: SQLITE_DROP_TEMP_VIEW, + SQLITE_DROP_TRIGGER: SQLITE_DROP_TRIGGER, + SQLITE_DROP_VIEW: SQLITE_DROP_VIEW, + SQLITE_DROP_VTABLE: SQLITE_DROP_VTABLE, + SQLITE_EMPTY: SQLITE_EMPTY, + SQLITE_ERROR: SQLITE_ERROR, + SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, + SQLITE_FCNTL_BUSYHANDLER: SQLITE_FCNTL_BUSYHANDLER, + SQLITE_FCNTL_CHUNK_SIZE: SQLITE_FCNTL_CHUNK_SIZE, + SQLITE_FCNTL_CKPT_DONE: SQLITE_FCNTL_CKPT_DONE, + SQLITE_FCNTL_CKPT_START: SQLITE_FCNTL_CKPT_START, + SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, + SQLITE_FCNTL_COMMIT_PHASETWO: SQLITE_FCNTL_COMMIT_PHASETWO, + SQLITE_FCNTL_DATA_VERSION: SQLITE_FCNTL_DATA_VERSION, + SQLITE_FCNTL_FILE_POINTER: SQLITE_FCNTL_FILE_POINTER, + SQLITE_FCNTL_GET_LOCKPROXYFILE: SQLITE_FCNTL_GET_LOCKPROXYFILE, + SQLITE_FCNTL_HAS_MOVED: SQLITE_FCNTL_HAS_MOVED, + SQLITE_FCNTL_JOURNAL_POINTER: SQLITE_FCNTL_JOURNAL_POINTER, + SQLITE_FCNTL_LAST_ERRNO: SQLITE_FCNTL_LAST_ERRNO, + SQLITE_FCNTL_LOCKSTATE: SQLITE_FCNTL_LOCKSTATE, + SQLITE_FCNTL_LOCK_TIMEOUT: SQLITE_FCNTL_LOCK_TIMEOUT, + SQLITE_FCNTL_MMAP_SIZE: SQLITE_FCNTL_MMAP_SIZE, + SQLITE_FCNTL_OVERWRITE: SQLITE_FCNTL_OVERWRITE, + SQLITE_FCNTL_PDB: SQLITE_FCNTL_PDB, + SQLITE_FCNTL_PERSIST_WAL: SQLITE_FCNTL_PERSIST_WAL, + SQLITE_FCNTL_POWERSAFE_OVERWRITE: SQLITE_FCNTL_POWERSAFE_OVERWRITE, + SQLITE_FCNTL_PRAGMA: SQLITE_FCNTL_PRAGMA, + SQLITE_FCNTL_RBU: SQLITE_FCNTL_RBU, + SQLITE_FCNTL_RESERVE_BYTES: SQLITE_FCNTL_RESERVE_BYTES, + SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, + SQLITE_FCNTL_SET_LOCKPROXYFILE: SQLITE_FCNTL_SET_LOCKPROXYFILE, + SQLITE_FCNTL_SIZE_HINT: SQLITE_FCNTL_SIZE_HINT, + SQLITE_FCNTL_SIZE_LIMIT: SQLITE_FCNTL_SIZE_LIMIT, + SQLITE_FCNTL_SYNC: SQLITE_FCNTL_SYNC, + SQLITE_FCNTL_SYNC_OMITTED: SQLITE_FCNTL_SYNC_OMITTED, + SQLITE_FCNTL_TEMPFILENAME: SQLITE_FCNTL_TEMPFILENAME, + SQLITE_FCNTL_TRACE: SQLITE_FCNTL_TRACE, + SQLITE_FCNTL_VFSNAME: SQLITE_FCNTL_VFSNAME, + SQLITE_FCNTL_VFS_POINTER: SQLITE_FCNTL_VFS_POINTER, + SQLITE_FCNTL_WAL_BLOCK: SQLITE_FCNTL_WAL_BLOCK, + SQLITE_FCNTL_WIN32_AV_RETRY: SQLITE_FCNTL_WIN32_AV_RETRY, + SQLITE_FCNTL_WIN32_GET_HANDLE: SQLITE_FCNTL_WIN32_GET_HANDLE, + SQLITE_FCNTL_WIN32_SET_HANDLE: SQLITE_FCNTL_WIN32_SET_HANDLE, + SQLITE_FCNTL_ZIPVFS: SQLITE_FCNTL_ZIPVFS, + SQLITE_FLOAT: SQLITE_FLOAT, + SQLITE_FORMAT: SQLITE_FORMAT, + SQLITE_FULL: SQLITE_FULL, + SQLITE_FUNCTION: SQLITE_FUNCTION, + SQLITE_IGNORE: SQLITE_IGNORE, + SQLITE_INDEX_CONSTRAINT_EQ: SQLITE_INDEX_CONSTRAINT_EQ, + SQLITE_INDEX_CONSTRAINT_FUNCTION: SQLITE_INDEX_CONSTRAINT_FUNCTION, + SQLITE_INDEX_CONSTRAINT_GE: SQLITE_INDEX_CONSTRAINT_GE, + SQLITE_INDEX_CONSTRAINT_GLOB: SQLITE_INDEX_CONSTRAINT_GLOB, + SQLITE_INDEX_CONSTRAINT_GT: SQLITE_INDEX_CONSTRAINT_GT, + SQLITE_INDEX_CONSTRAINT_IS: SQLITE_INDEX_CONSTRAINT_IS, + SQLITE_INDEX_CONSTRAINT_ISNOT: SQLITE_INDEX_CONSTRAINT_ISNOT, + SQLITE_INDEX_CONSTRAINT_ISNOTNULL: SQLITE_INDEX_CONSTRAINT_ISNOTNULL, + SQLITE_INDEX_CONSTRAINT_ISNULL: SQLITE_INDEX_CONSTRAINT_ISNULL, + SQLITE_INDEX_CONSTRAINT_LE: SQLITE_INDEX_CONSTRAINT_LE, + SQLITE_INDEX_CONSTRAINT_LIKE: SQLITE_INDEX_CONSTRAINT_LIKE, + SQLITE_INDEX_CONSTRAINT_LT: SQLITE_INDEX_CONSTRAINT_LT, + SQLITE_INDEX_CONSTRAINT_MATCH: SQLITE_INDEX_CONSTRAINT_MATCH, + SQLITE_INDEX_CONSTRAINT_NE: SQLITE_INDEX_CONSTRAINT_NE, + SQLITE_INDEX_CONSTRAINT_REGEXP: SQLITE_INDEX_CONSTRAINT_REGEXP, + SQLITE_INDEX_SCAN_UNIQUE: SQLITE_INDEX_SCAN_UNIQUE, + SQLITE_INNOCUOUS: SQLITE_INNOCUOUS, + SQLITE_INSERT: SQLITE_INSERT, + SQLITE_INTEGER: SQLITE_INTEGER, + SQLITE_INTERNAL: SQLITE_INTERNAL, + SQLITE_INTERRUPT: SQLITE_INTERRUPT, + SQLITE_IOCAP_ATOMIC: SQLITE_IOCAP_ATOMIC, + SQLITE_IOCAP_ATOMIC16K: SQLITE_IOCAP_ATOMIC16K, + SQLITE_IOCAP_ATOMIC1K: SQLITE_IOCAP_ATOMIC1K, + SQLITE_IOCAP_ATOMIC2K: SQLITE_IOCAP_ATOMIC2K, + SQLITE_IOCAP_ATOMIC32K: SQLITE_IOCAP_ATOMIC32K, + SQLITE_IOCAP_ATOMIC4K: SQLITE_IOCAP_ATOMIC4K, + SQLITE_IOCAP_ATOMIC512: SQLITE_IOCAP_ATOMIC512, + SQLITE_IOCAP_ATOMIC64K: SQLITE_IOCAP_ATOMIC64K, + SQLITE_IOCAP_ATOMIC8K: SQLITE_IOCAP_ATOMIC8K, + SQLITE_IOCAP_BATCH_ATOMIC: SQLITE_IOCAP_BATCH_ATOMIC, + SQLITE_IOCAP_IMMUTABLE: SQLITE_IOCAP_IMMUTABLE, + SQLITE_IOCAP_POWERSAFE_OVERWRITE: SQLITE_IOCAP_POWERSAFE_OVERWRITE, + SQLITE_IOCAP_SAFE_APPEND: SQLITE_IOCAP_SAFE_APPEND, + SQLITE_IOCAP_SEQUENTIAL: SQLITE_IOCAP_SEQUENTIAL, + SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN: SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN, + SQLITE_IOERR: SQLITE_IOERR, + SQLITE_IOERR_ACCESS: SQLITE_IOERR_ACCESS, + SQLITE_IOERR_BEGIN_ATOMIC: SQLITE_IOERR_BEGIN_ATOMIC, + SQLITE_IOERR_CHECKRESERVEDLOCK: SQLITE_IOERR_CHECKRESERVEDLOCK, + SQLITE_IOERR_CLOSE: SQLITE_IOERR_CLOSE, + SQLITE_IOERR_COMMIT_ATOMIC: SQLITE_IOERR_COMMIT_ATOMIC, + SQLITE_IOERR_DATA: SQLITE_IOERR_DATA, + SQLITE_IOERR_DELETE: SQLITE_IOERR_DELETE, + SQLITE_IOERR_DELETE_NOENT: SQLITE_IOERR_DELETE_NOENT, + SQLITE_IOERR_DIR_FSYNC: SQLITE_IOERR_DIR_FSYNC, + SQLITE_IOERR_FSTAT: SQLITE_IOERR_FSTAT, + SQLITE_IOERR_FSYNC: SQLITE_IOERR_FSYNC, + SQLITE_IOERR_GETTEMPPATH: SQLITE_IOERR_GETTEMPPATH, + SQLITE_IOERR_LOCK: SQLITE_IOERR_LOCK, + SQLITE_IOERR_NOMEM: SQLITE_IOERR_NOMEM, + SQLITE_IOERR_RDLOCK: SQLITE_IOERR_RDLOCK, + SQLITE_IOERR_READ: SQLITE_IOERR_READ, + SQLITE_IOERR_ROLLBACK_ATOMIC: SQLITE_IOERR_ROLLBACK_ATOMIC, + SQLITE_IOERR_SEEK: SQLITE_IOERR_SEEK, + SQLITE_IOERR_SHORT_READ: SQLITE_IOERR_SHORT_READ, + SQLITE_IOERR_TRUNCATE: SQLITE_IOERR_TRUNCATE, + SQLITE_IOERR_UNLOCK: SQLITE_IOERR_UNLOCK, + SQLITE_IOERR_VNODE: SQLITE_IOERR_VNODE, + SQLITE_IOERR_WRITE: SQLITE_IOERR_WRITE, + SQLITE_LIMIT_ATTACHED: SQLITE_LIMIT_ATTACHED, + SQLITE_LIMIT_COLUMN: SQLITE_LIMIT_COLUMN, + SQLITE_LIMIT_COMPOUND_SELECT: SQLITE_LIMIT_COMPOUND_SELECT, + SQLITE_LIMIT_EXPR_DEPTH: SQLITE_LIMIT_EXPR_DEPTH, + SQLITE_LIMIT_FUNCTION_ARG: SQLITE_LIMIT_FUNCTION_ARG, + SQLITE_LIMIT_LENGTH: SQLITE_LIMIT_LENGTH, + SQLITE_LIMIT_LIKE_PATTERN_LENGTH: SQLITE_LIMIT_LIKE_PATTERN_LENGTH, + SQLITE_LIMIT_SQL_LENGTH: SQLITE_LIMIT_SQL_LENGTH, + SQLITE_LIMIT_TRIGGER_DEPTH: SQLITE_LIMIT_TRIGGER_DEPTH, + SQLITE_LIMIT_VARIABLE_NUMBER: SQLITE_LIMIT_VARIABLE_NUMBER, + SQLITE_LIMIT_VDBE_OP: SQLITE_LIMIT_VDBE_OP, + SQLITE_LIMIT_WORKER_THREADS: SQLITE_LIMIT_WORKER_THREADS, + SQLITE_LOCKED: SQLITE_LOCKED, + SQLITE_LOCK_EXCLUSIVE: SQLITE_LOCK_EXCLUSIVE, + SQLITE_LOCK_NONE: SQLITE_LOCK_NONE, + SQLITE_LOCK_PENDING: SQLITE_LOCK_PENDING, + SQLITE_LOCK_RESERVED: SQLITE_LOCK_RESERVED, + SQLITE_LOCK_SHARED: SQLITE_LOCK_SHARED, + SQLITE_MISMATCH: SQLITE_MISMATCH, + SQLITE_MISUSE: SQLITE_MISUSE, + SQLITE_NOLFS: SQLITE_NOLFS, + SQLITE_NOMEM: SQLITE_NOMEM, + SQLITE_NOTADB: SQLITE_NOTADB, + SQLITE_NOTFOUND: SQLITE_NOTFOUND, + SQLITE_NOTICE: SQLITE_NOTICE, + SQLITE_NULL: SQLITE_NULL, + SQLITE_OK: SQLITE_OK, + SQLITE_OPEN_AUTOPROXY: SQLITE_OPEN_AUTOPROXY, + SQLITE_OPEN_CREATE: SQLITE_OPEN_CREATE, + SQLITE_OPEN_DELETEONCLOSE: SQLITE_OPEN_DELETEONCLOSE, + SQLITE_OPEN_EXCLUSIVE: SQLITE_OPEN_EXCLUSIVE, + SQLITE_OPEN_FULLMUTEX: SQLITE_OPEN_FULLMUTEX, + SQLITE_OPEN_MAIN_DB: SQLITE_OPEN_MAIN_DB, + SQLITE_OPEN_MAIN_JOURNAL: SQLITE_OPEN_MAIN_JOURNAL, + SQLITE_OPEN_MEMORY: SQLITE_OPEN_MEMORY, + SQLITE_OPEN_NOFOLLOW: SQLITE_OPEN_NOFOLLOW, + SQLITE_OPEN_NOMUTEX: SQLITE_OPEN_NOMUTEX, + SQLITE_OPEN_PRIVATECACHE: SQLITE_OPEN_PRIVATECACHE, + SQLITE_OPEN_READONLY: SQLITE_OPEN_READONLY, + SQLITE_OPEN_READWRITE: SQLITE_OPEN_READWRITE, + SQLITE_OPEN_SHAREDCACHE: SQLITE_OPEN_SHAREDCACHE, + SQLITE_OPEN_SUBJOURNAL: SQLITE_OPEN_SUBJOURNAL, + SQLITE_OPEN_SUPER_JOURNAL: SQLITE_OPEN_SUPER_JOURNAL, + SQLITE_OPEN_TEMP_DB: SQLITE_OPEN_TEMP_DB, + SQLITE_OPEN_TEMP_JOURNAL: SQLITE_OPEN_TEMP_JOURNAL, + SQLITE_OPEN_TRANSIENT_DB: SQLITE_OPEN_TRANSIENT_DB, + SQLITE_OPEN_URI: SQLITE_OPEN_URI, + SQLITE_OPEN_WAL: SQLITE_OPEN_WAL, + SQLITE_PERM: SQLITE_PERM, + SQLITE_PRAGMA: SQLITE_PRAGMA, + SQLITE_PREPARE_NORMALIZED: SQLITE_PREPARE_NORMALIZED, + SQLITE_PREPARE_NO_VTAB: SQLITE_PREPARE_NO_VTAB, + SQLITE_PREPARE_PERSISTENT: SQLITE_PREPARE_PERSISTENT, + SQLITE_PROTOCOL: SQLITE_PROTOCOL, + SQLITE_RANGE: SQLITE_RANGE, + SQLITE_READ: SQLITE_READ, + SQLITE_READONLY: SQLITE_READONLY, + SQLITE_RECURSIVE: SQLITE_RECURSIVE, + SQLITE_REINDEX: SQLITE_REINDEX, + SQLITE_ROW: SQLITE_ROW, + SQLITE_SAVEPOINT: SQLITE_SAVEPOINT, + SQLITE_SCHEMA: SQLITE_SCHEMA, + SQLITE_SELECT: SQLITE_SELECT, + SQLITE_STATIC: SQLITE_STATIC, + SQLITE_SUBTYPE: SQLITE_SUBTYPE, + SQLITE_SYNC_DATAONLY: SQLITE_SYNC_DATAONLY, + SQLITE_SYNC_FULL: SQLITE_SYNC_FULL, + SQLITE_SYNC_NORMAL: SQLITE_SYNC_NORMAL, + SQLITE_TEXT: SQLITE_TEXT, + SQLITE_TOOBIG: SQLITE_TOOBIG, + SQLITE_TRANSACTION: SQLITE_TRANSACTION, + SQLITE_TRANSIENT: SQLITE_TRANSIENT, + SQLITE_UPDATE: SQLITE_UPDATE, + SQLITE_UTF16: SQLITE_UTF16, + SQLITE_UTF16BE: SQLITE_UTF16BE, + SQLITE_UTF16LE: SQLITE_UTF16LE, + SQLITE_UTF8: SQLITE_UTF8, + SQLITE_WARNING: SQLITE_WARNING, + SQLiteError: SQLiteError +}); + +// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. + +const DEFAULT_SECTOR_SIZE = 512; + +// Base class for a VFS. +class Base { + name; + mxPathname = 64; + _module; + + /** + * @param {string} name + * @param {object} module + */ + constructor(name, module) { + this.name = name; + this._module = module; + } + + /** + * @returns {void|Promise} + */ + close() { + } + + /** + * @returns {boolean|Promise} + */ + isReady() { + return true; + } + + /** + * Overload in subclasses to indicate which methods are asynchronous. + * @param {string} methodName + * @returns {boolean} + */ + hasAsyncMethod(methodName) { + return false; + } + + /** + * @param {number} pVfs + * @param {number} zName + * @param {number} pFile + * @param {number} flags + * @param {number} pOutFlags + * @returns {number|Promise} + */ + xOpen(pVfs, zName, pFile, flags, pOutFlags) { + return SQLITE_CANTOPEN; + } + + /** + * @param {number} pVfs + * @param {number} zName + * @param {number} syncDir + * @returns {number|Promise} + */ + xDelete(pVfs, zName, syncDir) { + return SQLITE_OK; + } + + /** + * @param {number} pVfs + * @param {number} zName + * @param {number} flags + * @param {number} pResOut + * @returns {number|Promise} + */ + xAccess(pVfs, zName, flags, pResOut) { + return SQLITE_OK; + } + + /** + * @param {number} pVfs + * @param {number} zName + * @param {number} nOut + * @param {number} zOut + * @returns {number|Promise} + */ + xFullPathname(pVfs, zName, nOut, zOut) { + return SQLITE_OK; + } + + /** + * @param {number} pVfs + * @param {number} nBuf + * @param {number} zBuf + * @returns {number|Promise} + */ + xGetLastError(pVfs, nBuf, zBuf) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + xClose(pFile) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} pData + * @param {number} iAmt + * @param {number} iOffsetLo + * @param {number} iOffsetHi + * @returns {number|Promise} + */ + xRead(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} pData + * @param {number} iAmt + * @param {number} iOffsetLo + * @param {number} iOffsetHi + * @returns {number|Promise} + */ + xWrite(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} sizeLo + * @param {number} sizeHi + * @returns {number|Promise} + */ + xTruncate(pFile, sizeLo, sizeHi) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} flags + * @returns {number|Promise} + */ + xSync(pFile, flags) { + return SQLITE_OK; + } + + /** + * + * @param {number} pFile + * @param {number} pSize + * @returns {number|Promise} + */ + xFileSize(pFile, pSize) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} lockType + * @returns {number|Promise} + */ + xLock(pFile, lockType) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} lockType + * @returns {number|Promise} + */ + xUnlock(pFile, lockType) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} pResOut + * @returns {number|Promise} + */ + xCheckReservedLock(pFile, pResOut) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} op + * @param {number} pArg + * @returns {number|Promise} + */ + xFileControl(pFile, op, pArg) { + return SQLITE_NOTFOUND; + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + xSectorSize(pFile) { + return DEFAULT_SECTOR_SIZE; + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + xDeviceCharacteristics(pFile) { + return 0; + } +} + +// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. + +const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; + +// Convenience base class for a JavaScript VFS. +// The raw xOpen, xRead, etc. function signatures receive only C primitives +// which aren't easy to work with. This class provides corresponding calls +// like jOpen, jRead, etc., which receive JavaScript-friendlier arguments +// such as string, Uint8Array, and DataView. +class FacadeVFS extends Base { + /** + * @param {string} name + * @param {object} module + */ + constructor(name, module) { + super(name, module); + } + + /** + * Override to indicate which methods are asynchronous. + * @param {string} methodName + * @returns {boolean} + */ + hasAsyncMethod(methodName) { + // The input argument is a string like "xOpen", so convert to "jOpen". + // Then check if the method exists and is async. + const jMethodName = `j${methodName.slice(1)}`; + return this[jMethodName] instanceof AsyncFunction; + } + + /** + * Return the filename for a file id for use by mixins. + * @param {number} pFile + * @returns {string} + */ + getFilename(pFile) { + throw new Error('unimplemented'); + } + + /** + * @param {string?} filename + * @param {number} pFile + * @param {number} flags + * @param {DataView} pOutFlags + * @returns {number|Promise} + */ + jOpen(filename, pFile, flags, pOutFlags) { + return SQLITE_CANTOPEN; + } + + /** + * @param {string} filename + * @param {number} syncDir + * @returns {number|Promise} + */ + jDelete(filename, syncDir) { + return SQLITE_OK; + } + + /** + * @param {string} filename + * @param {number} flags + * @param {DataView} pResOut + * @returns {number|Promise} + */ + jAccess(filename, flags, pResOut) { + return SQLITE_OK; + } + + /** + * @param {string} filename + * @param {Uint8Array} zOut + * @returns {number|Promise} + */ + jFullPathname(filename, zOut) { + // Copy the filename to the output buffer. + const { read, written } = new TextEncoder().encodeInto(filename, zOut); + if (read < filename.length) return SQLITE_IOERR; + if (written >= zOut.length) return SQLITE_IOERR; + zOut[written] = 0; + return SQLITE_OK; + } + + /** + * @param {Uint8Array} zBuf + * @returns {number|Promise} + */ + jGetLastError(zBuf) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + jClose(pFile) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {Uint8Array} pData + * @param {number} iOffset + * @returns {number|Promise} + */ + jRead(pFile, pData, iOffset) { + pData.fill(0); + return SQLITE_IOERR_SHORT_READ; + } + + /** + * @param {number} pFile + * @param {Uint8Array} pData + * @param {number} iOffset + * @returns {number|Promise} + */ + jWrite(pFile, pData, iOffset) { + return SQLITE_IOERR_WRITE; + } + + /** + * @param {number} pFile + * @param {number} size + * @returns {number|Promise} + */ + jTruncate(pFile, size) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} flags + * @returns {number|Promise} + */ + jSync(pFile, flags) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {DataView} pSize + * @returns {number|Promise} + */ + jFileSize(pFile, pSize) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} lockType + * @returns {number|Promise} + */ + jLock(pFile, lockType) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} lockType + * @returns {number|Promise} + */ + jUnlock(pFile, lockType) { + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {DataView} pResOut + * @returns {number|Promise} + */ + jCheckReservedLock(pFile, pResOut) { + pResOut.setInt32(0, 0, true); + return SQLITE_OK; + } + + /** + * @param {number} pFile + * @param {number} op + * @param {DataView} pArg + * @returns {number|Promise} + */ + jFileControl(pFile, op, pArg) { + return SQLITE_NOTFOUND; + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + jSectorSize(pFile) { + return super.xSectorSize(pFile); + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + jDeviceCharacteristics(pFile) { + return 0; + } + + /** + * @param {number} pVfs + * @param {number} zName + * @param {number} pFile + * @param {number} flags + * @param {number} pOutFlags + * @returns {number|Promise} + */ + xOpen(pVfs, zName, pFile, flags, pOutFlags) { + const filename = this.#decodeFilename(zName, flags); + const pOutFlagsView = this.#makeTypedDataView('Int32', pOutFlags); + this['log']?.('jOpen', filename, pFile, '0x' + flags.toString(16)); + return this.jOpen(filename, pFile, flags, pOutFlagsView); + } + + /** + * @param {number} pVfs + * @param {number} zName + * @param {number} syncDir + * @returns {number|Promise} + */ + xDelete(pVfs, zName, syncDir) { + const filename = this._module.UTF8ToString(zName); + this['log']?.('jDelete', filename, syncDir); + return this.jDelete(filename, syncDir); + } + + /** + * @param {number} pVfs + * @param {number} zName + * @param {number} flags + * @param {number} pResOut + * @returns {number|Promise} + */ + xAccess(pVfs, zName, flags, pResOut) { + const filename = this._module.UTF8ToString(zName); + const pResOutView = this.#makeTypedDataView('Int32', pResOut); + this['log']?.('jAccess', filename, flags); + return this.jAccess(filename, flags, pResOutView); + } + + /** + * @param {number} pVfs + * @param {number} zName + * @param {number} nOut + * @param {number} zOut + * @returns {number|Promise} + */ + xFullPathname(pVfs, zName, nOut, zOut) { + const filename = this._module.UTF8ToString(zName); + const zOutArray = this._module.HEAPU8.subarray(zOut, zOut + nOut); + this['log']?.('jFullPathname', filename, nOut); + return this.jFullPathname(filename, zOutArray); + } + + /** + * @param {number} pVfs + * @param {number} nBuf + * @param {number} zBuf + * @returns {number|Promise} + */ + xGetLastError(pVfs, nBuf, zBuf) { + const zBufArray = this._module.HEAPU8.subarray(zBuf, zBuf + nBuf); + this['log']?.('jGetLastError', nBuf); + return this.jGetLastError(zBufArray); + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + xClose(pFile) { + this['log']?.('jClose', pFile); + return this.jClose(pFile); + } + + /** + * @param {number} pFile + * @param {number} pData + * @param {number} iAmt + * @param {number} iOffsetLo + * @param {number} iOffsetHi + * @returns {number|Promise} + */ + xRead(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { + const pDataArray = this.#makeDataArray(pData, iAmt); + const iOffset = delegalize(iOffsetLo, iOffsetHi); + this['log']?.('jRead', pFile, iAmt, iOffset); + return this.jRead(pFile, pDataArray, iOffset); + } + + /** + * @param {number} pFile + * @param {number} pData + * @param {number} iAmt + * @param {number} iOffsetLo + * @param {number} iOffsetHi + * @returns {number|Promise} + */ + xWrite(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { + const pDataArray = this.#makeDataArray(pData, iAmt); + const iOffset = delegalize(iOffsetLo, iOffsetHi); + this['log']?.('jWrite', pFile, pDataArray, iOffset); + return this.jWrite(pFile, pDataArray, iOffset); + } + + /** + * @param {number} pFile + * @param {number} sizeLo + * @param {number} sizeHi + * @returns {number|Promise} + */ + xTruncate(pFile, sizeLo, sizeHi) { + const size = delegalize(sizeLo, sizeHi); + this['log']?.('jTruncate', pFile, size); + return this.jTruncate(pFile, size); + } + + /** + * @param {number} pFile + * @param {number} flags + * @returns {number|Promise} + */ + xSync(pFile, flags) { + this['log']?.('jSync', pFile, flags); + return this.jSync(pFile, flags); + } + + /** + * + * @param {number} pFile + * @param {number} pSize + * @returns {number|Promise} + */ + xFileSize(pFile, pSize) { + const pSizeView = this.#makeTypedDataView('BigInt64', pSize); + this['log']?.('jFileSize', pFile); + return this.jFileSize(pFile, pSizeView); + } + + /** + * @param {number} pFile + * @param {number} lockType + * @returns {number|Promise} + */ + xLock(pFile, lockType) { + this['log']?.('jLock', pFile, lockType); + return this.jLock(pFile, lockType); + } + + /** + * @param {number} pFile + * @param {number} lockType + * @returns {number|Promise} + */ + xUnlock(pFile, lockType) { + this['log']?.('jUnlock', pFile, lockType); + return this.jUnlock(pFile, lockType); + } + + /** + * @param {number} pFile + * @param {number} pResOut + * @returns {number|Promise} + */ + xCheckReservedLock(pFile, pResOut) { + const pResOutView = this.#makeTypedDataView('Int32', pResOut); + this['log']?.('jCheckReservedLock', pFile); + return this.jCheckReservedLock(pFile, pResOutView); + } + + /** + * @param {number} pFile + * @param {number} op + * @param {number} pArg + * @returns {number|Promise} + */ + xFileControl(pFile, op, pArg) { + const pArgView = new DataView( + this._module.HEAPU8.buffer, + this._module.HEAPU8.byteOffset + pArg); + this['log']?.('jFileControl', pFile, op, pArgView); + return this.jFileControl(pFile, op, pArgView); + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + xSectorSize(pFile) { + this['log']?.('jSectorSize', pFile); + return this.jSectorSize(pFile); + } + + /** + * @param {number} pFile + * @returns {number|Promise} + */ + xDeviceCharacteristics(pFile) { + this['log']?.('jDeviceCharacteristics', pFile); + return this.jDeviceCharacteristics(pFile); + } + + /** + * Wrapped DataView for pointer arguments. + * Pointers to a single value are passed using DataView. A Proxy + * wrapper prevents use of incorrect type or endianness. + * @param {'Int32'|'BigInt64'} type + * @param {number} byteOffset + * @returns {DataView} + */ + #makeTypedDataView(type, byteOffset) { + const byteLength = type === 'Int32' ? 4 : 8; + const getter = `get${type}`; + const setter = `set${type}`; + const makeDataView = () => new DataView( + this._module.HEAPU8.buffer, + this._module.HEAPU8.byteOffset + byteOffset, + byteLength); + let dataView = makeDataView(); + return new Proxy(dataView, { + get(_, prop) { + if (dataView.buffer.byteLength === 0) { + // WebAssembly memory resize detached the buffer. + dataView = makeDataView(); + } + if (prop === getter) { + return function(byteOffset, littleEndian) { + if (!littleEndian) throw new Error('must be little endian'); + return dataView[prop](byteOffset, littleEndian); + } + } + if (prop === setter) { + return function(byteOffset, value, littleEndian) { + if (!littleEndian) throw new Error('must be little endian'); + return dataView[prop](byteOffset, value, littleEndian); + } + } + if (typeof prop === 'string' && (prop.match(/^(get)|(set)/))) { + throw new Error('invalid type'); + } + const result = dataView[prop]; + return typeof result === 'function' ? result.bind(dataView) : result; + } + }); + } + + /** + * @param {number} byteOffset + * @param {number} byteLength + */ + #makeDataArray(byteOffset, byteLength) { + let target = this._module.HEAPU8.subarray(byteOffset, byteOffset + byteLength); + return new Proxy(target, { + get: (_, prop, receiver) => { + if (target.buffer.byteLength === 0) { + // WebAssembly memory resize detached the buffer. + target = this._module.HEAPU8.subarray(byteOffset, byteOffset + byteLength); + } + const result = target[prop]; + return typeof result === 'function' ? result.bind(target) : result; + } + }); + } + + #decodeFilename(zName, flags) { + if (flags & SQLITE_OPEN_URI) { + // The first null-terminated string is the URI path. Subsequent + // strings are query parameter keys and values. + // https://www.sqlite.org/c3ref/open.html#urifilenamesinsqlite3open + let pName = zName; + let state = 1; + const charCodes = []; + while (state) { + const charCode = this._module.HEAPU8[pName++]; + if (charCode) { + charCodes.push(charCode); + } else { + if (!this._module.HEAPU8[pName]) state = null; + switch (state) { + case 1: // path + charCodes.push('?'.charCodeAt(0)); + state = 2; + break; + case 2: // key + charCodes.push('='.charCodeAt(0)); + state = 3; + break; + case 3: // value + charCodes.push('&'.charCodeAt(0)); + state = 2; + break; + } + } + } + return new TextDecoder().decode(new Uint8Array(charCodes)); + } + return zName ? this._module.UTF8ToString(zName) : null; + } +} + +// Emscripten "legalizes" 64-bit integer arguments by passing them as +// two 32-bit signed integers. +function delegalize(lo32, hi32) { + return (hi32 * 0x100000000) + lo32 + (lo32 < 0 ? 2**32 : 0); +} + +// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. + +const DEFAULT_TEMPORARY_FILES = 10; +const LOCK_NOTIFY_INTERVAL = 1000; + +const DB_RELATED_FILE_SUFFIXES = ['', '-journal', '-wal']; + +const finalizationRegistry = new FinalizationRegistry(releaser => releaser()); + +class File { + /** @type {string} */ path + /** @type {number} */ flags; + /** @type {FileSystemSyncAccessHandle} */ accessHandle; + + /** @type {PersistentFile?} */ persistentFile; + + constructor(path, flags) { + this.path = path; + this.flags = flags; + } +} + +class PersistentFile { + /** @type {FileSystemFileHandle} */ fileHandle + /** @type {FileSystemSyncAccessHandle} */ accessHandle = null + + // The following properties are for main database files. + + /** @type {boolean} */ isLockBusy = false; + /** @type {boolean} */ isFileLocked = false; + /** @type {boolean} */ isRequestInProgress = false; + /** @type {function} */ handleLockReleaser = null; + + /** @type {BroadcastChannel} */ handleRequestChannel; + /** @type {boolean} */ isHandleRequested = false; + + constructor(fileHandle) { + this.fileHandle = fileHandle; + } +} + +class OPFSCoopSyncVFS extends FacadeVFS { + /** @type {Map} */ mapIdToFile = new Map(); + + lastError = null; + log = null; //function(...args) { console.log(`[${contextName}]`, ...args) }; + + /** @type {Map} */ persistentFiles = new Map(); + /** @type {Map} */ boundAccessHandles = new Map(); + /** @type {Set} */ unboundAccessHandles = new Set(); + /** @type {Set} */ accessiblePaths = new Set(); + releaser = null; + + static async create(name, module) { + const vfs = new OPFSCoopSyncVFS(name, module); + await Promise.all([ + vfs.isReady(), + vfs.#initialize(DEFAULT_TEMPORARY_FILES), + ]); + return vfs; + } + + constructor(name, module) { + super(name, module); + } + + async #initialize(nTemporaryFiles) { + // Delete temporary directories no longer in use. + const root = await navigator.storage.getDirectory(); + // @ts-ignore + for await (const entry of root.values()) { + if (entry.kind === 'directory' && entry.name.startsWith('.ahp-')) { + // A lock with the same name as the directory protects it from + // being deleted. + await navigator.locks.request(entry.name, { ifAvailable: true }, async lock => { + if (lock) { + this.log?.(`Deleting temporary directory ${entry.name}`); + await root.removeEntry(entry.name, { recursive: true }); + } else { + this.log?.(`Temporary directory ${entry.name} is in use`); + } + }); + } + } + + // Create our temporary directory. + const tmpDirName = `.ahp-${Math.random().toString(36).slice(2)}`; + this.releaser = await new Promise(resolve => { + navigator.locks.request(tmpDirName, () => { + return new Promise(release => { + resolve(release); + }); + }); + }); + finalizationRegistry.register(this, this.releaser); + const tmpDir = await root.getDirectoryHandle(tmpDirName, { create: true }); + + // Populate temporary directory. + for (let i = 0; i < nTemporaryFiles; i++) { + const tmpFile = await tmpDir.getFileHandle(`${i}.tmp`, { create: true }); + const tmpAccessHandle = await tmpFile.createSyncAccessHandle(); + this.unboundAccessHandles.add(tmpAccessHandle); + } + } + + /** + * @param {string?} zName + * @param {number} fileId + * @param {number} flags + * @param {DataView} pOutFlags + * @returns {number} + */ + jOpen(zName, fileId, flags, pOutFlags) { + try { + const url = new URL(zName || Math.random().toString(36).slice(2), 'file://'); + const path = url.pathname; + + if (flags & SQLITE_OPEN_MAIN_DB) { + const persistentFile = this.persistentFiles.get(path); + if (persistentFile?.isRequestInProgress) { + // Should not reach here unless SQLite itself retries an open. + // Otherwise, asynchronous operations started on a previous + // open try should have completed. + return SQLITE_BUSY; + } else if (!persistentFile) { + // This is the usual starting point for opening a database. + // Register a Promise that resolves when the database and related + // files are ready to be used. + this.log?.(`creating persistent file for ${path}`); + const create = !!(flags & SQLITE_OPEN_CREATE); + this._module.retryOps.push((async () => { + try { + // Get the path directory handle. + let dirHandle = await navigator.storage.getDirectory(); + const directories = path.split('/').filter(d => d); + const filename = directories.pop(); + for (const directory of directories) { + dirHandle = await dirHandle.getDirectoryHandle(directory, { create }); + } + + // Get file handles for the database and related files, + // and create persistent file instances. + for (const suffix of DB_RELATED_FILE_SUFFIXES) { + const fileHandle = await dirHandle.getFileHandle(filename + suffix, { create }); + await this.#createPersistentFile(fileHandle); + } + + // Get access handles for the files. + const file = new File(path, flags); + file.persistentFile = this.persistentFiles.get(path); + await this.#requestAccessHandle(file); + } catch (e) { + // Use an invalid persistent file to signal this error + // for the retried open. + const persistentFile = new PersistentFile(null); + this.persistentFiles.set(path, persistentFile); + console.error(e); + } + })()); + return SQLITE_BUSY; + } else if (!persistentFile.fileHandle) { + // The asynchronous open operation failed. + this.persistentFiles.delete(path); + return SQLITE_CANTOPEN; + } else if (!persistentFile.accessHandle) { + // This branch is reached if the database was previously opened + // and closed. + this._module.retryOps.push((async () => { + const file = new File(path, flags); + file.persistentFile = this.persistentFiles.get(path); + await this.#requestAccessHandle(file); + })()); + return SQLITE_BUSY; + } + } + + if (!this.accessiblePaths.has(path) && + !(flags & SQLITE_OPEN_CREATE)) { + throw new Error(`File ${path} not found`); + } + + const file = new File(path, flags); + this.mapIdToFile.set(fileId, file); + + if (this.persistentFiles.has(path)) { + file.persistentFile = this.persistentFiles.get(path); + } else if (this.boundAccessHandles.has(path)) { + // This temporary file was previously created and closed. Reopen + // the same access handle. + file.accessHandle = this.boundAccessHandles.get(path); + } else if (this.unboundAccessHandles.size) { + // Associate an unbound access handle to this file. + file.accessHandle = this.unboundAccessHandles.values().next().value; + file.accessHandle.truncate(0); + this.unboundAccessHandles.delete(file.accessHandle); + this.boundAccessHandles.set(path, file.accessHandle); + } + this.accessiblePaths.add(path); + + pOutFlags.setInt32(0, flags, true); + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_CANTOPEN; + } + } + + /** + * @param {string} zName + * @param {number} syncDir + * @returns {number} + */ + jDelete(zName, syncDir) { + try { + const url = new URL(zName, 'file://'); + const path = url.pathname; + if (this.persistentFiles.has(path)) { + const persistentFile = this.persistentFiles.get(path); + persistentFile.accessHandle.truncate(0); + } else { + this.boundAccessHandles.get(path)?.truncate(0); + } + this.accessiblePaths.delete(path); + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_IOERR_DELETE; + } + } + + /** + * @param {string} zName + * @param {number} flags + * @param {DataView} pResOut + * @returns {number} + */ + jAccess(zName, flags, pResOut) { + try { + const url = new URL(zName, 'file://'); + const path = url.pathname; + pResOut.setInt32(0, this.accessiblePaths.has(path) ? 1 : 0, true); + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_IOERR_ACCESS; + } + } + + /** + * @param {number} fileId + * @returns {number} + */ + jClose(fileId) { + try { + const file = this.mapIdToFile.get(fileId); + this.mapIdToFile.delete(fileId); + + if (file?.flags & SQLITE_OPEN_MAIN_DB) { + if (file.persistentFile?.handleLockReleaser) { + this.#releaseAccessHandle(file); + } + } else if (file?.flags & SQLITE_OPEN_DELETEONCLOSE) { + file.accessHandle.truncate(0); + this.accessiblePaths.delete(file.path); + if (!this.persistentFiles.has(file.path)) { + this.boundAccessHandles.delete(file.path); + this.unboundAccessHandles.add(file.accessHandle); + } + } + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_IOERR_CLOSE; + } + } + + /** + * @param {number} fileId + * @param {Uint8Array} pData + * @param {number} iOffset + * @returns {number} + */ + jRead(fileId, pData, iOffset) { + try { + const file = this.mapIdToFile.get(fileId); + + // On Chrome (at least), passing pData to accessHandle.read() is + // an error because pData is a Proxy of a Uint8Array. Calling + // subarray() produces a real Uint8Array and that works. + const accessHandle = file.accessHandle || file.persistentFile.accessHandle; + const bytesRead = accessHandle.read(pData.subarray(), { at: iOffset }); + + // Opening a database file performs one read without a xLock call. + if ((file.flags & SQLITE_OPEN_MAIN_DB) && !file.persistentFile.isFileLocked) { + this.#releaseAccessHandle(file); + } + + if (bytesRead < pData.byteLength) { + pData.fill(0, bytesRead); + return SQLITE_IOERR_SHORT_READ; + } + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_IOERR_READ; + } + } + + /** + * @param {number} fileId + * @param {Uint8Array} pData + * @param {number} iOffset + * @returns {number} + */ + jWrite(fileId, pData, iOffset) { + try { + const file = this.mapIdToFile.get(fileId); + + // On Chrome (at least), passing pData to accessHandle.write() is + // an error because pData is a Proxy of a Uint8Array. Calling + // subarray() produces a real Uint8Array and that works. + const accessHandle = file.accessHandle || file.persistentFile.accessHandle; + const nBytes = accessHandle.write(pData.subarray(), { at: iOffset }); + if (nBytes !== pData.byteLength) throw new Error('short write'); + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_IOERR_WRITE; + } + } + + /** + * @param {number} fileId + * @param {number} iSize + * @returns {number} + */ + jTruncate(fileId, iSize) { + try { + const file = this.mapIdToFile.get(fileId); + const accessHandle = file.accessHandle || file.persistentFile.accessHandle; + accessHandle.truncate(iSize); + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_IOERR_TRUNCATE; + } + } + + /** + * @param {number} fileId + * @param {number} flags + * @returns {number} + */ + jSync(fileId, flags) { + try { + const file = this.mapIdToFile.get(fileId); + const accessHandle = file.accessHandle || file.persistentFile.accessHandle; + accessHandle.flush(); + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_IOERR_FSYNC; + } + } + + /** + * @param {number} fileId + * @param {DataView} pSize64 + * @returns {number} + */ + jFileSize(fileId, pSize64) { + try { + const file = this.mapIdToFile.get(fileId); + const accessHandle = file.accessHandle || file.persistentFile.accessHandle; + const size = accessHandle.getSize(); + pSize64.setBigInt64(0, BigInt(size), true); + return SQLITE_OK; + } catch (e) { + this.lastError = e; + return SQLITE_IOERR_FSTAT; + } + } + + /** + * @param {number} fileId + * @param {number} lockType + * @returns {number} + */ + jLock(fileId, lockType) { + const file = this.mapIdToFile.get(fileId); + if (file.persistentFile.isRequestInProgress) { + file.persistentFile.isLockBusy = true; + return SQLITE_BUSY; + } + + file.persistentFile.isFileLocked = true; + if (!file.persistentFile.handleLockReleaser) { + // Start listening for notifications from other connections. + // This is before we actually get access handles, but waiting to + // listen until then allows a race condition where notifications + // are missed. + file.persistentFile.handleRequestChannel.onmessage = () => { + this.log?.(`received notification for ${file.path}`); + if (file.persistentFile.isFileLocked) { + // We're still using the access handle, so mark it to be + // released when we're done. + file.persistentFile.isHandleRequested = true; + } else { + // Release the access handles immediately. + this.#releaseAccessHandle(file); + } + file.persistentFile.handleRequestChannel.onmessage = null; + }; + + this.#requestAccessHandle(file); + this.log?.('returning SQLITE_BUSY'); + file.persistentFile.isLockBusy = true; + return SQLITE_BUSY; + } + file.persistentFile.isLockBusy = false; + return SQLITE_OK; + } + + /** + * @param {number} fileId + * @param {number} lockType + * @returns {number} + */ + jUnlock(fileId, lockType) { + const file = this.mapIdToFile.get(fileId); + if (lockType === SQLITE_LOCK_NONE) { + // Don't change any state if this unlock is because xLock returned + // SQLITE_BUSY. + if (!file.persistentFile.isLockBusy) { + if (file.persistentFile.isHandleRequested) { + // Another connection wants the access handle. + this.#releaseAccessHandle(file); + this.isHandleRequested = false; + } + file.persistentFile.isFileLocked = false; + } + } + return SQLITE_OK; + } + + /** + * @param {number} fileId + * @param {number} op + * @param {DataView} pArg + * @returns {number|Promise} + */ + jFileControl(fileId, op, pArg) { + try { + const file = this.mapIdToFile.get(fileId); + switch (op) { + case SQLITE_FCNTL_PRAGMA: + const key = extractString(pArg, 4); + const value = extractString(pArg, 8); + this.log?.('xFileControl', file.path, 'PRAGMA', key, value); + switch (key.toLowerCase()) { + case 'journal_mode': + if (value && + !['off', 'memory', 'delete', 'wal'].includes(value.toLowerCase())) { + throw new Error('journal_mode must be "off", "memory", "delete", or "wal"'); + } + break; + } + break; + } + } catch (e) { + this.lastError = e; + return SQLITE_IOERR; + } + return SQLITE_NOTFOUND; + } + + /** + * @param {Uint8Array} zBuf + * @returns + */ + jGetLastError(zBuf) { + if (this.lastError) { + console.error(this.lastError); + const outputArray = zBuf.subarray(0, zBuf.byteLength - 1); + const { written } = new TextEncoder().encodeInto(this.lastError.message, outputArray); + zBuf[written] = 0; + } + return SQLITE_OK + } + + /** + * @param {FileSystemFileHandle} fileHandle + * @returns {Promise} + */ + async #createPersistentFile(fileHandle) { + const persistentFile = new PersistentFile(fileHandle); + const root = await navigator.storage.getDirectory(); + const relativePath = await root.resolve(fileHandle); + const path = `/${relativePath.join('/')}`; + persistentFile.handleRequestChannel = new BroadcastChannel(`ahp:${path}`); + this.persistentFiles.set(path, persistentFile); + + const f = await fileHandle.getFile(); + if (f.size) { + this.accessiblePaths.add(path); + } + return persistentFile; + } + + /** + * @param {File} file + */ + #requestAccessHandle(file) { + console.assert(!file.persistentFile.handleLockReleaser); + if (!file.persistentFile.isRequestInProgress) { + file.persistentFile.isRequestInProgress = true; + this._module.retryOps.push((async () => { + // Acquire the Web Lock. + file.persistentFile.handleLockReleaser = await this.#acquireLock(file.persistentFile); + + // Get access handles for the database and releated files in parallel. + this.log?.(`creating access handles for ${file.path}`); + await Promise.all(DB_RELATED_FILE_SUFFIXES.map(async suffix => { + const persistentFile = this.persistentFiles.get(file.path + suffix); + if (persistentFile) { + persistentFile.accessHandle = + await persistentFile.fileHandle.createSyncAccessHandle(); + } + })); + file.persistentFile.isRequestInProgress = false; + })()); + return this._module.retryOps.at(-1); + } + return Promise.resolve(); + } + + /** + * @param {File} file + */ + async #releaseAccessHandle(file) { + DB_RELATED_FILE_SUFFIXES.forEach(async suffix => { + const persistentFile = this.persistentFiles.get(file.path + suffix); + if (persistentFile) { + persistentFile.accessHandle?.close(); + persistentFile.accessHandle = null; + } + }); + this.log?.(`access handles closed for ${file.path}`); + + file.persistentFile.handleLockReleaser?.(); + file.persistentFile.handleLockReleaser = null; + this.log?.(`lock released for ${file.path}`); + } + + /** + * @param {PersistentFile} persistentFile + * @returns {Promise} lock releaser + */ + #acquireLock(persistentFile) { + return new Promise(resolve => { + // Tell other connections we want the access handle. + const lockName = persistentFile.handleRequestChannel.name; + const notify = () => { + this.log?.(`notifying for ${lockName}`); + persistentFile.handleRequestChannel.postMessage(null); + }; + const notifyId = setInterval(notify, LOCK_NOTIFY_INTERVAL); + setTimeout(notify); + + this.log?.(`lock requested: ${lockName}`); + navigator.locks.request(lockName, lock => { + // We have the lock. Stop asking other connections for it. + this.log?.(`lock acquired: ${lockName}`, lock); + clearInterval(notifyId); + return new Promise(resolve); + }); + }); + } +} + +function extractString(dataView, offset) { + const p = dataView.getUint32(offset, true); + if (p) { + const chars = new Uint8Array(dataView.buffer, p); + return new TextDecoder().decode(chars.subarray(0, chars.indexOf(0))); + } + return null; +} + +var Module = (() => { + var _scriptName = import.meta.url; + + return ( +function(moduleArg = {}) { + var moduleRtn; + +var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject;});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var moduleOverrides=Object.assign({},Module);var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href;}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src;}if(_scriptName){scriptDirectory=_scriptName;}if(scriptDirectory.startsWith("blob:")){scriptDirectory="";}else {scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1);}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)};}readAsync=url=>fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))});}}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift());}}callRuntimeCallbacks(__ATPRERUN__);}function initRuntime(){if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;callRuntimeCallbacks(__ATINIT__);}function preMain(){callRuntimeCallbacks(__ATMAIN__);}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift());}}callRuntimeCallbacks(__ATPOSTRUN__);}function addOnPreRun(cb){__ATPRERUN__.unshift(cb);}function addOnInit(cb){__ATINIT__.unshift(cb);}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb);}var runDependencies=0;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies);}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback();}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);function findWasmBinary(){if(Module["locateFile"]){var f="wa-sqlite.wasm";if(!isDataURI(f)){return locateFile(f)}return f}return new URL("wa-sqlite.wasm",import.meta.url).href}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw "both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason);})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return {a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["ja"];updateMemoryViews();wasmTable=wasmExports["af"];addOnInit(wasmExports["ka"]);removeRunDependency();return wasmExports}addRunDependency();function receiveInstantiationResult(result){receiveInstance(result["instance"]);}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e);}}if(!wasmBinaryFile)wasmBinaryFile=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return {}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status;}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module);}};function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`);}}var noExitRuntime=Module["noExitRuntime"]||true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`);}}var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023);}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var ___assert_fail=(condition,filename,line,func)=>{abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"]);};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1);}else if(last===".."){parts.splice(i,1);up++;}else if(up){parts.splice(i,1);up--;}}if(allowAboveRoot){for(;up;up--){parts.unshift("..");}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path=".";}if(path&&trailingSlash){path+="/";}return (isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return "."}if(dir){dir=dir.substr(0,dir.length-1);}return root+dir},basename:path=>{if(path==="/")return "/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else abort("initRandomDevice");};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return ""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path);}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return (resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return [];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i;}else {len+=3;}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023;}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u;}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63;}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;}else {if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n";}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true);}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops);},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false;},close(stream){stream.tty.ops.fsync(stream.tty);},fsync(stream){stream.tty.ops.fsync(stream.tty);},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[];}},ioctl_tcgets(tty){return {c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return [24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[];}else {if(val!=0)tty.output.push(val);}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[];}}}};var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={};}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null;}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream;}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream;}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp;}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;}else {var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)));}node.usedBytes=newSize;}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096;}else if(FS.isFile(node.mode)){attr.size=node.usedBytes;}else if(FS.isLink(node.mode)){attr.size=node.link.length;}else {attr.size=0;}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode;}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp;}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size);}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name);}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now();},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now();},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key);}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset);}else {for(var i=0;i0||position+length{var dep=getUniqueRunDependency(`al ${url}`);readAsync(url).then(arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency();},err=>{if(onerror){onerror();}else {throw `Loading data file "${url}" failed.`}});if(dep)addRunDependency();};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn);};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true;}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn);}onload?.();removeRunDependency();}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency();})){return}finish(byteArray);}addRunDependency();if(typeof url=="string"){asyncLoad(url,processData,onerror);}else {processData(url);}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{constructor(errno){this.name="ErrnoError";this.errno=errno;}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={};}get object(){return this.node}set object(val){this.node=val;}get isRead(){return (this.flags&2097155)!==1}get isWrite(){return (this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val;}get position(){return this.shared.position}set position(val){this.shared.position=val;}},FSNode:class{constructor(parent,name,mode,rdev){if(!parent){parent=this;}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev;this.readMode=292|73;this.writeMode=146;}get read(){return (this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode;}get write(){return (this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode;}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return {path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return {path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent;}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node;},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next;}else {var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next;}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node);},isRoot(node){return node===node.parent},isMountpoint(node){return !!node.mounted},isFile(mode){return (mode&61440)===32768},isDir(mode){return (mode&61440)===16384},isLink(mode){return (mode&61440)===40960},isChrdev(mode){return (mode&61440)===8192},isBlkdev(mode){return (mode&61440)===24576},isFIFO(mode){return (mode&61440)===4096},isSocket(mode){return (mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w";}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name);}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else {if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd();}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null;},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream);},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops};},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts);}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false;}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null);}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done);});},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot;}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount);}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current);}current=next;}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1);},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path;},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user");},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength;}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp");},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd");},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"]);}else {FS.symlink("/dev/tty","/dev/stdin");}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"]);}else {FS.symlink("/dev/tty","/dev/stdout");}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"]);}else {FS.symlink("/dev/tty1","/dev/stderr");}FS.open("/dev/stdin",0);FS.open("/dev/stdout",1);FS.open("/dev/stderr",1);},staticInit(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack="";});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS:MEMFS};},init(input,output,error){FS.init.initialized=true;Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams();},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter;}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined");}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end);}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed");}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true;}get length(){if(!this.lengthKnown){this.cacheLength();}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength();}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray};}else {var properties={isDevice:false,url:url};}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents;}else if(properties.url){node.contents=null;node.url=properties.url;}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)};});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return {ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd();}else {var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path;}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags);},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_chmod(path,mode){try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return -28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return -44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return -2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function syscallGetVarargI(){var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret}var syscallGetVarargP=syscallGetVarargI;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return -28}while(FS.streams[arg]){arg++;}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0}return -28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function ___syscall_ftruncate64(fd,length_low,length_high){var length=convertI32PairToI53Checked(length_low,length_high);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function ___syscall_getcwd(buf,size){try{if(size===0)return -28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(sizeHEAPU32[ptr>>2]+HEAP32[ptr+4>>2]*4294967296;function ___syscall_utimensat(dirfd,path,times,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);if(!times){var atime=Date.now();var mtime=atime;}else {var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>2];atime=seconds*1e3+nanoseconds/(1e3*1e3);times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>2];mtime=seconds*1e3+nanoseconds/(1e3*1e3);}FS.utime(path,atime,mtime);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst;}function __mmap_js(len,prot,flags,fd,offset_low,offset_high,allocated,addr){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset_low,offset_high){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset);}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var __tzset_js=(timezone,daylight,std_name,dst_name)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);var extractZone=date=>date.toLocaleTimeString(undefined,{hour12:false,timeZoneName:"short"}).split(" ")[1];var winterName=extractZone(winter);var summerName=extractZone(summer);if(summerOffsetDate.now();var _emscripten_get_now;_emscripten_get_now=()=>performance.now();var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x];}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`);}getEnvStrings.strings=strings;}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i{var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1;});return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4;}HEAP8[pbuf]=type;HEAP16[pbuf+2>>1]=flags;tempI64=[rightsBase>>>0,(tempDouble=rightsBase,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+8>>2]=tempI64[0],HEAP32[pbuf+12>>2]=tempI64[1];tempI64=[rightsInheriting>>>0,(tempDouble=rightsInheriting,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+16>>2]=tempI64[0],HEAP32[pbuf+20>>2]=tempI64[1];return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return -1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops?.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return -1;ret+=curr;}return ret};function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var adapters_support=function(){const handleAsync=typeof Asyncify==="object"?Asyncify.handleAsync.bind(Asyncify):null;Module["handleAsync"]=handleAsync;const targets=new Map;Module["setCallback"]=(key,target)=>targets.set(key,target);Module["getCallback"]=key=>targets.get(key);Module["deleteCallback"]=key=>targets.delete(key);adapters_support=function(isAsync,key,...args){const receiver=targets.get(key);let methodName=null;const f=typeof receiver==="function"?receiver:receiver[methodName=UTF8ToString(args.shift())];if(isAsync){if(handleAsync){return handleAsync(()=>f.apply(receiver,args))}throw new Error("Synchronous WebAssembly cannot call async function")}const result=f.apply(receiver,args);if(typeof result?.then=="function"){console.error("unexpected Promise",f);throw new Error(`${methodName} unexpectedly returned a Promise`)}return result};};function _ipp(...args){return adapters_support(false,...args)}function _ipp_async(...args){return adapters_support(true,...args)}function _ippipppp(...args){return adapters_support(false,...args)}function _ippipppp_async(...args){return adapters_support(true,...args)}function _ippp(...args){return adapters_support(false,...args)}function _ippp_async(...args){return adapters_support(true,...args)}function _ipppi(...args){return adapters_support(false,...args)}function _ipppi_async(...args){return adapters_support(true,...args)}function _ipppiii(...args){return adapters_support(false,...args)}function _ipppiii_async(...args){return adapters_support(true,...args)}function _ipppiiip(...args){return adapters_support(false,...args)}function _ipppiiip_async(...args){return adapters_support(true,...args)}function _ipppip(...args){return adapters_support(false,...args)}function _ipppip_async(...args){return adapters_support(true,...args)}function _ipppj(...args){return adapters_support(false,...args)}function _ipppj_async(...args){return adapters_support(true,...args)}function _ipppp(...args){return adapters_support(false,...args)}function _ipppp_async(...args){return adapters_support(true,...args)}function _ippppi(...args){return adapters_support(false,...args)}function _ippppi_async(...args){return adapters_support(true,...args)}function _ippppij(...args){return adapters_support(false,...args)}function _ippppij_async(...args){return adapters_support(true,...args)}function _ippppip(...args){return adapters_support(false,...args)}function _ippppip_async(...args){return adapters_support(true,...args)}function _ipppppip(...args){return adapters_support(false,...args)}function _ipppppip_async(...args){return adapters_support(true,...args)}function _vppp(...args){return adapters_support(false,...args)}function _vppp_async(...args){return adapters_support(true,...args)}function _vpppip(...args){return adapters_support(false,...args)}function _vpppip_async(...args){return adapters_support(true,...args)}var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true;}quit_(code,new ExitStatus(code));};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status);};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e);};var uleb128Encode=(n,target)=>{if(n<128){target.push(n);}else {target.push(n%128|128,n>>7);}};var sigToWasmTypes=sig=>{var typeNames={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",p:"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var sigRet=sig.slice(0,1);var sigParam=sig.slice(1);var typeCodes={i:127,p:127,j:126,f:125,d:124,e:111};target.push(96);uleb128Encode(sigParam.length,target);for(var i=0;i{if(typeof WebAssembly.Function=="function"){return new WebAssembly.Function(sigToWasmTypes(sig),func)}var typeSectionBody=[1];generateFuncType(sig,typeSectionBody);var bytes=[0,97,115,109,1,0,0,0,1];uleb128Encode(typeSectionBody.length,bytes);bytes.push(...typeSectionBody);bytes.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);var module=new WebAssembly.Module(new Uint8Array(bytes));var instance=new WebAssembly.Instance(module,{e:{f:func}});var wrappedFunc=instance.exports["f"];return wrappedFunc};var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var updateTableMap=(offset,count)=>{if(functionsInTableMap){for(var i=offset;i{if(!functionsInTableMap){functionsInTableMap=new WeakMap;updateTableMap(0,wasmTable.length);}return functionsInTableMap.get(func)||0};var freeTableIndexes=[];var getEmptyTableSlot=()=>{if(freeTableIndexes.length){return freeTableIndexes.pop()}try{wasmTable.grow(1);}catch(err){if(!(err instanceof RangeError)){throw err}throw "Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."}return wasmTable.length-1};var setWasmTableEntry=(idx,func)=>wasmTable.set(idx,func);var addFunction=(func,sig)=>{var rtn=getFunctionAddress(func);if(rtn){return rtn}var ret=getEmptyTableSlot();try{setWasmTableEntry(ret,func);}catch(err){if(!(err instanceof TypeError)){throw err}var wrapped=convertJsFunctionToWasm(func,sig);setWasmTableEntry(ret,wrapped);}functionsInTableMap.set(func,ret);return ret};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer);};var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str);}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return (...args)=>ccall(ident,returnType,argTypes,args)};var getTempRet0=val=>__emscripten_tempret_get();var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2;}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023;}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var AsciiToString=ptr=>{var str="";while(1){var ch=HEAPU8[ptr++];if(!ch)return str;str+=String.fromCharCode(ch);}};var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit);}return str};var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023);}else {str+=String.fromCharCode(utf32);}}return str};function intArrayToString(array){var ret=[];for(var i=0;i255){chr&=255;}ret.push(String.fromCharCode(chr));}return ret.join("")}FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();adapters_support();var wasmImports={a:___assert_fail,Y:___syscall_chmod,$:___syscall_faccessat,Z:___syscall_fchmod,X:___syscall_fchown32,b:___syscall_fcntl64,W:___syscall_fstat64,y:___syscall_ftruncate64,Q:___syscall_getcwd,U:___syscall_lstat64,N:___syscall_mkdirat,T:___syscall_newfstatat,L:___syscall_openat,J:___syscall_readlinkat,I:___syscall_rmdir,V:___syscall_stat64,G:___syscall_unlinkat,F:___syscall_utimensat,w:__localtime_js,u:__mmap_js,v:__munmap_js,M:__tzset_js,n:_emscripten_date_now,m:_emscripten_get_now,D:_emscripten_resize_heap,O:_environ_get,P:_environ_sizes_get,o:_fd_close,E:_fd_fdstat_get,K:_fd_read,x:_fd_seek,S:_fd_sync,H:_fd_write,s:_ipp,t:_ipp_async,fa:_ippipppp,ia:_ippipppp_async,i:_ippp,j:_ippp_async,c:_ipppi,d:_ipppi_async,ca:_ipppiii,da:_ipppiii_async,ea:_ipppiiip,ga:_ipppiiip_async,g:_ipppip,h:_ipppip_async,z:_ipppj,A:_ipppj_async,e:_ipppp,f:_ipppp_async,aa:_ippppi,ba:_ippppi_async,B:_ippppij,C:_ippppij_async,p:_ippppip,q:_ippppip_async,ha:_ipppppip,r:_ipppppip_async,k:_vppp,l:_vppp_async,R:_vpppip,_:_vpppip_async};var wasmExports=createWasm();Module["_sqlite3_status64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_status64"]=wasmExports["la"])(a0,a1,a2,a3);Module["_sqlite3_status"]=(a0,a1,a2,a3)=>(Module["_sqlite3_status"]=wasmExports["ma"])(a0,a1,a2,a3);Module["_sqlite3_db_status"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_db_status"]=wasmExports["na"])(a0,a1,a2,a3,a4);Module["_sqlite3_msize"]=a0=>(Module["_sqlite3_msize"]=wasmExports["oa"])(a0);Module["_sqlite3_vfs_find"]=a0=>(Module["_sqlite3_vfs_find"]=wasmExports["pa"])(a0);Module["_sqlite3_vfs_register"]=(a0,a1)=>(Module["_sqlite3_vfs_register"]=wasmExports["qa"])(a0,a1);Module["_sqlite3_vfs_unregister"]=a0=>(Module["_sqlite3_vfs_unregister"]=wasmExports["ra"])(a0);Module["_sqlite3_release_memory"]=a0=>(Module["_sqlite3_release_memory"]=wasmExports["sa"])(a0);Module["_sqlite3_soft_heap_limit64"]=(a0,a1)=>(Module["_sqlite3_soft_heap_limit64"]=wasmExports["ta"])(a0,a1);Module["_sqlite3_memory_used"]=()=>(Module["_sqlite3_memory_used"]=wasmExports["ua"])();Module["_sqlite3_hard_heap_limit64"]=(a0,a1)=>(Module["_sqlite3_hard_heap_limit64"]=wasmExports["va"])(a0,a1);Module["_sqlite3_memory_highwater"]=a0=>(Module["_sqlite3_memory_highwater"]=wasmExports["wa"])(a0);Module["_sqlite3_malloc"]=a0=>(Module["_sqlite3_malloc"]=wasmExports["xa"])(a0);Module["_sqlite3_malloc64"]=(a0,a1)=>(Module["_sqlite3_malloc64"]=wasmExports["ya"])(a0,a1);Module["_sqlite3_free"]=a0=>(Module["_sqlite3_free"]=wasmExports["za"])(a0);Module["_sqlite3_realloc"]=(a0,a1)=>(Module["_sqlite3_realloc"]=wasmExports["Aa"])(a0,a1);Module["_sqlite3_realloc64"]=(a0,a1,a2)=>(Module["_sqlite3_realloc64"]=wasmExports["Ba"])(a0,a1,a2);Module["_sqlite3_str_vappendf"]=(a0,a1,a2)=>(Module["_sqlite3_str_vappendf"]=wasmExports["Ca"])(a0,a1,a2);Module["_sqlite3_str_append"]=(a0,a1,a2)=>(Module["_sqlite3_str_append"]=wasmExports["Da"])(a0,a1,a2);Module["_sqlite3_str_appendchar"]=(a0,a1,a2)=>(Module["_sqlite3_str_appendchar"]=wasmExports["Ea"])(a0,a1,a2);Module["_sqlite3_str_appendall"]=(a0,a1)=>(Module["_sqlite3_str_appendall"]=wasmExports["Fa"])(a0,a1);Module["_sqlite3_str_appendf"]=(a0,a1,a2)=>(Module["_sqlite3_str_appendf"]=wasmExports["Ga"])(a0,a1,a2);Module["_sqlite3_str_finish"]=a0=>(Module["_sqlite3_str_finish"]=wasmExports["Ha"])(a0);Module["_sqlite3_str_errcode"]=a0=>(Module["_sqlite3_str_errcode"]=wasmExports["Ia"])(a0);Module["_sqlite3_str_length"]=a0=>(Module["_sqlite3_str_length"]=wasmExports["Ja"])(a0);Module["_sqlite3_str_value"]=a0=>(Module["_sqlite3_str_value"]=wasmExports["Ka"])(a0);Module["_sqlite3_str_reset"]=a0=>(Module["_sqlite3_str_reset"]=wasmExports["La"])(a0);Module["_sqlite3_str_new"]=a0=>(Module["_sqlite3_str_new"]=wasmExports["Ma"])(a0);Module["_sqlite3_vmprintf"]=(a0,a1)=>(Module["_sqlite3_vmprintf"]=wasmExports["Na"])(a0,a1);Module["_sqlite3_mprintf"]=(a0,a1)=>(Module["_sqlite3_mprintf"]=wasmExports["Oa"])(a0,a1);Module["_sqlite3_vsnprintf"]=(a0,a1,a2,a3)=>(Module["_sqlite3_vsnprintf"]=wasmExports["Pa"])(a0,a1,a2,a3);Module["_sqlite3_snprintf"]=(a0,a1,a2,a3)=>(Module["_sqlite3_snprintf"]=wasmExports["Qa"])(a0,a1,a2,a3);Module["_sqlite3_log"]=(a0,a1,a2)=>(Module["_sqlite3_log"]=wasmExports["Ra"])(a0,a1,a2);Module["_sqlite3_randomness"]=(a0,a1)=>(Module["_sqlite3_randomness"]=wasmExports["Sa"])(a0,a1);Module["_sqlite3_stricmp"]=(a0,a1)=>(Module["_sqlite3_stricmp"]=wasmExports["Ta"])(a0,a1);Module["_sqlite3_strnicmp"]=(a0,a1,a2)=>(Module["_sqlite3_strnicmp"]=wasmExports["Ua"])(a0,a1,a2);Module["_sqlite3_os_init"]=()=>(Module["_sqlite3_os_init"]=wasmExports["Va"])();Module["_sqlite3_os_end"]=()=>(Module["_sqlite3_os_end"]=wasmExports["Wa"])();Module["_sqlite3_serialize"]=(a0,a1,a2,a3)=>(Module["_sqlite3_serialize"]=wasmExports["Xa"])(a0,a1,a2,a3);Module["_sqlite3_prepare_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare_v2"]=wasmExports["Ya"])(a0,a1,a2,a3,a4);Module["_sqlite3_step"]=a0=>(Module["_sqlite3_step"]=wasmExports["Za"])(a0);Module["_sqlite3_column_int64"]=(a0,a1)=>(Module["_sqlite3_column_int64"]=wasmExports["_a"])(a0,a1);Module["_sqlite3_reset"]=a0=>(Module["_sqlite3_reset"]=wasmExports["$a"])(a0);Module["_sqlite3_exec"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_exec"]=wasmExports["ab"])(a0,a1,a2,a3,a4);Module["_sqlite3_column_int"]=(a0,a1)=>(Module["_sqlite3_column_int"]=wasmExports["bb"])(a0,a1);Module["_sqlite3_finalize"]=a0=>(Module["_sqlite3_finalize"]=wasmExports["cb"])(a0);Module["_sqlite3_deserialize"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_deserialize"]=wasmExports["db"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_database_file_object"]=a0=>(Module["_sqlite3_database_file_object"]=wasmExports["eb"])(a0);Module["_sqlite3_backup_init"]=(a0,a1,a2,a3)=>(Module["_sqlite3_backup_init"]=wasmExports["fb"])(a0,a1,a2,a3);Module["_sqlite3_backup_step"]=(a0,a1)=>(Module["_sqlite3_backup_step"]=wasmExports["gb"])(a0,a1);Module["_sqlite3_backup_finish"]=a0=>(Module["_sqlite3_backup_finish"]=wasmExports["hb"])(a0);Module["_sqlite3_backup_remaining"]=a0=>(Module["_sqlite3_backup_remaining"]=wasmExports["ib"])(a0);Module["_sqlite3_backup_pagecount"]=a0=>(Module["_sqlite3_backup_pagecount"]=wasmExports["jb"])(a0);Module["_sqlite3_clear_bindings"]=a0=>(Module["_sqlite3_clear_bindings"]=wasmExports["kb"])(a0);Module["_sqlite3_value_blob"]=a0=>(Module["_sqlite3_value_blob"]=wasmExports["lb"])(a0);Module["_sqlite3_value_text"]=a0=>(Module["_sqlite3_value_text"]=wasmExports["mb"])(a0);Module["_sqlite3_value_bytes"]=a0=>(Module["_sqlite3_value_bytes"]=wasmExports["nb"])(a0);Module["_sqlite3_value_bytes16"]=a0=>(Module["_sqlite3_value_bytes16"]=wasmExports["ob"])(a0);Module["_sqlite3_value_double"]=a0=>(Module["_sqlite3_value_double"]=wasmExports["pb"])(a0);Module["_sqlite3_value_int"]=a0=>(Module["_sqlite3_value_int"]=wasmExports["qb"])(a0);Module["_sqlite3_value_int64"]=a0=>(Module["_sqlite3_value_int64"]=wasmExports["rb"])(a0);Module["_sqlite3_value_subtype"]=a0=>(Module["_sqlite3_value_subtype"]=wasmExports["sb"])(a0);Module["_sqlite3_value_pointer"]=(a0,a1)=>(Module["_sqlite3_value_pointer"]=wasmExports["tb"])(a0,a1);Module["_sqlite3_value_text16"]=a0=>(Module["_sqlite3_value_text16"]=wasmExports["ub"])(a0);Module["_sqlite3_value_text16be"]=a0=>(Module["_sqlite3_value_text16be"]=wasmExports["vb"])(a0);Module["_sqlite3_value_text16le"]=a0=>(Module["_sqlite3_value_text16le"]=wasmExports["wb"])(a0);Module["_sqlite3_value_type"]=a0=>(Module["_sqlite3_value_type"]=wasmExports["xb"])(a0);Module["_sqlite3_value_encoding"]=a0=>(Module["_sqlite3_value_encoding"]=wasmExports["yb"])(a0);Module["_sqlite3_value_nochange"]=a0=>(Module["_sqlite3_value_nochange"]=wasmExports["zb"])(a0);Module["_sqlite3_value_frombind"]=a0=>(Module["_sqlite3_value_frombind"]=wasmExports["Ab"])(a0);Module["_sqlite3_value_dup"]=a0=>(Module["_sqlite3_value_dup"]=wasmExports["Bb"])(a0);Module["_sqlite3_value_free"]=a0=>(Module["_sqlite3_value_free"]=wasmExports["Cb"])(a0);Module["_sqlite3_result_blob"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_blob"]=wasmExports["Db"])(a0,a1,a2,a3);Module["_sqlite3_result_blob64"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_result_blob64"]=wasmExports["Eb"])(a0,a1,a2,a3,a4);Module["_sqlite3_result_double"]=(a0,a1)=>(Module["_sqlite3_result_double"]=wasmExports["Fb"])(a0,a1);Module["_sqlite3_result_error"]=(a0,a1,a2)=>(Module["_sqlite3_result_error"]=wasmExports["Gb"])(a0,a1,a2);Module["_sqlite3_result_error16"]=(a0,a1,a2)=>(Module["_sqlite3_result_error16"]=wasmExports["Hb"])(a0,a1,a2);Module["_sqlite3_result_int"]=(a0,a1)=>(Module["_sqlite3_result_int"]=wasmExports["Ib"])(a0,a1);Module["_sqlite3_result_int64"]=(a0,a1,a2)=>(Module["_sqlite3_result_int64"]=wasmExports["Jb"])(a0,a1,a2);Module["_sqlite3_result_null"]=a0=>(Module["_sqlite3_result_null"]=wasmExports["Kb"])(a0);Module["_sqlite3_result_pointer"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_pointer"]=wasmExports["Lb"])(a0,a1,a2,a3);Module["_sqlite3_result_subtype"]=(a0,a1)=>(Module["_sqlite3_result_subtype"]=wasmExports["Mb"])(a0,a1);Module["_sqlite3_result_text"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text"]=wasmExports["Nb"])(a0,a1,a2,a3);Module["_sqlite3_result_text64"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_result_text64"]=wasmExports["Ob"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_result_text16"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16"]=wasmExports["Pb"])(a0,a1,a2,a3);Module["_sqlite3_result_text16be"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16be"]=wasmExports["Qb"])(a0,a1,a2,a3);Module["_sqlite3_result_text16le"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16le"]=wasmExports["Rb"])(a0,a1,a2,a3);Module["_sqlite3_result_value"]=(a0,a1)=>(Module["_sqlite3_result_value"]=wasmExports["Sb"])(a0,a1);Module["_sqlite3_result_error_toobig"]=a0=>(Module["_sqlite3_result_error_toobig"]=wasmExports["Tb"])(a0);Module["_sqlite3_result_zeroblob"]=(a0,a1)=>(Module["_sqlite3_result_zeroblob"]=wasmExports["Ub"])(a0,a1);Module["_sqlite3_result_zeroblob64"]=(a0,a1,a2)=>(Module["_sqlite3_result_zeroblob64"]=wasmExports["Vb"])(a0,a1,a2);Module["_sqlite3_result_error_code"]=(a0,a1)=>(Module["_sqlite3_result_error_code"]=wasmExports["Wb"])(a0,a1);Module["_sqlite3_result_error_nomem"]=a0=>(Module["_sqlite3_result_error_nomem"]=wasmExports["Xb"])(a0);Module["_sqlite3_user_data"]=a0=>(Module["_sqlite3_user_data"]=wasmExports["Yb"])(a0);Module["_sqlite3_context_db_handle"]=a0=>(Module["_sqlite3_context_db_handle"]=wasmExports["Zb"])(a0);Module["_sqlite3_vtab_nochange"]=a0=>(Module["_sqlite3_vtab_nochange"]=wasmExports["_b"])(a0);Module["_sqlite3_vtab_in_first"]=(a0,a1)=>(Module["_sqlite3_vtab_in_first"]=wasmExports["$b"])(a0,a1);Module["_sqlite3_vtab_in_next"]=(a0,a1)=>(Module["_sqlite3_vtab_in_next"]=wasmExports["ac"])(a0,a1);Module["_sqlite3_aggregate_context"]=(a0,a1)=>(Module["_sqlite3_aggregate_context"]=wasmExports["bc"])(a0,a1);Module["_sqlite3_get_auxdata"]=(a0,a1)=>(Module["_sqlite3_get_auxdata"]=wasmExports["cc"])(a0,a1);Module["_sqlite3_set_auxdata"]=(a0,a1,a2,a3)=>(Module["_sqlite3_set_auxdata"]=wasmExports["dc"])(a0,a1,a2,a3);Module["_sqlite3_column_count"]=a0=>(Module["_sqlite3_column_count"]=wasmExports["ec"])(a0);Module["_sqlite3_data_count"]=a0=>(Module["_sqlite3_data_count"]=wasmExports["fc"])(a0);Module["_sqlite3_column_blob"]=(a0,a1)=>(Module["_sqlite3_column_blob"]=wasmExports["gc"])(a0,a1);Module["_sqlite3_column_bytes"]=(a0,a1)=>(Module["_sqlite3_column_bytes"]=wasmExports["hc"])(a0,a1);Module["_sqlite3_column_bytes16"]=(a0,a1)=>(Module["_sqlite3_column_bytes16"]=wasmExports["ic"])(a0,a1);Module["_sqlite3_column_double"]=(a0,a1)=>(Module["_sqlite3_column_double"]=wasmExports["jc"])(a0,a1);Module["_sqlite3_column_text"]=(a0,a1)=>(Module["_sqlite3_column_text"]=wasmExports["kc"])(a0,a1);Module["_sqlite3_column_value"]=(a0,a1)=>(Module["_sqlite3_column_value"]=wasmExports["lc"])(a0,a1);Module["_sqlite3_column_text16"]=(a0,a1)=>(Module["_sqlite3_column_text16"]=wasmExports["mc"])(a0,a1);Module["_sqlite3_column_type"]=(a0,a1)=>(Module["_sqlite3_column_type"]=wasmExports["nc"])(a0,a1);Module["_sqlite3_column_name"]=(a0,a1)=>(Module["_sqlite3_column_name"]=wasmExports["oc"])(a0,a1);Module["_sqlite3_column_name16"]=(a0,a1)=>(Module["_sqlite3_column_name16"]=wasmExports["pc"])(a0,a1);Module["_sqlite3_bind_blob"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_blob"]=wasmExports["qc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_blob64"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_bind_blob64"]=wasmExports["rc"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_bind_double"]=(a0,a1,a2)=>(Module["_sqlite3_bind_double"]=wasmExports["sc"])(a0,a1,a2);Module["_sqlite3_bind_int"]=(a0,a1,a2)=>(Module["_sqlite3_bind_int"]=wasmExports["tc"])(a0,a1,a2);Module["_sqlite3_bind_int64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_bind_int64"]=wasmExports["uc"])(a0,a1,a2,a3);Module["_sqlite3_bind_null"]=(a0,a1)=>(Module["_sqlite3_bind_null"]=wasmExports["vc"])(a0,a1);Module["_sqlite3_bind_pointer"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_pointer"]=wasmExports["wc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_text"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_text"]=wasmExports["xc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_text64"]=(a0,a1,a2,a3,a4,a5,a6)=>(Module["_sqlite3_bind_text64"]=wasmExports["yc"])(a0,a1,a2,a3,a4,a5,a6);Module["_sqlite3_bind_text16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_text16"]=wasmExports["zc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_value"]=(a0,a1,a2)=>(Module["_sqlite3_bind_value"]=wasmExports["Ac"])(a0,a1,a2);Module["_sqlite3_bind_zeroblob"]=(a0,a1,a2)=>(Module["_sqlite3_bind_zeroblob"]=wasmExports["Bc"])(a0,a1,a2);Module["_sqlite3_bind_zeroblob64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_bind_zeroblob64"]=wasmExports["Cc"])(a0,a1,a2,a3);Module["_sqlite3_bind_parameter_count"]=a0=>(Module["_sqlite3_bind_parameter_count"]=wasmExports["Dc"])(a0);Module["_sqlite3_bind_parameter_name"]=(a0,a1)=>(Module["_sqlite3_bind_parameter_name"]=wasmExports["Ec"])(a0,a1);Module["_sqlite3_bind_parameter_index"]=(a0,a1)=>(Module["_sqlite3_bind_parameter_index"]=wasmExports["Fc"])(a0,a1);Module["_sqlite3_db_handle"]=a0=>(Module["_sqlite3_db_handle"]=wasmExports["Gc"])(a0);Module["_sqlite3_stmt_readonly"]=a0=>(Module["_sqlite3_stmt_readonly"]=wasmExports["Hc"])(a0);Module["_sqlite3_stmt_isexplain"]=a0=>(Module["_sqlite3_stmt_isexplain"]=wasmExports["Ic"])(a0);Module["_sqlite3_stmt_explain"]=(a0,a1)=>(Module["_sqlite3_stmt_explain"]=wasmExports["Jc"])(a0,a1);Module["_sqlite3_stmt_busy"]=a0=>(Module["_sqlite3_stmt_busy"]=wasmExports["Kc"])(a0);Module["_sqlite3_next_stmt"]=(a0,a1)=>(Module["_sqlite3_next_stmt"]=wasmExports["Lc"])(a0,a1);Module["_sqlite3_stmt_status"]=(a0,a1,a2)=>(Module["_sqlite3_stmt_status"]=wasmExports["Mc"])(a0,a1,a2);Module["_sqlite3_sql"]=a0=>(Module["_sqlite3_sql"]=wasmExports["Nc"])(a0);Module["_sqlite3_expanded_sql"]=a0=>(Module["_sqlite3_expanded_sql"]=wasmExports["Oc"])(a0);Module["_sqlite3_value_numeric_type"]=a0=>(Module["_sqlite3_value_numeric_type"]=wasmExports["Pc"])(a0);Module["_sqlite3_blob_open"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_blob_open"]=wasmExports["Qc"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_blob_close"]=a0=>(Module["_sqlite3_blob_close"]=wasmExports["Rc"])(a0);Module["_sqlite3_blob_read"]=(a0,a1,a2,a3)=>(Module["_sqlite3_blob_read"]=wasmExports["Sc"])(a0,a1,a2,a3);Module["_sqlite3_blob_write"]=(a0,a1,a2,a3)=>(Module["_sqlite3_blob_write"]=wasmExports["Tc"])(a0,a1,a2,a3);Module["_sqlite3_blob_bytes"]=a0=>(Module["_sqlite3_blob_bytes"]=wasmExports["Uc"])(a0);Module["_sqlite3_blob_reopen"]=(a0,a1,a2)=>(Module["_sqlite3_blob_reopen"]=wasmExports["Vc"])(a0,a1,a2);Module["_sqlite3_set_authorizer"]=(a0,a1,a2)=>(Module["_sqlite3_set_authorizer"]=wasmExports["Wc"])(a0,a1,a2);Module["_sqlite3_strglob"]=(a0,a1)=>(Module["_sqlite3_strglob"]=wasmExports["Xc"])(a0,a1);Module["_sqlite3_strlike"]=(a0,a1,a2)=>(Module["_sqlite3_strlike"]=wasmExports["Yc"])(a0,a1,a2);Module["_sqlite3_errmsg"]=a0=>(Module["_sqlite3_errmsg"]=wasmExports["Zc"])(a0);Module["_sqlite3_auto_extension"]=a0=>(Module["_sqlite3_auto_extension"]=wasmExports["_c"])(a0);Module["_sqlite3_cancel_auto_extension"]=a0=>(Module["_sqlite3_cancel_auto_extension"]=wasmExports["$c"])(a0);Module["_sqlite3_reset_auto_extension"]=()=>(Module["_sqlite3_reset_auto_extension"]=wasmExports["ad"])();Module["_sqlite3_prepare"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare"]=wasmExports["bd"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare_v3"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_prepare_v3"]=wasmExports["cd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_prepare16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare16"]=wasmExports["dd"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare16_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare16_v2"]=wasmExports["ed"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare16_v3"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_prepare16_v3"]=wasmExports["fd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_get_table"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_get_table"]=wasmExports["gd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_free_table"]=a0=>(Module["_sqlite3_free_table"]=wasmExports["hd"])(a0);Module["_sqlite3_create_module"]=(a0,a1,a2,a3)=>(Module["_sqlite3_create_module"]=wasmExports["id"])(a0,a1,a2,a3);Module["_sqlite3_create_module_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_module_v2"]=wasmExports["jd"])(a0,a1,a2,a3,a4);Module["_sqlite3_drop_modules"]=(a0,a1)=>(Module["_sqlite3_drop_modules"]=wasmExports["kd"])(a0,a1);Module["_sqlite3_declare_vtab"]=(a0,a1)=>(Module["_sqlite3_declare_vtab"]=wasmExports["ld"])(a0,a1);Module["_sqlite3_vtab_on_conflict"]=a0=>(Module["_sqlite3_vtab_on_conflict"]=wasmExports["md"])(a0);Module["_sqlite3_vtab_config"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_config"]=wasmExports["nd"])(a0,a1,a2);Module["_sqlite3_vtab_collation"]=(a0,a1)=>(Module["_sqlite3_vtab_collation"]=wasmExports["od"])(a0,a1);Module["_sqlite3_vtab_in"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_in"]=wasmExports["pd"])(a0,a1,a2);Module["_sqlite3_vtab_rhs_value"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_rhs_value"]=wasmExports["qd"])(a0,a1,a2);Module["_sqlite3_vtab_distinct"]=a0=>(Module["_sqlite3_vtab_distinct"]=wasmExports["rd"])(a0);Module["_sqlite3_keyword_name"]=(a0,a1,a2)=>(Module["_sqlite3_keyword_name"]=wasmExports["sd"])(a0,a1,a2);Module["_sqlite3_keyword_count"]=()=>(Module["_sqlite3_keyword_count"]=wasmExports["td"])();Module["_sqlite3_keyword_check"]=(a0,a1)=>(Module["_sqlite3_keyword_check"]=wasmExports["ud"])(a0,a1);Module["_sqlite3_complete"]=a0=>(Module["_sqlite3_complete"]=wasmExports["vd"])(a0);Module["_sqlite3_complete16"]=a0=>(Module["_sqlite3_complete16"]=wasmExports["wd"])(a0);Module["_sqlite3_libversion"]=()=>(Module["_sqlite3_libversion"]=wasmExports["xd"])();Module["_sqlite3_libversion_number"]=()=>(Module["_sqlite3_libversion_number"]=wasmExports["yd"])();Module["_sqlite3_threadsafe"]=()=>(Module["_sqlite3_threadsafe"]=wasmExports["zd"])();Module["_sqlite3_initialize"]=()=>(Module["_sqlite3_initialize"]=wasmExports["Ad"])();Module["_sqlite3_shutdown"]=()=>(Module["_sqlite3_shutdown"]=wasmExports["Bd"])();Module["_sqlite3_config"]=(a0,a1)=>(Module["_sqlite3_config"]=wasmExports["Cd"])(a0,a1);Module["_sqlite3_db_mutex"]=a0=>(Module["_sqlite3_db_mutex"]=wasmExports["Dd"])(a0);Module["_sqlite3_db_release_memory"]=a0=>(Module["_sqlite3_db_release_memory"]=wasmExports["Ed"])(a0);Module["_sqlite3_db_cacheflush"]=a0=>(Module["_sqlite3_db_cacheflush"]=wasmExports["Fd"])(a0);Module["_sqlite3_db_config"]=(a0,a1,a2)=>(Module["_sqlite3_db_config"]=wasmExports["Gd"])(a0,a1,a2);Module["_sqlite3_last_insert_rowid"]=a0=>(Module["_sqlite3_last_insert_rowid"]=wasmExports["Hd"])(a0);Module["_sqlite3_set_last_insert_rowid"]=(a0,a1,a2)=>(Module["_sqlite3_set_last_insert_rowid"]=wasmExports["Id"])(a0,a1,a2);Module["_sqlite3_changes64"]=a0=>(Module["_sqlite3_changes64"]=wasmExports["Jd"])(a0);Module["_sqlite3_changes"]=a0=>(Module["_sqlite3_changes"]=wasmExports["Kd"])(a0);Module["_sqlite3_total_changes64"]=a0=>(Module["_sqlite3_total_changes64"]=wasmExports["Ld"])(a0);Module["_sqlite3_total_changes"]=a0=>(Module["_sqlite3_total_changes"]=wasmExports["Md"])(a0);Module["_sqlite3_txn_state"]=(a0,a1)=>(Module["_sqlite3_txn_state"]=wasmExports["Nd"])(a0,a1);Module["_sqlite3_close"]=a0=>(Module["_sqlite3_close"]=wasmExports["Od"])(a0);Module["_sqlite3_close_v2"]=a0=>(Module["_sqlite3_close_v2"]=wasmExports["Pd"])(a0);Module["_sqlite3_busy_handler"]=(a0,a1,a2)=>(Module["_sqlite3_busy_handler"]=wasmExports["Qd"])(a0,a1,a2);Module["_sqlite3_progress_handler"]=(a0,a1,a2,a3)=>(Module["_sqlite3_progress_handler"]=wasmExports["Rd"])(a0,a1,a2,a3);Module["_sqlite3_busy_timeout"]=(a0,a1)=>(Module["_sqlite3_busy_timeout"]=wasmExports["Sd"])(a0,a1);Module["_sqlite3_interrupt"]=a0=>(Module["_sqlite3_interrupt"]=wasmExports["Td"])(a0);Module["_sqlite3_is_interrupted"]=a0=>(Module["_sqlite3_is_interrupted"]=wasmExports["Ud"])(a0);Module["_sqlite3_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_create_function"]=wasmExports["Vd"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_create_function_v2"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(Module["_sqlite3_create_function_v2"]=wasmExports["Wd"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);Module["_sqlite3_create_window_function"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(Module["_sqlite3_create_window_function"]=wasmExports["Xd"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);Module["_sqlite3_create_function16"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_create_function16"]=wasmExports["Yd"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_overload_function"]=(a0,a1,a2)=>(Module["_sqlite3_overload_function"]=wasmExports["Zd"])(a0,a1,a2);Module["_sqlite3_trace_v2"]=(a0,a1,a2,a3)=>(Module["_sqlite3_trace_v2"]=wasmExports["_d"])(a0,a1,a2,a3);Module["_sqlite3_commit_hook"]=(a0,a1,a2)=>(Module["_sqlite3_commit_hook"]=wasmExports["$d"])(a0,a1,a2);Module["_sqlite3_update_hook"]=(a0,a1,a2)=>(Module["_sqlite3_update_hook"]=wasmExports["ae"])(a0,a1,a2);Module["_sqlite3_rollback_hook"]=(a0,a1,a2)=>(Module["_sqlite3_rollback_hook"]=wasmExports["be"])(a0,a1,a2);Module["_sqlite3_autovacuum_pages"]=(a0,a1,a2,a3)=>(Module["_sqlite3_autovacuum_pages"]=wasmExports["ce"])(a0,a1,a2,a3);Module["_sqlite3_wal_autocheckpoint"]=(a0,a1)=>(Module["_sqlite3_wal_autocheckpoint"]=wasmExports["de"])(a0,a1);Module["_sqlite3_wal_hook"]=(a0,a1,a2)=>(Module["_sqlite3_wal_hook"]=wasmExports["ee"])(a0,a1,a2);Module["_sqlite3_wal_checkpoint_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_wal_checkpoint_v2"]=wasmExports["fe"])(a0,a1,a2,a3,a4);Module["_sqlite3_wal_checkpoint"]=(a0,a1)=>(Module["_sqlite3_wal_checkpoint"]=wasmExports["ge"])(a0,a1);Module["_sqlite3_error_offset"]=a0=>(Module["_sqlite3_error_offset"]=wasmExports["he"])(a0);Module["_sqlite3_errmsg16"]=a0=>(Module["_sqlite3_errmsg16"]=wasmExports["ie"])(a0);Module["_sqlite3_errcode"]=a0=>(Module["_sqlite3_errcode"]=wasmExports["je"])(a0);Module["_sqlite3_extended_errcode"]=a0=>(Module["_sqlite3_extended_errcode"]=wasmExports["ke"])(a0);Module["_sqlite3_system_errno"]=a0=>(Module["_sqlite3_system_errno"]=wasmExports["le"])(a0);Module["_sqlite3_errstr"]=a0=>(Module["_sqlite3_errstr"]=wasmExports["me"])(a0);Module["_sqlite3_limit"]=(a0,a1,a2)=>(Module["_sqlite3_limit"]=wasmExports["ne"])(a0,a1,a2);Module["_sqlite3_open"]=(a0,a1)=>(Module["_sqlite3_open"]=wasmExports["oe"])(a0,a1);Module["_sqlite3_open_v2"]=(a0,a1,a2,a3)=>(Module["_sqlite3_open_v2"]=wasmExports["pe"])(a0,a1,a2,a3);Module["_sqlite3_open16"]=(a0,a1)=>(Module["_sqlite3_open16"]=wasmExports["qe"])(a0,a1);Module["_sqlite3_create_collation"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_collation"]=wasmExports["re"])(a0,a1,a2,a3,a4);Module["_sqlite3_create_collation_v2"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_create_collation_v2"]=wasmExports["se"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_create_collation16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_collation16"]=wasmExports["te"])(a0,a1,a2,a3,a4);Module["_sqlite3_collation_needed"]=(a0,a1,a2)=>(Module["_sqlite3_collation_needed"]=wasmExports["ue"])(a0,a1,a2);Module["_sqlite3_collation_needed16"]=(a0,a1,a2)=>(Module["_sqlite3_collation_needed16"]=wasmExports["ve"])(a0,a1,a2);Module["_sqlite3_get_clientdata"]=(a0,a1)=>(Module["_sqlite3_get_clientdata"]=wasmExports["we"])(a0,a1);Module["_sqlite3_set_clientdata"]=(a0,a1,a2,a3)=>(Module["_sqlite3_set_clientdata"]=wasmExports["xe"])(a0,a1,a2,a3);Module["_sqlite3_get_autocommit"]=a0=>(Module["_sqlite3_get_autocommit"]=wasmExports["ye"])(a0);Module["_sqlite3_table_column_metadata"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(Module["_sqlite3_table_column_metadata"]=wasmExports["ze"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);Module["_sqlite3_sleep"]=a0=>(Module["_sqlite3_sleep"]=wasmExports["Ae"])(a0);Module["_sqlite3_extended_result_codes"]=(a0,a1)=>(Module["_sqlite3_extended_result_codes"]=wasmExports["Be"])(a0,a1);Module["_sqlite3_file_control"]=(a0,a1,a2,a3)=>(Module["_sqlite3_file_control"]=wasmExports["Ce"])(a0,a1,a2,a3);Module["_sqlite3_test_control"]=(a0,a1)=>(Module["_sqlite3_test_control"]=wasmExports["De"])(a0,a1);Module["_sqlite3_create_filename"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_filename"]=wasmExports["Ee"])(a0,a1,a2,a3,a4);Module["_sqlite3_free_filename"]=a0=>(Module["_sqlite3_free_filename"]=wasmExports["Fe"])(a0);Module["_sqlite3_uri_parameter"]=(a0,a1)=>(Module["_sqlite3_uri_parameter"]=wasmExports["Ge"])(a0,a1);Module["_sqlite3_uri_key"]=(a0,a1)=>(Module["_sqlite3_uri_key"]=wasmExports["He"])(a0,a1);Module["_sqlite3_uri_boolean"]=(a0,a1,a2)=>(Module["_sqlite3_uri_boolean"]=wasmExports["Ie"])(a0,a1,a2);Module["_sqlite3_uri_int64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_uri_int64"]=wasmExports["Je"])(a0,a1,a2,a3);Module["_sqlite3_filename_database"]=a0=>(Module["_sqlite3_filename_database"]=wasmExports["Ke"])(a0);Module["_sqlite3_filename_journal"]=a0=>(Module["_sqlite3_filename_journal"]=wasmExports["Le"])(a0);Module["_sqlite3_filename_wal"]=a0=>(Module["_sqlite3_filename_wal"]=wasmExports["Me"])(a0);Module["_sqlite3_db_name"]=(a0,a1)=>(Module["_sqlite3_db_name"]=wasmExports["Ne"])(a0,a1);Module["_sqlite3_db_filename"]=(a0,a1)=>(Module["_sqlite3_db_filename"]=wasmExports["Oe"])(a0,a1);Module["_sqlite3_db_readonly"]=(a0,a1)=>(Module["_sqlite3_db_readonly"]=wasmExports["Pe"])(a0,a1);Module["_sqlite3_compileoption_used"]=a0=>(Module["_sqlite3_compileoption_used"]=wasmExports["Qe"])(a0);Module["_sqlite3_compileoption_get"]=a0=>(Module["_sqlite3_compileoption_get"]=wasmExports["Re"])(a0);Module["_sqlite3_sourceid"]=()=>(Module["_sqlite3_sourceid"]=wasmExports["Se"])();Module["_malloc"]=a0=>(Module["_malloc"]=wasmExports["Te"])(a0);Module["_free"]=a0=>(Module["_free"]=wasmExports["Ue"])(a0);Module["_RegisterExtensionFunctions"]=a0=>(Module["_RegisterExtensionFunctions"]=wasmExports["Ve"])(a0);Module["_getSqliteFree"]=()=>(Module["_getSqliteFree"]=wasmExports["We"])();var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["Xe"])(a0,a1);Module["_libauthorizer_set_authorizer"]=(a0,a1,a2)=>(Module["_libauthorizer_set_authorizer"]=wasmExports["Ye"])(a0,a1,a2);Module["_libfunction_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_libfunction_create_function"]=wasmExports["Ze"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_libprogress_progress_handler"]=(a0,a1,a2,a3)=>(Module["_libprogress_progress_handler"]=wasmExports["_e"])(a0,a1,a2,a3);Module["_libvfs_vfs_register"]=(a0,a1,a2,a3,a4,a5)=>(Module["_libvfs_vfs_register"]=wasmExports["$e"])(a0,a1,a2,a3,a4,a5);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["bf"])(a0,a1);var __emscripten_tempret_get=()=>(__emscripten_tempret_get=wasmExports["cf"])();var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["df"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["ef"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["ff"])();Module["_sqlite3_version"]=5472;Module["getTempRet0"]=getTempRet0;Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["addFunction"]=addFunction;Module["setValue"]=setValue;Module["getValue"]=getValue;Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;Module["intArrayFromString"]=intArrayFromString;Module["intArrayToString"]=intArrayToString;Module["AsciiToString"]=AsciiToString;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;Module["UTF32ToString"]=UTF32ToString;Module["stringToUTF32"]=stringToUTF32;Module["writeArrayToMemory"]=writeArrayToMemory;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller;};function callMain(){var entryFunction=_main;var argc=0;var argv=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();if(shouldRunNow)callMain();postRun();}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("");},1);doRun();},1);}else {doRun();}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()();}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;let pAsyncFlags=0;Module["set_authorizer"]=function(db,xAuthorizer,pApp){if(pAsyncFlags){Module["deleteCallback"](pAsyncFlags);Module["_sqlite3_free"](pAsyncFlags);pAsyncFlags=0;}pAsyncFlags=Module["_sqlite3_malloc"](4);setValue(pAsyncFlags,xAuthorizer instanceof AsyncFunction?1:0,"i32");const result=ccall("libauthorizer_set_authorizer","number",["number","number","number"],[db,xAuthorizer?1:0,pAsyncFlags]);if(!result&&xAuthorizer){Module["setCallback"](pAsyncFlags,(_,iAction,p3,p4,p5,p6)=>xAuthorizer(pApp,iAction,p3,p4,p5,p6));}return result};})();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;const FUNC_METHODS=["xFunc","xStep","xFinal"];const mapFunctionNameToKey=new Map;Module["create_function"]=function(db,zFunctionName,nArg,eTextRep,pApp,xFunc,xStep,xFinal){const pAsyncFlags=Module["_sqlite3_malloc"](4);const target={xFunc:xFunc,xStep:xStep,xFinal:xFinal};setValue(pAsyncFlags,FUNC_METHODS.reduce((mask,method,i)=>{if(target[method]instanceof AsyncFunction){return mask|1<xProgress(pApp));}};})();(function(){const VFS_METHODS=["xOpen","xDelete","xAccess","xFullPathname","xRandomness","xSleep","xCurrentTime","xGetLastError","xCurrentTimeInt64","xClose","xRead","xWrite","xTruncate","xSync","xFileSize","xLock","xUnlock","xCheckReservedLock","xFileControl","xSectorSize","xDeviceCharacteristics","xShmMap","xShmLock","xShmBarrier","xShmUnmap"];const mapVFSNameToKey=new Map;Module["vfs_register"]=function(vfs,makeDefault){let methodMask=0;let asyncMask=0;VFS_METHODS.forEach((method,i)=>{if(vfs[method]){methodMask|=1< { + console.log(row); + }); + } catch (error) { + console.log("exec err"); + throw error; + } + } + + finalize(stmt) { + try { + return this.sqlite3.finalize(stmt); + } catch (error) { + console.log("stmt error"); + } + } + + changes(db) { + return this.sqlite3.changes(db); + } + + clear_bindings(stmt) { + return this.sqlite3.clear_bindings(stmt); + } + + async close(db) { + try { + return this.sqlite3.close(db); + } catch (error) { + console.log("sqlite3.close error"); + throw error; + } + } + + column(stmt, i) { + return this.sqlite3.column(stmt, i); + } + + async prepare(database, sql, options) { + try { + return await this.sqlite3.statements(database, sql, options); + } catch (error) { + console.log("sqlite prepare error"); + throw error; + } + } + + async step(stmt) { + try { + return await this.sqlite3.step(stmt); + } catch (error) { + console.log("sqlite step error"); + throw error; + } + } + + column_name(stmt, idx) { + return this.sqlite3.column_name(stmt, idx); + } + + column_count(stmt) { + return this.sqlite3.column_count(stmt); + } + + batch_execute(database, query) { + try { + return this.sqlite3.exec(database, query); + console.log("Batch exec'ed"); + } catch { + console.log("exec err"); + } + } + + create_function( + database, + functionName, + nArg, + textRep, + pApp, + xFunc, + xStep, + xFinal, + ) { + try { + this.sqlite3.create_function( + database, + functionName, + nArg, + textRep, + pApp, // pApp is ignored + xFunc, + xStep, + xFinal, + ); + console.log("create function"); + } catch { + console.log("create function err"); + } + } + + register_diesel_sql_functions(database) { + try { + this.sqlite3.create_function( + database, + "diesel_manage_updated_at", + 1, + SQLITE_UTF8, + 0, + (context, values) => { + const table_name = this.sqlite3.value_text(values[0]); + + this.sqlite3.exec( + context, + `CREATE TRIGGER __diesel_manage_updated_at_${table_name} + AFTER UPDATE ON ${table_name} + FOR EACH ROW WHEN + old.updated_at IS NULL AND + new.updated_at IS NULL OR + old.updated_at == new.updated_at + BEGIN + UPDATE ${table_name} + SET updated_at = CURRENT_TIMESTAMP + WHERE ROWID = new.ROWID; + END`, + (row, columns) => { + console.log(`------------------------------------`); + console.log(`Created trigger for ${table_name}`); + console.log(row); + console.log(columns); + console.log(`------------------------------------`); + }, + ); + }, + ); + } catch (error) { + } + } + + /* + serialize(database, zSchema, size, flags) { + return this.module._sqlite3_serialize(database, zSchema, size, flags); + } + */ +} + +export { SQLite }; diff --git a/diesel-wasm-sqlite/tests/web.rs b/diesel-wasm-sqlite/tests/web.rs new file mode 100755 index 000000000..b8a3a28a5 --- /dev/null +++ b/diesel-wasm-sqlite/tests/web.rs @@ -0,0 +1,61 @@ +#![cfg(target_arch = "wasm32")] + +use diesel::connection::Connection; +use diesel_wasm_sqlite::connection::{AsyncConnection, WasmSqliteConnection}; +use wasm_bindgen_test::*; +use web_sys::console; +wasm_bindgen_test_configure!(run_in_dedicated_worker); +/* +#[wasm_bindgen_test] +async fn test_establish_and_exec() { + let rng: u16 = rand::random(); + let result = WasmSqliteConnection::establish("test-15873").await; + let mut conn = result.unwrap(); + console::log_1(&"CONNECTED".into()); + + let raw = conn.raw_connection; + + console::log_1(&"CREATE".into()); + raw.exec( + " + CREATE TABLE books ( + id INTEGER PRIMARY KEY, + title TEXT NOT NULL, + author TEXT NOT NULL, + published_year INTEGER, + genre TEXT + );", + ) + .await; + + console::log_1(&"INSERT".into()); + raw.exec( + " + INSERT INTO books (title, author, published_year, genre) VALUES + ('To Kill a Mockingbird', 'Harper Lee', 1960, 'Fiction'), + ('1984', 'George Orwell', 1949, 'Dystopian'), + ('The Great Gatsby', 'F. Scott Fitzgerald', 1925, 'Classics'), + ('Pride and Prejudice', 'Jane Austen', 1813, 'Romance'); + ", + ) + .await; + + console::log_1(&"SELECT ALL".into()); + raw.exec("SELECT * FROM books").await; + + console::log_1(&"SELECT title, author FROM books WHERE published_year > 1950;".into()); + raw.exec( + " + + SELECT title, published_year FROM books WHERE author = 'George Orwell'; + ", + ) + .await; + + console::log_1( + &"SELECT title, published_year FROM books WHERE author = 'George Orwell';".into(), + ); + raw.exec("SELECT title, author FROM books WHERE published_year > 1950;".into()) + .await; +} +*/ diff --git a/diesel-wasm-sqlite/yarn.lock b/diesel-wasm-sqlite/yarn.lock new file mode 100644 index 000000000..59311254a --- /dev/null +++ b/diesel-wasm-sqlite/yarn.lock @@ -0,0 +1,1640 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10 + +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 10/e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 + languageName: node + linkType: hard + +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" + dependencies: + "@nodelib/fs.stat": "npm:2.0.5" + run-parallel: "npm:^1.1.9" + checksum: 10/6ab2a9b8a1d67b067922c36f259e3b3dfd6b97b219c540877a4944549a4d49ea5ceba5663905ab5289682f1f3c15ff441d02f0447f620a42e1cb5e1937174d4b + languageName: node + linkType: hard + +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 10/012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 + languageName: node + linkType: hard + +"@nodelib/fs.walk@npm:^1.2.3": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" + dependencies: + "@nodelib/fs.scandir": "npm:2.1.5" + fastq: "npm:^1.6.0" + checksum: 10/40033e33e96e97d77fba5a238e4bba4487b8284678906a9f616b5579ddaf868a18874c0054a75402c9fbaaa033a25ceae093af58c9c30278e35c23c9479e79b0 + languageName: node + linkType: hard + +"@npmcli/agent@npm:^2.0.0": + version: 2.2.2 + resolution: "@npmcli/agent@npm:2.2.2" + dependencies: + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^10.0.1" + socks-proxy-agent: "npm:^8.0.3" + checksum: 10/96fc0036b101bae5032dc2a4cd832efb815ce9b33f9ee2f29909ee49d96a0026b3565f73c507a69eb8603f5cb32e0ae45a70cab1e2655990a4e06ae99f7f572a + languageName: node + linkType: hard + +"@npmcli/fs@npm:^3.1.0": + version: 3.1.1 + resolution: "@npmcli/fs@npm:3.1.1" + dependencies: + semver: "npm:^7.3.5" + checksum: 10/1e0e04087049b24b38bc0b30d87a9388ee3ca1d3fdfc347c2f77d84fcfe6a51f250bc57ba2c1f614d7e4285c6c62bf8c769bc19aa0949ea39e5b043ee023b0bd + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 10/115e8ceeec6bc69dff2048b35c0ab4f8bbee12d8bb6c1f4af758604586d802b6e669dcb02dda61d078de42c2b4ddce41b3d9e726d7daa6b4b850f4adbf7333ff + languageName: node + linkType: hard + +"@rollup/plugin-node-resolve@npm:^15.2.3": + version: 15.2.3 + resolution: "@rollup/plugin-node-resolve@npm:15.2.3" + dependencies: + "@rollup/pluginutils": "npm:^5.0.1" + "@types/resolve": "npm:1.20.2" + deepmerge: "npm:^4.2.2" + is-builtin-module: "npm:^3.2.1" + is-module: "npm:^1.0.0" + resolve: "npm:^1.22.1" + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10/d36a6792fbe9d8673d3a7c7dc88920be669ac54fba02ac0093d3c00fc9463fce2e87da1906a2651016742709c3d202b367fb49a62acd0d98f18409343f27b8b4 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^3.1.0": + version: 3.1.0 + resolution: "@rollup/pluginutils@npm:3.1.0" + dependencies: + "@types/estree": "npm:0.0.39" + estree-walker: "npm:^1.0.1" + picomatch: "npm:^2.2.2" + peerDependencies: + rollup: ^1.20.0||^2.0.0 + checksum: 10/3b69f02893eea42455fb97b81f612ac6bfadf94ac73bebd481ea13e90a693eef52c163210a095b12e574a25603af5e55f86a020889019167f331aa8dd3ff30e0 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^5.0.1": + version: 5.1.0 + resolution: "@rollup/pluginutils@npm:5.1.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-walker: "npm:^2.0.2" + picomatch: "npm:^2.3.1" + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10/abb15eaec5b36f159ec351b48578401bedcefdfa371d24a914cfdbb1e27d0ebfbf895299ec18ccc343d247e71f2502cba21202bc1362d7ef27d5ded699e5c2b2 + languageName: node + linkType: hard + +"@rollup/rollup-android-arm-eabi@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.19.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-android-arm64@npm:4.19.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.19.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.19.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.19.0" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.19.0" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.19.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.19.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.19.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.19.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.19.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.19.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.19.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.19.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.19.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.19.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@types/estree@npm:0.0.39": + version: 0.0.39 + resolution: "@types/estree@npm:0.0.39" + checksum: 10/9f0f20990dbf725470564d4d815d3758ac688b790f601ea98654b6e0b9797dc3c80306fb525abdacd9e75e014e3d09ad326098eaa2ed1851e4823a8e278538aa + languageName: node + linkType: hard + +"@types/estree@npm:1.0.5, @types/estree@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: 10/7de6d928dd4010b0e20c6919e1a6c27b61f8d4567befa89252055fad503d587ecb9a1e3eab1b1901f923964d7019796db810b7fd6430acb26c32866d126fd408 + languageName: node + linkType: hard + +"@types/fs-extra@npm:^8.0.1": + version: 8.1.5 + resolution: "@types/fs-extra@npm:8.1.5" + dependencies: + "@types/node": "npm:*" + checksum: 10/565d9e55cd05064b3ab272b8748ed512b8fa5cddc23fd32b0d5f147f9ea3a45981577c4478b5060cae7b3d914c508bd2ea97eb84d9c1fa6f967982c892e4ab26 + languageName: node + linkType: hard + +"@types/glob@npm:^7.1.1": + version: 7.2.0 + resolution: "@types/glob@npm:7.2.0" + dependencies: + "@types/minimatch": "npm:*" + "@types/node": "npm:*" + checksum: 10/6ae717fedfdfdad25f3d5a568323926c64f52ef35897bcac8aca8e19bc50c0bd84630bbd063e5d52078b2137d8e7d3c26eabebd1a2f03ff350fff8a91e79fc19 + languageName: node + linkType: hard + +"@types/minimatch@npm:*": + version: 5.1.2 + resolution: "@types/minimatch@npm:5.1.2" + checksum: 10/94db5060d20df2b80d77b74dd384df3115f01889b5b6c40fa2dfa27cfc03a68fb0ff7c1f2a0366070263eb2e9d6bfd8c87111d4bc3ae93c3f291297c1bf56c85 + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 20.14.11 + resolution: "@types/node@npm:20.14.11" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10/344e1ce1ed16c86ed1c4209ab4d1de67db83dd6b694a6fabe295c47144dde2c58dabddae9f39a0a2bdd246e95f8d141ccfe848e464884b48b8918df4f7788025 + languageName: node + linkType: hard + +"@types/resolve@npm:1.20.2": + version: 1.20.2 + resolution: "@types/resolve@npm:1.20.2" + checksum: 10/1bff0d3875e7e1557b6c030c465beca9bf3b1173ebc6937cac547654b0af3bb3ff0f16470e9c4d7c5dc308ad9ac8627c38dbff24ef698b66673ff5bd4ead7f7e + languageName: node + linkType: hard + +"@xmtp/wa-sqlite@npm:^1.0.1": + version: 1.0.1 + resolution: "@xmtp/wa-sqlite@npm:1.0.1" + dependenciesMeta: + monaco-editor@0.34.1: + unplugged: true + web-test-runner-jasmine@0.0.6: + unplugged: true + checksum: 10/bd08dd04fb98fef2f791274a502f6227c2050c92fdce288576d68c5e864efea2653217cfef73f134ed27999e90ad7300a64a1ab8344eeb9e9c6c2f802b7a7c64 + languageName: node + linkType: hard + +"abbrev@npm:^2.0.0": + version: 2.0.0 + resolution: "abbrev@npm:2.0.0" + checksum: 10/ca0a54e35bea4ece0ecb68a47b312e1a9a6f772408d5bcb9051230aaa94b0460671c5b5c9cb3240eb5b7bc94c52476550eb221f65a0bbd0145bdc9f3113a6707 + languageName: node + linkType: hard + +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": + version: 7.1.1 + resolution: "agent-base@npm:7.1.1" + dependencies: + debug: "npm:^4.3.4" + checksum: 10/c478fec8f79953f118704d007a38f2a185458853f5c45579b9669372bd0e12602e88dc2ad0233077831504f7cd6fcc8251c383375bba5eaaf563b102938bda26 + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: "npm:^2.0.0" + indent-string: "npm:^4.0.0" + checksum: 10/1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 10/2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b + languageName: node + linkType: hard + +"ansi-regex@npm:^6.0.1": + version: 6.0.1 + resolution: "ansi-regex@npm:6.0.1" + checksum: 10/1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 + 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: 10/b4494dfbfc7e4591b4711a396bd27e540f8153914123dccb4cdbbcb514015ada63a3809f362b9d8d4f6b17a706f1d7bea3c6f974b15fa5ae76b5b502070889ff + languageName: node + linkType: hard + +"ansi-styles@npm:^6.1.0": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: 10/70fdf883b704d17a5dfc9cde206e698c16bcd74e7f196ab821511651aee4f9f76c9514bdfa6ca3a27b5e49138b89cb222a28caf3afe4567570139577f991df32 + languageName: node + linkType: hard + +"array-union@npm:^2.1.0": + version: 2.1.0 + resolution: "array-union@npm:2.1.0" + checksum: 10/5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10/9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" + dependencies: + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + languageName: node + linkType: hard + +"brace-expansion@npm:^2.0.1": + version: 2.0.1 + resolution: "brace-expansion@npm:2.0.1" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: 10/a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 + languageName: node + linkType: hard + +"braces@npm:^3.0.3": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: "npm:^7.1.1" + checksum: 10/fad11a0d4697a27162840b02b1fad249c1683cbc510cd5bf1a471f2f8085c046d41094308c577a50a03a579dd99d5a6b3724c4b5e8b14df2c4443844cfcda2c6 + languageName: node + linkType: hard + +"builtin-modules@npm:^3.3.0": + version: 3.3.0 + resolution: "builtin-modules@npm:3.3.0" + checksum: 10/62e063ab40c0c1efccbfa9ffa31873e4f9d57408cb396a2649981a0ecbce56aabc93c28feaccbc5658c95aab2703ad1d11980e62ec2e5e72637404e1eb60f39e + languageName: node + linkType: hard + +"cacache@npm:^18.0.0": + version: 18.0.4 + resolution: "cacache@npm:18.0.4" + dependencies: + "@npmcli/fs": "npm:^3.1.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^10.2.2" + lru-cache: "npm:^10.0.1" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^4.0.0" + ssri: "npm:^10.0.0" + tar: "npm:^6.1.11" + unique-filename: "npm:^3.0.0" + checksum: 10/ca2f7b2d3003f84d362da9580b5561058ccaecd46cba661cbcff0375c90734b610520d46b472a339fd032d91597ad6ed12dde8af81571197f3c9772b5d35b104 + languageName: node + linkType: hard + +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: 10/c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 10/2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 + 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: 10/fa00c91b4332b294de06b443923246bccebe9fab1b253f7fe1772d37b06a2269b4039a85e309abe1fe11b267b11c08d1d0473fda3badd6167f57313af2887a64 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: 10/b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 + languageName: node + linkType: hard + +"colorette@npm:^1.1.0": + version: 1.4.0 + resolution: "colorette@npm:1.4.0" + checksum: 10/c8d6c8c3ef5a99acfc3dd9a68f48019f1479ec347551387e4a1762e40f69e98ce19d4dc321ffb4919d1f28a7bdc90c39d4e9a901f4c474fd2124ad93a00c0454 + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 10/9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.0": + version: 7.0.3 + resolution: "cross-spawn@npm:7.0.3" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10/e1a13869d2f57d974de0d9ef7acbf69dc6937db20b918525a01dacb5032129bd552d290d886d981e99f1b624cb03657084cc87bd40f115c07ecf376821c729ce + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.3.4": + version: 4.3.5 + resolution: "debug@npm:4.3.5" + dependencies: + ms: "npm:2.1.2" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10/cb6eab424c410e07813ca1392888589972ce9a32b8829c6508f5e1f25f3c3e70a76731610ae55b4bbe58d1a2fffa1424b30e97fa8d394e49cd2656a9643aedd2 + languageName: node + linkType: hard + +"deepmerge@npm:^4.2.2": + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 10/058d9e1b0ff1a154468bf3837aea436abcfea1ba1d165ddaaf48ca93765fdd01a30d33c36173da8fbbed951dd0a267602bc782fe288b0fc4b7e1e7091afc4529 + languageName: node + linkType: hard + +"diesel-wasm-sqlite@workspace:.": + version: 0.0.0-use.local + resolution: "diesel-wasm-sqlite@workspace:." + dependencies: + "@rollup/plugin-node-resolve": "npm:^15.2.3" + "@xmtp/wa-sqlite": "npm:^1.0.1" + rollup: "npm:^4.19.0" + rollup-plugin-base64: "npm:^1.0.1" + rollup-plugin-copy: "npm:^3.5.0" + languageName: unknown + linkType: soft + +"dir-glob@npm:^3.0.1": + version: 3.0.1 + resolution: "dir-glob@npm:3.0.1" + dependencies: + path-type: "npm:^4.0.0" + checksum: 10/fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 10/9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: 10/c72d67a6821be15ec11997877c437491c313d924306b8da5d87d2a2bcc2cec9903cb5b04ee1a088460501d8e5b44f10df82fdc93c444101a7610b80c8b6938e1 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 10/915acf859cea7131dac1b2b5c9c8e35c4849e325a1d114c30adb8cd615970f6dca0e27f64f3a4949d7d6ed86ecd79a1c5c63f02e697513cddd7b5835c90948b8 + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: "npm:^0.6.2" + checksum: 10/bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10/65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 10/1d20d825cdcce8d811bfbe86340f4755c02655a7feb2f13f8c880566d9d72a3f6c92c192a6867632e490d6da67b678271f46e01044996a6443e870331100dfdd + languageName: node + linkType: hard + +"estree-walker@npm:^1.0.1": + version: 1.0.1 + resolution: "estree-walker@npm:1.0.1" + checksum: 10/1cf11a0aff7613aa765dc535ed1d83e2a1986207d2353f4795df309a2c55726de3ca4948df635c09969a739dc59e8e2d69f88d3b3d2c6dfc5701257aafd1d11b + languageName: node + linkType: hard + +"estree-walker@npm:^2.0.2": + version: 2.0.2 + resolution: "estree-walker@npm:2.0.2" + checksum: 10/b02109c5d46bc2ed47de4990eef770f7457b1159a229f0999a09224d2b85ffeed2d7679cffcff90aeb4448e94b0168feb5265b209cdec29aad50a3d6e93d21e2 + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.1 + resolution: "exponential-backoff@npm:3.1.1" + checksum: 10/2d9bbb6473de7051f96790d5f9a678f32e60ed0aa70741dc7fdc96fec8d631124ec3374ac144387604f05afff9500f31a1d45bd9eee4cdc2e4f9ad2d9b9d5dbd + languageName: node + linkType: hard + +"fast-glob@npm:^3.0.3": + version: 3.3.2 + resolution: "fast-glob@npm:3.3.2" + dependencies: + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.4" + checksum: 10/222512e9315a0efca1276af9adb2127f02105d7288fa746145bf45e2716383fb79eb983c89601a72a399a56b7c18d38ce70457c5466218c5f13fad957cee16df + languageName: node + linkType: hard + +"fastq@npm:^1.6.0": + version: 1.17.1 + resolution: "fastq@npm:1.17.1" + dependencies: + reusify: "npm:^1.0.4" + checksum: 10/a443180068b527dd7b3a63dc7f2a47ceca2f3e97b9c00a1efe5538757e6cc4056a3526df94308075d7727561baf09ebaa5b67da8dcbddb913a021c5ae69d1f69 + languageName: node + linkType: hard + +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10/a7095cb39e5bc32fada2aa7c7249d3f6b01bd1ce461a61b0adabacccabd9198500c6fb1f68a7c851a657e273fce2233ba869638897f3d7ed2e87a2d89b4436ea + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.0": + version: 3.2.1 + resolution: "foreground-child@npm:3.2.1" + dependencies: + cross-spawn: "npm:^7.0.0" + signal-exit: "npm:^4.0.1" + checksum: 10/77b33b3c438a499201727ca84de39a66350ccd54a8805df712773e963cefb5c4632dbc4386109e97a0df8fb1585aee95fa35acb07587e3e04cfacabfc0ae15dc + languageName: node + linkType: hard + +"fs-extra@npm:^8.1.0": + version: 8.1.0 + resolution: "fs-extra@npm:8.1.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^4.0.0" + universalify: "npm:^0.1.0" + checksum: 10/6fb12449f5349be724a138b4a7b45fe6a317d2972054517f5971959c26fbd17c0e145731a11c7324460262baa33e0a799b183ceace98f7a372c95fbb6f20f5de + languageName: node + linkType: hard + +"fs-minipass@npm:^2.0.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10/03191781e94bc9a54bd376d3146f90fe8e082627c502185dbf7b9b3032f66b0b142c1115f3b2cc5936575fc1b44845ce903dd4c21bec2a8d69f3bd56f9cee9ec + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10/af143246cf6884fe26fa281621d45cfe111d34b30535a475bfa38dafe343dadb466c047a924ffc7d6b7b18265df4110224ce3803806dbb07173bf2087b648d7f + languageName: node + linkType: hard + +"fs.realpath@npm:^1.0.0": + version: 1.0.0 + resolution: "fs.realpath@npm:1.0.0" + checksum: 10/e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96 + languageName: node + linkType: hard + +"fsevents@npm:~2.3.2": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10/4c1ade961ded57cdbfbb5cac5106ec17bc8bccd62e16343c569a0ceeca83b9dfef87550b4dc5cbb89642da412b20c5071f304c8c464b80415446e8e155a038c0 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 10/185e20d20f10c8d661d59aac0f3b63b31132d492e1b11fcc2a93cb2c47257ebaee7407c38513efd2b35cafdf972d9beb2ea4593c1e0f3bf8f2744836928d7454 + languageName: node + linkType: hard + +"glob-parent@npm:^5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: "npm:^4.0.1" + checksum: 10/32cd106ce8c0d83731966d31517adb766d02c3812de49c30cfe0675c7c0ae6630c11214c54a5ae67aca882cf738d27fd7768f21aa19118b9245950554be07247 + languageName: node + linkType: hard + +"glob@npm:^10.2.2, glob@npm:^10.3.10": + version: 10.4.5 + resolution: "glob@npm:10.4.5" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10/698dfe11828b7efd0514cd11e573eaed26b2dff611f0400907281ce3eab0c1e56143ef9b35adc7c77ecc71fba74717b510c7c223d34ca8a98ec81777b293d4ac + languageName: node + linkType: hard + +"glob@npm:^7.1.3": + version: 7.2.3 + resolution: "glob@npm:7.2.3" + dependencies: + fs.realpath: "npm:^1.0.0" + inflight: "npm:^1.0.4" + inherits: "npm:2" + minimatch: "npm:^3.1.1" + once: "npm:^1.3.0" + path-is-absolute: "npm:^1.0.0" + checksum: 10/59452a9202c81d4508a43b8af7082ca5c76452b9fcc4a9ab17655822e6ce9b21d4f8fbadabe4fe3faef448294cec249af305e2cd824b7e9aaf689240e5e96a7b + languageName: node + linkType: hard + +"globby@npm:10.0.1": + version: 10.0.1 + resolution: "globby@npm:10.0.1" + dependencies: + "@types/glob": "npm:^7.1.1" + array-union: "npm:^2.1.0" + dir-glob: "npm:^3.0.1" + fast-glob: "npm:^3.0.3" + glob: "npm:^7.1.3" + ignore: "npm:^5.1.1" + merge2: "npm:^1.2.3" + slash: "npm:^3.0.0" + checksum: 10/ea724a820d7d4eafc5aa3882d667a7ef3505b3018652b2658185d58752f122b75d3370086e4d4a7b1bbcdf8c2e700e5709a48db189a930df37005e1b3c86c256 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 + languageName: node + linkType: hard + +"hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10/7898a9c1788b2862cf0f9c345a6bec77ba4a0c0983c7f19d610c382343d4f98fa260686b225dfb1f88393a66679d2ec58ee310c1d6868c081eda7918f32cc70a + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.1.1": + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 10/362d5ed66b12ceb9c0a328fb31200b590ab1b02f4a254a697dc796850cc4385603e75f53ec59f768b2dad3bfa1464bd229f7de278d2899a0e3beffc634b6683f + languageName: node + linkType: hard + +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10/d062acfa0cb82beeb558f1043c6ba770ea892b5fb7b28654dbc70ea2aeea55226dd34c02a294f6c1ca179a5aa483c4ea641846821b182edbd9cc5d89b54c6848 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^7.0.1": + version: 7.0.5 + resolution: "https-proxy-agent@npm:7.0.5" + dependencies: + agent-base: "npm:^7.0.2" + debug: "npm:4" + checksum: 10/6679d46159ab3f9a5509ee80c3a3fc83fba3a920a5e18d32176c3327852c3c00ad640c0c4210a8fd70ea3c4a6d3a1b375bf01942516e7df80e2646bdc77658ab + languageName: node + linkType: hard + +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f + languageName: node + linkType: hard + +"ignore@npm:^5.1.1": + version: 5.3.1 + resolution: "ignore@npm:5.3.1" + checksum: 10/0a884c2fbc8c316f0b9f92beaf84464253b73230a4d4d286697be45fca081199191ca33e1c2e82d9e5f851f5e9a48a78e25a35c951e7eb41e59f150db3530065 + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10/2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 + languageName: node + linkType: hard + +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 10/cd3f5cbc9ca2d624c6a1f53f12e6b341659aba0e2d3254ae2b4464aaea8b4294cdb09616abbc59458f980531f2429784ed6a420d48d245bcad0811980c9efae9 + languageName: node + linkType: hard + +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" + dependencies: + once: "npm:^1.3.0" + wrappy: "npm:1" + checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 + languageName: node + linkType: hard + +"inherits@npm:2": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 + languageName: node + linkType: hard + +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" + dependencies: + jsbn: "npm:1.1.0" + sprintf-js: "npm:^1.1.3" + checksum: 10/1ed81e06721af012306329b31f532b5e24e00cb537be18ddc905a84f19fe8f83a09a1699862bf3a1ec4b9dea93c55a3fa5faf8b5ea380431469df540f38b092c + languageName: node + linkType: hard + +"is-builtin-module@npm:^3.2.1": + version: 3.2.1 + resolution: "is-builtin-module@npm:3.2.1" + dependencies: + builtin-modules: "npm:^3.3.0" + checksum: 10/e8f0ffc19a98240bda9c7ada84d846486365af88d14616e737d280d378695c8c448a621dcafc8332dbf0fcd0a17b0763b845400709963fa9151ddffece90ae88 + languageName: node + linkType: hard + +"is-core-module@npm:^2.13.0": + version: 2.15.0 + resolution: "is-core-module@npm:2.15.0" + dependencies: + hasown: "npm:^2.0.2" + checksum: 10/70e962543e5d3a97c07cb29144a86792d545a21f28e67da5401d85878a0193d46fbab8d97bc3ca680e2778705dca66e7b6ca840c493497a27ca0e8c5f3ac3d1d + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10/df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 10/44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 + languageName: node + linkType: hard + +"is-glob@npm:^4.0.1": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: "npm:^2.1.1" + checksum: 10/3ed74f2b0cdf4f401f38edb0442ddfde3092d79d7d35c9919c86641efdbcbb32e45aa3c0f70ce5eecc946896cd5a0f26e4188b9f2b881876f7cb6c505b82da11 + languageName: node + linkType: hard + +"is-lambda@npm:^1.0.1": + version: 1.0.1 + resolution: "is-lambda@npm:1.0.1" + checksum: 10/93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 + languageName: node + linkType: hard + +"is-module@npm:^1.0.0": + version: 1.0.0 + resolution: "is-module@npm:1.0.0" + checksum: 10/8cd5390730c7976fb4e8546dd0b38865ee6f7bacfa08dfbb2cc07219606755f0b01709d9361e01f13009bbbd8099fa2927a8ed665118a6105d66e40f1b838c3f + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10/6a6c3383f68afa1e05b286af866017c78f1226d43ac8cb064e115ff9ed85eb33f5c4f7216c96a71e4dfea289ef52c5da3aef5bbfade8ffe47a0465d70c0c8e86 + languageName: node + linkType: hard + +"is-plain-object@npm:^3.0.0": + version: 3.0.1 + resolution: "is-plain-object@npm:3.0.1" + checksum: 10/d13fe75db350d4ac669595cdfe0242ae87fcecddf2bca858d2dd443a6ed6eb1f69951fac8c2fa85b16106c6b0d7738fea86c2aca2ecee7fd61de15c1574f2cc5 + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10/7c9f715c03aff08f35e98b1fadae1b9267b38f0615d501824f9743f3aab99ef10e303ce7db3f186763a0b70a19de5791ebfc854ff884d5a8c4d92211f642ec92 + languageName: node + linkType: hard + +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 10/7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e + languageName: node + linkType: hard + +"jackspeak@npm:^3.1.2": + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10/96f8786eaab98e4bf5b2a5d6d9588ea46c4d06bbc4f2eb861fdd7b6b182b16f71d8a70e79820f335d52653b16d4843b29dd9cdcf38ae80406756db9199497cf3 + languageName: node + linkType: hard + +"jsbn@npm:1.1.0": + version: 1.1.0 + resolution: "jsbn@npm:1.1.0" + checksum: 10/bebe7ae829bbd586ce8cbe83501dd8cb8c282c8902a8aeeed0a073a89dc37e8103b1244f3c6acd60278bcbfe12d93a3f83c9ac396868a3b3bbc3c5e5e3b648ef + languageName: node + linkType: hard + +"jsonfile@npm:^4.0.0": + version: 4.0.0 + resolution: "jsonfile@npm:4.0.0" + dependencies: + graceful-fs: "npm:^4.1.6" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10/17796f0ab1be8479827d3683433f97ebe0a1c6932c3360fa40348eac36904d69269aab26f8b16da311882d94b42e9208e8b28e490bf926364f3ac9bff134c226 + languageName: node + linkType: hard + +"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": + version: 10.4.3 + resolution: "lru-cache@npm:10.4.3" + checksum: 10/e6e90267360476720fa8e83cc168aa2bf0311f3f2eea20a6ba78b90a885ae72071d9db132f40fda4129c803e7dcec3a6b6a6fbb44ca90b081630b810b5d6a41a + languageName: node + linkType: hard + +"make-fetch-happen@npm:^13.0.0": + version: 13.0.1 + resolution: "make-fetch-happen@npm:13.0.1" + dependencies: + "@npmcli/agent": "npm:^2.0.0" + cacache: "npm:^18.0.0" + http-cache-semantics: "npm:^4.1.1" + is-lambda: "npm:^1.0.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^3.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^0.6.3" + proc-log: "npm:^4.2.0" + promise-retry: "npm:^2.0.1" + ssri: "npm:^10.0.0" + checksum: 10/11bae5ad6ac59b654dbd854f30782f9de052186c429dfce308eda42374528185a100ee40ac9ffdc36a2b6c821ecaba43913e4730a12f06f15e895ea9cb23fa59 + languageName: node + linkType: hard + +"merge2@npm:^1.2.3, merge2@npm:^1.3.0": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 10/7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.4": + version: 4.0.7 + resolution: "micromatch@npm:4.0.7" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10/a11ed1cb67dcbbe9a5fc02c4062cf8bb0157d73bf86956003af8dcfdf9b287f9e15ec0f6d6925ff6b8b5b496202335e497b01de4d95ef6cf06411bc5e5c474a0 + languageName: node + linkType: hard + +"minimatch@npm:^3.1.1": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10/e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 + languageName: node + linkType: hard + +"minimatch@npm:^9.0.4": + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348 + languageName: node + linkType: hard + +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10/b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 + languageName: node + linkType: hard + +"minipass-fetch@npm:^3.0.0": + version: 3.0.5 + resolution: "minipass-fetch@npm:3.0.5" + dependencies: + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^2.1.2" + dependenciesMeta: + encoding: + optional: true + checksum: 10/c669948bec1373313aaa8f104b962a3ced9f45c49b26366a4b0ae27ccdfa9c5740d72c8a84d3f8623d7a61c5fc7afdfda44789008c078f61a62441142efc4a97 + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10/56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10/b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b + languageName: node + linkType: hard + +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10/40982d8d836a52b0f37049a0a7e5d0f089637298e6d9b45df9c115d4f0520682a78258905e5c8b180fb41b593b0a82cc1361d2c74b45f7ada66334f84d1ecfdd + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: "npm:^4.0.0" + checksum: 10/a5c6ef069f70d9a524d3428af39f2b117ff8cd84172e19b754e7264a33df460873e6eb3d6e55758531580970de50ae950c496256bb4ad3691a2974cddff189f0 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 10/61682162d29f45d3152b78b08bab7fb32ca10899bc5991ffe98afc18c9e9543bd1e3be94f8b8373ba6262497db63607079dc242ea62e43e7b2270837b7347c93 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 + languageName: node + linkType: hard + +"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: "npm:^3.0.0" + yallist: "npm:^4.0.0" + checksum: 10/ae0f45436fb51344dcb87938446a32fbebb540d0e191d63b35e1c773d47512e17307bf54aa88326cc6d176594d00e4423563a091f7266c2f9a6872cdc1e234d1 + languageName: node + linkType: hard + +"mkdirp@npm:^1.0.3": + version: 1.0.4 + resolution: "mkdirp@npm:1.0.4" + bin: + mkdirp: bin/cmd.js + checksum: 10/d71b8dcd4b5af2fe13ecf3bd24070263489404fe216488c5ba7e38ece1f54daf219e72a833a3a2dc404331e870e9f44963a33399589490956bff003a3404d3b2 + languageName: node + linkType: hard + +"ms@npm:2.1.2": + version: 2.1.2 + resolution: "ms@npm:2.1.2" + checksum: 10/673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f + languageName: node + linkType: hard + +"negotiator@npm:^0.6.3": + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: 10/2723fb822a17ad55c93a588a4bc44d53b22855bf4be5499916ca0cab1e7165409d0b288ba2577d7b029f10ce18cf2ed8e703e5af31c984e1e2304277ef979837 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 10.2.0 + resolution: "node-gyp@npm:10.2.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^13.0.0" + nopt: "npm:^7.0.0" + proc-log: "npm:^4.1.0" + semver: "npm:^7.3.5" + tar: "npm:^6.2.1" + which: "npm:^4.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10/41773093b1275751dec942b985982fd4e7a69b88cae719b868babcef3880ee6168aaec8dcaa8cd0b9fa7c84873e36cc549c6cac6a124ee65ba4ce1f1cc108cfe + languageName: node + linkType: hard + +"nopt@npm:^7.0.0": + version: 7.2.1 + resolution: "nopt@npm:7.2.1" + dependencies: + abbrev: "npm:^2.0.0" + bin: + nopt: bin/nopt.js + checksum: 10/95a1f6dec8a81cd18cdc2fed93e6f0b4e02cf6bdb4501c848752c6e34f9883d9942f036a5e3b21a699047d8a448562d891e67492df68ec9c373e6198133337ae + languageName: node + linkType: hard + +"once@npm:^1.3.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: "npm:1" + checksum: 10/cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 + languageName: node + linkType: hard + +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: "npm:^3.0.0" + checksum: 10/7ba4a2b1e24c05e1fc14bbaea0fc6d85cf005ae7e9c9425d4575550f37e2e584b1af97bcde78eacd7559208f20995988d52881334db16cf77bc1bcf68e48ed7c + languageName: node + linkType: hard + +"package-json-from-dist@npm:^1.0.0": + version: 1.0.0 + resolution: "package-json-from-dist@npm:1.0.0" + checksum: 10/ac706ec856a5a03f5261e4e48fa974f24feb044d51f84f8332e2af0af04fbdbdd5bbbfb9cbbe354190409bc8307c83a9e38c6672c3c8855f709afb0006a009ea + languageName: node + linkType: hard + +"path-is-absolute@npm:^1.0.0": + version: 1.0.1 + resolution: "path-is-absolute@npm:1.0.1" + checksum: 10/060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + languageName: node + linkType: hard + +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 10/55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 + languageName: node + linkType: hard + +"path-parse@npm:^1.0.7": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 10/49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a + languageName: node + linkType: hard + +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" + dependencies: + lru-cache: "npm:^10.2.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10/5e8845c159261adda6f09814d7725683257fcc85a18f329880ab4d7cc1d12830967eae5d5894e453f341710d5484b8fdbbd4d75181b4d6e1eb2f4dc7aeadc434 + languageName: node + linkType: hard + +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 10/5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 + languageName: node + linkType: hard + +"picomatch@npm:^2.2.2, picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc + languageName: node + linkType: hard + +"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": + version: 4.2.0 + resolution: "proc-log@npm:4.2.0" + checksum: 10/4e1394491b717f6c1ade15c570ecd4c2b681698474d3ae2d303c1e4b6ab9455bd5a81566211e82890d5a5ae9859718cc6954d5150bb18b09b72ecb297beae90a + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: "npm:^2.0.2" + retry: "npm:^0.12.0" + checksum: 10/96e1a82453c6c96eef53a37a1d6134c9f2482f94068f98a59145d0986ca4e497bf110a410adf73857e588165eab3899f0ebcf7b3890c1b3ce802abc0d65967d4 + languageName: node + linkType: hard + +"queue-microtask@npm:^1.2.2": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: 10/72900df0616e473e824202113c3df6abae59150dfb73ed13273503127235320e9c8ca4aaaaccfd58cf417c6ca92a6e68ee9a5c3182886ae949a768639b388a7b + languageName: node + linkType: hard + +"resolve@npm:^1.22.1": + version: 1.22.8 + resolution: "resolve@npm:1.22.8" + dependencies: + is-core-module: "npm:^2.13.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/c473506ee01eb45cbcfefb68652ae5759e092e6b0fb64547feadf9736a6394f258fbc6f88e00c5ca36d5477fbb65388b272432a3600fa223062e54333c156753 + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^1.22.1#optional!builtin": + version: 1.22.8 + resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" + dependencies: + is-core-module: "npm:^2.13.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/f345cd37f56a2c0275e3fe062517c650bb673815d885e7507566df589375d165bbbf4bdb6aa95600a9bc55f4744b81f452b5a63f95b9f10a72787dba3c90890a + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 + languageName: node + linkType: hard + +"reusify@npm:^1.0.4": + version: 1.0.4 + resolution: "reusify@npm:1.0.4" + checksum: 10/14222c9e1d3f9ae01480c50d96057228a8524706db79cdeb5a2ce5bb7070dd9f409a6f84a02cbef8cdc80d39aef86f2dd03d155188a1300c599b05437dcd2ffb + languageName: node + linkType: hard + +"rollup-plugin-base64@npm:^1.0.1": + version: 1.0.1 + resolution: "rollup-plugin-base64@npm:1.0.1" + dependencies: + "@rollup/pluginutils": "npm:^3.1.0" + checksum: 10/1f4ebf46a9ec5220ba9b596820e56d6a7a1b77d567097b8713a63ef669b02b1d296d6e77f48c01e43de7c98c751b5ee5683b4b1f7e4cb4b76a4fe55109654862 + languageName: node + linkType: hard + +"rollup-plugin-copy@npm:^3.5.0": + version: 3.5.0 + resolution: "rollup-plugin-copy@npm:3.5.0" + dependencies: + "@types/fs-extra": "npm:^8.0.1" + colorette: "npm:^1.1.0" + fs-extra: "npm:^8.1.0" + globby: "npm:10.0.1" + is-plain-object: "npm:^3.0.0" + checksum: 10/706ba6bd2052b95d1037f12963ff4b50749730f18aefad10544f9574aff7c035c88c5dd9ae1f0c0408cf09862e595a0ea4d68e13c2717addaea2bda3ade0d0e0 + languageName: node + linkType: hard + +"rollup@npm:^4.19.0": + version: 4.19.0 + resolution: "rollup@npm:4.19.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.19.0" + "@rollup/rollup-android-arm64": "npm:4.19.0" + "@rollup/rollup-darwin-arm64": "npm:4.19.0" + "@rollup/rollup-darwin-x64": "npm:4.19.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.19.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.19.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.19.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.19.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.19.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.19.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.19.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.19.0" + "@rollup/rollup-linux-x64-musl": "npm:4.19.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.19.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.19.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.19.0" + "@types/estree": "npm:1.0.5" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10/a5f56e60d160e727f372fb0b0adbab03c1e5b858df7af62e626459687e6510d5b9685e4badef50bb6ffd916eaf53c1684a8e12ae959dacb8e6930c77a00a0f19 + languageName: node + linkType: hard + +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" + dependencies: + queue-microtask: "npm:^1.2.2" + checksum: 10/cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: 10/7eaf7a0cf37cc27b42fb3ef6a9b1df6e93a1c6d98c6c6702b02fe262d5fcbd89db63320793b99b21cb5348097d0a53de81bd5f4e8b86e20cc9412e3f1cfb4e83 + languageName: node + linkType: hard + +"semver@npm:^7.3.5": + version: 7.6.3 + resolution: "semver@npm:7.6.3" + bin: + semver: bin/semver.js + checksum: 10/36b1fbe1a2b6f873559cd57b238f1094a053dbfd997ceeb8757d79d1d2089c56d1321b9f1069ce263dc64cfa922fa1d2ad566b39426fe1ac6c723c1487589e10 + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 10/6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10/1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 + languageName: node + linkType: hard + +"signal-exit@npm:^4.0.1": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 10/c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f + languageName: node + linkType: hard + +"slash@npm:^3.0.0": + version: 3.0.0 + resolution: "slash@npm:3.0.0" + checksum: 10/94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: 10/927484aa0b1640fd9473cee3e0a0bcad6fce93fd7bbc18bac9ad0c33686f5d2e2c422fba24b5899c184524af01e11dd2bd051c2bf2b07e47aff8ca72cbfc60d2 + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.4 + resolution: "socks-proxy-agent@npm:8.0.4" + dependencies: + agent-base: "npm:^7.1.1" + debug: "npm:^4.3.4" + socks: "npm:^2.8.3" + checksum: 10/c8e7c2b398338b49a0a0f4d2bae5c0602aeeca6b478b99415927b6c5db349ca258448f2c87c6958ebf83eea17d42cbc5d1af0bfecb276cac10b9658b0f07f7d7 + languageName: node + linkType: hard + +"socks@npm:^2.8.3": + version: 2.8.3 + resolution: "socks@npm:2.8.3" + dependencies: + ip-address: "npm:^9.0.5" + smart-buffer: "npm:^4.2.0" + checksum: 10/ffcb622c22481dfcd7589aae71fbfd71ca34334064d181df64bf8b7feaeee19706aba4cffd1de35cc7bbaeeaa0af96be2d7f40fcbc7bc0ab69533a7ae9ffc4fb + languageName: node + linkType: hard + +"sprintf-js@npm:^1.1.3": + version: 1.1.3 + resolution: "sprintf-js@npm:1.1.3" + checksum: 10/e7587128c423f7e43cc625fe2f87e6affdf5ca51c1cc468e910d8aaca46bb44a7fbcfa552f787b1d3987f7043aeb4527d1b99559e6621e01b42b3f45e5a24cbb + languageName: node + linkType: hard + +"ssri@npm:^10.0.0": + version: 10.0.6 + resolution: "ssri@npm:10.0.6" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10/f92c1b3cc9bfd0a925417412d07d999935917bc87049f43ebec41074661d64cf720315661844106a77da9f8204b6d55ae29f9514e673083cae39464343af2a8b + languageName: node + linkType: hard + +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: "npm:^8.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + strip-ansi: "npm:^6.0.1" + checksum: 10/e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb + languageName: node + linkType: hard + +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 10/7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 + 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" + dependencies: + ansi-regex: "npm:^5.0.1" + checksum: 10/ae3b5436d34fadeb6096367626ce987057713c566e1e7768818797e00ac5d62023d0f198c4e681eae9e20701721980b26a64a8f5b91238869592a9c6800719a2 + languageName: node + linkType: hard + +"strip-ansi@npm:^7.0.1": + version: 7.1.0 + resolution: "strip-ansi@npm:7.1.0" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 10/475f53e9c44375d6e72807284024ac5d668ee1d06010740dec0b9744f2ddf47de8d7151f80e5f6190fc8f384e802fdf9504b76a7e9020c9faee7103623338be2 + languageName: node + linkType: hard + +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 10/a9dc19ae2220c952bd2231d08ddeecb1b0328b61e72071ff4000c8384e145cc07c1c0bdb3b5a1cb06e186a7b2790f1dee793418b332f6ddf320de25d9125be7e + languageName: node + linkType: hard + +"tar@npm:^6.1.11, tar@npm:^6.2.1": + version: 6.2.1 + resolution: "tar@npm:6.2.1" + dependencies: + chownr: "npm:^2.0.0" + fs-minipass: "npm:^2.0.0" + minipass: "npm:^5.0.0" + minizlib: "npm:^2.1.1" + mkdirp: "npm:^1.0.3" + yallist: "npm:^4.0.0" + checksum: 10/bfbfbb2861888077fc1130b84029cdc2721efb93d1d1fb80f22a7ac3a98ec6f8972f29e564103bbebf5e97be67ebc356d37fa48dbc4960600a1eb7230fbd1ea0 + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a + languageName: node + linkType: hard + +"undici-types@npm:~5.26.4": + version: 5.26.5 + resolution: "undici-types@npm:5.26.5" + checksum: 10/0097779d94bc0fd26f0418b3a05472410408877279141ded2bd449167be1aed7ea5b76f756562cb3586a07f251b90799bab22d9019ceba49c037c76445f7cddd + languageName: node + linkType: hard + +"unique-filename@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-filename@npm:3.0.0" + dependencies: + unique-slug: "npm:^4.0.0" + checksum: 10/8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df + languageName: node + linkType: hard + +"unique-slug@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 10/40912a8963fc02fb8b600cf50197df4a275c602c60de4cac4f75879d3c48558cfac48de08a25cc10df8112161f7180b3bbb4d662aadb711568602f9eddee54f0 + languageName: node + linkType: hard + +"universalify@npm:^0.1.0": + version: 0.1.2 + resolution: "universalify@npm:0.1.2" + checksum: 10/40cdc60f6e61070fe658ca36016a8f4ec216b29bf04a55dce14e3710cc84c7448538ef4dad3728d0bfe29975ccd7bfb5f414c45e7b78883567fb31b246f02dff + languageName: node + linkType: hard + +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: "npm:^2.0.0" + bin: + node-which: ./bin/node-which + checksum: 10/4782f8a1d6b8fc12c65e968fea49f59752bf6302dc43036c3bf87da718a80710f61a062516e9764c70008b487929a73546125570acea95c5b5dcc8ac3052c70f + languageName: node + linkType: hard + +"which@npm:^4.0.0": + version: 4.0.0 + resolution: "which@npm:4.0.0" + dependencies: + isexe: "npm:^3.1.1" + bin: + node-which: bin/which.js + checksum: 10/f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651 + languageName: node + linkType: hard + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" + dependencies: + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: 10/cebdaeca3a6880da410f75209e68cd05428580de5ad24535f22696d7d9cab134d1f8498599f344c3cf0fb37c1715807a183778d8c648d6cc0cb5ff2bb4236540 + languageName: node + linkType: hard + +"wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 10/7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf + languageName: node + linkType: hard + +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 10/159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 10/4cb02b42b8a93b5cf50caf5d8e9beb409400a8a4d85e83bb0685c1457e9ac0b7a00819e9f5991ac25ffabb56a78e2f017c1acc010b3a1babfe6de690ba531abd + languageName: node + linkType: hard From d7e509c67bf41357e46790c3bad6d10cc50c765a Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 15 Aug 2024 11:35:44 -0400 Subject: [PATCH 02/97] Statement Stream for AsyncConnection::Load (#961) * statement stream * fix lifetimes on load query * execute returning count * transaction manager * cleanup --- diesel-wasm-sqlite/.vscode/settings.json | 3 +- diesel-wasm-sqlite/Cargo.lock | 2 +- diesel-wasm-sqlite/src/backend.rs | 2 +- .../src/connection/bind_collector.rs | 4 +- diesel-wasm-sqlite/src/connection/mod.rs | 138 ++++++------ diesel-wasm-sqlite/src/connection/raw.rs | 5 +- diesel-wasm-sqlite/src/connection/row.rs | 30 +-- .../src/connection/sqlite_value.rs | 69 +++--- .../src/connection/statement_iterator.rs | 172 --------------- .../src/connection/statement_stream.rs | 199 ++++++++++++++++++ diesel-wasm-sqlite/src/connection/stmt.rs | 88 +++----- diesel-wasm-sqlite/src/query_builder/mod.rs | 2 +- 12 files changed, 355 insertions(+), 359 deletions(-) mode change 100644 => 100755 diesel-wasm-sqlite/src/connection/raw.rs delete mode 100644 diesel-wasm-sqlite/src/connection/statement_iterator.rs create mode 100644 diesel-wasm-sqlite/src/connection/statement_stream.rs diff --git a/diesel-wasm-sqlite/.vscode/settings.json b/diesel-wasm-sqlite/.vscode/settings.json index cb6099b62..ae0d8b87d 100644 --- a/diesel-wasm-sqlite/.vscode/settings.json +++ b/diesel-wasm-sqlite/.vscode/settings.json @@ -13,7 +13,8 @@ "napi-derive": ["napi"], "async-recursion": ["async_recursion"], "ctor": ["ctor"], - "tokio": ["test"] + "tokio": ["test"], + "diesel": ["table"], } } }, diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index aadc60362..f179de053 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -142,7 +142,7 @@ dependencies = [ [[package]] name = "diesel-async" version = "0.5.0" -source = "git+https://github.com/insipx/diesel_async?branch=insipx/make-stmt-cache-public#86a24a38d9d841ef9e92022cd983bbd700286397" +source = "git+https://github.com/insipx/diesel_async?branch=insipx/make-stmt-cache-public#f1c4838ae6d7951b78572c249ba65f7a107488a0" dependencies = [ "async-trait", "diesel", diff --git a/diesel-wasm-sqlite/src/backend.rs b/diesel-wasm-sqlite/src/backend.rs index 4891c37e0..05ecf0950 100644 --- a/diesel-wasm-sqlite/src/backend.rs +++ b/diesel-wasm-sqlite/src/backend.rs @@ -39,7 +39,7 @@ pub enum SqliteType { impl Backend for WasmSqlite { type QueryBuilder = SqliteQueryBuilder; - type RawValue<'a> = SqliteValue<'a, 'a, 'a>; + type RawValue<'a> = SqliteValue<'a, 'a>; type BindCollector<'a> = SqliteBindCollector<'a>; } diff --git a/diesel-wasm-sqlite/src/connection/bind_collector.rs b/diesel-wasm-sqlite/src/connection/bind_collector.rs index 6eef85140..dc51e115a 100644 --- a/diesel-wasm-sqlite/src/connection/bind_collector.rs +++ b/diesel-wasm-sqlite/src/connection/bind_collector.rs @@ -185,7 +185,7 @@ impl<'a> BindCollector<'a, WasmSqlite> for SqliteBindCollector<'a> { #[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] -enum OwnedSqliteBindValue { +pub enum OwnedSqliteBindValue { String(Box), Binary(Box<[u8]>), I32(i32), @@ -229,7 +229,7 @@ impl<'a> std::convert::From<&OwnedSqliteBindValue> for InternalSqliteBindValue<' #[derive(Debug)] /// Sqlite bind collector data that is movable across threads pub struct SqliteBindCollectorData { - binds: Vec<(OwnedSqliteBindValue, SqliteType)>, + pub binds: Vec<(OwnedSqliteBindValue, SqliteType)>, } impl MoveableBindCollector for SqliteBindCollector<'_> { diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index fac2bbe8b..2694eadfe 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -5,7 +5,7 @@ mod raw; mod row; // mod serialized_database; mod sqlite_value; -// mod statement_iterator; +mod statement_stream; mod stmt; pub(crate) use self::bind_collector::SqliteBindCollector; @@ -17,15 +17,19 @@ use self::raw::RawConnection; // use self::statement_iterator::*; use self::stmt::{Statement, StatementUse}; use crate::query_builder::*; -use diesel::{connection::{statement_cache::StatementCacheKey, DefaultLoadingMode, LoadConnection}, deserialize::{FromSqlRow, StaticallySizedRow}, expression::QueryMetadata, query_builder::QueryBuilder as _, result::*, serialize::ToSql, sql_types::HasSqlType}; -use futures::{FutureExt, TryFutureExt}; +use diesel::query_builder::MoveableBindCollector; +use diesel::{connection::{statement_cache::StatementCacheKey}, query_builder::QueryBuilder as _, result::*}; +use futures::future::LocalBoxFuture; +use futures::stream::LocalBoxStream; +use futures::FutureExt; +use owned_row::OwnedSqliteRow; +use statement_stream::StatementStream; +use std::future::Future; use std::sync::{Arc, Mutex}; -use diesel::{connection::{ConnectionSealed, Instrumentation, WithMetadataLookup}, query_builder::{AsQuery, QueryFragment, QueryId}, sql_types::TypeMetadata, QueryResult}; +use diesel::{connection::{ConnectionSealed, Instrumentation}, query_builder::{AsQuery, QueryFragment, QueryId}, QueryResult}; pub use diesel_async::{AnsiTransactionManager, AsyncConnection, SimpleAsyncConnection, TransactionManager, stmt_cache::StmtCache}; -use futures::{future::BoxFuture, stream::BoxStream}; -use row::SqliteRow; use crate::{get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; @@ -35,10 +39,9 @@ pub struct WasmSqliteConnection { // connection itself statement_cache: StmtCache, pub raw_connection: RawConnection, - transaction_state: AnsiTransactionManager, + transaction_manager: AnsiTransactionManager, // this exists for the sole purpose of implementing `WithMetadataLookup` trait // and avoiding static mut which will be deprecated in 2024 edition - metadata_lookup: (), instrumentation: Arc>>>, } @@ -69,37 +72,44 @@ impl SimpleAsyncConnection for WasmSqliteConnection { impl AsyncConnection for WasmSqliteConnection { type Backend = WasmSqlite; type TransactionManager = AnsiTransactionManager; - type ExecuteFuture<'conn, 'query> = BoxFuture<'query, QueryResult>; - type LoadFuture<'conn, 'query> = BoxFuture<'query, QueryResult>>; - type Stream<'conn, 'query> = BoxStream<'static, QueryResult>>; - type Row<'conn, 'query> = SqliteRow<'conn, 'query>; + type ExecuteFuture<'conn, 'query> = LocalBoxFuture<'conn, QueryResult>; + type LoadFuture<'conn, 'query> = LocalBoxFuture<'conn, QueryResult>>; + type Stream<'conn, 'query> = LocalBoxStream<'conn, QueryResult>>; + type Row<'conn, 'query> = OwnedSqliteRow; async fn establish(database_url: &str) -> diesel::prelude::ConnectionResult { WasmSqliteConnection::establish_inner(database_url).await } - fn load<'conn, 'query, T>(&'conn mut self, _source: T) -> Self::LoadFuture<'conn, 'query> + fn load<'conn, 'query, T>(&'conn mut self, source: T) -> Self::LoadFuture<'conn, 'query> where - T: AsQuery + 'query, - T::Query: QueryFragment + QueryId + 'query, + T: AsQuery, + T::Query: QueryFragment + QueryId, { - todo!() + let query = source.as_query(); + self.with_prepared_statement(query, |_, statement| async move { + Ok(StatementStream::new(statement).stream()) + }) } fn execute_returning_count<'conn, 'query, T>( &'conn mut self, - _source: T, + query: T, ) -> Self::ExecuteFuture<'conn, 'query> where T: QueryFragment + QueryId + 'query, { - todo!() + self.with_prepared_statement(query, |conn, statement| async move { + statement.run().await.map(|_| { + conn.rows_affected_by_last_query() + }) + }) } fn transaction_state( &mut self, ) -> &mut >::TransactionStateData{ - todo!() + &mut self.transaction_manager } fn instrumentation(&mut self) -> &mut dyn Instrumentation { @@ -111,32 +121,7 @@ impl AsyncConnection for WasmSqliteConnection { } } -/* -impl LoadConnection for WasmSqliteConnection { - type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>; - type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>; - - fn load<'conn, 'query, T>( - &'conn mut self, - source: T, - ) -> QueryResult> - where - T: Query + QueryFragment + QueryId + 'query, - Self::Backend: QueryMetadata, - { - let statement = self.prepared_query(source)?; - Ok(StatementIterator::new(statement)) - } -} -*/ -/* -impl WithMetadataLookup for WasmSqliteConnection { - fn metadata_lookup(&mut self) -> &mut ::MetadataLookup { - &mut self.metadata_lookup - } -} - */ #[cfg(feature = "r2d2")] impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection { @@ -243,39 +228,53 @@ impl WasmSqliteConnection { } } - async fn prepared_query<'conn, 'query, T>( + fn with_prepared_statement<'conn, Q, F, R>( &'conn mut self, - source: T, - ) -> QueryResult> + query: Q, + callback: impl (FnOnce(&'conn mut RawConnection, StatementUse<'conn>) -> F) + 'conn + ) -> LocalBoxFuture<'_, QueryResult> where - T: QueryFragment + QueryId + 'query, + Q: QueryFragment + QueryId, + F: Future>, { - let raw_connection = &self.raw_connection; - let cache = &mut self.statement_cache; - let maybe_type_id = T::query_id(); - let cache_key = StatementCacheKey::for_source(maybe_type_id, &source, &[], &WasmSqlite)?; - - - let is_safe_to_cache_prepared = source.is_safe_to_cache_prepared(&WasmSqlite)?; - let mut qb = SqliteQueryBuilder::new(); - let sql = source.to_sql(&mut qb, &WasmSqlite).map(|()| qb.finish())?; + let WasmSqliteConnection { + ref mut raw_connection, + ref mut statement_cache, + ref mut instrumentation, + .. + } = self; - let statement = cache.cached_prepared_statement( - cache_key, - sql, - is_safe_to_cache_prepared, - &[], - raw_connection.clone(), - &self.instrumentation, - ).await?.0; // Cloned RawConnection is dropped here + let maybe_type_id = Q::query_id(); + let instrumentation = instrumentation.clone(); - - Ok(StatementUse::bind(statement, source, self.instrumentation.as_ref())?) + let cache_key = StatementCacheKey::for_source(maybe_type_id, &query, &[], &WasmSqlite); + let is_safe_to_cache_prepared = query.is_safe_to_cache_prepared(&WasmSqlite); + + // C put this in box to avoid virtual fn call for SQLite C + // not sure if that still applies here + let query = Box::new(query); + let mut bind_collector = SqliteBindCollector::new(); + let bind_collector = query.collect_binds(&mut bind_collector, &mut (), &WasmSqlite).map(|()| bind_collector.moveable()); + + let mut qb = SqliteQueryBuilder::new(); + let sql = query.to_sql(&mut qb, &WasmSqlite).map(|()| qb.finish()); + async move { + let (statement, conn) = statement_cache.cached_prepared_statement( + cache_key?, + sql?, + is_safe_to_cache_prepared?, + &[], + raw_connection, + &instrumentation, + ).await?; // Cloned RawConnection is dropped here + let statement = StatementUse::bind(statement, bind_collector?, instrumentation)?; + callback(conn, statement).await + }.boxed_local() } async fn establish_inner(database_url: &str) -> Result { - use diesel::result::ConnectionError::CouldntSetupConfiguration; + // use diesel::result::ConnectionError::CouldntSetupConfiguration; let raw_connection = RawConnection::establish(database_url).await.unwrap(); let sqlite3 = crate::get_sqlite().await; @@ -284,8 +283,7 @@ impl WasmSqliteConnection { Ok(Self { statement_cache: StmtCache::new(), raw_connection, - transaction_state: AnsiTransactionManager::default(), - metadata_lookup: (), + transaction_manager: AnsiTransactionManager::default(), instrumentation: Arc::new(Mutex::new(None)), }) } diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs old mode 100644 new mode 100755 index dd11abf25..65d3cb4bc --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -1,3 +1,6 @@ +#![allow(dead_code)] +// functions are needed, but missing functionality means they aren't used yet. + use crate::{ sqlite_types::{SqliteFlags, SqliteOpenFlags}, SqliteType, WasmSqlite, WasmSqliteError, @@ -159,7 +162,7 @@ impl RawConnection { } #[async_trait::async_trait(?Send)] -impl diesel_async::stmt_cache::PrepareCallback for RawConnection { +impl diesel_async::stmt_cache::PrepareCallback for &'_ mut RawConnection { async fn prepare( self, sql: &str, diff --git a/diesel-wasm-sqlite/src/connection/row.rs b/diesel-wasm-sqlite/src/connection/row.rs index 41c2c132d..d63a29783 100644 --- a/diesel-wasm-sqlite/src/connection/row.rs +++ b/diesel-wasm-sqlite/src/connection/row.rs @@ -12,20 +12,20 @@ use diesel::{ }; #[allow(missing_debug_implementations)] -pub struct SqliteRow<'stmt, 'query> { - pub(super) inner: Rc>>, +pub struct SqliteRow<'stmt> { + pub(super) inner: Rc>>, pub(super) field_count: usize, } -pub(super) enum PrivateSqliteRow<'stmt, 'query> { - Direct(StatementUse<'stmt, 'query>), +pub(super) enum PrivateSqliteRow<'stmt> { + Direct(StatementUse<'stmt>), Duplicated { values: Vec>, column_names: Rc<[Option]>, }, } -impl<'stmt> IntoOwnedRow<'stmt, WasmSqlite> for SqliteRow<'stmt, '_> { +impl<'stmt> IntoOwnedRow<'stmt, WasmSqlite> for SqliteRow<'stmt> { type OwnedRow = OwnedSqliteRow; type Cache = Option]>>; @@ -35,11 +35,11 @@ impl<'stmt> IntoOwnedRow<'stmt, WasmSqlite> for SqliteRow<'stmt, '_> { } } -impl<'stmt, 'query> PrivateSqliteRow<'stmt, 'query> { +impl<'stmt> PrivateSqliteRow<'stmt> { pub(super) fn duplicate( &mut self, column_names: &mut Option]>>, - ) -> PrivateSqliteRow<'stmt, 'query> { + ) -> PrivateSqliteRow<'stmt> { match self { PrivateSqliteRow::Direct(stmt) => { let column_names = if let Some(column_names) = column_names { @@ -129,10 +129,10 @@ impl<'stmt, 'query> PrivateSqliteRow<'stmt, 'query> { } } -impl<'stmt, 'query> RowSealed for SqliteRow<'stmt, 'query> {} +impl<'stmt> RowSealed for SqliteRow<'stmt> {} -impl<'stmt, 'query> Row<'stmt, WasmSqlite> for SqliteRow<'stmt, 'query> { - type Field<'field> = SqliteField<'field, 'field> where 'stmt: 'field, Self: 'field; +impl<'stmt> Row<'stmt, WasmSqlite> for SqliteRow<'stmt> { + type Field<'field> = SqliteField<'field> where 'stmt: 'field, Self: 'field; type InnerPartialRow = Self; fn field_count(&self) -> usize { @@ -156,7 +156,7 @@ impl<'stmt, 'query> Row<'stmt, WasmSqlite> for SqliteRow<'stmt, 'query> { } } -impl<'stmt, 'query> RowIndex for SqliteRow<'stmt, 'query> { +impl<'stmt> RowIndex for SqliteRow<'stmt> { fn idx(&self, idx: usize) -> Option { if idx < self.field_count { Some(idx) @@ -166,7 +166,7 @@ impl<'stmt, 'query> RowIndex for SqliteRow<'stmt, 'query> { } } -impl<'stmt, 'idx, 'query> RowIndex<&'idx str> for SqliteRow<'stmt, 'query> { +impl<'stmt, 'idx> RowIndex<&'idx str> for SqliteRow<'stmt> { fn idx(&self, field_name: &'idx str) -> Option { match &mut *self.inner.borrow_mut() { PrivateSqliteRow::Direct(stmt) => stmt.index_for_column_name(field_name), @@ -178,12 +178,12 @@ impl<'stmt, 'idx, 'query> RowIndex<&'idx str> for SqliteRow<'stmt, 'query> { } #[allow(missing_debug_implementations)] -pub struct SqliteField<'stmt, 'query> { - pub(super) row: Ref<'stmt, PrivateSqliteRow<'stmt, 'query>>, +pub struct SqliteField<'stmt> { + pub(super) row: Ref<'stmt, PrivateSqliteRow<'stmt>>, pub(super) col_idx: i32, } -impl<'stmt, 'query> Field<'stmt, WasmSqlite> for SqliteField<'stmt, 'query> { +impl<'stmt> Field<'stmt, WasmSqlite> for SqliteField<'stmt> { fn field_name(&self) -> Option<&str> { match &*self.row { PrivateSqliteRow::Direct(stmt) => stmt.field_name(self.col_idx), diff --git a/diesel-wasm-sqlite/src/connection/sqlite_value.rs b/diesel-wasm-sqlite/src/connection/sqlite_value.rs index e94e77217..7510a892b 100644 --- a/diesel-wasm-sqlite/src/connection/sqlite_value.rs +++ b/diesel-wasm-sqlite/src/connection/sqlite_value.rs @@ -2,7 +2,7 @@ use std::cell::Ref; -use crate::ffi::{self, SQLiteCompatibleType}; +use crate::ffi::SQLiteCompatibleType; use crate::{backend::SqliteType, sqlite_types}; use wasm_bindgen::JsValue; @@ -14,11 +14,11 @@ use super::row::PrivateSqliteRow; /// Use existing `FromSql` implementations to convert this into /// rust values #[allow(missing_debug_implementations, missing_copy_implementations)] -pub struct SqliteValue<'row, 'stmt, 'query> { +pub struct SqliteValue<'row, 'stmt> { // This field exists to ensure that nobody // can modify the underlying row while we are // holding a reference to some row value here - _row: Option>>, + _row: Option>>, // we extract the raw value pointer as part of the constructor // to safe the match statements for each method // According to benchmarks this leads to a ~20-30% speedup @@ -39,11 +39,11 @@ pub(super) struct OwnedSqliteValue { // see https://www.sqlite.org/c3ref/value.html unsafe impl Send for OwnedSqliteValue {} -impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { +impl<'row, 'stmt> SqliteValue<'row, 'stmt> { pub(super) fn new( - row: Ref<'row, PrivateSqliteRow<'stmt, 'query>>, + row: Ref<'row, PrivateSqliteRow<'stmt>>, col_idx: i32, - ) -> Option> { + ) -> Option> { let value = match &*row { PrivateSqliteRow::Direct(stmt) => stmt.column_value(col_idx)?, PrivateSqliteRow::Duplicated { values, .. } => values @@ -67,7 +67,7 @@ impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { pub(super) fn from_owned_row( row: &'row OwnedSqliteRow, col_idx: i32, - ) -> Option> { + ) -> Option> { let value = row .values .get(col_idx as usize) @@ -81,38 +81,39 @@ impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { Some(ret) } } + /* + pub(crate) fn parse_string(&self, f: impl FnOnce(String) -> R) -> R { + let sqlite3 = crate::get_sqlite_unchecked(); + let s = sqlite3.value_text(&self.value); + f(s) + } - pub(crate) fn parse_string(&self, f: impl FnOnce(String) -> R) -> R { - let sqlite3 = crate::get_sqlite_unchecked(); - let s = sqlite3.value_text(&self.value); - f(s) - } - - // TODO: Wasm bindgen can't work with references yet - // not sure if this will effect perf - pub(crate) fn read_text(&self) -> String { - self.parse_string(|s| s) - } + // TODO: Wasm bindgen can't work with references yet + // not sure if this will effect perf + pub(crate) fn read_text(&self) -> String { + self.parse_string(|s| s) + } - pub(crate) fn read_blob(&self) -> Vec { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_blob(&self.value) - } + pub(crate) fn read_blob(&self) -> Vec { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_blob(&self.value) + } - pub(crate) fn read_integer(&self) -> i32 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_int(&self.value) - } + pub(crate) fn read_integer(&self) -> i32 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_int(&self.value) + } - pub(crate) fn read_long(&self) -> i64 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_int64(&self.value) - } + pub(crate) fn read_long(&self) -> i64 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_int64(&self.value) + } - pub(crate) fn read_double(&self) -> f64 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_double(&self.value) - } + pub(crate) fn read_double(&self) -> f64 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_double(&self.value) + } + */ /// Get the type of the value as returned by sqlite pub fn value_type(&self) -> Option { diff --git a/diesel-wasm-sqlite/src/connection/statement_iterator.rs b/diesel-wasm-sqlite/src/connection/statement_iterator.rs deleted file mode 100644 index 393ec9e47..000000000 --- a/diesel-wasm-sqlite/src/connection/statement_iterator.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::cell::RefCell; -use std::rc::Rc; - -use super::row::{PrivateSqliteRow, SqliteRow}; -use super::stmt::StatementUse; -use crate::result::QueryResult; - -#[allow(missing_debug_implementations)] -pub struct StatementIterator<'stmt, 'query> { - inner: PrivateStatementIterator<'stmt, 'query>, - column_names: Option]>>, - field_count: usize, -} - -impl<'stmt, 'query> StatementIterator<'stmt, 'query> { - #[cold] - #[allow(unsafe_code)] // call to unsafe function - fn handle_duplicated_row_case( - outer_last_row: &mut Rc>>, - column_names: &mut Option]>>, - field_count: usize, - ) -> Option>> { - // We don't own the statement. There is another existing reference, likely because - // a user stored the row in some long time container before calling next another time - // In this case we copy out the current values into a temporary store and advance - // the statement iterator internally afterwards - let last_row = { - let mut last_row = match outer_last_row.try_borrow_mut() { - Ok(o) => o, - Err(_e) => { - return Some(Err(crate::result::Error::DeserializationError( - "Failed to reborrow row. Try to release any `SqliteField` or `SqliteValue` \ - that exists at this point" - .into(), - ))); - } - }; - let last_row = &mut *last_row; - let duplicated = last_row.duplicate(column_names); - std::mem::replace(last_row, duplicated) - }; - if let PrivateSqliteRow::Direct(mut stmt) = last_row { - let res = unsafe { - // This is actually safe here as we've already - // performed one step. For the first step we would have - // used `PrivateStatementIterator::NotStarted` where we don't - // have access to `PrivateSqliteRow` at all - stmt.step(false) - }; - *outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); - match res { - Err(e) => Some(Err(e)), - Ok(false) => None, - Ok(true) => Some(Ok(SqliteRow { - inner: Rc::clone(outer_last_row), - field_count, - })), - } - } else { - // any other state than `PrivateSqliteRow::Direct` is invalid here - // and should not happen. If this ever happens this is a logic error - // in the code above - unreachable!( - "You've reached an impossible internal state. \ - If you ever see this error message please open \ - an issue at https://github.com/diesel-rs/diesel \ - providing example code how to trigger this error." - ) - } - } -} - -enum PrivateStatementIterator<'stmt, 'query> { - NotStarted(Option>), - Started(Rc>>), -} - -impl<'stmt, 'query> StatementIterator<'stmt, 'query> { - pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> { - Self { - inner: PrivateStatementIterator::NotStarted(Some(stmt)), - column_names: None, - field_count: 0, - } - } -} - -impl<'stmt, 'query> Iterator for StatementIterator<'stmt, 'query> { - type Item = QueryResult>; - - #[allow(unsafe_code)] // call to unsafe function - fn next(&mut self) -> Option { - use PrivateStatementIterator::{NotStarted, Started}; - match &mut self.inner { - NotStarted(ref mut stmt @ Some(_)) => { - let mut stmt = stmt - .take() - .expect("It must be there because we checked that above"); - let step = unsafe { - // This is safe as we pass `first_step = true` to reset the cached column names - stmt.step(true) - }; - match step { - Err(e) => Some(Err(e)), - Ok(false) => None, - Ok(true) => { - let field_count = stmt.column_count() as usize; - self.field_count = field_count; - let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); - self.inner = Started(inner.clone()); - Some(Ok(SqliteRow { inner, field_count })) - } - } - } - Started(ref mut last_row) => { - // There was already at least one iteration step - // We check here if the caller already released the row value or not - // by checking if our Rc owns the data or not - if let Some(last_row_ref) = Rc::get_mut(last_row) { - // We own the statement, there is no other reference here. - // This means we don't need to copy out values from the sqlite provided - // datastructures for now - // We don't need to use the runtime borrowing system of the RefCell here - // as we have a mutable reference, so all of this below is checked at compile time - if let PrivateSqliteRow::Direct(ref mut stmt) = last_row_ref.get_mut() { - let step = unsafe { - // This is actually safe here as we've already - // performed one step. For the first step we would have - // used `PrivateStatementIterator::NotStarted` where we don't - // have access to `PrivateSqliteRow` at all - - stmt.step(false) - }; - match step { - Err(e) => Some(Err(e)), - Ok(false) => None, - Ok(true) => { - let field_count = self.field_count; - Some(Ok(SqliteRow { - inner: Rc::clone(last_row), - field_count, - })) - } - } - } else { - // any other state than `PrivateSqliteRow::Direct` is invalid here - // and should not happen. If this ever happens this is a logic error - // in the code above - unreachable!( - "You've reached an impossible internal state. \ - If you ever see this error message please open \ - an issue at https://github.com/diesel-rs/diesel \ - providing example code how to trigger this error." - ) - } - } else { - Self::handle_duplicated_row_case( - last_row, - &mut self.column_names, - self.field_count, - ) - } - } - NotStarted(_s) => { - // we likely got an error while executing the other - // `NotStarted` branch above. In this case we just want to stop - // iterating here - None - } - } - } -} diff --git a/diesel-wasm-sqlite/src/connection/statement_stream.rs b/diesel-wasm-sqlite/src/connection/statement_stream.rs new file mode 100644 index 000000000..2b44cd5a3 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/statement_stream.rs @@ -0,0 +1,199 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use super::owned_row::OwnedSqliteRow; +use super::row::{PrivateSqliteRow, SqliteRow}; +use super::stmt::StatementUse; +use diesel::result::QueryResult; +use diesel::row::IntoOwnedRow; +use futures::stream::LocalBoxStream; + +#[allow(missing_debug_implementations)] +pub struct StatementStream<'stmt> { + inner: StatementStreamState<'stmt>, + column_names: Option]>>, + field_count: usize, +} + +impl<'stmt> StatementStream<'stmt> { + #[cold] + async fn handle_duplicated_row_case( + outer_last_row: &mut Rc>>, + column_names: &mut Option]>>, + field_count: usize, + ) -> Option> { + // We don't own the statement. There is another existing reference, likely because + // a user stored the row in some long time container before calling next another time + // In this case we copy out the current values into a temporary store and advance + // the statement iterator internally afterwards + let last_row = { + let mut last_row = match outer_last_row.try_borrow_mut() { + Ok(o) => o, + Err(_e) => { + return Some(Err(diesel::result::Error::DeserializationError( + "Failed to reborrow row. Try to release any `SqliteField` or `SqliteValue` \ + that exists at this point" + .into(), + ))); + } + }; + let last_row = &mut *last_row; + let duplicated = last_row.duplicate(column_names); + std::mem::replace(last_row, duplicated) + }; + if let PrivateSqliteRow::Direct(mut stmt) = last_row { + let res = stmt.step(false).await; + *outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); + match res { + Err(e) => Some(Err(e)), + Ok(false) => None, + Ok(true) => Some(Ok(SqliteRow { + inner: Rc::clone(outer_last_row), + field_count, + } + .into_owned(&mut None))), + } + } else { + // any other state than `PrivateSqliteRow::Direct` is invalid here + // and should not happen. If this ever happens this is a logic error + // in the code above + unreachable!( + "You've reached an impossible internal state. \ + If you ever see this error message please open \ + an issue at https://github.com/diesel-rs/diesel \ + providing example code how to trigger this error." + ) + } + } +} + +enum StatementStreamState<'stmt> { + NotStarted(Option>), + Started(Rc>>), +} + +impl<'stmt> StatementStream<'stmt> { + pub fn new(stmt: StatementUse<'stmt>) -> StatementStream<'stmt> { + Self { + inner: StatementStreamState::NotStarted(Some(stmt)), + column_names: None, + field_count: 0, + } + } +} +/// Rolling a custom `Stream` impl on StatementStream was taking too long/tricky +/// so using `futures::unfold`. Rolling a custom `Stream` would probably be better, +/// but performance wise/code-readability sense not very different +impl<'stmt> StatementStream<'stmt> { + pub fn stream(self) -> LocalBoxStream<'stmt, QueryResult> { + use StatementStreamState::{NotStarted, Started}; + let stream = futures::stream::unfold(self, |mut statement| async move { + match statement.inner { + NotStarted(mut stmt @ Some(_)) => { + let mut stmt = stmt + .take() + .expect("It must be there because we checked that above"); + match stmt.step(true).await { + Ok(true) => { + let field_count = stmt.column_count() as usize; + statement.field_count = field_count; + let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); + let new_inner = inner.clone(); + Some(( + Ok(SqliteRow { inner, field_count }.into_owned(&mut None)), + Self { + inner: Started(new_inner), + ..statement + }, + )) + } + Ok(false) => None, + Err(e) => Some(( + Err(e), + Self { + inner: NotStarted(Some(stmt)), + ..statement + }, + )), + } + // res.poll_next(cx).map(|t| t.flatten()) + } + Started(ref mut last_row) => { + // There was already at least one iteration step + // We check here if the caller already released the row value or not + // by checking if our Rc owns the data or not + if let Some(last_row_ref) = Rc::get_mut(last_row) { + // We own the statement, there is no other reference here. + // This means we don't need to copy out values from the sqlite provided + // datastructures for now + // We don't need to use the runtime borrowing system of the RefCell here + // as we have a mutable reference, so all of this below is checked at compile time + if let PrivateSqliteRow::Direct(ref mut stmt) = last_row_ref.get_mut() { + // This is actually safe here as we've already + // performed one step. For the first step we would have + // used `StatementStreamState::NotStarted` where we don't + // have access to `PrivateSqliteRow` at all + match stmt.step(false).await { + Err(e) => Some(( + Err(e), + Self { + inner: Started(Rc::clone(last_row)), + ..statement + }, + )), + Ok(false) => None, + Ok(true) => { + let field_count = statement.field_count; + Some(( + Ok(SqliteRow { + inner: Rc::clone(last_row), + field_count, + } + .into_owned(&mut None)), + Self { + inner: Started(Rc::clone(last_row)), + ..statement + }, + )) + } + } + } else { + // any other state than `PrivateSqliteRow::Direct` is invalid here + // and should not happen. If this ever happens this is a logic error + // in the code above + unreachable!( + "You've reached an impossible internal state. \ + If you ever see this error message please open \ + an issue at https://github.com/diesel-rs/diesel \ + providing example code how to trigger this error." + ) + } + } else { + let res = Self::handle_duplicated_row_case( + last_row, + &mut statement.column_names, + statement.field_count, + ) + .await; + res.map(|r| { + ( + r, + Self { + inner: Started(Rc::clone(last_row)), + ..statement + }, + ) + }) + } + } + NotStarted(_s) => { + // we likely got an error while executing the other + // `NotStarted` branch above. In this case we just want to stop + // iterating here + None + } + } + }); + Box::pin(stream) + } +} diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 53fb5ba78..37958f19c 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -1,22 +1,21 @@ #![allow(unsafe_code)] //TODO: can probably remove for wa-sqlite -use super::bind_collector::{InternalSqliteBindValue, SqliteBindCollector}; +use super::bind_collector::{OwnedSqliteBindValue, SqliteBindCollectorData}; use super::raw::RawConnection; use super::sqlite_value::OwnedSqliteValue; use crate::ffi::SQLiteCompatibleType; use crate::{ sqlite_types::{self, PrepareOptions, SqlitePrepareFlags}, - SqliteType, WasmSqlite, + SqliteType, }; use diesel::{ connection::{ statement_cache::{MaybeCached, PrepareForCache}, Instrumentation, }, - query_builder::{QueryFragment, QueryId}, - result::{Error::DatabaseError, *}, + result::{Error, QueryResult}, }; use std::cell::OnceCell; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; use wasm_bindgen::JsValue; @@ -90,7 +89,7 @@ impl Statement { fn bind( &self, _tpe: SqliteType, - value: InternalSqliteBindValue<'_>, + value: OwnedSqliteBindValue, bind_index: i32, ) -> QueryResult { let sqlite3 = crate::get_sqlite_unchecked(); @@ -100,7 +99,7 @@ impl Statement { .bind(&self.inner_statement, bind_index, value.into()) .unwrap(); - // TODO:insipx Pretty sure we can have a simpler implementation here + // TODO:insipx Pretty sure we can have a simpler implementation here vs diesel // making use of `wa-sqlite` `bind` which abstracts over the individual bind functions in // sqlite3. However, not sure how this will work further up the stack. // This might not work because of differences in how serde_json recognizes js types @@ -178,59 +177,41 @@ impl Drop for Statement { // * https://github.com/weiznich/diesel/pull/7 // * https://users.rust-lang.org/t/code-review-for-unsafe-code-in-diesel/66798/ // * https://github.com/rust-lang/unsafe-code-guidelines/issues/194 -struct BoundStatement<'stmt, 'query> { +struct BoundStatement<'stmt> { statement: MaybeCached<'stmt, Statement>, // we need to store the query here to ensure no one does // drop it till the end of the statement // We use a boxed queryfragment here just to erase the // generic type, we use NonNull to communicate // that this is a shared buffer - query: Option + 'query>>, - instrumentation: &'stmt Mutex, + // query: Option>>, + #[allow(unused)] + instrumentation: Arc>, has_error: bool, } -impl<'stmt, 'query> BoundStatement<'stmt, 'query> { - fn bind( +impl<'stmt> BoundStatement<'stmt> { + fn bind( statement: MaybeCached<'stmt, Statement>, - query: T, - instrumentation: &'stmt Mutex, - ) -> QueryResult> - where - T: QueryFragment + QueryId + 'query, - { - // Don't use a trait object here to prevent using a virtual function call - // For sqlite this can introduce a measurable overhead - // Query is boxed here to make sure it won't move in memory anymore, so any bind - // it could output would stay valid. - let query = Box::new(query); - - let mut bind_collector = SqliteBindCollector::new(); - query.collect_binds(&mut bind_collector, &mut (), &WasmSqlite)?; - let SqliteBindCollector { binds } = bind_collector; - + bind_collector: SqliteBindCollectorData, + instrumentation: Arc>, + ) -> QueryResult> { + let SqliteBindCollectorData { binds } = bind_collector; let mut ret = BoundStatement { statement, - query: None, instrumentation, has_error: false, }; ret.bind_buffers(binds)?; - let query = query as Box + 'query>; - ret.query = Some(query); - Ok(ret) } // This is a separated function so that // not the whole constructor is generic over the query type T. // This hopefully prevents binary bloat. - fn bind_buffers( - &mut self, - binds: Vec<(InternalSqliteBindValue<'_>, SqliteType)>, - ) -> QueryResult<()> { + fn bind_buffers(&mut self, binds: Vec<(OwnedSqliteBindValue, SqliteType)>) -> QueryResult<()> { for (bind_idx, (bind, tpe)) in (1..).zip(binds) { // It's safe to call bind here as: // * The type and value matches @@ -252,18 +233,6 @@ impl<'stmt, 'query> BoundStatement<'stmt, 'query> { fn finish_query_with_error(mut self, _e: &Error) { self.has_error = true; - /* - if let Some(q) = self.query { - // it's safe to get a reference from this ptr as it's guaranteed to not be null - let q = unsafe { q.as_ref() }; - self.instrumentation.on_connection_event( - diesel::connection::InstrumentationEvent::FinishQuery { - query: &crate::debug_query(&q), - error: Some(e), - }, - ); - } - */ } // FIXME: [`AsyncDrop`](https://github.com/rust-lang/rust/issues/126482) is a missing feature in rust. @@ -275,7 +244,7 @@ impl<'stmt, 'query> BoundStatement<'stmt, 'query> { } // Eventually replace with `AsyncDrop`: https://github.com/rust-lang/rust/issues/126482 -impl<'stmt, 'query> Drop for BoundStatement<'stmt, 'query> { +impl<'stmt> Drop for BoundStatement<'stmt> { fn drop(&mut self) { let sender = self .statement @@ -283,27 +252,24 @@ impl<'stmt, 'query> Drop for BoundStatement<'stmt, 'query> { .take() .expect("Drop may only be ran once"); let _ = sender.send(self.statement.inner_statement.clone()); - self.query.take(); } } #[allow(missing_debug_implementations)] -pub struct StatementUse<'stmt, 'query> { - statement: BoundStatement<'stmt, 'query>, +pub struct StatementUse<'stmt> { + statement: BoundStatement<'stmt>, column_names: OnceCell>, } -impl<'stmt, 'query> StatementUse<'stmt, 'query> { - pub(super) fn bind( +impl<'stmt> StatementUse<'stmt> { + pub(super) fn bind( statement: MaybeCached<'stmt, Statement>, - query: T, - instrumentation: &'stmt Mutex, - ) -> QueryResult> - where - T: QueryFragment + QueryId + 'query, - { + bind_collector: SqliteBindCollectorData, + instrumentation: Arc>, + ) -> QueryResult> +where { Ok(Self { - statement: BoundStatement::bind(statement, query, instrumentation)?, + statement: BoundStatement::bind(statement, bind_collector, instrumentation)?, column_names: OnceCell::new(), }) } diff --git a/diesel-wasm-sqlite/src/query_builder/mod.rs b/diesel-wasm-sqlite/src/query_builder/mod.rs index 8bf48119b..3489876b8 100644 --- a/diesel-wasm-sqlite/src/query_builder/mod.rs +++ b/diesel-wasm-sqlite/src/query_builder/mod.rs @@ -6,7 +6,7 @@ use diesel::result::QueryResult; mod limit_offset; mod query_fragment_impls; -mod returning; +// mod returning; /// Constructs SQL queries for use with the SQLite backend #[allow(missing_debug_implementations)] From 6a636ce59b8e0b988b1e88943f2cb80e685fe45b Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 22 Aug 2024 11:18:41 -0400 Subject: [PATCH 03/97] Insertion ORM w/ prepared statements works (#966) * fix diesel function registration * query building works * try insert with orml * compile with sqlite default fix * compile but still ahve static lifetimes * fix unimplemented traits * ORM compiles! * some cleanup, setup tracing in wasm for test * readme * upgrade wa-sqlite version * temp DebugQuery to help with debugging * make debug query unsafe * progress on statement issue * progress for destructor order * logs/fix async drop for BoundStatement * remove task spawn for statementfactory --- diesel-wasm-sqlite/Cargo.lock | 363 ++++++++++- diesel-wasm-sqlite/Cargo.toml | 17 +- diesel-wasm-sqlite/README.md | 20 +- diesel-wasm-sqlite/build.rs | 1 + diesel-wasm-sqlite/package.js | 33 +- diesel-wasm-sqlite/package.json | 2 +- diesel-wasm-sqlite/rollup.config.js | 4 +- diesel-wasm-sqlite/src/backend.rs | 5 +- .../src/connection/bind_collector.rs | 8 +- diesel-wasm-sqlite/src/connection/mod.rs | 39 +- diesel-wasm-sqlite/src/connection/raw.rs | 55 +- .../src/connection/sqlite_value.rs | 53 +- diesel-wasm-sqlite/src/connection/stmt.rs | 170 +++--- diesel-wasm-sqlite/src/ffi.rs | 26 +- diesel-wasm-sqlite/src/lib.rs | 34 +- .../insert_with_default_sqlite.rs | 565 +++++++++++++++++ diesel-wasm-sqlite/src/query_builder/mod.rs | 1 + .../src/query_builder/query_fragment_impls.rs | 1 - diesel-wasm-sqlite/src/sqlite_fixes.rs | 64 ++ diesel-wasm-sqlite/src/sqlite_types.rs | 4 +- diesel-wasm-sqlite/src/sqlite_types/to_sql.rs | 171 ++++++ .../src/wa-sqlite-diesel-bundle.js | 578 ++++++++++-------- diesel-wasm-sqlite/tests/web.rs | 173 +++++- .../2024-08-20-203551_create_books/down.sql | 1 + .../2024-08-20-203551_create_books/up.sql | 7 + diesel-wasm-sqlite/yarn.lock | 180 +++--- 26 files changed, 2001 insertions(+), 574 deletions(-) create mode 100644 diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs create mode 100644 diesel-wasm-sqlite/src/sqlite_fixes.rs create mode 100644 diesel-wasm-sqlite/src/sqlite_types/to_sql.rs create mode 100644 diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/down.sql create mode 100644 diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index f179de053..2f769c28c 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -17,6 +17,21 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "async-trait" version = "0.1.81" @@ -67,12 +82,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "bytes" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - [[package]] name = "cc" version = "1.1.8" @@ -85,6 +94,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -95,6 +119,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "darling" version = "0.20.10" @@ -136,13 +166,14 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" dependencies = [ + "chrono", "diesel_derives", ] [[package]] name = "diesel-async" version = "0.5.0" -source = "git+https://github.com/insipx/diesel_async?branch=insipx/make-stmt-cache-public#f1c4838ae6d7951b78572c249ba65f7a107488a0" +source = "git+https://github.com/insipx/diesel_async?branch=insipx/make-stmt-cache-public#3b771a153f66cb9cbb7e8fcd6d1a59d029f4368b" dependencies = [ "async-trait", "diesel", @@ -156,17 +187,23 @@ version = "0.1.1" dependencies = [ "async-trait", "bitflags", + "chrono", "console_error_panic_hook", "diesel", "diesel-async", + "diesel_derives", + "diesel_migrations", "futures", "futures-util", "getrandom", - "log", + "js-sys", "rand", "serde", "serde-wasm-bindgen", + "thiserror", "tokio", + "tracing", + "tracing-wasm", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", @@ -186,6 +223,17 @@ dependencies = [ "syn", ] +[[package]] +name = "diesel_migrations" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6" +dependencies = [ + "diesel", + "migrations_internals", + "migrations_macros", +] + [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" @@ -215,6 +263,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fnv" version = "1.0.7" @@ -329,18 +383,57 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -350,6 +443,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.155" @@ -368,6 +467,27 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "migrations_internals" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff" +dependencies = [ + "serde", + "toml", +] + +[[package]] +name = "migrations_macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd" +dependencies = [ + "migrations_internals", + "proc-macro2", + "quote", +] + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -377,6 +497,15 @@ dependencies = [ "adler", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.3" @@ -514,6 +643,24 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "slab" version = "0.4.9" @@ -540,6 +687,36 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tokio" version = "1.39.2" @@ -547,7 +724,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", - "bytes", "pin-project-lite", "tokio-macros", ] @@ -563,6 +739,93 @@ dependencies = [ "syn", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "tracing-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" +dependencies = [ + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -676,6 +939,88 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index 737e6d77d..f8d8149fe 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -2,32 +2,40 @@ name = "diesel-wasm-sqlite" version = "0.1.1" edition = "2021" +resolver = "2" [dependencies] # diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/wasm-backend", default-features = false, features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } -diesel = "2.2" +diesel = { version = "2.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } diesel-async = { git = "https://github.com/insipx/diesel_async", branch = "insipx/make-stmt-cache-public", features = ["stmt-cache"] } +diesel_derives = "2.2" wasm-bindgen = "0.2.92" wasm-bindgen-futures = "0.4.42" -log = "0.4" +tracing = "0.1" rand = "0.8" getrandom = { version = "0.2", features = ["js"] } web-sys = { version = "0.3", features = ["console"] } +js-sys = { version = "0.3" } # wee_alloc = { version = "0.4.2", optional = true } console_error_panic_hook = { version = "0.1", optional = true } -tokio = { version = "1.38", default-features = false, features = ["rt", "macros", "sync", "io-util", "time"] } +tokio = { version = "1.38", default-features = false, features = ["rt", "macros", "sync"] } futures = "0.3" futures-util = "0.3" async-trait = "0.1" bitflags = "2.6" serde = { version = "1.0", features = ["derive"] } serde-wasm-bindgen = "0.6" +thiserror = "1" [dev-dependencies] rand = "0.8" getrandom = { version = "0.2", features = ["js"] } wasm-bindgen-test = "0.3.42" web-sys = { version = "0.3", features = ["console"] } +chrono = { version = "0.4", features = ["wasmbind", "serde"] } +diesel_migrations = "2.2" +diesel = { version = "2.2", features = ["chrono"]} +tracing-wasm = { version = "0.2" } [lib] @@ -35,6 +43,9 @@ crate-type = ["cdylib", "rlib"] [features] default = ["console_error_panic_hook"] +# enables a `DebugQueryWrapper` for diesel +# but is unsafe because of mem::transmute +unsafe-debug-query = [] [build] target = "wasm32-unknown-unknown" diff --git a/diesel-wasm-sqlite/README.md b/diesel-wasm-sqlite/README.md index 77b146779..8e1e4be42 100644 --- a/diesel-wasm-sqlite/README.md +++ b/diesel-wasm-sqlite/README.md @@ -1,16 +1,20 @@ # Custom Diesel Backend for Wasm wa-sqlite -#### Bundle the javascript in `package.js` to rust +### Compile rust code without creating a npm package -`yarn run build` +`cargo build --target wasm32-unknown-unknown` -#### Build the JS WASM interface +#### Build the JS WASM interfaces `wasm-pack build` #### Run the Wasm Tests -wasm-pack test --chrome --headless +wasm-pack test --chrome + +navigate to `http://localhost:8000` to observe test output + +(headless tests don't work yet) # TODO @@ -18,8 +22,8 @@ wasm-pack test --chrome --headless issue?) - [ ] OPFS -# Notes +# Setting up the project in VSCode -- rust-analyzer doesn't like crates with different targets in the same - workspace. If you want this to work well with your LSP, open - `diesel-wasm-sqlite` as it's own project. +rust-analyzer does not like crates with different targets in the same workspace. +If you want this to work well with your LSP, open `diesel-wasm-sqlite` as it's +own project in VSCode. diff --git a/diesel-wasm-sqlite/build.rs b/diesel-wasm-sqlite/build.rs index 01bfc1044..f6e5b3913 100644 --- a/diesel-wasm-sqlite/build.rs +++ b/diesel-wasm-sqlite/build.rs @@ -3,6 +3,7 @@ use std::process::Command; fn main() { println!("cargo::rerun-if-changed=package.js"); + println!("cargo::rerun-if-changed=package.json"); Command::new("yarn") .args(["run", "build"]) diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index 9b4459237..ed1f73d14 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -67,7 +67,7 @@ export class SQLite { try { return this.sqlite3.bind(stmt, i, value); } catch (error) { - console.log("bind err"); + console.log(`bind err ${error}`); throw error; } } @@ -185,7 +185,7 @@ export class SQLite { } value_type(pValue) { - this.sqlite3.value_type(pValue); + return this.sqlite3.value_type(pValue); } async open_v2(database_url, iflags) { @@ -226,7 +226,12 @@ export class SQLite { } clear_bindings(stmt) { - return this.sqlite3.clear_bindings(stmt); + try { + return this.sqlite3.clear_bindings(stmt); + } catch (error) { + console.log("sqlite3.clear_bindings error"); + throw error; + } } async close(db) { @@ -251,6 +256,19 @@ export class SQLite { } } + // there should be a way to do this from Rust + // If we pass the statement we get from 'next' + // it does not work. + async get_stmt_from_iterator(iterator) { + try { + const stmt = await iterator.next(); + return stmt; + } catch (error) { + console.log("sqlite prepare error"); + throw error; + } + } + async step(stmt) { try { return await this.sqlite3.step(stmt); @@ -268,12 +286,11 @@ export class SQLite { return this.sqlite3.column_count(stmt); } - batch_execute(database, query) { + async batch_execute(database, query) { try { - return this.sqlite3.exec(database, query); - console.log("Batch exec'ed"); + return await this.sqlite3.exec(database, query); } catch (error) { - console.log("exec err"); + console.log("batch exec err"); throw error; } } @@ -315,7 +332,7 @@ export class SQLite { 1, WasmSQLiteLibrary.SQLITE_UTF8, 0, - (context, values) => { + async (context, values) => { const table_name = this.sqlite3.value_text(values[0]); await this.sqlite3.exec( diff --git a/diesel-wasm-sqlite/package.json b/diesel-wasm-sqlite/package.json index 6f529c83e..040c0cece 100644 --- a/diesel-wasm-sqlite/package.json +++ b/diesel-wasm-sqlite/package.json @@ -8,7 +8,7 @@ "build": "rollup -c" }, "dependencies": { - "@xmtp/wa-sqlite": "^1.0.1" + "@xmtp/wa-sqlite": ">=1.0.3" }, "packageManager": "yarn@4.3.1", "engines": { diff --git a/diesel-wasm-sqlite/rollup.config.js b/diesel-wasm-sqlite/rollup.config.js index 881eeadf5..7692eb6d7 100644 --- a/diesel-wasm-sqlite/rollup.config.js +++ b/diesel-wasm-sqlite/rollup.config.js @@ -1,5 +1,5 @@ import { defineConfig } from "rollup"; -import resolve from "@rollup/plugin-node-resolve"; +import { nodeResolve } from "@rollup/plugin-node-resolve"; import { base64 } from "rollup-plugin-base64"; export default defineConfig([ @@ -10,7 +10,7 @@ export default defineConfig([ format: "es", }, plugins: [ - resolve(), + nodeResolve(), base64({ include: "**/*.wasm" }), ], // external: ["@xmtp/wa-sqlite", "@xmtp/wa-sqlite/build"], diff --git a/diesel-wasm-sqlite/src/backend.rs b/diesel-wasm-sqlite/src/backend.rs index 05ecf0950..e0afa56ff 100644 --- a/diesel-wasm-sqlite/src/backend.rs +++ b/diesel-wasm-sqlite/src/backend.rs @@ -1,4 +1,4 @@ -//! The SQLite backend +//! The WasmSQLite backend use super::connection::SqliteBindCollector; use super::connection::SqliteValue; @@ -49,9 +49,6 @@ impl TypeMetadata for WasmSqlite { } impl SqlDialect for WasmSqlite { - #[cfg(not(feature = "returning_clauses_for_sqlite_3_35"))] - type ReturningClause = sql_dialect::returning_clause::DoesNotSupportReturningClause; - #[cfg(feature = "returning_clauses_for_sqlite_3_35")] type ReturningClause = SqliteReturningClause; type OnConflictClause = SqliteOnConflictClause; diff --git a/diesel-wasm-sqlite/src/connection/bind_collector.rs b/diesel-wasm-sqlite/src/connection/bind_collector.rs index dc51e115a..26ab3d4b5 100644 --- a/diesel-wasm-sqlite/src/connection/bind_collector.rs +++ b/diesel-wasm-sqlite/src/connection/bind_collector.rs @@ -6,11 +6,6 @@ use diesel::{ sql_types::HasSqlType, }; use serde::{Deserialize, Serialize}; -use wasm_bindgen::JsValue; - -// TODO:insipx this file remains largely unchanged other than the ffi::. Candidate for shared code? - -pub type BindValue = JsValue; #[derive(Debug, Default)] pub struct SqliteBindCollector<'a> { @@ -131,7 +126,7 @@ impl std::fmt::Display for InternalSqliteBindValue<'_> { f.write_str(n) } } - +/* impl InternalSqliteBindValue<'_> { #[allow(unsafe_code)] // ffi function calls pub(crate) fn result_of(self, ctx: &mut i32) { @@ -148,6 +143,7 @@ impl InternalSqliteBindValue<'_> { } } } +*/ impl<'a> BindCollector<'a, WasmSqlite> for SqliteBindCollector<'a> { type Buffer = SqliteBindValue<'a>; diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index 2694eadfe..ec990c6dc 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -33,29 +33,26 @@ pub use diesel_async::{AnsiTransactionManager, AsyncConnection, SimpleAsyncConne use crate::{get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; +// This relies on the invariant that RawConnection or Statement are never +// leaked. If a reference to one of those was held on a different thread, this +// would not be thread safe. +// Web is in one thread. Web workers can establish & hold a WasmSqliteConnection +// separately. +#[allow(unsafe_code)] +unsafe impl Send for WasmSqliteConnection {} + pub struct WasmSqliteConnection { // statement_cache needs to be before raw_connection // otherwise we will get errors about open statements before closing the // connection itself statement_cache: StmtCache, - pub raw_connection: RawConnection, + raw_connection: RawConnection, transaction_manager: AnsiTransactionManager, // this exists for the sole purpose of implementing `WithMetadataLookup` trait // and avoiding static mut which will be deprecated in 2024 edition instrumentation: Arc>>>, } - -// This relies on the invariant that RawConnection or Statement are never -// leaked. If a reference to one of those was held on a different thread, this -// would not be thread safe. -// Web is in one thread. Web workers can be used to hold a WasmSqliteConnection -// separately. - -#[allow(unsafe_code)] -unsafe impl Send for WasmSqliteConnection {} - - impl ConnectionSealed for WasmSqliteConnection {} #[async_trait::async_trait(?Send)] @@ -63,6 +60,7 @@ impl SimpleAsyncConnection for WasmSqliteConnection { async fn batch_execute(&mut self, query: &str) -> diesel::prelude::QueryResult<()> { get_sqlite_unchecked() .batch_execute(&self.raw_connection.internal_connection, query) + .await .map_err(WasmSqliteError::from) .map_err(Into::into) } @@ -88,6 +86,7 @@ impl AsyncConnection for WasmSqliteConnection { { let query = source.as_query(); self.with_prepared_statement(query, |_, statement| async move { + tracing::debug!("Loading statement!"); Ok(StatementStream::new(statement).stream()) }) } @@ -100,6 +99,7 @@ impl AsyncConnection for WasmSqliteConnection { T: QueryFragment + QueryId + 'query, { self.with_prepared_statement(query, |conn, statement| async move { + tracing::debug!("Running statement!"); statement.run().await.map(|_| { conn.rows_affected_by_last_query() }) @@ -113,11 +113,11 @@ impl AsyncConnection for WasmSqliteConnection { } fn instrumentation(&mut self) -> &mut dyn Instrumentation { - todo!() + Arc::get_mut(&mut self.instrumentation).expect("arc ref").get_mut().expect("Mutex poison") } fn set_instrumentation(&mut self, _instrumentation: impl Instrumentation) { - todo!() + tracing::debug!("Set instrumentation"); } } @@ -237,6 +237,7 @@ impl WasmSqliteConnection { Q: QueryFragment + QueryId, F: Future>, { + tracing::info!("WITH PREPARED STATEMENT"); let WasmSqliteConnection { ref mut raw_connection, ref mut statement_cache, @@ -260,6 +261,7 @@ impl WasmSqliteConnection { let sql = query.to_sql(&mut qb, &WasmSqlite).map(|()| qb.finish()); async move { + tracing::info!("IN STATEMENT PREPARE FUTURE"); let (statement, conn) = statement_cache.cached_prepared_statement( cache_key?, sql?, @@ -267,9 +269,14 @@ impl WasmSqliteConnection { &[], raw_connection, &instrumentation, - ).await?; // Cloned RawConnection is dropped here + ).await?; let statement = StatementUse::bind(statement, bind_collector?, instrumentation)?; - callback(conn, statement).await + let result = callback(conn, statement).await; + // statement is dropped here + // we need to yield back to the executor and allow + // the destructor for BoundStatement to run + tokio::task::yield_now().await; + result }.boxed_local() } diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs index 65d3cb4bc..0cd1583ed 100755 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -6,30 +6,24 @@ use crate::{ SqliteType, WasmSqlite, WasmSqliteError, }; use diesel::{ - connection::statement_cache::PrepareForCache, result::*, serialize::ToSql, + connection::statement_cache::{PrepareForCache, StatementCacheKey}, + result::*, + serialize::ToSql, sql_types::HasSqlType, }; +use std::collections::HashMap; use tokio::sync::oneshot; use wasm_bindgen::{closure::Closure, JsValue}; -use super::stmt::Statement; +use super::stmt::{Statement, StatementFactory}; #[allow(missing_copy_implementations)] -#[derive(Debug)] pub(super) struct RawConnection { pub(super) internal_connection: JsValue, + iterator_cache: HashMap, js_sys::AsyncIterator>, drop_signal: Option>, } -impl Clone for RawConnection { - fn clone(&self) -> Self { - Self { - internal_connection: self.internal_connection.clone(), - drop_signal: None, - } - } -} - impl RawConnection { pub(super) async fn establish(database_url: &str) -> ConnectionResult { let sqlite3 = crate::get_sqlite().await; @@ -49,15 +43,15 @@ impl RawConnection { Ok(conn) => { let sqlite3 = crate::get_sqlite_unchecked(); match sqlite3.close(&conn).await { - Ok(_) => log::debug!("db closed"), + Ok(_) => tracing::debug!("db closed"), Err(e) => { - log::error!("error during db close"); + tracing::error!("error during db close"); web_sys::console::log_1(&e); } } } Err(_) => { - log::error!("RawConnection never dropped."); + tracing::error!("RawConnection never dropped."); } } }); @@ -68,6 +62,7 @@ impl RawConnection { .await .map_err(WasmSqliteError::from) .map_err(ConnectionError::from)?, + iterator_cache: HashMap::new(), drop_signal: Some(tx), }) } @@ -169,8 +164,11 @@ impl diesel_async::stmt_cache::PrepareCallback for &'_ mu _metadata: &[SqliteType], is_for_cache: PrepareForCache, ) -> QueryResult<(Statement, Self)> { - let stmt = Statement::prepare(&self, sql, is_for_cache).await; - Ok((stmt?, self)) + let stmt = StatementFactory::new(&self, sql, is_for_cache) + .await? + .prepare() + .await; + Ok((stmt, self)) } } @@ -179,28 +177,7 @@ impl Drop for RawConnection { if let Some(s) = self.drop_signal.take() { let _ = s.send(self.internal_connection.clone()); } else { - log::warn!("RawConnection not dropped because drop_signal is empty"); + tracing::warn!("RawConnection not dropped because drop_signal is empty"); } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::connection::{AsyncConnection, WasmSqliteConnection}; - use diesel::connection::Connection; - use wasm_bindgen_test::*; - use web_sys::console; - wasm_bindgen_test_configure!(run_in_dedicated_worker); - - #[wasm_bindgen_test] - async fn test_fn_registration() { - let mut result = WasmSqliteConnection::establish("test").await; - let mut conn = result.unwrap(); - console::log_1(&"CONNECTED".into()); - conn.raw - .register_sql_function("test", 0, true, |ctx, values| { - console::log_1(&"Inside Fn".into()); - }); - } -} diff --git a/diesel-wasm-sqlite/src/connection/sqlite_value.rs b/diesel-wasm-sqlite/src/connection/sqlite_value.rs index 7510a892b..bfc104f79 100644 --- a/diesel-wasm-sqlite/src/connection/sqlite_value.rs +++ b/diesel-wasm-sqlite/src/connection/sqlite_value.rs @@ -81,39 +81,36 @@ impl<'row, 'stmt> SqliteValue<'row, 'stmt> { Some(ret) } } - /* - pub(crate) fn parse_string(&self, f: impl FnOnce(String) -> R) -> R { - let sqlite3 = crate::get_sqlite_unchecked(); - let s = sqlite3.value_text(&self.value); - f(s) - } - // TODO: Wasm bindgen can't work with references yet - // not sure if this will effect perf - pub(crate) fn read_text(&self) -> String { - self.parse_string(|s| s) - } + pub(crate) fn parse_string(&self, f: impl FnOnce(String) -> R) -> R { + let sqlite3 = crate::get_sqlite_unchecked(); + let s = sqlite3.value_text(&self.value); + f(s) + } + //FIXME: WE SHOULD TRY TO RETURN STRING REFERENCE HERE referenceing JS Type in wasm-bindgen! + pub(crate) fn read_text(&self) -> String { + self.parse_string(|s| s) + } - pub(crate) fn read_blob(&self) -> Vec { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_blob(&self.value) - } + pub(crate) fn read_blob(&self) -> Vec { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_blob(&self.value) + } - pub(crate) fn read_integer(&self) -> i32 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_int(&self.value) - } + pub(crate) fn read_integer(&self) -> i32 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_int(&self.value) + } - pub(crate) fn read_long(&self) -> i64 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_int64(&self.value) - } + pub(crate) fn read_long(&self) -> i64 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_int64(&self.value) + } - pub(crate) fn read_double(&self) -> f64 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_double(&self.value) - } - */ + pub(crate) fn read_double(&self) -> f64 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_double(&self.value) + } /// Get the type of the value as returned by sqlite pub fn value_type(&self) -> Option { diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 37958f19c..649ed71df 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -5,7 +5,7 @@ use super::sqlite_value::OwnedSqliteValue; use crate::ffi::SQLiteCompatibleType; use crate::{ sqlite_types::{self, PrepareOptions, SqlitePrepareFlags}, - SqliteType, + SqliteType, WasmSqliteError, }; use diesel::{ connection::{ @@ -14,24 +14,26 @@ use diesel::{ }, result::{Error, QueryResult}, }; +use js_sys::AsyncIterator; use std::cell::OnceCell; use std::sync::{Arc, Mutex}; +use tokio::sync::oneshot; use wasm_bindgen::JsValue; +use wasm_bindgen_futures::JsFuture; -// this is OK b/c web runs in one thread -unsafe impl Send for Statement {} -pub(super) struct Statement { - inner_statement: JsValue, - drop_signal: Option>, +// TODO: Drop impl make sure to free JS async iterat9or +pub struct StatementFactory { + statement_iterator: js_sys::AsyncIterator, } -impl Statement { - pub(super) async fn prepare( +impl StatementFactory { + pub async fn new( raw_connection: &RawConnection, sql: &str, is_cached: PrepareForCache, ) -> QueryResult { + tracing::debug!("new statement factory, is_cached = {:?}", is_cached); let sqlite3 = crate::get_sqlite_unchecked(); let flags = if matches!(is_cached, PrepareForCache::Yes) { Some(SqlitePrepareFlags::SQLITE_PREPARE_PERSISTENT.bits()) @@ -41,46 +43,45 @@ impl Statement { let options = PrepareOptions { flags, - unscoped: None, + unscoped: Some(true), }; let stmt = sqlite3 + // TODO: rename to something more fitting .prepare( &raw_connection.internal_connection, sql, serde_wasm_bindgen::to_value(&options).unwrap(), ) .await - .unwrap(); + .map_err(WasmSqliteError::from)?; - let (tx, rx) = tokio::sync::oneshot::channel::(); + let statement_iterator = js_sys::AsyncIterator::from(stmt); + Ok(Self { statement_iterator }) + } - // We don't have `AsyncDrop` in rust yet. - // instead, we `send` a signal on Drop for the destructor to run in an - // asynchronously-spawned task. - wasm_bindgen_futures::spawn_local(async move { - match rx.await { - Ok(inner_statement) => { - let this = Statement { - inner_statement, - drop_signal: None, - }; - - this.reset().await; - this.clear_bindings(); - } - Err(_) => { - log::error!("Statement never dropped"); - } - } - }); + /// compile a new statement based on given SQL in [`StatementFactory`] + pub async fn prepare(&self) -> Statement { + let inner_statement = JsFuture::from(self.statement_iterator.next().expect("No Next")) + .await + .expect("statement failed to compile"); + let inner_statement: JsValue = js_sys::Reflect::get(&inner_statement, &"value".into()) + .expect("Async Iterator API should be stable"); + tracing::debug!("Statement: {:?}", inner_statement); - Ok(Statement { - inner_statement: stmt, - drop_signal: Some(tx), - }) + Statement { inner_statement } } +} + +// this is OK b/c web runs in one thread +unsafe impl Send for Statement {} +#[derive(Debug)] +pub(super) struct Statement { + // each iteration compiles a new statement for use + inner_statement: JsValue, +} +impl Statement { // The caller of this function has to ensure that: // * Any buffer provided as `SqliteBindValue::BorrowedBinary`, `SqliteBindValue::Binary` // `SqliteBindValue::String` or `SqliteBindValue::BorrowedString` is valid @@ -95,9 +96,11 @@ impl Statement { let sqlite3 = crate::get_sqlite_unchecked(); let value = serde_wasm_bindgen::to_value(&value).expect("Bind value failed to convert to JsValue"); + tracing::info!("Statement: {:?}", self.inner_statement); + let result = sqlite3 .bind(&self.inner_statement, bind_index, value.into()) - .unwrap(); + .expect("could not bind"); // TODO:insipx Pretty sure we can have a simpler implementation here vs diesel // making use of `wa-sqlite` `bind` which abstracts over the individual bind functions in @@ -109,50 +112,24 @@ impl Statement { Ok(result) } - async fn reset(&self) { + async fn reset(&self) -> QueryResult<()> { let sqlite3 = crate::get_sqlite_unchecked(); - let _ = sqlite3.reset(&self.inner_statement).await.unwrap(); + let _ = sqlite3 + .reset(&self.inner_statement) + .await + .map_err(WasmSqliteError::from)?; + Ok(()) } - fn clear_bindings(&self) { + fn clear_bindings(&self) -> QueryResult<()> { let sqlite3 = crate::get_sqlite_unchecked(); - let _ = sqlite3.clear_bindings(&self.inner_statement).unwrap(); - } - - /* not sure if there is equivalent method or just cloning the stmt is enough - fn raw_connection(&self) -> *mut ffi::sqlite3 { - unsafe { ffi::sqlite3_db_handle(self.inner_statement.as_ptr()) } + let _ = sqlite3 + .clear_bindings(&self.inner_statement) + .map_err(WasmSqliteError::from)?; + Ok(()) } - */ -} - -/* TODO: Useful for converting JS Error messages to Rust -fn last_error(raw_connection: *mut ffi::sqlite3) -> Error { - let error_message = last_error_message(raw_connection); - let error_information = Box::new(error_message); - let error_kind = match last_error_code(raw_connection) { - ffi::SQLITE_CONSTRAINT_UNIQUE | ffi::SQLITE_CONSTRAINT_PRIMARYKEY => { - DatabaseErrorKind::UniqueViolation - } - ffi::SQLITE_CONSTRAINT_FOREIGNKEY => DatabaseErrorKind::ForeignKeyViolation, - ffi::SQLITE_CONSTRAINT_NOTNULL => DatabaseErrorKind::NotNullViolation, - ffi::SQLITE_CONSTRAINT_CHECK => DatabaseErrorKind::CheckViolation, - _ => DatabaseErrorKind::Unknown, - }; - DatabaseError(error_kind, error_information) } -fn last_error_message(conn: *mut ffi::sqlite3) -> String { - let c_str = unsafe { CStr::from_ptr(ffi::sqlite3_errmsg(conn)) }; - c_str.to_string_lossy().into_owned() -} - - -fn last_error_code(conn: *mut ffi::sqlite3) -> libc::c_int { - unsafe { ffi::sqlite3_extended_errcode(conn) } -} -*/ - impl Drop for Statement { fn drop(&mut self) { let sqlite3 = crate::get_sqlite_unchecked(); @@ -162,6 +139,7 @@ impl Drop for Statement { // in that case we might not know if this errored or not // maybe depends how wasm panic/errors work // Worth unit testing the Drop implementation. + tracing::info!("Statement dropped & finalized!"); let _ = sqlite3 .finalize(&self.inner_statement) .expect("Error finalized SQLite prepared statement"); @@ -188,6 +166,7 @@ struct BoundStatement<'stmt> { #[allow(unused)] instrumentation: Arc>, has_error: bool, + drop_signal: Option>, } impl<'stmt> BoundStatement<'stmt> { @@ -196,11 +175,44 @@ impl<'stmt> BoundStatement<'stmt> { bind_collector: SqliteBindCollectorData, instrumentation: Arc>, ) -> QueryResult> { + match &statement { + MaybeCached::CannotCache(s) => { + tracing::debug!("BoundStatement::bind, NOT CACHED statement={:?}", s) + } + MaybeCached::Cached(s) => { + tracing::debug!( + "BoundStatement::bind, MaybeCached::Cached statement={:?}", + s + ) + } + &_ => todo!(), + } let SqliteBindCollectorData { binds } = bind_collector; + + let (tx, rx) = tokio::sync::oneshot::channel::(); + wasm_bindgen_futures::spawn_local(async move { + let result = (|| async move { + let inner_statement = rx.await?; + let this = Statement { inner_statement }; + this.reset().await?; + this.clear_bindings()?; + tracing::debug!("Bound statement dropped succesfully!"); + // we forget here because we need a clone that's sent to this task + // we don't want to `finalizing` this Statement yet (which is what + // dropping it would do); + std::mem::forget(this); + Ok::<_, WasmSqliteError>(()) + })(); + if let Err(e) = result.await { + tracing::error!("BoundStatement never dropped! {}", e); + } + }); + let mut ret = BoundStatement { statement, instrumentation, has_error: false, + drop_signal: Some(tx), }; ret.bind_buffers(binds)?; @@ -237,20 +249,17 @@ impl<'stmt> BoundStatement<'stmt> { // FIXME: [`AsyncDrop`](https://github.com/rust-lang/rust/issues/126482) is a missing feature in rust. // Until then we need to manually reset the statement object. - pub async fn reset(&mut self) { - self.statement.reset().await; - self.statement.clear_bindings() + pub async fn reset(&mut self) -> QueryResult<()> { + self.statement.reset().await?; + self.statement.clear_bindings()?; + Ok(()) } } // Eventually replace with `AsyncDrop`: https://github.com/rust-lang/rust/issues/126482 impl<'stmt> Drop for BoundStatement<'stmt> { fn drop(&mut self) { - let sender = self - .statement - .drop_signal - .take() - .expect("Drop may only be ran once"); + let sender = self.drop_signal.take().expect("Drop may only be ran once"); let _ = sender.send(self.statement.inner_statement.clone()); } } @@ -359,6 +368,7 @@ where { Some(sqlite3.column(&self.statement.statement.inner_statement, idx)) } } + /* #[cfg(test)] mod tests { diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 9b11e0c95..722b6e7b3 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -1,17 +1,5 @@ use wasm_bindgen::{prelude::*, JsValue}; -/* -/// Simple Connection -#[wasm_bindgen(module = "/src/package.js")] -extern "C" { - #[wasm_bindgen(catch)] - pub fn batch_execute(database: &JsValue, query: &str) -> Result<(), JsValue>; - - #[wasm_bindgen(catch)] - pub async fn establish(database_url: &str) -> Result; -} -*/ - /* once https://github.com/rust-lang/rust/issues/128183 is merged this would work pub mod consts { pub const SQLITE_INTEGER: i32 = super::SQLITE_INTEGER; @@ -44,7 +32,9 @@ unsafe impl Sync for SQLite {} #[wasm_bindgen(module = "/src/wa-sqlite-diesel-bundle.js")] extern "C" { pub type SQLite; + #[derive(Debug, Clone)] + #[wasm_bindgen(typescript_type = "SQLiteCompatibleType")] pub type SQLiteCompatibleType; // pub type SqlitePrepareOptions; @@ -167,6 +157,12 @@ extern "C" { #[wasm_bindgen(method)] pub fn changes(this: &SQLite, database: &JsValue) -> usize; + #[wasm_bindgen(method, catch)] + pub async fn get_stmt_from_iterator( + this: &SQLite, + iterator: &JsValue, + ) -> Result; + #[wasm_bindgen(method, catch)] pub async fn step(this: &SQLite, stmt: &JsValue) -> Result; @@ -194,7 +190,11 @@ extern "C" { pub fn column_count(this: &SQLite, stmt: &JsValue) -> i32; #[wasm_bindgen(method, catch)] - pub fn batch_execute(this: &SQLite, database: &JsValue, query: &str) -> Result<(), JsValue>; + pub async fn batch_execute( + this: &SQLite, + database: &JsValue, + query: &str, + ) -> Result<(), JsValue>; #[wasm_bindgen(method, catch)] pub fn create_function( diff --git a/diesel-wasm-sqlite/src/lib.rs b/diesel-wasm-sqlite/src/lib.rs index ffd6ad0f1..84e816935 100755 --- a/diesel-wasm-sqlite/src/lib.rs +++ b/diesel-wasm-sqlite/src/lib.rs @@ -5,6 +5,12 @@ pub mod ffi; pub mod query_builder; pub mod sqlite_types; pub mod utils; +pub mod sqlite_fixes; +// pub mod migrations; + +#[cfg(any(feature = "unsafe-debug-query", test))] +pub use query_builder::insert_with_default_sqlite::unsafe_debug_query::DebugQueryWrapper; + #[cfg(not(target_arch = "wasm32"))] compile_error!("This crate only suports the `wasm32-unknown-unknown` target"); @@ -12,9 +18,18 @@ compile_error!("This crate only suports the `wasm32-unknown-unknown` target"); use self::ffi::SQLite; use tokio::sync::OnceCell; use wasm_bindgen::JsValue; +use std::cell::LazyCell; pub use backend::{SqliteType, WasmSqlite}; +/// the local tokio current-thread runtime +/// dont need locking, because this is current-thread only +const RUNTIME: LazyCell = LazyCell::new(|| { + tokio::runtime::Builder::new_current_thread() + .build() + .expect("Runtime should never fail to build") +}); + /// The SQLite Library /// this global constant references the loaded SQLite WASM. static SQLITE: OnceCell = OnceCell::const_new(); @@ -34,26 +49,33 @@ pub(crate) fn get_sqlite_unchecked() -> &'static SQLite { SQLITE.get().expect("SQLite is not initialized") } -#[derive(Debug)] -pub struct WasmSqliteError(JsValue); +#[derive(thiserror::Error, Debug)] +pub enum WasmSqliteError { + #[error("JS Bridge Error {0:?}")] + Js(JsValue), + #[error(transparent)] + OneshotRecv(#[from] tokio::sync::oneshot::error::RecvError), + #[error(transparent)] + Diesel(#[from] diesel::result::Error) +} impl From for diesel::result::Error { fn from(value: WasmSqliteError) -> diesel::result::Error { - log::error!("NOT IMPLEMENTED, {:?}", value); + tracing::error!("NOT IMPLEMENTED, {:?}", value); diesel::result::Error::NotFound } } impl From for diesel::result::ConnectionError { fn from(value: WasmSqliteError) -> diesel::result::ConnectionError { - log::error!("NOT IMPLEMENTED, {:?}", value); - web_sys::console::log_1(&value.0); + tracing::error!("{:?}", value); diesel::result::ConnectionError::BadConnection("Not implemented".to_string()) } } impl From for WasmSqliteError { fn from(err: JsValue) -> WasmSqliteError { - WasmSqliteError(err) + WasmSqliteError::Js(err) } } + diff --git a/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs b/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs new file mode 100644 index 000000000..0d65f40bb --- /dev/null +++ b/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs @@ -0,0 +1,565 @@ +use crate::{connection::WasmSqliteConnection, WasmSqlite}; +use diesel::insertable::InsertValues; +use diesel::insertable::{CanInsertInSingleQuery, ColumnInsertValue, DefaultableColumnInsertValue}; +use diesel::query_builder::{AstPass, QueryId, ValuesClause}; +use diesel::query_builder::{BatchInsert, InsertStatement}; +use diesel::query_builder::QueryFragment; +use diesel::{QueryResult, QuerySource, Table}; +use diesel_async::scoped_futures::ScopedFutureExt; +use diesel_async::{methods::ExecuteDsl, AsyncConnection, RunQueryDsl}; + + +#[cfg(any(feature = "unsafe-debug-query", test))] +pub mod unsafe_debug_query { + use super::*; + use diesel::backend::Backend; + use diesel::{debug_query, query_builder::DebugQuery}; + use futures_util::future::LocalBoxFuture; + use std::fmt::{self, Debug, Display}; + + pub trait DebugQueryHelper { + fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; + fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; + } + + // FIXME: Here to temporarily workaround private fields of `DebugQuery`. + // this should never go in prod + // this is cause `DebugQuery` is private + #[repr(transparent)] + struct DebugQueryUnsafe<'a, T: 'a, DB> { + pub(crate) query: &'a T, + _marker: std::marker::PhantomData, + } + + impl<'a, T, V, QId, Op, Ret, const STATIC_QUERY_ID: bool> DebugQueryHelper + for DebugQuery< + 'a, + InsertStatement>, T, QId, STATIC_QUERY_ID>, Op, Ret>, + WasmSqlite, + > + where + V: QueryFragment, + T: Copy + QuerySource, + Op: Copy, + Ret: Copy, + for<'b> InsertStatement, Op, Ret>: QueryFragment, + { + fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let query = unsafe { + std::mem::transmute::< + &DebugQuery< + 'a, + InsertStatement< + T, + BatchInsert>, T, QId, STATIC_QUERY_ID>, + Op, + Ret, + >, + WasmSqlite, + >, + &DebugQueryUnsafe< + 'a, + InsertStatement< + T, + BatchInsert>, T, QId, STATIC_QUERY_ID>, + Op, + Ret, + >, + WasmSqlite, + >, + >(self) + }; + let query = query.query; + let mut statements = vec![String::from("BEGIN")]; + for record in query.records.values.iter() { + let stmt = InsertStatement::new(query.target, record, query.operator, query.returning); + statements.push(debug_query(&stmt).to_string()); + } + statements.push("COMMIT".into()); + f.debug_struct("Query") + .field("sql", &statements) + .field("binds", &[] as &[i32; 0]) + .finish() + } + + fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let query = unsafe { + std::mem::transmute::< + &DebugQuery< + 'a, + InsertStatement< + T, + BatchInsert>, T, QId, STATIC_QUERY_ID>, + Op, + Ret, + >, + WasmSqlite, + >, + &DebugQueryUnsafe< + 'a, + InsertStatement< + T, + BatchInsert>, T, QId, STATIC_QUERY_ID>, + Op, + Ret, + >, + WasmSqlite, + >, + >(self) + }; + let query = query.query; + writeln!(f, "BEGIN;")?; + for record in query.records.values.iter() { + let stmt = InsertStatement::new(query.target, record, query.operator, query.returning); + writeln!(f, "{}", debug_query(&stmt))?; + } + writeln!(f, "COMMIT;")?; + Ok(()) + } + } + + #[allow(unsafe_code)] // cast to transparent wrapper type + impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> DebugQueryHelper + for DebugQuery<'a, InsertStatement, Op>, WasmSqlite> + where + T: Copy + QuerySource, + Op: Copy, + DebugQuery< + 'a, + InsertStatement, Op>, + WasmSqlite, + >: Debug + Display, + { + fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let value = unsafe { + // This cast is safe as `SqliteBatchInsertWrapper` is #[repr(transparent)] + &*(self as *const DebugQuery< + 'a, + InsertStatement, Op>, + WasmSqlite, + > + as *const DebugQuery< + 'a, + InsertStatement, Op>, + WasmSqlite, + >) + }; + <_ as Debug>::fmt(value, f) + } + fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let value = unsafe { + // This cast is safe as `SqliteBatchInsertWrapper` is #[repr(transparent)] + &*(self as *const DebugQuery< + 'a, + InsertStatement, Op>, + WasmSqlite, + > + as *const DebugQuery< + 'a, + InsertStatement, Op>, + WasmSqlite, + >) + }; + <_ as Display>::fmt(value, f) + } + } + + pub struct DebugQueryWrapper<'a, T: 'a, DB>(DebugQuery<'a, T, DB>); + + + impl<'a, T, DB> DebugQueryWrapper<'a, T, DB> { + pub fn new(query: &'a T) -> Self { + DebugQueryWrapper(diesel::debug_query(query)) + } + } + + impl<'a, T, DB> Display for DebugQueryWrapper<'a, T, DB> + where + DB: Backend + Default, + DB::QueryBuilder: Default, + T: QueryFragment, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } + } + + impl<'a, T, DB> Debug for DebugQueryWrapper<'a, T, DB> + where + DB: Backend + Default, + DB::QueryBuilder: Default, + T: QueryFragment, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::Debug::fmt(&self.0, f) + } + } + + + + impl<'a, T, V, QId, Op, Ret, const STATIC_QUERY_ID: bool> DebugQueryHelper + for DebugQueryWrapper< + 'a, + InsertStatement>, T, QId, STATIC_QUERY_ID>, Op, Ret>, + WasmSqlite, + > + where + V: QueryFragment, + T: Copy + QuerySource, + Op: Copy, + Ret: Copy, + for<'b> InsertStatement, Op, Ret>: QueryFragment, + { + fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + DebugQueryHelper::fmt_debug(&self.0, f) + } + + fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + DebugQueryHelper::fmt_display(&self.0, f) + } + } + + impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> DebugQueryHelper + for DebugQueryWrapper<'a, InsertStatement, Op>, WasmSqlite> + where + T: Copy + QuerySource, + Op: Copy, + DebugQuery< + 'a, + InsertStatement, Op>, + WasmSqlite, + >: Debug + Display, + { + fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + DebugQueryHelper::fmt_debug(&self.0, f) + } + + fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + DebugQueryHelper::fmt_display(&self.0, f) + } + } + + + impl<'a, T, V, QId, Op, O, const STATIC_QUERY_ID: bool> Display + for DebugQueryWrapper< + 'a, + InsertStatement>, T, QId, STATIC_QUERY_ID>, Op>, + WasmSqlite, + > + where + T: QuerySource, + V: ContainsDefaultableValue, + Self: DebugQueryHelper, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt_display(f) + } + } + + + impl<'a, T, V, QId, Op, O, const STATIC_QUERY_ID: bool> Debug + for DebugQueryWrapper< + 'a, + InsertStatement>, T, QId, STATIC_QUERY_ID>, Op>, + WasmSqlite, + > + where + T: QuerySource, + V: ContainsDefaultableValue, + Self: DebugQueryHelper, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt_debug(f) + } + } +} + +#[allow(missing_debug_implementations, missing_copy_implementations)] +pub struct Yes; + +impl Default for Yes { + fn default() -> Self { + Yes + } +} + +#[allow(missing_debug_implementations, missing_copy_implementations)] +pub struct No; + +impl Default for No { + fn default() -> Self { + No + } +} + +pub trait Any { + type Out: Any + Any; +} + +impl Any for No { + type Out = No; +} + +impl Any for No { + type Out = Yes; +} + +impl Any for Yes { + type Out = Yes; +} + +impl Any for Yes { + type Out = Yes; +} + +pub trait ContainsDefaultableValue { + type Out: Any + Any; +} + +impl ContainsDefaultableValue for ColumnInsertValue { + type Out = No; +} + +impl ContainsDefaultableValue for DefaultableColumnInsertValue { + type Out = Yes; +} + +impl ContainsDefaultableValue for [I; SIZE] +where + I: ContainsDefaultableValue, +{ + type Out = I::Out; +} + +impl ContainsDefaultableValue for ValuesClause +where + I: ContainsDefaultableValue, +{ + type Out = I::Out; +} + +impl<'a, T> ContainsDefaultableValue for &'a T +where + T: ContainsDefaultableValue, +{ + type Out = T::Out; +} + +impl ExecuteDsl + for InsertStatement>, T, QId, STATIC_QUERY_ID>, Op> +where + T: QuerySource, + V: ContainsDefaultableValue, + O: Default, + (O, Self): ExecuteDsl, +{ + fn execute<'conn, 'query>( + query: Self, + conn: &'conn mut WasmSqliteConnection, + ) -> ::ExecuteFuture<'conn, 'query> { + <(O, Self) as ExecuteDsl>::execute( + (O::default(), query), + conn, + ) + } +} + +impl ExecuteDsl + for ( + Yes, + InsertStatement>, T, QId, STATIC_QUERY_ID>, Op>, + ) +where + for<'query> T: Table + Copy + QueryId + std::fmt::Debug + 'query, + T::FromClause: QueryFragment, + for<'query> Op: Copy + QueryId + QueryFragment + 'query + std::fmt::Debug, + for<'query> V: + InsertValues + CanInsertInSingleQuery + QueryId + std::fmt::Debug + 'query, + ::FromClause: std::fmt::Debug, + for<'query> QId: std::fmt::Debug + 'query +{ + fn execute<'conn, 'query>( + (Yes, query): Self, + conn: &'conn mut WasmSqliteConnection, + ) -> ::ExecuteFuture<'conn, 'query> + where + Self: 'query, + { + conn.transaction(move |conn| { + async move { + let mut result = 0; + // tracing::debug!("QUERY {:?}", query); + for record in &query.records.values { + // tracing::debug!("processing record {:?}", record); + let stmt = + InsertStatement::new(query.target, record, query.operator, query.returning); + // tracing::debug!("Processing statement {:?}", stmt); + result += stmt.execute(conn).await?; + } + Ok(result) + } + .scope_boxed_local() + }) + } +} + +#[allow(missing_debug_implementations, missing_copy_implementations)] +#[repr(transparent)] +pub struct SqliteBatchInsertWrapper( + BatchInsert, +); + +impl QueryFragment + for SqliteBatchInsertWrapper>, Tab, QId, STATIC_QUERY_ID> +where + ValuesClause: QueryFragment, + V: QueryFragment, +{ + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + if !STATIC_QUERY_ID { + out.unsafe_to_cache_prepared(); + } + + let mut values = self.0.values.iter(); + if let Some(value) = values.next() { + value.walk_ast(out.reborrow())?; + } + for value in values { + out.push_sql(", ("); + value.values.walk_ast(out.reborrow())?; + out.push_sql(")"); + } + Ok(()) + } +} + +#[allow(missing_copy_implementations, missing_debug_implementations)] +#[repr(transparent)] +pub struct SqliteCanInsertInSingleQueryHelper(T); + +impl CanInsertInSingleQuery + for SqliteBatchInsertWrapper>, T, QId, STATIC_QUERY_ID> +where + // We constrain that here on an internal helper type + // to make sure that this does not accidentally leak + // so that none does really implement normal batch + // insert for inserts with default values here + SqliteCanInsertInSingleQueryHelper: CanInsertInSingleQuery, +{ + fn rows_to_insert(&self) -> Option { + Some(self.0.values.len()) + } +} + +impl CanInsertInSingleQuery for SqliteCanInsertInSingleQueryHelper +where + T: CanInsertInSingleQuery, +{ + fn rows_to_insert(&self) -> Option { + self.0.rows_to_insert() + } +} + +impl QueryId + for SqliteBatchInsertWrapper +where + BatchInsert: QueryId, +{ + type QueryId = as QueryId>::QueryId; + + const HAS_STATIC_QUERY_ID: bool = + as QueryId>::HAS_STATIC_QUERY_ID; +} + +impl ExecuteDsl + for ( + No, + InsertStatement, Op>, + ) +where + for<'query> T: Table + QueryId + 'query, + T::FromClause: QueryFragment, + for<'query> Op: QueryFragment + QueryId + 'query, + for<'query> V: 'query, + for<'query> QId: 'query, + SqliteBatchInsertWrapper: + QueryFragment + QueryId + CanInsertInSingleQuery, +{ + fn execute<'conn, 'query>( + (No, query): Self, + conn: &'conn mut WasmSqliteConnection, + ) -> ::ExecuteFuture<'conn, 'query> { + let query = InsertStatement::new( + query.target, + SqliteBatchInsertWrapper(query.records), + query.operator, + query.returning, + ); + query.execute(conn) + } +} + +macro_rules! tuple_impls { + ($( + $Tuple:tt { + $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+ + } + )+) => { + $( + impl_contains_defaultable_value!($($T,)*); + )* + } + } + +macro_rules! impl_contains_defaultable_value { + ( + @build + start_ts = [$($ST: ident,)*], + ts = [$T1: ident,], + bounds = [$($bounds: tt)*], + out = [$($out: tt)*], + )=> { + impl<$($ST,)*> ContainsDefaultableValue for ($($ST,)*) + where + $($ST: ContainsDefaultableValue,)* + $($bounds)* + $T1::Out: Any<$($out)*>, + { + type Out = <$T1::Out as Any<$($out)*>>::Out; + } + + }; + ( + @build + start_ts = [$($ST: ident,)*], + ts = [$T1: ident, $($T: ident,)+], + bounds = [$($bounds: tt)*], + out = [$($out: tt)*], + )=> { + impl_contains_defaultable_value! { + @build + start_ts = [$($ST,)*], + ts = [$($T,)*], + bounds = [$($bounds)* $T1::Out: Any<$($out)*>,], + out = [<$T1::Out as Any<$($out)*>>::Out], + } + }; + ($T1: ident, $($T: ident,)+) => { + impl_contains_defaultable_value! { + @build + start_ts = [$T1, $($T,)*], + ts = [$($T,)*], + bounds = [], + out = [$T1::Out], + } + }; + ($T1: ident,) => { + impl<$T1> ContainsDefaultableValue for ($T1,) + where $T1: ContainsDefaultableValue, + { + type Out = <$T1 as ContainsDefaultableValue>::Out; + } + } +} + +diesel_derives::__diesel_for_each_tuple!(tuple_impls); diff --git a/diesel-wasm-sqlite/src/query_builder/mod.rs b/diesel-wasm-sqlite/src/query_builder/mod.rs index 3489876b8..bfeff776c 100644 --- a/diesel-wasm-sqlite/src/query_builder/mod.rs +++ b/diesel-wasm-sqlite/src/query_builder/mod.rs @@ -4,6 +4,7 @@ use super::backend::WasmSqlite; use diesel::query_builder::QueryBuilder; use diesel::result::QueryResult; +pub(super) mod insert_with_default_sqlite; mod limit_offset; mod query_fragment_impls; // mod returning; diff --git a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs index 4d840529e..d09773d6a 100644 --- a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs +++ b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs @@ -21,7 +21,6 @@ where } } -// #[cfg(feature = "sqlite")] impl<'a, ST, QS, GB> QueryFragment for OnConflictSelectWrapper> where diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs new file mode 100644 index 000000000..3a7afdc4c --- /dev/null +++ b/diesel-wasm-sqlite/src/sqlite_fixes.rs @@ -0,0 +1,64 @@ +use crate::WasmSqlite; +use diesel::{ + insertable::{ColumnInsertValue, DefaultableColumnInsertValue, InsertValues}, + query_builder::AstPass, + query_builder::NoFromClause, + query_builder::QueryFragment, + AppearsOnTable, Column, Expression, QueryResult, +}; + +impl InsertValues + for DefaultableColumnInsertValue> +where + Col: Column, + Expr: Expression + AppearsOnTable, + Self: QueryFragment, +{ + fn column_names(&self, mut out: AstPass<'_, '_, WasmSqlite>) -> QueryResult<()> { + if let Self::Expression(..) = *self { + out.push_identifier(Col::NAME)?; + } + Ok(()) + } +} + +impl + QueryFragment< + WasmSqlite, + diesel::backend::sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword, + > for DefaultableColumnInsertValue> +where + Expr: QueryFragment, +{ + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + if let Self::Expression(ref inner) = *self { + inner.walk_ast(out.reborrow())?; + } + Ok(()) + } +} +/* +mod parenthesis_wrapper { + use crate::WasmSqlite; + use diesel::helper_types::{Distinct, Except, Intersect, Union}; + use diesel::query_builder::ParenthesisWrapper; + use diesel::query_builder::{AstPass, QueryFragment}; + + impl> QueryFragment for ParenthesisWrapper { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + // SQLite does not support parenthesis around this clause + // we can emulate this by construct a fake outer + // SELECT * FROM (inner_query) statement + out.push_sql("SELECT * FROM ("); + self.0.walk_ast(out.reborrow())?; + out.push_sql(")"); + Ok(()) + } + } + + impl SupportsCombinationClause for WasmSqlite {} + impl SupportsCombinationClause for WasmSqlite {} + impl SupportsCombinationClause for WasmSqlite {} + impl SupportsCombinationClause for WasmSqlite {} +} +*/ diff --git a/diesel-wasm-sqlite/src/sqlite_types.rs b/diesel-wasm-sqlite/src/sqlite_types.rs index 1d2066976..3ddc74d96 100644 --- a/diesel-wasm-sqlite/src/sqlite_types.rs +++ b/diesel-wasm-sqlite/src/sqlite_types.rs @@ -3,6 +3,8 @@ use bitflags::bitflags; use diesel::sql_types::*; use serde::{Deserialize, Serialize}; +pub mod to_sql; + //TODO These Database Types are defined in the wasm file and should be imported. // this is easier for now because of quirks with converting from JsValue to integer within extern // "C" declaration. @@ -23,7 +25,7 @@ pub const SQLITE_NULL: i32 = 5; #[derive(Serialize, Deserialize, Default, Clone, Debug, Copy)] pub struct PrepareOptions { pub flags: Option, - pub unscoped: Option, + pub unscoped: Option, } macro_rules! impl_has_sql_type { diff --git a/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs b/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs new file mode 100644 index 000000000..911a35712 --- /dev/null +++ b/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs @@ -0,0 +1,171 @@ +// mod date_and_time; +// mod numeric; + +//TODO: CODE CAN BE SHARED (pretty muhch exactly the same) +use crate::connection::SqliteValue; +use crate::WasmSqlite; +use diesel::deserialize::{self, FromSql, Queryable}; +use diesel::query_builder::QueryId; +use diesel::serialize::{self, IsNull, Output, ToSql}; +use diesel::sql_types; +use diesel::sql_types::SqlType; + +/// The returned pointer is *only* valid for the lifetime to the argument of +/// `from_sql`. This impl is intended for uses where you want to write a new +/// impl in terms of `String`, but don't want to allocate. We have to return a +/// raw pointer instead of a reference with a lifetime due to the structure of +/// `FromSql` +/// FIXME: THIS IS probably problematic for wa-sqlite +/// because we allocate a string in `read_text`. So this function would +/// producea dangling pointer. +/// `*const` types are not unsafe to _create_ but are unsafe once dereferenced/used +impl FromSql for *const str { + fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + let text = value.read_text(); + let string = text.as_str(); + Ok(string as *const _) + } +} + +impl Queryable for *const str { + type Row = Self; + + fn build(row: Self::Row) -> deserialize::Result { + Ok(row) + } +} + +/// The returned pointer is *only* valid for the lifetime to the argument of +/// `from_sql`. This impl is intended for uses where you want to write a new +/// impl in terms of `Vec`, but don't want to allocate. We have to return a +/// raw pointer instead of a reference with a lifetime due to the structure of +/// `FromSql` +impl FromSql for *const [u8] { + fn from_sql(bytes: SqliteValue<'_, '_>) -> deserialize::Result { + let bytes = bytes.read_blob(); + let bytes = bytes.as_slice(); + Ok(bytes as *const _) + } +} + +impl Queryable for *const [u8] { + type Row = Self; + + fn build(row: Self::Row) -> deserialize::Result { + Ok(row) + } +} + +impl FromSql for i16 { + fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + Ok(value.read_integer() as i16) + } +} + +impl FromSql for i32 { + fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + Ok(value.read_integer()) + } +} + +impl FromSql for bool { + fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + Ok(value.read_integer() != 0) + } +} + +impl FromSql for i64 { + fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + Ok(value.read_long()) + } +} + +impl FromSql for f32 { + fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + Ok(value.read_double() as f32) + } +} + +impl FromSql for f64 { + fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + Ok(value.read_double()) + } +} + +impl ToSql for bool { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { + let int_value = if *self { &1 } else { &0 }; + >::to_sql(int_value, out) + } +} + +impl ToSql for str { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { + out.set_value(self); + Ok(IsNull::No) + } +} + +impl ToSql for [u8] { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { + out.set_value(self); + Ok(IsNull::No) + } +} + +impl ToSql for i16 { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { + out.set_value(*self as i32); + Ok(IsNull::No) + } +} + +impl ToSql for i32 { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { + out.set_value(*self); + Ok(IsNull::No) + } +} + +impl ToSql for i64 { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { + out.set_value(*self); + Ok(IsNull::No) + } +} + +impl ToSql for f32 { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { + out.set_value(*self as f64); + Ok(IsNull::No) + } +} + +impl ToSql for f64 { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { + out.set_value(*self); + Ok(IsNull::No) + } +} + +/// The SQLite timestamp with time zone type +/// +/// ### [`ToSql`] impls +/// +/// - [`chrono::NaiveDateTime`] with `feature = "chrono"` +/// - [`chrono::DateTime`] with `feature = "chrono"` +/// - [`time::PrimitiveDateTime`] with `feature = "time"` +/// - [`time::OffsetDateTime`] with `feature = "time"` +/// +/// ### [`FromSql`] impls +/// +/// - [`chrono::NaiveDateTime`] with `feature = "chrono"` +/// - [`chrono::DateTime`] with `feature = "chrono"` +/// - [`time::PrimitiveDateTime`] with `feature = "time"` +/// - [`time::OffsetDateTime`] with `feature = "time"` +/// +/// [`ToSql`]: crate::serialize::ToSql +/// [`FromSql`]: crate::deserialize::FromSql +#[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] +#[diesel(sqlite_type(name = "Text"))] +pub struct Timestamptz; diff --git a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js index 2e16221b9..9e49297e0 100644 --- a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js @@ -280,7 +280,7 @@ const SQLITE_PREPARE_NO_VTAB = 0x04; const MAX_INT64 = 0x7fffffffffffffffn; const MIN_INT64 = -0x8000000000000000n; -const AsyncFunction$1 = Object.getPrototypeOf(async function(){}).constructor; +const AsyncFunction$1 = Object.getPrototypeOf(async function () {}).constructor; class SQLiteError extends Error { constructor(message, code) { @@ -311,7 +311,7 @@ function Factory(Module) { // Convert a JS string to a C string. sqlite3_malloc is used to allocate // memory (use sqlite3_free to deallocate). function createUTF8(s) { - if (typeof s !== 'string') return 0; + if (typeof s !== "string") return 0; const utf8 = new TextEncoder().encode(s); const zts = Module._sqlite3_malloc(utf8.byteLength + 1); Module.HEAPU8.set(utf8, zts); @@ -332,15 +332,15 @@ function Factory(Module) { /** * Concatenate 32-bit numbers and return as number or BigInt, depending * on the value. - * @param {number} lo32 - * @param {number} hi32 + * @param {number} lo32 + * @param {number} hi32 * @returns {number|bigint} */ - const cvt32x2AsSafe = (function() { + const cvt32x2AsSafe = (function () { const hiMax = BigInt(Number.MAX_SAFE_INTEGER) >> 32n; const hiMin = BigInt(Number.MIN_SAFE_INTEGER) >> 32n; - return function(lo32, hi32) { + return function (lo32, hi32) { if (hi32 > hiMax || hi32 < hiMin) { // Can't be expressed as a Number so use BigInt. return cvt32x2ToBigInt(lo32, hi32); @@ -350,24 +350,24 @@ function Factory(Module) { // a little tricky - the sign bit gets handled separately. return (hi32 * 0x100000000) + (lo32 & 0x7fffffff) - (lo32 & 0x80000000); } - } + }; })(); const databases = new Set(); function verifyDatabase(db) { if (!databases.has(db)) { - throw new SQLiteError('not a database', SQLITE_MISUSE); + throw new SQLiteError("not a database", SQLITE_MISUSE); } } const mapStmtToDB = new Map(); function verifyStatement(stmt) { if (!mapStmtToDB.has(stmt)) { - throw new SQLiteError('not a statement', SQLITE_MISUSE); + throw new SQLiteError("not a statement", SQLITE_MISUSE); } } - sqlite3.bind_collection = function(stmt, bindings) { + sqlite3.bind_collection = function (stmt, bindings) { verifyStatement(stmt); const isArray = Array.isArray(bindings); const nBindings = sqlite3.bind_parameter_count(stmt); @@ -381,38 +381,38 @@ function Factory(Module) { return SQLITE_OK; }; - sqlite3.bind = function(stmt, i, value) { + sqlite3.bind = function (stmt, i, value) { verifyStatement(stmt); switch (typeof value) { - case 'number': + case "number": if (value === (value | 0)) { return sqlite3.bind_int(stmt, i, value); } else { return sqlite3.bind_double(stmt, i, value); } - case 'string': + case "string": return sqlite3.bind_text(stmt, i, value); default: if (value instanceof Uint8Array || Array.isArray(value)) { return sqlite3.bind_blob(stmt, i, value); } else if (value === null) { return sqlite3.bind_null(stmt, i); - } else if (typeof value === 'bigint') { + } else if (typeof value === "bigint") { return sqlite3.bind_int64(stmt, i, value); } else if (value === undefined) { // Existing binding (or NULL) will be used. return SQLITE_NOTICE; } else { - console.warn('unknown binding converted to null', value); + console.warn("unknown binding converted to null", value); return sqlite3.bind_null(stmt, i); } } }; - sqlite3.bind_blob = (function() { - const fname = 'sqlite3_bind_blob'; - const f = Module.cwrap(fname, ...decl('nnnnn:n')); - return function(stmt, i, value) { + sqlite3.bind_blob = (function () { + const fname = "sqlite3_bind_blob"; + const f = Module.cwrap(fname, ...decl("nnnnn:n")); + return function (stmt, i, value) { verifyStatement(stmt); // @ts-ignore const byteLength = value.byteLength ?? value.length; @@ -423,30 +423,30 @@ function Factory(Module) { }; })(); - sqlite3.bind_parameter_count = (function() { - const fname = 'sqlite3_bind_parameter_count'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(stmt) { + sqlite3.bind_parameter_count = (function () { + const fname = "sqlite3_bind_parameter_count"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (stmt) { verifyStatement(stmt); const result = f(stmt); return result; }; })(); - sqlite3.bind_double = (function() { - const fname = 'sqlite3_bind_double'; - const f = Module.cwrap(fname, ...decl('nnn:n')); - return function(stmt, i, value) { + sqlite3.bind_double = (function () { + const fname = "sqlite3_bind_double"; + const f = Module.cwrap(fname, ...decl("nnn:n")); + return function (stmt, i, value) { verifyStatement(stmt); const result = f(stmt, i, value); return check(fname, result, mapStmtToDB.get(stmt)); }; })(); - sqlite3.bind_int = (function() { - const fname = 'sqlite3_bind_int'; - const f = Module.cwrap(fname, ...decl('nnn:n')); - return function(stmt, i, value) { + sqlite3.bind_int = (function () { + const fname = "sqlite3_bind_int"; + const f = Module.cwrap(fname, ...decl("nnn:n")); + return function (stmt, i, value) { verifyStatement(stmt); if (value > 0x7fffffff || value < -0x80000000) return SQLITE_RANGE; @@ -455,10 +455,10 @@ function Factory(Module) { }; })(); - sqlite3.bind_int64 = (function() { - const fname = 'sqlite3_bind_int64'; - const f = Module.cwrap(fname, ...decl('nnnn:n')); - return function(stmt, i, value) { + sqlite3.bind_int64 = (function () { + const fname = "sqlite3_bind_int64"; + const f = Module.cwrap(fname, ...decl("nnnn:n")); + return function (stmt, i, value) { verifyStatement(stmt); if (value > MAX_INT64 || value < MIN_INT64) return SQLITE_RANGE; @@ -469,30 +469,30 @@ function Factory(Module) { }; })(); - sqlite3.bind_null = (function() { - const fname = 'sqlite3_bind_null'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(stmt, i) { + sqlite3.bind_null = (function () { + const fname = "sqlite3_bind_null"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (stmt, i) { verifyStatement(stmt); const result = f(stmt, i); return check(fname, result, mapStmtToDB.get(stmt)); }; })(); - sqlite3.bind_parameter_name = (function() { - const fname = 'sqlite3_bind_parameter_name'; - const f = Module.cwrap(fname, ...decl('n:s')); - return function(stmt, i) { + sqlite3.bind_parameter_name = (function () { + const fname = "sqlite3_bind_parameter_name"; + const f = Module.cwrap(fname, ...decl("n:s")); + return function (stmt, i) { verifyStatement(stmt); const result = f(stmt, i); return result; }; })(); - sqlite3.bind_text = (function() { - const fname = 'sqlite3_bind_text'; - const f = Module.cwrap(fname, ...decl('nnnnn:n')); - return function(stmt, i, value) { + sqlite3.bind_text = (function () { + const fname = "sqlite3_bind_text"; + const f = Module.cwrap(fname, ...decl("nnnnn:n")); + return function (stmt, i, value) { verifyStatement(stmt); const ptr = createUTF8(value); const result = f(stmt, i, ptr, -1, sqliteFreeAddress); @@ -500,20 +500,30 @@ function Factory(Module) { }; })(); - sqlite3.changes = (function() { - const fname = 'sqlite3_changes'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(db) { + sqlite3.changes = (function () { + const fname = "sqlite3_changes"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (db) { verifyDatabase(db); const result = f(db); return result; }; })(); - sqlite3.close = (function() { - const fname = 'sqlite3_close'; - const f = Module.cwrap(fname, ...decl('n:n'), { async }); - return async function(db) { + sqlite3.clear_bindings = (function () { + const fname = "sqlite3_clear_bindings"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (stmt) { + verifyStatement(stmt); + const result = f(stmt); + return check(fname, result, mapStmtToDB.get(stmt)); + }; + })(); + + sqlite3.close = (function () { + const fname = "sqlite3_close"; + const f = Module.cwrap(fname, ...decl("n:n"), { async }); + return async function (db) { verifyDatabase(db); const result = await f(db); databases.delete(db); @@ -521,7 +531,7 @@ function Factory(Module) { }; })(); - sqlite3.column = function(stmt, iCol) { + sqlite3.column = function (stmt, iCol) { verifyStatement(stmt); const type = sqlite3.column_type(stmt, iCol); switch (type) { @@ -538,14 +548,14 @@ function Factory(Module) { case SQLITE_TEXT: return sqlite3.column_text(stmt, iCol); default: - throw new SQLiteError('unknown type', type); + throw new SQLiteError("unknown type", type); } }; - sqlite3.column_blob = (function() { - const fname = 'sqlite3_column_blob'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(stmt, iCol) { + sqlite3.column_blob = (function () { + const fname = "sqlite3_column_blob"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (stmt, iCol) { verifyStatement(stmt); const nBytes = sqlite3.column_bytes(stmt, iCol); const address = f(stmt, iCol); @@ -554,52 +564,52 @@ function Factory(Module) { }; })(); - sqlite3.column_bytes = (function() { - const fname = 'sqlite3_column_bytes'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(stmt, iCol) { + sqlite3.column_bytes = (function () { + const fname = "sqlite3_column_bytes"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (stmt, iCol) { verifyStatement(stmt); const result = f(stmt, iCol); return result; }; })(); - sqlite3.column_count = (function() { - const fname = 'sqlite3_column_count'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(stmt) { + sqlite3.column_count = (function () { + const fname = "sqlite3_column_count"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (stmt) { verifyStatement(stmt); const result = f(stmt); return result; }; })(); - sqlite3.column_double = (function() { - const fname = 'sqlite3_column_double'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(stmt, iCol) { + sqlite3.column_double = (function () { + const fname = "sqlite3_column_double"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (stmt, iCol) { verifyStatement(stmt); const result = f(stmt, iCol); return result; }; })(); - sqlite3.column_int = (function() { + sqlite3.column_int = (function () { // Retrieve int64 but use only the lower 32 bits. The upper 32-bits are // accessible with Module.getTempRet0(). - const fname = 'sqlite3_column_int64'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(stmt, iCol) { + const fname = "sqlite3_column_int64"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (stmt, iCol) { verifyStatement(stmt); const result = f(stmt, iCol); return result; }; })(); - sqlite3.column_int64 = (function() { - const fname = 'sqlite3_column_int64'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(stmt, iCol) { + sqlite3.column_int64 = (function () { + const fname = "sqlite3_column_int64"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (stmt, iCol) { verifyStatement(stmt); const lo32 = f(stmt, iCol); const hi32 = Module.getTempRet0(); @@ -608,17 +618,17 @@ function Factory(Module) { }; })(); - sqlite3.column_name = (function() { - const fname = 'sqlite3_column_name'; - const f = Module.cwrap(fname, ...decl('nn:s')); - return function(stmt, iCol) { + sqlite3.column_name = (function () { + const fname = "sqlite3_column_name"; + const f = Module.cwrap(fname, ...decl("nn:s")); + return function (stmt, iCol) { verifyStatement(stmt); const result = f(stmt, iCol); return result; }; })(); - sqlite3.column_names = function(stmt) { + sqlite3.column_names = function (stmt) { const columns = []; const nColumns = sqlite3.column_count(stmt); for (let i = 0; i < nColumns; ++i) { @@ -627,34 +637,45 @@ function Factory(Module) { return columns; }; - sqlite3.column_text = (function() { - const fname = 'sqlite3_column_text'; - const f = Module.cwrap(fname, ...decl('nn:s')); - return function(stmt, iCol) { + sqlite3.column_text = (function () { + const fname = "sqlite3_column_text"; + const f = Module.cwrap(fname, ...decl("nn:s")); + return function (stmt, iCol) { verifyStatement(stmt); const result = f(stmt, iCol); return result; }; })(); - sqlite3.column_type = (function() { - const fname = 'sqlite3_column_type'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(stmt, iCol) { + sqlite3.column_type = (function () { + const fname = "sqlite3_column_type"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (stmt, iCol) { verifyStatement(stmt); const result = f(stmt, iCol); return result; }; })(); - sqlite3.create_function = function(db, zFunctionName, nArg, eTextRep, pApp, xFunc, xStep, xFinal) { + sqlite3.create_function = function ( + db, + zFunctionName, + nArg, + eTextRep, + pApp, + xFunc, + xStep, + xFinal, + ) { verifyDatabase(db); - + // Convert SQLite callback arguments to JavaScript-friendly arguments. function adapt(f) { - return f instanceof AsyncFunction$1 ? - (async (ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))) : - ((ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))); + return f instanceof AsyncFunction$1 + ? (async (ctx, n, values) => + f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))) + : ((ctx, n, values) => + f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))); } const result = Module.create_function( @@ -665,21 +686,22 @@ function Factory(Module) { pApp, xFunc && adapt(xFunc), xStep && adapt(xStep), - xFinal); - return check('sqlite3_create_function', result, db); + xFinal, + ); + return check("sqlite3_create_function", result, db); }; - sqlite3.data_count = (function() { - const fname = 'sqlite3_data_count'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(stmt) { + sqlite3.data_count = (function () { + const fname = "sqlite3_data_count"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (stmt) { verifyStatement(stmt); const result = f(stmt); return result; }; })(); - sqlite3.exec = async function(db, sql, callback) { + sqlite3.exec = async function (db, sql, callback) { for await (const stmt of sqlite3.statements(db, sql)) { let columns; while (await sqlite3.step(stmt) === SQLITE_ROW) { @@ -693,10 +715,10 @@ function Factory(Module) { return SQLITE_OK; }; - sqlite3.finalize = (function() { - const fname = 'sqlite3_finalize'; - const f = Module.cwrap(fname, ...decl('n:n'), { async }); - return async function(stmt) { + sqlite3.finalize = (function () { + const fname = "sqlite3_finalize"; + const f = Module.cwrap(fname, ...decl("n:n"), { async }); + return async function (stmt) { const result = await f(stmt); mapStmtToDB.delete(stmt); @@ -706,56 +728,56 @@ function Factory(Module) { }; })(); - sqlite3.get_autocommit = (function() { - const fname = 'sqlite3_get_autocommit'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(db) { + sqlite3.get_autocommit = (function () { + const fname = "sqlite3_get_autocommit"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (db) { const result = f(db); return result; }; })(); - sqlite3.libversion = (function() { - const fname = 'sqlite3_libversion'; - const f = Module.cwrap(fname, ...decl(':s')); - return function() { + sqlite3.libversion = (function () { + const fname = "sqlite3_libversion"; + const f = Module.cwrap(fname, ...decl(":s")); + return function () { const result = f(); return result; }; })(); - sqlite3.libversion_number = (function() { - const fname = 'sqlite3_libversion_number'; - const f = Module.cwrap(fname, ...decl(':n')); - return function() { + sqlite3.libversion_number = (function () { + const fname = "sqlite3_libversion_number"; + const f = Module.cwrap(fname, ...decl(":n")); + return function () { const result = f(); return result; }; })(); - sqlite3.limit = (function() { - const fname = 'sqlite3_limit'; - const f = Module.cwrap(fname, ...decl('nnn:n')); - return function(db, id, newVal) { + sqlite3.limit = (function () { + const fname = "sqlite3_limit"; + const f = Module.cwrap(fname, ...decl("nnn:n")); + return function (db, id, newVal) { const result = f(db, id, newVal); return result; }; })(); - sqlite3.open_v2 = (function() { - const fname = 'sqlite3_open_v2'; - const f = Module.cwrap(fname, ...decl('snnn:n'), { async }); - return async function(zFilename, flags, zVfs) { + sqlite3.open_v2 = (function () { + const fname = "sqlite3_open_v2"; + const f = Module.cwrap(fname, ...decl("snnn:n"), { async }); + return async function (zFilename, flags, zVfs) { flags = flags || SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE; zVfs = createUTF8(zVfs); try { // Allow retry operations. const rc = await retry(() => f(zFilename, tmpPtr[0], flags, zVfs)); - const db = Module.getValue(tmpPtr[0], '*'); + const db = Module.getValue(tmpPtr[0], "*"); databases.add(db); - Module.ccall('RegisterExtensionFunctions', 'void', ['number'], [db]); + Module.ccall("RegisterExtensionFunctions", "void", ["number"], [db]); check(fname, rc); return db; } finally { @@ -764,30 +786,31 @@ function Factory(Module) { }; })(); - sqlite3.progress_handler = function(db, nProgressOps, handler, userData) { + sqlite3.progress_handler = function (db, nProgressOps, handler, userData) { verifyDatabase(db); Module.progress_handler(db, nProgressOps, handler, userData); }; - sqlite3.reset = (function() { - const fname = 'sqlite3_reset'; - const f = Module.cwrap(fname, ...decl('n:n'), { async }); - return async function(stmt) { + + sqlite3.reset = (function () { + const fname = "sqlite3_reset"; + const f = Module.cwrap(fname, ...decl("n:n"), { async }); + return async function (stmt) { verifyStatement(stmt); const result = await f(stmt); return check(fname, result, mapStmtToDB.get(stmt)); }; })(); - sqlite3.result = function(context, value) { + sqlite3.result = function (context, value) { switch (typeof value) { - case 'number': + case "number": if (value === (value | 0)) { sqlite3.result_int(context, value); } else { sqlite3.result_double(context, value); } break; - case 'string': + case "string": sqlite3.result_text(context, value); break; default: @@ -795,21 +818,20 @@ function Factory(Module) { sqlite3.result_blob(context, value); } else if (value === null) { sqlite3.result_null(context); - } else if (typeof value === 'bigint') { + } else if (typeof value === "bigint") { return sqlite3.result_int64(context, value); } else { - console.warn('unknown result converted to null', value); + console.warn("unknown result converted to null", value); sqlite3.result_null(context); } break; } - }; - sqlite3.result_blob = (function() { - const fname = 'sqlite3_result_blob'; - const f = Module.cwrap(fname, ...decl('nnnn:n')); - return function(context, value) { + sqlite3.result_blob = (function () { + const fname = "sqlite3_result_blob"; + const f = Module.cwrap(fname, ...decl("nnnn:n")); + return function (context, value) { // @ts-ignore const byteLength = value.byteLength ?? value.length; const ptr = Module._sqlite3_malloc(byteLength); @@ -818,26 +840,26 @@ function Factory(Module) { }; })(); - sqlite3.result_double = (function() { - const fname = 'sqlite3_result_double'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(context, value) { + sqlite3.result_double = (function () { + const fname = "sqlite3_result_double"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (context, value) { f(context, value); // void return }; })(); - sqlite3.result_int = (function() { - const fname = 'sqlite3_result_int'; - const f = Module.cwrap(fname, ...decl('nn:n')); - return function(context, value) { + sqlite3.result_int = (function () { + const fname = "sqlite3_result_int"; + const f = Module.cwrap(fname, ...decl("nn:n")); + return function (context, value) { f(context, value); // void return }; })(); - sqlite3.result_int64 = (function() { - const fname = 'sqlite3_result_int64'; - const f = Module.cwrap(fname, ...decl('nnn:n')); - return function(context, value) { + sqlite3.result_int64 = (function () { + const fname = "sqlite3_result_int64"; + const f = Module.cwrap(fname, ...decl("nnn:n")); + return function (context, value) { if (value > MAX_INT64 || value < MIN_INT64) return SQLITE_RANGE; const lo32 = value & 0xffffffffn; @@ -846,24 +868,24 @@ function Factory(Module) { }; })(); - sqlite3.result_null = (function() { - const fname = 'sqlite3_result_null'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(context) { + sqlite3.result_null = (function () { + const fname = "sqlite3_result_null"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (context) { f(context); // void return }; })(); - sqlite3.result_text = (function() { - const fname = 'sqlite3_result_text'; - const f = Module.cwrap(fname, ...decl('nnnn:n')); - return function(context, value) { + sqlite3.result_text = (function () { + const fname = "sqlite3_result_text"; + const f = Module.cwrap(fname, ...decl("nnnn:n")); + return function (context, value) { const ptr = createUTF8(value); f(context, ptr, -1, sqliteFreeAddress); // void return }; })(); - sqlite3.row = function(stmt) { + sqlite3.row = function (stmt) { const row = []; const nColumns = sqlite3.data_count(stmt); for (let i = 0; i < nColumns; ++i) { @@ -877,7 +899,7 @@ function Factory(Module) { return row; }; - sqlite3.set_authorizer = function(db, xAuth, pApp) { + sqlite3.set_authorizer = function (db, xAuth, pApp) { verifyDatabase(db); // Convert SQLite callback arguments to JavaScript-friendly arguments. @@ -888,35 +910,40 @@ function Factory(Module) { Module.UTF8ToString(p3), Module.UTF8ToString(p4), Module.UTF8ToString(p5), - Module.UTF8ToString(p6) + Module.UTF8ToString(p6), ]; - } function adapt(f) { - return f instanceof AsyncFunction$1 ? - (async (_, iAction, p3, p4, p5, p6) => f(cvtArgs(_, iAction, p3, p4, p5, p6))) : - ((_, iAction, p3, p4, p5, p6) => f(cvtArgs(_, iAction, p3, p4, p5, p6))); + } + function adapt(f) { + return f instanceof AsyncFunction$1 + ? (async (_, iAction, p3, p4, p5, p6) => + f(cvtArgs(_, iAction, p3, p4, p5, p6))) + : ((_, iAction, p3, p4, p5, p6) => + f(cvtArgs(_, iAction, p3, p4, p5, p6))); } const result = Module.set_authorizer(db, adapt(xAuth), pApp); - return check('sqlite3_set_authorizer', result, db); - }; - sqlite3.sql = (function() { - const fname = 'sqlite3_sql'; - const f = Module.cwrap(fname, ...decl('n:s')); - return function(stmt) { + return check("sqlite3_set_authorizer", result, db); + }; + + sqlite3.sql = (function () { + const fname = "sqlite3_sql"; + const f = Module.cwrap(fname, ...decl("n:s")); + return function (stmt) { verifyStatement(stmt); const result = f(stmt); return result; }; })(); - sqlite3.statements = function(db, sql, options = {}) { + sqlite3.statements = function (db, sql, options = {}) { const prepare = Module.cwrap( - 'sqlite3_prepare_v3', - 'number', - ['number', 'number', 'number', 'number', 'number', 'number'], - { async: true }); + "sqlite3_prepare_v3", + "number", + ["number", "number", "number", "number", "number", "number"], + { async: true }, + ); - return (async function*() { + return (async function* () { const onFinally = []; try { // Encode SQL string to UTF-8. @@ -931,7 +958,7 @@ function Factory(Module) { onFinally.push(() => Module._sqlite3_free(pzHead)); Module.HEAPU8.set(utf8, pzHead); Module.HEAPU8[pzEnd - 1] = 0; - + // Use extra space for the statement handle and SQL tail pointer. const pStmt = pzHead + allocSize - 8; const pzTail = pzHead + allocSize - 4; @@ -945,16 +972,16 @@ function Factory(Module) { stmt = 0; } onFinally.push(maybeFinalize); - + // Loop over statements. - Module.setValue(pzTail, pzHead, '*'); + Module.setValue(pzTail, pzHead, "*"); do { // Reclaim resources for the previous iteration. maybeFinalize(); // Call sqlite3_prepare_v3() for the next statement. // Allow retry operations. - const zTail = Module.getValue(pzTail, '*'); + const zTail = Module.getValue(pzTail, "*"); const rc = await retry(() => { return prepare( db, @@ -962,14 +989,15 @@ function Factory(Module) { pzEnd - pzTail, options.flags || 0, pStmt, - pzTail); + pzTail, + ); }); if (rc !== SQLITE_OK) { - check('sqlite3_prepare_v3', rc, db); + check("sqlite3_prepare_v3", rc, db); } - - stmt = Module.getValue(pStmt, '*'); + + stmt = Module.getValue(pStmt, "*"); if (stmt) { mapStmtToDB.set(stmt, db); yield stmt; @@ -983,20 +1011,23 @@ function Factory(Module) { })(); }; - sqlite3.step = (function() { - const fname = 'sqlite3_step'; - const f = Module.cwrap(fname, ...decl('n:n'), { async }); - return async function(stmt) { + sqlite3.step = (function () { + const fname = "sqlite3_step"; + const f = Module.cwrap(fname, ...decl("n:n"), { async }); + return async function (stmt) { verifyStatement(stmt); // Allow retry operations. const rc = await retry(() => f(stmt)); - return check(fname, rc, mapStmtToDB.get(stmt), [SQLITE_ROW, SQLITE_DONE]); + return check(fname, rc, mapStmtToDB.get(stmt), [ + SQLITE_ROW, + SQLITE_DONE, + ]); }; })(); - sqlite3.value = function(pValue) { + sqlite3.value = function (pValue) { const type = sqlite3.value_type(pValue); switch (type) { case SQLITE_BLOB: @@ -1012,14 +1043,14 @@ function Factory(Module) { case SQLITE_TEXT: return sqlite3.value_text(pValue); default: - throw new SQLiteError('unknown type', type); + throw new SQLiteError("unknown type", type); } }; - sqlite3.value_blob = (function() { - const fname = 'sqlite3_value_blob'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(pValue) { + sqlite3.value_blob = (function () { + const fname = "sqlite3_value_blob"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (pValue) { const nBytes = sqlite3.value_bytes(pValue); const address = f(pValue); const result = Module.HEAPU8.subarray(address, address + nBytes); @@ -1027,37 +1058,37 @@ function Factory(Module) { }; })(); - sqlite3.value_bytes = (function() { - const fname = 'sqlite3_value_bytes'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(pValue) { + sqlite3.value_bytes = (function () { + const fname = "sqlite3_value_bytes"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (pValue) { const result = f(pValue); return result; }; })(); - sqlite3.value_double = (function() { - const fname = 'sqlite3_value_double'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(pValue) { + sqlite3.value_double = (function () { + const fname = "sqlite3_value_double"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (pValue) { const result = f(pValue); return result; }; })(); - sqlite3.value_int = (function() { - const fname = 'sqlite3_value_int64'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(pValue) { + sqlite3.value_int = (function () { + const fname = "sqlite3_value_int64"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (pValue) { const result = f(pValue); return result; }; })(); - sqlite3.value_int64 = (function() { - const fname = 'sqlite3_value_int64'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(pValue) { + sqlite3.value_int64 = (function () { + const fname = "sqlite3_value_int64"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (pValue) { const lo32 = f(pValue); const hi32 = Module.getTempRet0(); const result = cvt32x2ToBigInt(lo32, hi32); @@ -1065,34 +1096,34 @@ function Factory(Module) { }; })(); - sqlite3.value_text = (function() { - const fname = 'sqlite3_value_text'; - const f = Module.cwrap(fname, ...decl('n:s')); - return function(pValue) { + sqlite3.value_text = (function () { + const fname = "sqlite3_value_text"; + const f = Module.cwrap(fname, ...decl("n:s")); + return function (pValue) { const result = f(pValue); return result; }; })(); - sqlite3.value_type = (function() { - const fname = 'sqlite3_value_type'; - const f = Module.cwrap(fname, ...decl('n:n')); - return function(pValue) { + sqlite3.value_type = (function () { + const fname = "sqlite3_value_type"; + const f = Module.cwrap(fname, ...decl("n:n")); + return function (pValue) { const result = f(pValue); return result; }; })(); - sqlite3.vfs_register = function(vfs, makeDefault) { + sqlite3.vfs_register = function (vfs, makeDefault) { const result = Module.vfs_register(vfs, makeDefault); - return check('sqlite3_vfs_register', result); + return check("sqlite3_vfs_register", result); }; function check(fname, result, db = null, allowed = [SQLITE_OK]) { if (allowed.includes(result)) return result; - const message = db ? - Module.ccall('sqlite3_errmsg', 'string', ['number'], [db]) : - fname; + const message = db + ? Module.ccall("sqlite3_errmsg", "string", ["number"], [db]) + : fname; throw new SQLiteError(message, result); } @@ -1108,7 +1139,7 @@ function Factory(Module) { await Promise.all(Module.retryOps); Module.retryOps = []; } - + rc = await f(); // Retry on failure with new pending retry operations. @@ -1124,16 +1155,26 @@ function decl(s) { const result = []; const m = s.match(/([ns@]*):([nsv@])/); switch (m[2]) { - case 'n': result.push('number'); break; - case 's': result.push('string'); break; - case 'v': result.push(null); break; + case "n": + result.push("number"); + break; + case "s": + result.push("string"); + break; + case "v": + result.push(null); + break; } const args = []; for (let c of m[1]) { switch (c) { - case 'n': args.push('number'); break; - case 's': args.push('string'); break; + case "n": + args.push("number"); + break; + case "s": + args.push("string"); + break; } } result.push(args); @@ -2686,21 +2727,21 @@ function extractString(dataView, offset) { } var Module = (() => { - var _scriptName = import.meta.url; + var _scriptDir = import.meta.url; return ( function(moduleArg = {}) { - var moduleRtn; -var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject;});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var moduleOverrides=Object.assign({},Module);var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href;}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src;}if(_scriptName){scriptDirectory=_scriptName;}if(scriptDirectory.startsWith("blob:")){scriptDirectory="";}else {scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1);}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)};}readAsync=url=>fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))});}}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift());}}callRuntimeCallbacks(__ATPRERUN__);}function initRuntime(){if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;callRuntimeCallbacks(__ATINIT__);}function preMain(){callRuntimeCallbacks(__ATMAIN__);}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift());}}callRuntimeCallbacks(__ATPOSTRUN__);}function addOnPreRun(cb){__ATPRERUN__.unshift(cb);}function addOnInit(cb){__ATINIT__.unshift(cb);}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb);}var runDependencies=0;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies);}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback();}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);function findWasmBinary(){if(Module["locateFile"]){var f="wa-sqlite.wasm";if(!isDataURI(f)){return locateFile(f)}return f}return new URL("wa-sqlite.wasm",import.meta.url).href}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw "both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason);})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return {a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["ja"];updateMemoryViews();wasmTable=wasmExports["af"];addOnInit(wasmExports["ka"]);removeRunDependency();return wasmExports}addRunDependency();function receiveInstantiationResult(result){receiveInstance(result["instance"]);}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e);}}if(!wasmBinaryFile)wasmBinaryFile=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return {}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status;}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module);}};function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`);}}var noExitRuntime=Module["noExitRuntime"]||true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`);}}var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023);}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var ___assert_fail=(condition,filename,line,func)=>{abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"]);};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1);}else if(last===".."){parts.splice(i,1);up++;}else if(up){parts.splice(i,1);up--;}}if(allowAboveRoot){for(;up;up--){parts.unshift("..");}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path=".";}if(path&&trailingSlash){path+="/";}return (isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return "."}if(dir){dir=dir.substr(0,dir.length-1);}return root+dir},basename:path=>{if(path==="/")return "/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else abort("initRandomDevice");};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return ""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path);}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return (resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return [];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i;}else {len+=3;}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023;}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u;}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63;}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;}else {if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n";}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true);}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops);},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false;},close(stream){stream.tty.ops.fsync(stream.tty);},fsync(stream){stream.tty.ops.fsync(stream.tty);},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[];}},ioctl_tcgets(tty){return {c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return [24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[];}else {if(val!=0)tty.output.push(val);}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[];}}}};var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={};}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null;}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream;}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream;}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp;}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;}else {var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)));}node.usedBytes=newSize;}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096;}else if(FS.isFile(node.mode)){attr.size=node.usedBytes;}else if(FS.isLink(node.mode)){attr.size=node.link.length;}else {attr.size=0;}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode;}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp;}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size);}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name);}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now();},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now();},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key);}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset);}else {for(var i=0;i0||position+length{var dep=getUniqueRunDependency(`al ${url}`);readAsync(url).then(arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency();},err=>{if(onerror){onerror();}else {throw `Loading data file "${url}" failed.`}});if(dep)addRunDependency();};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn);};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true;}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn);}onload?.();removeRunDependency();}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency();})){return}finish(byteArray);}addRunDependency();if(typeof url=="string"){asyncLoad(url,processData,onerror);}else {processData(url);}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{constructor(errno){this.name="ErrnoError";this.errno=errno;}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={};}get object(){return this.node}set object(val){this.node=val;}get isRead(){return (this.flags&2097155)!==1}get isWrite(){return (this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val;}get position(){return this.shared.position}set position(val){this.shared.position=val;}},FSNode:class{constructor(parent,name,mode,rdev){if(!parent){parent=this;}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev;this.readMode=292|73;this.writeMode=146;}get read(){return (this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode;}get write(){return (this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode;}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return {path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return {path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent;}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node;},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next;}else {var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next;}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node);},isRoot(node){return node===node.parent},isMountpoint(node){return !!node.mounted},isFile(mode){return (mode&61440)===32768},isDir(mode){return (mode&61440)===16384},isLink(mode){return (mode&61440)===40960},isChrdev(mode){return (mode&61440)===8192},isBlkdev(mode){return (mode&61440)===24576},isFIFO(mode){return (mode&61440)===4096},isSocket(mode){return (mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w";}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name);}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else {if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd();}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null;},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream);},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops};},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts);}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false;}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null);}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done);});},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot;}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount);}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current);}current=next;}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1);},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path;},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user");},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength;}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp");},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd");},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"]);}else {FS.symlink("/dev/tty","/dev/stdin");}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"]);}else {FS.symlink("/dev/tty","/dev/stdout");}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"]);}else {FS.symlink("/dev/tty1","/dev/stderr");}FS.open("/dev/stdin",0);FS.open("/dev/stdout",1);FS.open("/dev/stderr",1);},staticInit(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack="";});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS:MEMFS};},init(input,output,error){FS.init.initialized=true;Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams();},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter;}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined");}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end);}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed");}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true;}get length(){if(!this.lengthKnown){this.cacheLength();}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength();}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray};}else {var properties={isDevice:false,url:url};}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents;}else if(properties.url){node.contents=null;node.url=properties.url;}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)};});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return {ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd();}else {var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path;}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags);},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_chmod(path,mode){try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return -28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return -44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return -2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function syscallGetVarargI(){var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret}var syscallGetVarargP=syscallGetVarargI;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return -28}while(FS.streams[arg]){arg++;}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0}return -28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function ___syscall_ftruncate64(fd,length_low,length_high){var length=convertI32PairToI53Checked(length_low,length_high);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function ___syscall_getcwd(buf,size){try{if(size===0)return -28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(sizeHEAPU32[ptr>>2]+HEAP32[ptr+4>>2]*4294967296;function ___syscall_utimensat(dirfd,path,times,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);if(!times){var atime=Date.now();var mtime=atime;}else {var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>2];atime=seconds*1e3+nanoseconds/(1e3*1e3);times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>2];mtime=seconds*1e3+nanoseconds/(1e3*1e3);}FS.utime(path,atime,mtime);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst;}function __mmap_js(len,prot,flags,fd,offset_low,offset_high,allocated,addr){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset_low,offset_high){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset);}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var __tzset_js=(timezone,daylight,std_name,dst_name)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);var extractZone=date=>date.toLocaleTimeString(undefined,{hour12:false,timeZoneName:"short"}).split(" ")[1];var winterName=extractZone(winter);var summerName=extractZone(summer);if(summerOffsetDate.now();var _emscripten_get_now;_emscripten_get_now=()=>performance.now();var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x];}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`);}getEnvStrings.strings=strings;}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i{var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1;});return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4;}HEAP8[pbuf]=type;HEAP16[pbuf+2>>1]=flags;tempI64=[rightsBase>>>0,(tempDouble=rightsBase,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+8>>2]=tempI64[0],HEAP32[pbuf+12>>2]=tempI64[1];tempI64=[rightsInheriting>>>0,(tempDouble=rightsInheriting,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+16>>2]=tempI64[0],HEAP32[pbuf+20>>2]=tempI64[1];return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return -1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops?.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return -1;ret+=curr;}return ret};function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var adapters_support=function(){const handleAsync=typeof Asyncify==="object"?Asyncify.handleAsync.bind(Asyncify):null;Module["handleAsync"]=handleAsync;const targets=new Map;Module["setCallback"]=(key,target)=>targets.set(key,target);Module["getCallback"]=key=>targets.get(key);Module["deleteCallback"]=key=>targets.delete(key);adapters_support=function(isAsync,key,...args){const receiver=targets.get(key);let methodName=null;const f=typeof receiver==="function"?receiver:receiver[methodName=UTF8ToString(args.shift())];if(isAsync){if(handleAsync){return handleAsync(()=>f.apply(receiver,args))}throw new Error("Synchronous WebAssembly cannot call async function")}const result=f.apply(receiver,args);if(typeof result?.then=="function"){console.error("unexpected Promise",f);throw new Error(`${methodName} unexpectedly returned a Promise`)}return result};};function _ipp(...args){return adapters_support(false,...args)}function _ipp_async(...args){return adapters_support(true,...args)}function _ippipppp(...args){return adapters_support(false,...args)}function _ippipppp_async(...args){return adapters_support(true,...args)}function _ippp(...args){return adapters_support(false,...args)}function _ippp_async(...args){return adapters_support(true,...args)}function _ipppi(...args){return adapters_support(false,...args)}function _ipppi_async(...args){return adapters_support(true,...args)}function _ipppiii(...args){return adapters_support(false,...args)}function _ipppiii_async(...args){return adapters_support(true,...args)}function _ipppiiip(...args){return adapters_support(false,...args)}function _ipppiiip_async(...args){return adapters_support(true,...args)}function _ipppip(...args){return adapters_support(false,...args)}function _ipppip_async(...args){return adapters_support(true,...args)}function _ipppj(...args){return adapters_support(false,...args)}function _ipppj_async(...args){return adapters_support(true,...args)}function _ipppp(...args){return adapters_support(false,...args)}function _ipppp_async(...args){return adapters_support(true,...args)}function _ippppi(...args){return adapters_support(false,...args)}function _ippppi_async(...args){return adapters_support(true,...args)}function _ippppij(...args){return adapters_support(false,...args)}function _ippppij_async(...args){return adapters_support(true,...args)}function _ippppip(...args){return adapters_support(false,...args)}function _ippppip_async(...args){return adapters_support(true,...args)}function _ipppppip(...args){return adapters_support(false,...args)}function _ipppppip_async(...args){return adapters_support(true,...args)}function _vppp(...args){return adapters_support(false,...args)}function _vppp_async(...args){return adapters_support(true,...args)}function _vpppip(...args){return adapters_support(false,...args)}function _vpppip_async(...args){return adapters_support(true,...args)}var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true;}quit_(code,new ExitStatus(code));};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status);};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e);};var uleb128Encode=(n,target)=>{if(n<128){target.push(n);}else {target.push(n%128|128,n>>7);}};var sigToWasmTypes=sig=>{var typeNames={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",p:"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var sigRet=sig.slice(0,1);var sigParam=sig.slice(1);var typeCodes={i:127,p:127,j:126,f:125,d:124,e:111};target.push(96);uleb128Encode(sigParam.length,target);for(var i=0;i{if(typeof WebAssembly.Function=="function"){return new WebAssembly.Function(sigToWasmTypes(sig),func)}var typeSectionBody=[1];generateFuncType(sig,typeSectionBody);var bytes=[0,97,115,109,1,0,0,0,1];uleb128Encode(typeSectionBody.length,bytes);bytes.push(...typeSectionBody);bytes.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);var module=new WebAssembly.Module(new Uint8Array(bytes));var instance=new WebAssembly.Instance(module,{e:{f:func}});var wrappedFunc=instance.exports["f"];return wrappedFunc};var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var updateTableMap=(offset,count)=>{if(functionsInTableMap){for(var i=offset;i{if(!functionsInTableMap){functionsInTableMap=new WeakMap;updateTableMap(0,wasmTable.length);}return functionsInTableMap.get(func)||0};var freeTableIndexes=[];var getEmptyTableSlot=()=>{if(freeTableIndexes.length){return freeTableIndexes.pop()}try{wasmTable.grow(1);}catch(err){if(!(err instanceof RangeError)){throw err}throw "Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."}return wasmTable.length-1};var setWasmTableEntry=(idx,func)=>wasmTable.set(idx,func);var addFunction=(func,sig)=>{var rtn=getFunctionAddress(func);if(rtn){return rtn}var ret=getEmptyTableSlot();try{setWasmTableEntry(ret,func);}catch(err){if(!(err instanceof TypeError)){throw err}var wrapped=convertJsFunctionToWasm(func,sig);setWasmTableEntry(ret,wrapped);}functionsInTableMap.set(func,ret);return ret};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer);};var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str);}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return (...args)=>ccall(ident,returnType,argTypes,args)};var getTempRet0=val=>__emscripten_tempret_get();var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2;}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023;}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var AsciiToString=ptr=>{var str="";while(1){var ch=HEAPU8[ptr++];if(!ch)return str;str+=String.fromCharCode(ch);}};var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit);}return str};var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023);}else {str+=String.fromCharCode(utf32);}}return str};function intArrayToString(array){var ret=[];for(var i=0;i255){chr&=255;}ret.push(String.fromCharCode(chr));}return ret.join("")}FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();adapters_support();var wasmImports={a:___assert_fail,Y:___syscall_chmod,$:___syscall_faccessat,Z:___syscall_fchmod,X:___syscall_fchown32,b:___syscall_fcntl64,W:___syscall_fstat64,y:___syscall_ftruncate64,Q:___syscall_getcwd,U:___syscall_lstat64,N:___syscall_mkdirat,T:___syscall_newfstatat,L:___syscall_openat,J:___syscall_readlinkat,I:___syscall_rmdir,V:___syscall_stat64,G:___syscall_unlinkat,F:___syscall_utimensat,w:__localtime_js,u:__mmap_js,v:__munmap_js,M:__tzset_js,n:_emscripten_date_now,m:_emscripten_get_now,D:_emscripten_resize_heap,O:_environ_get,P:_environ_sizes_get,o:_fd_close,E:_fd_fdstat_get,K:_fd_read,x:_fd_seek,S:_fd_sync,H:_fd_write,s:_ipp,t:_ipp_async,fa:_ippipppp,ia:_ippipppp_async,i:_ippp,j:_ippp_async,c:_ipppi,d:_ipppi_async,ca:_ipppiii,da:_ipppiii_async,ea:_ipppiiip,ga:_ipppiiip_async,g:_ipppip,h:_ipppip_async,z:_ipppj,A:_ipppj_async,e:_ipppp,f:_ipppp_async,aa:_ippppi,ba:_ippppi_async,B:_ippppij,C:_ippppij_async,p:_ippppip,q:_ippppip_async,ha:_ipppppip,r:_ipppppip_async,k:_vppp,l:_vppp_async,R:_vpppip,_:_vpppip_async};var wasmExports=createWasm();Module["_sqlite3_status64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_status64"]=wasmExports["la"])(a0,a1,a2,a3);Module["_sqlite3_status"]=(a0,a1,a2,a3)=>(Module["_sqlite3_status"]=wasmExports["ma"])(a0,a1,a2,a3);Module["_sqlite3_db_status"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_db_status"]=wasmExports["na"])(a0,a1,a2,a3,a4);Module["_sqlite3_msize"]=a0=>(Module["_sqlite3_msize"]=wasmExports["oa"])(a0);Module["_sqlite3_vfs_find"]=a0=>(Module["_sqlite3_vfs_find"]=wasmExports["pa"])(a0);Module["_sqlite3_vfs_register"]=(a0,a1)=>(Module["_sqlite3_vfs_register"]=wasmExports["qa"])(a0,a1);Module["_sqlite3_vfs_unregister"]=a0=>(Module["_sqlite3_vfs_unregister"]=wasmExports["ra"])(a0);Module["_sqlite3_release_memory"]=a0=>(Module["_sqlite3_release_memory"]=wasmExports["sa"])(a0);Module["_sqlite3_soft_heap_limit64"]=(a0,a1)=>(Module["_sqlite3_soft_heap_limit64"]=wasmExports["ta"])(a0,a1);Module["_sqlite3_memory_used"]=()=>(Module["_sqlite3_memory_used"]=wasmExports["ua"])();Module["_sqlite3_hard_heap_limit64"]=(a0,a1)=>(Module["_sqlite3_hard_heap_limit64"]=wasmExports["va"])(a0,a1);Module["_sqlite3_memory_highwater"]=a0=>(Module["_sqlite3_memory_highwater"]=wasmExports["wa"])(a0);Module["_sqlite3_malloc"]=a0=>(Module["_sqlite3_malloc"]=wasmExports["xa"])(a0);Module["_sqlite3_malloc64"]=(a0,a1)=>(Module["_sqlite3_malloc64"]=wasmExports["ya"])(a0,a1);Module["_sqlite3_free"]=a0=>(Module["_sqlite3_free"]=wasmExports["za"])(a0);Module["_sqlite3_realloc"]=(a0,a1)=>(Module["_sqlite3_realloc"]=wasmExports["Aa"])(a0,a1);Module["_sqlite3_realloc64"]=(a0,a1,a2)=>(Module["_sqlite3_realloc64"]=wasmExports["Ba"])(a0,a1,a2);Module["_sqlite3_str_vappendf"]=(a0,a1,a2)=>(Module["_sqlite3_str_vappendf"]=wasmExports["Ca"])(a0,a1,a2);Module["_sqlite3_str_append"]=(a0,a1,a2)=>(Module["_sqlite3_str_append"]=wasmExports["Da"])(a0,a1,a2);Module["_sqlite3_str_appendchar"]=(a0,a1,a2)=>(Module["_sqlite3_str_appendchar"]=wasmExports["Ea"])(a0,a1,a2);Module["_sqlite3_str_appendall"]=(a0,a1)=>(Module["_sqlite3_str_appendall"]=wasmExports["Fa"])(a0,a1);Module["_sqlite3_str_appendf"]=(a0,a1,a2)=>(Module["_sqlite3_str_appendf"]=wasmExports["Ga"])(a0,a1,a2);Module["_sqlite3_str_finish"]=a0=>(Module["_sqlite3_str_finish"]=wasmExports["Ha"])(a0);Module["_sqlite3_str_errcode"]=a0=>(Module["_sqlite3_str_errcode"]=wasmExports["Ia"])(a0);Module["_sqlite3_str_length"]=a0=>(Module["_sqlite3_str_length"]=wasmExports["Ja"])(a0);Module["_sqlite3_str_value"]=a0=>(Module["_sqlite3_str_value"]=wasmExports["Ka"])(a0);Module["_sqlite3_str_reset"]=a0=>(Module["_sqlite3_str_reset"]=wasmExports["La"])(a0);Module["_sqlite3_str_new"]=a0=>(Module["_sqlite3_str_new"]=wasmExports["Ma"])(a0);Module["_sqlite3_vmprintf"]=(a0,a1)=>(Module["_sqlite3_vmprintf"]=wasmExports["Na"])(a0,a1);Module["_sqlite3_mprintf"]=(a0,a1)=>(Module["_sqlite3_mprintf"]=wasmExports["Oa"])(a0,a1);Module["_sqlite3_vsnprintf"]=(a0,a1,a2,a3)=>(Module["_sqlite3_vsnprintf"]=wasmExports["Pa"])(a0,a1,a2,a3);Module["_sqlite3_snprintf"]=(a0,a1,a2,a3)=>(Module["_sqlite3_snprintf"]=wasmExports["Qa"])(a0,a1,a2,a3);Module["_sqlite3_log"]=(a0,a1,a2)=>(Module["_sqlite3_log"]=wasmExports["Ra"])(a0,a1,a2);Module["_sqlite3_randomness"]=(a0,a1)=>(Module["_sqlite3_randomness"]=wasmExports["Sa"])(a0,a1);Module["_sqlite3_stricmp"]=(a0,a1)=>(Module["_sqlite3_stricmp"]=wasmExports["Ta"])(a0,a1);Module["_sqlite3_strnicmp"]=(a0,a1,a2)=>(Module["_sqlite3_strnicmp"]=wasmExports["Ua"])(a0,a1,a2);Module["_sqlite3_os_init"]=()=>(Module["_sqlite3_os_init"]=wasmExports["Va"])();Module["_sqlite3_os_end"]=()=>(Module["_sqlite3_os_end"]=wasmExports["Wa"])();Module["_sqlite3_serialize"]=(a0,a1,a2,a3)=>(Module["_sqlite3_serialize"]=wasmExports["Xa"])(a0,a1,a2,a3);Module["_sqlite3_prepare_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare_v2"]=wasmExports["Ya"])(a0,a1,a2,a3,a4);Module["_sqlite3_step"]=a0=>(Module["_sqlite3_step"]=wasmExports["Za"])(a0);Module["_sqlite3_column_int64"]=(a0,a1)=>(Module["_sqlite3_column_int64"]=wasmExports["_a"])(a0,a1);Module["_sqlite3_reset"]=a0=>(Module["_sqlite3_reset"]=wasmExports["$a"])(a0);Module["_sqlite3_exec"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_exec"]=wasmExports["ab"])(a0,a1,a2,a3,a4);Module["_sqlite3_column_int"]=(a0,a1)=>(Module["_sqlite3_column_int"]=wasmExports["bb"])(a0,a1);Module["_sqlite3_finalize"]=a0=>(Module["_sqlite3_finalize"]=wasmExports["cb"])(a0);Module["_sqlite3_deserialize"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_deserialize"]=wasmExports["db"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_database_file_object"]=a0=>(Module["_sqlite3_database_file_object"]=wasmExports["eb"])(a0);Module["_sqlite3_backup_init"]=(a0,a1,a2,a3)=>(Module["_sqlite3_backup_init"]=wasmExports["fb"])(a0,a1,a2,a3);Module["_sqlite3_backup_step"]=(a0,a1)=>(Module["_sqlite3_backup_step"]=wasmExports["gb"])(a0,a1);Module["_sqlite3_backup_finish"]=a0=>(Module["_sqlite3_backup_finish"]=wasmExports["hb"])(a0);Module["_sqlite3_backup_remaining"]=a0=>(Module["_sqlite3_backup_remaining"]=wasmExports["ib"])(a0);Module["_sqlite3_backup_pagecount"]=a0=>(Module["_sqlite3_backup_pagecount"]=wasmExports["jb"])(a0);Module["_sqlite3_clear_bindings"]=a0=>(Module["_sqlite3_clear_bindings"]=wasmExports["kb"])(a0);Module["_sqlite3_value_blob"]=a0=>(Module["_sqlite3_value_blob"]=wasmExports["lb"])(a0);Module["_sqlite3_value_text"]=a0=>(Module["_sqlite3_value_text"]=wasmExports["mb"])(a0);Module["_sqlite3_value_bytes"]=a0=>(Module["_sqlite3_value_bytes"]=wasmExports["nb"])(a0);Module["_sqlite3_value_bytes16"]=a0=>(Module["_sqlite3_value_bytes16"]=wasmExports["ob"])(a0);Module["_sqlite3_value_double"]=a0=>(Module["_sqlite3_value_double"]=wasmExports["pb"])(a0);Module["_sqlite3_value_int"]=a0=>(Module["_sqlite3_value_int"]=wasmExports["qb"])(a0);Module["_sqlite3_value_int64"]=a0=>(Module["_sqlite3_value_int64"]=wasmExports["rb"])(a0);Module["_sqlite3_value_subtype"]=a0=>(Module["_sqlite3_value_subtype"]=wasmExports["sb"])(a0);Module["_sqlite3_value_pointer"]=(a0,a1)=>(Module["_sqlite3_value_pointer"]=wasmExports["tb"])(a0,a1);Module["_sqlite3_value_text16"]=a0=>(Module["_sqlite3_value_text16"]=wasmExports["ub"])(a0);Module["_sqlite3_value_text16be"]=a0=>(Module["_sqlite3_value_text16be"]=wasmExports["vb"])(a0);Module["_sqlite3_value_text16le"]=a0=>(Module["_sqlite3_value_text16le"]=wasmExports["wb"])(a0);Module["_sqlite3_value_type"]=a0=>(Module["_sqlite3_value_type"]=wasmExports["xb"])(a0);Module["_sqlite3_value_encoding"]=a0=>(Module["_sqlite3_value_encoding"]=wasmExports["yb"])(a0);Module["_sqlite3_value_nochange"]=a0=>(Module["_sqlite3_value_nochange"]=wasmExports["zb"])(a0);Module["_sqlite3_value_frombind"]=a0=>(Module["_sqlite3_value_frombind"]=wasmExports["Ab"])(a0);Module["_sqlite3_value_dup"]=a0=>(Module["_sqlite3_value_dup"]=wasmExports["Bb"])(a0);Module["_sqlite3_value_free"]=a0=>(Module["_sqlite3_value_free"]=wasmExports["Cb"])(a0);Module["_sqlite3_result_blob"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_blob"]=wasmExports["Db"])(a0,a1,a2,a3);Module["_sqlite3_result_blob64"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_result_blob64"]=wasmExports["Eb"])(a0,a1,a2,a3,a4);Module["_sqlite3_result_double"]=(a0,a1)=>(Module["_sqlite3_result_double"]=wasmExports["Fb"])(a0,a1);Module["_sqlite3_result_error"]=(a0,a1,a2)=>(Module["_sqlite3_result_error"]=wasmExports["Gb"])(a0,a1,a2);Module["_sqlite3_result_error16"]=(a0,a1,a2)=>(Module["_sqlite3_result_error16"]=wasmExports["Hb"])(a0,a1,a2);Module["_sqlite3_result_int"]=(a0,a1)=>(Module["_sqlite3_result_int"]=wasmExports["Ib"])(a0,a1);Module["_sqlite3_result_int64"]=(a0,a1,a2)=>(Module["_sqlite3_result_int64"]=wasmExports["Jb"])(a0,a1,a2);Module["_sqlite3_result_null"]=a0=>(Module["_sqlite3_result_null"]=wasmExports["Kb"])(a0);Module["_sqlite3_result_pointer"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_pointer"]=wasmExports["Lb"])(a0,a1,a2,a3);Module["_sqlite3_result_subtype"]=(a0,a1)=>(Module["_sqlite3_result_subtype"]=wasmExports["Mb"])(a0,a1);Module["_sqlite3_result_text"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text"]=wasmExports["Nb"])(a0,a1,a2,a3);Module["_sqlite3_result_text64"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_result_text64"]=wasmExports["Ob"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_result_text16"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16"]=wasmExports["Pb"])(a0,a1,a2,a3);Module["_sqlite3_result_text16be"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16be"]=wasmExports["Qb"])(a0,a1,a2,a3);Module["_sqlite3_result_text16le"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16le"]=wasmExports["Rb"])(a0,a1,a2,a3);Module["_sqlite3_result_value"]=(a0,a1)=>(Module["_sqlite3_result_value"]=wasmExports["Sb"])(a0,a1);Module["_sqlite3_result_error_toobig"]=a0=>(Module["_sqlite3_result_error_toobig"]=wasmExports["Tb"])(a0);Module["_sqlite3_result_zeroblob"]=(a0,a1)=>(Module["_sqlite3_result_zeroblob"]=wasmExports["Ub"])(a0,a1);Module["_sqlite3_result_zeroblob64"]=(a0,a1,a2)=>(Module["_sqlite3_result_zeroblob64"]=wasmExports["Vb"])(a0,a1,a2);Module["_sqlite3_result_error_code"]=(a0,a1)=>(Module["_sqlite3_result_error_code"]=wasmExports["Wb"])(a0,a1);Module["_sqlite3_result_error_nomem"]=a0=>(Module["_sqlite3_result_error_nomem"]=wasmExports["Xb"])(a0);Module["_sqlite3_user_data"]=a0=>(Module["_sqlite3_user_data"]=wasmExports["Yb"])(a0);Module["_sqlite3_context_db_handle"]=a0=>(Module["_sqlite3_context_db_handle"]=wasmExports["Zb"])(a0);Module["_sqlite3_vtab_nochange"]=a0=>(Module["_sqlite3_vtab_nochange"]=wasmExports["_b"])(a0);Module["_sqlite3_vtab_in_first"]=(a0,a1)=>(Module["_sqlite3_vtab_in_first"]=wasmExports["$b"])(a0,a1);Module["_sqlite3_vtab_in_next"]=(a0,a1)=>(Module["_sqlite3_vtab_in_next"]=wasmExports["ac"])(a0,a1);Module["_sqlite3_aggregate_context"]=(a0,a1)=>(Module["_sqlite3_aggregate_context"]=wasmExports["bc"])(a0,a1);Module["_sqlite3_get_auxdata"]=(a0,a1)=>(Module["_sqlite3_get_auxdata"]=wasmExports["cc"])(a0,a1);Module["_sqlite3_set_auxdata"]=(a0,a1,a2,a3)=>(Module["_sqlite3_set_auxdata"]=wasmExports["dc"])(a0,a1,a2,a3);Module["_sqlite3_column_count"]=a0=>(Module["_sqlite3_column_count"]=wasmExports["ec"])(a0);Module["_sqlite3_data_count"]=a0=>(Module["_sqlite3_data_count"]=wasmExports["fc"])(a0);Module["_sqlite3_column_blob"]=(a0,a1)=>(Module["_sqlite3_column_blob"]=wasmExports["gc"])(a0,a1);Module["_sqlite3_column_bytes"]=(a0,a1)=>(Module["_sqlite3_column_bytes"]=wasmExports["hc"])(a0,a1);Module["_sqlite3_column_bytes16"]=(a0,a1)=>(Module["_sqlite3_column_bytes16"]=wasmExports["ic"])(a0,a1);Module["_sqlite3_column_double"]=(a0,a1)=>(Module["_sqlite3_column_double"]=wasmExports["jc"])(a0,a1);Module["_sqlite3_column_text"]=(a0,a1)=>(Module["_sqlite3_column_text"]=wasmExports["kc"])(a0,a1);Module["_sqlite3_column_value"]=(a0,a1)=>(Module["_sqlite3_column_value"]=wasmExports["lc"])(a0,a1);Module["_sqlite3_column_text16"]=(a0,a1)=>(Module["_sqlite3_column_text16"]=wasmExports["mc"])(a0,a1);Module["_sqlite3_column_type"]=(a0,a1)=>(Module["_sqlite3_column_type"]=wasmExports["nc"])(a0,a1);Module["_sqlite3_column_name"]=(a0,a1)=>(Module["_sqlite3_column_name"]=wasmExports["oc"])(a0,a1);Module["_sqlite3_column_name16"]=(a0,a1)=>(Module["_sqlite3_column_name16"]=wasmExports["pc"])(a0,a1);Module["_sqlite3_bind_blob"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_blob"]=wasmExports["qc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_blob64"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_bind_blob64"]=wasmExports["rc"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_bind_double"]=(a0,a1,a2)=>(Module["_sqlite3_bind_double"]=wasmExports["sc"])(a0,a1,a2);Module["_sqlite3_bind_int"]=(a0,a1,a2)=>(Module["_sqlite3_bind_int"]=wasmExports["tc"])(a0,a1,a2);Module["_sqlite3_bind_int64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_bind_int64"]=wasmExports["uc"])(a0,a1,a2,a3);Module["_sqlite3_bind_null"]=(a0,a1)=>(Module["_sqlite3_bind_null"]=wasmExports["vc"])(a0,a1);Module["_sqlite3_bind_pointer"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_pointer"]=wasmExports["wc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_text"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_text"]=wasmExports["xc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_text64"]=(a0,a1,a2,a3,a4,a5,a6)=>(Module["_sqlite3_bind_text64"]=wasmExports["yc"])(a0,a1,a2,a3,a4,a5,a6);Module["_sqlite3_bind_text16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_text16"]=wasmExports["zc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_value"]=(a0,a1,a2)=>(Module["_sqlite3_bind_value"]=wasmExports["Ac"])(a0,a1,a2);Module["_sqlite3_bind_zeroblob"]=(a0,a1,a2)=>(Module["_sqlite3_bind_zeroblob"]=wasmExports["Bc"])(a0,a1,a2);Module["_sqlite3_bind_zeroblob64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_bind_zeroblob64"]=wasmExports["Cc"])(a0,a1,a2,a3);Module["_sqlite3_bind_parameter_count"]=a0=>(Module["_sqlite3_bind_parameter_count"]=wasmExports["Dc"])(a0);Module["_sqlite3_bind_parameter_name"]=(a0,a1)=>(Module["_sqlite3_bind_parameter_name"]=wasmExports["Ec"])(a0,a1);Module["_sqlite3_bind_parameter_index"]=(a0,a1)=>(Module["_sqlite3_bind_parameter_index"]=wasmExports["Fc"])(a0,a1);Module["_sqlite3_db_handle"]=a0=>(Module["_sqlite3_db_handle"]=wasmExports["Gc"])(a0);Module["_sqlite3_stmt_readonly"]=a0=>(Module["_sqlite3_stmt_readonly"]=wasmExports["Hc"])(a0);Module["_sqlite3_stmt_isexplain"]=a0=>(Module["_sqlite3_stmt_isexplain"]=wasmExports["Ic"])(a0);Module["_sqlite3_stmt_explain"]=(a0,a1)=>(Module["_sqlite3_stmt_explain"]=wasmExports["Jc"])(a0,a1);Module["_sqlite3_stmt_busy"]=a0=>(Module["_sqlite3_stmt_busy"]=wasmExports["Kc"])(a0);Module["_sqlite3_next_stmt"]=(a0,a1)=>(Module["_sqlite3_next_stmt"]=wasmExports["Lc"])(a0,a1);Module["_sqlite3_stmt_status"]=(a0,a1,a2)=>(Module["_sqlite3_stmt_status"]=wasmExports["Mc"])(a0,a1,a2);Module["_sqlite3_sql"]=a0=>(Module["_sqlite3_sql"]=wasmExports["Nc"])(a0);Module["_sqlite3_expanded_sql"]=a0=>(Module["_sqlite3_expanded_sql"]=wasmExports["Oc"])(a0);Module["_sqlite3_value_numeric_type"]=a0=>(Module["_sqlite3_value_numeric_type"]=wasmExports["Pc"])(a0);Module["_sqlite3_blob_open"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_blob_open"]=wasmExports["Qc"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_blob_close"]=a0=>(Module["_sqlite3_blob_close"]=wasmExports["Rc"])(a0);Module["_sqlite3_blob_read"]=(a0,a1,a2,a3)=>(Module["_sqlite3_blob_read"]=wasmExports["Sc"])(a0,a1,a2,a3);Module["_sqlite3_blob_write"]=(a0,a1,a2,a3)=>(Module["_sqlite3_blob_write"]=wasmExports["Tc"])(a0,a1,a2,a3);Module["_sqlite3_blob_bytes"]=a0=>(Module["_sqlite3_blob_bytes"]=wasmExports["Uc"])(a0);Module["_sqlite3_blob_reopen"]=(a0,a1,a2)=>(Module["_sqlite3_blob_reopen"]=wasmExports["Vc"])(a0,a1,a2);Module["_sqlite3_set_authorizer"]=(a0,a1,a2)=>(Module["_sqlite3_set_authorizer"]=wasmExports["Wc"])(a0,a1,a2);Module["_sqlite3_strglob"]=(a0,a1)=>(Module["_sqlite3_strglob"]=wasmExports["Xc"])(a0,a1);Module["_sqlite3_strlike"]=(a0,a1,a2)=>(Module["_sqlite3_strlike"]=wasmExports["Yc"])(a0,a1,a2);Module["_sqlite3_errmsg"]=a0=>(Module["_sqlite3_errmsg"]=wasmExports["Zc"])(a0);Module["_sqlite3_auto_extension"]=a0=>(Module["_sqlite3_auto_extension"]=wasmExports["_c"])(a0);Module["_sqlite3_cancel_auto_extension"]=a0=>(Module["_sqlite3_cancel_auto_extension"]=wasmExports["$c"])(a0);Module["_sqlite3_reset_auto_extension"]=()=>(Module["_sqlite3_reset_auto_extension"]=wasmExports["ad"])();Module["_sqlite3_prepare"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare"]=wasmExports["bd"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare_v3"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_prepare_v3"]=wasmExports["cd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_prepare16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare16"]=wasmExports["dd"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare16_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare16_v2"]=wasmExports["ed"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare16_v3"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_prepare16_v3"]=wasmExports["fd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_get_table"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_get_table"]=wasmExports["gd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_free_table"]=a0=>(Module["_sqlite3_free_table"]=wasmExports["hd"])(a0);Module["_sqlite3_create_module"]=(a0,a1,a2,a3)=>(Module["_sqlite3_create_module"]=wasmExports["id"])(a0,a1,a2,a3);Module["_sqlite3_create_module_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_module_v2"]=wasmExports["jd"])(a0,a1,a2,a3,a4);Module["_sqlite3_drop_modules"]=(a0,a1)=>(Module["_sqlite3_drop_modules"]=wasmExports["kd"])(a0,a1);Module["_sqlite3_declare_vtab"]=(a0,a1)=>(Module["_sqlite3_declare_vtab"]=wasmExports["ld"])(a0,a1);Module["_sqlite3_vtab_on_conflict"]=a0=>(Module["_sqlite3_vtab_on_conflict"]=wasmExports["md"])(a0);Module["_sqlite3_vtab_config"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_config"]=wasmExports["nd"])(a0,a1,a2);Module["_sqlite3_vtab_collation"]=(a0,a1)=>(Module["_sqlite3_vtab_collation"]=wasmExports["od"])(a0,a1);Module["_sqlite3_vtab_in"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_in"]=wasmExports["pd"])(a0,a1,a2);Module["_sqlite3_vtab_rhs_value"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_rhs_value"]=wasmExports["qd"])(a0,a1,a2);Module["_sqlite3_vtab_distinct"]=a0=>(Module["_sqlite3_vtab_distinct"]=wasmExports["rd"])(a0);Module["_sqlite3_keyword_name"]=(a0,a1,a2)=>(Module["_sqlite3_keyword_name"]=wasmExports["sd"])(a0,a1,a2);Module["_sqlite3_keyword_count"]=()=>(Module["_sqlite3_keyword_count"]=wasmExports["td"])();Module["_sqlite3_keyword_check"]=(a0,a1)=>(Module["_sqlite3_keyword_check"]=wasmExports["ud"])(a0,a1);Module["_sqlite3_complete"]=a0=>(Module["_sqlite3_complete"]=wasmExports["vd"])(a0);Module["_sqlite3_complete16"]=a0=>(Module["_sqlite3_complete16"]=wasmExports["wd"])(a0);Module["_sqlite3_libversion"]=()=>(Module["_sqlite3_libversion"]=wasmExports["xd"])();Module["_sqlite3_libversion_number"]=()=>(Module["_sqlite3_libversion_number"]=wasmExports["yd"])();Module["_sqlite3_threadsafe"]=()=>(Module["_sqlite3_threadsafe"]=wasmExports["zd"])();Module["_sqlite3_initialize"]=()=>(Module["_sqlite3_initialize"]=wasmExports["Ad"])();Module["_sqlite3_shutdown"]=()=>(Module["_sqlite3_shutdown"]=wasmExports["Bd"])();Module["_sqlite3_config"]=(a0,a1)=>(Module["_sqlite3_config"]=wasmExports["Cd"])(a0,a1);Module["_sqlite3_db_mutex"]=a0=>(Module["_sqlite3_db_mutex"]=wasmExports["Dd"])(a0);Module["_sqlite3_db_release_memory"]=a0=>(Module["_sqlite3_db_release_memory"]=wasmExports["Ed"])(a0);Module["_sqlite3_db_cacheflush"]=a0=>(Module["_sqlite3_db_cacheflush"]=wasmExports["Fd"])(a0);Module["_sqlite3_db_config"]=(a0,a1,a2)=>(Module["_sqlite3_db_config"]=wasmExports["Gd"])(a0,a1,a2);Module["_sqlite3_last_insert_rowid"]=a0=>(Module["_sqlite3_last_insert_rowid"]=wasmExports["Hd"])(a0);Module["_sqlite3_set_last_insert_rowid"]=(a0,a1,a2)=>(Module["_sqlite3_set_last_insert_rowid"]=wasmExports["Id"])(a0,a1,a2);Module["_sqlite3_changes64"]=a0=>(Module["_sqlite3_changes64"]=wasmExports["Jd"])(a0);Module["_sqlite3_changes"]=a0=>(Module["_sqlite3_changes"]=wasmExports["Kd"])(a0);Module["_sqlite3_total_changes64"]=a0=>(Module["_sqlite3_total_changes64"]=wasmExports["Ld"])(a0);Module["_sqlite3_total_changes"]=a0=>(Module["_sqlite3_total_changes"]=wasmExports["Md"])(a0);Module["_sqlite3_txn_state"]=(a0,a1)=>(Module["_sqlite3_txn_state"]=wasmExports["Nd"])(a0,a1);Module["_sqlite3_close"]=a0=>(Module["_sqlite3_close"]=wasmExports["Od"])(a0);Module["_sqlite3_close_v2"]=a0=>(Module["_sqlite3_close_v2"]=wasmExports["Pd"])(a0);Module["_sqlite3_busy_handler"]=(a0,a1,a2)=>(Module["_sqlite3_busy_handler"]=wasmExports["Qd"])(a0,a1,a2);Module["_sqlite3_progress_handler"]=(a0,a1,a2,a3)=>(Module["_sqlite3_progress_handler"]=wasmExports["Rd"])(a0,a1,a2,a3);Module["_sqlite3_busy_timeout"]=(a0,a1)=>(Module["_sqlite3_busy_timeout"]=wasmExports["Sd"])(a0,a1);Module["_sqlite3_interrupt"]=a0=>(Module["_sqlite3_interrupt"]=wasmExports["Td"])(a0);Module["_sqlite3_is_interrupted"]=a0=>(Module["_sqlite3_is_interrupted"]=wasmExports["Ud"])(a0);Module["_sqlite3_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_create_function"]=wasmExports["Vd"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_create_function_v2"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(Module["_sqlite3_create_function_v2"]=wasmExports["Wd"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);Module["_sqlite3_create_window_function"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(Module["_sqlite3_create_window_function"]=wasmExports["Xd"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);Module["_sqlite3_create_function16"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_create_function16"]=wasmExports["Yd"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_overload_function"]=(a0,a1,a2)=>(Module["_sqlite3_overload_function"]=wasmExports["Zd"])(a0,a1,a2);Module["_sqlite3_trace_v2"]=(a0,a1,a2,a3)=>(Module["_sqlite3_trace_v2"]=wasmExports["_d"])(a0,a1,a2,a3);Module["_sqlite3_commit_hook"]=(a0,a1,a2)=>(Module["_sqlite3_commit_hook"]=wasmExports["$d"])(a0,a1,a2);Module["_sqlite3_update_hook"]=(a0,a1,a2)=>(Module["_sqlite3_update_hook"]=wasmExports["ae"])(a0,a1,a2);Module["_sqlite3_rollback_hook"]=(a0,a1,a2)=>(Module["_sqlite3_rollback_hook"]=wasmExports["be"])(a0,a1,a2);Module["_sqlite3_autovacuum_pages"]=(a0,a1,a2,a3)=>(Module["_sqlite3_autovacuum_pages"]=wasmExports["ce"])(a0,a1,a2,a3);Module["_sqlite3_wal_autocheckpoint"]=(a0,a1)=>(Module["_sqlite3_wal_autocheckpoint"]=wasmExports["de"])(a0,a1);Module["_sqlite3_wal_hook"]=(a0,a1,a2)=>(Module["_sqlite3_wal_hook"]=wasmExports["ee"])(a0,a1,a2);Module["_sqlite3_wal_checkpoint_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_wal_checkpoint_v2"]=wasmExports["fe"])(a0,a1,a2,a3,a4);Module["_sqlite3_wal_checkpoint"]=(a0,a1)=>(Module["_sqlite3_wal_checkpoint"]=wasmExports["ge"])(a0,a1);Module["_sqlite3_error_offset"]=a0=>(Module["_sqlite3_error_offset"]=wasmExports["he"])(a0);Module["_sqlite3_errmsg16"]=a0=>(Module["_sqlite3_errmsg16"]=wasmExports["ie"])(a0);Module["_sqlite3_errcode"]=a0=>(Module["_sqlite3_errcode"]=wasmExports["je"])(a0);Module["_sqlite3_extended_errcode"]=a0=>(Module["_sqlite3_extended_errcode"]=wasmExports["ke"])(a0);Module["_sqlite3_system_errno"]=a0=>(Module["_sqlite3_system_errno"]=wasmExports["le"])(a0);Module["_sqlite3_errstr"]=a0=>(Module["_sqlite3_errstr"]=wasmExports["me"])(a0);Module["_sqlite3_limit"]=(a0,a1,a2)=>(Module["_sqlite3_limit"]=wasmExports["ne"])(a0,a1,a2);Module["_sqlite3_open"]=(a0,a1)=>(Module["_sqlite3_open"]=wasmExports["oe"])(a0,a1);Module["_sqlite3_open_v2"]=(a0,a1,a2,a3)=>(Module["_sqlite3_open_v2"]=wasmExports["pe"])(a0,a1,a2,a3);Module["_sqlite3_open16"]=(a0,a1)=>(Module["_sqlite3_open16"]=wasmExports["qe"])(a0,a1);Module["_sqlite3_create_collation"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_collation"]=wasmExports["re"])(a0,a1,a2,a3,a4);Module["_sqlite3_create_collation_v2"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_create_collation_v2"]=wasmExports["se"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_create_collation16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_collation16"]=wasmExports["te"])(a0,a1,a2,a3,a4);Module["_sqlite3_collation_needed"]=(a0,a1,a2)=>(Module["_sqlite3_collation_needed"]=wasmExports["ue"])(a0,a1,a2);Module["_sqlite3_collation_needed16"]=(a0,a1,a2)=>(Module["_sqlite3_collation_needed16"]=wasmExports["ve"])(a0,a1,a2);Module["_sqlite3_get_clientdata"]=(a0,a1)=>(Module["_sqlite3_get_clientdata"]=wasmExports["we"])(a0,a1);Module["_sqlite3_set_clientdata"]=(a0,a1,a2,a3)=>(Module["_sqlite3_set_clientdata"]=wasmExports["xe"])(a0,a1,a2,a3);Module["_sqlite3_get_autocommit"]=a0=>(Module["_sqlite3_get_autocommit"]=wasmExports["ye"])(a0);Module["_sqlite3_table_column_metadata"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(Module["_sqlite3_table_column_metadata"]=wasmExports["ze"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);Module["_sqlite3_sleep"]=a0=>(Module["_sqlite3_sleep"]=wasmExports["Ae"])(a0);Module["_sqlite3_extended_result_codes"]=(a0,a1)=>(Module["_sqlite3_extended_result_codes"]=wasmExports["Be"])(a0,a1);Module["_sqlite3_file_control"]=(a0,a1,a2,a3)=>(Module["_sqlite3_file_control"]=wasmExports["Ce"])(a0,a1,a2,a3);Module["_sqlite3_test_control"]=(a0,a1)=>(Module["_sqlite3_test_control"]=wasmExports["De"])(a0,a1);Module["_sqlite3_create_filename"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_filename"]=wasmExports["Ee"])(a0,a1,a2,a3,a4);Module["_sqlite3_free_filename"]=a0=>(Module["_sqlite3_free_filename"]=wasmExports["Fe"])(a0);Module["_sqlite3_uri_parameter"]=(a0,a1)=>(Module["_sqlite3_uri_parameter"]=wasmExports["Ge"])(a0,a1);Module["_sqlite3_uri_key"]=(a0,a1)=>(Module["_sqlite3_uri_key"]=wasmExports["He"])(a0,a1);Module["_sqlite3_uri_boolean"]=(a0,a1,a2)=>(Module["_sqlite3_uri_boolean"]=wasmExports["Ie"])(a0,a1,a2);Module["_sqlite3_uri_int64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_uri_int64"]=wasmExports["Je"])(a0,a1,a2,a3);Module["_sqlite3_filename_database"]=a0=>(Module["_sqlite3_filename_database"]=wasmExports["Ke"])(a0);Module["_sqlite3_filename_journal"]=a0=>(Module["_sqlite3_filename_journal"]=wasmExports["Le"])(a0);Module["_sqlite3_filename_wal"]=a0=>(Module["_sqlite3_filename_wal"]=wasmExports["Me"])(a0);Module["_sqlite3_db_name"]=(a0,a1)=>(Module["_sqlite3_db_name"]=wasmExports["Ne"])(a0,a1);Module["_sqlite3_db_filename"]=(a0,a1)=>(Module["_sqlite3_db_filename"]=wasmExports["Oe"])(a0,a1);Module["_sqlite3_db_readonly"]=(a0,a1)=>(Module["_sqlite3_db_readonly"]=wasmExports["Pe"])(a0,a1);Module["_sqlite3_compileoption_used"]=a0=>(Module["_sqlite3_compileoption_used"]=wasmExports["Qe"])(a0);Module["_sqlite3_compileoption_get"]=a0=>(Module["_sqlite3_compileoption_get"]=wasmExports["Re"])(a0);Module["_sqlite3_sourceid"]=()=>(Module["_sqlite3_sourceid"]=wasmExports["Se"])();Module["_malloc"]=a0=>(Module["_malloc"]=wasmExports["Te"])(a0);Module["_free"]=a0=>(Module["_free"]=wasmExports["Ue"])(a0);Module["_RegisterExtensionFunctions"]=a0=>(Module["_RegisterExtensionFunctions"]=wasmExports["Ve"])(a0);Module["_getSqliteFree"]=()=>(Module["_getSqliteFree"]=wasmExports["We"])();var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["Xe"])(a0,a1);Module["_libauthorizer_set_authorizer"]=(a0,a1,a2)=>(Module["_libauthorizer_set_authorizer"]=wasmExports["Ye"])(a0,a1,a2);Module["_libfunction_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_libfunction_create_function"]=wasmExports["Ze"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_libprogress_progress_handler"]=(a0,a1,a2,a3)=>(Module["_libprogress_progress_handler"]=wasmExports["_e"])(a0,a1,a2,a3);Module["_libvfs_vfs_register"]=(a0,a1,a2,a3,a4,a5)=>(Module["_libvfs_vfs_register"]=wasmExports["$e"])(a0,a1,a2,a3,a4,a5);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["bf"])(a0,a1);var __emscripten_tempret_get=()=>(__emscripten_tempret_get=wasmExports["cf"])();var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["df"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["ef"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["ff"])();Module["_sqlite3_version"]=5472;Module["getTempRet0"]=getTempRet0;Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["addFunction"]=addFunction;Module["setValue"]=setValue;Module["getValue"]=getValue;Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;Module["intArrayFromString"]=intArrayFromString;Module["intArrayToString"]=intArrayToString;Module["AsciiToString"]=AsciiToString;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;Module["UTF32ToString"]=UTF32ToString;Module["stringToUTF32"]=stringToUTF32;Module["writeArrayToMemory"]=writeArrayToMemory;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller;};function callMain(){var entryFunction=_main;var argc=0;var argv=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();if(shouldRunNow)callMain();postRun();}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("");},1);doRun();},1);}else {doRun();}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()();}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;let pAsyncFlags=0;Module["set_authorizer"]=function(db,xAuthorizer,pApp){if(pAsyncFlags){Module["deleteCallback"](pAsyncFlags);Module["_sqlite3_free"](pAsyncFlags);pAsyncFlags=0;}pAsyncFlags=Module["_sqlite3_malloc"](4);setValue(pAsyncFlags,xAuthorizer instanceof AsyncFunction?1:0,"i32");const result=ccall("libauthorizer_set_authorizer","number",["number","number","number"],[db,xAuthorizer?1:0,pAsyncFlags]);if(!result&&xAuthorizer){Module["setCallback"](pAsyncFlags,(_,iAction,p3,p4,p5,p6)=>xAuthorizer(pApp,iAction,p3,p4,p5,p6));}return result};})();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;const FUNC_METHODS=["xFunc","xStep","xFinal"];const mapFunctionNameToKey=new Map;Module["create_function"]=function(db,zFunctionName,nArg,eTextRep,pApp,xFunc,xStep,xFinal){const pAsyncFlags=Module["_sqlite3_malloc"](4);const target={xFunc:xFunc,xStep:xStep,xFinal:xFinal};setValue(pAsyncFlags,FUNC_METHODS.reduce((mask,method,i)=>{if(target[method]instanceof AsyncFunction){return mask|1<xProgress(pApp));}};})();(function(){const VFS_METHODS=["xOpen","xDelete","xAccess","xFullPathname","xRandomness","xSleep","xCurrentTime","xGetLastError","xCurrentTimeInt64","xClose","xRead","xWrite","xTruncate","xSync","xFileSize","xLock","xUnlock","xCheckReservedLock","xFileControl","xSectorSize","xDeviceCharacteristics","xShmMap","xShmLock","xShmBarrier","xShmUnmap"];const mapVFSNameToKey=new Map;Module["vfs_register"]=function(vfs,makeDefault){let methodMask=0;let asyncMask=0;VFS_METHODS.forEach((method,i)=>{if(vfs[method]){methodMask|=1<{readyPromiseResolve=resolve;readyPromiseReject=reject;});var moduleOverrides=Object.assign({},Module);var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href;}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src;}if(_scriptDir){scriptDirectory=_scriptDir;}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1);}else {scriptDirectory="";}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)};}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror();};xhr.onerror=onerror;xhr.send(null);};}}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(typeof WebAssembly!="object"){abort("no native wasm support detected");}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text);}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift());}}callRuntimeCallbacks(__ATPRERUN__);}function initRuntime(){if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;callRuntimeCallbacks(__ATINIT__);}function preMain(){callRuntimeCallbacks(__ATMAIN__);}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift());}}callRuntimeCallbacks(__ATPOSTRUN__);}function addOnPreRun(cb){__ATPRERUN__.unshift(cb);}function addOnInit(cb){__ATINIT__.unshift(cb);}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb);}var runDependencies=0;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies);}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies);}if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback();}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what);}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var wasmBinaryFile;if(Module["locateFile"]){wasmBinaryFile="wa-sqlite.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile);}}else {wasmBinaryFile=new URL("wa-sqlite.wasm",import.meta.url).href;}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw "both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw "failed to load wasm binary file at '"+binaryFile+"'"}return response["arrayBuffer"]()}).catch(()=>getBinarySync(binaryFile))}}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(instance=>instance).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason);})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["ja"];updateMemoryViews();wasmTable=wasmExports["bf"];addOnInit(wasmExports["ka"]);removeRunDependency();return wasmExports}addRunDependency();function receiveInstantiationResult(result){receiveInstance(result["instance"]);}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e);}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return {}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status;}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module);}};function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`);}}var noExitRuntime=Module["noExitRuntime"]||true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`);}}var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023);}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var ___assert_fail=(condition,filename,line,func)=>{abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"]);};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1);}else if(last===".."){parts.splice(i,1);up++;}else if(up){parts.splice(i,1);up--;}}if(allowAboveRoot){for(;up;up--){parts.unshift("..");}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path=".";}if(path&&trailingSlash){path+="/";}return (isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return "."}if(dir){dir=dir.substr(0,dir.length-1);}return root+dir},basename:path=>{if(path==="/")return "/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else abort("initRandomDevice");};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return ""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path);}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return (resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return [];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i;}else {len+=3;}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023;}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u;}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63;}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;}else {if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n";}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n";}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true);}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops);},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false;},close(stream){stream.tty.ops.fsync(stream.tty);},fsync(stream){stream.tty.ops.fsync(stream.tty);},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[];}},ioctl_tcgets(tty){return {c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return [24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[];}else {if(val!=0)tty.output.push(val);}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[];}}}};var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={};}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null;}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream;}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream;}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp;}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;}else {var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)));}node.usedBytes=newSize;}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096;}else if(FS.isFile(node.mode)){attr.size=node.usedBytes;}else if(FS.isLink(node.mode)){attr.size=node.link.length;}else {attr.size=0;}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode;}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp;}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size);}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name);}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir;},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now();},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now();},readdir(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key);}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset);}else {for(var i=0;i0||position+length{var dep=getUniqueRunDependency(`al ${url}`);readAsync(url,arrayBuffer=>{assert(arrayBuffer,`Loading data file "${url}" failed (no arrayBuffer).`);onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency();},event=>{if(onerror){onerror();}else {throw `Loading data file "${url}" failed.`}});if(dep)addRunDependency();};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn);var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true;}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn);}if(onload)onload();removeRunDependency();}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency();})){return}finish(byteArray);}addRunDependency();if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror);}else {processData(url);}};var FS_modeStringToFlags=str=>{var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return {path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return {path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent;}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node;},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next;}else {var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next;}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node);},isRoot(node){return node===node.parent},isMountpoint(node){return !!node.mounted},isFile(mode){return (mode&61440)===32768},isDir(mode){return (mode&61440)===16384},isLink(mode){return (mode&61440)===40960},isChrdev(mode){return (mode&61440)===8192},isBlkdev(mode){return (mode&61440)===24576},isFIFO(mode){return (mode&61440)===4096},isSocket(mode){return (mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w";}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name);}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else {if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){if(!FS.FSStream){FS.FSStream=function(){this.shared={};};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get(){return this.node},set(val){this.node=val;}},isRead:{get(){return (this.flags&2097155)!==1}},isWrite:{get(){return (this.flags&2097155)!==0}},isAppend:{get(){return this.flags&1024}},flags:{get(){return this.shared.flags},set(val){this.shared.flags=val;}},position:{get(){return this.shared.position},set(val){this.shared.position=val;}}});}stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd();}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null;},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream);}},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops};},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts);}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false;}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null);}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done);});},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot;}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount);}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current);}current=next;}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1);},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;i0,ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0);}else if(opts.encoding==="binary"){ret=buf;}FS.close(stream);return ret},writeFile(path,data,opts={}){opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn);}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn);}else {throw new Error("Unsupported data type")}FS.close(stream);},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path;},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user");},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength;}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp");},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd");},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"]);}else {FS.symlink("/dev/tty","/dev/stdin");}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"]);}else {FS.symlink("/dev/tty","/dev/stdout");}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"]);}else {FS.symlink("/dev/tty1","/dev/stderr");}FS.open("/dev/stdin",0);FS.open("/dev/stdout",1);FS.open("/dev/stderr",1);},ensureErrnoError(){if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno;};this.setErrno(errno);this.message="FS error";};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack="";});},staticInit(){FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS};},init(input,output,error){FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams();},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter;};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined");}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end);}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed");}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true;};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength();}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength();}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray};}else {var properties={isDevice:false,url:url};}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents;}else if(properties.url){node.contents=null;node.url=properties.url;}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)};});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return {ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd();}else {var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path;}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){try{var stat=func(path);}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return -54}throw e}HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags);},varargs:undefined,get(){var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret},getp(){return SYSCALLS.get()},getStr(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream}};function ___syscall_chmod(path,mode){try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return -28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return -44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return -2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var setErrNo=value=>{HEAP32[___errno_location()>>2]=value;return value};function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return -28}while(FS.streams[arg]){arg++;}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.getp();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return -28;case 9:setErrNo(28);return -1;default:{return -28}}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function ___syscall_ftruncate64(fd,length_low,length_high){var length=convertI32PairToI53Checked(length_low,length_high);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function ___syscall_getcwd(buf,size){try{if(size===0)return -28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(sizeHEAPU32[ptr>>2]+HEAP32[ptr+4>>2]*4294967296;function ___syscall_utimensat(dirfd,path,times,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);if(!times){var atime=Date.now();var mtime=atime;}else {var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>2];atime=seconds*1e3+nanoseconds/(1e3*1e3);times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>2];mtime=seconds*1e3+nanoseconds/(1e3*1e3);}FS.utime(path,atime,mtime);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst;}function __mmap_js(len,prot,flags,fd,offset_low,offset_high,allocated,addr){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset_low,offset_high){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset);}FS.munmap(stream);}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};var __tzset_js=(timezone,daylight,tzname)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=stringToNewUTF8(winterName);var summerNamePtr=stringToNewUTF8(summerName);if(summerOffset>2]=winterNamePtr;HEAPU32[tzname+4>>2]=summerNamePtr;}else {HEAPU32[tzname>>2]=summerNamePtr;HEAPU32[tzname+4>>2]=winterNamePtr;}};var _emscripten_date_now=()=>Date.now();var _emscripten_get_now;_emscripten_get_now=()=>performance.now();var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x];}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`);}getEnvStrings.strings=strings;}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>0]=str.charCodeAt(i);}HEAP8[buffer>>0]=0;};var _environ_get=(__environ,environ_buf)=>{var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1;});return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4;}HEAP8[pbuf>>0]=type;HEAP16[pbuf+2>>1]=flags;tempI64=[rightsBase>>>0,(tempDouble=rightsBase,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+8>>2]=tempI64[0],HEAP32[pbuf+12>>2]=tempI64[1];tempI64=[rightsInheriting>>>0,(tempDouble=rightsInheriting,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+16>>2]=tempI64[0],HEAP32[pbuf+20>>2]=tempI64[1];return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return -1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops&&stream.stream_ops.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return -1;ret+=curr;}return ret};function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var adapters_support=function(){const handleAsync=typeof Asyncify==="object"?Asyncify.handleAsync.bind(Asyncify):null;Module["handleAsync"]=handleAsync;const targets=new Map;Module["setCallback"]=(key,target)=>targets.set(key,target);Module["getCallback"]=key=>targets.get(key);Module["deleteCallback"]=key=>targets.delete(key);adapters_support=function(isAsync,key,...args){const receiver=targets.get(key);let methodName=null;const f=typeof receiver==="function"?receiver:receiver[methodName=UTF8ToString(args.shift())];if(isAsync){if(handleAsync){return handleAsync(()=>f.apply(receiver,args))}throw new Error("Synchronous WebAssembly cannot call async function")}const result=f.apply(receiver,args);if(typeof result?.then=="function"){console.error("unexpected Promise",f);throw new Error(`${methodName} unexpectedly returned a Promise`)}return result};};function _ipp(...args){return adapters_support(false,...args)}function _ipp_async(...args){return adapters_support(true,...args)}function _ippipppp(...args){return adapters_support(false,...args)}function _ippipppp_async(...args){return adapters_support(true,...args)}function _ippp(...args){return adapters_support(false,...args)}function _ippp_async(...args){return adapters_support(true,...args)}function _ipppi(...args){return adapters_support(false,...args)}function _ipppi_async(...args){return adapters_support(true,...args)}function _ipppiii(...args){return adapters_support(false,...args)}function _ipppiii_async(...args){return adapters_support(true,...args)}function _ipppiiip(...args){return adapters_support(false,...args)}function _ipppiiip_async(...args){return adapters_support(true,...args)}function _ipppip(...args){return adapters_support(false,...args)}function _ipppip_async(...args){return adapters_support(true,...args)}function _ipppj(...args){return adapters_support(false,...args)}function _ipppj_async(...args){return adapters_support(true,...args)}function _ipppp(...args){return adapters_support(false,...args)}function _ipppp_async(...args){return adapters_support(true,...args)}function _ippppi(...args){return adapters_support(false,...args)}function _ippppi_async(...args){return adapters_support(true,...args)}function _ippppij(...args){return adapters_support(false,...args)}function _ippppij_async(...args){return adapters_support(true,...args)}function _ippppip(...args){return adapters_support(false,...args)}function _ippppip_async(...args){return adapters_support(true,...args)}function _ipppppip(...args){return adapters_support(false,...args)}function _ipppppip_async(...args){return adapters_support(true,...args)}function _vppp(...args){return adapters_support(false,...args)}function _vppp_async(...args){return adapters_support(true,...args)}function _vpppip(...args){return adapters_support(false,...args)}function _vpppip_async(...args){return adapters_support(true,...args)}var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true;}quit_(code,new ExitStatus(code));};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status);};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e);};var uleb128Encode=(n,target)=>{if(n<128){target.push(n);}else {target.push(n%128|128,n>>7);}};var sigToWasmTypes=sig=>{var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64","e":"externref","p":"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var sigRet=sig.slice(0,1);var sigParam=sig.slice(1);var typeCodes={"i":127,"p":127,"j":126,"f":125,"d":124,"e":111};target.push(96);uleb128Encode(sigParam.length,target);for(var i=0;i{if(typeof WebAssembly.Function=="function"){return new WebAssembly.Function(sigToWasmTypes(sig),func)}var typeSectionBody=[1];generateFuncType(sig,typeSectionBody);var bytes=[0,97,115,109,1,0,0,0,1];uleb128Encode(typeSectionBody.length,bytes);bytes.push.apply(bytes,typeSectionBody);bytes.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);var module=new WebAssembly.Module(new Uint8Array(bytes));var instance=new WebAssembly.Instance(module,{"e":{"f":func}});var wrappedFunc=instance.exports["f"];return wrappedFunc};var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var updateTableMap=(offset,count)=>{if(functionsInTableMap){for(var i=offset;i{if(!functionsInTableMap){functionsInTableMap=new WeakMap;updateTableMap(0,wasmTable.length);}return functionsInTableMap.get(func)||0};var freeTableIndexes=[];var getEmptyTableSlot=()=>{if(freeTableIndexes.length){return freeTableIndexes.pop()}try{wasmTable.grow(1);}catch(err){if(!(err instanceof RangeError)){throw err}throw "Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."}return wasmTable.length-1};var setWasmTableEntry=(idx,func)=>wasmTable.set(idx,func);var addFunction=(func,sig)=>{var rtn=getFunctionAddress(func);if(rtn){return rtn}var ret=getEmptyTableSlot();try{setWasmTableEntry(ret,func);}catch(err){if(!(err instanceof TypeError)){throw err}var wrapped=convertJsFunctionToWasm(func,sig);setWasmTableEntry(ret,wrapped);}functionsInTableMap.set(func,ret);return ret};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer);};var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={"string":str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str);}return ret},"array":arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return function(){return ccall(ident,returnType,argTypes,arguments)}};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647;}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2;}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647;}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023;}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var AsciiToString=ptr=>{var str="";while(1){var ch=HEAPU8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch);}};var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit);}return str};var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023);}else {str+=String.fromCharCode(utf32);}}return str};function intArrayToString(array){var ret=[];for(var i=0;i255){chr&=255;}ret.push(String.fromCharCode(chr));}return ret.join("")}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this;}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev;};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return (this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode;}},write:{get:function(){return (this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode;}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();adapters_support();var wasmImports={a:___assert_fail,Y:___syscall_chmod,$:___syscall_faccessat,Z:___syscall_fchmod,X:___syscall_fchown32,b:___syscall_fcntl64,W:___syscall_fstat64,y:___syscall_ftruncate64,Q:___syscall_getcwd,U:___syscall_lstat64,N:___syscall_mkdirat,T:___syscall_newfstatat,M:___syscall_openat,K:___syscall_readlinkat,J:___syscall_rmdir,V:___syscall_stat64,G:___syscall_unlinkat,F:___syscall_utimensat,w:__localtime_js,u:__mmap_js,v:__munmap_js,H:__tzset_js,n:_emscripten_date_now,m:_emscripten_get_now,D:_emscripten_resize_heap,O:_environ_get,P:_environ_sizes_get,o:_fd_close,E:_fd_fdstat_get,L:_fd_read,x:_fd_seek,S:_fd_sync,I:_fd_write,s:_ipp,t:_ipp_async,fa:_ippipppp,ia:_ippipppp_async,i:_ippp,j:_ippp_async,c:_ipppi,d:_ipppi_async,ca:_ipppiii,da:_ipppiii_async,ea:_ipppiiip,ga:_ipppiiip_async,g:_ipppip,h:_ipppip_async,z:_ipppj,A:_ipppj_async,e:_ipppp,f:_ipppp_async,aa:_ippppi,ba:_ippppi_async,B:_ippppij,C:_ippppij_async,p:_ippppip,q:_ippppip_async,ha:_ipppppip,r:_ipppppip_async,k:_vppp,l:_vppp_async,R:_vpppip,_:_vpppip_async};var wasmExports=createWasm();Module["_sqlite3_status64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_status64"]=wasmExports["la"])(a0,a1,a2,a3);Module["_sqlite3_status"]=(a0,a1,a2,a3)=>(Module["_sqlite3_status"]=wasmExports["ma"])(a0,a1,a2,a3);Module["_sqlite3_db_status"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_db_status"]=wasmExports["na"])(a0,a1,a2,a3,a4);Module["_sqlite3_msize"]=a0=>(Module["_sqlite3_msize"]=wasmExports["oa"])(a0);Module["_sqlite3_vfs_find"]=a0=>(Module["_sqlite3_vfs_find"]=wasmExports["pa"])(a0);Module["_sqlite3_vfs_register"]=(a0,a1)=>(Module["_sqlite3_vfs_register"]=wasmExports["qa"])(a0,a1);Module["_sqlite3_vfs_unregister"]=a0=>(Module["_sqlite3_vfs_unregister"]=wasmExports["ra"])(a0);Module["_sqlite3_release_memory"]=a0=>(Module["_sqlite3_release_memory"]=wasmExports["sa"])(a0);Module["_sqlite3_soft_heap_limit64"]=(a0,a1)=>(Module["_sqlite3_soft_heap_limit64"]=wasmExports["ta"])(a0,a1);Module["_sqlite3_memory_used"]=()=>(Module["_sqlite3_memory_used"]=wasmExports["ua"])();Module["_sqlite3_hard_heap_limit64"]=(a0,a1)=>(Module["_sqlite3_hard_heap_limit64"]=wasmExports["va"])(a0,a1);Module["_sqlite3_memory_highwater"]=a0=>(Module["_sqlite3_memory_highwater"]=wasmExports["wa"])(a0);Module["_sqlite3_malloc"]=a0=>(Module["_sqlite3_malloc"]=wasmExports["xa"])(a0);Module["_sqlite3_malloc64"]=(a0,a1)=>(Module["_sqlite3_malloc64"]=wasmExports["ya"])(a0,a1);Module["_sqlite3_free"]=a0=>(Module["_sqlite3_free"]=wasmExports["za"])(a0);Module["_sqlite3_realloc"]=(a0,a1)=>(Module["_sqlite3_realloc"]=wasmExports["Aa"])(a0,a1);Module["_sqlite3_realloc64"]=(a0,a1,a2)=>(Module["_sqlite3_realloc64"]=wasmExports["Ba"])(a0,a1,a2);Module["_sqlite3_str_vappendf"]=(a0,a1,a2)=>(Module["_sqlite3_str_vappendf"]=wasmExports["Ca"])(a0,a1,a2);Module["_sqlite3_str_append"]=(a0,a1,a2)=>(Module["_sqlite3_str_append"]=wasmExports["Da"])(a0,a1,a2);Module["_sqlite3_str_appendchar"]=(a0,a1,a2)=>(Module["_sqlite3_str_appendchar"]=wasmExports["Ea"])(a0,a1,a2);Module["_sqlite3_str_appendall"]=(a0,a1)=>(Module["_sqlite3_str_appendall"]=wasmExports["Fa"])(a0,a1);Module["_sqlite3_str_appendf"]=(a0,a1,a2)=>(Module["_sqlite3_str_appendf"]=wasmExports["Ga"])(a0,a1,a2);Module["_sqlite3_str_finish"]=a0=>(Module["_sqlite3_str_finish"]=wasmExports["Ha"])(a0);Module["_sqlite3_str_errcode"]=a0=>(Module["_sqlite3_str_errcode"]=wasmExports["Ia"])(a0);Module["_sqlite3_str_length"]=a0=>(Module["_sqlite3_str_length"]=wasmExports["Ja"])(a0);Module["_sqlite3_str_value"]=a0=>(Module["_sqlite3_str_value"]=wasmExports["Ka"])(a0);Module["_sqlite3_str_reset"]=a0=>(Module["_sqlite3_str_reset"]=wasmExports["La"])(a0);Module["_sqlite3_str_new"]=a0=>(Module["_sqlite3_str_new"]=wasmExports["Ma"])(a0);Module["_sqlite3_vmprintf"]=(a0,a1)=>(Module["_sqlite3_vmprintf"]=wasmExports["Na"])(a0,a1);Module["_sqlite3_mprintf"]=(a0,a1)=>(Module["_sqlite3_mprintf"]=wasmExports["Oa"])(a0,a1);Module["_sqlite3_vsnprintf"]=(a0,a1,a2,a3)=>(Module["_sqlite3_vsnprintf"]=wasmExports["Pa"])(a0,a1,a2,a3);Module["_sqlite3_snprintf"]=(a0,a1,a2,a3)=>(Module["_sqlite3_snprintf"]=wasmExports["Qa"])(a0,a1,a2,a3);Module["_sqlite3_log"]=(a0,a1,a2)=>(Module["_sqlite3_log"]=wasmExports["Ra"])(a0,a1,a2);Module["_sqlite3_randomness"]=(a0,a1)=>(Module["_sqlite3_randomness"]=wasmExports["Sa"])(a0,a1);Module["_sqlite3_stricmp"]=(a0,a1)=>(Module["_sqlite3_stricmp"]=wasmExports["Ta"])(a0,a1);Module["_sqlite3_strnicmp"]=(a0,a1,a2)=>(Module["_sqlite3_strnicmp"]=wasmExports["Ua"])(a0,a1,a2);Module["_sqlite3_os_init"]=()=>(Module["_sqlite3_os_init"]=wasmExports["Va"])();Module["_sqlite3_os_end"]=()=>(Module["_sqlite3_os_end"]=wasmExports["Wa"])();Module["_sqlite3_serialize"]=(a0,a1,a2,a3)=>(Module["_sqlite3_serialize"]=wasmExports["Xa"])(a0,a1,a2,a3);Module["_sqlite3_prepare_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare_v2"]=wasmExports["Ya"])(a0,a1,a2,a3,a4);Module["_sqlite3_step"]=a0=>(Module["_sqlite3_step"]=wasmExports["Za"])(a0);Module["_sqlite3_column_int64"]=(a0,a1)=>(Module["_sqlite3_column_int64"]=wasmExports["_a"])(a0,a1);Module["_sqlite3_reset"]=a0=>(Module["_sqlite3_reset"]=wasmExports["$a"])(a0);Module["_sqlite3_exec"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_exec"]=wasmExports["ab"])(a0,a1,a2,a3,a4);Module["_sqlite3_column_int"]=(a0,a1)=>(Module["_sqlite3_column_int"]=wasmExports["bb"])(a0,a1);Module["_sqlite3_finalize"]=a0=>(Module["_sqlite3_finalize"]=wasmExports["cb"])(a0);Module["_sqlite3_deserialize"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_deserialize"]=wasmExports["db"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_database_file_object"]=a0=>(Module["_sqlite3_database_file_object"]=wasmExports["eb"])(a0);Module["_sqlite3_backup_init"]=(a0,a1,a2,a3)=>(Module["_sqlite3_backup_init"]=wasmExports["fb"])(a0,a1,a2,a3);Module["_sqlite3_backup_step"]=(a0,a1)=>(Module["_sqlite3_backup_step"]=wasmExports["gb"])(a0,a1);Module["_sqlite3_backup_finish"]=a0=>(Module["_sqlite3_backup_finish"]=wasmExports["hb"])(a0);Module["_sqlite3_backup_remaining"]=a0=>(Module["_sqlite3_backup_remaining"]=wasmExports["ib"])(a0);Module["_sqlite3_backup_pagecount"]=a0=>(Module["_sqlite3_backup_pagecount"]=wasmExports["jb"])(a0);Module["_sqlite3_clear_bindings"]=a0=>(Module["_sqlite3_clear_bindings"]=wasmExports["kb"])(a0);Module["_sqlite3_value_blob"]=a0=>(Module["_sqlite3_value_blob"]=wasmExports["lb"])(a0);Module["_sqlite3_value_text"]=a0=>(Module["_sqlite3_value_text"]=wasmExports["mb"])(a0);Module["_sqlite3_value_bytes"]=a0=>(Module["_sqlite3_value_bytes"]=wasmExports["nb"])(a0);Module["_sqlite3_value_bytes16"]=a0=>(Module["_sqlite3_value_bytes16"]=wasmExports["ob"])(a0);Module["_sqlite3_value_double"]=a0=>(Module["_sqlite3_value_double"]=wasmExports["pb"])(a0);Module["_sqlite3_value_int"]=a0=>(Module["_sqlite3_value_int"]=wasmExports["qb"])(a0);Module["_sqlite3_value_int64"]=a0=>(Module["_sqlite3_value_int64"]=wasmExports["rb"])(a0);Module["_sqlite3_value_subtype"]=a0=>(Module["_sqlite3_value_subtype"]=wasmExports["sb"])(a0);Module["_sqlite3_value_pointer"]=(a0,a1)=>(Module["_sqlite3_value_pointer"]=wasmExports["tb"])(a0,a1);Module["_sqlite3_value_text16"]=a0=>(Module["_sqlite3_value_text16"]=wasmExports["ub"])(a0);Module["_sqlite3_value_text16be"]=a0=>(Module["_sqlite3_value_text16be"]=wasmExports["vb"])(a0);Module["_sqlite3_value_text16le"]=a0=>(Module["_sqlite3_value_text16le"]=wasmExports["wb"])(a0);Module["_sqlite3_value_type"]=a0=>(Module["_sqlite3_value_type"]=wasmExports["xb"])(a0);Module["_sqlite3_value_encoding"]=a0=>(Module["_sqlite3_value_encoding"]=wasmExports["yb"])(a0);Module["_sqlite3_value_nochange"]=a0=>(Module["_sqlite3_value_nochange"]=wasmExports["zb"])(a0);Module["_sqlite3_value_frombind"]=a0=>(Module["_sqlite3_value_frombind"]=wasmExports["Ab"])(a0);Module["_sqlite3_value_dup"]=a0=>(Module["_sqlite3_value_dup"]=wasmExports["Bb"])(a0);Module["_sqlite3_value_free"]=a0=>(Module["_sqlite3_value_free"]=wasmExports["Cb"])(a0);Module["_sqlite3_result_blob"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_blob"]=wasmExports["Db"])(a0,a1,a2,a3);Module["_sqlite3_result_blob64"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_result_blob64"]=wasmExports["Eb"])(a0,a1,a2,a3,a4);Module["_sqlite3_result_double"]=(a0,a1)=>(Module["_sqlite3_result_double"]=wasmExports["Fb"])(a0,a1);Module["_sqlite3_result_error"]=(a0,a1,a2)=>(Module["_sqlite3_result_error"]=wasmExports["Gb"])(a0,a1,a2);Module["_sqlite3_result_error16"]=(a0,a1,a2)=>(Module["_sqlite3_result_error16"]=wasmExports["Hb"])(a0,a1,a2);Module["_sqlite3_result_int"]=(a0,a1)=>(Module["_sqlite3_result_int"]=wasmExports["Ib"])(a0,a1);Module["_sqlite3_result_int64"]=(a0,a1,a2)=>(Module["_sqlite3_result_int64"]=wasmExports["Jb"])(a0,a1,a2);Module["_sqlite3_result_null"]=a0=>(Module["_sqlite3_result_null"]=wasmExports["Kb"])(a0);Module["_sqlite3_result_pointer"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_pointer"]=wasmExports["Lb"])(a0,a1,a2,a3);Module["_sqlite3_result_subtype"]=(a0,a1)=>(Module["_sqlite3_result_subtype"]=wasmExports["Mb"])(a0,a1);Module["_sqlite3_result_text"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text"]=wasmExports["Nb"])(a0,a1,a2,a3);Module["_sqlite3_result_text64"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_result_text64"]=wasmExports["Ob"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_result_text16"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16"]=wasmExports["Pb"])(a0,a1,a2,a3);Module["_sqlite3_result_text16be"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16be"]=wasmExports["Qb"])(a0,a1,a2,a3);Module["_sqlite3_result_text16le"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16le"]=wasmExports["Rb"])(a0,a1,a2,a3);Module["_sqlite3_result_value"]=(a0,a1)=>(Module["_sqlite3_result_value"]=wasmExports["Sb"])(a0,a1);Module["_sqlite3_result_error_toobig"]=a0=>(Module["_sqlite3_result_error_toobig"]=wasmExports["Tb"])(a0);Module["_sqlite3_result_zeroblob"]=(a0,a1)=>(Module["_sqlite3_result_zeroblob"]=wasmExports["Ub"])(a0,a1);Module["_sqlite3_result_zeroblob64"]=(a0,a1,a2)=>(Module["_sqlite3_result_zeroblob64"]=wasmExports["Vb"])(a0,a1,a2);Module["_sqlite3_result_error_code"]=(a0,a1)=>(Module["_sqlite3_result_error_code"]=wasmExports["Wb"])(a0,a1);Module["_sqlite3_result_error_nomem"]=a0=>(Module["_sqlite3_result_error_nomem"]=wasmExports["Xb"])(a0);Module["_sqlite3_user_data"]=a0=>(Module["_sqlite3_user_data"]=wasmExports["Yb"])(a0);Module["_sqlite3_context_db_handle"]=a0=>(Module["_sqlite3_context_db_handle"]=wasmExports["Zb"])(a0);Module["_sqlite3_vtab_nochange"]=a0=>(Module["_sqlite3_vtab_nochange"]=wasmExports["_b"])(a0);Module["_sqlite3_vtab_in_first"]=(a0,a1)=>(Module["_sqlite3_vtab_in_first"]=wasmExports["$b"])(a0,a1);Module["_sqlite3_vtab_in_next"]=(a0,a1)=>(Module["_sqlite3_vtab_in_next"]=wasmExports["ac"])(a0,a1);Module["_sqlite3_aggregate_context"]=(a0,a1)=>(Module["_sqlite3_aggregate_context"]=wasmExports["bc"])(a0,a1);Module["_sqlite3_get_auxdata"]=(a0,a1)=>(Module["_sqlite3_get_auxdata"]=wasmExports["cc"])(a0,a1);Module["_sqlite3_set_auxdata"]=(a0,a1,a2,a3)=>(Module["_sqlite3_set_auxdata"]=wasmExports["dc"])(a0,a1,a2,a3);Module["_sqlite3_column_count"]=a0=>(Module["_sqlite3_column_count"]=wasmExports["ec"])(a0);Module["_sqlite3_data_count"]=a0=>(Module["_sqlite3_data_count"]=wasmExports["fc"])(a0);Module["_sqlite3_column_blob"]=(a0,a1)=>(Module["_sqlite3_column_blob"]=wasmExports["gc"])(a0,a1);Module["_sqlite3_column_bytes"]=(a0,a1)=>(Module["_sqlite3_column_bytes"]=wasmExports["hc"])(a0,a1);Module["_sqlite3_column_bytes16"]=(a0,a1)=>(Module["_sqlite3_column_bytes16"]=wasmExports["ic"])(a0,a1);Module["_sqlite3_column_double"]=(a0,a1)=>(Module["_sqlite3_column_double"]=wasmExports["jc"])(a0,a1);Module["_sqlite3_column_text"]=(a0,a1)=>(Module["_sqlite3_column_text"]=wasmExports["kc"])(a0,a1);Module["_sqlite3_column_value"]=(a0,a1)=>(Module["_sqlite3_column_value"]=wasmExports["lc"])(a0,a1);Module["_sqlite3_column_text16"]=(a0,a1)=>(Module["_sqlite3_column_text16"]=wasmExports["mc"])(a0,a1);Module["_sqlite3_column_type"]=(a0,a1)=>(Module["_sqlite3_column_type"]=wasmExports["nc"])(a0,a1);Module["_sqlite3_column_name"]=(a0,a1)=>(Module["_sqlite3_column_name"]=wasmExports["oc"])(a0,a1);Module["_sqlite3_column_name16"]=(a0,a1)=>(Module["_sqlite3_column_name16"]=wasmExports["pc"])(a0,a1);Module["_sqlite3_bind_blob"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_blob"]=wasmExports["qc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_blob64"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_bind_blob64"]=wasmExports["rc"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_bind_double"]=(a0,a1,a2)=>(Module["_sqlite3_bind_double"]=wasmExports["sc"])(a0,a1,a2);Module["_sqlite3_bind_int"]=(a0,a1,a2)=>(Module["_sqlite3_bind_int"]=wasmExports["tc"])(a0,a1,a2);Module["_sqlite3_bind_int64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_bind_int64"]=wasmExports["uc"])(a0,a1,a2,a3);Module["_sqlite3_bind_null"]=(a0,a1)=>(Module["_sqlite3_bind_null"]=wasmExports["vc"])(a0,a1);Module["_sqlite3_bind_pointer"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_pointer"]=wasmExports["wc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_text"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_text"]=wasmExports["xc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_text64"]=(a0,a1,a2,a3,a4,a5,a6)=>(Module["_sqlite3_bind_text64"]=wasmExports["yc"])(a0,a1,a2,a3,a4,a5,a6);Module["_sqlite3_bind_text16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_text16"]=wasmExports["zc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_value"]=(a0,a1,a2)=>(Module["_sqlite3_bind_value"]=wasmExports["Ac"])(a0,a1,a2);Module["_sqlite3_bind_zeroblob"]=(a0,a1,a2)=>(Module["_sqlite3_bind_zeroblob"]=wasmExports["Bc"])(a0,a1,a2);Module["_sqlite3_bind_zeroblob64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_bind_zeroblob64"]=wasmExports["Cc"])(a0,a1,a2,a3);Module["_sqlite3_bind_parameter_count"]=a0=>(Module["_sqlite3_bind_parameter_count"]=wasmExports["Dc"])(a0);Module["_sqlite3_bind_parameter_name"]=(a0,a1)=>(Module["_sqlite3_bind_parameter_name"]=wasmExports["Ec"])(a0,a1);Module["_sqlite3_bind_parameter_index"]=(a0,a1)=>(Module["_sqlite3_bind_parameter_index"]=wasmExports["Fc"])(a0,a1);Module["_sqlite3_db_handle"]=a0=>(Module["_sqlite3_db_handle"]=wasmExports["Gc"])(a0);Module["_sqlite3_stmt_readonly"]=a0=>(Module["_sqlite3_stmt_readonly"]=wasmExports["Hc"])(a0);Module["_sqlite3_stmt_isexplain"]=a0=>(Module["_sqlite3_stmt_isexplain"]=wasmExports["Ic"])(a0);Module["_sqlite3_stmt_explain"]=(a0,a1)=>(Module["_sqlite3_stmt_explain"]=wasmExports["Jc"])(a0,a1);Module["_sqlite3_stmt_busy"]=a0=>(Module["_sqlite3_stmt_busy"]=wasmExports["Kc"])(a0);Module["_sqlite3_next_stmt"]=(a0,a1)=>(Module["_sqlite3_next_stmt"]=wasmExports["Lc"])(a0,a1);Module["_sqlite3_stmt_status"]=(a0,a1,a2)=>(Module["_sqlite3_stmt_status"]=wasmExports["Mc"])(a0,a1,a2);Module["_sqlite3_sql"]=a0=>(Module["_sqlite3_sql"]=wasmExports["Nc"])(a0);Module["_sqlite3_expanded_sql"]=a0=>(Module["_sqlite3_expanded_sql"]=wasmExports["Oc"])(a0);Module["_sqlite3_value_numeric_type"]=a0=>(Module["_sqlite3_value_numeric_type"]=wasmExports["Pc"])(a0);Module["_sqlite3_blob_open"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_blob_open"]=wasmExports["Qc"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_blob_close"]=a0=>(Module["_sqlite3_blob_close"]=wasmExports["Rc"])(a0);Module["_sqlite3_blob_read"]=(a0,a1,a2,a3)=>(Module["_sqlite3_blob_read"]=wasmExports["Sc"])(a0,a1,a2,a3);Module["_sqlite3_blob_write"]=(a0,a1,a2,a3)=>(Module["_sqlite3_blob_write"]=wasmExports["Tc"])(a0,a1,a2,a3);Module["_sqlite3_blob_bytes"]=a0=>(Module["_sqlite3_blob_bytes"]=wasmExports["Uc"])(a0);Module["_sqlite3_blob_reopen"]=(a0,a1,a2)=>(Module["_sqlite3_blob_reopen"]=wasmExports["Vc"])(a0,a1,a2);Module["_sqlite3_set_authorizer"]=(a0,a1,a2)=>(Module["_sqlite3_set_authorizer"]=wasmExports["Wc"])(a0,a1,a2);Module["_sqlite3_strglob"]=(a0,a1)=>(Module["_sqlite3_strglob"]=wasmExports["Xc"])(a0,a1);Module["_sqlite3_strlike"]=(a0,a1,a2)=>(Module["_sqlite3_strlike"]=wasmExports["Yc"])(a0,a1,a2);Module["_sqlite3_errmsg"]=a0=>(Module["_sqlite3_errmsg"]=wasmExports["Zc"])(a0);Module["_sqlite3_auto_extension"]=a0=>(Module["_sqlite3_auto_extension"]=wasmExports["_c"])(a0);Module["_sqlite3_cancel_auto_extension"]=a0=>(Module["_sqlite3_cancel_auto_extension"]=wasmExports["$c"])(a0);Module["_sqlite3_reset_auto_extension"]=()=>(Module["_sqlite3_reset_auto_extension"]=wasmExports["ad"])();Module["_sqlite3_prepare"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare"]=wasmExports["bd"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare_v3"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_prepare_v3"]=wasmExports["cd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_prepare16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare16"]=wasmExports["dd"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare16_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare16_v2"]=wasmExports["ed"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare16_v3"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_prepare16_v3"]=wasmExports["fd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_get_table"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_get_table"]=wasmExports["gd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_free_table"]=a0=>(Module["_sqlite3_free_table"]=wasmExports["hd"])(a0);Module["_sqlite3_create_module"]=(a0,a1,a2,a3)=>(Module["_sqlite3_create_module"]=wasmExports["id"])(a0,a1,a2,a3);Module["_sqlite3_create_module_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_module_v2"]=wasmExports["jd"])(a0,a1,a2,a3,a4);Module["_sqlite3_drop_modules"]=(a0,a1)=>(Module["_sqlite3_drop_modules"]=wasmExports["kd"])(a0,a1);Module["_sqlite3_declare_vtab"]=(a0,a1)=>(Module["_sqlite3_declare_vtab"]=wasmExports["ld"])(a0,a1);Module["_sqlite3_vtab_on_conflict"]=a0=>(Module["_sqlite3_vtab_on_conflict"]=wasmExports["md"])(a0);Module["_sqlite3_vtab_config"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_config"]=wasmExports["nd"])(a0,a1,a2);Module["_sqlite3_vtab_collation"]=(a0,a1)=>(Module["_sqlite3_vtab_collation"]=wasmExports["od"])(a0,a1);Module["_sqlite3_vtab_in"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_in"]=wasmExports["pd"])(a0,a1,a2);Module["_sqlite3_vtab_rhs_value"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_rhs_value"]=wasmExports["qd"])(a0,a1,a2);Module["_sqlite3_vtab_distinct"]=a0=>(Module["_sqlite3_vtab_distinct"]=wasmExports["rd"])(a0);Module["_sqlite3_keyword_name"]=(a0,a1,a2)=>(Module["_sqlite3_keyword_name"]=wasmExports["sd"])(a0,a1,a2);Module["_sqlite3_keyword_count"]=()=>(Module["_sqlite3_keyword_count"]=wasmExports["td"])();Module["_sqlite3_keyword_check"]=(a0,a1)=>(Module["_sqlite3_keyword_check"]=wasmExports["ud"])(a0,a1);Module["_sqlite3_complete"]=a0=>(Module["_sqlite3_complete"]=wasmExports["vd"])(a0);Module["_sqlite3_complete16"]=a0=>(Module["_sqlite3_complete16"]=wasmExports["wd"])(a0);Module["_sqlite3_libversion"]=()=>(Module["_sqlite3_libversion"]=wasmExports["xd"])();Module["_sqlite3_libversion_number"]=()=>(Module["_sqlite3_libversion_number"]=wasmExports["yd"])();Module["_sqlite3_threadsafe"]=()=>(Module["_sqlite3_threadsafe"]=wasmExports["zd"])();Module["_sqlite3_initialize"]=()=>(Module["_sqlite3_initialize"]=wasmExports["Ad"])();Module["_sqlite3_shutdown"]=()=>(Module["_sqlite3_shutdown"]=wasmExports["Bd"])();Module["_sqlite3_config"]=(a0,a1)=>(Module["_sqlite3_config"]=wasmExports["Cd"])(a0,a1);Module["_sqlite3_db_mutex"]=a0=>(Module["_sqlite3_db_mutex"]=wasmExports["Dd"])(a0);Module["_sqlite3_db_release_memory"]=a0=>(Module["_sqlite3_db_release_memory"]=wasmExports["Ed"])(a0);Module["_sqlite3_db_cacheflush"]=a0=>(Module["_sqlite3_db_cacheflush"]=wasmExports["Fd"])(a0);Module["_sqlite3_db_config"]=(a0,a1,a2)=>(Module["_sqlite3_db_config"]=wasmExports["Gd"])(a0,a1,a2);Module["_sqlite3_last_insert_rowid"]=a0=>(Module["_sqlite3_last_insert_rowid"]=wasmExports["Hd"])(a0);Module["_sqlite3_set_last_insert_rowid"]=(a0,a1,a2)=>(Module["_sqlite3_set_last_insert_rowid"]=wasmExports["Id"])(a0,a1,a2);Module["_sqlite3_changes64"]=a0=>(Module["_sqlite3_changes64"]=wasmExports["Jd"])(a0);Module["_sqlite3_changes"]=a0=>(Module["_sqlite3_changes"]=wasmExports["Kd"])(a0);Module["_sqlite3_total_changes64"]=a0=>(Module["_sqlite3_total_changes64"]=wasmExports["Ld"])(a0);Module["_sqlite3_total_changes"]=a0=>(Module["_sqlite3_total_changes"]=wasmExports["Md"])(a0);Module["_sqlite3_txn_state"]=(a0,a1)=>(Module["_sqlite3_txn_state"]=wasmExports["Nd"])(a0,a1);Module["_sqlite3_close"]=a0=>(Module["_sqlite3_close"]=wasmExports["Od"])(a0);Module["_sqlite3_close_v2"]=a0=>(Module["_sqlite3_close_v2"]=wasmExports["Pd"])(a0);Module["_sqlite3_busy_handler"]=(a0,a1,a2)=>(Module["_sqlite3_busy_handler"]=wasmExports["Qd"])(a0,a1,a2);Module["_sqlite3_progress_handler"]=(a0,a1,a2,a3)=>(Module["_sqlite3_progress_handler"]=wasmExports["Rd"])(a0,a1,a2,a3);Module["_sqlite3_busy_timeout"]=(a0,a1)=>(Module["_sqlite3_busy_timeout"]=wasmExports["Sd"])(a0,a1);Module["_sqlite3_interrupt"]=a0=>(Module["_sqlite3_interrupt"]=wasmExports["Td"])(a0);Module["_sqlite3_is_interrupted"]=a0=>(Module["_sqlite3_is_interrupted"]=wasmExports["Ud"])(a0);Module["_sqlite3_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_create_function"]=wasmExports["Vd"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_create_function_v2"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(Module["_sqlite3_create_function_v2"]=wasmExports["Wd"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);Module["_sqlite3_create_window_function"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(Module["_sqlite3_create_window_function"]=wasmExports["Xd"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);Module["_sqlite3_create_function16"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_create_function16"]=wasmExports["Yd"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_overload_function"]=(a0,a1,a2)=>(Module["_sqlite3_overload_function"]=wasmExports["Zd"])(a0,a1,a2);Module["_sqlite3_trace_v2"]=(a0,a1,a2,a3)=>(Module["_sqlite3_trace_v2"]=wasmExports["_d"])(a0,a1,a2,a3);Module["_sqlite3_commit_hook"]=(a0,a1,a2)=>(Module["_sqlite3_commit_hook"]=wasmExports["$d"])(a0,a1,a2);Module["_sqlite3_update_hook"]=(a0,a1,a2)=>(Module["_sqlite3_update_hook"]=wasmExports["ae"])(a0,a1,a2);Module["_sqlite3_rollback_hook"]=(a0,a1,a2)=>(Module["_sqlite3_rollback_hook"]=wasmExports["be"])(a0,a1,a2);Module["_sqlite3_autovacuum_pages"]=(a0,a1,a2,a3)=>(Module["_sqlite3_autovacuum_pages"]=wasmExports["ce"])(a0,a1,a2,a3);Module["_sqlite3_wal_autocheckpoint"]=(a0,a1)=>(Module["_sqlite3_wal_autocheckpoint"]=wasmExports["de"])(a0,a1);Module["_sqlite3_wal_hook"]=(a0,a1,a2)=>(Module["_sqlite3_wal_hook"]=wasmExports["ee"])(a0,a1,a2);Module["_sqlite3_wal_checkpoint_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_wal_checkpoint_v2"]=wasmExports["fe"])(a0,a1,a2,a3,a4);Module["_sqlite3_wal_checkpoint"]=(a0,a1)=>(Module["_sqlite3_wal_checkpoint"]=wasmExports["ge"])(a0,a1);Module["_sqlite3_error_offset"]=a0=>(Module["_sqlite3_error_offset"]=wasmExports["he"])(a0);Module["_sqlite3_errmsg16"]=a0=>(Module["_sqlite3_errmsg16"]=wasmExports["ie"])(a0);Module["_sqlite3_errcode"]=a0=>(Module["_sqlite3_errcode"]=wasmExports["je"])(a0);Module["_sqlite3_extended_errcode"]=a0=>(Module["_sqlite3_extended_errcode"]=wasmExports["ke"])(a0);Module["_sqlite3_system_errno"]=a0=>(Module["_sqlite3_system_errno"]=wasmExports["le"])(a0);Module["_sqlite3_errstr"]=a0=>(Module["_sqlite3_errstr"]=wasmExports["me"])(a0);Module["_sqlite3_limit"]=(a0,a1,a2)=>(Module["_sqlite3_limit"]=wasmExports["ne"])(a0,a1,a2);Module["_sqlite3_open"]=(a0,a1)=>(Module["_sqlite3_open"]=wasmExports["oe"])(a0,a1);Module["_sqlite3_open_v2"]=(a0,a1,a2,a3)=>(Module["_sqlite3_open_v2"]=wasmExports["pe"])(a0,a1,a2,a3);Module["_sqlite3_open16"]=(a0,a1)=>(Module["_sqlite3_open16"]=wasmExports["qe"])(a0,a1);Module["_sqlite3_create_collation"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_collation"]=wasmExports["re"])(a0,a1,a2,a3,a4);Module["_sqlite3_create_collation_v2"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_create_collation_v2"]=wasmExports["se"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_create_collation16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_collation16"]=wasmExports["te"])(a0,a1,a2,a3,a4);Module["_sqlite3_collation_needed"]=(a0,a1,a2)=>(Module["_sqlite3_collation_needed"]=wasmExports["ue"])(a0,a1,a2);Module["_sqlite3_collation_needed16"]=(a0,a1,a2)=>(Module["_sqlite3_collation_needed16"]=wasmExports["ve"])(a0,a1,a2);Module["_sqlite3_get_clientdata"]=(a0,a1)=>(Module["_sqlite3_get_clientdata"]=wasmExports["we"])(a0,a1);Module["_sqlite3_set_clientdata"]=(a0,a1,a2,a3)=>(Module["_sqlite3_set_clientdata"]=wasmExports["xe"])(a0,a1,a2,a3);Module["_sqlite3_get_autocommit"]=a0=>(Module["_sqlite3_get_autocommit"]=wasmExports["ye"])(a0);Module["_sqlite3_table_column_metadata"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(Module["_sqlite3_table_column_metadata"]=wasmExports["ze"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);Module["_sqlite3_sleep"]=a0=>(Module["_sqlite3_sleep"]=wasmExports["Ae"])(a0);Module["_sqlite3_extended_result_codes"]=(a0,a1)=>(Module["_sqlite3_extended_result_codes"]=wasmExports["Be"])(a0,a1);Module["_sqlite3_file_control"]=(a0,a1,a2,a3)=>(Module["_sqlite3_file_control"]=wasmExports["Ce"])(a0,a1,a2,a3);Module["_sqlite3_test_control"]=(a0,a1)=>(Module["_sqlite3_test_control"]=wasmExports["De"])(a0,a1);Module["_sqlite3_create_filename"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_filename"]=wasmExports["Ee"])(a0,a1,a2,a3,a4);Module["_sqlite3_free_filename"]=a0=>(Module["_sqlite3_free_filename"]=wasmExports["Fe"])(a0);Module["_sqlite3_uri_parameter"]=(a0,a1)=>(Module["_sqlite3_uri_parameter"]=wasmExports["Ge"])(a0,a1);Module["_sqlite3_uri_key"]=(a0,a1)=>(Module["_sqlite3_uri_key"]=wasmExports["He"])(a0,a1);Module["_sqlite3_uri_boolean"]=(a0,a1,a2)=>(Module["_sqlite3_uri_boolean"]=wasmExports["Ie"])(a0,a1,a2);Module["_sqlite3_uri_int64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_uri_int64"]=wasmExports["Je"])(a0,a1,a2,a3);Module["_sqlite3_filename_database"]=a0=>(Module["_sqlite3_filename_database"]=wasmExports["Ke"])(a0);Module["_sqlite3_filename_journal"]=a0=>(Module["_sqlite3_filename_journal"]=wasmExports["Le"])(a0);Module["_sqlite3_filename_wal"]=a0=>(Module["_sqlite3_filename_wal"]=wasmExports["Me"])(a0);Module["_sqlite3_db_name"]=(a0,a1)=>(Module["_sqlite3_db_name"]=wasmExports["Ne"])(a0,a1);Module["_sqlite3_db_filename"]=(a0,a1)=>(Module["_sqlite3_db_filename"]=wasmExports["Oe"])(a0,a1);Module["_sqlite3_db_readonly"]=(a0,a1)=>(Module["_sqlite3_db_readonly"]=wasmExports["Pe"])(a0,a1);Module["_sqlite3_compileoption_used"]=a0=>(Module["_sqlite3_compileoption_used"]=wasmExports["Qe"])(a0);Module["_sqlite3_compileoption_get"]=a0=>(Module["_sqlite3_compileoption_get"]=wasmExports["Re"])(a0);Module["_sqlite3_sourceid"]=()=>(Module["_sqlite3_sourceid"]=wasmExports["Se"])();var ___errno_location=()=>(___errno_location=wasmExports["Te"])();var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["Ue"])(a0);Module["_free"]=a0=>(Module["_free"]=wasmExports["Ve"])(a0);Module["_RegisterExtensionFunctions"]=a0=>(Module["_RegisterExtensionFunctions"]=wasmExports["We"])(a0);Module["_getSqliteFree"]=()=>(Module["_getSqliteFree"]=wasmExports["Xe"])();var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["Ye"])(a0,a1);Module["_libauthorizer_set_authorizer"]=(a0,a1,a2)=>(Module["_libauthorizer_set_authorizer"]=wasmExports["Ze"])(a0,a1,a2);Module["_libfunction_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_libfunction_create_function"]=wasmExports["_e"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_libprogress_progress_handler"]=(a0,a1,a2,a3)=>(Module["_libprogress_progress_handler"]=wasmExports["$e"])(a0,a1,a2,a3);Module["_libvfs_vfs_register"]=(a0,a1,a2,a3,a4,a5)=>(Module["_libvfs_vfs_register"]=wasmExports["af"])(a0,a1,a2,a3,a4,a5);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["cf"])(a0,a1);var getTempRet0=()=>(getTempRet0=wasmExports["df"])();var stackSave=()=>(stackSave=wasmExports["ef"])();var stackRestore=a0=>(stackRestore=wasmExports["ff"])(a0);var stackAlloc=a0=>(stackAlloc=wasmExports["gf"])(a0);Module["_sqlite3_version"]=3232;Module["getTempRet0"]=getTempRet0;Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["addFunction"]=addFunction;Module["setValue"]=setValue;Module["getValue"]=getValue;Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;Module["intArrayFromString"]=intArrayFromString;Module["intArrayToString"]=intArrayToString;Module["AsciiToString"]=AsciiToString;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;Module["UTF32ToString"]=UTF32ToString;Module["stringToUTF32"]=stringToUTF32;Module["writeArrayToMemory"]=writeArrayToMemory;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller;};function callMain(){var entryFunction=_main;var argc=0;var argv=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain();postRun();}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("");},1);doRun();},1);}else {doRun();}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()();}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;let pAsyncFlags=0;Module["set_authorizer"]=function(db,xAuthorizer,pApp){if(pAsyncFlags){Module["deleteCallback"](pAsyncFlags);Module["_sqlite3_free"](pAsyncFlags);pAsyncFlags=0;}pAsyncFlags=Module["_sqlite3_malloc"](4);setValue(pAsyncFlags,xAuthorizer instanceof AsyncFunction?1:0,"i32");const result=ccall("libauthorizer_set_authorizer","number",["number","number","number"],[db,xAuthorizer?1:0,pAsyncFlags]);if(!result&&xAuthorizer){Module["setCallback"](pAsyncFlags,(_,iAction,p3,p4,p5,p6)=>xAuthorizer(pApp,iAction,p3,p4,p5,p6));}return result};})();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;const FUNC_METHODS=["xFunc","xStep","xFinal"];const mapFunctionNameToKey=new Map;Module["create_function"]=function(db,zFunctionName,nArg,eTextRep,pApp,xFunc,xStep,xFinal){const pAsyncFlags=Module["_sqlite3_malloc"](4);const target={xFunc:xFunc,xStep:xStep,xFinal:xFinal};setValue(pAsyncFlags,FUNC_METHODS.reduce((mask,method,i)=>{if(target[method]instanceof AsyncFunction){return mask|1<xProgress(pApp));}};})();(function(){const VFS_METHODS=["xOpen","xDelete","xAccess","xFullPathname","xRandomness","xSleep","xCurrentTime","xGetLastError","xCurrentTimeInt64","xClose","xRead","xWrite","xTruncate","xSync","xFileSize","xLock","xUnlock","xCheckReservedLock","xFileControl","xSectorSize","xDeviceCharacteristics","xShmMap","xShmLock","xShmBarrier","xShmUnmap"];const mapVFSNameToKey=new Map;Module["vfs_register"]=function(vfs,makeDefault){let methodMask=0;let asyncMask=0;VFS_METHODS.forEach((method,i)=>{if(vfs[method]){methodMask|=1< { + async (context, values) => { const table_name = this.sqlite3.value_text(values[0]); - this.sqlite3.exec( + await this.sqlite3.exec( context, `CREATE TRIGGER __diesel_manage_updated_at_${table_name} AFTER UPDATE ON ${table_name} @@ -3037,6 +3099,8 @@ class SQLite { }, ); } catch (error) { + console.log("error creating diesel trigger"); + throw error; } } diff --git a/diesel-wasm-sqlite/tests/web.rs b/diesel-wasm-sqlite/tests/web.rs index b8a3a28a5..da34cc14b 100755 --- a/diesel-wasm-sqlite/tests/web.rs +++ b/diesel-wasm-sqlite/tests/web.rs @@ -1,10 +1,179 @@ +#![recursion_limit = "256"] #![cfg(target_arch = "wasm32")] -use diesel::connection::Connection; -use diesel_wasm_sqlite::connection::{AsyncConnection, WasmSqliteConnection}; +use diesel_async::RunQueryDsl; +use diesel_wasm_sqlite::{ + connection::{AsyncConnection, SimpleAsyncConnection, WasmSqliteConnection}, + WasmSqlite, DebugQueryWrapper +}; +use diesel_migrations::embed_migrations; +use diesel_migrations::EmbeddedMigrations; use wasm_bindgen_test::*; use web_sys::console; + +use chrono::{NaiveDate, NaiveDateTime}; +use diesel::debug_query; +use diesel::insert_into; +use diesel::prelude::*; +use serde::Deserialize; +use std::error::Error; + wasm_bindgen_test_configure!(run_in_dedicated_worker); + +pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/web/migrations/"); + +mod schema { + diesel::table! { + books { + id -> Integer, + title -> Text, + author -> Nullable, + // published_year -> Timestamp, + } + } +} + +use schema::books; + +#[derive(Deserialize, Insertable, Debug, PartialEq, Clone)] +#[diesel(table_name = books)] +pub struct BookForm { + title: String, + author: Option, + // published_year: NaiveDateTime, +} + +#[derive(Queryable, Selectable, PartialEq, Debug)] +pub struct Book { + id: i32, + title: String, + author: Option, + // published_year: NaiveDateTime, +} + +async fn establish_connection() -> WasmSqliteConnection { + let rng: u16 = rand::random(); + let result = WasmSqliteConnection::establish(&format!("test-{}", rng)).await; + let mut conn = result.unwrap(); + // conn.run_pending_migrations(MIGRATIONS); + //TODO: we can use `embed_migrations` to run our migrations + + conn.batch_execute( + " + CREATE TABLE books ( + id INTEGER PRIMARY KEY, + title TEXT NOT NULL, + author TEXT + ) + ", + ) + .await + .expect("Batch exec failed to run"); + conn +} + +async fn insert_books( + conn: &mut WasmSqliteConnection, + new_books: Vec, +) -> QueryResult { + use schema::books::dsl::*; + let query = insert_into(books).values(new_books); + let sql = DebugQueryWrapper::<_, WasmSqlite>::new(&query).to_string(); + tracing::info!("QUERY = {}", sql); + let rows_changed = query.execute(conn).await.unwrap(); + Ok(rows_changed) +} + + +async fn insert_book( + conn: &mut WasmSqliteConnection, + new_book: BookForm, +) -> QueryResult { + use schema::books::dsl::*; + let query = insert_into(books).values(new_book); + let sql = debug_query::(&query).to_string(); + tracing::info!("QUERY = {}", sql); + let rows_changed = query.execute(conn).await.unwrap(); + Ok(rows_changed) +} + +#[wasm_bindgen_test] +fn examine_sql_from_insert_default_values() { + use schema::books::dsl::*; + + let query = insert_into(books).default_values(); + let sql = "INSERT INTO `books` DEFAULT VALUES -- binds: []"; + assert_eq!(sql, debug_query::(&query).to_string()); + console::log_1(&debug_query::(&query).to_string().into()); +} + +#[wasm_bindgen_test] +async fn test_orm_insert() { + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + + let mut conn = establish_connection().await; + + let changed = insert_books( + &mut conn, + vec![ + BookForm { + title: "Game of Thrones".into(), + author: Some("George R.R".into()), + // published_year: NaiveDate::from_ymd_opt(2015, 5, 3).unwrap(), + }, + BookForm { + title: "The Hobbit".into(), + author: Some("J.R.R. Tolkien".into()), + // published_year: NaiveDate::from_ymd_opt(1937, 9, 21).unwrap(), + }, + BookForm { + title: "To Kill a Mockingbird".into(), + author: Some("Harper Lee".into()), + // published_year: NaiveDate::from_ymd_opt(1960, 7, 11).unwrap(), + }, + BookForm { + title: "1984".into(), + author: Some("George Orwell".into()), + // published_year: NaiveDate::from_ymd_opt(1949, 6, 8).unwrap(), + }, + BookForm { + title: "Pride and Prejudice".into(), + author: Some("Jane Austen".into()), + // published_year: NaiveDate::from_ymd_opt(1813, 1, 28).unwrap(), + }, + BookForm { + title: "Moby-Dick".into(), + author: Some("Herman Melville".into()), + // published_year: NaiveDate::from_ymd_opt(1851, 10, 18).unwrap(), + }, + ], + ) + .await.unwrap(); + assert_eq!(rows_changed, 6); + tracing::info!("{} rows changed", changed); + console::log_1(&"Showing Users".into()); + + let books = schema::books::table + .limit(5) + .select(Book::as_select()) + .load(&mut conn) + .await + .unwrap(); + tracing::info!("BOOKS??? {:?}----------", books); + + // console::log_1(&debug_query::(&query).to_string().into()); + // .load(&mut conn) + // .await + // .expect("Error loading users"); + + /* + for book in books { + console::log_1(&format!("{}", book.title).into()); + } + */ +} + /* #[wasm_bindgen_test] async fn test_establish_and_exec() { diff --git a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/down.sql b/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/down.sql new file mode 100644 index 000000000..a865c73a8 --- /dev/null +++ b/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/down.sql @@ -0,0 +1 @@ +DROP TABLE books diff --git a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql b/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql new file mode 100644 index 000000000..e6b55d875 --- /dev/null +++ b/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql @@ -0,0 +1,7 @@ +-- Your SQL goes here + +CREATE TABLE books ( + id SERIAL PRIMARY KEY, + title TEXT NOT NULL, + author TEXT, +) diff --git a/diesel-wasm-sqlite/yarn.lock b/diesel-wasm-sqlite/yarn.lock index 59311254a..4986db559 100644 --- a/diesel-wasm-sqlite/yarn.lock +++ b/diesel-wasm-sqlite/yarn.lock @@ -123,114 +123,114 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.19.0" +"@rollup/rollup-android-arm-eabi@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.21.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-android-arm64@npm:4.19.0" +"@rollup/rollup-android-arm64@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-android-arm64@npm:4.21.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.19.0" +"@rollup/rollup-darwin-arm64@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.21.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.19.0" +"@rollup/rollup-darwin-x64@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.21.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.19.0" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.21.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.19.0" +"@rollup/rollup-linux-arm-musleabihf@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.21.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.19.0" +"@rollup/rollup-linux-arm64-gnu@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.21.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.19.0" +"@rollup/rollup-linux-arm64-musl@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.21.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.19.0" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.19.0" +"@rollup/rollup-linux-riscv64-gnu@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.21.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.19.0" +"@rollup/rollup-linux-s390x-gnu@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.21.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.19.0" +"@rollup/rollup-linux-x64-gnu@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.21.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.19.0" +"@rollup/rollup-linux-x64-musl@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.21.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.19.0" +"@rollup/rollup-win32-arm64-msvc@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.21.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.19.0" +"@rollup/rollup-win32-ia32-msvc@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.21.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.19.0": - version: 4.19.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.19.0" +"@rollup/rollup-win32-x64-msvc@npm:4.21.0": + version: 4.21.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.21.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -276,11 +276,11 @@ __metadata: linkType: hard "@types/node@npm:*": - version: 20.14.11 - resolution: "@types/node@npm:20.14.11" + version: 22.4.1 + resolution: "@types/node@npm:22.4.1" dependencies: - undici-types: "npm:~5.26.4" - checksum: 10/344e1ce1ed16c86ed1c4209ab4d1de67db83dd6b694a6fabe295c47144dde2c58dabddae9f39a0a2bdd246e95f8d141ccfe848e464884b48b8918df4f7788025 + undici-types: "npm:~6.19.2" + checksum: 10/cce9221aea24688bccc3d7c25afd26d95c1bdab73a32ee5c43bb456e070116abf6ba537a9ff19c728bc06fe054e69a2c7ec8e5d818e34a3bf9567eae2cb20059 languageName: node linkType: hard @@ -291,15 +291,15 @@ __metadata: languageName: node linkType: hard -"@xmtp/wa-sqlite@npm:^1.0.1": - version: 1.0.1 - resolution: "@xmtp/wa-sqlite@npm:1.0.1" +"@xmtp/wa-sqlite@npm:>=1.0.3": + version: 1.0.3 + resolution: "@xmtp/wa-sqlite@npm:1.0.3" dependenciesMeta: monaco-editor@0.34.1: unplugged: true web-test-runner-jasmine@0.0.6: unplugged: true - checksum: 10/bd08dd04fb98fef2f791274a502f6227c2050c92fdce288576d68c5e864efea2653217cfef73f134ed27999e90ad7300a64a1ab8344eeb9e9c6c2f802b7a7c64 + checksum: 10/16f0a79ea4a6a39ae3c38bddf20a83d8ca990a1366800c315059c28f0c712d127c76c64144a87757648343785bd1106096d92288fa6c5b3f97a9d3c81c5e6047 languageName: node linkType: hard @@ -484,14 +484,14 @@ __metadata: linkType: hard "debug@npm:4, debug@npm:^4.3.4": - version: 4.3.5 - resolution: "debug@npm:4.3.5" + version: 4.3.6 + resolution: "debug@npm:4.3.6" dependencies: ms: "npm:2.1.2" peerDependenciesMeta: supports-color: optional: true - checksum: 10/cb6eab424c410e07813ca1392888589972ce9a32b8829c6508f5e1f25f3c3e70a76731610ae55b4bbe58d1a2fffa1424b30e97fa8d394e49cd2656a9643aedd2 + checksum: 10/d3adb9af7d57a9e809a68f404490cf776122acca16e6359a2702c0f462e510e91f9765c07f707b8ab0d91e03bad57328f3256f5082631cefb5393d0394d50fb7 languageName: node linkType: hard @@ -507,7 +507,7 @@ __metadata: resolution: "diesel-wasm-sqlite@workspace:." dependencies: "@rollup/plugin-node-resolve": "npm:^15.2.3" - "@xmtp/wa-sqlite": "npm:^1.0.1" + "@xmtp/wa-sqlite": "npm:>=1.0.3" rollup: "npm:^4.19.0" rollup-plugin-base64: "npm:^1.0.1" rollup-plugin-copy: "npm:^3.5.0" @@ -620,12 +620,12 @@ __metadata: linkType: hard "foreground-child@npm:^3.1.0": - version: 3.2.1 - resolution: "foreground-child@npm:3.2.1" + version: 3.3.0 + resolution: "foreground-child@npm:3.3.0" dependencies: cross-spawn: "npm:^7.0.0" signal-exit: "npm:^4.0.1" - checksum: 10/77b33b3c438a499201727ca84de39a66350ccd54a8805df712773e963cefb5c4632dbc4386109e97a0df8fb1585aee95fa35acb07587e3e04cfacabfc0ae15dc + checksum: 10/e3a60480f3a09b12273ce2c5fcb9514d98dd0e528f58656a1b04680225f918d60a2f81f6a368f2f3b937fcee9cfc0cbf16f1ad9a0bc6a3a6e103a84c9a90087e languageName: node linkType: hard @@ -799,9 +799,9 @@ __metadata: linkType: hard "ignore@npm:^5.1.1": - version: 5.3.1 - resolution: "ignore@npm:5.3.1" - checksum: 10/0a884c2fbc8c316f0b9f92beaf84464253b73230a4d4d286697be45fca081199191ca33e1c2e82d9e5f851f5e9a48a78e25a35c951e7eb41e59f150db3530065 + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10/cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98 languageName: node linkType: hard @@ -1318,25 +1318,25 @@ __metadata: linkType: hard "rollup@npm:^4.19.0": - version: 4.19.0 - resolution: "rollup@npm:4.19.0" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.19.0" - "@rollup/rollup-android-arm64": "npm:4.19.0" - "@rollup/rollup-darwin-arm64": "npm:4.19.0" - "@rollup/rollup-darwin-x64": "npm:4.19.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.19.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.19.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.19.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.19.0" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.19.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.19.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.19.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.19.0" - "@rollup/rollup-linux-x64-musl": "npm:4.19.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.19.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.19.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.19.0" + version: 4.21.0 + resolution: "rollup@npm:4.21.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.21.0" + "@rollup/rollup-android-arm64": "npm:4.21.0" + "@rollup/rollup-darwin-arm64": "npm:4.21.0" + "@rollup/rollup-darwin-x64": "npm:4.21.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.21.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.21.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.21.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.21.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.21.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.21.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.21.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.21.0" + "@rollup/rollup-linux-x64-musl": "npm:4.21.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.21.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.21.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.21.0" "@types/estree": "npm:1.0.5" fsevents: "npm:~2.3.2" dependenciesMeta: @@ -1376,7 +1376,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/a5f56e60d160e727f372fb0b0adbab03c1e5b858df7af62e626459687e6510d5b9685e4badef50bb6ffd916eaf53c1684a8e12ae959dacb8e6930c77a00a0f19 + checksum: 10/27ac47d5049719249d2a44982e31f01423158a3625cabff2f2362219aee64bdc14c32572b669169c22c324c3a965044ce8f06e27eee00fd8802861cd13697f87 languageName: node linkType: hard @@ -1549,10 +1549,10 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~5.26.4": - version: 5.26.5 - resolution: "undici-types@npm:5.26.5" - checksum: 10/0097779d94bc0fd26f0418b3a05472410408877279141ded2bd449167be1aed7ea5b76f756562cb3586a07f251b90799bab22d9019ceba49c037c76445f7cddd +"undici-types@npm:~6.19.2": + version: 6.19.8 + resolution: "undici-types@npm:6.19.8" + checksum: 10/cf0b48ed4fc99baf56584afa91aaffa5010c268b8842f62e02f752df209e3dea138b372a60a963b3b2576ed932f32329ce7ddb9cb5f27a6c83040d8cd74b7a70 languageName: node linkType: hard From f1274c09b0cbb5da9e3af3ae031bfb1c4f24af54 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 26 Aug 2024 11:09:12 -0400 Subject: [PATCH 04/97] Use sqlite.org/sqlite, revert to sync api (#988) * use official sqlite bindings * PORTED * can establish conn * getters/setters * constant from JS workaround * r2d2 connection * add custom allocator for faster memory * memory optimization, tests * clean up dependencies * clean * workflow * readme * dep pruning * readme change * readme --- .github/workflows/test-wasm.yml | 32 + diesel-wasm-sqlite/.vscode/settings.json | 1 + diesel-wasm-sqlite/Cargo.lock | 226 +- diesel-wasm-sqlite/Cargo.toml | 27 +- diesel-wasm-sqlite/README.md | 95 +- diesel-wasm-sqlite/package.js | 325 +- diesel-wasm-sqlite/package.json | 4 +- diesel-wasm-sqlite/rollup.config.js | 12 +- diesel-wasm-sqlite/src/backend.rs | 2 +- .../src/connection/bind_collector.rs | 20 +- diesel-wasm-sqlite/src/connection/err.rs | 42 + .../src/connection/functions.rs | 6 +- diesel-wasm-sqlite/src/connection/mod.rs | 288 +- diesel-wasm-sqlite/src/connection/raw.rs | 97 +- diesel-wasm-sqlite/src/connection/row.rs | 239 +- .../src/connection/sqlite_value.rs | 99 +- .../src/connection/statement_iterator.rs | 159 + .../src/connection/statement_stream.rs | 199 - diesel-wasm-sqlite/src/connection/stmt.rs | 422 +- diesel-wasm-sqlite/src/ffi.rs | 339 +- diesel-wasm-sqlite/src/ffi/constants.rs | 180 + diesel-wasm-sqlite/src/ffi/wasm.rs | 65 + diesel-wasm-sqlite/src/lib.rs | 56 +- .../insert_with_default_sqlite.rs | 117 +- .../src/sqlite3-opfs-async-proxy.js | 692 + diesel-wasm-sqlite/src/sqlite_types.rs | 77 - diesel-wasm-sqlite/src/sqlite_types/to_sql.rs | 56 +- diesel-wasm-sqlite/src/utils.rs | 11 +- .../src/wa-sqlite-diesel-bundle.js | 17127 +++++++++++++--- diesel-wasm-sqlite/tests/row.rs | 210 + diesel-wasm-sqlite/tests/web.rs | 141 +- .../2024-08-20-203551_create_books/up.sql | 4 +- diesel-wasm-sqlite/yarn.lock | 68 +- 33 files changed, 16980 insertions(+), 4458 deletions(-) create mode 100644 .github/workflows/test-wasm.yml create mode 100644 diesel-wasm-sqlite/src/connection/err.rs create mode 100644 diesel-wasm-sqlite/src/connection/statement_iterator.rs delete mode 100644 diesel-wasm-sqlite/src/connection/statement_stream.rs create mode 100644 diesel-wasm-sqlite/src/ffi/constants.rs create mode 100644 diesel-wasm-sqlite/src/ffi/wasm.rs create mode 100644 diesel-wasm-sqlite/src/sqlite3-opfs-async-proxy.js create mode 100644 diesel-wasm-sqlite/tests/row.rs diff --git a/.github/workflows/test-wasm.yml b/.github/workflows/test-wasm.yml new file mode 100644 index 000000000..aa74e889e --- /dev/null +++ b/.github/workflows/test-wasm.yml @@ -0,0 +1,32 @@ +name: Test DIesel WASM Backend +on: + push: + branches: + - main + pull_request: + # only run tests when related changes are made + paths: + - ".github/workflows/test-workspace.yml" + - "dev/**" + - "diesel-wasm-sqlite/**" + - "Cargo.toml" + - "Cargo.lock" + - "rust-toolchain" +jobs: + test: + name: Test + runs-on: warp-ubuntu-latest-x64-16x + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Update rust toolchains + run: rustup update + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: Cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + . + - name: Run cargo test on main workspace + run: wasm-pack test --manifest-path diesel-wasm-sqlite/Cargo.toml --features test-util --features unsafe-debug-query diff --git a/diesel-wasm-sqlite/.vscode/settings.json b/diesel-wasm-sqlite/.vscode/settings.json index ae0d8b87d..7f7e17ce9 100644 --- a/diesel-wasm-sqlite/.vscode/settings.json +++ b/diesel-wasm-sqlite/.vscode/settings.json @@ -15,6 +15,7 @@ "ctor": ["ctor"], "tokio": ["test"], "diesel": ["table"], + "wasm-bindgen": ["wasm-bindgen"], } } }, diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index 2f769c28c..ae8ddc8bf 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -32,17 +32,6 @@ dependencies = [ "libc", ] -[[package]] -name = "async-trait" -version = "0.1.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "autocfg" version = "1.3.0" @@ -162,44 +151,30 @@ dependencies = [ [[package]] name = "diesel" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" +checksum = "65e13bab2796f412722112327f3e575601a3e9cdcbe426f0d30dbf43f3f5dc71" dependencies = [ "chrono", "diesel_derives", -] - -[[package]] -name = "diesel-async" -version = "0.5.0" -source = "git+https://github.com/insipx/diesel_async?branch=insipx/make-stmt-cache-public#3b771a153f66cb9cbb7e8fcd6d1a59d029f4368b" -dependencies = [ - "async-trait", - "diesel", - "futures-util", - "scoped-futures", + "r2d2", ] [[package]] name = "diesel-wasm-sqlite" version = "0.1.1" dependencies = [ - "async-trait", - "bitflags", "chrono", "console_error_panic_hook", "diesel", - "diesel-async", "diesel_derives", "diesel_migrations", - "futures", - "futures-util", "getrandom", "js-sys", "rand", "serde", "serde-wasm-bindgen", + "talc", "thiserror", "tokio", "tracing", @@ -275,95 +250,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -455,6 +341,16 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.22" @@ -522,16 +418,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "pin-project-lite" -version = "0.2.14" +name = "parking_lot" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] [[package]] -name = "pin-utils" -version = "0.1.0" +name = "pin-project-lite" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "ppv-lite86" @@ -560,6 +473,17 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + [[package]] name = "rand" version = "0.8.5" @@ -590,6 +514,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -597,13 +530,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] -name = "scoped-futures" -version = "0.1.3" +name = "scheduled-thread-pool" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "cfg-if", - "pin-utils", + "parking_lot", ] [[package]] @@ -612,6 +544,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" version = "1.0.204" @@ -662,13 +600,10 @@ dependencies = [ ] [[package]] -name = "slab" -version = "0.4.9" +name = "smallvec" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "strsim" @@ -687,6 +622,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "talc" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" +dependencies = [ + "lock_api", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -725,18 +669,6 @@ checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "pin-project-lite", - "tokio-macros", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn", ] [[package]] diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index f8d8149fe..e83253ce3 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -5,29 +5,20 @@ edition = "2021" resolver = "2" [dependencies] -# diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/wasm-backend", default-features = false, features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } +talc = { version = "4.4", default-features = false, features = ["lock_api"] } diesel = { version = "2.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } -diesel-async = { git = "https://github.com/insipx/diesel_async", branch = "insipx/make-stmt-cache-public", features = ["stmt-cache"] } diesel_derives = "2.2" wasm-bindgen = "0.2.92" -wasm-bindgen-futures = "0.4.42" -tracing = "0.1" -rand = "0.8" -getrandom = { version = "0.2", features = ["js"] } -web-sys = { version = "0.3", features = ["console"] } -js-sys = { version = "0.3" } -# wee_alloc = { version = "0.4.2", optional = true } -console_error_panic_hook = { version = "0.1", optional = true } -tokio = { version = "1.38", default-features = false, features = ["rt", "macros", "sync"] } -futures = "0.3" -futures-util = "0.3" -async-trait = "0.1" -bitflags = "2.6" -serde = { version = "1.0", features = ["derive"] } +wasm-bindgen-futures = "0.4" +js-sys = { version = "0.3" } +tracing = "0.1" +tokio = { version = "1.38", default-features = false, features = ["sync"] } +serde = { version = "1.0", default-features = false, features = ["derive"] } serde-wasm-bindgen = "0.6" thiserror = "1" [dev-dependencies] +console_error_panic_hook = { version = "0.1"} rand = "0.8" getrandom = { version = "0.2", features = ["js"] } wasm-bindgen-test = "0.3.42" @@ -42,10 +33,12 @@ tracing-wasm = { version = "0.2" } crate-type = ["cdylib", "rlib"] [features] -default = ["console_error_panic_hook"] +default = [] +r2d2 = ["diesel/r2d2"] # enables a `DebugQueryWrapper` for diesel # but is unsafe because of mem::transmute unsafe-debug-query = [] +test-util = ["unsafe-debug-query"] [build] target = "wasm32-unknown-unknown" diff --git a/diesel-wasm-sqlite/README.md b/diesel-wasm-sqlite/README.md index 8e1e4be42..d6bd44bc0 100644 --- a/diesel-wasm-sqlite/README.md +++ b/diesel-wasm-sqlite/README.md @@ -1,28 +1,95 @@ -# Custom Diesel Backend for Wasm wa-sqlite +# Diesel Backend for SQLite and WASM -### Compile rust code without creating a npm package +### Use SQLite with Diesel ORM in your web apps! -`cargo build --target wasm32-unknown-unknown` +## Quickstart -#### Build the JS WASM interfaces +add `diesel-wasm-sqlite` to your project. SQLite is automatically bundled with +the library. -`wasm-pack build` +```toml +[dependencies] +diesel = { version = "2.2" } +diesel-wasm-sqlite = { git = "https://github.com/xmtp/libxmtp", branch = "insipx/abandon-async" } +wasm-bindgen = "0.2" +``` -#### Run the Wasm Tests +```rust +use diesel_wasm_sqlite::{connection::WasmSqliteConnection, WasmSqlite}; +use wasm_bindgen::prelude::*; -wasm-pack test --chrome +pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/web/migrations/"); -navigate to `http://localhost:8000` to observe test output +mod schema { + diesel::table! { + books { + id -> Integer, + title -> Text, + author -> Nullable, + } + } +} + + +#[derive(Deserialize, Insertable, Debug, PartialEq, Clone)] +#[diesel(table_name = books)] +pub struct BookForm { + title: String, + author: Option, +} + +// SQLite must be instantiated in a web-worker +// to take advantage of OPFS +#[wasm_bindgen] +async fn code_in_web_worker() -> Result> { + use schema::books::dsl::*; + // `init_sqlite` sets up OPFS and SQLite. It must be ran before anything else, + // or we crash once we start trying to do queries. + diesel_wasm_sqlite::init_sqlite().await; + + // create a new persistent SQLite database with OPFS + let result = WasmSqliteConnection::establish(&format!("test-{}", rng)); + let query = insert_into(books).values(vec![ + BookForm { + title: "Game of Thrones".into(), + author: Some("George R.R".into()), + }, + BookForm { + title: "The Hobbit".into(), + author: Some("J.R.R. Tolkien".into()), + }, + ]); + Ok(query.execute(conn)?) +} +``` + +look in `tests/web.rs` for working example! + +## Development + +### Install yarn dependencies -(headless tests don't work yet) +`yarn install` + +### Build the SQLite/OPFS BUndle + +`yarn run build` + +### Build the rust code, and re-build `package.json` if it changed + +`cargo build --target wasm32-unknown-unknown` + +### Run Tests + +`wasm-pack test --safari --features unsafe-debug-query` + +navigate to `http://localhost:8000` to observe test output -# TODO +### Run Tests (headless) -- [ ] wa-sqlite should be included in `pkg` build w/o manual copy (wasm-pack - issue?) -- [ ] OPFS +`wasm-pack test --safari --headless` -# Setting up the project in VSCode +### Setting up the project in VSCode rust-analyzer does not like crates with different targets in the same workspace. If you want this to work well with your LSP, open `diesel-wasm-sqlite` as it's diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index ed1f73d14..d322767dc 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -1,298 +1,239 @@ -import * as WasmSQLiteLibrary from "@xmtp/wa-sqlite"; -import { OPFSCoopSyncVFS } from "@xmtp/wa-sqlite/vfs/OPFSCoopSync"; -import SQLiteESMFactory from "./node_modules/@xmtp/wa-sqlite/dist/wa-sqlite.mjs"; -import base64Wasm from "./node_modules/@xmtp/wa-sqlite/dist/wa-sqlite.wasm"; - -function base64Decode(str) { - const binaryString = typeof atob === "function" - ? atob(str) - : Buffer.from(str, "base64").toString("binary"); - const len = binaryString.length; - const bytes = new Uint8Array(len); - for (let i = 0; i < len; i++) { - bytes[i] = binaryString.charCodeAt(i); - } - return bytes.buffer; +import sqlite3InitModule from "@sqlite.org/sqlite-wasm"; + +const log = console.log; +const err_log = console.error; + +export class SQLiteError extends Error { + constructor(message, code) { + super(message); + this.code = code; + } } export class SQLite { #module; #sqlite3; - constructor(module) { - if (typeof module === "undefined") { - throw new Error("Cannot be called directly"); + constructor(sqlite3) { + if (typeof sqlite3 === "undefined") { + throw new Error( + "`sqliteObject` must be defined before calling constructor", + ); } - this.module = module; - this.sqlite3 = WasmSQLiteLibrary.Factory(module); + this.sqlite3 = sqlite3; } - static async wasm_module() { - return await SQLiteESMFactory({ - "wasmBinary": base64Decode(base64Wasm), + static async init_module(opts) { + return await sqlite3InitModule({ + print: log, + printErr: err_log, + ...opts, }); } - static async build() { - const module = await SQLiteESMFactory({ - "wasmBinary": base64Decode(base64Wasm), - }); - return new WasmSQLiteLibrary(module); + version() { + return this.sqlite3.version; + } + + extended_errcode(connection) { + return this.sqlite3.capi.sqlite3_extended_errcode(connection); + } + + errstr(code) { + return this.sqlite3.capi.sqlite3_errstr(code); + } + + errmsg(connection) { + return this.sqlite3.capi.sqlite3_errmsg(connection); + } + + result_js(context, value) { + return this.sqlite3.capi.sqlite3_result_js(context, value); } result_text(context, value) { - this.sqlite3.result_text(context, value); + return this.sqlite3.capi.sqlite3_result_text(context, value); } result_int(context, value) { - this.sqlite3.result_int(context, value); + return this.sqlite3.capi.sqlite3_result_int(context, value); } result_int64(context, value) { - this.sqlite3.result_int64(context, value); + return this.sqlite3.capi.sqlite3_result_int64(context, value); } result_double(context, value) { - this.sqlite3.result_double(context, value); + return this.sqlite3.capi.sqlite3_result_double(context, value); } result_blob(context, value) { - this.sqlite3.result_blob(context, value); + return this.sqlite3.capi.sqlite3_result_blob(context, value); } result_null(context) { - this.sqlite3.result_null(context); - } - - bind(stmt, i, value) { - try { - return this.sqlite3.bind(stmt, i, value); - } catch (error) { - console.log(`bind err ${error}`); - throw error; - } + return this.sqlite3.capi.sqlite3_result_null(context); } - bind_blob(stmt, i, value) { - try { - return this.sqlite3.bind_blob(stmt, i, value); - } catch (error) { - console.log("bind blob error"); - throw error; - } + bind_blob(stmt, i, value, len, flags) { + return this.sqlite3.capi.sqlite_bind_blob(stmt, i, value); } - bind_collection(stmt, bindings) { - try { - return this.sqlite3.bind_collection(stmt, bindings); - } catch (error) { - console.log("bind collection error"); - throw error; - } + bind_text(stmt, i, value, len, flags) { + return this.sqlite3.capi.sqlite3_bind_text(stmt, i, value, len, flags); } bind_double(stmt, i, value) { - try { - return this.sqlite3.bind_double(stmt, i, value); - } catch (error) { - console.log("bind double error"); - throw error; - } + return this.sqlite3.capi.sqlite3_bind_double(stmt, i, value); } bind_int(stmt, i, value) { - try { - return this.sqlite3.bind_int(stmt, i, value); - } catch (error) { - console.log("bind int error"); - throw error; - } + return this.sqlite3.capi.sqlite3_bind_int(stmt, i, value); } bind_int64(stmt, i, value) { - try { - return this.sqlite3.bind_int64(stmt, i, value); - } catch (error) { - console.log("bind int644 error"); - throw error; - } + return this.sqlite3.capi.sqlite3_bind_int64(stmt, i, value); } bind_null(stmt, i) { - try { - return this.sqlite3.bind_null(stmt, i); - } catch (error) { - console.log("bind null error"); - throw error; - } + this.sqlite3.capi.sqlite3_bind_null(stmt, i); + /// There's no way bind_null can fail. + return this.sqlite3.capi.SQLITE_OK; } bind_parameter_count(stmt) { - return this.sqlite3.bind_parameter_count(stmt); + return this.sqlite3.capi.sqlite3_bind_parameter_count(stmt); } bind_parameter_name(stmt, i) { - return this.sqlite3.bind_paramater_name(stmt, it); - } - - bind_text(stmt, i, value) { - try { - this.sqlite3.bind_text(stmt, i, value); - } catch (error) { - console.log("bind text error"); - throw error; - } - } - - async reset(stmt) { - try { - return await this.sqlite3.reset(stmt); - } catch (error) { - console.log("reset err"); - throw error; - } - } - - value(pValue) { - this.sqlite3.value(pValue); + return this.sqlite3.capi.sqlite3_bind_paramater_name(stmt, it); } value_dup(pValue) { - return this.module._sqlite3_value_dup(pValue); + return this.sqlite3.capi.sqlite3_value_dup(pValue); } value_blob(pValue) { - this.sqlite3.value_blob(pValue); + return this.sqlite3.capi.sqlite3_value_blob(pValue); } value_bytes(pValue) { - this.sqlite3.value_bytes(pValue); + return this.sqlite3.capi.sqlite3_value_bytes(pValue); } value_double(pValue) { - this.sqlite3.value_double(pValue); + return this.sqlite3.capi.sqlite3_value_double(pValue); } value_int(pValue) { - this.sqlite3.value_int(pValue); + return this.sqlite3.capi.sqlite3_value_int(pValue); } value_int64(pValue) { - this.sqlite3.value_int64(pValue); + return this.sqlite3.capi.sqlite3_value_int64(pValue); } value_text(pValue) { - this.sqlite3.value_text(pValue); + return this.sqlite3.capi.sqlite3_value_text(pValue); } value_type(pValue) { - return this.sqlite3.value_type(pValue); + return this.sqlite3.capi.sqlite3_value_type(pValue); } - async open_v2(database_url, iflags) { + open(database_url, iflags) { try { - console.log("Opening database!", database_url); - const vfs = await OPFSCoopSyncVFS.create(database_url, this.module); - this.sqlite3.vfs_register(vfs, true); - let db = await this.sqlite3.open_v2(database_url, iflags); + let db; + if (database_url === ":memory:") { + db = new this.sqlite3.oo1.DB("transient_in_memory_db:"); + console.log(`Created in-memory database`); + } else { + db = new this.sqlite3.oo1.OpfsDb(database_url); + console.log(`Created persistent database at ${db.filename}`); + } return db; } catch (error) { - console.log("openv2 error", error); + console.log("OPFS open error", error); throw error; } } - async exec(db, query) { + exec(db, query) { try { - return await this.sqlite3.exec(db, query, (row, columns) => { - console.log(row); + return db.exec(query, { + callback: (row) => { + log(`exec'd ${row}`); + }, }); } catch (error) { - console.log("exec err"); throw error; } } finalize(stmt) { - try { - return this.sqlite3.finalize(stmt); - } catch (error) { - console.log("stmt error"); - throw error; - } + return this.sqlite3.capi.sqlite3_finalize(stmt); } changes(db) { - return this.sqlite3.changes(db); + return this.sqlite3.capi.sqlite3_changes(db); } clear_bindings(stmt) { - try { - return this.sqlite3.clear_bindings(stmt); - } catch (error) { - console.log("sqlite3.clear_bindings error"); - throw error; - } + return this.sqlite3.capi.sqlite3_clear_bindings(stmt); } - async close(db) { - try { - return this.sqlite3.close(db); - } catch (error) { - console.log("sqlite3.close error"); - throw error; - } + reset(stmt) { + return this.sqlite3.capi.sqlite3_reset(stmt); } - column(stmt, i) { - return this.sqlite3.column(stmt, i); + close(db) { + return this.sqlite3.capi.sqlite3_close_v2(db.pointer); } - async prepare(database, sql, options) { - try { - return await this.sqlite3.statements(database, sql, options); - } catch (error) { - console.log("sqlite prepare error"); - throw error; - } + db_handle(stmt) { + return this.sqlite3.capi.sqlite3_db_handle(stmt); } - // there should be a way to do this from Rust - // If we pass the statement we get from 'next' - // it does not work. - async get_stmt_from_iterator(iterator) { - try { - const stmt = await iterator.next(); - return stmt; - } catch (error) { - console.log("sqlite prepare error"); - throw error; - } + prepare_v3(db, sql, nByte, prepFlags, ppStmt, pzTail) { + return this.sqlite3.capi.sqlite3_prepare_v3( + db.pointer, + sql, + nByte, + prepFlags, + ppStmt, + pzTail, + ); } - async step(stmt) { - try { - return await this.sqlite3.step(stmt); - } catch (error) { - console.log("sqlite step error"); - throw error; + into_statement(pStmt) { + const BindTypes = { + null: 1, + number: 2, + string: 3, + boolean: 4, + blob: 5, + }; + BindTypes["undefined"] == BindTypes.null; + if (wasm.bigIntEnabled) { + BindTypes.bigint = BindTypes.number; } + + new Stmt(this, pStmt, BindTypes); } - column_name(stmt, idx) { - return this.sqlite3.column_name(stmt, idx); + step(stmt) { + return this.sqlite3.capi.sqlite3_step(stmt); } - column_count(stmt) { - return this.sqlite3.column_count(stmt); + column_value(stmt, i) { + return this.sqlite3.capi.sqlite3_column_value(stmt, i); } - async batch_execute(database, query) { - try { - return await this.sqlite3.exec(database, query); - } catch (error) { - console.log("batch exec err"); - throw error; - } + column_name(stmt, idx) { + return this.sqlite3.capi.sqlite3_column_name(stmt, idx); + } + + column_count(stmt) { + return this.sqlite3.capi.sqlite3_column_count(stmt); } create_function( @@ -306,7 +247,7 @@ export class SQLite { xFinal, ) { try { - this.sqlite3.create_function( + this.sqlite3.capi.sqlite3_create_function( database, functionName, nArg, @@ -322,20 +263,21 @@ export class SQLite { throw error; } } + //TODO: At some point need a way to register functions from rust //but for just libxmtp this is fine. register_diesel_sql_functions(database) { try { - this.sqlite3.create_function( + this.sqlite3.capi.sqlite3_create_function( database, "diesel_manage_updated_at", 1, - WasmSQLiteLibrary.SQLITE_UTF8, + this.sqlite3.capi.SQLITE_UTF8, 0, async (context, values) => { const table_name = this.sqlite3.value_text(values[0]); - await this.sqlite3.exec( + database.exec( context, `CREATE TRIGGER __diesel_manage_updated_at_${table_name} AFTER UPDATE ON ${table_name} @@ -348,12 +290,11 @@ export class SQLite { SET updated_at = CURRENT_TIMESTAMP WHERE ROWID = new.ROWID; END`, - (row, columns) => { - console.log(`------------------------------------`); - console.log(`Created trigger for ${table_name}`); - console.log(row); - console.log(columns); - console.log(`------------------------------------`); + (row) => { + log(`------------------------------------`); + log(`Created trigger for ${table_name}`); + log(row); + log(`------------------------------------`); }, ); }, @@ -364,6 +305,10 @@ export class SQLite { } } + value_free(value) { + return this.sqlite3.capi.sqlite3_value_free(value); + } + /* serialize(database, zSchema, size, flags) { return this.module._sqlite3_serialize(database, zSchema, size, flags); diff --git a/diesel-wasm-sqlite/package.json b/diesel-wasm-sqlite/package.json index 040c0cece..f8d2b750c 100644 --- a/diesel-wasm-sqlite/package.json +++ b/diesel-wasm-sqlite/package.json @@ -8,7 +8,7 @@ "build": "rollup -c" }, "dependencies": { - "@xmtp/wa-sqlite": ">=1.0.3" + "@sqlite.org/sqlite-wasm": "latest" }, "packageManager": "yarn@4.3.1", "engines": { @@ -16,8 +16,8 @@ }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-typescript": "^11.1.6", "rollup": "^4.19.0", - "rollup-plugin-base64": "^1.0.1", "rollup-plugin-copy": "^3.5.0" } } diff --git a/diesel-wasm-sqlite/rollup.config.js b/diesel-wasm-sqlite/rollup.config.js index 7692eb6d7..1b4c72408 100644 --- a/diesel-wasm-sqlite/rollup.config.js +++ b/diesel-wasm-sqlite/rollup.config.js @@ -1,6 +1,5 @@ import { defineConfig } from "rollup"; import { nodeResolve } from "@rollup/plugin-node-resolve"; -import { base64 } from "rollup-plugin-base64"; export default defineConfig([ { @@ -11,8 +10,15 @@ export default defineConfig([ }, plugins: [ nodeResolve(), - base64({ include: "**/*.wasm" }), ], - // external: ["@xmtp/wa-sqlite", "@xmtp/wa-sqlite/build"], + // external: ["@sqlite.org/sqlite-wasm"], + }, + { + input: + "./node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-opfs-async-proxy.js", + output: { + file: "src/sqlite3-opfs-async-proxy.js", + format: "es", + }, }, ]); diff --git a/diesel-wasm-sqlite/src/backend.rs b/diesel-wasm-sqlite/src/backend.rs index e0afa56ff..f967dc273 100644 --- a/diesel-wasm-sqlite/src/backend.rs +++ b/diesel-wasm-sqlite/src/backend.rs @@ -39,7 +39,7 @@ pub enum SqliteType { impl Backend for WasmSqlite { type QueryBuilder = SqliteQueryBuilder; - type RawValue<'a> = SqliteValue<'a, 'a>; + type RawValue<'a> = SqliteValue<'a, 'a, 'a>; type BindCollector<'a> = SqliteBindCollector<'a>; } diff --git a/diesel-wasm-sqlite/src/connection/bind_collector.rs b/diesel-wasm-sqlite/src/connection/bind_collector.rs index 26ab3d4b5..13b1bae68 100644 --- a/diesel-wasm-sqlite/src/connection/bind_collector.rs +++ b/diesel-wasm-sqlite/src/connection/bind_collector.rs @@ -76,7 +76,7 @@ impl<'a> From<&'a str> for SqliteBindValue<'a> { impl<'a> From for SqliteBindValue<'a> { fn from(s: String) -> Self { Self { - inner: InternalSqliteBindValue::String(s.into_boxed_str()), + inner: InternalSqliteBindValue::String(s), } } } @@ -84,7 +84,7 @@ impl<'a> From for SqliteBindValue<'a> { impl<'a> From> for SqliteBindValue<'a> { fn from(b: Vec) -> Self { Self { - inner: InternalSqliteBindValue::Binary(b.into_boxed_slice()), + inner: InternalSqliteBindValue::Binary(b), } } } @@ -101,9 +101,9 @@ impl<'a> From<&'a [u8]> for SqliteBindValue<'a> { #[serde(untagged)] pub(crate) enum InternalSqliteBindValue<'a> { BorrowedString(&'a str), - String(Box), + String(String), BorrowedBinary(&'a [u8]), - Binary(Box<[u8]>), + Binary(Vec), I32(i32), I64(i64), F64(f64), @@ -182,8 +182,8 @@ impl<'a> BindCollector<'a, WasmSqlite> for SqliteBindCollector<'a> { #[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] pub enum OwnedSqliteBindValue { - String(Box), - Binary(Box<[u8]>), + String(String), + Binary(Vec), I32(i32), I64(i64), F64(f64), @@ -194,13 +194,9 @@ impl<'a> std::convert::From<&InternalSqliteBindValue<'a>> for OwnedSqliteBindVal fn from(value: &InternalSqliteBindValue<'a>) -> Self { match value { InternalSqliteBindValue::String(s) => Self::String(s.clone()), - InternalSqliteBindValue::BorrowedString(s) => { - Self::String(String::from(*s).into_boxed_str()) - } + InternalSqliteBindValue::BorrowedString(s) => Self::String(String::from(*s)), InternalSqliteBindValue::Binary(b) => Self::Binary(b.clone()), - InternalSqliteBindValue::BorrowedBinary(s) => { - Self::Binary(Vec::from(*s).into_boxed_slice()) - } + InternalSqliteBindValue::BorrowedBinary(s) => Self::Binary(Vec::from(*s)), InternalSqliteBindValue::I32(val) => Self::I32(*val), InternalSqliteBindValue::I64(val) => Self::I64(*val), InternalSqliteBindValue::F64(val) => Self::F64(*val), diff --git a/diesel-wasm-sqlite/src/connection/err.rs b/diesel-wasm-sqlite/src/connection/err.rs new file mode 100644 index 000000000..841dee922 --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/err.rs @@ -0,0 +1,42 @@ +use crate::ffi; +use diesel::result::Error::DatabaseError; +use diesel::result::*; +use wasm_bindgen::JsValue; + +pub(super) fn error_message(code: i32) -> String { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.errstr(code) +} + +pub(super) fn ensure_sqlite_ok(code: i32, raw_connection: &JsValue) -> QueryResult<()> { + if code == *ffi::SQLITE_OK { + Ok(()) + } else { + Err(last_error(raw_connection)) + } +} + +pub(super) fn last_error(raw_connection: &JsValue) -> diesel::result::Error { + let error_message = last_error_message(raw_connection); + let error_information = Box::new(error_message); + let error_kind = match last_error_code(raw_connection) { + e if *ffi::SQLITE_CONSTRAINT_UNIQUE | *ffi::SQLITE_CONSTRAINT_PRIMARYKEY == e => { + DatabaseErrorKind::UniqueViolation + } + e if *ffi::SQLITE_CONSTRAINT_FOREIGNKEY == e => DatabaseErrorKind::ForeignKeyViolation, + e if *ffi::SQLITE_CONSTRAINT_NOTNULL == e => DatabaseErrorKind::NotNullViolation, + e if *ffi::SQLITE_CONSTRAINT_CHECK == e => DatabaseErrorKind::CheckViolation, + _ => DatabaseErrorKind::Unknown, + }; + DatabaseError(error_kind, error_information) +} + +fn last_error_message(conn: &JsValue) -> String { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.errmsg(conn) +} + +fn last_error_code(conn: &JsValue) -> i32 { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.extended_errcode(conn) +} diff --git a/diesel-wasm-sqlite/src/connection/functions.rs b/diesel-wasm-sqlite/src/connection/functions.rs index b8d8f7538..2fbf1e303 100644 --- a/diesel-wasm-sqlite/src/connection/functions.rs +++ b/diesel-wasm-sqlite/src/connection/functions.rs @@ -10,8 +10,6 @@ use diesel::result::{DatabaseErrorKind, Error, QueryResult}; use diesel::row::{Field, PartialRow, Row, RowIndex, RowSealed}; use diesel::serialize::{IsNull, Output, ToSql}; use diesel::sql_types::HasSqlType; -use futures::future::BoxFuture; -use futures::FutureExt; use std::cell::{Ref, RefCell}; use std::marker::PhantomData; use std::mem::ManuallyDrop; @@ -26,7 +24,7 @@ pub(super) fn register( mut f: F, ) -> QueryResult<()> where - F: FnMut(&RawConnection, Args) -> BoxFuture<'static, Ret>, + F: FnMut(&RawConnection, Args) -> QueryResult, Args: FromSqlRow + StaticallySizedRow, Ret: ToSql, WasmSqlite: HasSqlType, @@ -45,7 +43,7 @@ where let conn = RawConnection { internal_connection: conn, }; - Ok(f(&conn, args).await) + Ok(f(&conn, args)) } .boxed() })?; diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index ec990c6dc..06087d907 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -1,35 +1,40 @@ mod bind_collector; -// mod functions; +mod err; mod owned_row; mod raw; mod row; -// mod serialized_database; mod sqlite_value; -mod statement_stream; +mod statement_iterator; mod stmt; pub(crate) use self::bind_collector::SqliteBindCollector; pub use self::bind_collector::SqliteBindValue; pub use self::sqlite_value::SqliteValue; - // pub use self::serialized_database::SerializedDatabase; - +// pub use self::serialized_database::SerializedDatabase; + use self::raw::RawConnection; -// use self::statement_iterator::*; +pub use self::statement_iterator::*; use self::stmt::{Statement, StatementUse}; -use crate::query_builder::*; -use diesel::query_builder::MoveableBindCollector; -use diesel::{connection::{statement_cache::StatementCacheKey}, query_builder::QueryBuilder as _, result::*}; -use futures::future::LocalBoxFuture; -use futures::stream::LocalBoxStream; -use futures::FutureExt; -use owned_row::OwnedSqliteRow; -use statement_stream::StatementStream; -use std::future::Future; -use std::sync::{Arc, Mutex}; - +pub(self) use err::*; +// use diesel::connection::DynInstrumentation; +use diesel::{ + connection::WithMetadataLookup, + connection::{statement_cache::StatementCache, DefaultLoadingMode, LoadConnection}, + expression::QueryMetadata, + query_builder::Query, + result::*, + sql_types::TypeMetadata, + RunQueryDsl, +}; -use diesel::{connection::{ConnectionSealed, Instrumentation}, query_builder::{AsQuery, QueryFragment, QueryId}, QueryResult}; -pub use diesel_async::{AnsiTransactionManager, AsyncConnection, SimpleAsyncConnection, TransactionManager, stmt_cache::StmtCache}; +use diesel::{ + connection::{ + AnsiTransactionManager, Connection, ConnectionSealed, Instrumentation, SimpleConnection, + TransactionManager, + }, + query_builder::{QueryFragment, QueryId}, + QueryResult, +}; use crate::{get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; @@ -45,111 +50,137 @@ pub struct WasmSqliteConnection { // statement_cache needs to be before raw_connection // otherwise we will get errors about open statements before closing the // connection itself - statement_cache: StmtCache, + statement_cache: StatementCache, raw_connection: RawConnection, transaction_manager: AnsiTransactionManager, + metadata_lookup: (), // this exists for the sole purpose of implementing `WithMetadataLookup` trait // and avoiding static mut which will be deprecated in 2024 edition - instrumentation: Arc>>>, + instrumentation: Box, } impl ConnectionSealed for WasmSqliteConnection {} - #[async_trait::async_trait(?Send)] -impl SimpleAsyncConnection for WasmSqliteConnection { - async fn batch_execute(&mut self, query: &str) -> diesel::prelude::QueryResult<()> { +impl SimpleConnection for WasmSqliteConnection { + fn batch_execute(&mut self, query: &str) -> diesel::prelude::QueryResult<()> { get_sqlite_unchecked() - .batch_execute(&self.raw_connection.internal_connection, query) - .await + .exec(&self.raw_connection.internal_connection, query) .map_err(WasmSqliteError::from) .map_err(Into::into) } } -#[async_trait::async_trait(?Send)] -impl AsyncConnection for WasmSqliteConnection { +impl Connection for WasmSqliteConnection { type Backend = WasmSqlite; type TransactionManager = AnsiTransactionManager; - type ExecuteFuture<'conn, 'query> = LocalBoxFuture<'conn, QueryResult>; - type LoadFuture<'conn, 'query> = LocalBoxFuture<'conn, QueryResult>>; - type Stream<'conn, 'query> = LocalBoxStream<'conn, QueryResult>>; - type Row<'conn, 'query> = OwnedSqliteRow; - async fn establish(database_url: &str) -> diesel::prelude::ConnectionResult { - WasmSqliteConnection::establish_inner(database_url).await + fn establish(database_url: &str) -> ConnectionResult { + WasmSqliteConnection::establish_inner(database_url) } - fn load<'conn, 'query, T>(&'conn mut self, source: T) -> Self::LoadFuture<'conn, 'query> + fn execute_returning_count(&mut self, source: &T) -> QueryResult where - T: AsQuery, - T::Query: QueryFragment + QueryId, + T: QueryFragment + QueryId, { - let query = source.as_query(); - self.with_prepared_statement(query, |_, statement| async move { - tracing::debug!("Loading statement!"); - Ok(StatementStream::new(statement).stream()) - }) + let statement_use = self.prepared_query(source)?; + statement_use + .run() + .map(|_| self.raw_connection.rows_affected_by_last_query()) + } + + fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) { + self.instrumentation = Box::new(instrumentation); + } + + fn instrumentation(&mut self) -> &mut dyn Instrumentation { + self.instrumentation.as_mut() + } + + fn transaction_state(&mut self) -> &mut AnsiTransactionManager + where + Self: Sized, + { + &mut self.transaction_manager } +} - fn execute_returning_count<'conn, 'query, T>( +impl LoadConnection for WasmSqliteConnection { + type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>; + type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>; + + fn load<'conn, 'query, T>( &'conn mut self, - query: T, - ) -> Self::ExecuteFuture<'conn, 'query> + source: T, + ) -> QueryResult> where - T: QueryFragment + QueryId + 'query, + T: Query + QueryFragment + QueryId + 'query, + Self::Backend: QueryMetadata, { - self.with_prepared_statement(query, |conn, statement| async move { - tracing::debug!("Running statement!"); - statement.run().await.map(|_| { - conn.rows_affected_by_last_query() - }) - }) + let statement = self.prepared_query(source)?; + + Ok(StatementIterator::new(statement)) } - - fn transaction_state( - &mut self, - ) -> &mut >::TransactionStateData{ - &mut self.transaction_manager +} + +impl WithMetadataLookup for WasmSqliteConnection { + fn metadata_lookup(&mut self) -> &mut ::MetadataLookup { + &mut self.metadata_lookup } +} - fn instrumentation(&mut self) -> &mut dyn Instrumentation { - Arc::get_mut(&mut self.instrumentation).expect("arc ref").get_mut().expect("Mutex poison") +impl diesel::migration::MigrationConnection for WasmSqliteConnection { + fn setup(&mut self) -> QueryResult { + use diesel::RunQueryDsl; + diesel::sql_query(diesel::migration::CREATE_MIGRATIONS_TABLE).execute(self) } +} - fn set_instrumentation(&mut self, _instrumentation: impl Instrumentation) { - tracing::debug!("Set instrumentation"); +#[derive(diesel::QueryId)] +pub(crate) struct CheckConnectionQuery; + +impl QueryFragment for CheckConnectionQuery +where + DB: diesel::backend::Backend, +{ + fn walk_ast<'b>( + &'b self, + mut pass: diesel::query_builder::AstPass<'_, 'b, DB>, + ) -> QueryResult<()> { + pass.push_sql("SELECT 1"); + Ok(()) } } +impl Query for CheckConnectionQuery { + type SqlType = diesel::sql_types::Integer; +} +impl RunQueryDsl for CheckConnectionQuery {} #[cfg(feature = "r2d2")] -impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection { +impl diesel::r2d2::R2D2Connection for crate::connection::WasmSqliteConnection { fn ping(&mut self) -> QueryResult<()> { - use crate::RunQueryDsl; - - crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ()) + CheckConnectionQuery.execute(self).map(|_| ()) } fn is_broken(&mut self) -> bool { AnsiTransactionManager::is_broken_transaction_manager(self) } } - /* -impl MultiConnectionHelper for SqliteConnection { + +impl diesel::connection::MultiConnectionHelper for WasmSqliteConnection { fn to_any<'a>( - lookup: &mut ::MetadataLookup, + lookup: &mut ::MetadataLookup, ) -> &mut (dyn std::any::Any + 'a) { lookup } fn from_any( lookup: &mut dyn std::any::Any, - ) -> Option<&mut ::MetadataLookup> { + ) -> Option<&mut ::MetadataLookup> { lookup.downcast_mut() } } -*/ impl WasmSqliteConnection { /// Run a transaction with `BEGIN IMMEDIATE` @@ -173,12 +204,12 @@ impl WasmSqliteConnection { /// }) /// # } /// ``` - pub async fn immediate_transaction(&mut self, f: F) -> Result + pub fn immediate_transaction(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, E: From, { - self.transaction_sql(f, "BEGIN IMMEDIATE").await + self.transaction_sql(f, "BEGIN IMMEDIATE") } /// Run a transaction with `BEGIN EXCLUSIVE` @@ -202,96 +233,95 @@ impl WasmSqliteConnection { /// }) /// # } /// ``` - pub async fn exclusive_transaction(&mut self, f: F) -> Result + pub fn exclusive_transaction(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, E: From, { - self.transaction_sql(f, "BEGIN EXCLUSIVE").await + self.transaction_sql(f, "BEGIN EXCLUSIVE") } - async fn transaction_sql(&mut self, f: F, sql: &str) -> Result + fn transaction_sql(&mut self, f: F, sql: &str) -> Result where F: FnOnce(&mut Self) -> Result, E: From, { - AnsiTransactionManager::begin_transaction_sql(&mut *self, sql).await?; + AnsiTransactionManager::begin_transaction_sql(&mut *self, sql)?; match f(&mut *self) { Ok(value) => { - AnsiTransactionManager::commit_transaction(&mut *self).await?; + AnsiTransactionManager::commit_transaction(&mut *self)?; Ok(value) } Err(e) => { - AnsiTransactionManager::rollback_transaction(&mut *self).await?; + AnsiTransactionManager::rollback_transaction(&mut *self)?; Err(e) } } } - - fn with_prepared_statement<'conn, Q, F, R>( + + fn prepared_query<'conn, 'query, T>( &'conn mut self, - query: Q, - callback: impl (FnOnce(&'conn mut RawConnection, StatementUse<'conn>) -> F) + 'conn - ) -> LocalBoxFuture<'_, QueryResult> + source: T, + ) -> QueryResult> where - Q: QueryFragment + QueryId, - F: Future>, + T: QueryFragment + QueryId + 'query, { - tracing::info!("WITH PREPARED STATEMENT"); + /* + self.instrumentation + .on_connection_event(InstrumentationEvent::StartQuery { + query: &crate::debug_query(&source), + }); + */ let WasmSqliteConnection { ref mut raw_connection, ref mut statement_cache, ref mut instrumentation, .. } = self; - - let maybe_type_id = Q::query_id(); - let instrumentation = instrumentation.clone(); - - let cache_key = StatementCacheKey::for_source(maybe_type_id, &query, &[], &WasmSqlite); - let is_safe_to_cache_prepared = query.is_safe_to_cache_prepared(&WasmSqlite); - - // C put this in box to avoid virtual fn call for SQLite C - // not sure if that still applies here - let query = Box::new(query); - let mut bind_collector = SqliteBindCollector::new(); - let bind_collector = query.collect_binds(&mut bind_collector, &mut (), &WasmSqlite).map(|()| bind_collector.moveable()); - - let mut qb = SqliteQueryBuilder::new(); - let sql = query.to_sql(&mut qb, &WasmSqlite).map(|()| qb.finish()); - - async move { - tracing::info!("IN STATEMENT PREPARE FUTURE"); - let (statement, conn) = statement_cache.cached_prepared_statement( - cache_key?, - sql?, - is_safe_to_cache_prepared?, - &[], - raw_connection, - &instrumentation, - ).await?; - let statement = StatementUse::bind(statement, bind_collector?, instrumentation)?; - let result = callback(conn, statement).await; - // statement is dropped here - // we need to yield back to the executor and allow - // the destructor for BoundStatement to run - tokio::task::yield_now().await; - result - }.boxed_local() + + let statement = match statement_cache.cached_statement( + &source, + &WasmSqlite, + &[], + |sql, is_cached| Statement::prepare(raw_connection, sql, is_cached), + instrumentation.as_mut(), + ) { + Ok(statement) => statement, + Err(e) => { + /* + self.instrumentation + .on_connection_event(InstrumentationEvent::FinishQuery { + query: &crate::debug_query(&source), + error: Some(&e), + }); + */ + return Err(e); + } + }; + + StatementUse::bind(statement, source, instrumentation.as_mut()) } - - async fn establish_inner(database_url: &str) -> Result { - // use diesel::result::ConnectionError::CouldntSetupConfiguration; - let raw_connection = RawConnection::establish(database_url).await.unwrap(); - let sqlite3 = crate::get_sqlite().await; - - sqlite3.register_diesel_sql_functions(&raw_connection.internal_connection).map_err(WasmSqliteError::from)?; + fn establish_inner(database_url: &str) -> Result { + let sqlite3 = crate::get_sqlite_unchecked(); + let raw_connection = RawConnection::establish(database_url).unwrap(); + sqlite3 + .register_diesel_sql_functions(&raw_connection.internal_connection) + .map_err(WasmSqliteError::from)?; Ok(Self { - statement_cache: StmtCache::new(), + statement_cache: StatementCache::new(), raw_connection, transaction_manager: AnsiTransactionManager::default(), - instrumentation: Arc::new(Mutex::new(None)), + instrumentation: Box::new(Nothing) as Box, + metadata_lookup: (), }) } } + +pub struct Nothing; + +impl Instrumentation for Nothing { + fn on_connection_event(&mut self, event: diesel::connection::InstrumentationEvent<'_>) { + tracing::info!("Inst. Event {:?}", event); + } +} diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs index 0cd1583ed..03ac436a0 100755 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -1,79 +1,40 @@ #![allow(dead_code)] // functions are needed, but missing functionality means they aren't used yet. -use crate::{ - sqlite_types::{SqliteFlags, SqliteOpenFlags}, - SqliteType, WasmSqlite, WasmSqliteError, -}; -use diesel::{ - connection::statement_cache::{PrepareForCache, StatementCacheKey}, - result::*, - serialize::ToSql, - sql_types::HasSqlType, -}; -use std::collections::HashMap; -use tokio::sync::oneshot; +use crate::{WasmSqlite, WasmSqliteError}; +use diesel::{result::*, serialize::ToSql, sql_types::HasSqlType}; use wasm_bindgen::{closure::Closure, JsValue}; -use super::stmt::{Statement, StatementFactory}; - #[allow(missing_copy_implementations)] pub(super) struct RawConnection { pub(super) internal_connection: JsValue, - iterator_cache: HashMap, js_sys::AsyncIterator>, - drop_signal: Option>, } impl RawConnection { - pub(super) async fn establish(database_url: &str) -> ConnectionResult { - let sqlite3 = crate::get_sqlite().await; + pub(super) fn establish(database_url: &str) -> ConnectionResult { + let sqlite3 = crate::get_sqlite_unchecked(); let database_url = if database_url.starts_with("sqlite://") { database_url.replacen("sqlite://", "file:", 1) } else { database_url.to_string() }; - let flags = SqliteOpenFlags::SQLITE_OPEN_READWRITE - | SqliteOpenFlags::SQLITE_OPEN_CREATE - | SqliteOpenFlags::SQLITE_OPEN_URI; - let (tx, rx) = oneshot::channel::(); - // TODO: can make this into function/macro - wasm_bindgen_futures::spawn_local(async move { - match rx.await { - Ok(conn) => { - let sqlite3 = crate::get_sqlite_unchecked(); - match sqlite3.close(&conn).await { - Ok(_) => tracing::debug!("db closed"), - Err(e) => { - tracing::error!("error during db close"); - web_sys::console::log_1(&e); - } - } - } - Err(_) => { - tracing::error!("RawConnection never dropped."); - } - } - }); + let capi = sqlite3.inner().capi(); + let flags = + capi.SQLITE_OPEN_READWRITE() | capi.SQLITE_OPEN_CREATE() | capi.SQLITE_OPEN_URI(); + // TODO: flags are ignored for now Ok(RawConnection { internal_connection: sqlite3 - .open_v2(&database_url, Some(flags.bits() as i32)) - .await + .open(&database_url, Some(flags as i32)) .map_err(WasmSqliteError::from) .map_err(ConnectionError::from)?, - iterator_cache: HashMap::new(), - drop_signal: Some(tx), }) } - pub(super) async fn exec(&self, query: &str) -> QueryResult<()> { - let sqlite3 = crate::get_sqlite().await; - let result = sqlite3 - .exec(&self.internal_connection, query) - .await - .unwrap(); - + pub(super) fn exec(&self, query: &str) -> QueryResult<()> { + let sqlite3 = crate::get_sqlite_unchecked(); + let result = sqlite3.exec(&self.internal_connection, query).unwrap(); Ok(result) } @@ -116,11 +77,12 @@ impl RawConnection { } fn get_flags(deterministic: bool) -> i32 { - let mut flags = SqliteFlags::SQLITE_UTF8; + let capi = crate::get_sqlite_unchecked().inner().capi(); + let mut flags = capi.SQLITE_UTF8(); if deterministic { - flags |= SqliteFlags::SQLITE_DETERMINISTIC; + flags |= capi.SQLITE_DETERMINISTIC(); } - flags.bits() as i32 + flags as i32 } /* possible to implement this, but would need to fill in the missing wa-sqlite functions @@ -156,28 +118,15 @@ impl RawConnection { */ } -#[async_trait::async_trait(?Send)] -impl diesel_async::stmt_cache::PrepareCallback for &'_ mut RawConnection { - async fn prepare( - self, - sql: &str, - _metadata: &[SqliteType], - is_for_cache: PrepareForCache, - ) -> QueryResult<(Statement, Self)> { - let stmt = StatementFactory::new(&self, sql, is_for_cache) - .await? - .prepare() - .await; - Ok((stmt, self)) - } -} - impl Drop for RawConnection { fn drop(&mut self) { - if let Some(s) = self.drop_signal.take() { - let _ = s.send(self.internal_connection.clone()); - } else { - tracing::warn!("RawConnection not dropped because drop_signal is empty"); + let sqlite3 = crate::get_sqlite_unchecked(); + + + let result = sqlite3.close(&self.internal_connection); + if result != *crate::ffi::SQLITE_OK { + let error_message = super::error_message(result); + panic!("Error closing SQLite connection: {}", error_message); } } } diff --git a/diesel-wasm-sqlite/src/connection/row.rs b/diesel-wasm-sqlite/src/connection/row.rs index d63a29783..1af468dbf 100644 --- a/diesel-wasm-sqlite/src/connection/row.rs +++ b/diesel-wasm-sqlite/src/connection/row.rs @@ -12,20 +12,20 @@ use diesel::{ }; #[allow(missing_debug_implementations)] -pub struct SqliteRow<'stmt> { - pub(super) inner: Rc>>, +pub struct SqliteRow<'stmt, 'query> { + pub(super) inner: Rc>>, pub(super) field_count: usize, } -pub(super) enum PrivateSqliteRow<'stmt> { - Direct(StatementUse<'stmt>), +pub(super) enum PrivateSqliteRow<'stmt, 'query> { + Direct(StatementUse<'stmt, 'query>), Duplicated { values: Vec>, column_names: Rc<[Option]>, }, } -impl<'stmt> IntoOwnedRow<'stmt, WasmSqlite> for SqliteRow<'stmt> { +impl<'stmt, 'query> IntoOwnedRow<'stmt, WasmSqlite> for SqliteRow<'stmt, 'query> { type OwnedRow = OwnedSqliteRow; type Cache = Option]>>; @@ -35,11 +35,11 @@ impl<'stmt> IntoOwnedRow<'stmt, WasmSqlite> for SqliteRow<'stmt> { } } -impl<'stmt> PrivateSqliteRow<'stmt> { +impl<'stmt, 'query> PrivateSqliteRow<'stmt, 'query> { pub(super) fn duplicate( &mut self, column_names: &mut Option]>>, - ) -> PrivateSqliteRow<'stmt> { + ) -> PrivateSqliteRow<'stmt, 'query> { match self { PrivateSqliteRow::Direct(stmt) => { let column_names = if let Some(column_names) = column_names { @@ -129,10 +129,10 @@ impl<'stmt> PrivateSqliteRow<'stmt> { } } -impl<'stmt> RowSealed for SqliteRow<'stmt> {} +impl<'stmt, 'query> RowSealed for SqliteRow<'stmt, 'query> {} -impl<'stmt> Row<'stmt, WasmSqlite> for SqliteRow<'stmt> { - type Field<'field> = SqliteField<'field> where 'stmt: 'field, Self: 'field; +impl<'stmt, 'query> Row<'stmt, WasmSqlite> for SqliteRow<'stmt, 'query> { + type Field<'field> = SqliteField<'field, 'field> where 'stmt: 'field, Self: 'field; type InnerPartialRow = Self; fn field_count(&self) -> usize { @@ -156,7 +156,7 @@ impl<'stmt> Row<'stmt, WasmSqlite> for SqliteRow<'stmt> { } } -impl<'stmt> RowIndex for SqliteRow<'stmt> { +impl<'stmt, 'query> RowIndex for SqliteRow<'stmt, 'query> { fn idx(&self, idx: usize) -> Option { if idx < self.field_count { Some(idx) @@ -166,7 +166,7 @@ impl<'stmt> RowIndex for SqliteRow<'stmt> { } } -impl<'stmt, 'idx> RowIndex<&'idx str> for SqliteRow<'stmt> { +impl<'stmt, 'idx, 'query> RowIndex<&'idx str> for SqliteRow<'stmt, 'query> { fn idx(&self, field_name: &'idx str) -> Option { match &mut *self.inner.borrow_mut() { PrivateSqliteRow::Direct(stmt) => stmt.index_for_column_name(field_name), @@ -178,12 +178,12 @@ impl<'stmt, 'idx> RowIndex<&'idx str> for SqliteRow<'stmt> { } #[allow(missing_debug_implementations)] -pub struct SqliteField<'stmt> { - pub(super) row: Ref<'stmt, PrivateSqliteRow<'stmt>>, +pub struct SqliteField<'stmt, 'query> { + pub(super) row: Ref<'stmt, PrivateSqliteRow<'stmt, 'query>>, pub(super) col_idx: i32, } -impl<'stmt> Field<'stmt, WasmSqlite> for SqliteField<'stmt> { +impl<'stmt, 'query> Field<'stmt, WasmSqlite> for SqliteField<'stmt, 'query> { fn field_name(&self) -> Option<&str> { match &*self.row { PrivateSqliteRow::Direct(stmt) => stmt.field_name(self.col_idx), @@ -201,212 +201,3 @@ impl<'stmt> Field<'stmt, WasmSqlite> for SqliteField<'stmt> { SqliteValue::new(Ref::clone(&self.row), self.col_idx) } } - -/* -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn fun_with_row_iters() { - crate::table! { - #[allow(unused_parens)] - users(id) { - id -> Integer, - name -> Text, - } - } - - use crate::connection::LoadConnection; - use crate::deserialize::{FromSql, FromSqlRow}; - use crate::prelude::*; - use crate::row::{Field, Row}; - use crate::sql_types; - - let conn = &mut crate::test_helpers::connection(); - - crate::sql_query("CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);") - .execute(conn) - .unwrap(); - - crate::insert_into(users::table) - .values(vec![ - (users::id.eq(1), users::name.eq("Sean")), - (users::id.eq(2), users::name.eq("Tess")), - ]) - .execute(conn) - .unwrap(); - - let query = users::table.select((users::id, users::name)); - - let expected = vec![(1, String::from("Sean")), (2, String::from("Tess"))]; - - let row_iter = conn.load(query).unwrap(); - for (row, expected) in row_iter.zip(&expected) { - let row = row.unwrap(); - - let deserialized = <(i32, String) as FromSqlRow< - (sql_types::Integer, sql_types::Text), - _, - >>::build_from_row(&row) - .unwrap(); - - assert_eq!(&deserialized, expected); - } - - { - let collected_rows = conn.load(query).unwrap().collect::>(); - - for (row, expected) in collected_rows.iter().zip(&expected) { - let deserialized = row - .as_ref() - .map(|row| { - <(i32, String) as FromSqlRow< - (sql_types::Integer, sql_types::Text), - _, - >>::build_from_row(row).unwrap() - }) - .unwrap(); - - assert_eq!(&deserialized, expected); - } - } - - let mut row_iter = conn.load(query).unwrap(); - - let first_row = row_iter.next().unwrap().unwrap(); - let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); - let first_values = (first_fields.0.value(), first_fields.1.value()); - - assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(first_values); - assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(first_fields); - - let second_row = row_iter.next().unwrap().unwrap(); - let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap()); - let second_values = (second_fields.0.value(), second_fields.1.value()); - - assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(second_values); - assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(second_fields); - - assert!(row_iter.next().is_none()); - - let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); - let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap()); - - let first_values = (first_fields.0.value(), first_fields.1.value()); - let second_values = (second_fields.0.value(), second_fields.1.value()); - - assert_eq!( - >::from_nullable_sql(first_values.0) - .unwrap(), - expected[0].0 - ); - assert_eq!( - >::from_nullable_sql(first_values.1) - .unwrap(), - expected[0].1 - ); - - assert_eq!( - >::from_nullable_sql(second_values.0) - .unwrap(), - expected[1].0 - ); - assert_eq!( - >::from_nullable_sql(second_values.1) - .unwrap(), - expected[1].1 - ); - - let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); - let first_values = (first_fields.0.value(), first_fields.1.value()); - - assert_eq!( - >::from_nullable_sql(first_values.0) - .unwrap(), - expected[0].0 - ); - assert_eq!( - >::from_nullable_sql(first_values.1) - .unwrap(), - expected[0].1 - ); - } - - #[cfg(feature = "returning_clauses_for_sqlite_3_35")] - crate::define_sql_function! {fn sleep(a: diesel::sql_types::Integer) -> diesel::sql_types::Integer} - - #[test] - #[cfg(feature = "returning_clauses_for_sqlite_3_35")] - fn parallel_iter_with_error() { - use crate::connection::Connection; - use crate::connection::LoadConnection; - use crate::connection::SimpleConnection; - use crate::expression_methods::ExpressionMethods; - use crate::SqliteConnection; - use std::sync::{Arc, Barrier}; - use std::time::Duration; - - let temp_dir = tempfile::tempdir().unwrap(); - let db_path = format!("{}/test.db", temp_dir.path().display()); - let mut conn1 = SqliteConnection::establish(&db_path).unwrap(); - let mut conn2 = SqliteConnection::establish(&db_path).unwrap(); - - crate::table! { - users { - id -> Integer, - name -> Text, - } - } - - conn1 - .batch_execute("CREATE TABLE users(id INTEGER NOT NULL PRIMARY KEY, name TEXT)") - .unwrap(); - - let barrier = Arc::new(Barrier::new(2)); - let barrier2 = barrier.clone(); - - // we unblock the main thread from the sleep function - sleep_utils::register_impl(&mut conn2, move |a: i32| { - barrier.wait(); - std::thread::sleep(Duration::from_secs(a as u64)); - a - }) - .unwrap(); - - // spawn a background thread that locks the database file - let handle = std::thread::spawn(move || { - use crate::query_dsl::RunQueryDsl; - - conn2 - .immediate_transaction(|conn| diesel::select(sleep(1)).execute(conn)) - .unwrap(); - }); - barrier2.wait(); - - // execute some action that also requires a lock - let mut iter = conn1 - .load( - diesel::insert_into(users::table) - .values((users::id.eq(1), users::name.eq("John"))) - .returning(users::id), - ) - .unwrap(); - - // get the first iterator result, that should return the lock error - let n = iter.next().unwrap(); - assert!(n.is_err()); - - // check that the iterator is now empty - let n = iter.next(); - assert!(n.is_none()); - - // join the background thread - handle.join().unwrap(); - } -} -*/ diff --git a/diesel-wasm-sqlite/src/connection/sqlite_value.rs b/diesel-wasm-sqlite/src/connection/sqlite_value.rs index bfc104f79..13f3603c6 100644 --- a/diesel-wasm-sqlite/src/connection/sqlite_value.rs +++ b/diesel-wasm-sqlite/src/connection/sqlite_value.rs @@ -2,9 +2,8 @@ use std::cell::Ref; -use crate::ffi::SQLiteCompatibleType; -use crate::{backend::SqliteType, sqlite_types}; -use wasm_bindgen::JsValue; +use crate::backend::SqliteType; +use crate::ffi; use super::owned_row::OwnedSqliteRow; use super::row::PrivateSqliteRow; @@ -14,11 +13,11 @@ use super::row::PrivateSqliteRow; /// Use existing `FromSql` implementations to convert this into /// rust values #[allow(missing_debug_implementations, missing_copy_implementations)] -pub struct SqliteValue<'row, 'stmt> { +pub struct SqliteValue<'row, 'stmt, 'query> { // This field exists to ensure that nobody // can modify the underlying row while we are // holding a reference to some row value here - _row: Option>>, + _row: Option>>, // we extract the raw value pointer as part of the constructor // to safe the match statements for each method // According to benchmarks this leads to a ~20-30% speedup @@ -27,25 +26,36 @@ pub struct SqliteValue<'row, 'stmt> { // This is sound as long as nobody calls `stmt.step()` // while holding this value. We ensure this by including // a reference to the row above. - value: SQLiteCompatibleType, + /// We are referencing SQLites WASM memory, + /// so we just have to trust its not null rather than using `NonNull` + /// (i dont think that would work unless its our mem) + value: *mut u8, } #[derive(Debug, Clone)] pub(super) struct OwnedSqliteValue { - pub(super) value: SQLiteCompatibleType, + // maybe make JsValue? + pub(super) value: *mut u8, +} + +impl Drop for OwnedSqliteValue { + fn drop(&mut self) { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.value_free(self.value) + } } // Unsafe Send impl safe since sqlite3_value is built with sqlite3_value_dup // see https://www.sqlite.org/c3ref/value.html unsafe impl Send for OwnedSqliteValue {} -impl<'row, 'stmt> SqliteValue<'row, 'stmt> { +impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { pub(super) fn new( - row: Ref<'row, PrivateSqliteRow<'stmt>>, + row: Ref<'row, PrivateSqliteRow<'stmt, 'query>>, col_idx: i32, - ) -> Option> { + ) -> Option> { let value = match &*row { - PrivateSqliteRow::Direct(stmt) => stmt.column_value(col_idx)?, + PrivateSqliteRow::Direct(stmt) => stmt.column_value(col_idx), PrivateSqliteRow::Duplicated { values, .. } => values .get(col_idx as usize) .and_then(|v| v.as_ref())? @@ -67,7 +77,7 @@ impl<'row, 'stmt> SqliteValue<'row, 'stmt> { pub(super) fn from_owned_row( row: &'row OwnedSqliteRow, col_idx: i32, - ) -> Option> { + ) -> Option> { let value = row .values .get(col_idx as usize) @@ -82,46 +92,67 @@ impl<'row, 'stmt> SqliteValue<'row, 'stmt> { } } - pub(crate) fn parse_string(&self, f: impl FnOnce(String) -> R) -> R { - let sqlite3 = crate::get_sqlite_unchecked(); - let s = sqlite3.value_text(&self.value); - f(s) - } - //FIXME: WE SHOULD TRY TO RETURN STRING REFERENCE HERE referenceing JS Type in wasm-bindgen! pub(crate) fn read_text(&self) -> String { self.parse_string(|s| s) } + // TODO: If we share memory with SQLITE, we can return a &'value str here rathre than an + // allocated String + pub(crate) fn parse_string<'value, R>(&self, f: impl FnOnce(String) -> R) -> R { + let sqlite3 = crate::get_sqlite_unchecked(); + // TODO: + // for some reason sqlite3_value_text returns the String and not a + // pointer. There's probably a way to make it return a pointer + let s = sqlite3.value_text(self.value); + // let s = unsafe { + // let ptr = sqlite3.value_text(self.value); + // let len = sqlite3.value_bytes(self.value); + // let mut bytes = Vec::with_capacity(len as usize); + // ffi::raw_copy_from_sqlite(ptr, len, bytes.as_mut_slice()); + // unsafe { bytes.set_len(len) }; // not sure we need this + // String::from_utf8_unchecked(bytes) + // }; + f(s) + } + pub(crate) fn read_blob(&self) -> Vec { let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_blob(&self.value) + unsafe { + let ptr = sqlite3.value_blob(self.value); + let len = sqlite3.value_bytes(self.value); + let mut bytes = Vec::with_capacity(len as usize); + ffi::raw_copy_from_sqlite(ptr, len, bytes.as_mut_slice()); + // bytes.set_len(len); // not sure we need this + bytes + } } pub(crate) fn read_integer(&self) -> i32 { let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_int(&self.value) + sqlite3.value_int(self.value) } pub(crate) fn read_long(&self) -> i64 { let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_int64(&self.value) + sqlite3.value_int64(self.value) } pub(crate) fn read_double(&self) -> f64 { let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_double(&self.value) + sqlite3.value_double(self.value) } /// Get the type of the value as returned by sqlite pub fn value_type(&self) -> Option { let sqlite3 = crate::get_sqlite_unchecked(); - let tpe = sqlite3.value_type(&self.value); + let tpe = sqlite3.value_type(self.value); + match tpe { - sqlite_types::SQLITE_TEXT => Some(SqliteType::Text), - sqlite_types::SQLITE_INTEGER => Some(SqliteType::Long), - sqlite_types::SQLITE_FLOAT => Some(SqliteType::Double), - sqlite_types::SQLITE_BLOB => Some(SqliteType::Binary), - sqlite_types::SQLITE_NULL => None, + _ if *ffi::SQLITE_TEXT == tpe => Some(SqliteType::Text), + _ if *ffi::SQLITE_INTEGER == tpe => Some(SqliteType::Long), + _ if *ffi::SQLITE_FLOAT == tpe => Some(SqliteType::Double), + _ if *ffi::SQLITE_BLOB == tpe => Some(SqliteType::Binary), + _ if *ffi::SQLITE_NULL == tpe => None, _ => unreachable!( "Sqlite's documentation state that this case ({}) is not reachable. \ If you ever see this error message please open an issue at \ @@ -133,23 +164,21 @@ impl<'row, 'stmt> SqliteValue<'row, 'stmt> { } impl OwnedSqliteValue { - pub(super) fn copy_from_ptr(ptr: &JsValue) -> Option { + pub(super) fn copy_from_ptr(ptr: *mut u8) -> Option { let sqlite3 = crate::get_sqlite_unchecked(); - let tpe = sqlite3.value_type(&ptr); - if sqlite_types::SQLITE_NULL == tpe { + let tpe = sqlite3.value_type(ptr); + if *ffi::SQLITE_NULL == tpe { return None; } let value = sqlite3.value_dup(ptr); - Some(Self { - value: value.into(), - }) + Some(Self { value }) } pub(super) fn duplicate(&self) -> OwnedSqliteValue { let sqlite3 = crate::get_sqlite_unchecked(); - let value = sqlite3.value_dup(&self.value); + let value = sqlite3.value_dup(self.value); OwnedSqliteValue { value: value.into(), } diff --git a/diesel-wasm-sqlite/src/connection/statement_iterator.rs b/diesel-wasm-sqlite/src/connection/statement_iterator.rs new file mode 100644 index 000000000..2e47d59cd --- /dev/null +++ b/diesel-wasm-sqlite/src/connection/statement_iterator.rs @@ -0,0 +1,159 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use super::row::{PrivateSqliteRow, SqliteRow}; +use super::stmt::StatementUse; +use diesel::result::QueryResult; + +#[allow(missing_debug_implementations)] +pub struct StatementIterator<'stmt, 'query> { + inner: PrivateStatementIterator<'stmt, 'query>, + column_names: Option]>>, + field_count: usize, +} + +impl<'stmt, 'query> StatementIterator<'stmt, 'query> { + #[cold] + fn handle_duplicated_row_case( + outer_last_row: &mut Rc>>, + column_names: &mut Option]>>, + field_count: usize, + ) -> Option>> { + // We don't own the statement. There is another existing reference, likely because + // a user stored the row in some long time container before calling next another time + // In this case we copy out the current values into a temporary store and advance + // the statement iterator internally afterwards + let last_row = { + let mut last_row = match outer_last_row.try_borrow_mut() { + Ok(o) => o, + Err(_e) => { + return Some(Err(diesel::result::Error::DeserializationError( + "Failed to reborrow row. Try to release any `SqliteField` or `SqliteValue` \ + that exists at this point" + .into(), + ))); + } + }; + let last_row = &mut *last_row; + let duplicated = last_row.duplicate(column_names); + std::mem::replace(last_row, duplicated) + }; + if let PrivateSqliteRow::Direct(mut stmt) = last_row { + // This is actually safe here as we've already + // performed one step. For the first step we would have + // used `PrivateStatementIterator::NotStarted` where we don't + // have access to `PrivateSqliteRow` at all + let res = stmt.step(false); + *outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); + match res { + Err(e) => Some(Err(e)), + Ok(false) => None, + Ok(true) => Some(Ok(SqliteRow { + inner: Rc::clone(outer_last_row), + field_count, + })), + } + } else { + // any other state than `PrivateSqliteRow::Direct` is invalid here + // and should not happen. If this ever happens this is a logic error + // in the code above + unreachable!( + "You've reached an impossible internal state. \ + If you ever see this error message please open \ + an issue at https://github.com/diesel-rs/diesel \ + providing example code how to trigger this error." + ) + } + } +} + +enum PrivateStatementIterator<'stmt, 'query> { + NotStarted(Option>), + Started(Rc>>), +} + +impl<'stmt, 'query> StatementIterator<'stmt, 'query> { + pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> { + Self { + inner: PrivateStatementIterator::NotStarted(Some(stmt)), + column_names: None, + field_count: 0, + } + } +} + +impl<'stmt, 'query> Iterator for StatementIterator<'stmt, 'query> { + type Item = QueryResult>; + + fn next(&mut self) -> Option { + use PrivateStatementIterator::{NotStarted, Started}; + match &mut self.inner { + NotStarted(ref mut stmt @ Some(_)) => { + let mut stmt = stmt + .take() + .expect("It must be there because we checked that above"); + let step = stmt.step(true); + match step { + Err(e) => Some(Err(e)), + Ok(false) => None, + Ok(true) => { + let field_count = stmt.column_count() as usize; + self.field_count = field_count; + let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); + self.inner = Started(inner.clone()); + Some(Ok(SqliteRow { inner, field_count })) + } + } + } + Started(ref mut last_row) => { + // There was already at least one iteration step + // We check here if the caller already released the row value or not + // by checking if our Rc owns the data or not + if let Some(last_row_ref) = Rc::get_mut(last_row) { + // We own the statement, there is no other reference here. + // This means we don't need to copy out values from the sqlite provided + // datastructures for now + // We don't need to use the runtime borrowing system of the RefCell here + // as we have a mutable reference, so all of this below is checked at compile time + if let PrivateSqliteRow::Direct(ref mut stmt) = last_row_ref.get_mut() { + let step = stmt.step(false); + + match step { + Err(e) => Some(Err(e)), + Ok(false) => None, + Ok(true) => { + let field_count = self.field_count; + Some(Ok(SqliteRow { + inner: Rc::clone(last_row), + field_count, + })) + } + } + } else { + // any other state than `PrivateSqliteRow::Direct` is invalid here + // and should not happen. If this ever happens this is a logic error + // in the code above + unreachable!( + "You've reached an impossible internal state. \ + If you ever see this error message please open \ + an issue at https://github.com/diesel-rs/diesel \ + providing example code how to trigger this error." + ) + } + } else { + Self::handle_duplicated_row_case( + last_row, + &mut self.column_names, + self.field_count, + ) + } + } + NotStarted(_s) => { + // we likely got an error while executing the other + // `NotStarted` branch above. In this case we just want to stop + // iterating here + None + } + } + } +} diff --git a/diesel-wasm-sqlite/src/connection/statement_stream.rs b/diesel-wasm-sqlite/src/connection/statement_stream.rs deleted file mode 100644 index 2b44cd5a3..000000000 --- a/diesel-wasm-sqlite/src/connection/statement_stream.rs +++ /dev/null @@ -1,199 +0,0 @@ -use std::cell::RefCell; -use std::rc::Rc; - -use super::owned_row::OwnedSqliteRow; -use super::row::{PrivateSqliteRow, SqliteRow}; -use super::stmt::StatementUse; -use diesel::result::QueryResult; -use diesel::row::IntoOwnedRow; -use futures::stream::LocalBoxStream; - -#[allow(missing_debug_implementations)] -pub struct StatementStream<'stmt> { - inner: StatementStreamState<'stmt>, - column_names: Option]>>, - field_count: usize, -} - -impl<'stmt> StatementStream<'stmt> { - #[cold] - async fn handle_duplicated_row_case( - outer_last_row: &mut Rc>>, - column_names: &mut Option]>>, - field_count: usize, - ) -> Option> { - // We don't own the statement. There is another existing reference, likely because - // a user stored the row in some long time container before calling next another time - // In this case we copy out the current values into a temporary store and advance - // the statement iterator internally afterwards - let last_row = { - let mut last_row = match outer_last_row.try_borrow_mut() { - Ok(o) => o, - Err(_e) => { - return Some(Err(diesel::result::Error::DeserializationError( - "Failed to reborrow row. Try to release any `SqliteField` or `SqliteValue` \ - that exists at this point" - .into(), - ))); - } - }; - let last_row = &mut *last_row; - let duplicated = last_row.duplicate(column_names); - std::mem::replace(last_row, duplicated) - }; - if let PrivateSqliteRow::Direct(mut stmt) = last_row { - let res = stmt.step(false).await; - *outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); - match res { - Err(e) => Some(Err(e)), - Ok(false) => None, - Ok(true) => Some(Ok(SqliteRow { - inner: Rc::clone(outer_last_row), - field_count, - } - .into_owned(&mut None))), - } - } else { - // any other state than `PrivateSqliteRow::Direct` is invalid here - // and should not happen. If this ever happens this is a logic error - // in the code above - unreachable!( - "You've reached an impossible internal state. \ - If you ever see this error message please open \ - an issue at https://github.com/diesel-rs/diesel \ - providing example code how to trigger this error." - ) - } - } -} - -enum StatementStreamState<'stmt> { - NotStarted(Option>), - Started(Rc>>), -} - -impl<'stmt> StatementStream<'stmt> { - pub fn new(stmt: StatementUse<'stmt>) -> StatementStream<'stmt> { - Self { - inner: StatementStreamState::NotStarted(Some(stmt)), - column_names: None, - field_count: 0, - } - } -} -/// Rolling a custom `Stream` impl on StatementStream was taking too long/tricky -/// so using `futures::unfold`. Rolling a custom `Stream` would probably be better, -/// but performance wise/code-readability sense not very different -impl<'stmt> StatementStream<'stmt> { - pub fn stream(self) -> LocalBoxStream<'stmt, QueryResult> { - use StatementStreamState::{NotStarted, Started}; - let stream = futures::stream::unfold(self, |mut statement| async move { - match statement.inner { - NotStarted(mut stmt @ Some(_)) => { - let mut stmt = stmt - .take() - .expect("It must be there because we checked that above"); - match stmt.step(true).await { - Ok(true) => { - let field_count = stmt.column_count() as usize; - statement.field_count = field_count; - let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); - let new_inner = inner.clone(); - Some(( - Ok(SqliteRow { inner, field_count }.into_owned(&mut None)), - Self { - inner: Started(new_inner), - ..statement - }, - )) - } - Ok(false) => None, - Err(e) => Some(( - Err(e), - Self { - inner: NotStarted(Some(stmt)), - ..statement - }, - )), - } - // res.poll_next(cx).map(|t| t.flatten()) - } - Started(ref mut last_row) => { - // There was already at least one iteration step - // We check here if the caller already released the row value or not - // by checking if our Rc owns the data or not - if let Some(last_row_ref) = Rc::get_mut(last_row) { - // We own the statement, there is no other reference here. - // This means we don't need to copy out values from the sqlite provided - // datastructures for now - // We don't need to use the runtime borrowing system of the RefCell here - // as we have a mutable reference, so all of this below is checked at compile time - if let PrivateSqliteRow::Direct(ref mut stmt) = last_row_ref.get_mut() { - // This is actually safe here as we've already - // performed one step. For the first step we would have - // used `StatementStreamState::NotStarted` where we don't - // have access to `PrivateSqliteRow` at all - match stmt.step(false).await { - Err(e) => Some(( - Err(e), - Self { - inner: Started(Rc::clone(last_row)), - ..statement - }, - )), - Ok(false) => None, - Ok(true) => { - let field_count = statement.field_count; - Some(( - Ok(SqliteRow { - inner: Rc::clone(last_row), - field_count, - } - .into_owned(&mut None)), - Self { - inner: Started(Rc::clone(last_row)), - ..statement - }, - )) - } - } - } else { - // any other state than `PrivateSqliteRow::Direct` is invalid here - // and should not happen. If this ever happens this is a logic error - // in the code above - unreachable!( - "You've reached an impossible internal state. \ - If you ever see this error message please open \ - an issue at https://github.com/diesel-rs/diesel \ - providing example code how to trigger this error." - ) - } - } else { - let res = Self::handle_duplicated_row_case( - last_row, - &mut statement.column_names, - statement.field_count, - ) - .await; - res.map(|r| { - ( - r, - Self { - inner: Started(Rc::clone(last_row)), - ..statement - }, - ) - }) - } - } - NotStarted(_s) => { - // we likely got an error while executing the other - // `NotStarted` branch above. In this case we just want to stop - // iterating here - None - } - } - }); - Box::pin(stream) - } -} diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 649ed71df..64e076160 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -1,87 +1,70 @@ #![allow(unsafe_code)] //TODO: can probably remove for wa-sqlite -use super::bind_collector::{OwnedSqliteBindValue, SqliteBindCollectorData}; use super::raw::RawConnection; use super::sqlite_value::OwnedSqliteValue; -use crate::ffi::SQLiteCompatibleType; +use crate::ffi; use crate::{ - sqlite_types::{self, PrepareOptions, SqlitePrepareFlags}, - SqliteType, WasmSqliteError, + connection::{bind_collector::InternalSqliteBindValue, err::*, SqliteBindCollector}, + SqliteType, WasmSqlite, }; use diesel::{ connection::{ statement_cache::{MaybeCached, PrepareForCache}, Instrumentation, }, + query_builder::{QueryFragment, QueryId}, result::{Error, QueryResult}, }; -use js_sys::AsyncIterator; -use std::cell::OnceCell; -use std::sync::{Arc, Mutex}; +use std::{cell::OnceCell, ptr::NonNull}; -use tokio::sync::oneshot; use wasm_bindgen::JsValue; -use wasm_bindgen_futures::JsFuture; -// TODO: Drop impl make sure to free JS async iterat9or -pub struct StatementFactory { - statement_iterator: js_sys::AsyncIterator, +// this is OK b/c web runs in one thread +unsafe impl Send for Statement {} +#[derive(Debug)] +pub(super) struct Statement { + // each iteration compiles a new statement for use + inner_statement: JsValue, } -impl StatementFactory { - pub async fn new( +impl Statement { + // NOTE: During diesel prepared statements, + // statements are cached. WASM might not like statements being cached + // since the statement pointer might be invalidated if a memory resize + // takes place. + pub fn prepare( raw_connection: &RawConnection, sql: &str, is_cached: PrepareForCache, ) -> QueryResult { - tracing::debug!("new statement factory, is_cached = {:?}", is_cached); let sqlite3 = crate::get_sqlite_unchecked(); let flags = if matches!(is_cached, PrepareForCache::Yes) { - Some(SqlitePrepareFlags::SQLITE_PREPARE_PERSISTENT.bits()) + Some(*ffi::SQLITE_PREPARE_PERSISTENT) } else { None }; - - let options = PrepareOptions { - flags, - unscoped: Some(true), - }; - - let stmt = sqlite3 - // TODO: rename to something more fitting - .prepare( - &raw_connection.internal_connection, - sql, - serde_wasm_bindgen::to_value(&options).unwrap(), - ) - .await - .map_err(WasmSqliteError::from)?; - - let statement_iterator = js_sys::AsyncIterator::from(stmt); - Ok(Self { statement_iterator }) - } - - /// compile a new statement based on given SQL in [`StatementFactory`] - pub async fn prepare(&self) -> Statement { - let inner_statement = JsFuture::from(self.statement_iterator.next().expect("No Next")) - .await - .expect("statement failed to compile"); - let inner_statement: JsValue = js_sys::Reflect::get(&inner_statement, &"value".into()) - .expect("Async Iterator API should be stable"); - tracing::debug!("Statement: {:?}", inner_statement); - - Statement { inner_statement } + let wasm = sqlite3.inner().wasm(); + let stack = wasm.pstack().pointer(); + + // allocate one 64bit pointer value + let pp_stmt = wasm.pstack().alloc(8); + let prepare_result = sqlite3.prepare_v3( + &raw_connection.internal_connection, + sql, + -1, + flags.unwrap_or(0), + &pp_stmt, + &JsValue::NULL, + ); + + let p_stmt = wasm.peek_ptr(&pp_stmt); + + ensure_sqlite_ok(prepare_result, &raw_connection.internal_connection)?; + wasm.pstack().restore(&stack); + Ok(Self { + inner_statement: p_stmt, + }) } -} - -// this is OK b/c web runs in one thread -unsafe impl Send for Statement {} -#[derive(Debug)] -pub(super) struct Statement { - // each iteration compiles a new statement for use - inner_statement: JsValue, -} -impl Statement { // The caller of this function has to ensure that: // * Any buffer provided as `SqliteBindValue::BorrowedBinary`, `SqliteBindValue::Binary` // `SqliteBindValue::String` or `SqliteBindValue::BorrowedString` is valid @@ -89,56 +72,118 @@ impl Statement { // prepared statement is dropped. fn bind( &self, - _tpe: SqliteType, - value: OwnedSqliteBindValue, + tpe: SqliteType, + value: InternalSqliteBindValue<'_>, bind_index: i32, - ) -> QueryResult { + ) -> QueryResult>> { let sqlite3 = crate::get_sqlite_unchecked(); - let value = - serde_wasm_bindgen::to_value(&value).expect("Bind value failed to convert to JsValue"); - tracing::info!("Statement: {:?}", self.inner_statement); - - let result = sqlite3 - .bind(&self.inner_statement, bind_index, value.into()) - .expect("could not bind"); - - // TODO:insipx Pretty sure we can have a simpler implementation here vs diesel - // making use of `wa-sqlite` `bind` which abstracts over the individual bind functions in - // sqlite3. However, not sure how this will work further up the stack. - // This might not work because of differences in how serde_json recognizes js types - // and how wa-sqlite recogizes js types. In that case, need to resort to matching on - // individual types with bind_$type fns . - - Ok(result) + + let mut ret_ptr = None; + let wasm = sqlite3.inner().wasm(); + + let result = match (tpe, value) { + (_, InternalSqliteBindValue::Null) => { + sqlite3.bind_null(&self.inner_statement, bind_index) + } + (SqliteType::Binary, InternalSqliteBindValue::BorrowedBinary(bytes)) => { + // copy bytes from our WASM memory to SQLites WASM memory + let ptr = wasm.alloc(bytes.len() as u32); + ffi::raw_copy_to_sqlite(bytes, ptr); + ret_ptr = NonNull::new(ptr); + sqlite3.bind_blob( + &self.inner_statement, + bind_index, + ptr, + bytes.len() as i32, + *ffi::SQLITE_STATIC, + ) + } + (SqliteType::Binary, InternalSqliteBindValue::Binary(bytes)) => { + let ptr = wasm.alloc(bytes.len() as u32); + ffi::raw_copy_to_sqlite(bytes.as_slice(), ptr); + ret_ptr = NonNull::new(ptr); + sqlite3.bind_blob( + &self.inner_statement, + bind_index, + ptr, + bytes.len() as i32, + *ffi::SQLITE_STATIC, + ) + } + (SqliteType::Text, InternalSqliteBindValue::BorrowedString(bytes)) => { + let ptr = wasm.alloc_cstring(bytes.to_string()); + ret_ptr = NonNull::new(ptr); + sqlite3.bind_text( + &self.inner_statement, + bind_index, + ptr, + bytes.len() as i32, + *ffi::SQLITE_STATIC, + ) + } + (SqliteType::Text, InternalSqliteBindValue::String(bytes)) => { + let len = bytes.len(); + let ptr = wasm.alloc_cstring(bytes); + ret_ptr = NonNull::new(ptr); + sqlite3.bind_text( + &self.inner_statement, + bind_index, + ptr, + len as i32, + *ffi::SQLITE_STATIC, + ) + } + (SqliteType::Float, InternalSqliteBindValue::F64(value)) + | (SqliteType::Double, InternalSqliteBindValue::F64(value)) => { + sqlite3.bind_double(&self.inner_statement, bind_index, value) + } + (SqliteType::SmallInt, InternalSqliteBindValue::I32(value)) + | (SqliteType::Integer, InternalSqliteBindValue::I32(value)) => { + sqlite3.bind_int(&self.inner_statement, bind_index, value) + } + (SqliteType::Long, InternalSqliteBindValue::I64(value)) => { + sqlite3.bind_int64(&self.inner_statement, bind_index, value) + } + (t, b) => { + return Err(Error::SerializationError( + format!("Type mismatch: Expected {t:?}, got {b}").into(), + )) + } + }; + match ensure_sqlite_ok(result, &self.raw_connection()) { + Ok(()) => Ok(ret_ptr), + Err(e) => { + if let Some(ptr) = ret_ptr { + wasm.dealloc(ptr); + } + Err(e) + } + } } - async fn reset(&self) -> QueryResult<()> { + fn reset(&self) -> QueryResult<()> { let sqlite3 = crate::get_sqlite_unchecked(); - let _ = sqlite3 - .reset(&self.inner_statement) - .await - .map_err(WasmSqliteError::from)?; + let rc = sqlite3.reset(&self.inner_statement); + ensure_sqlite_ok(rc, &self.raw_connection())?; Ok(()) } fn clear_bindings(&self) -> QueryResult<()> { let sqlite3 = crate::get_sqlite_unchecked(); - let _ = sqlite3 - .clear_bindings(&self.inner_statement) - .map_err(WasmSqliteError::from)?; + let rc = sqlite3.clear_bindings(&self.inner_statement); + ensure_sqlite_ok(rc, &self.raw_connection())?; Ok(()) } + + fn raw_connection(&self) -> JsValue { + let sqlite3 = crate::get_sqlite_unchecked(); + sqlite3.db_handle(&self.inner_statement) + } } impl Drop for Statement { fn drop(&mut self) { let sqlite3 = crate::get_sqlite_unchecked(); - // TODO:insipx potential problems here. - // wa-sqlite does not throw an error if finalize fails: -- it might just crash - // doc: https://rhashimoto.github.io/wa-sqlite/docs/interfaces/SQLiteAPI.html#finalize.finalize-1 - // in that case we might not know if this errored or not - // maybe depends how wasm panic/errors work - // Worth unit testing the Drop implementation. tracing::info!("Statement dropped & finalized!"); let _ = sqlite3 .finalize(&self.inner_statement) @@ -155,140 +200,159 @@ impl Drop for Statement { // * https://github.com/weiznich/diesel/pull/7 // * https://users.rust-lang.org/t/code-review-for-unsafe-code-in-diesel/66798/ // * https://github.com/rust-lang/unsafe-code-guidelines/issues/194 -struct BoundStatement<'stmt> { +struct BoundStatement<'stmt, 'query> { statement: MaybeCached<'stmt, Statement>, // we need to store the query here to ensure no one does // drop it till the end of the statement // We use a boxed queryfragment here just to erase the // generic type, we use NonNull to communicate // that this is a shared buffer - // query: Option>>, + query: Option + 'query>>, + binds_to_free: Vec<(i32, Option>)>, #[allow(unused)] - instrumentation: Arc>, + instrumentation: &'stmt mut dyn Instrumentation, has_error: bool, - drop_signal: Option>, } -impl<'stmt> BoundStatement<'stmt> { - fn bind( +impl<'stmt, 'query> BoundStatement<'stmt, 'query> { + fn bind( statement: MaybeCached<'stmt, Statement>, - bind_collector: SqliteBindCollectorData, - instrumentation: Arc>, - ) -> QueryResult> { - match &statement { - MaybeCached::CannotCache(s) => { - tracing::debug!("BoundStatement::bind, NOT CACHED statement={:?}", s) - } - MaybeCached::Cached(s) => { - tracing::debug!( - "BoundStatement::bind, MaybeCached::Cached statement={:?}", - s - ) - } - &_ => todo!(), - } - let SqliteBindCollectorData { binds } = bind_collector; - - let (tx, rx) = tokio::sync::oneshot::channel::(); - wasm_bindgen_futures::spawn_local(async move { - let result = (|| async move { - let inner_statement = rx.await?; - let this = Statement { inner_statement }; - this.reset().await?; - this.clear_bindings()?; - tracing::debug!("Bound statement dropped succesfully!"); - // we forget here because we need a clone that's sent to this task - // we don't want to `finalizing` this Statement yet (which is what - // dropping it would do); - std::mem::forget(this); - Ok::<_, WasmSqliteError>(()) - })(); - if let Err(e) = result.await { - tracing::error!("BoundStatement never dropped! {}", e); - } - }); + query: T, + instrumentation: &'stmt mut dyn Instrumentation, + ) -> QueryResult> + where + T: QueryFragment + QueryId + 'query, + { + // Don't use a trait object here to prevent using a virtual function call + // For sqlite this can introduce a measurable overhead + // Query is boxed here to make sure it won't move in memory anymore, so any bind + // it could output would stay valid. + let query = Box::new(query); + + let mut bind_collector = SqliteBindCollector::new(); + query.collect_binds(&mut bind_collector, &mut (), &WasmSqlite)?; + let SqliteBindCollector { binds } = bind_collector; let mut ret = BoundStatement { statement, + query: None, + binds_to_free: Vec::new(), instrumentation, has_error: false, - drop_signal: Some(tx), }; ret.bind_buffers(binds)?; + let query = query as Box + 'query>; + ret.query = Some(query); + Ok(ret) } // This is a separated function so that // not the whole constructor is generic over the query type T. // This hopefully prevents binary bloat. - fn bind_buffers(&mut self, binds: Vec<(OwnedSqliteBindValue, SqliteType)>) -> QueryResult<()> { + fn bind_buffers( + &mut self, + binds: Vec<(InternalSqliteBindValue<'_>, SqliteType)>, + ) -> QueryResult<()> { + self.binds_to_free.reserve( + binds + .iter() + .filter(|&(b, _)| { + matches!( + b, + InternalSqliteBindValue::BorrowedBinary(_) + | InternalSqliteBindValue::BorrowedString(_) + | InternalSqliteBindValue::String(_) + | InternalSqliteBindValue::Binary(_) + ) + }) + .count(), + ); for (bind_idx, (bind, tpe)) in (1..).zip(binds) { // It's safe to call bind here as: // * The type and value matches // * We ensure that corresponding buffers lives long enough below // * The statement is not used yet by `step` or anything else - let _ = self.statement.bind(tpe, bind, bind_idx)?; - - // we don't track binds to free like sqlite3 C bindings - // The assumption is that wa-sqlite, being WASM run in web browser that - // lies in the middle of rust -> sqlite, takes care of this for us. - // if we run into memory issues, especially memory leaks - // this should be the first place to pay attention to. - // - // The bindings shuold be collected/freed with JS once `clear_bindings` is - // run on `Drop` for `BoundStatement` + let res = self.statement.bind(tpe, bind, bind_idx)?; + + // it's important to push these only after + // the call to bind succeeded, otherwise we might attempt to + // call bind to an non-existing bind position in + // the destructor + + if let Some(ptr) = res { + // Store the id + pointer for a owned bind + // as we must unbind and free them on drop + self.binds_to_free.push((bind_idx, Some(ptr))); + } } Ok(()) } - fn finish_query_with_error(mut self, _e: &Error) { + fn finish_query_with_error(mut self, e: &Error) { + if let Some(q) = &self.query { + tracing::warn!( + "Query finished with error query={:?}, err={:?}", + &diesel::debug_query(&q), + e + ); + } self.has_error = true; } - - // FIXME: [`AsyncDrop`](https://github.com/rust-lang/rust/issues/126482) is a missing feature in rust. - // Until then we need to manually reset the statement object. - pub async fn reset(&mut self) -> QueryResult<()> { - self.statement.reset().await?; - self.statement.clear_bindings()?; - Ok(()) - } } -// Eventually replace with `AsyncDrop`: https://github.com/rust-lang/rust/issues/126482 -impl<'stmt> Drop for BoundStatement<'stmt> { +// we have to free the wawsm memory here not C memory so this will change significantly +impl<'stmt, 'query> Drop for BoundStatement<'stmt, 'query> { fn drop(&mut self) { - let sender = self.drop_signal.take().expect("Drop may only be ran once"); - let _ = sender.send(self.statement.inner_statement.clone()); + self.statement.reset().unwrap(); + self.statement.clear_bindings().unwrap(); + let wasm = ffi::get_sqlite_unchecked().inner().wasm(); + for (idx, buffer) in std::mem::take(&mut self.binds_to_free) { + // It's always safe to bind null values, as there is no buffer that needs to outlife something + self.statement + .bind(SqliteType::Text, InternalSqliteBindValue::Null, idx) + .expect( + "Binding a null value should never fail. \ + If you ever see this error message please open \ + an issue at diesels issue tracker containing \ + code how to trigger this message.", + ); + + if let Some(buffer) = buffer { + wasm.dealloc(buffer); + } + } } } #[allow(missing_debug_implementations)] -pub struct StatementUse<'stmt> { - statement: BoundStatement<'stmt>, +pub struct StatementUse<'stmt, 'query> { + statement: BoundStatement<'stmt, 'query>, column_names: OnceCell>, } -impl<'stmt> StatementUse<'stmt> { - pub(super) fn bind( +impl<'stmt, 'query> StatementUse<'stmt, 'query> { + pub(super) fn bind( statement: MaybeCached<'stmt, Statement>, - bind_collector: SqliteBindCollectorData, - instrumentation: Arc>, - ) -> QueryResult> -where { + query: T, + instrumentation: &'stmt mut dyn Instrumentation, + ) -> QueryResult> + where + T: QueryFragment + QueryId + 'query, + { Ok(Self { - statement: BoundStatement::bind(statement, bind_collector, instrumentation)?, + statement: BoundStatement::bind(statement, query, instrumentation)?, column_names: OnceCell::new(), }) } - pub(super) async fn run(mut self) -> QueryResult<()> { + pub(super) fn run(mut self) -> QueryResult<()> { // This is safe as we pass `first_step = true` // and we consume the statement so nobody could // access the columns later on anyway. - let r = self.step(true).await.map(|_| ()); - + let r = self.step(true).map(|_| ()); if let Err(ref e) = r { self.statement.finish_query_with_error(e); } @@ -301,21 +365,13 @@ where { // // It's always safe to call this function with `first_step = true` as this removes // the cached column names - pub(super) async fn step(&mut self, first_step: bool) -> QueryResult { + pub(super) fn step(&mut self, first_step: bool) -> QueryResult { let sqlite3 = crate::get_sqlite_unchecked(); - let res = match serde_wasm_bindgen::from_value::( - sqlite3 - .step(&self.statement.statement.inner_statement) - .await - .unwrap(), - ) - .unwrap() - { - sqlite_types::SQLITE_DONE => Ok(false), - sqlite_types::SQLITE_ROW => Ok(true), - _ => panic!("SQLite Step returned Unhandled Result Code. Turn into err message"), + let res = match sqlite3.step(&self.statement.statement.inner_statement) { + v if *ffi::SQLITE_DONE == v => Ok(false), + v if *ffi::SQLITE_ROW == v => Ok(true), + _ => Err(last_error(&self.statement.statement.raw_connection())), }; - if first_step { self.column_names = OnceCell::new(); } @@ -360,12 +416,12 @@ where { } pub(super) fn copy_value(&self, idx: i32) -> Option { - OwnedSqliteValue::copy_from_ptr(&self.column_value(idx)?.into()) + OwnedSqliteValue::copy_from_ptr(self.column_value(idx)) } - pub(super) fn column_value(&self, idx: i32) -> Option { + pub(super) fn column_value(&self, idx: i32) -> *mut u8 { let sqlite3 = crate::get_sqlite_unchecked(); - Some(sqlite3.column(&self.statement.statement.inner_statement, idx)) + sqlite3.column_value(&self.statement.statement.inner_statement, idx) } } diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 722b6e7b3..527547501 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -1,48 +1,180 @@ +mod constants; +mod wasm; + +use js_sys::{Object, Uint8Array, WebAssembly::Memory}; +use serde::{Deserialize, Serialize}; +use tokio::sync::OnceCell; use wasm_bindgen::{prelude::*, JsValue}; -/* once https://github.com/rust-lang/rust/issues/128183 is merged this would work -pub mod consts { - pub const SQLITE_INTEGER: i32 = super::SQLITE_INTEGER; +pub use constants::*; +pub use wasm::*; +// WASM is ran in the browser thread, either main or worker`. Tokio is only a single-threaded runtime. +// We need SQLite available globally, so this should be ok until we get threads with WASI or +// something. +unsafe impl Send for SQLite {} +unsafe impl Sync for SQLite {} + +/// The SQLite Library +/// this global constant references the loaded SQLite WASM. +pub(super) static SQLITE: OnceCell = OnceCell::const_new(); + +// it should be possible to: +// - shared WASM memory between us and SQLite, thereby reducing allocation overhead +// - Instantiate the WebAssembly.Module + WebAssembly.Instance from Rust (this could enable sharing +// of memory) +// - SQLite OpfsVfs just needs to be instantiated from WASM +// - OpfsVfs instantiation would be a one-time cost +// - this would make things overall more efficient since we wouldn't +// have to go through JS/browser at all. + +/// the raw WASM bytes +pub(super) const WASM: &[u8] = + include_bytes!("../node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm/sqlite3.wasm"); + +/// Options for instantiating memory constraints +#[derive(Serialize, Deserialize)] +struct MemoryOpts { + initial: u32, + maximum: u32, +} +/// Opts for the WASM Module +#[derive(Serialize, Deserialize)] +struct Opts { + /// The Sqlite3 WASM blob, compiled from C + #[serde(rename = "wasmBinary")] + wasm_binary: &'static [u8], + /// the shared WebAssembly Memory buffer + /// this allows us to manipulate the WASM memory from rust + #[serde(with = "serde_wasm_bindgen::preserve", rename = "wasmMemory")] + wasm_memory: Memory, + /// The URI for the OPFS async proxy. + #[serde(rename = "proxyUri")] + proxy_uri: String, } -*/ -// Constants -#[wasm_bindgen(module = "/src/wa-sqlite-diesel-bundle.js")] -extern "C" { - pub static SQLITE_DONE: i32; - pub static SQLITE_ROW: i32; - - // Fundamental datatypes. - // https://www.sqlite.org/c3ref/c_blob.html - pub static SQLITE_INTEGER: i32; - pub static SQLITE_FLOAT: i32; - pub static SQLITE_TEXT: i32; - pub static SQLITE_BLOB: i32; - pub static SQLITE_NULL: i32; +/// Copy the contents of this wasms typed array into SQLite's memory. +/// +/// This function will efficiently copy the memory from a typed +/// array into this wasm module's own linear memory, initializing +/// the memory destination provided. +/// +/// # Unsafety +/// +/// This function requires `dst` to point to a buffer +/// large enough to fit this array's contents. +pub fn raw_copy_to_sqlite>(bytes: B, dst: *mut u8) { + let wasm = get_sqlite_unchecked().inner().wasm(); + let bytes: Uint8Array = bytes.into(); + let wasm_sqlite_mem = wasm.heap8u(); + let offset = dst as usize / std::mem::size_of::(); + wasm_sqlite_mem.set(&bytes, offset as u32); } -// WASM is ran in the browser `main thread`. Tokio is only a single-threaded runtime. -// We need SQLite available globally, so this should be ok until we get threads with WASI or -// something. At which point we can (hopefully) use multi-threaded async runtime to block the -// thread and get SQLite. -unsafe impl Send for SQLite {} -unsafe impl Sync for SQLite {} +/// Copy the contents of this SQLite bytes this Wasms memory. +/// +/// This function will efficiently copy the memory from a typed +/// array into this wasm module's own linear memory, initializing +/// the memory destination provided. +/// +/// # Unsafety +/// +/// This function requires `buf` to point to a buffer +/// large enough to fit this array's contents. +pub unsafe fn raw_copy_from_sqlite(src: *mut u8, len: u32, buf: &mut [u8]) { + let wasm = crate::get_sqlite_unchecked().inner().wasm(); + let mem = wasm.heap8u(); + let offset = (src as u32) / std::mem::size_of::() as u32; + // this is safe because we view the slice and immediately copy it into + // our memory. + let view = Uint8Array::new_with_byte_offset_and_length(&mem, offset, len); + view.raw_copy_to_ptr(buf.as_mut_ptr()) +} + +pub async fn init_sqlite() { + SQLITE + .get_or_init(|| async { + let mem = serde_wasm_bindgen::to_value(&MemoryOpts { + initial: 16_777_216 / 65_536, + maximum: 2_147_483_648 / 65_536, + }) + .expect("Serialization must be infallible for const struct"); + let mem = Memory::new(&js_sys::Object::from(mem)) + .expect("Wasm Memory could not be instantiated"); + let opts = serde_wasm_bindgen::to_value(&Opts { + wasm_binary: WASM, + wasm_memory: mem, + proxy_uri: wasm_bindgen::link_to!(module = "/src/sqlite3-opfs-async-proxy.js"), + }) + .expect("serialization must be infallible for const struct"); + let opts = Object::from(opts); + let object = SQLite::init_module(&opts).await; + let sqlite3 = SQLite::new(object); + let version: crate::ffi::Version = serde_wasm_bindgen::from_value(sqlite3.version()) + .expect("Version unexpected format"); + tracing::info!( + "SQLite initialized. version={}, download_version={}", + version.lib_version, + version.download_version + ); + + sqlite3 + }) + .await; +} + +pub(super) fn get_sqlite_unchecked() -> &'static SQLite { + SQLITE.get().expect("SQLite is not initialized") +} + +#[wasm_bindgen] +#[derive(Serialize, Deserialize, Debug)] +struct Version { + #[serde(rename = "libVersion")] + lib_version: String, + #[serde(rename = "libVersionNumber")] + lib_version_number: u32, + #[serde(rename = "sourceId")] + source_id: String, + #[serde(rename = "downloadVersion")] + download_version: u32, +} -/// Direct Shim for wa-sqlite +/// Direct Sqlite3 bindings #[wasm_bindgen(module = "/src/wa-sqlite-diesel-bundle.js")] extern "C" { + #[derive(Debug)] pub type SQLite; - #[derive(Debug, Clone)] - #[wasm_bindgen(typescript_type = "SQLiteCompatibleType")] - pub type SQLiteCompatibleType; - // pub type SqlitePrepareOptions; + #[derive(Debug)] + #[wasm_bindgen(extends = SQLite)] + pub type Inner; + + #[wasm_bindgen(method, getter, js_name = "sqlite3")] + pub fn inner(this: &SQLite) -> Inner; + + #[wasm_bindgen(method, getter)] + pub fn wasm(this: &Inner) -> Wasm; + + #[wasm_bindgen(method, getter)] + pub fn capi(this: &Inner) -> CApi; + + #[wasm_bindgen(static_method_of = SQLite)] + pub async fn init_module(module: &Object) -> JsValue; #[wasm_bindgen(constructor)] pub fn new(module: JsValue) -> SQLite; - #[wasm_bindgen(static_method_of = SQLite)] - pub async fn wasm_module() -> JsValue; + #[wasm_bindgen(method)] + pub fn version(this: &SQLite) -> JsValue; + + #[wasm_bindgen(method)] + pub fn errstr(this: &SQLite, code: i32) -> String; + + #[wasm_bindgen(method)] + pub fn errmsg(this: &SQLite, conn: &JsValue) -> String; + + #[wasm_bindgen(method)] + pub fn extended_errcode(this: &SQLite, conn: &JsValue) -> i32; #[wasm_bindgen(method)] pub fn result_text(this: &SQLite, context: i32, value: String); @@ -62,94 +194,77 @@ extern "C" { #[wasm_bindgen(method)] pub fn result_null(this: &SQLite, context: i32); - #[wasm_bindgen(method, catch)] - pub fn bind( + #[wasm_bindgen(method)] + pub fn bind_parameter_count(this: &SQLite, stmt: &JsValue) -> i32; + + #[wasm_bindgen(method)] + pub fn bind_parameter_name(this: &SQLite, stmt: &JsValue, idx: i32) -> String; + + #[wasm_bindgen(method)] + pub fn bind_null(this: &SQLite, stmt: &JsValue, idx: i32) -> i32; + + #[wasm_bindgen(method)] + pub fn bind_text( this: &SQLite, stmt: &JsValue, idx: i32, - value: SQLiteCompatibleType, - ) -> Result; - /* - #[wasm_bindgen(method, catch)] - pub fn bind_blob( - this: &SQLite, - stmt: &JsValue, - idx: i32, - value: Vec, - ) -> Result; - - // JsValue here is an interesting type that needs to be ported in order to make use of this - // but not currently using it. - - #[wasm_bindgen(method, catch)] - pub fn bind_collection( - this: &SQLite, - stmt: &JsValue, - bindings: JsValue, - ) -> Result; - - #[wasm_bindgen(method, catch)] - pub fn bind_double(this: &SQLite, stmt: &JsValue, idx: i32, value: f64) - -> Result; - - #[wasm_bindgen(method, catch)] - pub fn bind_int(this: &SQLite, stmt: &JsValue, idx: i32, value: i32) -> Result; - - #[wasm_bindgen(method, catch)] - pub fn bind_int64(this: &SQLite, stmt: &JsValue, idx: i32, value: i64) -> Result; - - #[wasm_bindgen(method, catch)] - pub fn bind_null(this: &SQLite, stmt: &JsValue, idx: i32) -> Result; - */ + ptr: *mut u8, + len: i32, + flags: i32, + ) -> i32; + #[wasm_bindgen(method)] - pub fn bind_parameter_count(this: &SQLite, stmt: &JsValue) -> i32; + pub fn bind_blob( + this: &SQLite, + stmt: &JsValue, + idx: i32, + ptr: *mut u8, + len: i32, + flags: i32, + ) -> i32; #[wasm_bindgen(method)] - pub fn bind_parameter_name(this: &SQLite, stmt: &JsValue, idx: i32) -> String; + pub fn bind_double(this: &SQLite, stmt: &JsValue, idx: i32, value: f64) -> i32; - #[wasm_bindgen(method, catch)] - pub fn bind_text(this: &SQLite, stmt: &JsValue, idx: i32, value: &str) -> Result; + #[wasm_bindgen(method)] + pub fn bind_int(this: &SQLite, stmt: &JsValue, idx: i32, value: i32) -> i32; - #[wasm_bindgen(method, catch)] - pub async fn reset(this: &SQLite, stmt: &JsValue) -> Result; + #[wasm_bindgen(method)] + pub fn bind_int64(this: &SQLite, stmt: &JsValue, idx: i32, value: i64) -> i32; #[wasm_bindgen(method)] - pub fn value(this: &SQLite, pValue: &JsValue) -> SQLiteCompatibleType; + pub fn reset(this: &SQLite, stmt: &JsValue) -> i32; #[wasm_bindgen(method)] - pub fn value_dup(this: &SQLite, pValue: &JsValue) -> SQLiteCompatibleType; + pub fn value_dup(this: &SQLite, pValue: *mut u8) -> *mut u8; #[wasm_bindgen(method)] - pub fn value_blob(this: &SQLite, pValue: &JsValue) -> Vec; + pub fn value_blob(this: &SQLite, pValue: *mut u8) -> *mut u8; #[wasm_bindgen(method)] - pub fn value_bytes(this: &SQLite, pValue: &JsValue) -> i32; + pub fn value_bytes(this: &SQLite, pValue: *mut u8) -> u32; #[wasm_bindgen(method)] - pub fn value_double(this: &SQLite, pValue: &JsValue) -> f64; + pub fn value_double(this: &SQLite, pValue: *mut u8) -> f64; #[wasm_bindgen(method)] - pub fn value_int(this: &SQLite, pValue: &JsValue) -> i32; + pub fn value_int(this: &SQLite, pValue: *mut u8) -> i32; #[wasm_bindgen(method)] - pub fn value_int64(this: &SQLite, pValue: &JsValue) -> i64; + pub fn value_int64(this: &SQLite, pValue: *mut u8) -> i64; - // TODO: If wasm-bindgen allows returning references, could return &str #[wasm_bindgen(method)] - pub fn value_text(this: &SQLite, pValue: &JsValue) -> String; + pub fn value_text(this: &SQLite, pValue: *mut u8) -> String; #[wasm_bindgen(method)] - pub fn value_type(this: &SQLite, pValue: &JsValue) -> i32; + pub fn value_type(this: &SQLite, pValue: *mut u8) -> i32; #[wasm_bindgen(method, catch)] - pub async fn open_v2( - this: &SQLite, - database_url: &str, - iflags: Option, - ) -> Result; + pub fn open(this: &SQLite, database_url: &str, iflags: Option) + -> Result; #[wasm_bindgen(method, catch)] - pub async fn exec(this: &SQLite, database: &JsValue, query: &str) -> Result<(), JsValue>; + pub fn exec(this: &SQLite, database: &JsValue, query: &str) -> Result<(), JsValue>; #[wasm_bindgen(method, catch)] pub fn finalize(this: &SQLite, stmt: &JsValue) -> Result<(), JsValue>; @@ -158,30 +273,33 @@ extern "C" { pub fn changes(this: &SQLite, database: &JsValue) -> usize; #[wasm_bindgen(method, catch)] - pub async fn get_stmt_from_iterator( - this: &SQLite, - iterator: &JsValue, - ) -> Result; + pub fn get_stmt_from_iterator(this: &SQLite, iterator: &JsValue) -> Result; - #[wasm_bindgen(method, catch)] - pub async fn step(this: &SQLite, stmt: &JsValue) -> Result; + #[wasm_bindgen(method)] + pub fn step(this: &SQLite, stmt: &JsValue) -> i32; - #[wasm_bindgen(method, catch)] - pub fn clear_bindings(this: &SQLite, stmt: &JsValue) -> Result; + #[wasm_bindgen(method)] + pub fn clear_bindings(this: &SQLite, stmt: &JsValue) -> i32; - #[wasm_bindgen(method, catch)] - pub async fn close(this: &SQLite, database: &JsValue) -> Result<(), JsValue>; + #[wasm_bindgen(method)] + pub fn close(this: &SQLite, database: &JsValue) -> i32; #[wasm_bindgen(method)] - pub fn column(this: &SQLite, stmt: &JsValue, idx: i32) -> SQLiteCompatibleType; + pub fn db_handle(this: &SQLite, stmt: &JsValue) -> JsValue; - #[wasm_bindgen(method, catch)] - pub async fn prepare( + #[wasm_bindgen(method)] + pub fn column_value(this: &SQLite, stmt: &JsValue, idx: i32) -> *mut u8; + + #[wasm_bindgen(method)] + pub fn prepare_v3( this: &SQLite, database: &JsValue, sql: &str, - options: JsValue, - ) -> Result; + n_byte: i32, + prep_flags: u32, + stmt: &JsValue, + pzTail: &JsValue, + ) -> i32; #[wasm_bindgen(method)] pub fn column_name(this: &SQLite, stmt: &JsValue, idx: i32) -> String; @@ -189,13 +307,6 @@ extern "C" { #[wasm_bindgen(method)] pub fn column_count(this: &SQLite, stmt: &JsValue) -> i32; - #[wasm_bindgen(method, catch)] - pub async fn batch_execute( - this: &SQLite, - database: &JsValue, - query: &str, - ) -> Result<(), JsValue>; - #[wasm_bindgen(method, catch)] pub fn create_function( this: &SQLite, @@ -211,10 +322,8 @@ extern "C" { #[wasm_bindgen(method, catch)] pub fn register_diesel_sql_functions(this: &SQLite, database: &JsValue) -> Result<(), JsValue>; -} -impl std::fmt::Debug for SQLite { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!(f, "SQLite WASM bridge") - } + #[wasm_bindgen(method)] + pub fn value_free(this: &SQLite, value: *mut u8); + } diff --git a/diesel-wasm-sqlite/src/ffi/constants.rs b/diesel-wasm-sqlite/src/ffi/constants.rs new file mode 100644 index 000000000..5ed3708cc --- /dev/null +++ b/diesel-wasm-sqlite/src/ffi/constants.rs @@ -0,0 +1,180 @@ +//! WASM Constant bindings +use std::cell::LazyCell; +use wasm_bindgen::prelude::*; + +/// Normally, statics or methods cannot be pattern-matched. +/// Pattern matching also does not automatically dereference. +/// constants are imported into wasm-bindgen as statics and/or const +/// methods. We use a combination of `LazyCell` +/// and exported wasm getters to achieve some kind of +/// pattern-matching syntax +/// ``` +/// match variable { +/// v if *ffi::SQLITE_DONE == v { +/// /* SQLITE_DONE */ +/// }, +/// v if *ffi:SQLITE_ROW == v { +/// /* SQLITE_ROW */ +/// } +/// } +/// ``` +/// +/// This is also a micro-optimization, +/// These constants will be initialized exactly once, rather +/// than on every access thus reducing the context-switching between wasm-js barrier. +macro_rules! generate_sqlite_constant { + ($fn_name:ident, $ty: ident) => { + pub const $fn_name: LazyCell<$ty> = LazyCell::new(|| { + let capi: CApi = crate::get_sqlite_unchecked().inner().capi(); + CApi::$fn_name(&capi) + }); + }; +} + +generate_sqlite_constant!(SQLITE_OK, i32); + +generate_sqlite_constant!(SQLITE_DONE, i32); +generate_sqlite_constant!(SQLITE_ROW, i32); + +generate_sqlite_constant!(SQLITE_INTEGER, i32); +generate_sqlite_constant!(SQLITE_FLOAT, i32); +generate_sqlite_constant!(SQLITE_TEXT, i32); +generate_sqlite_constant!(SQLITE_BLOB, i32); +generate_sqlite_constant!(SQLITE_NULL, i32); + +generate_sqlite_constant!(SQLITE_PREPARE_PERSISTENT, u32); + +generate_sqlite_constant!(SQLITE_CONSTRAINT_PRIMARYKEY, i32); +generate_sqlite_constant!(SQLITE_CONSTRAINT_UNIQUE, i32); +generate_sqlite_constant!(SQLITE_CONSTRAINT_FOREIGNKEY, i32); +generate_sqlite_constant!(SQLITE_CONSTRAINT_NOTNULL, i32); +generate_sqlite_constant!(SQLITE_CONSTRAINT_CHECK, i32); + +generate_sqlite_constant!(SQLITE_STATIC, i32); + +// C-Style API Constants +#[wasm_bindgen] +extern "C" { + /// C-Api Style bindings + #[wasm_bindgen(extends = super::Inner)] + pub type CApi; + + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OK(this: &CApi) -> i32; + + /// SQLite statement returns + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_DONE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_ROW(this: &CApi) -> i32; + + // Fundamental datatypes. + // https://www.sqlite.org/c3ref/c_blob.html + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_INTEGER(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_FLOAT(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_TEXT(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_BLOB(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_NULL(this: &CApi) -> i32; + + /// SQLite Open Flags + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_READONLY(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_READWRITE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_CREATE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_DELETEONCLOSE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_EXCLUSIVE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_AUTOPROXY(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_URI(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_MEMORY(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_MAIN_DB(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_TEMP_DB(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_TRANSIENT_DB(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_MAIN_JOURNAL(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_TEMP_JOURNAL(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_SUBJOURNAL(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_SUPER_JOURNAL(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_NOMUTEX(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_FULLMUTEX(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_SHAREDCACHE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_PRIVATECACHE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_WAL(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_NOFOLLOW(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_OPEN_EXRESCODE(this: &CApi) -> i32; + + // SQLite Text Encodings https://www.sqlite.org/capi3ref.html#SQLITE_ANY + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_UTF8(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_UTF16LE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_UTF16BE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_UTF16(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_ANY(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_UTF16_ALIGNED(this: &CApi) -> i32; + + /// SQLite Function Flags https://www.sqlite.org/capi3ref.html#sqlitedeterministic + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_DETERMINISTIC(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_DIRECTONLY(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_SUBTYPE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_INNOCUOUS(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_RESULT_SUBTYPE(this: &CApi) -> i32; + + // SQLite Prepare Flags https://www.sqlite.org/c3ref/c_prepare_normalize.html#sqlitepreparepersistent + #[wasm_bindgen(method, getter)] + pub const fn SQLITE_PREPARE_PERSISTENT(this: &CApi) -> u32; + #[wasm_bindgen(method, getter)] + pub fn SQLITE_PREPARE_NORMALIZE(this: &CApi) -> u32; + #[wasm_bindgen(method, getter)] + pub fn SQLITE_PREPARE_NO_VTAB(this: &CApi) -> u32; + + /// Constraint + + #[wasm_bindgen(method, getter)] + pub fn SQLITE_CONSTRAINT_UNIQUE(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub fn SQLITE_CONSTRAINT_PRIMARYKEY(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub fn SQLITE_CONSTRAINT_FOREIGNKEY(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub fn SQLITE_CONSTRAINT_NOTNULL(this: &CApi) -> i32; + #[wasm_bindgen(method, getter)] + pub fn SQLITE_CONSTRAINT_CHECK(this: &CApi) -> i32; + + /// Binds + #[wasm_bindgen(method, getter)] + pub fn SQLITE_STATIC(this: &CApi) -> i32; +} diff --git a/diesel-wasm-sqlite/src/ffi/wasm.rs b/diesel-wasm-sqlite/src/ffi/wasm.rs new file mode 100644 index 000000000..3f02bdd55 --- /dev/null +++ b/diesel-wasm-sqlite/src/ffi/wasm.rs @@ -0,0 +1,65 @@ +//! WASM bindings for memory management +use std::ptr::NonNull; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + #[derive(Debug)] + #[wasm_bindgen(extends = super::Inner)] + pub type Wasm; + + #[wasm_bindgen(method, js_name = "peekPtr")] + pub fn peek_ptr(this: &Wasm, stmt: &JsValue) -> JsValue; + /// The "pstack" (pseudo-stack) API is a special-purpose allocator + /// intended solely for use with allocating small amounts of memory such + /// as that needed for output pointers. + /// It is more efficient than the scoped allocation API, + /// and covers many of the use cases for that API, but it + /// has a tiny static memory limit (with an unspecified total size no less than 4kb). + #[wasm_bindgen(method, getter)] + pub fn pstack(this: &Wasm) -> PStack; + + #[wasm_bindgen(method)] + pub fn alloc(this: &Wasm, bytes: u32) -> *mut u8; + + // Uses alloc() to allocate enough memory for the byte-length of the given JS string, plus 1 (for a NUL terminator), copies the given JS string to that memory using jstrcpy(), NUL-terminates it, and returns the pointer to that C-string. Ownership of the pointer is transfered to the caller, who must eventually pass the pointer to dealloc() to free it. + // + #[wasm_bindgen(method, js_name = "allocCString")] + pub fn alloc_cstring(this: &Wasm, string: String) -> *mut u8; + + #[wasm_bindgen(method)] + pub fn dealloc(this: &Wasm, ptr: NonNull); + + /// View into the wasm memory reprsented as unsigned 8-bit integers + #[wasm_bindgen(method)] + pub fn heap8u(this: &Wasm) -> js_sys::Uint8Array; +} + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(extends = Wasm)] + pub type PStack; + + /// allocate some memory on the PStack + #[wasm_bindgen(method)] + pub fn alloc(this: &PStack, bytes: u32) -> JsValue; + + /// Resolves the current pstack position pointer. + /// should only be used in argument for `restore` + #[wasm_bindgen(method, getter)] + pub fn pointer(this: &PStack) -> JsValue; + + /// resolves to total number of bytes available in pstack, including any + /// space currently allocated. compile-time constant + #[wasm_bindgen(method, getter)] + pub fn quota(this: &PStack) -> u32; + + // Property resolves to the amount of space remaining in the pstack + #[wasm_bindgen(method, getter)] + pub fn remaining(this: &PStack) -> u32; + + /// sets current pstack + #[wasm_bindgen(method)] + pub fn restore(this: &PStack, ptr: &JsValue); + +} diff --git a/diesel-wasm-sqlite/src/lib.rs b/diesel-wasm-sqlite/src/lib.rs index 84e816935..5fb80d088 100755 --- a/diesel-wasm-sqlite/src/lib.rs +++ b/diesel-wasm-sqlite/src/lib.rs @@ -3,60 +3,35 @@ pub mod backend; pub mod connection; pub mod ffi; pub mod query_builder; -pub mod sqlite_types; -pub mod utils; pub mod sqlite_fixes; -// pub mod migrations; +pub mod sqlite_types; + +#[global_allocator] +static ALLOCATOR: talc::TalckWasm = unsafe { talc::TalckWasm::new_global() }; #[cfg(any(feature = "unsafe-debug-query", test))] pub use query_builder::insert_with_default_sqlite::unsafe_debug_query::DebugQueryWrapper; - #[cfg(not(target_arch = "wasm32"))] compile_error!("This crate only suports the `wasm32-unknown-unknown` target"); -use self::ffi::SQLite; -use tokio::sync::OnceCell; +#[cfg(any(test))] +pub use test_common::*; + use wasm_bindgen::JsValue; -use std::cell::LazyCell; pub use backend::{SqliteType, WasmSqlite}; - -/// the local tokio current-thread runtime -/// dont need locking, because this is current-thread only -const RUNTIME: LazyCell = LazyCell::new(|| { - tokio::runtime::Builder::new_current_thread() - .build() - .expect("Runtime should never fail to build") -}); - -/// The SQLite Library -/// this global constant references the loaded SQLite WASM. -static SQLITE: OnceCell = OnceCell::const_new(); - -pub type SQLiteWasm = &'static JsValue; - -pub(crate) async fn get_sqlite() -> &'static SQLite { - SQLITE - .get_or_init(|| async { - let module = SQLite::wasm_module().await; - SQLite::new(module) - }) - .await -} - -pub(crate) fn get_sqlite_unchecked() -> &'static SQLite { - SQLITE.get().expect("SQLite is not initialized") -} +pub(crate) use ffi::get_sqlite_unchecked; +pub use ffi::init_sqlite; #[derive(thiserror::Error, Debug)] pub enum WasmSqliteError { #[error("JS Bridge Error {0:?}")] Js(JsValue), #[error(transparent)] - OneshotRecv(#[from] tokio::sync::oneshot::error::RecvError), + Diesel(#[from] diesel::result::Error), #[error(transparent)] - Diesel(#[from] diesel::result::Error) + Bindgen(#[from] serde_wasm_bindgen::Error), } impl From for diesel::result::Error { @@ -79,3 +54,12 @@ impl From for WasmSqliteError { } } +#[cfg(any(test, feature = "test-util"))] +pub mod test_common { + use super::connection::WasmSqliteConnection; + use diesel::Connection; + pub async fn connection() -> WasmSqliteConnection { + crate::init_sqlite().await; + WasmSqliteConnection::establish(":memory:").unwrap() + } +} diff --git a/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs b/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs index 0d65f40bb..344db3b68 100644 --- a/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs +++ b/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs @@ -1,27 +1,26 @@ use crate::{connection::WasmSqliteConnection, WasmSqlite}; +use diesel::connection::Connection; use diesel::insertable::InsertValues; use diesel::insertable::{CanInsertInSingleQuery, ColumnInsertValue, DefaultableColumnInsertValue}; +use diesel::prelude::RunQueryDsl; +use diesel::query_builder::QueryFragment; use diesel::query_builder::{AstPass, QueryId, ValuesClause}; use diesel::query_builder::{BatchInsert, InsertStatement}; -use diesel::query_builder::QueryFragment; +use diesel::query_dsl::load_dsl::ExecuteDsl; use diesel::{QueryResult, QuerySource, Table}; -use diesel_async::scoped_futures::ScopedFutureExt; -use diesel_async::{methods::ExecuteDsl, AsyncConnection, RunQueryDsl}; - #[cfg(any(feature = "unsafe-debug-query", test))] pub mod unsafe_debug_query { use super::*; use diesel::backend::Backend; use diesel::{debug_query, query_builder::DebugQuery}; - use futures_util::future::LocalBoxFuture; use std::fmt::{self, Debug, Display}; pub trait DebugQueryHelper { fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; } - + // FIXME: Here to temporarily workaround private fields of `DebugQuery`. // this should never go in prod // this is cause `DebugQuery` is private @@ -34,7 +33,12 @@ pub mod unsafe_debug_query { impl<'a, T, V, QId, Op, Ret, const STATIC_QUERY_ID: bool> DebugQueryHelper for DebugQuery< 'a, - InsertStatement>, T, QId, STATIC_QUERY_ID>, Op, Ret>, + InsertStatement< + T, + BatchInsert>, T, QId, STATIC_QUERY_ID>, + Op, + Ret, + >, WasmSqlite, > where @@ -72,7 +76,8 @@ pub mod unsafe_debug_query { let query = query.query; let mut statements = vec![String::from("BEGIN")]; for record in query.records.values.iter() { - let stmt = InsertStatement::new(query.target, record, query.operator, query.returning); + let stmt = + InsertStatement::new(query.target, record, query.operator, query.returning); statements.push(debug_query(&stmt).to_string()); } statements.push("COMMIT".into()); @@ -110,7 +115,8 @@ pub mod unsafe_debug_query { let query = query.query; writeln!(f, "BEGIN;")?; for record in query.records.values.iter() { - let stmt = InsertStatement::new(query.target, record, query.operator, query.returning); + let stmt = + InsertStatement::new(query.target, record, query.operator, query.returning); writeln!(f, "{}", debug_query(&stmt))?; } writeln!(f, "COMMIT;")?; @@ -120,7 +126,11 @@ pub mod unsafe_debug_query { #[allow(unsafe_code)] // cast to transparent wrapper type impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> DebugQueryHelper - for DebugQuery<'a, InsertStatement, Op>, WasmSqlite> + for DebugQuery< + 'a, + InsertStatement, Op>, + WasmSqlite, + > where T: Copy + QuerySource, Op: Copy, @@ -140,7 +150,11 @@ pub mod unsafe_debug_query { > as *const DebugQuery< 'a, - InsertStatement, Op>, + InsertStatement< + T, + SqliteBatchInsertWrapper, + Op, + >, WasmSqlite, >) }; @@ -156,7 +170,11 @@ pub mod unsafe_debug_query { > as *const DebugQuery< 'a, - InsertStatement, Op>, + InsertStatement< + T, + SqliteBatchInsertWrapper, + Op, + >, WasmSqlite, >) }; @@ -166,7 +184,6 @@ pub mod unsafe_debug_query { pub struct DebugQueryWrapper<'a, T: 'a, DB>(DebugQuery<'a, T, DB>); - impl<'a, T, DB> DebugQueryWrapper<'a, T, DB> { pub fn new(query: &'a T) -> Self { DebugQueryWrapper(diesel::debug_query(query)) @@ -195,12 +212,15 @@ pub mod unsafe_debug_query { } } - - impl<'a, T, V, QId, Op, Ret, const STATIC_QUERY_ID: bool> DebugQueryHelper for DebugQueryWrapper< 'a, - InsertStatement>, T, QId, STATIC_QUERY_ID>, Op, Ret>, + InsertStatement< + T, + BatchInsert>, T, QId, STATIC_QUERY_ID>, + Op, + Ret, + >, WasmSqlite, > where @@ -213,14 +233,18 @@ pub mod unsafe_debug_query { fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DebugQueryHelper::fmt_debug(&self.0, f) } - + fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DebugQueryHelper::fmt_display(&self.0, f) } } impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> DebugQueryHelper - for DebugQueryWrapper<'a, InsertStatement, Op>, WasmSqlite> + for DebugQueryWrapper< + 'a, + InsertStatement, Op>, + WasmSqlite, + > where T: Copy + QuerySource, Op: Copy, @@ -233,13 +257,12 @@ pub mod unsafe_debug_query { fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DebugQueryHelper::fmt_debug(&self.0, f) } - + fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DebugQueryHelper::fmt_display(&self.0, f) } } - impl<'a, T, V, QId, Op, O, const STATIC_QUERY_ID: bool> Display for DebugQueryWrapper< 'a, @@ -256,7 +279,6 @@ pub mod unsafe_debug_query { } } - impl<'a, T, V, QId, Op, O, const STATIC_QUERY_ID: bool> Debug for DebugQueryWrapper< 'a, @@ -353,10 +375,7 @@ where O: Default, (O, Self): ExecuteDsl, { - fn execute<'conn, 'query>( - query: Self, - conn: &'conn mut WasmSqliteConnection, - ) -> ::ExecuteFuture<'conn, 'query> { + fn execute(query: Self, conn: &mut WasmSqliteConnection) -> QueryResult { <(O, Self) as ExecuteDsl>::execute( (O::default(), query), conn, @@ -370,35 +389,20 @@ impl ExecuteDsl>, T, QId, STATIC_QUERY_ID>, Op>, ) where - for<'query> T: Table + Copy + QueryId + std::fmt::Debug + 'query, + T: Table + Copy + QueryId + 'static, T::FromClause: QueryFragment, - for<'query> Op: Copy + QueryId + QueryFragment + 'query + std::fmt::Debug, - for<'query> V: - InsertValues + CanInsertInSingleQuery + QueryId + std::fmt::Debug + 'query, - ::FromClause: std::fmt::Debug, - for<'query> QId: std::fmt::Debug + 'query + Op: Copy + QueryId + QueryFragment, + V: InsertValues + CanInsertInSingleQuery + QueryId, { - fn execute<'conn, 'query>( - (Yes, query): Self, - conn: &'conn mut WasmSqliteConnection, - ) -> ::ExecuteFuture<'conn, 'query> - where - Self: 'query, - { - conn.transaction(move |conn| { - async move { - let mut result = 0; - // tracing::debug!("QUERY {:?}", query); - for record in &query.records.values { - // tracing::debug!("processing record {:?}", record); - let stmt = - InsertStatement::new(query.target, record, query.operator, query.returning); - // tracing::debug!("Processing statement {:?}", stmt); - result += stmt.execute(conn).await?; - } - Ok(result) + fn execute((Yes, query): Self, conn: &mut WasmSqliteConnection) -> QueryResult { + conn.transaction(|conn| { + let mut result = 0; + for record in &query.records.values { + let stmt = + InsertStatement::new(query.target, record, query.operator, query.returning); + result += stmt.execute(conn)?; } - .scope_boxed_local() + Ok(result) }) } } @@ -477,18 +481,13 @@ impl ExecuteDsl, Op>, ) where - for<'query> T: Table + QueryId + 'query, + T: Table + QueryId + 'static, T::FromClause: QueryFragment, - for<'query> Op: QueryFragment + QueryId + 'query, - for<'query> V: 'query, - for<'query> QId: 'query, + Op: QueryFragment + QueryId, SqliteBatchInsertWrapper: QueryFragment + QueryId + CanInsertInSingleQuery, { - fn execute<'conn, 'query>( - (No, query): Self, - conn: &'conn mut WasmSqliteConnection, - ) -> ::ExecuteFuture<'conn, 'query> { + fn execute((No, query): Self, conn: &mut WasmSqliteConnection) -> QueryResult { let query = InsertStatement::new( query.target, SqliteBatchInsertWrapper(query.records), diff --git a/diesel-wasm-sqlite/src/sqlite3-opfs-async-proxy.js b/diesel-wasm-sqlite/src/sqlite3-opfs-async-proxy.js new file mode 100644 index 000000000..07d4ac1f8 --- /dev/null +++ b/diesel-wasm-sqlite/src/sqlite3-opfs-async-proxy.js @@ -0,0 +1,692 @@ +/* + 2022-09-16 + + The author disclaims copyright to this source code. In place of a + legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + + *********************************************************************** + + A Worker which manages asynchronous OPFS handles on behalf of a + synchronous API which controls it via a combination of Worker + messages, SharedArrayBuffer, and Atomics. It is the asynchronous + counterpart of the API defined in sqlite3-vfs-opfs.js. + + Highly indebted to: + + https://github.com/rhashimoto/wa-sqlite/blob/master/src/examples/OriginPrivateFileSystemVFS.js + + for demonstrating how to use the OPFS APIs. + + This file is to be loaded as a Worker. It does not have any direct + access to the sqlite3 JS/WASM bits, so any bits which it needs (most + notably SQLITE_xxx integer codes) have to be imported into it via an + initialization process. + + This file represents an implementation detail of a larger piece of + code, and not a public interface. Its details may change at any time + and are not intended to be used by any client-level code. + + 2022-11-27: Chrome v108 changes some async methods to synchronous, as + documented at: + + https://developer.chrome.com/blog/sync-methods-for-accesshandles/ + + Firefox v111 and Safari 16.4, both released in March 2023, also + include this. + + We cannot change to the sync forms at this point without breaking + clients who use Chrome v104-ish or higher. truncate(), getSize(), + flush(), and close() are now (as of v108) synchronous. Calling them + with an "await", as we have to for the async forms, is still legal + with the sync forms but is superfluous. Calling the async forms with + theFunc().then(...) is not compatible with the change to + synchronous, but we do do not use those APIs that way. i.e. we don't + _need_ to change anything for this, but at some point (after Chrome + versions (approximately) 104-107 are extinct) should change our + usage of those methods to remove the "await". +*/ +const wPost = (type, ...args) => postMessage({ type, payload: args }); +const installAsyncProxy = function () { + const toss = function (...args) { + throw new Error(args.join(' ')); + }; + if (globalThis.window === globalThis) { + toss( + 'This code cannot run from the main thread.', + 'Load it as a Worker from a separate Worker.', + ); + } else if (!navigator?.storage?.getDirectory) { + toss('This API requires navigator.storage.getDirectory.'); + } + + const state = Object.create(null); + + state.verbose = 1; + + const loggers = { + 0: console.error.bind(console), + 1: console.warn.bind(console), + 2: console.log.bind(console), + }; + const logImpl = (level, ...args) => { + if (state.verbose > level) loggers[level]('OPFS asyncer:', ...args); + }; + const log = (...args) => logImpl(2, ...args); + const warn = (...args) => logImpl(1, ...args); + const error = (...args) => logImpl(0, ...args); + + const __openFiles = Object.create(null); + + const __implicitLocks = new Set(); + + const getResolvedPath = function (filename, splitIt) { + const p = new URL(filename, 'file://irrelevant').pathname; + return splitIt ? p.split('/').filter((v) => !!v) : p; + }; + + const getDirForFilename = async function f(absFilename, createDirs = false) { + const path = getResolvedPath(absFilename, true); + const filename = path.pop(); + let dh = state.rootDir; + for (const dirName of path) { + if (dirName) { + dh = await dh.getDirectoryHandle(dirName, { create: !!createDirs }); + } + } + return [dh, filename]; + }; + + const closeSyncHandle = async (fh) => { + if (fh.syncHandle) { + log('Closing sync handle for', fh.filenameAbs); + const h = fh.syncHandle; + delete fh.syncHandle; + delete fh.xLock; + __implicitLocks.delete(fh.fid); + return h.close(); + } + }; + + const closeSyncHandleNoThrow = async (fh) => { + try { + await closeSyncHandle(fh); + } catch (e) { + warn('closeSyncHandleNoThrow() ignoring:', e, fh); + } + }; + + const releaseImplicitLocks = async () => { + if (__implicitLocks.size) { + for (const fid of __implicitLocks) { + const fh = __openFiles[fid]; + await closeSyncHandleNoThrow(fh); + log('Auto-unlocked', fid, fh.filenameAbs); + } + } + }; + + const releaseImplicitLock = async (fh) => { + if (fh.releaseImplicitLocks && __implicitLocks.has(fh.fid)) { + return closeSyncHandleNoThrow(fh); + } + }; + + class GetSyncHandleError extends Error { + constructor(errorObject, ...msg) { + super( + [...msg, ': ' + errorObject.name + ':', errorObject.message].join(' '), + { + cause: errorObject, + }, + ); + this.name = 'GetSyncHandleError'; + } + } + + GetSyncHandleError.convertRc = (e, rc) => { + if (e instanceof GetSyncHandleError) { + if ( + e.cause.name === 'NoModificationAllowedError' || + (e.cause.name === 'DOMException' && + 0 === e.cause.message.indexOf('Access Handles cannot')) + ) { + return state.sq3Codes.SQLITE_BUSY; + } else if ('NotFoundError' === e.cause.name) { + return state.sq3Codes.SQLITE_CANTOPEN; + } + } else if ('NotFoundError' === e?.name) { + return state.sq3Codes.SQLITE_CANTOPEN; + } + return rc; + }; + + const getSyncHandle = async (fh, opName) => { + if (!fh.syncHandle) { + const t = performance.now(); + log('Acquiring sync handle for', fh.filenameAbs); + const maxTries = 6, + msBase = state.asyncIdleWaitTime * 2; + let i = 1, + ms = msBase; + for (; true; ms = msBase * ++i) { + try { + fh.syncHandle = await fh.fileHandle.createSyncAccessHandle(); + break; + } catch (e) { + if (i === maxTries) { + throw new GetSyncHandleError( + e, + 'Error getting sync handle for', + opName + '().', + maxTries, + 'attempts failed.', + fh.filenameAbs, + ); + } + warn( + 'Error getting sync handle for', + opName + '(). Waiting', + ms, + 'ms and trying again.', + fh.filenameAbs, + e, + ); + Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms); + } + } + log( + 'Got', + opName + '() sync handle for', + fh.filenameAbs, + 'in', + performance.now() - t, + 'ms', + ); + if (!fh.xLock) { + __implicitLocks.add(fh.fid); + log( + 'Acquired implicit lock for', + opName + '()', + fh.fid, + fh.filenameAbs, + ); + } + } + return fh.syncHandle; + }; + + const storeAndNotify = (opName, value) => { + log(opName + '() => notify(', value, ')'); + Atomics.store(state.sabOPView, state.opIds.rc, value); + Atomics.notify(state.sabOPView, state.opIds.rc); + }; + + const affirmNotRO = function (opName, fh) { + if (fh.readOnly) toss(opName + '(): File is read-only: ' + fh.filenameAbs); + }; + + let flagAsyncShutdown = false; + + const vfsAsyncImpls = { + 'opfs-async-shutdown': async () => { + flagAsyncShutdown = true; + storeAndNotify('opfs-async-shutdown', 0); + }, + mkdir: async (dirname) => { + let rc = 0; + try { + await getDirForFilename(dirname + '/filepart', true); + } catch (e) { + state.s11n.storeException(2, e); + rc = state.sq3Codes.SQLITE_IOERR; + } + storeAndNotify('mkdir', rc); + }, + xAccess: async (filename) => { + let rc = 0; + try { + const [dh, fn] = await getDirForFilename(filename); + await dh.getFileHandle(fn); + } catch (e) { + state.s11n.storeException(2, e); + rc = state.sq3Codes.SQLITE_IOERR; + } + storeAndNotify('xAccess', rc); + }, + xClose: async function (fid) { + const opName = 'xClose'; + __implicitLocks.delete(fid); + const fh = __openFiles[fid]; + let rc = 0; + if (fh) { + delete __openFiles[fid]; + await closeSyncHandle(fh); + if (fh.deleteOnClose) { + try { + await fh.dirHandle.removeEntry(fh.filenamePart); + } catch (e) { + warn('Ignoring dirHandle.removeEntry() failure of', fh, e); + } + } + } else { + state.s11n.serialize(); + rc = state.sq3Codes.SQLITE_NOTFOUND; + } + storeAndNotify(opName, rc); + }, + xDelete: async function (...args) { + const rc = await vfsAsyncImpls.xDeleteNoWait(...args); + storeAndNotify('xDelete', rc); + }, + xDeleteNoWait: async function (filename, syncDir = 0, recursive = false) { + let rc = 0; + try { + while (filename) { + const [hDir, filenamePart] = await getDirForFilename(filename, false); + if (!filenamePart) break; + await hDir.removeEntry(filenamePart, { recursive }); + if (0x1234 !== syncDir) break; + recursive = false; + filename = getResolvedPath(filename, true); + filename.pop(); + filename = filename.join('/'); + } + } catch (e) { + state.s11n.storeException(2, e); + rc = state.sq3Codes.SQLITE_IOERR_DELETE; + } + return rc; + }, + xFileSize: async function (fid) { + const fh = __openFiles[fid]; + let rc = 0; + try { + const sz = await (await getSyncHandle(fh, 'xFileSize')).getSize(); + state.s11n.serialize(Number(sz)); + } catch (e) { + state.s11n.storeException(1, e); + rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR); + } + await releaseImplicitLock(fh); + storeAndNotify('xFileSize', rc); + }, + xLock: async function (fid, lockType) { + const fh = __openFiles[fid]; + let rc = 0; + const oldLockType = fh.xLock; + fh.xLock = lockType; + if (!fh.syncHandle) { + try { + await getSyncHandle(fh, 'xLock'); + __implicitLocks.delete(fid); + } catch (e) { + state.s11n.storeException(1, e); + rc = GetSyncHandleError.convertRc( + e, + state.sq3Codes.SQLITE_IOERR_LOCK, + ); + fh.xLock = oldLockType; + } + } + storeAndNotify('xLock', rc); + }, + xOpen: async function (fid, filename, flags, opfsFlags) { + const opName = 'xOpen'; + const create = state.sq3Codes.SQLITE_OPEN_CREATE & flags; + try { + let hDir, filenamePart; + try { + [hDir, filenamePart] = await getDirForFilename(filename, !!create); + } catch (e) { + state.s11n.storeException(1, e); + storeAndNotify(opName, state.sq3Codes.SQLITE_NOTFOUND); + return; + } + if (state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN & opfsFlags) { + try { + await hDir.removeEntry(filenamePart); + } catch (e) {} + } + const hFile = await hDir.getFileHandle(filenamePart, { create }); + const fh = Object.assign(Object.create(null), { + fid: fid, + filenameAbs: filename, + filenamePart: filenamePart, + dirHandle: hDir, + fileHandle: hFile, + sabView: state.sabFileBufView, + readOnly: create + ? false + : state.sq3Codes.SQLITE_OPEN_READONLY & flags, + deleteOnClose: !!(state.sq3Codes.SQLITE_OPEN_DELETEONCLOSE & flags), + }); + fh.releaseImplicitLocks = + opfsFlags & state.opfsFlags.OPFS_UNLOCK_ASAP || + state.opfsFlags.defaultUnlockAsap; + __openFiles[fid] = fh; + storeAndNotify(opName, 0); + } catch (e) { + error(opName, e); + state.s11n.storeException(1, e); + storeAndNotify(opName, state.sq3Codes.SQLITE_IOERR); + } + }, + xRead: async function (fid, n, offset64) { + let rc = 0, + nRead; + const fh = __openFiles[fid]; + try { + nRead = (await getSyncHandle(fh, 'xRead')).read( + fh.sabView.subarray(0, n), + { at: Number(offset64) }, + ); + if (nRead < n) { + fh.sabView.fill(0, nRead, n); + rc = state.sq3Codes.SQLITE_IOERR_SHORT_READ; + } + } catch (e) { + error('xRead() failed', e, fh); + state.s11n.storeException(1, e); + rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_READ); + } + await releaseImplicitLock(fh); + storeAndNotify('xRead', rc); + }, + xSync: async function (fid, flags) { + const fh = __openFiles[fid]; + let rc = 0; + if (!fh.readOnly && fh.syncHandle) { + try { + await fh.syncHandle.flush(); + } catch (e) { + state.s11n.storeException(2, e); + rc = state.sq3Codes.SQLITE_IOERR_FSYNC; + } + } + storeAndNotify('xSync', rc); + }, + xTruncate: async function (fid, size) { + let rc = 0; + const fh = __openFiles[fid]; + try { + affirmNotRO('xTruncate', fh); + await (await getSyncHandle(fh, 'xTruncate')).truncate(size); + } catch (e) { + error('xTruncate():', e, fh); + state.s11n.storeException(2, e); + rc = GetSyncHandleError.convertRc( + e, + state.sq3Codes.SQLITE_IOERR_TRUNCATE, + ); + } + await releaseImplicitLock(fh); + storeAndNotify('xTruncate', rc); + }, + xUnlock: async function (fid, lockType) { + let rc = 0; + const fh = __openFiles[fid]; + if (state.sq3Codes.SQLITE_LOCK_NONE === lockType && fh.syncHandle) { + try { + await closeSyncHandle(fh); + } catch (e) { + state.s11n.storeException(1, e); + rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; + } + } + storeAndNotify('xUnlock', rc); + }, + xWrite: async function (fid, n, offset64) { + let rc; + const fh = __openFiles[fid]; + try { + affirmNotRO('xWrite', fh); + rc = + n === + (await getSyncHandle(fh, 'xWrite')).write(fh.sabView.subarray(0, n), { + at: Number(offset64), + }) + ? 0 + : state.sq3Codes.SQLITE_IOERR_WRITE; + } catch (e) { + error('xWrite():', e, fh); + state.s11n.storeException(1, e); + rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_WRITE); + } + await releaseImplicitLock(fh); + storeAndNotify('xWrite', rc); + }, + }; + + const initS11n = () => { + if (state.s11n) return state.s11n; + const textDecoder = new TextDecoder(), + textEncoder = new TextEncoder('utf-8'), + viewU8 = new Uint8Array( + state.sabIO, + state.sabS11nOffset, + state.sabS11nSize, + ), + viewDV = new DataView( + state.sabIO, + state.sabS11nOffset, + state.sabS11nSize, + ); + state.s11n = Object.create(null); + const TypeIds = Object.create(null); + TypeIds.number = { + id: 1, + size: 8, + getter: 'getFloat64', + setter: 'setFloat64', + }; + TypeIds.bigint = { + id: 2, + size: 8, + getter: 'getBigInt64', + setter: 'setBigInt64', + }; + TypeIds.boolean = { + id: 3, + size: 4, + getter: 'getInt32', + setter: 'setInt32', + }; + TypeIds.string = { id: 4 }; + const getTypeId = (v) => + TypeIds[typeof v] || + toss('Maintenance required: this value type cannot be serialized.', v); + const getTypeIdById = (tid) => { + switch (tid) { + case TypeIds.number.id: + return TypeIds.number; + case TypeIds.bigint.id: + return TypeIds.bigint; + case TypeIds.boolean.id: + return TypeIds.boolean; + case TypeIds.string.id: + return TypeIds.string; + default: + toss('Invalid type ID:', tid); + } + }; + state.s11n.deserialize = function (clear = false) { + const argc = viewU8[0]; + const rc = argc ? [] : null; + if (argc) { + const typeIds = []; + let offset = 1, + i, + n, + v; + for (i = 0; i < argc; ++i, ++offset) { + typeIds.push(getTypeIdById(viewU8[offset])); + } + for (i = 0; i < argc; ++i) { + const t = typeIds[i]; + if (t.getter) { + v = viewDV[t.getter](offset, state.littleEndian); + offset += t.size; + } else { + n = viewDV.getInt32(offset, state.littleEndian); + offset += 4; + v = textDecoder.decode(viewU8.slice(offset, offset + n)); + offset += n; + } + rc.push(v); + } + } + if (clear) viewU8[0] = 0; + + return rc; + }; + state.s11n.serialize = function (...args) { + if (args.length) { + const typeIds = []; + let i = 0, + offset = 1; + viewU8[0] = args.length & 0xff; + for (; i < args.length; ++i, ++offset) { + typeIds.push(getTypeId(args[i])); + viewU8[offset] = typeIds[i].id; + } + for (i = 0; i < args.length; ++i) { + const t = typeIds[i]; + if (t.setter) { + viewDV[t.setter](offset, args[i], state.littleEndian); + offset += t.size; + } else { + const s = textEncoder.encode(args[i]); + viewDV.setInt32(offset, s.byteLength, state.littleEndian); + offset += 4; + viewU8.set(s, offset); + offset += s.byteLength; + } + } + } else { + viewU8[0] = 0; + } + }; + + state.s11n.storeException = state.asyncS11nExceptions + ? (priority, e) => { + if (priority <= state.asyncS11nExceptions) { + state.s11n.serialize([e.name, ': ', e.message].join('')); + } + } + : () => {}; + + return state.s11n; + }; + + const waitLoop = async function f() { + const opHandlers = Object.create(null); + for (let k of Object.keys(state.opIds)) { + const vi = vfsAsyncImpls[k]; + if (!vi) continue; + const o = Object.create(null); + opHandlers[state.opIds[k]] = o; + o.key = k; + o.f = vi; + } + while (!flagAsyncShutdown) { + try { + if ( + 'not-equal' !== + Atomics.wait( + state.sabOPView, + state.opIds.whichOp, + 0, + state.asyncIdleWaitTime, + ) + ) { + await releaseImplicitLocks(); + continue; + } + const opId = Atomics.load(state.sabOPView, state.opIds.whichOp); + Atomics.store(state.sabOPView, state.opIds.whichOp, 0); + const hnd = + opHandlers[opId] ?? toss('No waitLoop handler for whichOp #', opId); + const args = state.s11n.deserialize(true) || []; + + if (hnd.f) await hnd.f(...args); + else error('Missing callback for opId', opId); + } catch (e) { + error('in waitLoop():', e); + } + } + }; + + navigator.storage + .getDirectory() + .then(function (d) { + state.rootDir = d; + globalThis.onmessage = function ({ data }) { + switch (data.type) { + case 'opfs-async-init': { + const opt = data.args; + for (const k in opt) state[k] = opt[k]; + state.verbose = opt.verbose ?? 1; + state.sabOPView = new Int32Array(state.sabOP); + state.sabFileBufView = new Uint8Array( + state.sabIO, + 0, + state.fileBufferSize, + ); + state.sabS11nView = new Uint8Array( + state.sabIO, + state.sabS11nOffset, + state.sabS11nSize, + ); + Object.keys(vfsAsyncImpls).forEach((k) => { + if (!Number.isFinite(state.opIds[k])) { + toss('Maintenance required: missing state.opIds[', k, ']'); + } + }); + initS11n(); + log('init state', state); + wPost('opfs-async-inited'); + waitLoop(); + break; + } + case 'opfs-async-restart': + if (flagAsyncShutdown) { + warn( + 'Restarting after opfs-async-shutdown. Might or might not work.', + ); + flagAsyncShutdown = false; + waitLoop(); + } + break; + } + }; + wPost('opfs-async-loaded'); + }) + .catch((e) => error('error initializing OPFS asyncer:', e)); +}; +if (!globalThis.SharedArrayBuffer) { + wPost( + 'opfs-unavailable', + 'Missing SharedArrayBuffer API.', + 'The server must emit the COOP/COEP response headers to enable that.', + ); +} else if (!globalThis.Atomics) { + wPost( + 'opfs-unavailable', + 'Missing Atomics API.', + 'The server must emit the COOP/COEP response headers to enable that.', + ); +} else if ( + !globalThis.FileSystemHandle || + !globalThis.FileSystemDirectoryHandle || + !globalThis.FileSystemFileHandle || + !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || + !navigator?.storage?.getDirectory +) { + wPost('opfs-unavailable', 'Missing required OPFS APIs.'); +} else { + installAsyncProxy(); +} diff --git a/diesel-wasm-sqlite/src/sqlite_types.rs b/diesel-wasm-sqlite/src/sqlite_types.rs index 3ddc74d96..2b4a9d2f1 100644 --- a/diesel-wasm-sqlite/src/sqlite_types.rs +++ b/diesel-wasm-sqlite/src/sqlite_types.rs @@ -1,33 +1,11 @@ use super::backend::{SqliteType, WasmSqlite}; -use bitflags::bitflags; use diesel::sql_types::*; -use serde::{Deserialize, Serialize}; pub mod to_sql; //TODO These Database Types are defined in the wasm file and should be imported. // this is easier for now because of quirks with converting from JsValue to integer within extern // "C" declaration. - -// result codes -pub const SQLITE_DONE: i32 = 101; -pub const SQLITE_ROW: i32 = 100; - -// Fundamental datatypes. -// https://www.sqlite.org/c3ref/c_blob.html -pub const SQLITE_INTEGER: i32 = 1; -pub const SQLITE_FLOAT: i32 = 2; -pub const SQLITE_TEXT: i32 = 3; -pub const SQLITE_BLOB: i32 = 4; -pub const SQLITE_NULL: i32 = 5; - -/// `SqlitePrepareOptions` imported type -#[derive(Serialize, Deserialize, Default, Clone, Debug, Copy)] -pub struct PrepareOptions { - pub flags: Option, - pub unscoped: Option, -} - macro_rules! impl_has_sql_type { ($type:ty, $sql_type:expr) => { impl HasSqlType<$type> for WasmSqlite { @@ -50,58 +28,3 @@ impl_has_sql_type!(Binary, SqliteType::Binary); impl_has_sql_type!(Date, SqliteType::Text); impl_has_sql_type!(Time, SqliteType::Text); impl_has_sql_type!(Timestamp, SqliteType::Text); - -bitflags! { - pub struct SqliteOpenFlags: u32 { - const SQLITE_OPEN_READONLY = 0x00000001; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_READWRITE = 0x00000002; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_CREATE = 0x00000004; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_DELETEONCLOSE = 0x00000008; /* VFS only */ - const SQLITE_OPEN_EXCLUSIVE = 0x00000010; /* VFS only */ - const SQLITE_OPEN_AUTOPROXY = 0x00000020; /* VFS only */ - const SQLITE_OPEN_URI = 0x00000040; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_MEMORY = 0x00000080; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_MAIN_DB = 0x00000100; /* VFS only */ - const SQLITE_OPEN_TEMP_DB = 0x00000200; /* VFS only */ - const SQLITE_OPEN_TRANSIENT_DB = 0x00000400; /* VFS only */ - const SQLITE_OPEN_MAIN_JOURNAL = 0x00000800; /* VFS only */ - const SQLITE_OPEN_TEMP_JOURNAL = 0x00001000; /* VFS only */ - const SQLITE_OPEN_SUBJOURNAL = 0x00002000; /* VFS only */ - const SQLITE_OPEN_SUPER_JOURNAL = 0x00004000; /* VFS only */ - const SQLITE_OPEN_NOMUTEX = 0x00008000; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_FULLMUTEX = 0x00010000; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_SHAREDCACHE = 0x00020000; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_PRIVATECACHE = 0x00040000; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_WAL = 0x00080000; /* VFS only */ - const SQLITE_OPEN_NOFOLLOW = 0x01000000; /* Ok for sqlite3_open_v2() */ - const SQLITE_OPEN_EXRESCODE = 0x02000000; /* Extended result codes */ - } -} - -// SQLite Text Encodings https://www.sqlite.org/capi3ref.html#SQLITE_ANY -bitflags! { - pub struct SqliteFlags: u32 { - const SQLITE_UTF8 = 1; /* IMP: R-37514-35566 */ - const SQLITE_UTF16LE = 2; /* IMP: R-03371-37637 */ - const SQLITE_UTF16BE = 3; /* IMP: R-51971-34154 */ - const SQLITE_UTF16 = 4; /* Use native byte order */ - const SQLITE_ANY = 5; /* Deprecated */ - const SQLITE_UTF16_ALIGNED = 8; /* sqlite3_create_collation only */ - - /// SQLite Function Flags https://www.sqlite.org/capi3ref.html#sqlitedeterministic - const SQLITE_DETERMINISTIC = 0x000000800; - const SQLITE_DIRECTONLY = 0x000080000; - const SQLITE_SUBTYPE = 0x000100000; - const SQLITE_INNOCUOUS = 0x000200000; - const SQLITE_RESULT_SUBTYPE = 0x001000000; - } -} - -// SQLite Prepare Flags https://www.sqlite.org/c3ref/c_prepare_normalize.html#sqlitepreparepersistent -bitflags! { - pub struct SqlitePrepareFlags: i32 { - const SQLITE_PREPARE_PERSISTENT = 0x01; - const SQLITE_PREPARE_NORMALIZE = 0x02; - const SQLITE_PREPARE_NO_VTAB = 0x04; - } -} diff --git a/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs b/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs index 911a35712..4915e6a86 100644 --- a/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs +++ b/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs @@ -4,7 +4,7 @@ //TODO: CODE CAN BE SHARED (pretty muhch exactly the same) use crate::connection::SqliteValue; use crate::WasmSqlite; -use diesel::deserialize::{self, FromSql, Queryable}; +use diesel::deserialize::{self, FromSql}; use diesel::query_builder::QueryId; use diesel::serialize::{self, IsNull, Output, ToSql}; use diesel::sql_types; @@ -12,21 +12,34 @@ use diesel::sql_types::SqlType; /// The returned pointer is *only* valid for the lifetime to the argument of /// `from_sql`. This impl is intended for uses where you want to write a new -/// impl in terms of `String`, but don't want to allocate. We have to return a +/// impl in terms of `String`, but don't want to allocate. +/// +/// FIXME: +/// We have to return a /// raw pointer instead of a reference with a lifetime due to the structure of -/// `FromSql` -/// FIXME: THIS IS probably problematic for wa-sqlite -/// because we allocate a string in `read_text`. So this function would -/// producea dangling pointer. -/// `*const` types are not unsafe to _create_ but are unsafe once dereferenced/used +/// `FromSql` because we allocate a string in `read_text` (since SQLite memory is not shared with +/// us). So this function would +/// produce a dangling pointer. +/* +// Not posible until we share mem with sqlite. There's no +// way to avoid an allocation into our host memory until then. impl FromSql for *const str { - fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { + tracing::debug!("IN FROM SQL"); let text = value.read_text(); - let string = text.as_str(); - Ok(string as *const _) + let text = text.as_str(); + Ok(text as *const _) + } +} +*/ + +impl FromSql for String { + fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { + Ok(value.read_text()) } } +/* Not Possible until we share mem with SQLite impl Queryable for *const str { type Row = Self; @@ -34,14 +47,22 @@ impl Queryable for *const str { Ok(row) } } +*/ + +impl FromSql for Vec { + fn from_sql(bytes: SqliteValue<'_, '_, '_>) -> deserialize::Result { + Ok(bytes.read_blob()) + } +} /// The returned pointer is *only* valid for the lifetime to the argument of /// `from_sql`. This impl is intended for uses where you want to write a new /// impl in terms of `Vec`, but don't want to allocate. We have to return a /// raw pointer instead of a reference with a lifetime due to the structure of /// `FromSql` +/* Not possible until we share mem with SQLite impl FromSql for *const [u8] { - fn from_sql(bytes: SqliteValue<'_, '_>) -> deserialize::Result { + fn from_sql(bytes: SqliteValue<'_, '_, '_>) -> deserialize::Result { let bytes = bytes.read_blob(); let bytes = bytes.as_slice(); Ok(bytes as *const _) @@ -55,39 +76,40 @@ impl Queryable for *const [u8] { Ok(row) } } +*/ impl FromSql for i16 { - fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { Ok(value.read_integer() as i16) } } impl FromSql for i32 { - fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { Ok(value.read_integer()) } } impl FromSql for bool { - fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { Ok(value.read_integer() != 0) } } impl FromSql for i64 { - fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { Ok(value.read_long()) } } impl FromSql for f32 { - fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { Ok(value.read_double() as f32) } } impl FromSql for f64 { - fn from_sql(value: SqliteValue<'_, '_>) -> deserialize::Result { + fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { Ok(value.read_double()) } } diff --git a/diesel-wasm-sqlite/src/utils.rs b/diesel-wasm-sqlite/src/utils.rs index b1d7929dc..8b1378917 100644 --- a/diesel-wasm-sqlite/src/utils.rs +++ b/diesel-wasm-sqlite/src/utils.rs @@ -1,10 +1 @@ -pub fn set_panic_hook() { - // When the `console_error_panic_hook` feature is enabled, we can call the - // `set_panic_hook` function at least once during initialization, and then - // we will get better error messages if our code ever panics. - // - // For more details see - // https://github.com/rustwasm/console_error_panic_hook#readme - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); -} + diff --git a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js index 9e49297e0..38da2f941 100644 --- a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js @@ -1,3038 +1,14645 @@ -// Primary result codes. -// https://www.sqlite.org/rescode.html -const SQLITE_OK = 0; -const SQLITE_ERROR = 1; -const SQLITE_INTERNAL = 2; -const SQLITE_PERM = 3; -const SQLITE_ABORT = 4; -const SQLITE_BUSY = 5; -const SQLITE_LOCKED = 6; -const SQLITE_NOMEM = 7; -const SQLITE_READONLY = 8; -const SQLITE_INTERRUPT = 9; -const SQLITE_IOERR = 10; -const SQLITE_CORRUPT = 11; -const SQLITE_NOTFOUND = 12; -const SQLITE_FULL = 13; -const SQLITE_CANTOPEN = 14; -const SQLITE_PROTOCOL = 15; -const SQLITE_EMPTY = 16; -const SQLITE_SCHEMA = 17; -const SQLITE_TOOBIG = 18; -const SQLITE_CONSTRAINT = 19; -const SQLITE_MISMATCH = 20; -const SQLITE_MISUSE = 21; -const SQLITE_NOLFS = 22; -const SQLITE_AUTH = 23; -const SQLITE_FORMAT = 24; -const SQLITE_RANGE = 25; -const SQLITE_NOTADB = 26; -const SQLITE_NOTICE = 27; -const SQLITE_WARNING = 28; -const SQLITE_ROW = 100; -const SQLITE_DONE = 101; - -// Extended error codes. -const SQLITE_IOERR_ACCESS = 3338; -const SQLITE_IOERR_CHECKRESERVEDLOCK = 3594; -const SQLITE_IOERR_CLOSE = 4106; -const SQLITE_IOERR_DATA = 8202; -const SQLITE_IOERR_DELETE = 2570; -const SQLITE_IOERR_DELETE_NOENT = 5898; -const SQLITE_IOERR_DIR_FSYNC = 1290; -const SQLITE_IOERR_FSTAT = 1802; -const SQLITE_IOERR_FSYNC = 1034; -const SQLITE_IOERR_GETTEMPPATH = 6410; -const SQLITE_IOERR_LOCK = 3850; -const SQLITE_IOERR_NOMEM = 3082; -const SQLITE_IOERR_READ = 266; -const SQLITE_IOERR_RDLOCK = 2314; -const SQLITE_IOERR_SEEK = 5642; -const SQLITE_IOERR_SHORT_READ = 522; -const SQLITE_IOERR_TRUNCATE = 1546; -const SQLITE_IOERR_UNLOCK = 2058; -const SQLITE_IOERR_VNODE = 6922; -const SQLITE_IOERR_WRITE = 778; -const SQLITE_IOERR_BEGIN_ATOMIC = 7434; -const SQLITE_IOERR_COMMIT_ATOMIC = 7690; -const SQLITE_IOERR_ROLLBACK_ATOMIC = 7946; - -// Other extended result codes. -const SQLITE_CONSTRAINT_CHECK = 275; -const SQLITE_CONSTRAINT_COMMITHOOK = 531; -const SQLITE_CONSTRAINT_FOREIGNKEY = 787; -const SQLITE_CONSTRAINT_FUNCTION = 1043; -const SQLITE_CONSTRAINT_NOTNULL = 1299; -const SQLITE_CONSTRAINT_PINNED = 2835; -const SQLITE_CONSTRAINT_PRIMARYKEY = 1555; -const SQLITE_CONSTRAINT_ROWID = 2579; -const SQLITE_CONSTRAINT_TRIGGER = 1811; -const SQLITE_CONSTRAINT_UNIQUE = 2067; -const SQLITE_CONSTRAINT_VTAB = 2323; - -// Open flags. -// https://www.sqlite.org/c3ref/c_open_autoproxy.html -const SQLITE_OPEN_READONLY = 0x00000001; -const SQLITE_OPEN_READWRITE = 0x00000002; -const SQLITE_OPEN_CREATE = 0x00000004; -const SQLITE_OPEN_DELETEONCLOSE = 0x00000008; -const SQLITE_OPEN_EXCLUSIVE = 0x00000010; -const SQLITE_OPEN_AUTOPROXY = 0x00000020; -const SQLITE_OPEN_URI = 0x00000040; -const SQLITE_OPEN_MEMORY = 0x00000080; -const SQLITE_OPEN_MAIN_DB = 0x00000100; -const SQLITE_OPEN_TEMP_DB = 0x00000200; -const SQLITE_OPEN_TRANSIENT_DB = 0x00000400; -const SQLITE_OPEN_MAIN_JOURNAL = 0x00000800; -const SQLITE_OPEN_TEMP_JOURNAL = 0x00001000; -const SQLITE_OPEN_SUBJOURNAL = 0x00002000; -const SQLITE_OPEN_SUPER_JOURNAL = 0x00004000; -const SQLITE_OPEN_NOMUTEX = 0x00008000; -const SQLITE_OPEN_FULLMUTEX = 0x00010000; -const SQLITE_OPEN_SHAREDCACHE = 0x00020000; -const SQLITE_OPEN_PRIVATECACHE = 0x00040000; -const SQLITE_OPEN_WAL = 0x00080000; -const SQLITE_OPEN_NOFOLLOW = 0x01000000; - -// Locking levels. -// https://www.sqlite.org/c3ref/c_lock_exclusive.html -const SQLITE_LOCK_NONE = 0; -const SQLITE_LOCK_SHARED = 1; -const SQLITE_LOCK_RESERVED = 2; -const SQLITE_LOCK_PENDING = 3; -const SQLITE_LOCK_EXCLUSIVE = 4; - -// Device characteristics. -// https://www.sqlite.org/c3ref/c_iocap_atomic.html -const SQLITE_IOCAP_ATOMIC = 0x00000001; -const SQLITE_IOCAP_ATOMIC512 = 0x00000002; -const SQLITE_IOCAP_ATOMIC1K = 0x00000004; -const SQLITE_IOCAP_ATOMIC2K = 0x00000008; -const SQLITE_IOCAP_ATOMIC4K = 0x00000010; -const SQLITE_IOCAP_ATOMIC8K = 0x00000020; -const SQLITE_IOCAP_ATOMIC16K = 0x00000040; -const SQLITE_IOCAP_ATOMIC32K = 0x00000080; -const SQLITE_IOCAP_ATOMIC64K = 0x00000100; -const SQLITE_IOCAP_SAFE_APPEND = 0x00000200; -const SQLITE_IOCAP_SEQUENTIAL = 0x00000400; -const SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN = 0x00000800; -const SQLITE_IOCAP_POWERSAFE_OVERWRITE = 0x00001000; -const SQLITE_IOCAP_IMMUTABLE = 0x00002000; -const SQLITE_IOCAP_BATCH_ATOMIC = 0x00004000; - -// xAccess flags. -// https://www.sqlite.org/c3ref/c_access_exists.html -const SQLITE_ACCESS_EXISTS = 0; -const SQLITE_ACCESS_READWRITE = 1; -const SQLITE_ACCESS_READ = 2; - -// File control opcodes -// https://www.sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlbeginatomicwrite -const SQLITE_FCNTL_LOCKSTATE = 1; -const SQLITE_FCNTL_GET_LOCKPROXYFILE = 2; -const SQLITE_FCNTL_SET_LOCKPROXYFILE = 3; -const SQLITE_FCNTL_LAST_ERRNO = 4; -const SQLITE_FCNTL_SIZE_HINT = 5; -const SQLITE_FCNTL_CHUNK_SIZE = 6; -const SQLITE_FCNTL_FILE_POINTER = 7; -const SQLITE_FCNTL_SYNC_OMITTED = 8; -const SQLITE_FCNTL_WIN32_AV_RETRY = 9; -const SQLITE_FCNTL_PERSIST_WAL = 10; -const SQLITE_FCNTL_OVERWRITE = 11; -const SQLITE_FCNTL_VFSNAME = 12; -const SQLITE_FCNTL_POWERSAFE_OVERWRITE = 13; -const SQLITE_FCNTL_PRAGMA = 14; -const SQLITE_FCNTL_BUSYHANDLER = 15; -const SQLITE_FCNTL_TEMPFILENAME = 16; -const SQLITE_FCNTL_MMAP_SIZE = 18; -const SQLITE_FCNTL_TRACE = 19; -const SQLITE_FCNTL_HAS_MOVED = 20; -const SQLITE_FCNTL_SYNC = 21; -const SQLITE_FCNTL_COMMIT_PHASETWO = 22; -const SQLITE_FCNTL_WIN32_SET_HANDLE = 23; -const SQLITE_FCNTL_WAL_BLOCK = 24; -const SQLITE_FCNTL_ZIPVFS = 25; -const SQLITE_FCNTL_RBU = 26; -const SQLITE_FCNTL_VFS_POINTER = 27; -const SQLITE_FCNTL_JOURNAL_POINTER = 28; -const SQLITE_FCNTL_WIN32_GET_HANDLE = 29; -const SQLITE_FCNTL_PDB = 30; -const SQLITE_FCNTL_BEGIN_ATOMIC_WRITE = 31; -const SQLITE_FCNTL_COMMIT_ATOMIC_WRITE = 32; -const SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE = 33; -const SQLITE_FCNTL_LOCK_TIMEOUT = 34; -const SQLITE_FCNTL_DATA_VERSION = 35; -const SQLITE_FCNTL_SIZE_LIMIT = 36; -const SQLITE_FCNTL_CKPT_DONE = 37; -const SQLITE_FCNTL_RESERVE_BYTES = 38; -const SQLITE_FCNTL_CKPT_START = 39; - -// Fundamental datatypes. -// https://www.sqlite.org/c3ref/c_blob.html -const SQLITE_INTEGER = 1; -const SQLITE_FLOAT = 2; -const SQLITE_TEXT = 3; -const SQLITE_BLOB = 4; -const SQLITE_NULL = 5; - -// Special destructor behavior. -// https://www.sqlite.org/c3ref/c_static.html -const SQLITE_STATIC = 0; -const SQLITE_TRANSIENT = -1; - -// Text encodings. -// https://sqlite.org/c3ref/c_any.html -const SQLITE_UTF8 = 1; /* IMP: R-37514-35566 */ -const SQLITE_UTF16LE = 2; /* IMP: R-03371-37637 */ -const SQLITE_UTF16BE = 3; /* IMP: R-51971-34154 */ -const SQLITE_UTF16 = 4; /* Use native byte order */ - -// Module constraint ops. -const SQLITE_INDEX_CONSTRAINT_EQ = 2; -const SQLITE_INDEX_CONSTRAINT_GT = 4; -const SQLITE_INDEX_CONSTRAINT_LE = 8; -const SQLITE_INDEX_CONSTRAINT_LT = 16; -const SQLITE_INDEX_CONSTRAINT_GE = 32; -const SQLITE_INDEX_CONSTRAINT_MATCH = 64; -const SQLITE_INDEX_CONSTRAINT_LIKE = 65; -const SQLITE_INDEX_CONSTRAINT_GLOB = 66; -const SQLITE_INDEX_CONSTRAINT_REGEXP = 67; -const SQLITE_INDEX_CONSTRAINT_NE = 68; -const SQLITE_INDEX_CONSTRAINT_ISNOT = 69; -const SQLITE_INDEX_CONSTRAINT_ISNOTNULL = 70; -const SQLITE_INDEX_CONSTRAINT_ISNULL = 71; -const SQLITE_INDEX_CONSTRAINT_IS = 72; -const SQLITE_INDEX_CONSTRAINT_FUNCTION = 150; -const SQLITE_INDEX_SCAN_UNIQUE = 1; /* Scan visits at most = 1 row */ - -// Function flags -const SQLITE_DETERMINISTIC = 0x000000800; -const SQLITE_DIRECTONLY = 0x000080000; -const SQLITE_SUBTYPE = 0x000100000; -const SQLITE_INNOCUOUS = 0x000200000; - -// Sync flags -const SQLITE_SYNC_NORMAL = 0x00002; -const SQLITE_SYNC_FULL = 0x00003; -const SQLITE_SYNC_DATAONLY = 0x00010; - -// Authorizer action codes -const SQLITE_CREATE_INDEX = 1; -const SQLITE_CREATE_TABLE = 2; -const SQLITE_CREATE_TEMP_INDEX = 3; -const SQLITE_CREATE_TEMP_TABLE = 4; -const SQLITE_CREATE_TEMP_TRIGGER = 5; -const SQLITE_CREATE_TEMP_VIEW = 6; -const SQLITE_CREATE_TRIGGER = 7; -const SQLITE_CREATE_VIEW = 8; -const SQLITE_DELETE = 9; -const SQLITE_DROP_INDEX = 10; -const SQLITE_DROP_TABLE = 11; -const SQLITE_DROP_TEMP_INDEX = 12; -const SQLITE_DROP_TEMP_TABLE = 13; -const SQLITE_DROP_TEMP_TRIGGER = 14; -const SQLITE_DROP_TEMP_VIEW = 15; -const SQLITE_DROP_TRIGGER = 16; -const SQLITE_DROP_VIEW = 17; -const SQLITE_INSERT = 18; -const SQLITE_PRAGMA = 19; -const SQLITE_READ = 20; -const SQLITE_SELECT = 21; -const SQLITE_TRANSACTION = 22; -const SQLITE_UPDATE = 23; -const SQLITE_ATTACH = 24; -const SQLITE_DETACH = 25; -const SQLITE_ALTER_TABLE = 26; -const SQLITE_REINDEX = 27; -const SQLITE_ANALYZE = 28; -const SQLITE_CREATE_VTABLE = 29; -const SQLITE_DROP_VTABLE = 30; -const SQLITE_FUNCTION = 31; -const SQLITE_SAVEPOINT = 32; -const SQLITE_COPY = 0; -const SQLITE_RECURSIVE = 33; - -// Authorizer return codes -const SQLITE_DENY = 1; -const SQLITE_IGNORE = 2; - -// Limit categories -const SQLITE_LIMIT_LENGTH = 0; -const SQLITE_LIMIT_SQL_LENGTH = 1; -const SQLITE_LIMIT_COLUMN = 2; -const SQLITE_LIMIT_EXPR_DEPTH = 3; -const SQLITE_LIMIT_COMPOUND_SELECT = 4; -const SQLITE_LIMIT_VDBE_OP = 5; -const SQLITE_LIMIT_FUNCTION_ARG = 6; -const SQLITE_LIMIT_ATTACHED = 7; -const SQLITE_LIMIT_LIKE_PATTERN_LENGTH = 8; -const SQLITE_LIMIT_VARIABLE_NUMBER = 9; -const SQLITE_LIMIT_TRIGGER_DEPTH = 10; -const SQLITE_LIMIT_WORKER_THREADS = 11; - -const SQLITE_PREPARE_PERSISTENT = 0x01; -const SQLITE_PREPARE_NORMALIZED = 0x02; -const SQLITE_PREPARE_NO_VTAB = 0x04; - -// Copyright 2021 Roy T. Hashimoto. All Rights Reserved. - - -const MAX_INT64 = 0x7fffffffffffffffn; -const MIN_INT64 = -0x8000000000000000n; - -const AsyncFunction$1 = Object.getPrototypeOf(async function () {}).constructor; +/* + ** LICENSE for the sqlite3 WebAssembly/JavaScript APIs. + ** + ** This bundle (typically released as sqlite3.js or sqlite3.mjs) + ** is an amalgamation of JavaScript source code from two projects: + ** + ** 1) https://emscripten.org: the Emscripten "glue code" is covered by + ** the terms of the MIT license and University of Illinois/NCSA + ** Open Source License, as described at: + ** + ** https://emscripten.org/docs/introducing_emscripten/emscripten_license.html + ** + ** 2) https://sqlite.org: all code and documentation labeled as being + ** from this source are released under the same terms as the sqlite3 + ** C library: + ** + ** 2022-10-16 + ** + ** The author disclaims copyright to this source code. In place of a + ** legal notice, here is a blessing: + ** + ** * May you do good and not evil. + ** * May you find forgiveness for yourself and forgive others. + ** * May you share freely, never taking more than you give. + */ +/* + ** This code was built from sqlite3 version... + ** + ** SQLITE_VERSION "3.46.1" + ** SQLITE_VERSION_NUMBER 3046001 + ** SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33" + ** + ** Using the Emscripten SDK version 3.1.30. + */ -class SQLiteError extends Error { - constructor(message, code) { - super(message); - this.code = code; - } -} +var sqlite3InitModule = (() => { + var _scriptDir = import.meta.url; -const async = true; + return function (config) { + var sqlite3InitModule = config || {}; -/** - * Builds a Javascript API from the Emscripten module. This API is still - * low-level and closely corresponds to the C API exported by the module, - * but differs in some specifics like throwing exceptions on errors. - * @param {*} Module SQLite Emscripten module - * @returns {SQLiteAPI} - */ -function Factory(Module) { - /** @type {SQLiteAPI} */ const sqlite3 = {}; - - Module.retryOps = []; - const sqliteFreeAddress = Module._getSqliteFree(); - - // Allocate some space for 32-bit returned values. - const tmp = Module._malloc(8); - const tmpPtr = [tmp, tmp + 4]; - - // Convert a JS string to a C string. sqlite3_malloc is used to allocate - // memory (use sqlite3_free to deallocate). - function createUTF8(s) { - if (typeof s !== "string") return 0; - const utf8 = new TextEncoder().encode(s); - const zts = Module._sqlite3_malloc(utf8.byteLength + 1); - Module.HEAPU8.set(utf8, zts); - Module.HEAPU8[zts + utf8.byteLength] = 0; - return zts; - } + var Module = + typeof sqlite3InitModule != 'undefined' ? sqlite3InitModule : {}; - /** - * Concatenate 32-bit numbers into a 64-bit (signed) BigInt. - * @param {number} lo32 - * @param {number} hi32 - * @returns {bigint} - */ - function cvt32x2ToBigInt(lo32, hi32) { - return (BigInt(hi32) << 32n) | (BigInt(lo32) & 0xffffffffn); - } + var readyPromiseResolve, readyPromiseReject; + Module['ready'] = new Promise(function (resolve, reject) { + readyPromiseResolve = resolve; + readyPromiseReject = reject; + }); - /** - * Concatenate 32-bit numbers and return as number or BigInt, depending - * on the value. - * @param {number} lo32 - * @param {number} hi32 - * @returns {number|bigint} - */ - const cvt32x2AsSafe = (function () { - const hiMax = BigInt(Number.MAX_SAFE_INTEGER) >> 32n; - const hiMin = BigInt(Number.MIN_SAFE_INTEGER) >> 32n; - - return function (lo32, hi32) { - if (hi32 > hiMax || hi32 < hiMin) { - // Can't be expressed as a Number so use BigInt. - return cvt32x2ToBigInt(lo32, hi32); - } else { - // Combine the upper and lower 32-bit numbers. The complication is - // that lo32 is a signed integer which makes manipulating its bits - // a little tricky - the sign bit gets handled separately. - return (hi32 * 0x100000000) + (lo32 & 0x7fffffff) - (lo32 & 0x80000000); - } + const sqlite3InitModuleState = + globalThis.sqlite3InitModuleState || + Object.assign(Object.create(null), { + debugModule: () => {}, + }); + delete globalThis.sqlite3InitModuleState; + sqlite3InitModuleState.debugModule( + 'globalThis.location =', + globalThis.location, + ); + + const xNameOfInstantiateWasm = 'emscripten-bug-17951'; + Module[xNameOfInstantiateWasm] = function callee(imports, onSuccess) { + imports.env.foo = function () {}; + const uri = Module.locateFile( + callee.uri, + 'undefined' === typeof scriptDirectory ? '' : scriptDirectory, + ); + sqlite3InitModuleState.debugModule('instantiateWasm() uri =', uri); + const wfetch = () => fetch(uri, { credentials: 'same-origin' }); + const loadWasm = WebAssembly.instantiateStreaming + ? async () => { + return WebAssembly.instantiateStreaming(wfetch(), imports).then( + (arg) => onSuccess(arg.instance, arg.module), + ); + } + : async () => { + return wfetch() + .then((response) => response.arrayBuffer()) + .then((bytes) => WebAssembly.instantiate(bytes, imports)) + .then((arg) => onSuccess(arg.instance, arg.module)); + }; + loadWasm(); + return {}; }; - })(); - const databases = new Set(); - function verifyDatabase(db) { - if (!databases.has(db)) { - throw new SQLiteError("not a database", SQLITE_MISUSE); - } - } + Module[xNameOfInstantiateWasm].uri = 'sqlite3.wasm'; - const mapStmtToDB = new Map(); - function verifyStatement(stmt) { - if (!mapStmtToDB.has(stmt)) { - throw new SQLiteError("not a statement", SQLITE_MISUSE); - } - } + var moduleOverrides = Object.assign({}, Module); + var thisProgram = './this.program'; + + var ENVIRONMENT_IS_WEB = typeof window == 'object'; + var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'; - sqlite3.bind_collection = function (stmt, bindings) { - verifyStatement(stmt); - const isArray = Array.isArray(bindings); - const nBindings = sqlite3.bind_parameter_count(stmt); - for (let i = 1; i <= nBindings; ++i) { - const key = isArray ? i - 1 : sqlite3.bind_parameter_name(stmt, i); - const value = bindings[key]; - if (value !== undefined) { - sqlite3.bind(stmt, i, value); + typeof process == 'object' && + typeof process.versions == 'object' && + typeof process.versions.node == 'string'; + + var scriptDirectory = ''; + function locateFile(path) { + if (Module['locateFile']) { + return Module['locateFile'](path, scriptDirectory); } + return scriptDirectory + path; } - return SQLITE_OK; - }; - sqlite3.bind = function (stmt, i, value) { - verifyStatement(stmt); - switch (typeof value) { - case "number": - if (value === (value | 0)) { - return sqlite3.bind_int(stmt, i, value); - } else { - return sqlite3.bind_double(stmt, i, value); - } - case "string": - return sqlite3.bind_text(stmt, i, value); - default: - if (value instanceof Uint8Array || Array.isArray(value)) { - return sqlite3.bind_blob(stmt, i, value); - } else if (value === null) { - return sqlite3.bind_null(stmt, i); - } else if (typeof value === "bigint") { - return sqlite3.bind_int64(stmt, i, value); - } else if (value === undefined) { - // Existing binding (or NULL) will be used. - return SQLITE_NOTICE; - } else { - console.warn("unknown binding converted to null", value); - return sqlite3.bind_null(stmt, i); - } - } - }; + var read_, readAsync, readBinary; - sqlite3.bind_blob = (function () { - const fname = "sqlite3_bind_blob"; - const f = Module.cwrap(fname, ...decl("nnnnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - // @ts-ignore - const byteLength = value.byteLength ?? value.length; - const ptr = Module._sqlite3_malloc(byteLength); - Module.HEAPU8.subarray(ptr).set(value); - const result = f(stmt, i, ptr, byteLength, sqliteFreeAddress); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_parameter_count = (function () { - const fname = "sqlite3_bind_parameter_count"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return result; - }; - })(); - - sqlite3.bind_double = (function () { - const fname = "sqlite3_bind_double"; - const f = Module.cwrap(fname, ...decl("nnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - const result = f(stmt, i, value); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); + if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = self.location.href; + } else if (typeof document != 'undefined' && document.currentScript) { + scriptDirectory = document.currentScript.src; + } - sqlite3.bind_int = (function () { - const fname = "sqlite3_bind_int"; - const f = Module.cwrap(fname, ...decl("nnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - if (value > 0x7fffffff || value < -0x80000000) return SQLITE_RANGE; + if (_scriptDir) { + scriptDirectory = _scriptDir; + } - const result = f(stmt, i, value); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_int64 = (function () { - const fname = "sqlite3_bind_int64"; - const f = Module.cwrap(fname, ...decl("nnnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - if (value > MAX_INT64 || value < MIN_INT64) return SQLITE_RANGE; - - const lo32 = value & 0xffffffffn; - const hi32 = value >> 32n; - const result = f(stmt, i, Number(lo32), Number(hi32)); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_null = (function () { - const fname = "sqlite3_bind_null"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, i) { - verifyStatement(stmt); - const result = f(stmt, i); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_parameter_name = (function () { - const fname = "sqlite3_bind_parameter_name"; - const f = Module.cwrap(fname, ...decl("n:s")); - return function (stmt, i) { - verifyStatement(stmt); - const result = f(stmt, i); - return result; - }; - })(); - - sqlite3.bind_text = (function () { - const fname = "sqlite3_bind_text"; - const f = Module.cwrap(fname, ...decl("nnnnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - const ptr = createUTF8(value); - const result = f(stmt, i, ptr, -1, sqliteFreeAddress); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.changes = (function () { - const fname = "sqlite3_changes"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (db) { - verifyDatabase(db); - const result = f(db); - return result; - }; - })(); - - sqlite3.clear_bindings = (function () { - const fname = "sqlite3_clear_bindings"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.close = (function () { - const fname = "sqlite3_close"; - const f = Module.cwrap(fname, ...decl("n:n"), { async }); - return async function (db) { - verifyDatabase(db); - const result = await f(db); - databases.delete(db); - return check(fname, result, db); - }; - })(); - - sqlite3.column = function (stmt, iCol) { - verifyStatement(stmt); - const type = sqlite3.column_type(stmt, iCol); - switch (type) { - case SQLITE_BLOB: - return sqlite3.column_blob(stmt, iCol); - case SQLITE_FLOAT: - return sqlite3.column_double(stmt, iCol); - case SQLITE_INTEGER: - const lo32 = sqlite3.column_int(stmt, iCol); - const hi32 = Module.getTempRet0(); - return cvt32x2AsSafe(lo32, hi32); - case SQLITE_NULL: - return null; - case SQLITE_TEXT: - return sqlite3.column_text(stmt, iCol); - default: - throw new SQLiteError("unknown type", type); - } - }; + if (scriptDirectory.indexOf('blob:') !== 0) { + scriptDirectory = scriptDirectory.substr( + 0, + scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1, + ); + } else { + scriptDirectory = ''; + } - sqlite3.column_blob = (function () { - const fname = "sqlite3_column_blob"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const nBytes = sqlite3.column_bytes(stmt, iCol); - const address = f(stmt, iCol); - const result = Module.HEAPU8.subarray(address, address + nBytes); - return result; - }; - })(); - - sqlite3.column_bytes = (function () { - const fname = "sqlite3_column_bytes"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_count = (function () { - const fname = "sqlite3_column_count"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return result; - }; - })(); - - sqlite3.column_double = (function () { - const fname = "sqlite3_column_double"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_int = (function () { - // Retrieve int64 but use only the lower 32 bits. The upper 32-bits are - // accessible with Module.getTempRet0(). - const fname = "sqlite3_column_int64"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_int64 = (function () { - const fname = "sqlite3_column_int64"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const lo32 = f(stmt, iCol); - const hi32 = Module.getTempRet0(); - const result = cvt32x2ToBigInt(lo32, hi32); - return result; - }; - })(); - - sqlite3.column_name = (function () { - const fname = "sqlite3_column_name"; - const f = Module.cwrap(fname, ...decl("nn:s")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); + { + read_ = (url) => { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + xhr.send(null); + return xhr.responseText; + }; + + if (ENVIRONMENT_IS_WORKER) { + readBinary = (url) => { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + xhr.responseType = 'arraybuffer'; + xhr.send(null); + return new Uint8Array(xhr.response); + }; + } - sqlite3.column_names = function (stmt) { - const columns = []; - const nColumns = sqlite3.column_count(stmt); - for (let i = 0; i < nColumns; ++i) { - columns.push(sqlite3.column_name(stmt, i)); + readAsync = (url, onload, onerror) => { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'arraybuffer'; + xhr.onload = () => { + if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { + onload(xhr.response); + return; + } + onerror(); + }; + xhr.onerror = onerror; + xhr.send(null); + }; + } } - return columns; - }; - sqlite3.column_text = (function () { - const fname = "sqlite3_column_text"; - const f = Module.cwrap(fname, ...decl("nn:s")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_type = (function () { - const fname = "sqlite3_column_type"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); + var out = Module['print'] || console.log.bind(console); + var err = Module['printErr'] || console.warn.bind(console); - sqlite3.create_function = function ( - db, - zFunctionName, - nArg, - eTextRep, - pApp, - xFunc, - xStep, - xFinal, - ) { - verifyDatabase(db); - - // Convert SQLite callback arguments to JavaScript-friendly arguments. - function adapt(f) { - return f instanceof AsyncFunction$1 - ? (async (ctx, n, values) => - f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))) - : ((ctx, n, values) => - f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))); - } - - const result = Module.create_function( - db, - zFunctionName, - nArg, - eTextRep, - pApp, - xFunc && adapt(xFunc), - xStep && adapt(xStep), - xFinal, - ); - return check("sqlite3_create_function", result, db); - }; + Object.assign(Module, moduleOverrides); - sqlite3.data_count = (function () { - const fname = "sqlite3_data_count"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return result; - }; - })(); + moduleOverrides = null; - sqlite3.exec = async function (db, sql, callback) { - for await (const stmt of sqlite3.statements(db, sql)) { - let columns; - while (await sqlite3.step(stmt) === SQLITE_ROW) { - if (callback) { - columns = columns ?? sqlite3.column_names(stmt); - const row = sqlite3.row(stmt); - await callback(row, columns); - } - } - } - return SQLITE_OK; - }; + if (Module['arguments']) Module['arguments']; - sqlite3.finalize = (function () { - const fname = "sqlite3_finalize"; - const f = Module.cwrap(fname, ...decl("n:n"), { async }); - return async function (stmt) { - const result = await f(stmt); - mapStmtToDB.delete(stmt); + if (Module['thisProgram']) thisProgram = Module['thisProgram']; - // Don't throw on error here. Typically the error has already been - // thrown and finalize() is part of the cleanup. - return result; - }; - })(); - - sqlite3.get_autocommit = (function () { - const fname = "sqlite3_get_autocommit"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (db) { - const result = f(db); - return result; - }; - })(); - - sqlite3.libversion = (function () { - const fname = "sqlite3_libversion"; - const f = Module.cwrap(fname, ...decl(":s")); - return function () { - const result = f(); - return result; - }; - })(); - - sqlite3.libversion_number = (function () { - const fname = "sqlite3_libversion_number"; - const f = Module.cwrap(fname, ...decl(":n")); - return function () { - const result = f(); - return result; - }; - })(); - - sqlite3.limit = (function () { - const fname = "sqlite3_limit"; - const f = Module.cwrap(fname, ...decl("nnn:n")); - return function (db, id, newVal) { - const result = f(db, id, newVal); - return result; - }; - })(); - - sqlite3.open_v2 = (function () { - const fname = "sqlite3_open_v2"; - const f = Module.cwrap(fname, ...decl("snnn:n"), { async }); - return async function (zFilename, flags, zVfs) { - flags = flags || SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE; - zVfs = createUTF8(zVfs); - try { - // Allow retry operations. - const rc = await retry(() => f(zFilename, tmpPtr[0], flags, zVfs)); + if (Module['quit']) Module['quit']; - const db = Module.getValue(tmpPtr[0], "*"); - databases.add(db); + var wasmBinary; + if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; + Module['noExitRuntime'] || true; - Module.ccall("RegisterExtensionFunctions", "void", ["number"], [db]); - check(fname, rc); - return db; - } finally { - Module._sqlite3_free(zVfs); - } - }; - })(); + if (typeof WebAssembly != 'object') { + abort('no native wasm support detected'); + } - sqlite3.progress_handler = function (db, nProgressOps, handler, userData) { - verifyDatabase(db); - Module.progress_handler(db, nProgressOps, handler, userData); - }; + var wasmMemory; - sqlite3.reset = (function () { - const fname = "sqlite3_reset"; - const f = Module.cwrap(fname, ...decl("n:n"), { async }); - return async function (stmt) { - verifyStatement(stmt); - const result = await f(stmt); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); + var ABORT = false; - sqlite3.result = function (context, value) { - switch (typeof value) { - case "number": - if (value === (value | 0)) { - sqlite3.result_int(context, value); - } else { - sqlite3.result_double(context, value); - } - break; - case "string": - sqlite3.result_text(context, value); - break; - default: - if (value instanceof Uint8Array || Array.isArray(value)) { - sqlite3.result_blob(context, value); - } else if (value === null) { - sqlite3.result_null(context); - } else if (typeof value === "bigint") { - return sqlite3.result_int64(context, value); - } else { - console.warn("unknown result converted to null", value); - sqlite3.result_null(context); - } - break; + function assert(condition, text) { + if (!condition) { + abort(text); + } } - }; - sqlite3.result_blob = (function () { - const fname = "sqlite3_result_blob"; - const f = Module.cwrap(fname, ...decl("nnnn:n")); - return function (context, value) { - // @ts-ignore - const byteLength = value.byteLength ?? value.length; - const ptr = Module._sqlite3_malloc(byteLength); - Module.HEAPU8.subarray(ptr).set(value); - f(context, ptr, byteLength, sqliteFreeAddress); // void return - }; - })(); - - sqlite3.result_double = (function () { - const fname = "sqlite3_result_double"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (context, value) { - f(context, value); // void return - }; - })(); + var UTF8Decoder = + typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; - sqlite3.result_int = (function () { - const fname = "sqlite3_result_int"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (context, value) { - f(context, value); // void return - }; - })(); + function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) { + var endIdx = idx + maxBytesToRead; + var endPtr = idx; - sqlite3.result_int64 = (function () { - const fname = "sqlite3_result_int64"; - const f = Module.cwrap(fname, ...decl("nnn:n")); - return function (context, value) { - if (value > MAX_INT64 || value < MIN_INT64) return SQLITE_RANGE; + while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; - const lo32 = value & 0xffffffffn; - const hi32 = value >> 32n; - f(context, Number(lo32), Number(hi32)); // void return - }; - })(); + if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { + return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); + } + var str = ''; - sqlite3.result_null = (function () { - const fname = "sqlite3_result_null"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (context) { - f(context); // void return - }; - })(); - - sqlite3.result_text = (function () { - const fname = "sqlite3_result_text"; - const f = Module.cwrap(fname, ...decl("nnnn:n")); - return function (context, value) { - const ptr = createUTF8(value); - f(context, ptr, -1, sqliteFreeAddress); // void return - }; - })(); + while (idx < endPtr) { + var u0 = heapOrArray[idx++]; + if (!(u0 & 0x80)) { + str += String.fromCharCode(u0); + continue; + } + var u1 = heapOrArray[idx++] & 63; + if ((u0 & 0xe0) == 0xc0) { + str += String.fromCharCode(((u0 & 31) << 6) | u1); + continue; + } + var u2 = heapOrArray[idx++] & 63; + if ((u0 & 0xf0) == 0xe0) { + u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; + } else { + u0 = + ((u0 & 7) << 18) | + (u1 << 12) | + (u2 << 6) | + (heapOrArray[idx++] & 63); + } - sqlite3.row = function (stmt) { - const row = []; - const nColumns = sqlite3.data_count(stmt); - for (let i = 0; i < nColumns; ++i) { - const value = sqlite3.column(stmt, i); + if (u0 < 0x10000) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 0x10000; + str += String.fromCharCode( + 0xd800 | (ch >> 10), + 0xdc00 | (ch & 0x3ff), + ); + } + } + return str; + } - // Copy blob if aliasing volatile WebAssembly memory. This avoids an - // unnecessary copy if users monkey patch column_blob to copy. - // @ts-ignore - row.push(value?.buffer === Module.HEAPU8.buffer ? value.slice() : value); + function UTF8ToString(ptr, maxBytesToRead) { + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; } - return row; - }; - sqlite3.set_authorizer = function (db, xAuth, pApp) { - verifyDatabase(db); - - // Convert SQLite callback arguments to JavaScript-friendly arguments. - function cvtArgs(_, iAction, p3, p4, p5, p6) { - return [ - _, - iAction, - Module.UTF8ToString(p3), - Module.UTF8ToString(p4), - Module.UTF8ToString(p5), - Module.UTF8ToString(p6), - ]; - } - function adapt(f) { - return f instanceof AsyncFunction$1 - ? (async (_, iAction, p3, p4, p5, p6) => - f(cvtArgs(_, iAction, p3, p4, p5, p6))) - : ((_, iAction, p3, p4, p5, p6) => - f(cvtArgs(_, iAction, p3, p4, p5, p6))); - } - - const result = Module.set_authorizer(db, adapt(xAuth), pApp); - return check("sqlite3_set_authorizer", result, db); - }; + function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { + if (!(maxBytesToWrite > 0)) return 0; - sqlite3.sql = (function () { - const fname = "sqlite3_sql"; - const f = Module.cwrap(fname, ...decl("n:s")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return result; - }; - })(); - - sqlite3.statements = function (db, sql, options = {}) { - const prepare = Module.cwrap( - "sqlite3_prepare_v3", - "number", - ["number", "number", "number", "number", "number", "number"], - { async: true }, - ); + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; + for (var i = 0; i < str.length; ++i) { + var u = str.charCodeAt(i); + if (u >= 0xd800 && u <= 0xdfff) { + var u1 = str.charCodeAt(++i); + u = (0x10000 + ((u & 0x3ff) << 10)) | (u1 & 0x3ff); + } + if (u <= 0x7f) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 0x7ff) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 0xc0 | (u >> 6); + heap[outIdx++] = 0x80 | (u & 63); + } else if (u <= 0xffff) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 0xe0 | (u >> 12); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++] = 0xf0 | (u >> 18); + heap[outIdx++] = 0x80 | ((u >> 12) & 63); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } + } - return (async function* () { - const onFinally = []; - try { - // Encode SQL string to UTF-8. - const utf8 = new TextEncoder().encode(sql); - - // Copy encoded string to WebAssembly memory. The SQLite docs say - // zero-termination is a minor optimization so add room for that. - // Also add space for the statement handle and SQL tail pointer. - const allocSize = utf8.byteLength - (utf8.byteLength % 4) + 12; - const pzHead = Module._sqlite3_malloc(allocSize); - const pzEnd = pzHead + utf8.byteLength + 1; - onFinally.push(() => Module._sqlite3_free(pzHead)); - Module.HEAPU8.set(utf8, pzHead); - Module.HEAPU8[pzEnd - 1] = 0; - - // Use extra space for the statement handle and SQL tail pointer. - const pStmt = pzHead + allocSize - 8; - const pzTail = pzHead + allocSize - 4; - - // Ensure that statement handles are not leaked. - let stmt; - function maybeFinalize() { - if (stmt && !options.unscoped) { - sqlite3.finalize(stmt); - } - stmt = 0; - } - onFinally.push(maybeFinalize); - - // Loop over statements. - Module.setValue(pzTail, pzHead, "*"); - do { - // Reclaim resources for the previous iteration. - maybeFinalize(); - - // Call sqlite3_prepare_v3() for the next statement. - // Allow retry operations. - const zTail = Module.getValue(pzTail, "*"); - const rc = await retry(() => { - return prepare( - db, - zTail, - pzEnd - pzTail, - options.flags || 0, - pStmt, - pzTail, - ); - }); + heap[outIdx] = 0; + return outIdx - startIdx; + } - if (rc !== SQLITE_OK) { - check("sqlite3_prepare_v3", rc, db); - } + function stringToUTF8(str, outPtr, maxBytesToWrite) { + return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + } - stmt = Module.getValue(pStmt, "*"); - if (stmt) { - mapStmtToDB.set(stmt, db); - yield stmt; - } - } while (stmt); - } finally { - while (onFinally.length) { - onFinally.pop()(); + function lengthBytesUTF8(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var c = str.charCodeAt(i); + if (c <= 0x7f) { + len++; + } else if (c <= 0x7ff) { + len += 2; + } else if (c >= 0xd800 && c <= 0xdfff) { + len += 4; + ++i; + } else { + len += 3; } } - })(); - }; + return len; + } + + var HEAP8, + HEAPU8, + HEAP16, + HEAP32, + HEAPU32; + + function updateMemoryViews() { + var b = wasmMemory.buffer; + Module['HEAP8'] = HEAP8 = new Int8Array(b); + Module['HEAP16'] = HEAP16 = new Int16Array(b); + Module['HEAP32'] = HEAP32 = new Int32Array(b); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); + Module['HEAPU16'] = new Uint16Array(b); + Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); + Module['HEAPF32'] = new Float32Array(b); + Module['HEAPF64'] = new Float64Array(b); + Module['HEAP64'] = new BigInt64Array(b); + Module['HEAPU64'] = new BigUint64Array(b); + } - sqlite3.step = (function () { - const fname = "sqlite3_step"; - const f = Module.cwrap(fname, ...decl("n:n"), { async }); - return async function (stmt) { - verifyStatement(stmt); + var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216; - // Allow retry operations. - const rc = await retry(() => f(stmt)); + if (Module['wasmMemory']) { + wasmMemory = Module['wasmMemory']; + } else { + wasmMemory = new WebAssembly.Memory({ + initial: INITIAL_MEMORY / 65536, - return check(fname, rc, mapStmtToDB.get(stmt), [ - SQLITE_ROW, - SQLITE_DONE, - ]); - }; - })(); - - sqlite3.value = function (pValue) { - const type = sqlite3.value_type(pValue); - switch (type) { - case SQLITE_BLOB: - return sqlite3.value_blob(pValue); - case SQLITE_FLOAT: - return sqlite3.value_double(pValue); - case SQLITE_INTEGER: - const lo32 = sqlite3.value_int(pValue); - const hi32 = Module.getTempRet0(); - return cvt32x2AsSafe(lo32, hi32); - case SQLITE_NULL: - return null; - case SQLITE_TEXT: - return sqlite3.value_text(pValue); - default: - throw new SQLiteError("unknown type", type); + maximum: 2147483648 / 65536, + }); } - }; - sqlite3.value_blob = (function () { - const fname = "sqlite3_value_blob"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const nBytes = sqlite3.value_bytes(pValue); - const address = f(pValue); - const result = Module.HEAPU8.subarray(address, address + nBytes); - return result; - }; - })(); - - sqlite3.value_bytes = (function () { - const fname = "sqlite3_value_bytes"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.value_double = (function () { - const fname = "sqlite3_value_double"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.value_int = (function () { - const fname = "sqlite3_value_int64"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.value_int64 = (function () { - const fname = "sqlite3_value_int64"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const lo32 = f(pValue); - const hi32 = Module.getTempRet0(); - const result = cvt32x2ToBigInt(lo32, hi32); - return result; - }; - })(); - - sqlite3.value_text = (function () { - const fname = "sqlite3_value_text"; - const f = Module.cwrap(fname, ...decl("n:s")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.value_type = (function () { - const fname = "sqlite3_value_type"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); + updateMemoryViews(); - sqlite3.vfs_register = function (vfs, makeDefault) { - const result = Module.vfs_register(vfs, makeDefault); - return check("sqlite3_vfs_register", result); - }; + INITIAL_MEMORY = wasmMemory.buffer.byteLength; - function check(fname, result, db = null, allowed = [SQLITE_OK]) { - if (allowed.includes(result)) return result; - const message = db - ? Module.ccall("sqlite3_errmsg", "string", ["number"], [db]) - : fname; - throw new SQLiteError(message, result); - } + var __ATPRERUN__ = []; + var __ATINIT__ = []; + var __ATPOSTRUN__ = []; - // This function is used to automatically retry failed calls that - // have pending retry operations that should allow the retry to - // succeed. - async function retry(f) { - let rc; - do { - // Wait for all pending retry operations to complete. This is - // normally empty on the first loop iteration. - if (Module.retryOps.length) { - await Promise.all(Module.retryOps); - Module.retryOps = []; + function preRun() { + if (Module['preRun']) { + if (typeof Module['preRun'] == 'function') + Module['preRun'] = [Module['preRun']]; + while (Module['preRun'].length) { + addOnPreRun(Module['preRun'].shift()); + } } - rc = await f(); - - // Retry on failure with new pending retry operations. - } while (rc && Module.retryOps.length); - return rc; - } - - return sqlite3; -} + callRuntimeCallbacks(__ATPRERUN__); + } -// Helper function to use a more compact signature specification. -function decl(s) { - const result = []; - const m = s.match(/([ns@]*):([nsv@])/); - switch (m[2]) { - case "n": - result.push("number"); - break; - case "s": - result.push("string"); - break; - case "v": - result.push(null); - break; - } + function initRuntime() { - const args = []; - for (let c of m[1]) { - switch (c) { - case "n": - args.push("number"); - break; - case "s": - args.push("string"); - break; + if (!Module['noFSInit'] && !FS.init.initialized) FS.init(); + FS.ignorePermissions = false; + callRuntimeCallbacks(__ATINIT__); } - } - result.push(args); - return result; -} -var WasmSQLiteLibrary = /*#__PURE__*/Object.freeze({ - __proto__: null, - Factory: Factory, - SQLITE_ABORT: SQLITE_ABORT, - SQLITE_ACCESS_EXISTS: SQLITE_ACCESS_EXISTS, - SQLITE_ACCESS_READ: SQLITE_ACCESS_READ, - SQLITE_ACCESS_READWRITE: SQLITE_ACCESS_READWRITE, - SQLITE_ALTER_TABLE: SQLITE_ALTER_TABLE, - SQLITE_ANALYZE: SQLITE_ANALYZE, - SQLITE_ATTACH: SQLITE_ATTACH, - SQLITE_AUTH: SQLITE_AUTH, - SQLITE_BLOB: SQLITE_BLOB, - SQLITE_BUSY: SQLITE_BUSY, - SQLITE_CANTOPEN: SQLITE_CANTOPEN, - SQLITE_CONSTRAINT: SQLITE_CONSTRAINT, - SQLITE_CONSTRAINT_CHECK: SQLITE_CONSTRAINT_CHECK, - SQLITE_CONSTRAINT_COMMITHOOK: SQLITE_CONSTRAINT_COMMITHOOK, - SQLITE_CONSTRAINT_FOREIGNKEY: SQLITE_CONSTRAINT_FOREIGNKEY, - SQLITE_CONSTRAINT_FUNCTION: SQLITE_CONSTRAINT_FUNCTION, - SQLITE_CONSTRAINT_NOTNULL: SQLITE_CONSTRAINT_NOTNULL, - SQLITE_CONSTRAINT_PINNED: SQLITE_CONSTRAINT_PINNED, - SQLITE_CONSTRAINT_PRIMARYKEY: SQLITE_CONSTRAINT_PRIMARYKEY, - SQLITE_CONSTRAINT_ROWID: SQLITE_CONSTRAINT_ROWID, - SQLITE_CONSTRAINT_TRIGGER: SQLITE_CONSTRAINT_TRIGGER, - SQLITE_CONSTRAINT_UNIQUE: SQLITE_CONSTRAINT_UNIQUE, - SQLITE_CONSTRAINT_VTAB: SQLITE_CONSTRAINT_VTAB, - SQLITE_COPY: SQLITE_COPY, - SQLITE_CORRUPT: SQLITE_CORRUPT, - SQLITE_CREATE_INDEX: SQLITE_CREATE_INDEX, - SQLITE_CREATE_TABLE: SQLITE_CREATE_TABLE, - SQLITE_CREATE_TEMP_INDEX: SQLITE_CREATE_TEMP_INDEX, - SQLITE_CREATE_TEMP_TABLE: SQLITE_CREATE_TEMP_TABLE, - SQLITE_CREATE_TEMP_TRIGGER: SQLITE_CREATE_TEMP_TRIGGER, - SQLITE_CREATE_TEMP_VIEW: SQLITE_CREATE_TEMP_VIEW, - SQLITE_CREATE_TRIGGER: SQLITE_CREATE_TRIGGER, - SQLITE_CREATE_VIEW: SQLITE_CREATE_VIEW, - SQLITE_CREATE_VTABLE: SQLITE_CREATE_VTABLE, - SQLITE_DELETE: SQLITE_DELETE, - SQLITE_DENY: SQLITE_DENY, - SQLITE_DETACH: SQLITE_DETACH, - SQLITE_DETERMINISTIC: SQLITE_DETERMINISTIC, - SQLITE_DIRECTONLY: SQLITE_DIRECTONLY, - SQLITE_DONE: SQLITE_DONE, - SQLITE_DROP_INDEX: SQLITE_DROP_INDEX, - SQLITE_DROP_TABLE: SQLITE_DROP_TABLE, - SQLITE_DROP_TEMP_INDEX: SQLITE_DROP_TEMP_INDEX, - SQLITE_DROP_TEMP_TABLE: SQLITE_DROP_TEMP_TABLE, - SQLITE_DROP_TEMP_TRIGGER: SQLITE_DROP_TEMP_TRIGGER, - SQLITE_DROP_TEMP_VIEW: SQLITE_DROP_TEMP_VIEW, - SQLITE_DROP_TRIGGER: SQLITE_DROP_TRIGGER, - SQLITE_DROP_VIEW: SQLITE_DROP_VIEW, - SQLITE_DROP_VTABLE: SQLITE_DROP_VTABLE, - SQLITE_EMPTY: SQLITE_EMPTY, - SQLITE_ERROR: SQLITE_ERROR, - SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, - SQLITE_FCNTL_BUSYHANDLER: SQLITE_FCNTL_BUSYHANDLER, - SQLITE_FCNTL_CHUNK_SIZE: SQLITE_FCNTL_CHUNK_SIZE, - SQLITE_FCNTL_CKPT_DONE: SQLITE_FCNTL_CKPT_DONE, - SQLITE_FCNTL_CKPT_START: SQLITE_FCNTL_CKPT_START, - SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, - SQLITE_FCNTL_COMMIT_PHASETWO: SQLITE_FCNTL_COMMIT_PHASETWO, - SQLITE_FCNTL_DATA_VERSION: SQLITE_FCNTL_DATA_VERSION, - SQLITE_FCNTL_FILE_POINTER: SQLITE_FCNTL_FILE_POINTER, - SQLITE_FCNTL_GET_LOCKPROXYFILE: SQLITE_FCNTL_GET_LOCKPROXYFILE, - SQLITE_FCNTL_HAS_MOVED: SQLITE_FCNTL_HAS_MOVED, - SQLITE_FCNTL_JOURNAL_POINTER: SQLITE_FCNTL_JOURNAL_POINTER, - SQLITE_FCNTL_LAST_ERRNO: SQLITE_FCNTL_LAST_ERRNO, - SQLITE_FCNTL_LOCKSTATE: SQLITE_FCNTL_LOCKSTATE, - SQLITE_FCNTL_LOCK_TIMEOUT: SQLITE_FCNTL_LOCK_TIMEOUT, - SQLITE_FCNTL_MMAP_SIZE: SQLITE_FCNTL_MMAP_SIZE, - SQLITE_FCNTL_OVERWRITE: SQLITE_FCNTL_OVERWRITE, - SQLITE_FCNTL_PDB: SQLITE_FCNTL_PDB, - SQLITE_FCNTL_PERSIST_WAL: SQLITE_FCNTL_PERSIST_WAL, - SQLITE_FCNTL_POWERSAFE_OVERWRITE: SQLITE_FCNTL_POWERSAFE_OVERWRITE, - SQLITE_FCNTL_PRAGMA: SQLITE_FCNTL_PRAGMA, - SQLITE_FCNTL_RBU: SQLITE_FCNTL_RBU, - SQLITE_FCNTL_RESERVE_BYTES: SQLITE_FCNTL_RESERVE_BYTES, - SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, - SQLITE_FCNTL_SET_LOCKPROXYFILE: SQLITE_FCNTL_SET_LOCKPROXYFILE, - SQLITE_FCNTL_SIZE_HINT: SQLITE_FCNTL_SIZE_HINT, - SQLITE_FCNTL_SIZE_LIMIT: SQLITE_FCNTL_SIZE_LIMIT, - SQLITE_FCNTL_SYNC: SQLITE_FCNTL_SYNC, - SQLITE_FCNTL_SYNC_OMITTED: SQLITE_FCNTL_SYNC_OMITTED, - SQLITE_FCNTL_TEMPFILENAME: SQLITE_FCNTL_TEMPFILENAME, - SQLITE_FCNTL_TRACE: SQLITE_FCNTL_TRACE, - SQLITE_FCNTL_VFSNAME: SQLITE_FCNTL_VFSNAME, - SQLITE_FCNTL_VFS_POINTER: SQLITE_FCNTL_VFS_POINTER, - SQLITE_FCNTL_WAL_BLOCK: SQLITE_FCNTL_WAL_BLOCK, - SQLITE_FCNTL_WIN32_AV_RETRY: SQLITE_FCNTL_WIN32_AV_RETRY, - SQLITE_FCNTL_WIN32_GET_HANDLE: SQLITE_FCNTL_WIN32_GET_HANDLE, - SQLITE_FCNTL_WIN32_SET_HANDLE: SQLITE_FCNTL_WIN32_SET_HANDLE, - SQLITE_FCNTL_ZIPVFS: SQLITE_FCNTL_ZIPVFS, - SQLITE_FLOAT: SQLITE_FLOAT, - SQLITE_FORMAT: SQLITE_FORMAT, - SQLITE_FULL: SQLITE_FULL, - SQLITE_FUNCTION: SQLITE_FUNCTION, - SQLITE_IGNORE: SQLITE_IGNORE, - SQLITE_INDEX_CONSTRAINT_EQ: SQLITE_INDEX_CONSTRAINT_EQ, - SQLITE_INDEX_CONSTRAINT_FUNCTION: SQLITE_INDEX_CONSTRAINT_FUNCTION, - SQLITE_INDEX_CONSTRAINT_GE: SQLITE_INDEX_CONSTRAINT_GE, - SQLITE_INDEX_CONSTRAINT_GLOB: SQLITE_INDEX_CONSTRAINT_GLOB, - SQLITE_INDEX_CONSTRAINT_GT: SQLITE_INDEX_CONSTRAINT_GT, - SQLITE_INDEX_CONSTRAINT_IS: SQLITE_INDEX_CONSTRAINT_IS, - SQLITE_INDEX_CONSTRAINT_ISNOT: SQLITE_INDEX_CONSTRAINT_ISNOT, - SQLITE_INDEX_CONSTRAINT_ISNOTNULL: SQLITE_INDEX_CONSTRAINT_ISNOTNULL, - SQLITE_INDEX_CONSTRAINT_ISNULL: SQLITE_INDEX_CONSTRAINT_ISNULL, - SQLITE_INDEX_CONSTRAINT_LE: SQLITE_INDEX_CONSTRAINT_LE, - SQLITE_INDEX_CONSTRAINT_LIKE: SQLITE_INDEX_CONSTRAINT_LIKE, - SQLITE_INDEX_CONSTRAINT_LT: SQLITE_INDEX_CONSTRAINT_LT, - SQLITE_INDEX_CONSTRAINT_MATCH: SQLITE_INDEX_CONSTRAINT_MATCH, - SQLITE_INDEX_CONSTRAINT_NE: SQLITE_INDEX_CONSTRAINT_NE, - SQLITE_INDEX_CONSTRAINT_REGEXP: SQLITE_INDEX_CONSTRAINT_REGEXP, - SQLITE_INDEX_SCAN_UNIQUE: SQLITE_INDEX_SCAN_UNIQUE, - SQLITE_INNOCUOUS: SQLITE_INNOCUOUS, - SQLITE_INSERT: SQLITE_INSERT, - SQLITE_INTEGER: SQLITE_INTEGER, - SQLITE_INTERNAL: SQLITE_INTERNAL, - SQLITE_INTERRUPT: SQLITE_INTERRUPT, - SQLITE_IOCAP_ATOMIC: SQLITE_IOCAP_ATOMIC, - SQLITE_IOCAP_ATOMIC16K: SQLITE_IOCAP_ATOMIC16K, - SQLITE_IOCAP_ATOMIC1K: SQLITE_IOCAP_ATOMIC1K, - SQLITE_IOCAP_ATOMIC2K: SQLITE_IOCAP_ATOMIC2K, - SQLITE_IOCAP_ATOMIC32K: SQLITE_IOCAP_ATOMIC32K, - SQLITE_IOCAP_ATOMIC4K: SQLITE_IOCAP_ATOMIC4K, - SQLITE_IOCAP_ATOMIC512: SQLITE_IOCAP_ATOMIC512, - SQLITE_IOCAP_ATOMIC64K: SQLITE_IOCAP_ATOMIC64K, - SQLITE_IOCAP_ATOMIC8K: SQLITE_IOCAP_ATOMIC8K, - SQLITE_IOCAP_BATCH_ATOMIC: SQLITE_IOCAP_BATCH_ATOMIC, - SQLITE_IOCAP_IMMUTABLE: SQLITE_IOCAP_IMMUTABLE, - SQLITE_IOCAP_POWERSAFE_OVERWRITE: SQLITE_IOCAP_POWERSAFE_OVERWRITE, - SQLITE_IOCAP_SAFE_APPEND: SQLITE_IOCAP_SAFE_APPEND, - SQLITE_IOCAP_SEQUENTIAL: SQLITE_IOCAP_SEQUENTIAL, - SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN: SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN, - SQLITE_IOERR: SQLITE_IOERR, - SQLITE_IOERR_ACCESS: SQLITE_IOERR_ACCESS, - SQLITE_IOERR_BEGIN_ATOMIC: SQLITE_IOERR_BEGIN_ATOMIC, - SQLITE_IOERR_CHECKRESERVEDLOCK: SQLITE_IOERR_CHECKRESERVEDLOCK, - SQLITE_IOERR_CLOSE: SQLITE_IOERR_CLOSE, - SQLITE_IOERR_COMMIT_ATOMIC: SQLITE_IOERR_COMMIT_ATOMIC, - SQLITE_IOERR_DATA: SQLITE_IOERR_DATA, - SQLITE_IOERR_DELETE: SQLITE_IOERR_DELETE, - SQLITE_IOERR_DELETE_NOENT: SQLITE_IOERR_DELETE_NOENT, - SQLITE_IOERR_DIR_FSYNC: SQLITE_IOERR_DIR_FSYNC, - SQLITE_IOERR_FSTAT: SQLITE_IOERR_FSTAT, - SQLITE_IOERR_FSYNC: SQLITE_IOERR_FSYNC, - SQLITE_IOERR_GETTEMPPATH: SQLITE_IOERR_GETTEMPPATH, - SQLITE_IOERR_LOCK: SQLITE_IOERR_LOCK, - SQLITE_IOERR_NOMEM: SQLITE_IOERR_NOMEM, - SQLITE_IOERR_RDLOCK: SQLITE_IOERR_RDLOCK, - SQLITE_IOERR_READ: SQLITE_IOERR_READ, - SQLITE_IOERR_ROLLBACK_ATOMIC: SQLITE_IOERR_ROLLBACK_ATOMIC, - SQLITE_IOERR_SEEK: SQLITE_IOERR_SEEK, - SQLITE_IOERR_SHORT_READ: SQLITE_IOERR_SHORT_READ, - SQLITE_IOERR_TRUNCATE: SQLITE_IOERR_TRUNCATE, - SQLITE_IOERR_UNLOCK: SQLITE_IOERR_UNLOCK, - SQLITE_IOERR_VNODE: SQLITE_IOERR_VNODE, - SQLITE_IOERR_WRITE: SQLITE_IOERR_WRITE, - SQLITE_LIMIT_ATTACHED: SQLITE_LIMIT_ATTACHED, - SQLITE_LIMIT_COLUMN: SQLITE_LIMIT_COLUMN, - SQLITE_LIMIT_COMPOUND_SELECT: SQLITE_LIMIT_COMPOUND_SELECT, - SQLITE_LIMIT_EXPR_DEPTH: SQLITE_LIMIT_EXPR_DEPTH, - SQLITE_LIMIT_FUNCTION_ARG: SQLITE_LIMIT_FUNCTION_ARG, - SQLITE_LIMIT_LENGTH: SQLITE_LIMIT_LENGTH, - SQLITE_LIMIT_LIKE_PATTERN_LENGTH: SQLITE_LIMIT_LIKE_PATTERN_LENGTH, - SQLITE_LIMIT_SQL_LENGTH: SQLITE_LIMIT_SQL_LENGTH, - SQLITE_LIMIT_TRIGGER_DEPTH: SQLITE_LIMIT_TRIGGER_DEPTH, - SQLITE_LIMIT_VARIABLE_NUMBER: SQLITE_LIMIT_VARIABLE_NUMBER, - SQLITE_LIMIT_VDBE_OP: SQLITE_LIMIT_VDBE_OP, - SQLITE_LIMIT_WORKER_THREADS: SQLITE_LIMIT_WORKER_THREADS, - SQLITE_LOCKED: SQLITE_LOCKED, - SQLITE_LOCK_EXCLUSIVE: SQLITE_LOCK_EXCLUSIVE, - SQLITE_LOCK_NONE: SQLITE_LOCK_NONE, - SQLITE_LOCK_PENDING: SQLITE_LOCK_PENDING, - SQLITE_LOCK_RESERVED: SQLITE_LOCK_RESERVED, - SQLITE_LOCK_SHARED: SQLITE_LOCK_SHARED, - SQLITE_MISMATCH: SQLITE_MISMATCH, - SQLITE_MISUSE: SQLITE_MISUSE, - SQLITE_NOLFS: SQLITE_NOLFS, - SQLITE_NOMEM: SQLITE_NOMEM, - SQLITE_NOTADB: SQLITE_NOTADB, - SQLITE_NOTFOUND: SQLITE_NOTFOUND, - SQLITE_NOTICE: SQLITE_NOTICE, - SQLITE_NULL: SQLITE_NULL, - SQLITE_OK: SQLITE_OK, - SQLITE_OPEN_AUTOPROXY: SQLITE_OPEN_AUTOPROXY, - SQLITE_OPEN_CREATE: SQLITE_OPEN_CREATE, - SQLITE_OPEN_DELETEONCLOSE: SQLITE_OPEN_DELETEONCLOSE, - SQLITE_OPEN_EXCLUSIVE: SQLITE_OPEN_EXCLUSIVE, - SQLITE_OPEN_FULLMUTEX: SQLITE_OPEN_FULLMUTEX, - SQLITE_OPEN_MAIN_DB: SQLITE_OPEN_MAIN_DB, - SQLITE_OPEN_MAIN_JOURNAL: SQLITE_OPEN_MAIN_JOURNAL, - SQLITE_OPEN_MEMORY: SQLITE_OPEN_MEMORY, - SQLITE_OPEN_NOFOLLOW: SQLITE_OPEN_NOFOLLOW, - SQLITE_OPEN_NOMUTEX: SQLITE_OPEN_NOMUTEX, - SQLITE_OPEN_PRIVATECACHE: SQLITE_OPEN_PRIVATECACHE, - SQLITE_OPEN_READONLY: SQLITE_OPEN_READONLY, - SQLITE_OPEN_READWRITE: SQLITE_OPEN_READWRITE, - SQLITE_OPEN_SHAREDCACHE: SQLITE_OPEN_SHAREDCACHE, - SQLITE_OPEN_SUBJOURNAL: SQLITE_OPEN_SUBJOURNAL, - SQLITE_OPEN_SUPER_JOURNAL: SQLITE_OPEN_SUPER_JOURNAL, - SQLITE_OPEN_TEMP_DB: SQLITE_OPEN_TEMP_DB, - SQLITE_OPEN_TEMP_JOURNAL: SQLITE_OPEN_TEMP_JOURNAL, - SQLITE_OPEN_TRANSIENT_DB: SQLITE_OPEN_TRANSIENT_DB, - SQLITE_OPEN_URI: SQLITE_OPEN_URI, - SQLITE_OPEN_WAL: SQLITE_OPEN_WAL, - SQLITE_PERM: SQLITE_PERM, - SQLITE_PRAGMA: SQLITE_PRAGMA, - SQLITE_PREPARE_NORMALIZED: SQLITE_PREPARE_NORMALIZED, - SQLITE_PREPARE_NO_VTAB: SQLITE_PREPARE_NO_VTAB, - SQLITE_PREPARE_PERSISTENT: SQLITE_PREPARE_PERSISTENT, - SQLITE_PROTOCOL: SQLITE_PROTOCOL, - SQLITE_RANGE: SQLITE_RANGE, - SQLITE_READ: SQLITE_READ, - SQLITE_READONLY: SQLITE_READONLY, - SQLITE_RECURSIVE: SQLITE_RECURSIVE, - SQLITE_REINDEX: SQLITE_REINDEX, - SQLITE_ROW: SQLITE_ROW, - SQLITE_SAVEPOINT: SQLITE_SAVEPOINT, - SQLITE_SCHEMA: SQLITE_SCHEMA, - SQLITE_SELECT: SQLITE_SELECT, - SQLITE_STATIC: SQLITE_STATIC, - SQLITE_SUBTYPE: SQLITE_SUBTYPE, - SQLITE_SYNC_DATAONLY: SQLITE_SYNC_DATAONLY, - SQLITE_SYNC_FULL: SQLITE_SYNC_FULL, - SQLITE_SYNC_NORMAL: SQLITE_SYNC_NORMAL, - SQLITE_TEXT: SQLITE_TEXT, - SQLITE_TOOBIG: SQLITE_TOOBIG, - SQLITE_TRANSACTION: SQLITE_TRANSACTION, - SQLITE_TRANSIENT: SQLITE_TRANSIENT, - SQLITE_UPDATE: SQLITE_UPDATE, - SQLITE_UTF16: SQLITE_UTF16, - SQLITE_UTF16BE: SQLITE_UTF16BE, - SQLITE_UTF16LE: SQLITE_UTF16LE, - SQLITE_UTF8: SQLITE_UTF8, - SQLITE_WARNING: SQLITE_WARNING, - SQLiteError: SQLiteError -}); + function postRun() { + if (Module['postRun']) { + if (typeof Module['postRun'] == 'function') + Module['postRun'] = [Module['postRun']]; + while (Module['postRun'].length) { + addOnPostRun(Module['postRun'].shift()); + } + } -// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. + callRuntimeCallbacks(__ATPOSTRUN__); + } -const DEFAULT_SECTOR_SIZE = 512; + function addOnPreRun(cb) { + __ATPRERUN__.unshift(cb); + } -// Base class for a VFS. -class Base { - name; - mxPathname = 64; - _module; + function addOnInit(cb) { + __ATINIT__.unshift(cb); + } - /** - * @param {string} name - * @param {object} module - */ - constructor(name, module) { - this.name = name; - this._module = module; - } + function addOnPostRun(cb) { + __ATPOSTRUN__.unshift(cb); + } - /** - * @returns {void|Promise} - */ - close() { - } + var runDependencies = 0; + var dependenciesFulfilled = null; - /** - * @returns {boolean|Promise} - */ - isReady() { - return true; - } + function getUniqueRunDependency(id) { + return id; + } - /** - * Overload in subclasses to indicate which methods are asynchronous. - * @param {string} methodName - * @returns {boolean} - */ - hasAsyncMethod(methodName) { - return false; - } + function addRunDependency(id) { + runDependencies++; - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} pFile - * @param {number} flags - * @param {number} pOutFlags - * @returns {number|Promise} - */ - xOpen(pVfs, zName, pFile, flags, pOutFlags) { - return SQLITE_CANTOPEN; - } + if (Module['monitorRunDependencies']) { + Module['monitorRunDependencies'](runDependencies); + } + } - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} syncDir - * @returns {number|Promise} - */ - xDelete(pVfs, zName, syncDir) { - return SQLITE_OK; - } + function removeRunDependency(id) { + runDependencies--; - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} flags - * @param {number} pResOut - * @returns {number|Promise} - */ - xAccess(pVfs, zName, flags, pResOut) { - return SQLITE_OK; - } + if (Module['monitorRunDependencies']) { + Module['monitorRunDependencies'](runDependencies); + } - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} nOut - * @param {number} zOut - * @returns {number|Promise} - */ - xFullPathname(pVfs, zName, nOut, zOut) { - return SQLITE_OK; - } + if (runDependencies == 0) { + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); + } + } + } - /** - * @param {number} pVfs - * @param {number} nBuf - * @param {number} zBuf - * @returns {number|Promise} - */ - xGetLastError(pVfs, nBuf, zBuf) { - return SQLITE_OK; - } + function abort(what) { + if (Module['onAbort']) { + Module['onAbort'](what); + } - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xClose(pFile) { - return SQLITE_OK; - } + what = 'Aborted(' + what + ')'; - /** - * @param {number} pFile - * @param {number} pData - * @param {number} iAmt - * @param {number} iOffsetLo - * @param {number} iOffsetHi - * @returns {number|Promise} - */ - xRead(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { - return SQLITE_OK; - } + err(what); - /** - * @param {number} pFile - * @param {number} pData - * @param {number} iAmt - * @param {number} iOffsetLo - * @param {number} iOffsetHi - * @returns {number|Promise} - */ - xWrite(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { - return SQLITE_OK; - } + ABORT = true; - /** - * @param {number} pFile - * @param {number} sizeLo - * @param {number} sizeHi - * @returns {number|Promise} - */ - xTruncate(pFile, sizeLo, sizeHi) { - return SQLITE_OK; - } + what += '. Build with -sASSERTIONS for more info.'; - /** - * @param {number} pFile - * @param {number} flags - * @returns {number|Promise} - */ - xSync(pFile, flags) { - return SQLITE_OK; - } + var e = new WebAssembly.RuntimeError(what); - /** - * - * @param {number} pFile - * @param {number} pSize - * @returns {number|Promise} - */ - xFileSize(pFile, pSize) { - return SQLITE_OK; - } + readyPromiseReject(e); - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - xLock(pFile, lockType) { - return SQLITE_OK; - } + throw e; + } - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - xUnlock(pFile, lockType) { - return SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} pResOut - * @returns {number|Promise} - */ - xCheckReservedLock(pFile, pResOut) { - return SQLITE_OK; - } + var dataURIPrefix = 'data:application/octet-stream;base64,'; - /** - * @param {number} pFile - * @param {number} op - * @param {number} pArg - * @returns {number|Promise} - */ - xFileControl(pFile, op, pArg) { - return SQLITE_NOTFOUND; - } + function isDataURI(filename) { + return filename.startsWith(dataURIPrefix); + } - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xSectorSize(pFile) { - return DEFAULT_SECTOR_SIZE; - } + var wasmBinaryFile; + if (Module['locateFile']) { + wasmBinaryFile = 'sqlite3.wasm'; + if (!isDataURI(wasmBinaryFile)) { + wasmBinaryFile = locateFile(wasmBinaryFile); + } + } else { + wasmBinaryFile = new URL('sqlite3.wasm', import.meta.url).href; + } - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xDeviceCharacteristics(pFile) { - return 0; - } -} + function getBinary(file) { + try { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } + throw 'both async and sync fetching of the wasm failed'; + } catch (err) { + abort(err); + } + } -// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. - -const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; - -// Convenience base class for a JavaScript VFS. -// The raw xOpen, xRead, etc. function signatures receive only C primitives -// which aren't easy to work with. This class provides corresponding calls -// like jOpen, jRead, etc., which receive JavaScript-friendlier arguments -// such as string, Uint8Array, and DataView. -class FacadeVFS extends Base { - /** - * @param {string} name - * @param {object} module - */ - constructor(name, module) { - super(name, module); - } + function getBinaryPromise() { + if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { + if (typeof fetch == 'function') { + return fetch(wasmBinaryFile, { credentials: 'same-origin' }) + .then(function (response) { + if (!response['ok']) { + throw ( + "failed to load wasm binary file at '" + wasmBinaryFile + "'" + ); + } + return response['arrayBuffer'](); + }) + .catch(function () { + return getBinary(wasmBinaryFile); + }); + } + } - /** - * Override to indicate which methods are asynchronous. - * @param {string} methodName - * @returns {boolean} - */ - hasAsyncMethod(methodName) { - // The input argument is a string like "xOpen", so convert to "jOpen". - // Then check if the method exists and is async. - const jMethodName = `j${methodName.slice(1)}`; - return this[jMethodName] instanceof AsyncFunction; - } - - /** - * Return the filename for a file id for use by mixins. - * @param {number} pFile - * @returns {string} - */ - getFilename(pFile) { - throw new Error('unimplemented'); - } + return Promise.resolve().then(function () { + return getBinary(wasmBinaryFile); + }); + } - /** - * @param {string?} filename - * @param {number} pFile - * @param {number} flags - * @param {DataView} pOutFlags - * @returns {number|Promise} - */ - jOpen(filename, pFile, flags, pOutFlags) { - return SQLITE_CANTOPEN; - } + function createWasm() { + var info = { + env: asmLibraryArg, + wasi_snapshot_preview1: asmLibraryArg, + }; - /** - * @param {string} filename - * @param {number} syncDir - * @returns {number|Promise} - */ - jDelete(filename, syncDir) { - return SQLITE_OK; - } + function receiveInstance(instance, module) { + var exports = instance.exports; - /** - * @param {string} filename - * @param {number} flags - * @param {DataView} pResOut - * @returns {number|Promise} - */ - jAccess(filename, flags, pResOut) { - return SQLITE_OK; - } + Module['asm'] = exports; - /** - * @param {string} filename - * @param {Uint8Array} zOut - * @returns {number|Promise} - */ - jFullPathname(filename, zOut) { - // Copy the filename to the output buffer. - const { read, written } = new TextEncoder().encodeInto(filename, zOut); - if (read < filename.length) return SQLITE_IOERR; - if (written >= zOut.length) return SQLITE_IOERR; - zOut[written] = 0; - return SQLITE_OK; - } + Module['asm']['__indirect_function_table']; - /** - * @param {Uint8Array} zBuf - * @returns {number|Promise} - */ - jGetLastError(zBuf) { - return SQLITE_OK; - } + addOnInit(Module['asm']['__wasm_call_ctors']); - /** - * @param {number} pFile - * @returns {number|Promise} - */ - jClose(pFile) { - return SQLITE_OK; - } + removeRunDependency(); + } - /** - * @param {number} pFile - * @param {Uint8Array} pData - * @param {number} iOffset - * @returns {number|Promise} - */ - jRead(pFile, pData, iOffset) { - pData.fill(0); - return SQLITE_IOERR_SHORT_READ; - } + addRunDependency(); - /** - * @param {number} pFile - * @param {Uint8Array} pData - * @param {number} iOffset - * @returns {number|Promise} - */ - jWrite(pFile, pData, iOffset) { - return SQLITE_IOERR_WRITE; - } + function receiveInstantiationResult(result) { + receiveInstance(result['instance']); + } - /** - * @param {number} pFile - * @param {number} size - * @returns {number|Promise} - */ - jTruncate(pFile, size) { - return SQLITE_OK; - } + function instantiateArrayBuffer(receiver) { + return getBinaryPromise() + .then(function (binary) { + return WebAssembly.instantiate(binary, info); + }) + .then(function (instance) { + return instance; + }) + .then(receiver, function (reason) { + err('failed to asynchronously prepare wasm: ' + reason); + + abort(reason); + }); + } - /** - * @param {number} pFile - * @param {number} flags - * @returns {number|Promise} - */ - jSync(pFile, flags) { - return SQLITE_OK; - } + function instantiateAsync() { + if ( + !wasmBinary && + typeof WebAssembly.instantiateStreaming == 'function' && + !isDataURI(wasmBinaryFile) && + typeof fetch == 'function' + ) { + return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then( + function (response) { + var result = WebAssembly.instantiateStreaming(response, info); + + return result.then(receiveInstantiationResult, function (reason) { + err('wasm streaming compile failed: ' + reason); + err('falling back to ArrayBuffer instantiation'); + return instantiateArrayBuffer(receiveInstantiationResult); + }); + }, + ); + } else { + return instantiateArrayBuffer(receiveInstantiationResult); + } + } - /** - * @param {number} pFile - * @param {DataView} pSize - * @returns {number|Promise} - */ - jFileSize(pFile, pSize) { - return SQLITE_OK; - } + if (Module['instantiateWasm']) { + try { + var exports = Module['instantiateWasm'](info, receiveInstance); + return exports; + } catch (e) { + err('Module.instantiateWasm callback failed with error: ' + e); - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - jLock(pFile, lockType) { - return SQLITE_OK; - } + readyPromiseReject(e); + } + } - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - jUnlock(pFile, lockType) { - return SQLITE_OK; - } + instantiateAsync().catch(readyPromiseReject); + return {}; + } - /** - * @param {number} pFile - * @param {DataView} pResOut - * @returns {number|Promise} - */ - jCheckReservedLock(pFile, pResOut) { - pResOut.setInt32(0, 0, true); - return SQLITE_OK; - } + var tempDouble; + var tempI64; - /** - * @param {number} pFile - * @param {number} op - * @param {DataView} pArg - * @returns {number|Promise} - */ - jFileControl(pFile, op, pArg) { - return SQLITE_NOTFOUND; - } + function callRuntimeCallbacks(callbacks) { + while (callbacks.length > 0) { + callbacks.shift()(Module); + } + } - /** - * @param {number} pFile - * @returns {number|Promise} - */ - jSectorSize(pFile) { - return super.xSectorSize(pFile); - } + var PATH = { + isAbs: (path) => path.charAt(0) === '/', + splitPath: (filename) => { + var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + return splitPathRe.exec(filename).slice(1); + }, + normalizeArray: (parts, allowAboveRoot) => { + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } - /** - * @param {number} pFile - * @returns {number|Promise} - */ - jDeviceCharacteristics(pFile) { - return 0; - } + if (allowAboveRoot) { + for (; up; up--) { + parts.unshift('..'); + } + } + return parts; + }, + normalize: (path) => { + var isAbsolute = PATH.isAbs(path), + trailingSlash = path.substr(-1) === '/'; + + path = PATH.normalizeArray( + path.split('/').filter((p) => !!p), + !isAbsolute, + ).join('/'); + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + return (isAbsolute ? '/' : '') + path; + }, + dirname: (path) => { + var result = PATH.splitPath(path), + root = result[0], + dir = result[1]; + if (!root && !dir) { + return '.'; + } + if (dir) { + dir = dir.substr(0, dir.length - 1); + } + return root + dir; + }, + basename: (path) => { + if (path === '/') return '/'; + path = PATH.normalize(path); + path = path.replace(/\/$/, ''); + var lastSlash = path.lastIndexOf('/'); + if (lastSlash === -1) return path; + return path.substr(lastSlash + 1); + }, + join: function () { + var paths = Array.prototype.slice.call(arguments); + return PATH.normalize(paths.join('/')); + }, + join2: (l, r) => { + return PATH.normalize(l + '/' + r); + }, + }; - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} pFile - * @param {number} flags - * @param {number} pOutFlags - * @returns {number|Promise} - */ - xOpen(pVfs, zName, pFile, flags, pOutFlags) { - const filename = this.#decodeFilename(zName, flags); - const pOutFlagsView = this.#makeTypedDataView('Int32', pOutFlags); - this['log']?.('jOpen', filename, pFile, '0x' + flags.toString(16)); - return this.jOpen(filename, pFile, flags, pOutFlagsView); - } + function getRandomDevice() { + if ( + typeof crypto == 'object' && + typeof crypto['getRandomValues'] == 'function' + ) { + var randomBuffer = new Uint8Array(1); + return () => { + crypto.getRandomValues(randomBuffer); + return randomBuffer[0]; + }; + } else return () => abort('randomDevice'); + } - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} syncDir - * @returns {number|Promise} - */ - xDelete(pVfs, zName, syncDir) { - const filename = this._module.UTF8ToString(zName); - this['log']?.('jDelete', filename, syncDir); - return this.jDelete(filename, syncDir); - } + var PATH_FS = { + resolve: function () { + var resolvedPath = '', + resolvedAbsolute = false; + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = i >= 0 ? arguments[i] : FS.cwd(); + + if (typeof path != 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + return ''; + } + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = PATH.isAbs(path); + } - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} flags - * @param {number} pResOut - * @returns {number|Promise} - */ - xAccess(pVfs, zName, flags, pResOut) { - const filename = this._module.UTF8ToString(zName); - const pResOutView = this.#makeTypedDataView('Int32', pResOut); - this['log']?.('jAccess', filename, flags); - return this.jAccess(filename, flags, pResOutView); - } + resolvedPath = PATH.normalizeArray( + resolvedPath.split('/').filter((p) => !!p), + !resolvedAbsolute, + ).join('/'); + return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'; + }, + relative: (from, to) => { + from = PATH_FS.resolve(from).substr(1); + to = PATH_FS.resolve(to).substr(1); + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + return outputParts.join('/'); + }, + }; - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} nOut - * @param {number} zOut - * @returns {number|Promise} - */ - xFullPathname(pVfs, zName, nOut, zOut) { - const filename = this._module.UTF8ToString(zName); - const zOutArray = this._module.HEAPU8.subarray(zOut, zOut + nOut); - this['log']?.('jFullPathname', filename, nOut); - return this.jFullPathname(filename, zOutArray); - } + function intArrayFromString(stringy, dontAddNull, length) { + var len = lengthBytesUTF8(stringy) + 1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array( + stringy, + u8array, + 0, + u8array.length, + ); + u8array.length = numBytesWritten; + return u8array; + } + var TTY = { + ttys: [], + init: function () {}, + shutdown: function () {}, + register: function (dev, ops) { + TTY.ttys[dev] = { input: [], output: [], ops: ops }; + FS.registerDevice(dev, TTY.stream_ops); + }, + stream_ops: { + open: function (stream) { + var tty = TTY.ttys[stream.node.rdev]; + if (!tty) { + throw new FS.ErrnoError(43); + } + stream.tty = tty; + stream.seekable = false; + }, + close: function (stream) { + stream.tty.ops.fsync(stream.tty); + }, + fsync: function (stream) { + stream.tty.ops.fsync(stream.tty); + }, + read: function (stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.get_char) { + throw new FS.ErrnoError(60); + } + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = stream.tty.ops.get_char(stream.tty); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset + i] = result; + } + if (bytesRead) { + stream.node.timestamp = Date.now(); + } + return bytesRead; + }, + write: function (stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.put_char) { + throw new FS.ErrnoError(60); + } + try { + for (var i = 0; i < length; i++) { + stream.tty.ops.put_char(stream.tty, buffer[offset + i]); + } + } catch (e) { + throw new FS.ErrnoError(29); + } + if (length) { + stream.node.timestamp = Date.now(); + } + return i; + }, + }, + default_tty_ops: { + get_char: function (tty) { + if (!tty.input.length) { + var result = null; + if ( + typeof window != 'undefined' && + typeof window.prompt == 'function' + ) { + result = window.prompt('Input: '); + if (result !== null) { + result += '\n'; + } + } else if (typeof readline == 'function') { + result = readline(); + if (result !== null) { + result += '\n'; + } + } + if (!result) { + return null; + } + tty.input = intArrayFromString(result); + } + return tty.input.shift(); + }, + put_char: function (tty, val) { + if (val === null || val === 10) { + out(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync: function (tty) { + if (tty.output && tty.output.length > 0) { + out(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } + }, + }, + default_tty1_ops: { + put_char: function (tty, val) { + if (val === null || val === 10) { + err(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync: function (tty) { + if (tty.output && tty.output.length > 0) { + err(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } + }, + }, + }; - /** - * @param {number} pVfs - * @param {number} nBuf - * @param {number} zBuf - * @returns {number|Promise} - */ - xGetLastError(pVfs, nBuf, zBuf) { - const zBufArray = this._module.HEAPU8.subarray(zBuf, zBuf + nBuf); - this['log']?.('jGetLastError', nBuf); - return this.jGetLastError(zBufArray); - } + function zeroMemory(address, size) { + HEAPU8.fill(0, address, address + size); + return address; + } - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xClose(pFile) { - this['log']?.('jClose', pFile); - return this.jClose(pFile); - } + function alignMemory(size, alignment) { + return Math.ceil(size / alignment) * alignment; + } + function mmapAlloc(size) { + size = alignMemory(size, 65536); + var ptr = _emscripten_builtin_memalign(65536, size); + if (!ptr) return 0; + return zeroMemory(ptr, size); + } + var MEMFS = { + ops_table: null, + mount: function (mount) { + return MEMFS.createNode(null, '/', 16384 | 511, 0); + }, + createNode: function (parent, name, mode, dev) { + if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { + throw new FS.ErrnoError(63); + } + if (!MEMFS.ops_table) { + MEMFS.ops_table = { + dir: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + lookup: MEMFS.node_ops.lookup, + mknod: MEMFS.node_ops.mknod, + rename: MEMFS.node_ops.rename, + unlink: MEMFS.node_ops.unlink, + rmdir: MEMFS.node_ops.rmdir, + readdir: MEMFS.node_ops.readdir, + symlink: MEMFS.node_ops.symlink, + }, + stream: { + llseek: MEMFS.stream_ops.llseek, + }, + }, + file: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + }, + stream: { + llseek: MEMFS.stream_ops.llseek, + read: MEMFS.stream_ops.read, + write: MEMFS.stream_ops.write, + allocate: MEMFS.stream_ops.allocate, + mmap: MEMFS.stream_ops.mmap, + msync: MEMFS.stream_ops.msync, + }, + }, + link: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + readlink: MEMFS.node_ops.readlink, + }, + stream: {}, + }, + chrdev: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + }, + stream: FS.chrdev_stream_ops, + }, + }; + } + var node = FS.createNode(parent, name, mode, dev); + if (FS.isDir(node.mode)) { + node.node_ops = MEMFS.ops_table.dir.node; + node.stream_ops = MEMFS.ops_table.dir.stream; + node.contents = {}; + } else if (FS.isFile(node.mode)) { + node.node_ops = MEMFS.ops_table.file.node; + node.stream_ops = MEMFS.ops_table.file.stream; + node.usedBytes = 0; + + node.contents = null; + } else if (FS.isLink(node.mode)) { + node.node_ops = MEMFS.ops_table.link.node; + node.stream_ops = MEMFS.ops_table.link.stream; + } else if (FS.isChrdev(node.mode)) { + node.node_ops = MEMFS.ops_table.chrdev.node; + node.stream_ops = MEMFS.ops_table.chrdev.stream; + } + node.timestamp = Date.now(); - /** - * @param {number} pFile - * @param {number} pData - * @param {number} iAmt - * @param {number} iOffsetLo - * @param {number} iOffsetHi - * @returns {number|Promise} - */ - xRead(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { - const pDataArray = this.#makeDataArray(pData, iAmt); - const iOffset = delegalize(iOffsetLo, iOffsetHi); - this['log']?.('jRead', pFile, iAmt, iOffset); - return this.jRead(pFile, pDataArray, iOffset); - } + if (parent) { + parent.contents[name] = node; + parent.timestamp = node.timestamp; + } + return node; + }, + getFileDataAsTypedArray: function (node) { + if (!node.contents) return new Uint8Array(0); + if (node.contents.subarray) + return node.contents.subarray(0, node.usedBytes); + return new Uint8Array(node.contents); + }, + expandFileStorage: function (node, newCapacity) { + var prevCapacity = node.contents ? node.contents.length : 0; + if (prevCapacity >= newCapacity) return; + + var CAPACITY_DOUBLING_MAX = 1024 * 1024; + newCapacity = Math.max( + newCapacity, + (prevCapacity * + (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> + 0, + ); + if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); + var oldContents = node.contents; + node.contents = new Uint8Array(newCapacity); + if (node.usedBytes > 0) + node.contents.set(oldContents.subarray(0, node.usedBytes), 0); + }, + resizeFileStorage: function (node, newSize) { + if (node.usedBytes == newSize) return; + if (newSize == 0) { + node.contents = null; + node.usedBytes = 0; + } else { + var oldContents = node.contents; + node.contents = new Uint8Array(newSize); + if (oldContents) { + node.contents.set( + oldContents.subarray(0, Math.min(newSize, node.usedBytes)), + ); + } + node.usedBytes = newSize; + } + }, + node_ops: { + getattr: function (node) { + var attr = {}; + + attr.dev = FS.isChrdev(node.mode) ? node.id : 1; + attr.ino = node.id; + attr.mode = node.mode; + attr.nlink = 1; + attr.uid = 0; + attr.gid = 0; + attr.rdev = node.rdev; + if (FS.isDir(node.mode)) { + attr.size = 4096; + } else if (FS.isFile(node.mode)) { + attr.size = node.usedBytes; + } else if (FS.isLink(node.mode)) { + attr.size = node.link.length; + } else { + attr.size = 0; + } + attr.atime = new Date(node.timestamp); + attr.mtime = new Date(node.timestamp); + attr.ctime = new Date(node.timestamp); - /** - * @param {number} pFile - * @param {number} pData - * @param {number} iAmt - * @param {number} iOffsetLo - * @param {number} iOffsetHi - * @returns {number|Promise} - */ - xWrite(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { - const pDataArray = this.#makeDataArray(pData, iAmt); - const iOffset = delegalize(iOffsetLo, iOffsetHi); - this['log']?.('jWrite', pFile, pDataArray, iOffset); - return this.jWrite(pFile, pDataArray, iOffset); - } + attr.blksize = 4096; + attr.blocks = Math.ceil(attr.size / attr.blksize); + return attr; + }, + setattr: function (node, attr) { + if (attr.mode !== undefined) { + node.mode = attr.mode; + } + if (attr.timestamp !== undefined) { + node.timestamp = attr.timestamp; + } + if (attr.size !== undefined) { + MEMFS.resizeFileStorage(node, attr.size); + } + }, + lookup: function (parent, name) { + throw FS.genericErrors[44]; + }, + mknod: function (parent, name, mode, dev) { + return MEMFS.createNode(parent, name, mode, dev); + }, + rename: function (old_node, new_dir, new_name) { + if (FS.isDir(old_node.mode)) { + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + if (new_node) { + for (var i in new_node.contents) { + throw new FS.ErrnoError(55); + } + } + } - /** - * @param {number} pFile - * @param {number} sizeLo - * @param {number} sizeHi - * @returns {number|Promise} - */ - xTruncate(pFile, sizeLo, sizeHi) { - const size = delegalize(sizeLo, sizeHi); - this['log']?.('jTruncate', pFile, size); - return this.jTruncate(pFile, size); - } + delete old_node.parent.contents[old_node.name]; + old_node.parent.timestamp = Date.now(); + old_node.name = new_name; + new_dir.contents[new_name] = old_node; + new_dir.timestamp = old_node.parent.timestamp; + old_node.parent = new_dir; + }, + unlink: function (parent, name) { + delete parent.contents[name]; + parent.timestamp = Date.now(); + }, + rmdir: function (parent, name) { + var node = FS.lookupNode(parent, name); + for (var i in node.contents) { + throw new FS.ErrnoError(55); + } + delete parent.contents[name]; + parent.timestamp = Date.now(); + }, + readdir: function (node) { + var entries = ['.', '..']; + for (var key in node.contents) { + if (!node.contents.hasOwnProperty(key)) { + continue; + } + entries.push(key); + } + return entries; + }, + symlink: function (parent, newname, oldpath) { + var node = MEMFS.createNode(parent, newname, 511 | 40960, 0); + node.link = oldpath; + return node; + }, + readlink: function (node) { + if (!FS.isLink(node.mode)) { + throw new FS.ErrnoError(28); + } + return node.link; + }, + }, + stream_ops: { + read: function (stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= stream.node.usedBytes) return 0; + var size = Math.min(stream.node.usedBytes - position, length); + if (size > 8 && contents.subarray) { + buffer.set(contents.subarray(position, position + size), offset); + } else { + for (var i = 0; i < size; i++) + buffer[offset + i] = contents[position + i]; + } + return size; + }, + write: function (stream, buffer, offset, length, position, canOwn) { + if (buffer.buffer === HEAP8.buffer) { + canOwn = false; + } - /** - * @param {number} pFile - * @param {number} flags - * @returns {number|Promise} - */ - xSync(pFile, flags) { - this['log']?.('jSync', pFile, flags); - return this.jSync(pFile, flags); - } + if (!length) return 0; + var node = stream.node; + node.timestamp = Date.now(); + + if (buffer.subarray && (!node.contents || node.contents.subarray)) { + if (canOwn) { + node.contents = buffer.subarray(offset, offset + length); + node.usedBytes = length; + return length; + } else if (node.usedBytes === 0 && position === 0) { + node.contents = buffer.slice(offset, offset + length); + node.usedBytes = length; + return length; + } else if (position + length <= node.usedBytes) { + node.contents.set( + buffer.subarray(offset, offset + length), + position, + ); + return length; + } + } - /** - * - * @param {number} pFile - * @param {number} pSize - * @returns {number|Promise} - */ - xFileSize(pFile, pSize) { - const pSizeView = this.#makeTypedDataView('BigInt64', pSize); - this['log']?.('jFileSize', pFile); - return this.jFileSize(pFile, pSizeView); - } + MEMFS.expandFileStorage(node, position + length); + if (node.contents.subarray && buffer.subarray) { + node.contents.set( + buffer.subarray(offset, offset + length), + position, + ); + } else { + for (var i = 0; i < length; i++) { + node.contents[position + i] = buffer[offset + i]; + } + } + node.usedBytes = Math.max(node.usedBytes, position + length); + return length; + }, + llseek: function (stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + position += stream.node.usedBytes; + } + } + if (position < 0) { + throw new FS.ErrnoError(28); + } + return position; + }, + allocate: function (stream, offset, length) { + MEMFS.expandFileStorage(stream.node, offset + length); + stream.node.usedBytes = Math.max( + stream.node.usedBytes, + offset + length, + ); + }, + mmap: function (stream, length, position, prot, flags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + var ptr; + var allocated; + var contents = stream.node.contents; - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - xLock(pFile, lockType) { - this['log']?.('jLock', pFile, lockType); - return this.jLock(pFile, lockType); - } + if (!(flags & 2) && contents.buffer === HEAP8.buffer) { + allocated = false; + ptr = contents.byteOffset; + } else { + if (position > 0 || position + length < contents.length) { + if (contents.subarray) { + contents = contents.subarray(position, position + length); + } else { + contents = Array.prototype.slice.call( + contents, + position, + position + length, + ); + } + } + allocated = true; + ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + HEAP8.set(contents, ptr); + } + return { ptr: ptr, allocated: allocated }; + }, + msync: function (stream, buffer, offset, length, mmapFlags) { + MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false); - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - xUnlock(pFile, lockType) { - this['log']?.('jUnlock', pFile, lockType); - return this.jUnlock(pFile, lockType); - } - - /** - * @param {number} pFile - * @param {number} pResOut - * @returns {number|Promise} - */ - xCheckReservedLock(pFile, pResOut) { - const pResOutView = this.#makeTypedDataView('Int32', pResOut); - this['log']?.('jCheckReservedLock', pFile); - return this.jCheckReservedLock(pFile, pResOutView); - } + return 0; + }, + }, + }; - /** - * @param {number} pFile - * @param {number} op - * @param {number} pArg - * @returns {number|Promise} - */ - xFileControl(pFile, op, pArg) { - const pArgView = new DataView( - this._module.HEAPU8.buffer, - this._module.HEAPU8.byteOffset + pArg); - this['log']?.('jFileControl', pFile, op, pArgView); - return this.jFileControl(pFile, op, pArgView); - } + function asyncLoad(url, onload, onerror, noRunDep) { + var dep = getUniqueRunDependency('al ' + url) ; + readAsync( + url, + (arrayBuffer) => { + assert( + arrayBuffer, + 'Loading data file "' + url + '" failed (no arrayBuffer).', + ); + onload(new Uint8Array(arrayBuffer)); + if (dep) removeRunDependency(); + }, + (event) => { + if (onerror) { + onerror(); + } else { + throw 'Loading data file "' + url + '" failed.'; + } + }, + ); + if (dep) addRunDependency(); + } - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xSectorSize(pFile) { - this['log']?.('jSectorSize', pFile); - return this.jSectorSize(pFile); - } + var FS = { + root: null, + mounts: [], + devices: {}, + streams: [], + nextInode: 1, + nameTable: null, + currentPath: '/', + initialized: false, + ignorePermissions: true, + ErrnoError: null, + genericErrors: {}, + filesystems: null, + syncFSRequests: 0, + lookupPath: (path, opts = {}) => { + path = PATH_FS.resolve(path); + + if (!path) return { path: '', node: null }; + + var defaults = { + follow_mount: true, + recurse_count: 0, + }; + opts = Object.assign(defaults, opts); + + if (opts.recurse_count > 8) { + throw new FS.ErrnoError(32); + } - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xDeviceCharacteristics(pFile) { - this['log']?.('jDeviceCharacteristics', pFile); - return this.jDeviceCharacteristics(pFile); - } + var parts = path.split('/').filter((p) => !!p); - /** - * Wrapped DataView for pointer arguments. - * Pointers to a single value are passed using DataView. A Proxy - * wrapper prevents use of incorrect type or endianness. - * @param {'Int32'|'BigInt64'} type - * @param {number} byteOffset - * @returns {DataView} - */ - #makeTypedDataView(type, byteOffset) { - const byteLength = type === 'Int32' ? 4 : 8; - const getter = `get${type}`; - const setter = `set${type}`; - const makeDataView = () => new DataView( - this._module.HEAPU8.buffer, - this._module.HEAPU8.byteOffset + byteOffset, - byteLength); - let dataView = makeDataView(); - return new Proxy(dataView, { - get(_, prop) { - if (dataView.buffer.byteLength === 0) { - // WebAssembly memory resize detached the buffer. - dataView = makeDataView(); - } - if (prop === getter) { - return function(byteOffset, littleEndian) { - if (!littleEndian) throw new Error('must be little endian'); - return dataView[prop](byteOffset, littleEndian); - } - } - if (prop === setter) { - return function(byteOffset, value, littleEndian) { - if (!littleEndian) throw new Error('must be little endian'); - return dataView[prop](byteOffset, value, littleEndian); - } - } - if (typeof prop === 'string' && (prop.match(/^(get)|(set)/))) { - throw new Error('invalid type'); - } - const result = dataView[prop]; - return typeof result === 'function' ? result.bind(dataView) : result; - } - }); - } + var current = FS.root; + var current_path = '/'; + + for (var i = 0; i < parts.length; i++) { + var islast = i === parts.length - 1; + if (islast && opts.parent) { + break; + } + + current = FS.lookupNode(current, parts[i]); + current_path = PATH.join2(current_path, parts[i]); + + if (FS.isMountpoint(current)) { + if (!islast || (islast && opts.follow_mount)) { + current = current.mounted.root; + } + } + + if (!islast || opts.follow) { + var count = 0; + while (FS.isLink(current.mode)) { + var link = FS.readlink(current_path); + current_path = PATH_FS.resolve(PATH.dirname(current_path), link); + + var lookup = FS.lookupPath(current_path, { + recurse_count: opts.recurse_count + 1, + }); + current = lookup.node; - /** - * @param {number} byteOffset - * @param {number} byteLength - */ - #makeDataArray(byteOffset, byteLength) { - let target = this._module.HEAPU8.subarray(byteOffset, byteOffset + byteLength); - return new Proxy(target, { - get: (_, prop, receiver) => { - if (target.buffer.byteLength === 0) { - // WebAssembly memory resize detached the buffer. - target = this._module.HEAPU8.subarray(byteOffset, byteOffset + byteLength); + if (count++ > 40) { + throw new FS.ErrnoError(32); + } + } + } } - const result = target[prop]; - return typeof result === 'function' ? result.bind(target) : result; - } - }); - } - #decodeFilename(zName, flags) { - if (flags & SQLITE_OPEN_URI) { - // The first null-terminated string is the URI path. Subsequent - // strings are query parameter keys and values. - // https://www.sqlite.org/c3ref/open.html#urifilenamesinsqlite3open - let pName = zName; - let state = 1; - const charCodes = []; - while (state) { - const charCode = this._module.HEAPU8[pName++]; - if (charCode) { - charCodes.push(charCode); + return { path: current_path, node: current }; + }, + getPath: (node) => { + var path; + while (true) { + if (FS.isRoot(node)) { + var mount = node.mount.mountpoint; + if (!path) return mount; + return mount[mount.length - 1] !== '/' + ? mount + '/' + path + : mount + path; + } + path = path ? node.name + '/' + path : node.name; + node = node.parent; + } + }, + hashName: (parentid, name) => { + var hash = 0; + + for (var i = 0; i < name.length; i++) { + hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; + } + return ((parentid + hash) >>> 0) % FS.nameTable.length; + }, + hashAddNode: (node) => { + var hash = FS.hashName(node.parent.id, node.name); + node.name_next = FS.nameTable[hash]; + FS.nameTable[hash] = node; + }, + hashRemoveNode: (node) => { + var hash = FS.hashName(node.parent.id, node.name); + if (FS.nameTable[hash] === node) { + FS.nameTable[hash] = node.name_next; } else { - if (!this._module.HEAPU8[pName]) state = null; - switch (state) { - case 1: // path - charCodes.push('?'.charCodeAt(0)); - state = 2; - break; - case 2: // key - charCodes.push('='.charCodeAt(0)); - state = 3; - break; - case 3: // value - charCodes.push('&'.charCodeAt(0)); - state = 2; + var current = FS.nameTable[hash]; + while (current) { + if (current.name_next === node) { + current.name_next = node.name_next; break; + } + current = current.name_next; } } - } - return new TextDecoder().decode(new Uint8Array(charCodes)); - } - return zName ? this._module.UTF8ToString(zName) : null; - } -} + }, + lookupNode: (parent, name) => { + var errCode = FS.mayLookup(parent); + if (errCode) { + throw new FS.ErrnoError(errCode, parent); + } + var hash = FS.hashName(parent.id, name); + for (var node = FS.nameTable[hash]; node; node = node.name_next) { + var nodeName = node.name; + if (node.parent.id === parent.id && nodeName === name) { + return node; + } + } + + return FS.lookup(parent, name); + }, + createNode: (parent, name, mode, rdev) => { + var node = new FS.FSNode(parent, name, mode, rdev); + + FS.hashAddNode(node); + + return node; + }, + destroyNode: (node) => { + FS.hashRemoveNode(node); + }, + isRoot: (node) => { + return node === node.parent; + }, + isMountpoint: (node) => { + return !!node.mounted; + }, + isFile: (mode) => { + return (mode & 61440) === 32768; + }, + isDir: (mode) => { + return (mode & 61440) === 16384; + }, + isLink: (mode) => { + return (mode & 61440) === 40960; + }, + isChrdev: (mode) => { + return (mode & 61440) === 8192; + }, + isBlkdev: (mode) => { + return (mode & 61440) === 24576; + }, + isFIFO: (mode) => { + return (mode & 61440) === 4096; + }, + isSocket: (mode) => { + return (mode & 49152) === 49152; + }, + flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 }, + modeStringToFlags: (str) => { + var flags = FS.flagModes[str]; + if (typeof flags == 'undefined') { + throw new Error('Unknown file open mode: ' + str); + } + return flags; + }, + flagsToPermissionString: (flag) => { + var perms = ['r', 'w', 'rw'][flag & 3]; + if (flag & 512) { + perms += 'w'; + } + return perms; + }, + nodePermissions: (node, perms) => { + if (FS.ignorePermissions) { + return 0; + } + + if (perms.includes('r') && !(node.mode & 292)) { + return 2; + } else if (perms.includes('w') && !(node.mode & 146)) { + return 2; + } else if (perms.includes('x') && !(node.mode & 73)) { + return 2; + } + return 0; + }, + mayLookup: (dir) => { + var errCode = FS.nodePermissions(dir, 'x'); + if (errCode) return errCode; + if (!dir.node_ops.lookup) return 2; + return 0; + }, + mayCreate: (dir, name) => { + try { + var node = FS.lookupNode(dir, name); + return 20; + } catch (e) {} + return FS.nodePermissions(dir, 'wx'); + }, + mayDelete: (dir, name, isdir) => { + var node; + try { + node = FS.lookupNode(dir, name); + } catch (e) { + return e.errno; + } + var errCode = FS.nodePermissions(dir, 'wx'); + if (errCode) { + return errCode; + } + if (isdir) { + if (!FS.isDir(node.mode)) { + return 54; + } + if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { + return 10; + } + } else { + if (FS.isDir(node.mode)) { + return 31; + } + } + return 0; + }, + mayOpen: (node, flags) => { + if (!node) { + return 44; + } + if (FS.isLink(node.mode)) { + return 32; + } else if (FS.isDir(node.mode)) { + if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) { + return 31; + } + } + return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); + }, + MAX_OPEN_FDS: 4096, + nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => { + for (var fd = fd_start; fd <= fd_end; fd++) { + if (!FS.streams[fd]) { + return fd; + } + } + throw new FS.ErrnoError(33); + }, + getStream: (fd) => FS.streams[fd], + createStream: (stream, fd_start, fd_end) => { + if (!FS.FSStream) { + FS.FSStream = function () { + this.shared = {}; + }; + FS.FSStream.prototype = {}; + Object.defineProperties(FS.FSStream.prototype, { + object: { + get: function () { + return this.node; + }, + + set: function (val) { + this.node = val; + }, + }, + isRead: { + get: function () { + return (this.flags & 2097155) !== 1; + }, + }, + isWrite: { + get: function () { + return (this.flags & 2097155) !== 0; + }, + }, + isAppend: { + get: function () { + return this.flags & 1024; + }, + }, + flags: { + get: function () { + return this.shared.flags; + }, + + set: function (val) { + this.shared.flags = val; + }, + }, + position: { + get: function () { + return this.shared.position; + }, + + set: function (val) { + this.shared.position = val; + }, + }, + }); + } + + stream = Object.assign(new FS.FSStream(), stream); + var fd = FS.nextfd(fd_start, fd_end); + stream.fd = fd; + FS.streams[fd] = stream; + return stream; + }, + closeStream: (fd) => { + FS.streams[fd] = null; + }, + chrdev_stream_ops: { + open: (stream) => { + var device = FS.getDevice(stream.node.rdev); + + stream.stream_ops = device.stream_ops; + + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + }, + llseek: () => { + throw new FS.ErrnoError(70); + }, + }, + major: (dev) => dev >> 8, + minor: (dev) => dev & 0xff, + makedev: (ma, mi) => (ma << 8) | mi, + registerDevice: (dev, ops) => { + FS.devices[dev] = { stream_ops: ops }; + }, + getDevice: (dev) => FS.devices[dev], + getMounts: (mount) => { + var mounts = []; + var check = [mount]; + + while (check.length) { + var m = check.pop(); + + mounts.push(m); + + check.push.apply(check, m.mounts); + } + + return mounts; + }, + syncfs: (populate, callback) => { + if (typeof populate == 'function') { + callback = populate; + populate = false; + } + + FS.syncFSRequests++; + + if (FS.syncFSRequests > 1) { + err( + 'warning: ' + + FS.syncFSRequests + + ' FS.syncfs operations in flight at once, probably just doing extra work', + ); + } + + var mounts = FS.getMounts(FS.root.mount); + var completed = 0; + + function doCallback(errCode) { + FS.syncFSRequests--; + return callback(errCode); + } + + function done(errCode) { + if (errCode) { + if (!done.errored) { + done.errored = true; + return doCallback(errCode); + } + return; + } + if (++completed >= mounts.length) { + doCallback(null); + } + } + + mounts.forEach((mount) => { + if (!mount.type.syncfs) { + return done(null); + } + mount.type.syncfs(mount, populate, done); + }); + }, + mount: (type, opts, mountpoint) => { + var root = mountpoint === '/'; + var pseudo = !mountpoint; + var node; + + if (root && FS.root) { + throw new FS.ErrnoError(10); + } else if (!root && !pseudo) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + + mountpoint = lookup.path; + node = lookup.node; + + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + + if (!FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + } + + var mount = { + type: type, + opts: opts, + mountpoint: mountpoint, + mounts: [], + }; + + var mountRoot = type.mount(mount); + mountRoot.mount = mount; + mount.root = mountRoot; + + if (root) { + FS.root = mountRoot; + } else if (node) { + node.mounted = mount; + + if (node.mount) { + node.mount.mounts.push(mount); + } + } + + return mountRoot; + }, + unmount: (mountpoint) => { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + + if (!FS.isMountpoint(lookup.node)) { + throw new FS.ErrnoError(28); + } + + var node = lookup.node; + var mount = node.mounted; + var mounts = FS.getMounts(mount); + + Object.keys(FS.nameTable).forEach((hash) => { + var current = FS.nameTable[hash]; + + while (current) { + var next = current.name_next; + + if (mounts.includes(current.mount)) { + FS.destroyNode(current); + } + + current = next; + } + }); + + node.mounted = null; + + var idx = node.mount.mounts.indexOf(mount); + node.mount.mounts.splice(idx, 1); + }, + lookup: (parent, name) => { + return parent.node_ops.lookup(parent, name); + }, + mknod: (path, mode, dev) => { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name = PATH.basename(path); + if (!name || name === '.' || name === '..') { + throw new FS.ErrnoError(28); + } + var errCode = FS.mayCreate(parent, name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.mknod) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.mknod(parent, name, mode, dev); + }, + create: (path, mode) => { + mode = mode !== undefined ? mode : 438; + mode &= 4095; + mode |= 32768; + return FS.mknod(path, mode, 0); + }, + mkdir: (path, mode) => { + mode = mode !== undefined ? mode : 511; + mode &= 511 | 512; + mode |= 16384; + return FS.mknod(path, mode, 0); + }, + mkdirTree: (path, mode) => { + var dirs = path.split('/'); + var d = ''; + for (var i = 0; i < dirs.length; ++i) { + if (!dirs[i]) continue; + d += '/' + dirs[i]; + try { + FS.mkdir(d, mode); + } catch (e) { + if (e.errno != 20) throw e; + } + } + }, + mkdev: (path, mode, dev) => { + if (typeof dev == 'undefined') { + dev = mode; + mode = 438; + } + mode |= 8192; + return FS.mknod(path, mode, dev); + }, + symlink: (oldpath, newpath) => { + if (!PATH_FS.resolve(oldpath)) { + throw new FS.ErrnoError(44); + } + var lookup = FS.lookupPath(newpath, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var newname = PATH.basename(newpath); + var errCode = FS.mayCreate(parent, newname); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.symlink) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.symlink(parent, newname, oldpath); + }, + rename: (old_path, new_path) => { + var old_dirname = PATH.dirname(old_path); + var new_dirname = PATH.dirname(new_path); + var old_name = PATH.basename(old_path); + var new_name = PATH.basename(new_path); + + var lookup, old_dir, new_dir; + + lookup = FS.lookupPath(old_path, { parent: true }); + old_dir = lookup.node; + lookup = FS.lookupPath(new_path, { parent: true }); + new_dir = lookup.node; + + if (!old_dir || !new_dir) throw new FS.ErrnoError(44); + + if (old_dir.mount !== new_dir.mount) { + throw new FS.ErrnoError(75); + } + + var old_node = FS.lookupNode(old_dir, old_name); + + var relative = PATH_FS.relative(old_path, new_dirname); + if (relative.charAt(0) !== '.') { + throw new FS.ErrnoError(28); + } + + relative = PATH_FS.relative(new_path, old_dirname); + if (relative.charAt(0) !== '.') { + throw new FS.ErrnoError(55); + } + + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + + if (old_node === new_node) { + return; + } + + var isdir = FS.isDir(old_node.mode); + var errCode = FS.mayDelete(old_dir, old_name, isdir); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + + errCode = new_node + ? FS.mayDelete(new_dir, new_name, isdir) + : FS.mayCreate(new_dir, new_name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!old_dir.node_ops.rename) { + throw new FS.ErrnoError(63); + } + if ( + FS.isMountpoint(old_node) || + (new_node && FS.isMountpoint(new_node)) + ) { + throw new FS.ErrnoError(10); + } + + if (new_dir !== old_dir) { + errCode = FS.nodePermissions(old_dir, 'w'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + + FS.hashRemoveNode(old_node); + + try { + old_dir.node_ops.rename(old_node, new_dir, new_name); + } catch (e) { + throw e; + } finally { + FS.hashAddNode(old_node); + } + }, + rmdir: (path) => { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, true); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.rmdir) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.rmdir(parent, name); + FS.destroyNode(node); + }, + readdir: (path) => { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + if (!node.node_ops.readdir) { + throw new FS.ErrnoError(54); + } + return node.node_ops.readdir(node); + }, + unlink: (path) => { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, false); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.unlink) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.unlink(parent, name); + FS.destroyNode(node); + }, + readlink: (path) => { + var lookup = FS.lookupPath(path); + var link = lookup.node; + if (!link) { + throw new FS.ErrnoError(44); + } + if (!link.node_ops.readlink) { + throw new FS.ErrnoError(28); + } + return PATH_FS.resolve( + FS.getPath(link.parent), + link.node_ops.readlink(link), + ); + }, + stat: (path, dontFollow) => { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + var node = lookup.node; + if (!node) { + throw new FS.ErrnoError(44); + } + if (!node.node_ops.getattr) { + throw new FS.ErrnoError(63); + } + return node.node_ops.getattr(node); + }, + lstat: (path) => { + return FS.stat(path, true); + }, + chmod: (path, mode, dontFollow) => { + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + node.node_ops.setattr(node, { + mode: (mode & 4095) | (node.mode & ~4095), + timestamp: Date.now(), + }); + }, + lchmod: (path, mode) => { + FS.chmod(path, mode, true); + }, + fchmod: (fd, mode) => { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + FS.chmod(stream.node, mode); + }, + chown: (path, uid, gid, dontFollow) => { + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + node.node_ops.setattr(node, { + timestamp: Date.now(), + }); + }, + lchown: (path, uid, gid) => { + FS.chown(path, uid, gid, true); + }, + fchown: (fd, uid, gid) => { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + FS.chown(stream.node, uid, gid); + }, + truncate: (path, len) => { + if (len < 0) { + throw new FS.ErrnoError(28); + } + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: true }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + if (FS.isDir(node.mode)) { + throw new FS.ErrnoError(31); + } + if (!FS.isFile(node.mode)) { + throw new FS.ErrnoError(28); + } + var errCode = FS.nodePermissions(node, 'w'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + node.node_ops.setattr(node, { + size: len, + timestamp: Date.now(), + }); + }, + ftruncate: (fd, len) => { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(28); + } + FS.truncate(stream.node, len); + }, + utime: (path, atime, mtime) => { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + node.node_ops.setattr(node, { + timestamp: Math.max(atime, mtime), + }); + }, + open: (path, flags, mode) => { + if (path === '') { + throw new FS.ErrnoError(44); + } + flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; + mode = typeof mode == 'undefined' ? 438 : mode; + if (flags & 64) { + mode = (mode & 4095) | 32768; + } else { + mode = 0; + } + var node; + if (typeof path == 'object') { + node = path; + } else { + path = PATH.normalize(path); + try { + var lookup = FS.lookupPath(path, { + follow: !(flags & 131072), + }); + node = lookup.node; + } catch (e) {} + } + + var created = false; + if (flags & 64) { + if (node) { + if (flags & 128) { + throw new FS.ErrnoError(20); + } + } else { + node = FS.mknod(path, mode, 0); + created = true; + } + } + if (!node) { + throw new FS.ErrnoError(44); + } + + if (FS.isChrdev(node.mode)) { + flags &= ~512; + } + + if (flags & 65536 && !FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + + if (!created) { + var errCode = FS.mayOpen(node, flags); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + + if (flags & 512 && !created) { + FS.truncate(node, 0); + } + + flags &= ~(128 | 512 | 131072); + + var stream = FS.createStream({ + node: node, + path: FS.getPath(node), + flags: flags, + seekable: true, + position: 0, + stream_ops: node.stream_ops, + + ungotten: [], + error: false, + }); + + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + if (Module['logReadFiles'] && !(flags & 1)) { + if (!FS.readFiles) FS.readFiles = {}; + if (!(path in FS.readFiles)) { + FS.readFiles[path] = 1; + } + } + return stream; + }, + close: (stream) => { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (stream.getdents) stream.getdents = null; + try { + if (stream.stream_ops.close) { + stream.stream_ops.close(stream); + } + } catch (e) { + throw e; + } finally { + FS.closeStream(stream.fd); + } + stream.fd = null; + }, + isClosed: (stream) => { + return stream.fd === null; + }, + llseek: (stream, offset, whence) => { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (!stream.seekable || !stream.stream_ops.llseek) { + throw new FS.ErrnoError(70); + } + if (whence != 0 && whence != 1 && whence != 2) { + throw new FS.ErrnoError(28); + } + stream.position = stream.stream_ops.llseek(stream, offset, whence); + stream.ungotten = []; + return stream.position; + }, + read: (stream, buffer, offset, length, position) => { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.read) { + throw new FS.ErrnoError(28); + } + var seeking = typeof position != 'undefined'; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesRead = stream.stream_ops.read( + stream, + buffer, + offset, + length, + position, + ); + if (!seeking) stream.position += bytesRead; + return bytesRead; + }, + write: (stream, buffer, offset, length, position, canOwn) => { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.write) { + throw new FS.ErrnoError(28); + } + if (stream.seekable && stream.flags & 1024) { + FS.llseek(stream, 0, 2); + } + var seeking = typeof position != 'undefined'; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesWritten = stream.stream_ops.write( + stream, + buffer, + offset, + length, + position, + canOwn, + ); + if (!seeking) stream.position += bytesWritten; + return bytesWritten; + }, + allocate: (stream, offset, length) => { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (offset < 0 || length <= 0) { + throw new FS.ErrnoError(28); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (!stream.stream_ops.allocate) { + throw new FS.ErrnoError(138); + } + stream.stream_ops.allocate(stream, offset, length); + }, + mmap: (stream, length, position, prot, flags) => { + if ( + (prot & 2) !== 0 && + (flags & 2) === 0 && + (stream.flags & 2097155) !== 2 + ) { + throw new FS.ErrnoError(2); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(2); + } + if (!stream.stream_ops.mmap) { + throw new FS.ErrnoError(43); + } + return stream.stream_ops.mmap(stream, length, position, prot, flags); + }, + msync: (stream, buffer, offset, length, mmapFlags) => { + if (!stream.stream_ops.msync) { + return 0; + } + return stream.stream_ops.msync( + stream, + buffer, + offset, + length, + mmapFlags, + ); + }, + munmap: (stream) => 0, + ioctl: (stream, cmd, arg) => { + if (!stream.stream_ops.ioctl) { + throw new FS.ErrnoError(59); + } + return stream.stream_ops.ioctl(stream, cmd, arg); + }, + readFile: (path, opts = {}) => { + opts.flags = opts.flags || 0; + opts.encoding = opts.encoding || 'binary'; + if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { + throw new Error('Invalid encoding type "' + opts.encoding + '"'); + } + var ret; + var stream = FS.open(path, opts.flags); + var stat = FS.stat(path); + var length = stat.size; + var buf = new Uint8Array(length); + FS.read(stream, buf, 0, length, 0); + if (opts.encoding === 'utf8') { + ret = UTF8ArrayToString(buf, 0); + } else if (opts.encoding === 'binary') { + ret = buf; + } + FS.close(stream); + return ret; + }, + writeFile: (path, data, opts = {}) => { + opts.flags = opts.flags || 577; + var stream = FS.open(path, opts.flags, opts.mode); + if (typeof data == 'string') { + var buf = new Uint8Array(lengthBytesUTF8(data) + 1); + var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); + FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn); + } else if (ArrayBuffer.isView(data)) { + FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); + } else { + throw new Error('Unsupported data type'); + } + FS.close(stream); + }, + cwd: () => FS.currentPath, + chdir: (path) => { + var lookup = FS.lookupPath(path, { follow: true }); + if (lookup.node === null) { + throw new FS.ErrnoError(44); + } + if (!FS.isDir(lookup.node.mode)) { + throw new FS.ErrnoError(54); + } + var errCode = FS.nodePermissions(lookup.node, 'x'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.currentPath = lookup.path; + }, + createDefaultDirectories: () => { + FS.mkdir('/tmp'); + FS.mkdir('/home'); + FS.mkdir('/home/web_user'); + }, + createDefaultDevices: () => { + FS.mkdir('/dev'); + + FS.registerDevice(FS.makedev(1, 3), { + read: () => 0, + write: (stream, buffer, offset, length, pos) => length, + }); + FS.mkdev('/dev/null', FS.makedev(1, 3)); + + TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); + TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); + FS.mkdev('/dev/tty', FS.makedev(5, 0)); + FS.mkdev('/dev/tty1', FS.makedev(6, 0)); + + var random_device = getRandomDevice(); + FS.createDevice('/dev', 'random', random_device); + FS.createDevice('/dev', 'urandom', random_device); + + FS.mkdir('/dev/shm'); + FS.mkdir('/dev/shm/tmp'); + }, + createSpecialDirectories: () => { + FS.mkdir('/proc'); + var proc_self = FS.mkdir('/proc/self'); + FS.mkdir('/proc/self/fd'); + FS.mount( + { + mount: () => { + var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73); + node.node_ops = { + lookup: (parent, name) => { + var fd = +name; + var stream = FS.getStream(fd); + if (!stream) throw new FS.ErrnoError(8); + var ret = { + parent: null, + mount: { mountpoint: 'fake' }, + node_ops: { readlink: () => stream.path }, + }; + ret.parent = ret; + return ret; + }, + }; + return node; + }, + }, + {}, + '/proc/self/fd', + ); + }, + createStandardStreams: () => { + if (Module['stdin']) { + FS.createDevice('/dev', 'stdin', Module['stdin']); + } else { + FS.symlink('/dev/tty', '/dev/stdin'); + } + if (Module['stdout']) { + FS.createDevice('/dev', 'stdout', null, Module['stdout']); + } else { + FS.symlink('/dev/tty', '/dev/stdout'); + } + if (Module['stderr']) { + FS.createDevice('/dev', 'stderr', null, Module['stderr']); + } else { + FS.symlink('/dev/tty1', '/dev/stderr'); + } + + FS.open('/dev/stdin', 0); + FS.open('/dev/stdout', 1); + FS.open('/dev/stderr', 1); + }, + ensureErrnoError: () => { + if (FS.ErrnoError) return; + FS.ErrnoError = function ErrnoError(errno, node) { + this.node = node; + this.setErrno = function (errno) { + this.errno = errno; + }; + this.setErrno(errno); + this.message = 'FS error'; + }; + FS.ErrnoError.prototype = new Error(); + FS.ErrnoError.prototype.constructor = FS.ErrnoError; + + [44].forEach((code) => { + FS.genericErrors[code] = new FS.ErrnoError(code); + FS.genericErrors[code].stack = ''; + }); + }, + staticInit: () => { + FS.ensureErrnoError(); + + FS.nameTable = new Array(4096); + + FS.mount(MEMFS, {}, '/'); + + FS.createDefaultDirectories(); + FS.createDefaultDevices(); + FS.createSpecialDirectories(); + + FS.filesystems = { + MEMFS: MEMFS, + }; + }, + init: (input, output, error) => { + FS.init.initialized = true; + + FS.ensureErrnoError(); + + Module['stdin'] = input || Module['stdin']; + Module['stdout'] = output || Module['stdout']; + Module['stderr'] = error || Module['stderr']; + + FS.createStandardStreams(); + }, + quit: () => { + FS.init.initialized = false; + + for (var i = 0; i < FS.streams.length; i++) { + var stream = FS.streams[i]; + if (!stream) { + continue; + } + FS.close(stream); + } + }, + getMode: (canRead, canWrite) => { + var mode = 0; + if (canRead) mode |= 292 | 73; + if (canWrite) mode |= 146; + return mode; + }, + findObject: (path, dontResolveLastLink) => { + var ret = FS.analyzePath(path, dontResolveLastLink); + if (!ret.exists) { + return null; + } + return ret.object; + }, + analyzePath: (path, dontResolveLastLink) => { + try { + var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + path = lookup.path; + } catch (e) {} + var ret = { + isRoot: false, + exists: false, + error: 0, + name: null, + path: null, + object: null, + parentExists: false, + parentPath: null, + parentObject: null, + }; + try { + var lookup = FS.lookupPath(path, { parent: true }); + ret.parentExists = true; + ret.parentPath = lookup.path; + ret.parentObject = lookup.node; + ret.name = PATH.basename(path); + lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + ret.exists = true; + ret.path = lookup.path; + ret.object = lookup.node; + ret.name = lookup.node.name; + ret.isRoot = lookup.path === '/'; + } catch (e) { + ret.error = e.errno; + } + return ret; + }, + createPath: (parent, path, canRead, canWrite) => { + parent = typeof parent == 'string' ? parent : FS.getPath(parent); + var parts = path.split('/').reverse(); + while (parts.length) { + var part = parts.pop(); + if (!part) continue; + var current = PATH.join2(parent, part); + try { + FS.mkdir(current); + } catch (e) {} + parent = current; + } + return current; + }, + createFile: (parent, name, properties, canRead, canWrite) => { + var path = PATH.join2( + typeof parent == 'string' ? parent : FS.getPath(parent), + name, + ); + var mode = FS.getMode(canRead, canWrite); + return FS.create(path, mode); + }, + createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { + var path = name; + if (parent) { + parent = typeof parent == 'string' ? parent : FS.getPath(parent); + path = name ? PATH.join2(parent, name) : parent; + } + var mode = FS.getMode(canRead, canWrite); + var node = FS.create(path, mode); + if (data) { + if (typeof data == 'string') { + var arr = new Array(data.length); + for (var i = 0, len = data.length; i < len; ++i) + arr[i] = data.charCodeAt(i); + data = arr; + } + + FS.chmod(node, mode | 146); + var stream = FS.open(node, 577); + FS.write(stream, data, 0, data.length, 0, canOwn); + FS.close(stream); + FS.chmod(node, mode); + } + return node; + }, + createDevice: (parent, name, input, output) => { + var path = PATH.join2( + typeof parent == 'string' ? parent : FS.getPath(parent), + name, + ); + var mode = FS.getMode(!!input, !!output); + if (!FS.createDevice.major) FS.createDevice.major = 64; + var dev = FS.makedev(FS.createDevice.major++, 0); + + FS.registerDevice(dev, { + open: (stream) => { + stream.seekable = false; + }, + close: (stream) => { + if (output && output.buffer && output.buffer.length) { + output(10); + } + }, + read: (stream, buffer, offset, length, pos) => { + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = input(); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset + i] = result; + } + if (bytesRead) { + stream.node.timestamp = Date.now(); + } + return bytesRead; + }, + write: (stream, buffer, offset, length, pos) => { + for (var i = 0; i < length; i++) { + try { + output(buffer[offset + i]); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + if (length) { + stream.node.timestamp = Date.now(); + } + return i; + }, + }); + return FS.mkdev(path, mode, dev); + }, + forceLoadFile: (obj) => { + if (obj.isDevice || obj.isFolder || obj.link || obj.contents) + return true; + if (typeof XMLHttpRequest != 'undefined') { + throw new Error( + 'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.', + ); + } else if (read_) { + try { + obj.contents = intArrayFromString(read_(obj.url), true); + obj.usedBytes = obj.contents.length; + } catch (e) { + throw new FS.ErrnoError(29); + } + } else { + throw new Error('Cannot load without read() or XMLHttpRequest.'); + } + }, + createLazyFile: (parent, name, url, canRead, canWrite) => { + function LazyUint8Array() { + this.lengthKnown = false; + this.chunks = []; + } + LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) { + if (idx > this.length - 1 || idx < 0) { + return undefined; + } + var chunkOffset = idx % this.chunkSize; + var chunkNum = (idx / this.chunkSize) | 0; + return this.getter(chunkNum)[chunkOffset]; + }; + LazyUint8Array.prototype.setDataGetter = + function LazyUint8Array_setDataGetter(getter) { + this.getter = getter; + }; + LazyUint8Array.prototype.cacheLength = + function LazyUint8Array_cacheLength() { + var xhr = new XMLHttpRequest(); + xhr.open('HEAD', url, false); + xhr.send(null); + if ( + !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) + ) + throw new Error( + "Couldn't load " + url + '. Status: ' + xhr.status, + ); + var datalength = Number(xhr.getResponseHeader('Content-length')); + var header; + var hasByteServing = + (header = xhr.getResponseHeader('Accept-Ranges')) && + header === 'bytes'; + var usesGzip = + (header = xhr.getResponseHeader('Content-Encoding')) && + header === 'gzip'; + + var chunkSize = 1024 * 1024; + + if (!hasByteServing) chunkSize = datalength; + + var doXHR = (from, to) => { + if (from > to) + throw new Error( + 'invalid range (' + + from + + ', ' + + to + + ') or no bytes requested!', + ); + if (to > datalength - 1) + throw new Error( + 'only ' + datalength + ' bytes available! programmer error!', + ); + + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + if (datalength !== chunkSize) + xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to); + + xhr.responseType = 'arraybuffer'; + if (xhr.overrideMimeType) { + xhr.overrideMimeType('text/plain; charset=x-user-defined'); + } + + xhr.send(null); + if ( + !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) + ) + throw new Error( + "Couldn't load " + url + '. Status: ' + xhr.status, + ); + if (xhr.response !== undefined) { + return new Uint8Array(xhr.response || []); + } + return intArrayFromString(xhr.responseText || ''); + }; + var lazyArray = this; + lazyArray.setDataGetter((chunkNum) => { + var start = chunkNum * chunkSize; + var end = (chunkNum + 1) * chunkSize - 1; + end = Math.min(end, datalength - 1); + if (typeof lazyArray.chunks[chunkNum] == 'undefined') { + lazyArray.chunks[chunkNum] = doXHR(start, end); + } + if (typeof lazyArray.chunks[chunkNum] == 'undefined') + throw new Error('doXHR failed!'); + return lazyArray.chunks[chunkNum]; + }); + + if (usesGzip || !datalength) { + chunkSize = datalength = 1; + datalength = this.getter(0).length; + chunkSize = datalength; + out( + 'LazyFiles on gzip forces download of the whole file when length is accessed', + ); + } + + this._length = datalength; + this._chunkSize = chunkSize; + this.lengthKnown = true; + }; + if (typeof XMLHttpRequest != 'undefined') { + if (!ENVIRONMENT_IS_WORKER) + throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; + var lazyArray = new LazyUint8Array(); + Object.defineProperties(lazyArray, { + length: { + get: function () { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._length; + }, + }, + chunkSize: { + get: function () { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._chunkSize; + }, + }, + }); + + var properties = { isDevice: false, contents: lazyArray }; + } else { + var properties = { isDevice: false, url: url }; + } + + var node = FS.createFile(parent, name, properties, canRead, canWrite); + + if (properties.contents) { + node.contents = properties.contents; + } else if (properties.url) { + node.contents = null; + node.url = properties.url; + } + + Object.defineProperties(node, { + usedBytes: { + get: function () { + return this.contents.length; + }, + }, + }); + + var stream_ops = {}; + var keys = Object.keys(node.stream_ops); + keys.forEach((key) => { + var fn = node.stream_ops[key]; + stream_ops[key] = function forceLoadLazyFile() { + FS.forceLoadFile(node); + return fn.apply(null, arguments); + }; + }); + function writeChunks(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= contents.length) return 0; + var size = Math.min(contents.length - position, length); + if (contents.slice) { + for (var i = 0; i < size; i++) { + buffer[offset + i] = contents[position + i]; + } + } else { + for (var i = 0; i < size; i++) { + buffer[offset + i] = contents.get(position + i); + } + } + return size; + } + + stream_ops.read = (stream, buffer, offset, length, position) => { + FS.forceLoadFile(node); + return writeChunks(stream, buffer, offset, length, position); + }; + + stream_ops.mmap = (stream, length, position, prot, flags) => { + FS.forceLoadFile(node); + var ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + writeChunks(stream, HEAP8, ptr, length, position); + return { ptr: ptr, allocated: true }; + }; + node.stream_ops = stream_ops; + return node; + }, + createPreloadedFile: ( + parent, + name, + url, + canRead, + canWrite, + onload, + onerror, + dontCreateFile, + canOwn, + preFinish, + ) => { + var fullname = name + ? PATH_FS.resolve(PATH.join2(parent, name)) + : parent; + function processData(byteArray) { + function finish(byteArray) { + if (preFinish) preFinish(); + if (!dontCreateFile) { + FS.createDataFile( + parent, + name, + byteArray, + canRead, + canWrite, + canOwn, + ); + } + if (onload) onload(); + removeRunDependency(); + } + if ( + Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => { + if (onerror) onerror(); + removeRunDependency(); + }) + ) { + return; + } + finish(byteArray); + } + addRunDependency(); + if (typeof url == 'string') { + asyncLoad(url, (byteArray) => processData(byteArray), onerror); + } else { + processData(url); + } + }, + indexedDB: () => { + return ( + window.indexedDB || + window.mozIndexedDB || + window.webkitIndexedDB || + window.msIndexedDB + ); + }, + DB_NAME: () => { + return 'EM_FS_' + window.location.pathname; + }, + DB_VERSION: 20, + DB_STORE_NAME: 'FILE_DATA', + saveFilesToDB: (paths, onload, onerror) => { + onload = onload || (() => {}); + onerror = onerror || (() => {}); + var indexedDB = FS.indexedDB(); + try { + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); + } catch (e) { + return onerror(e); + } + openRequest.onupgradeneeded = () => { + out('creating db'); + var db = openRequest.result; + db.createObjectStore(FS.DB_STORE_NAME); + }; + openRequest.onsuccess = () => { + var db = openRequest.result; + var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite'); + var files = transaction.objectStore(FS.DB_STORE_NAME); + var ok = 0, + fail = 0, + total = paths.length; + function finish() { + if (fail == 0) onload(); + else onerror(); + } + paths.forEach((path) => { + var putRequest = files.put( + FS.analyzePath(path).object.contents, + path, + ); + putRequest.onsuccess = () => { + ok++; + if (ok + fail == total) finish(); + }; + putRequest.onerror = () => { + fail++; + if (ok + fail == total) finish(); + }; + }); + transaction.onerror = onerror; + }; + openRequest.onerror = onerror; + }, + loadFilesFromDB: (paths, onload, onerror) => { + onload = onload || (() => {}); + onerror = onerror || (() => {}); + var indexedDB = FS.indexedDB(); + try { + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); + } catch (e) { + return onerror(e); + } + openRequest.onupgradeneeded = onerror; + openRequest.onsuccess = () => { + var db = openRequest.result; + try { + var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly'); + } catch (e) { + onerror(e); + return; + } + var files = transaction.objectStore(FS.DB_STORE_NAME); + var ok = 0, + fail = 0, + total = paths.length; + function finish() { + if (fail == 0) onload(); + else onerror(); + } + paths.forEach((path) => { + var getRequest = files.get(path); + getRequest.onsuccess = () => { + if (FS.analyzePath(path).exists) { + FS.unlink(path); + } + FS.createDataFile( + PATH.dirname(path), + PATH.basename(path), + getRequest.result, + true, + true, + true, + ); + ok++; + if (ok + fail == total) finish(); + }; + getRequest.onerror = () => { + fail++; + if (ok + fail == total) finish(); + }; + }); + transaction.onerror = onerror; + }; + openRequest.onerror = onerror; + }, + }; + var SYSCALLS = { + DEFAULT_POLLMASK: 5, + calculateAt: function (dirfd, path, allowEmpty) { + if (PATH.isAbs(path)) { + return path; + } + + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = SYSCALLS.getStreamFromFD(dirfd); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44); + } + return dir; + } + return PATH.join2(dir, path); + }, + doStat: function (func, path, buf) { + try { + var stat = func(path); + } catch (e) { + if ( + e && + e.node && + PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node)) + ) { + return -54; + } + throw e; + } + HEAP32[buf >> 2] = stat.dev; + HEAP32[(buf + 8) >> 2] = stat.ino; + HEAP32[(buf + 12) >> 2] = stat.mode; + HEAPU32[(buf + 16) >> 2] = stat.nlink; + HEAP32[(buf + 20) >> 2] = stat.uid; + HEAP32[(buf + 24) >> 2] = stat.gid; + HEAP32[(buf + 28) >> 2] = stat.rdev; + (tempI64 = [ + stat.size >>> 0, + ((tempDouble = stat.size), + +Math.abs(tempDouble) >= 1.0 + ? tempDouble > 0.0 + ? (Math.min( + +Math.floor(tempDouble / 4294967296.0), + 4294967295.0, + ) | + 0) >>> + 0 + : ~~+Math.ceil( + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + ) >>> 0 + : 0), + ]), + (HEAP32[(buf + 40) >> 2] = tempI64[0]), + (HEAP32[(buf + 44) >> 2] = tempI64[1]); + HEAP32[(buf + 48) >> 2] = 4096; + HEAP32[(buf + 52) >> 2] = stat.blocks; + var atime = stat.atime.getTime(); + var mtime = stat.mtime.getTime(); + var ctime = stat.ctime.getTime(); + (tempI64 = [ + Math.floor(atime / 1000) >>> 0, + ((tempDouble = Math.floor(atime / 1000)), + +Math.abs(tempDouble) >= 1.0 + ? tempDouble > 0.0 + ? (Math.min( + +Math.floor(tempDouble / 4294967296.0), + 4294967295.0, + ) | + 0) >>> + 0 + : ~~+Math.ceil( + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + ) >>> 0 + : 0), + ]), + (HEAP32[(buf + 56) >> 2] = tempI64[0]), + (HEAP32[(buf + 60) >> 2] = tempI64[1]); + HEAPU32[(buf + 64) >> 2] = (atime % 1000) * 1000; + (tempI64 = [ + Math.floor(mtime / 1000) >>> 0, + ((tempDouble = Math.floor(mtime / 1000)), + +Math.abs(tempDouble) >= 1.0 + ? tempDouble > 0.0 + ? (Math.min( + +Math.floor(tempDouble / 4294967296.0), + 4294967295.0, + ) | + 0) >>> + 0 + : ~~+Math.ceil( + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + ) >>> 0 + : 0), + ]), + (HEAP32[(buf + 72) >> 2] = tempI64[0]), + (HEAP32[(buf + 76) >> 2] = tempI64[1]); + HEAPU32[(buf + 80) >> 2] = (mtime % 1000) * 1000; + (tempI64 = [ + Math.floor(ctime / 1000) >>> 0, + ((tempDouble = Math.floor(ctime / 1000)), + +Math.abs(tempDouble) >= 1.0 + ? tempDouble > 0.0 + ? (Math.min( + +Math.floor(tempDouble / 4294967296.0), + 4294967295.0, + ) | + 0) >>> + 0 + : ~~+Math.ceil( + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + ) >>> 0 + : 0), + ]), + (HEAP32[(buf + 88) >> 2] = tempI64[0]), + (HEAP32[(buf + 92) >> 2] = tempI64[1]); + HEAPU32[(buf + 96) >> 2] = (ctime % 1000) * 1000; + (tempI64 = [ + stat.ino >>> 0, + ((tempDouble = stat.ino), + +Math.abs(tempDouble) >= 1.0 + ? tempDouble > 0.0 + ? (Math.min( + +Math.floor(tempDouble / 4294967296.0), + 4294967295.0, + ) | + 0) >>> + 0 + : ~~+Math.ceil( + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + ) >>> 0 + : 0), + ]), + (HEAP32[(buf + 104) >> 2] = tempI64[0]), + (HEAP32[(buf + 108) >> 2] = tempI64[1]); + return 0; + }, + doMsync: function (addr, stream, len, flags, offset) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (flags & 2) { + return 0; + } + var buffer = HEAPU8.slice(addr, addr + len); + FS.msync(stream, buffer, offset, len, flags); + }, + varargs: undefined, + get: function () { + SYSCALLS.varargs += 4; + var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]; + return ret; + }, + getStr: function (ptr) { + var ret = UTF8ToString(ptr); + return ret; + }, + getStreamFromFD: function (fd) { + var stream = FS.getStream(fd); + if (!stream) throw new FS.ErrnoError(8); + return stream; + }, + }; + function ___syscall_chmod(path, mode) { + try { + path = SYSCALLS.getStr(path); + FS.chmod(path, mode); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_faccessat(dirfd, path, amode, flags) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (amode & ~7) { + return -28; + } + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + if (!node) { + return -44; + } + var perms = ''; + if (amode & 4) perms += 'r'; + if (amode & 2) perms += 'w'; + if (amode & 1) perms += 'x'; + if (perms && FS.nodePermissions(node, perms)) { + return -2; + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_fchmod(fd, mode) { + try { + FS.fchmod(fd, mode); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_fchown32(fd, owner, group) { + try { + FS.fchown(fd, owner, group); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function setErrNo(value) { + HEAP32[___errno_location() >> 2] = value; + return value; + } + + function ___syscall_fcntl64(fd, cmd, varargs) { + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (cmd) { + case 0: { + var arg = SYSCALLS.get(); + if (arg < 0) { + return -28; + } + var newStream; + newStream = FS.createStream(stream, arg); + return newStream.fd; + } + case 1: + case 2: + return 0; + case 3: + return stream.flags; + case 4: { + var arg = SYSCALLS.get(); + stream.flags |= arg; + return 0; + } + case 5: { + var arg = SYSCALLS.get(); + var offset = 0; + + HEAP16[(arg + offset) >> 1] = 2; + return 0; + } + case 6: + case 7: + return 0; + case 16: + case 8: + return -28; + case 9: + setErrNo(28); + return -1; + default: { + return -28; + } + } + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_fstat64(fd, buf) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + return SYSCALLS.doStat(FS.stat, stream.path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + var MAX_INT53 = 9007199254740992; + + var MIN_INT53 = -9007199254740992; + function bigintToI53Checked(num) { + return num < MIN_INT53 || num > MAX_INT53 ? NaN : Number(num); + } + + function ___syscall_ftruncate64(fd, length) { + try { + length = bigintToI53Checked(length); + if (isNaN(length)) return -61; + FS.ftruncate(fd, length); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_getcwd(buf, size) { + try { + if (size === 0) return -28; + var cwd = FS.cwd(); + var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; + if (size < cwdLengthInBytes) return -68; + stringToUTF8(cwd, buf, size); + return cwdLengthInBytes; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_ioctl(fd, op, varargs) { + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (op) { + case 21509: + case 21505: { + if (!stream.tty) return -59; + return 0; + } + case 21510: + case 21511: + case 21512: + case 21506: + case 21507: + case 21508: { + if (!stream.tty) return -59; + return 0; + } + case 21519: { + if (!stream.tty) return -59; + var argp = SYSCALLS.get(); + HEAP32[argp >> 2] = 0; + return 0; + } + case 21520: { + if (!stream.tty) return -59; + return -28; + } + case 21531: { + var argp = SYSCALLS.get(); + return FS.ioctl(stream, op, argp); + } + case 21523: { + if (!stream.tty) return -59; + return 0; + } + case 21524: { + if (!stream.tty) return -59; + return 0; + } + default: + return -28; + } + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_lstat64(path, buf) { + try { + path = SYSCALLS.getStr(path); + return SYSCALLS.doStat(FS.lstat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_mkdirat(dirfd, path, mode) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + + path = PATH.normalize(path); + if (path[path.length - 1] === '/') + path = path.substr(0, path.length - 1); + FS.mkdir(path, mode, 0); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_newfstatat(dirfd, path, buf, flags) { + try { + path = SYSCALLS.getStr(path); + var nofollow = flags & 256; + var allowEmpty = flags & 4096; + flags = flags & ~6400; + path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); + return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_openat(dirfd, path, flags, varargs) { + SYSCALLS.varargs = varargs; + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + var mode = varargs ? SYSCALLS.get() : 0; + return FS.open(path, flags, mode).fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_readlinkat(dirfd, path, buf, bufsize) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (bufsize <= 0) return -28; + var ret = FS.readlink(path); + + var len = Math.min(bufsize, lengthBytesUTF8(ret)); + var endChar = HEAP8[buf + len]; + stringToUTF8(ret, buf, bufsize + 1); + + HEAP8[buf + len] = endChar; + return len; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_rmdir(path) { + try { + path = SYSCALLS.getStr(path); + FS.rmdir(path); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_stat64(path, buf) { + try { + path = SYSCALLS.getStr(path); + return SYSCALLS.doStat(FS.stat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function ___syscall_unlinkat(dirfd, path, flags) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (flags === 0) { + FS.unlink(path); + } else if (flags === 512) { + FS.rmdir(path); + } else { + abort('Invalid flags passed to unlinkat'); + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function readI53FromI64(ptr) { + return HEAPU32[ptr >> 2] + HEAP32[(ptr + 4) >> 2] * 4294967296; + } + + function ___syscall_utimensat(dirfd, path, times, flags) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path, true); + if (!times) { + var atime = Date.now(); + var mtime = atime; + } else { + var seconds = readI53FromI64(times); + var nanoseconds = HEAP32[(times + 8) >> 2]; + atime = seconds * 1000 + nanoseconds / (1000 * 1000); + times += 16; + seconds = readI53FromI64(times); + nanoseconds = HEAP32[(times + 8) >> 2]; + mtime = seconds * 1000 + nanoseconds / (1000 * 1000); + } + FS.utime(path, atime, mtime); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + var nowIsMonotonic = true; + function __emscripten_get_now_is_monotonic() { + return nowIsMonotonic; + } + + function __isLeapYear(year) { + return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + } + + var __MONTH_DAYS_LEAP_CUMULATIVE = [ + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, + ]; + + var __MONTH_DAYS_REGULAR_CUMULATIVE = [ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, + ]; + function __yday_from_date(date) { + var isLeapYear = __isLeapYear(date.getFullYear()); + var monthDaysCumulative = isLeapYear + ? __MONTH_DAYS_LEAP_CUMULATIVE + : __MONTH_DAYS_REGULAR_CUMULATIVE; + var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; + + return yday; + } + function __localtime_js(time, tmPtr) { + var date = new Date(readI53FromI64(time) * 1000); + HEAP32[tmPtr >> 2] = date.getSeconds(); + HEAP32[(tmPtr + 4) >> 2] = date.getMinutes(); + HEAP32[(tmPtr + 8) >> 2] = date.getHours(); + HEAP32[(tmPtr + 12) >> 2] = date.getDate(); + HEAP32[(tmPtr + 16) >> 2] = date.getMonth(); + HEAP32[(tmPtr + 20) >> 2] = date.getFullYear() - 1900; + HEAP32[(tmPtr + 24) >> 2] = date.getDay(); + + var yday = __yday_from_date(date) | 0; + HEAP32[(tmPtr + 28) >> 2] = yday; + HEAP32[(tmPtr + 36) >> 2] = -(date.getTimezoneOffset() * 60); + + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dst = + (summerOffset != winterOffset && + date.getTimezoneOffset() == Math.min(winterOffset, summerOffset)) | 0; + HEAP32[(tmPtr + 32) >> 2] = dst; + } + + function __mmap_js(len, prot, flags, fd, off, allocated, addr) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var res = FS.mmap(stream, len, off, prot, flags); + var ptr = res.ptr; + HEAP32[allocated >> 2] = res.allocated; + HEAPU32[addr >> 2] = ptr; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function __munmap_js(addr, len, prot, flags, fd, offset) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + if (prot & 2) { + SYSCALLS.doMsync(addr, stream, len, flags, offset); + } + FS.munmap(stream); + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return -e.errno; + } + } + + function allocateUTF8(str) { + var size = lengthBytesUTF8(str) + 1; + var ret = _malloc(size); + if (ret) stringToUTF8Array(str, HEAP8, ret, size); + return ret; + } + function __tzset_js(timezone, daylight, tzname) { + var currentYear = new Date().getFullYear(); + var winter = new Date(currentYear, 0, 1); + var summer = new Date(currentYear, 6, 1); + var winterOffset = winter.getTimezoneOffset(); + var summerOffset = summer.getTimezoneOffset(); + + var stdTimezoneOffset = Math.max(winterOffset, summerOffset); + + HEAPU32[timezone >> 2] = stdTimezoneOffset * 60; + + HEAP32[daylight >> 2] = Number(winterOffset != summerOffset); + + function extractZone(date) { + var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/); + return match ? match[1] : 'GMT'; + } + var winterName = extractZone(winter); + var summerName = extractZone(summer); + var winterNamePtr = allocateUTF8(winterName); + var summerNamePtr = allocateUTF8(summerName); + if (summerOffset < winterOffset) { + HEAPU32[tzname >> 2] = winterNamePtr; + HEAPU32[(tzname + 4) >> 2] = summerNamePtr; + } else { + HEAPU32[tzname >> 2] = summerNamePtr; + HEAPU32[(tzname + 4) >> 2] = winterNamePtr; + } + } + + function _emscripten_date_now() { + return Date.now(); + } + + var _emscripten_get_now; + _emscripten_get_now = () => performance.now(); + function getHeapMax() { + return 2147483648; + } + + function emscripten_realloc_buffer(size) { + var b = wasmMemory.buffer; + try { + wasmMemory.grow((size - b.byteLength + 65535) >>> 16); + updateMemoryViews(); + return 1; + } catch (e) {} + } + function _emscripten_resize_heap(requestedSize) { + var oldSize = HEAPU8.length; + requestedSize = requestedSize >>> 0; + + var maxHeapSize = getHeapMax(); + if (requestedSize > maxHeapSize) { + return false; + } + + let alignUp = (x, multiple) => + x + ((multiple - (x % multiple)) % multiple); + + for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); + + overGrownHeapSize = Math.min( + overGrownHeapSize, + requestedSize + 100663296, + ); + + var newSize = Math.min( + maxHeapSize, + alignUp(Math.max(requestedSize, overGrownHeapSize), 65536), + ); + + var replacement = emscripten_realloc_buffer(newSize); + if (replacement) { + return true; + } + } + return false; + } + + var ENV = {}; + + function getExecutableName() { + return thisProgram || './this.program'; + } + function getEnvStrings() { + if (!getEnvStrings.strings) { + var lang = + ( + (typeof navigator == 'object' && + navigator.languages && + navigator.languages[0]) || + 'C' + ).replace('-', '_') + '.UTF-8'; + var env = { + USER: 'web_user', + LOGNAME: 'web_user', + PATH: '/', + PWD: '/', + HOME: '/home/web_user', + LANG: lang, + _: getExecutableName(), + }; + + for (var x in ENV) { + if (ENV[x] === undefined) delete env[x]; + else env[x] = ENV[x]; + } + var strings = []; + for (var x in env) { + strings.push(x + '=' + env[x]); + } + getEnvStrings.strings = strings; + } + return getEnvStrings.strings; + } + + function writeAsciiToMemory(str, buffer, dontAddNull) { + for (var i = 0; i < str.length; ++i) { + HEAP8[buffer++ >> 0] = str.charCodeAt(i); + } + + HEAP8[buffer >> 0] = 0; + } + + function _environ_get(__environ, environ_buf) { + var bufSize = 0; + getEnvStrings().forEach(function (string, i) { + var ptr = environ_buf + bufSize; + HEAPU32[(__environ + i * 4) >> 2] = ptr; + writeAsciiToMemory(string, ptr); + bufSize += string.length + 1; + }); + return 0; + } + + function _environ_sizes_get(penviron_count, penviron_buf_size) { + var strings = getEnvStrings(); + HEAPU32[penviron_count >> 2] = strings.length; + var bufSize = 0; + strings.forEach(function (string) { + bufSize += string.length + 1; + }); + HEAPU32[penviron_buf_size >> 2] = bufSize; + return 0; + } + + function _fd_close(fd) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + FS.close(stream); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return e.errno; + } + } + + function _fd_fdstat_get(fd, pbuf) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + + var type = stream.tty + ? 2 + : FS.isDir(stream.mode) + ? 3 + : FS.isLink(stream.mode) + ? 7 + : 4; + HEAP8[pbuf >> 0] = type; + + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return e.errno; + } + } + + function doReadv(stream, iov, iovcnt, offset) { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[iov >> 2]; + var len = HEAPU32[(iov + 4) >> 2]; + iov += 8; + var curr = FS.read(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) break; + } + return ret; + } + + function _fd_read(fd, iov, iovcnt, pnum) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doReadv(stream, iov, iovcnt); + HEAPU32[pnum >> 2] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return e.errno; + } + } + + function _fd_seek(fd, offset, whence, newOffset) { + try { + offset = bigintToI53Checked(offset); + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + FS.llseek(stream, offset, whence); + (tempI64 = [ + stream.position >>> 0, + ((tempDouble = stream.position), + +Math.abs(tempDouble) >= 1.0 + ? tempDouble > 0.0 + ? (Math.min( + +Math.floor(tempDouble / 4294967296.0), + 4294967295.0, + ) | + 0) >>> + 0 + : ~~+Math.ceil( + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + ) >>> 0 + : 0), + ]), + (HEAP32[newOffset >> 2] = tempI64[0]), + (HEAP32[(newOffset + 4) >> 2] = tempI64[1]); + if (stream.getdents && offset === 0 && whence === 0) + stream.getdents = null; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return e.errno; + } + } + + function _fd_sync(fd) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + if (stream.stream_ops && stream.stream_ops.fsync) { + return stream.stream_ops.fsync(stream); + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return e.errno; + } + } + + function doWritev(stream, iov, iovcnt, offset) { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[iov >> 2]; + var len = HEAPU32[(iov + 4) >> 2]; + iov += 8; + var curr = FS.write(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + } + return ret; + } + + function _fd_write(fd, iov, iovcnt, pnum) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doWritev(stream, iov, iovcnt); + HEAPU32[pnum >> 2] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + return e.errno; + } + } + + var FSNode = function (parent, name, mode, rdev) { + if (!parent) { + parent = this; + } + this.parent = parent; + this.mount = parent.mount; + this.mounted = null; + this.id = FS.nextInode++; + this.name = name; + this.mode = mode; + this.node_ops = {}; + this.stream_ops = {}; + this.rdev = rdev; + }; + var readMode = 292 | 73; + var writeMode = 146; + Object.defineProperties(FSNode.prototype, { + read: { + get: function () { + return (this.mode & readMode) === readMode; + }, + set: function (val) { + val ? (this.mode |= readMode) : (this.mode &= ~readMode); + }, + }, + write: { + get: function () { + return (this.mode & writeMode) === writeMode; + }, + set: function (val) { + val ? (this.mode |= writeMode) : (this.mode &= ~writeMode); + }, + }, + isFolder: { + get: function () { + return FS.isDir(this.mode); + }, + }, + isDevice: { + get: function () { + return FS.isChrdev(this.mode); + }, + }, + }); + FS.FSNode = FSNode; + FS.staticInit(); + + var asmLibraryArg = { + __syscall_chmod: ___syscall_chmod, + __syscall_faccessat: ___syscall_faccessat, + __syscall_fchmod: ___syscall_fchmod, + __syscall_fchown32: ___syscall_fchown32, + __syscall_fcntl64: ___syscall_fcntl64, + __syscall_fstat64: ___syscall_fstat64, + __syscall_ftruncate64: ___syscall_ftruncate64, + __syscall_getcwd: ___syscall_getcwd, + __syscall_ioctl: ___syscall_ioctl, + __syscall_lstat64: ___syscall_lstat64, + __syscall_mkdirat: ___syscall_mkdirat, + __syscall_newfstatat: ___syscall_newfstatat, + __syscall_openat: ___syscall_openat, + __syscall_readlinkat: ___syscall_readlinkat, + __syscall_rmdir: ___syscall_rmdir, + __syscall_stat64: ___syscall_stat64, + __syscall_unlinkat: ___syscall_unlinkat, + __syscall_utimensat: ___syscall_utimensat, + _emscripten_get_now_is_monotonic: __emscripten_get_now_is_monotonic, + _localtime_js: __localtime_js, + _mmap_js: __mmap_js, + _munmap_js: __munmap_js, + _tzset_js: __tzset_js, + emscripten_date_now: _emscripten_date_now, + emscripten_get_now: _emscripten_get_now, + emscripten_resize_heap: _emscripten_resize_heap, + environ_get: _environ_get, + environ_sizes_get: _environ_sizes_get, + fd_close: _fd_close, + fd_fdstat_get: _fd_fdstat_get, + fd_read: _fd_read, + fd_seek: _fd_seek, + fd_sync: _fd_sync, + fd_write: _fd_write, + memory: wasmMemory, + }; + createWasm(); + + (Module['___wasm_call_ctors'] = function () { + return (Module['___wasm_call_ctors'] = + Module['asm']['__wasm_call_ctors']).apply(null, arguments); + }); + + (Module['_sqlite3_status64'] = function () { + return (Module['_sqlite3_status64'] = + Module['asm']['sqlite3_status64']).apply(null, arguments); + }); + + (Module['_sqlite3_status'] = function () { + return (Module['_sqlite3_status'] = + Module['asm']['sqlite3_status']).apply(null, arguments); + }); + + (Module['_sqlite3_db_status'] = function () { + return (Module['_sqlite3_db_status'] = + Module['asm']['sqlite3_db_status']).apply(null, arguments); + }); + + (Module['_sqlite3_msize'] = function () { + return (Module['_sqlite3_msize'] = + Module['asm']['sqlite3_msize']).apply(null, arguments); + }); + + (Module['_sqlite3_vfs_find'] = function () { + return (Module['_sqlite3_vfs_find'] = + Module['asm']['sqlite3_vfs_find']).apply(null, arguments); + }); + + (Module['_sqlite3_initialize'] = function () { + return (Module['_sqlite3_initialize'] = + Module['asm']['sqlite3_initialize']).apply(null, arguments); + }); + + (Module['_sqlite3_malloc'] = function () { + return (Module['_sqlite3_malloc'] = + Module['asm']['sqlite3_malloc']).apply(null, arguments); + }); + + (Module['_sqlite3_free'] = function () { + return (Module['_sqlite3_free'] = + Module['asm']['sqlite3_free']).apply(null, arguments); + }); + + (Module['_sqlite3_vfs_register'] = function () { + return (Module['_sqlite3_vfs_register'] = + Module['asm']['sqlite3_vfs_register']).apply(null, arguments); + }); + + (Module['_sqlite3_vfs_unregister'] = + function () { + return (Module['_sqlite3_vfs_unregister'] = + Module['asm']['sqlite3_vfs_unregister']).apply(null, arguments); + }); + + (Module['_sqlite3_malloc64'] = function () { + return (Module['_sqlite3_malloc64'] = + Module['asm']['sqlite3_malloc64']).apply(null, arguments); + }); + + (Module['_sqlite3_realloc'] = function () { + return (Module['_sqlite3_realloc'] = + Module['asm']['sqlite3_realloc']).apply(null, arguments); + }); + + (Module['_sqlite3_realloc64'] = function () { + return (Module['_sqlite3_realloc64'] = + Module['asm']['sqlite3_realloc64']).apply(null, arguments); + }); + + (Module['_sqlite3_value_text'] = function () { + return (Module['_sqlite3_value_text'] = + Module['asm']['sqlite3_value_text']).apply(null, arguments); + }); + + (Module['_sqlite3_randomness'] = function () { + return (Module['_sqlite3_randomness'] = + Module['asm']['sqlite3_randomness']).apply(null, arguments); + }); + + (Module['_sqlite3_stricmp'] = function () { + return (Module['_sqlite3_stricmp'] = + Module['asm']['sqlite3_stricmp']).apply(null, arguments); + }); + + (Module['_sqlite3_strnicmp'] = function () { + return (Module['_sqlite3_strnicmp'] = + Module['asm']['sqlite3_strnicmp']).apply(null, arguments); + }); + + (Module['_sqlite3_uri_parameter'] = + function () { + return (Module['_sqlite3_uri_parameter'] = + Module['asm']['sqlite3_uri_parameter']).apply(null, arguments); + }); + + var ___errno_location = (Module['___errno_location'] = function () { + return (___errno_location = Module['___errno_location'] = + Module['asm']['__errno_location']).apply(null, arguments); + }); + + (Module['_sqlite3_uri_boolean'] = function () { + return (Module['_sqlite3_uri_boolean'] = + Module['asm']['sqlite3_uri_boolean']).apply(null, arguments); + }); + + (Module['_sqlite3_serialize'] = function () { + return (Module['_sqlite3_serialize'] = + Module['asm']['sqlite3_serialize']).apply(null, arguments); + }); + + (Module['_sqlite3_prepare_v2'] = function () { + return (Module['_sqlite3_prepare_v2'] = + Module['asm']['sqlite3_prepare_v2']).apply(null, arguments); + }); + + (Module['_sqlite3_step'] = function () { + return (Module['_sqlite3_step'] = + Module['asm']['sqlite3_step']).apply(null, arguments); + }); + + (Module['_sqlite3_column_int64'] = function () { + return (Module['_sqlite3_column_int64'] = + Module['asm']['sqlite3_column_int64']).apply(null, arguments); + }); + + (Module['_sqlite3_reset'] = function () { + return (Module['_sqlite3_reset'] = + Module['asm']['sqlite3_reset']).apply(null, arguments); + }); + + (Module['_sqlite3_exec'] = function () { + return (Module['_sqlite3_exec'] = + Module['asm']['sqlite3_exec']).apply(null, arguments); + }); + + (Module['_sqlite3_column_int'] = function () { + return (Module['_sqlite3_column_int'] = + Module['asm']['sqlite3_column_int']).apply(null, arguments); + }); + + (Module['_sqlite3_finalize'] = function () { + return (Module['_sqlite3_finalize'] = + Module['asm']['sqlite3_finalize']).apply(null, arguments); + }); + + (Module['_sqlite3_file_control'] = function () { + return (Module['_sqlite3_file_control'] = + Module['asm']['sqlite3_file_control']).apply(null, arguments); + }); + + (Module['_sqlite3_column_name'] = function () { + return (Module['_sqlite3_column_name'] = + Module['asm']['sqlite3_column_name']).apply(null, arguments); + }); + + (Module['_sqlite3_column_text'] = function () { + return (Module['_sqlite3_column_text'] = + Module['asm']['sqlite3_column_text']).apply(null, arguments); + }); + + (Module['_sqlite3_column_type'] = function () { + return (Module['_sqlite3_column_type'] = + Module['asm']['sqlite3_column_type']).apply(null, arguments); + }); + + (Module['_sqlite3_errmsg'] = function () { + return (Module['_sqlite3_errmsg'] = + Module['asm']['sqlite3_errmsg']).apply(null, arguments); + }); + + (Module['_sqlite3_deserialize'] = function () { + return (Module['_sqlite3_deserialize'] = + Module['asm']['sqlite3_deserialize']).apply(null, arguments); + }); + + (Module['_sqlite3_clear_bindings'] = + function () { + return (Module['_sqlite3_clear_bindings'] = + Module['asm']['sqlite3_clear_bindings']).apply(null, arguments); + }); + + (Module['_sqlite3_value_blob'] = function () { + return (Module['_sqlite3_value_blob'] = + Module['asm']['sqlite3_value_blob']).apply(null, arguments); + }); + + (Module['_sqlite3_value_bytes'] = function () { + return (Module['_sqlite3_value_bytes'] = + Module['asm']['sqlite3_value_bytes']).apply(null, arguments); + }); + + (Module['_sqlite3_value_double'] = function () { + return (Module['_sqlite3_value_double'] = + Module['asm']['sqlite3_value_double']).apply(null, arguments); + }); + + (Module['_sqlite3_value_int'] = function () { + return (Module['_sqlite3_value_int'] = + Module['asm']['sqlite3_value_int']).apply(null, arguments); + }); + + (Module['_sqlite3_value_int64'] = function () { + return (Module['_sqlite3_value_int64'] = + Module['asm']['sqlite3_value_int64']).apply(null, arguments); + }); + + (Module['_sqlite3_value_subtype'] = + function () { + return (Module['_sqlite3_value_subtype'] = + Module['asm']['sqlite3_value_subtype']).apply(null, arguments); + }); + + (Module['_sqlite3_value_pointer'] = + function () { + return (Module['_sqlite3_value_pointer'] = + Module['asm']['sqlite3_value_pointer']).apply(null, arguments); + }); + + (Module['_sqlite3_value_type'] = function () { + return (Module['_sqlite3_value_type'] = + Module['asm']['sqlite3_value_type']).apply(null, arguments); + }); + + (Module['_sqlite3_value_nochange'] = + function () { + return (Module['_sqlite3_value_nochange'] = + Module['asm']['sqlite3_value_nochange']).apply(null, arguments); + }); + + (Module['_sqlite3_value_frombind'] = + function () { + return (Module['_sqlite3_value_frombind'] = + Module['asm']['sqlite3_value_frombind']).apply(null, arguments); + }); + + (Module['_sqlite3_value_dup'] = function () { + return (Module['_sqlite3_value_dup'] = + Module['asm']['sqlite3_value_dup']).apply(null, arguments); + }); + + (Module['_sqlite3_value_free'] = function () { + return (Module['_sqlite3_value_free'] = + Module['asm']['sqlite3_value_free']).apply(null, arguments); + }); + + (Module['_sqlite3_result_blob'] = function () { + return (Module['_sqlite3_result_blob'] = + Module['asm']['sqlite3_result_blob']).apply(null, arguments); + }); + + (Module['_sqlite3_result_error_toobig'] = + function () { + return (Module[ + '_sqlite3_result_error_toobig' + ] = + Module['asm']['sqlite3_result_error_toobig']).apply(null, arguments); + }); + + (Module['_sqlite3_result_error_nomem'] = + function () { + return (Module[ + '_sqlite3_result_error_nomem' + ] = + Module['asm']['sqlite3_result_error_nomem']).apply(null, arguments); + }); + + (Module['_sqlite3_result_double'] = + function () { + return (Module['_sqlite3_result_double'] = + Module['asm']['sqlite3_result_double']).apply(null, arguments); + }); + + (Module['_sqlite3_result_error'] = function () { + return (Module['_sqlite3_result_error'] = + Module['asm']['sqlite3_result_error']).apply(null, arguments); + }); + + (Module['_sqlite3_result_int'] = function () { + return (Module['_sqlite3_result_int'] = + Module['asm']['sqlite3_result_int']).apply(null, arguments); + }); + + (Module['_sqlite3_result_int64'] = function () { + return (Module['_sqlite3_result_int64'] = + Module['asm']['sqlite3_result_int64']).apply(null, arguments); + }); + + (Module['_sqlite3_result_null'] = function () { + return (Module['_sqlite3_result_null'] = + Module['asm']['sqlite3_result_null']).apply(null, arguments); + }); + + (Module['_sqlite3_result_pointer'] = + function () { + return (Module['_sqlite3_result_pointer'] = + Module['asm']['sqlite3_result_pointer']).apply(null, arguments); + }); + + (Module['_sqlite3_result_subtype'] = + function () { + return (Module['_sqlite3_result_subtype'] = + Module['asm']['sqlite3_result_subtype']).apply(null, arguments); + }); + + (Module['_sqlite3_result_text'] = function () { + return (Module['_sqlite3_result_text'] = + Module['asm']['sqlite3_result_text']).apply(null, arguments); + }); + + (Module['_sqlite3_result_zeroblob'] = + function () { + return (Module['_sqlite3_result_zeroblob'] = + Module['asm']['sqlite3_result_zeroblob']).apply(null, arguments); + }); + + (Module['_sqlite3_result_zeroblob64'] = + function () { + return (Module[ + '_sqlite3_result_zeroblob64' + ] = + Module['asm']['sqlite3_result_zeroblob64']).apply(null, arguments); + }); + + (Module['_sqlite3_result_error_code'] = + function () { + return (Module[ + '_sqlite3_result_error_code' + ] = + Module['asm']['sqlite3_result_error_code']).apply(null, arguments); + }); + + (Module['_sqlite3_user_data'] = function () { + return (Module['_sqlite3_user_data'] = + Module['asm']['sqlite3_user_data']).apply(null, arguments); + }); + + (Module['_sqlite3_context_db_handle'] = + function () { + return (Module[ + '_sqlite3_context_db_handle' + ] = + Module['asm']['sqlite3_context_db_handle']).apply(null, arguments); + }); + + (Module['_sqlite3_vtab_nochange'] = + function () { + return (Module['_sqlite3_vtab_nochange'] = + Module['asm']['sqlite3_vtab_nochange']).apply(null, arguments); + }); + + (Module['_sqlite3_vtab_in_first'] = + function () { + return (Module['_sqlite3_vtab_in_first'] = + Module['asm']['sqlite3_vtab_in_first']).apply(null, arguments); + }); + + (Module['_sqlite3_vtab_in_next'] = function () { + return (Module['_sqlite3_vtab_in_next'] = + Module['asm']['sqlite3_vtab_in_next']).apply(null, arguments); + }); + + (Module['_sqlite3_aggregate_context'] = + function () { + return (Module[ + '_sqlite3_aggregate_context' + ] = + Module['asm']['sqlite3_aggregate_context']).apply(null, arguments); + }); + + (Module['_sqlite3_get_auxdata'] = function () { + return (Module['_sqlite3_get_auxdata'] = + Module['asm']['sqlite3_get_auxdata']).apply(null, arguments); + }); + + (Module['_sqlite3_set_auxdata'] = function () { + return (Module['_sqlite3_set_auxdata'] = + Module['asm']['sqlite3_set_auxdata']).apply(null, arguments); + }); + + (Module['_sqlite3_column_count'] = function () { + return (Module['_sqlite3_column_count'] = + Module['asm']['sqlite3_column_count']).apply(null, arguments); + }); + + (Module['_sqlite3_data_count'] = function () { + return (Module['_sqlite3_data_count'] = + Module['asm']['sqlite3_data_count']).apply(null, arguments); + }); + + (Module['_sqlite3_column_blob'] = function () { + return (Module['_sqlite3_column_blob'] = + Module['asm']['sqlite3_column_blob']).apply(null, arguments); + }); + + (Module['_sqlite3_column_bytes'] = function () { + return (Module['_sqlite3_column_bytes'] = + Module['asm']['sqlite3_column_bytes']).apply(null, arguments); + }); + + (Module['_sqlite3_column_double'] = + function () { + return (Module['_sqlite3_column_double'] = + Module['asm']['sqlite3_column_double']).apply(null, arguments); + }); + + (Module['_sqlite3_column_value'] = function () { + return (Module['_sqlite3_column_value'] = + Module['asm']['sqlite3_column_value']).apply(null, arguments); + }); + + (Module['_sqlite3_bind_blob'] = function () { + return (Module['_sqlite3_bind_blob'] = + Module['asm']['sqlite3_bind_blob']).apply(null, arguments); + }); + + (Module['_sqlite3_bind_double'] = function () { + return (Module['_sqlite3_bind_double'] = + Module['asm']['sqlite3_bind_double']).apply(null, arguments); + }); + + (Module['_sqlite3_bind_int'] = function () { + return (Module['_sqlite3_bind_int'] = + Module['asm']['sqlite3_bind_int']).apply(null, arguments); + }); + + (Module['_sqlite3_bind_int64'] = function () { + return (Module['_sqlite3_bind_int64'] = + Module['asm']['sqlite3_bind_int64']).apply(null, arguments); + }); + + (Module['_sqlite3_bind_null'] = function () { + return (Module['_sqlite3_bind_null'] = + Module['asm']['sqlite3_bind_null']).apply(null, arguments); + }); + + (Module['_sqlite3_bind_pointer'] = function () { + return (Module['_sqlite3_bind_pointer'] = + Module['asm']['sqlite3_bind_pointer']).apply(null, arguments); + }); + + (Module['_sqlite3_bind_text'] = function () { + return (Module['_sqlite3_bind_text'] = + Module['asm']['sqlite3_bind_text']).apply(null, arguments); + }); + + (Module[ + '_sqlite3_bind_parameter_count' + ] = function () { + return (Module[ + '_sqlite3_bind_parameter_count' + ] = + Module['asm']['sqlite3_bind_parameter_count']).apply(null, arguments); + }); + + (Module[ + '_sqlite3_bind_parameter_index' + ] = function () { + return (Module[ + '_sqlite3_bind_parameter_index' + ] = + Module['asm']['sqlite3_bind_parameter_index']).apply(null, arguments); + }); + + (Module['_sqlite3_db_handle'] = function () { + return (Module['_sqlite3_db_handle'] = + Module['asm']['sqlite3_db_handle']).apply(null, arguments); + }); + + (Module['_sqlite3_stmt_readonly'] = + function () { + return (Module['_sqlite3_stmt_readonly'] = + Module['asm']['sqlite3_stmt_readonly']).apply(null, arguments); + }); + + (Module['_sqlite3_stmt_isexplain'] = + function () { + return (Module['_sqlite3_stmt_isexplain'] = + Module['asm']['sqlite3_stmt_isexplain']).apply(null, arguments); + }); + + (Module['_sqlite3_stmt_status'] = function () { + return (Module['_sqlite3_stmt_status'] = + Module['asm']['sqlite3_stmt_status']).apply(null, arguments); + }); + + (Module['_sqlite3_sql'] = function () { + return (Module['_sqlite3_sql'] = + Module['asm']['sqlite3_sql']).apply(null, arguments); + }); + + (Module['_sqlite3_expanded_sql'] = function () { + return (Module['_sqlite3_expanded_sql'] = + Module['asm']['sqlite3_expanded_sql']).apply(null, arguments); + }); + + (Module['_sqlite3_preupdate_old'] = + function () { + return (Module['_sqlite3_preupdate_old'] = + Module['asm']['sqlite3_preupdate_old']).apply(null, arguments); + }); + + (Module['_sqlite3_preupdate_count'] = + function () { + return (Module['_sqlite3_preupdate_count'] = + Module['asm']['sqlite3_preupdate_count']).apply(null, arguments); + }); + + (Module['_sqlite3_preupdate_depth'] = + function () { + return (Module['_sqlite3_preupdate_depth'] = + Module['asm']['sqlite3_preupdate_depth']).apply(null, arguments); + }); + + (Module['_sqlite3_preupdate_blobwrite'] = + function () { + return (Module[ + '_sqlite3_preupdate_blobwrite' + ] = + Module['asm']['sqlite3_preupdate_blobwrite']).apply(null, arguments); + }); + + (Module['_sqlite3_preupdate_new'] = + function () { + return (Module['_sqlite3_preupdate_new'] = + Module['asm']['sqlite3_preupdate_new']).apply(null, arguments); + }); + + (Module['_sqlite3_value_numeric_type'] = + function () { + return (Module[ + '_sqlite3_value_numeric_type' + ] = + Module['asm']['sqlite3_value_numeric_type']).apply(null, arguments); + }); + + (Module['_sqlite3_set_authorizer'] = + function () { + return (Module['_sqlite3_set_authorizer'] = + Module['asm']['sqlite3_set_authorizer']).apply(null, arguments); + }); + + (Module['_sqlite3_strglob'] = function () { + return (Module['_sqlite3_strglob'] = + Module['asm']['sqlite3_strglob']).apply(null, arguments); + }); + + (Module['_sqlite3_strlike'] = function () { + return (Module['_sqlite3_strlike'] = + Module['asm']['sqlite3_strlike']).apply(null, arguments); + }); + + (Module['_sqlite3_auto_extension'] = + function () { + return (Module['_sqlite3_auto_extension'] = + Module['asm']['sqlite3_auto_extension']).apply(null, arguments); + }); + + (Module[ + '_sqlite3_cancel_auto_extension' + ] = function () { + return (Module[ + '_sqlite3_cancel_auto_extension' + ] = + Module['asm']['sqlite3_cancel_auto_extension']).apply(null, arguments); + }); + + (Module[ + '_sqlite3_reset_auto_extension' + ] = function () { + return (Module[ + '_sqlite3_reset_auto_extension' + ] = + Module['asm']['sqlite3_reset_auto_extension']).apply(null, arguments); + }); + + (Module['_sqlite3_prepare_v3'] = function () { + return (Module['_sqlite3_prepare_v3'] = + Module['asm']['sqlite3_prepare_v3']).apply(null, arguments); + }); + + (Module['_sqlite3_create_module'] = + function () { + return (Module['_sqlite3_create_module'] = + Module['asm']['sqlite3_create_module']).apply(null, arguments); + }); + + (Module['_sqlite3_create_module_v2'] = + function () { + return (Module[ + '_sqlite3_create_module_v2' + ] = + Module['asm']['sqlite3_create_module_v2']).apply(null, arguments); + }); + + (Module['_sqlite3_drop_modules'] = function () { + return (Module['_sqlite3_drop_modules'] = + Module['asm']['sqlite3_drop_modules']).apply(null, arguments); + }); + + (Module['_sqlite3_declare_vtab'] = function () { + return (Module['_sqlite3_declare_vtab'] = + Module['asm']['sqlite3_declare_vtab']).apply(null, arguments); + }); + + (Module['_sqlite3_vtab_on_conflict'] = + function () { + return (Module[ + '_sqlite3_vtab_on_conflict' + ] = + Module['asm']['sqlite3_vtab_on_conflict']).apply(null, arguments); + }); + + (Module['_sqlite3_vtab_collation'] = + function () { + return (Module['_sqlite3_vtab_collation'] = + Module['asm']['sqlite3_vtab_collation']).apply(null, arguments); + }); + + (Module['_sqlite3_vtab_in'] = function () { + return (Module['_sqlite3_vtab_in'] = + Module['asm']['sqlite3_vtab_in']).apply(null, arguments); + }); + + (Module['_sqlite3_vtab_rhs_value'] = + function () { + return (Module['_sqlite3_vtab_rhs_value'] = + Module['asm']['sqlite3_vtab_rhs_value']).apply(null, arguments); + }); + + (Module['_sqlite3_vtab_distinct'] = + function () { + return (Module['_sqlite3_vtab_distinct'] = + Module['asm']['sqlite3_vtab_distinct']).apply(null, arguments); + }); + + (Module['_sqlite3_keyword_name'] = function () { + return (Module['_sqlite3_keyword_name'] = + Module['asm']['sqlite3_keyword_name']).apply(null, arguments); + }); + + (Module['_sqlite3_keyword_count'] = + function () { + return (Module['_sqlite3_keyword_count'] = + Module['asm']['sqlite3_keyword_count']).apply(null, arguments); + }); + + (Module['_sqlite3_keyword_check'] = + function () { + return (Module['_sqlite3_keyword_check'] = + Module['asm']['sqlite3_keyword_check']).apply(null, arguments); + }); + + (Module['_sqlite3_complete'] = function () { + return (Module['_sqlite3_complete'] = + Module['asm']['sqlite3_complete']).apply(null, arguments); + }); + + (Module['_sqlite3_libversion'] = function () { + return (Module['_sqlite3_libversion'] = + Module['asm']['sqlite3_libversion']).apply(null, arguments); + }); + + (Module['_sqlite3_libversion_number'] = + function () { + return (Module[ + '_sqlite3_libversion_number' + ] = + Module['asm']['sqlite3_libversion_number']).apply(null, arguments); + }); + + (Module['_sqlite3_shutdown'] = function () { + return (Module['_sqlite3_shutdown'] = + Module['asm']['sqlite3_shutdown']).apply(null, arguments); + }); + + (Module['_sqlite3_last_insert_rowid'] = + function () { + return (Module[ + '_sqlite3_last_insert_rowid' + ] = + Module['asm']['sqlite3_last_insert_rowid']).apply(null, arguments); + }); + + (Module[ + '_sqlite3_set_last_insert_rowid' + ] = function () { + return (Module[ + '_sqlite3_set_last_insert_rowid' + ] = + Module['asm']['sqlite3_set_last_insert_rowid']).apply(null, arguments); + }); + + (Module['_sqlite3_changes64'] = function () { + return (Module['_sqlite3_changes64'] = + Module['asm']['sqlite3_changes64']).apply(null, arguments); + }); + + (Module['_sqlite3_changes'] = function () { + return (Module['_sqlite3_changes'] = + Module['asm']['sqlite3_changes']).apply(null, arguments); + }); + + (Module['_sqlite3_total_changes64'] = + function () { + return (Module['_sqlite3_total_changes64'] = + Module['asm']['sqlite3_total_changes64']).apply(null, arguments); + }); + + (Module['_sqlite3_total_changes'] = + function () { + return (Module['_sqlite3_total_changes'] = + Module['asm']['sqlite3_total_changes']).apply(null, arguments); + }); + + (Module['_sqlite3_txn_state'] = function () { + return (Module['_sqlite3_txn_state'] = + Module['asm']['sqlite3_txn_state']).apply(null, arguments); + }); + + (Module['_sqlite3_close_v2'] = function () { + return (Module['_sqlite3_close_v2'] = + Module['asm']['sqlite3_close_v2']).apply(null, arguments); + }); + + (Module['_sqlite3_busy_handler'] = function () { + return (Module['_sqlite3_busy_handler'] = + Module['asm']['sqlite3_busy_handler']).apply(null, arguments); + }); + + (Module['_sqlite3_progress_handler'] = + function () { + return (Module[ + '_sqlite3_progress_handler' + ] = + Module['asm']['sqlite3_progress_handler']).apply(null, arguments); + }); + + (Module['_sqlite3_busy_timeout'] = function () { + return (Module['_sqlite3_busy_timeout'] = + Module['asm']['sqlite3_busy_timeout']).apply(null, arguments); + }); + + (Module['_sqlite3_create_function'] = + function () { + return (Module['_sqlite3_create_function'] = + Module['asm']['sqlite3_create_function']).apply(null, arguments); + }); + + (Module['_sqlite3_create_function_v2'] = + function () { + return (Module[ + '_sqlite3_create_function_v2' + ] = + Module['asm']['sqlite3_create_function_v2']).apply(null, arguments); + }); + + (Module[ + '_sqlite3_create_window_function' + ] = function () { + return (Module[ + '_sqlite3_create_window_function' + ] = + Module['asm']['sqlite3_create_window_function']).apply(null, arguments); + }); + + (Module['_sqlite3_overload_function'] = + function () { + return (Module[ + '_sqlite3_overload_function' + ] = + Module['asm']['sqlite3_overload_function']).apply(null, arguments); + }); + + (Module['_sqlite3_trace_v2'] = function () { + return (Module['_sqlite3_trace_v2'] = + Module['asm']['sqlite3_trace_v2']).apply(null, arguments); + }); + + (Module['_sqlite3_commit_hook'] = function () { + return (Module['_sqlite3_commit_hook'] = + Module['asm']['sqlite3_commit_hook']).apply(null, arguments); + }); + + (Module['_sqlite3_update_hook'] = function () { + return (Module['_sqlite3_update_hook'] = + Module['asm']['sqlite3_update_hook']).apply(null, arguments); + }); + + (Module['_sqlite3_rollback_hook'] = + function () { + return (Module['_sqlite3_rollback_hook'] = + Module['asm']['sqlite3_rollback_hook']).apply(null, arguments); + }); + + (Module['_sqlite3_preupdate_hook'] = + function () { + return (Module['_sqlite3_preupdate_hook'] = + Module['asm']['sqlite3_preupdate_hook']).apply(null, arguments); + }); + + (Module['_sqlite3_error_offset'] = function () { + return (Module['_sqlite3_error_offset'] = + Module['asm']['sqlite3_error_offset']).apply(null, arguments); + }); + + (Module['_sqlite3_errcode'] = function () { + return (Module['_sqlite3_errcode'] = + Module['asm']['sqlite3_errcode']).apply(null, arguments); + }); + + (Module['_sqlite3_extended_errcode'] = + function () { + return (Module[ + '_sqlite3_extended_errcode' + ] = + Module['asm']['sqlite3_extended_errcode']).apply(null, arguments); + }); + + (Module['_sqlite3_errstr'] = function () { + return (Module['_sqlite3_errstr'] = + Module['asm']['sqlite3_errstr']).apply(null, arguments); + }); + + (Module['_sqlite3_limit'] = function () { + return (Module['_sqlite3_limit'] = + Module['asm']['sqlite3_limit']).apply(null, arguments); + }); + + (Module['_sqlite3_open'] = function () { + return (Module['_sqlite3_open'] = + Module['asm']['sqlite3_open']).apply(null, arguments); + }); + + (Module['_sqlite3_open_v2'] = function () { + return (Module['_sqlite3_open_v2'] = + Module['asm']['sqlite3_open_v2']).apply(null, arguments); + }); + + (Module['_sqlite3_create_collation'] = + function () { + return (Module[ + '_sqlite3_create_collation' + ] = + Module['asm']['sqlite3_create_collation']).apply(null, arguments); + }); + + (Module['_sqlite3_create_collation_v2'] = + function () { + return (Module[ + '_sqlite3_create_collation_v2' + ] = + Module['asm']['sqlite3_create_collation_v2']).apply(null, arguments); + }); + + (Module['_sqlite3_collation_needed'] = + function () { + return (Module[ + '_sqlite3_collation_needed' + ] = + Module['asm']['sqlite3_collation_needed']).apply(null, arguments); + }); + + (Module['_sqlite3_get_autocommit'] = + function () { + return (Module['_sqlite3_get_autocommit'] = + Module['asm']['sqlite3_get_autocommit']).apply(null, arguments); + }); + + (Module[ + '_sqlite3_table_column_metadata' + ] = function () { + return (Module[ + '_sqlite3_table_column_metadata' + ] = + Module['asm']['sqlite3_table_column_metadata']).apply(null, arguments); + }); + + (Module[ + '_sqlite3_extended_result_codes' + ] = function () { + return (Module[ + '_sqlite3_extended_result_codes' + ] = + Module['asm']['sqlite3_extended_result_codes']).apply(null, arguments); + }); + + (Module['_sqlite3_uri_key'] = function () { + return (Module['_sqlite3_uri_key'] = + Module['asm']['sqlite3_uri_key']).apply(null, arguments); + }); + + (Module['_sqlite3_uri_int64'] = function () { + return (Module['_sqlite3_uri_int64'] = + Module['asm']['sqlite3_uri_int64']).apply(null, arguments); + }); + + (Module['_sqlite3_db_name'] = function () { + return (Module['_sqlite3_db_name'] = + Module['asm']['sqlite3_db_name']).apply(null, arguments); + }); + + (Module['_sqlite3_db_filename'] = function () { + return (Module['_sqlite3_db_filename'] = + Module['asm']['sqlite3_db_filename']).apply(null, arguments); + }); + + (Module['_sqlite3_compileoption_used'] = + function () { + return (Module[ + '_sqlite3_compileoption_used' + ] = + Module['asm']['sqlite3_compileoption_used']).apply(null, arguments); + }); + + (Module['_sqlite3_compileoption_get'] = + function () { + return (Module[ + '_sqlite3_compileoption_get' + ] = + Module['asm']['sqlite3_compileoption_get']).apply(null, arguments); + }); + + (Module['_sqlite3session_diff'] = function () { + return (Module['_sqlite3session_diff'] = + Module['asm']['sqlite3session_diff']).apply(null, arguments); + }); + + (Module['_sqlite3session_attach'] = + function () { + return (Module['_sqlite3session_attach'] = + Module['asm']['sqlite3session_attach']).apply(null, arguments); + }); + + (Module['_sqlite3session_create'] = + function () { + return (Module['_sqlite3session_create'] = + Module['asm']['sqlite3session_create']).apply(null, arguments); + }); + + (Module['_sqlite3session_delete'] = + function () { + return (Module['_sqlite3session_delete'] = + Module['asm']['sqlite3session_delete']).apply(null, arguments); + }); + + (Module['_sqlite3session_table_filter'] = + function () { + return (Module[ + '_sqlite3session_table_filter' + ] = + Module['asm']['sqlite3session_table_filter']).apply(null, arguments); + }); + + (Module['_sqlite3session_changeset'] = + function () { + return (Module[ + '_sqlite3session_changeset' + ] = + Module['asm']['sqlite3session_changeset']).apply(null, arguments); + }); + + (Module[ + '_sqlite3session_changeset_strm' + ] = function () { + return (Module[ + '_sqlite3session_changeset_strm' + ] = + Module['asm']['sqlite3session_changeset_strm']).apply(null, arguments); + }); + + (Module[ + '_sqlite3session_patchset_strm' + ] = function () { + return (Module[ + '_sqlite3session_patchset_strm' + ] = + Module['asm']['sqlite3session_patchset_strm']).apply(null, arguments); + }); + + (Module['_sqlite3session_patchset'] = + function () { + return (Module['_sqlite3session_patchset'] = + Module['asm']['sqlite3session_patchset']).apply(null, arguments); + }); + + (Module['_sqlite3session_enable'] = + function () { + return (Module['_sqlite3session_enable'] = + Module['asm']['sqlite3session_enable']).apply(null, arguments); + }); + + (Module['_sqlite3session_indirect'] = + function () { + return (Module['_sqlite3session_indirect'] = + Module['asm']['sqlite3session_indirect']).apply(null, arguments); + }); + + (Module['_sqlite3session_isempty'] = + function () { + return (Module['_sqlite3session_isempty'] = + Module['asm']['sqlite3session_isempty']).apply(null, arguments); + }); + + (Module['_sqlite3session_memory_used'] = + function () { + return (Module[ + '_sqlite3session_memory_used' + ] = + Module['asm']['sqlite3session_memory_used']).apply(null, arguments); + }); + + (Module[ + '_sqlite3session_object_config' + ] = function () { + return (Module[ + '_sqlite3session_object_config' + ] = + Module['asm']['sqlite3session_object_config']).apply(null, arguments); + }); + + (Module[ + '_sqlite3session_changeset_size' + ] = function () { + return (Module[ + '_sqlite3session_changeset_size' + ] = + Module['asm']['sqlite3session_changeset_size']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_start'] = + function () { + return (Module['_sqlite3changeset_start'] = + Module['asm']['sqlite3changeset_start']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_start_v2'] = + function () { + return (Module[ + '_sqlite3changeset_start_v2' + ] = + Module['asm']['sqlite3changeset_start_v2']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_start_strm'] = + function () { + return (Module[ + '_sqlite3changeset_start_strm' + ] = + Module['asm']['sqlite3changeset_start_strm']).apply(null, arguments); + }); + + (Module[ + '_sqlite3changeset_start_v2_strm' + ] = function () { + return (Module[ + '_sqlite3changeset_start_v2_strm' + ] = + Module['asm']['sqlite3changeset_start_v2_strm']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_next'] = + function () { + return (Module['_sqlite3changeset_next'] = + Module['asm']['sqlite3changeset_next']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_op'] = function () { + return (Module['_sqlite3changeset_op'] = + Module['asm']['sqlite3changeset_op']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_pk'] = function () { + return (Module['_sqlite3changeset_pk'] = + Module['asm']['sqlite3changeset_pk']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_old'] = function () { + return (Module['_sqlite3changeset_old'] = + Module['asm']['sqlite3changeset_old']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_new'] = function () { + return (Module['_sqlite3changeset_new'] = + Module['asm']['sqlite3changeset_new']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_conflict'] = + function () { + return (Module[ + '_sqlite3changeset_conflict' + ] = + Module['asm']['sqlite3changeset_conflict']).apply(null, arguments); + }); + + (Module[ + '_sqlite3changeset_fk_conflicts' + ] = function () { + return (Module[ + '_sqlite3changeset_fk_conflicts' + ] = + Module['asm']['sqlite3changeset_fk_conflicts']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_finalize'] = + function () { + return (Module[ + '_sqlite3changeset_finalize' + ] = + Module['asm']['sqlite3changeset_finalize']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_invert'] = + function () { + return (Module['_sqlite3changeset_invert'] = + Module['asm']['sqlite3changeset_invert']).apply(null, arguments); + }); + + (Module[ + '_sqlite3changeset_invert_strm' + ] = function () { + return (Module[ + '_sqlite3changeset_invert_strm' + ] = + Module['asm']['sqlite3changeset_invert_strm']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_apply_v2'] = + function () { + return (Module[ + '_sqlite3changeset_apply_v2' + ] = + Module['asm']['sqlite3changeset_apply_v2']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_apply'] = + function () { + return (Module['_sqlite3changeset_apply'] = + Module['asm']['sqlite3changeset_apply']).apply(null, arguments); + }); + + (Module[ + '_sqlite3changeset_apply_v2_strm' + ] = function () { + return (Module[ + '_sqlite3changeset_apply_v2_strm' + ] = + Module['asm']['sqlite3changeset_apply_v2_strm']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_apply_strm'] = + function () { + return (Module[ + '_sqlite3changeset_apply_strm' + ] = + Module['asm']['sqlite3changeset_apply_strm']).apply(null, arguments); + }); + + (Module['_sqlite3changegroup_new'] = + function () { + return (Module['_sqlite3changegroup_new'] = + Module['asm']['sqlite3changegroup_new']).apply(null, arguments); + }); + + (Module['_sqlite3changegroup_add'] = + function () { + return (Module['_sqlite3changegroup_add'] = + Module['asm']['sqlite3changegroup_add']).apply(null, arguments); + }); + + (Module['_sqlite3changegroup_output'] = + function () { + return (Module[ + '_sqlite3changegroup_output' + ] = + Module['asm']['sqlite3changegroup_output']).apply(null, arguments); + }); + + (Module['_sqlite3changegroup_add_strm'] = + function () { + return (Module[ + '_sqlite3changegroup_add_strm' + ] = + Module['asm']['sqlite3changegroup_add_strm']).apply(null, arguments); + }); + + (Module[ + '_sqlite3changegroup_output_strm' + ] = function () { + return (Module[ + '_sqlite3changegroup_output_strm' + ] = + Module['asm']['sqlite3changegroup_output_strm']).apply(null, arguments); + }); + + (Module['_sqlite3changegroup_delete'] = + function () { + return (Module[ + '_sqlite3changegroup_delete' + ] = + Module['asm']['sqlite3changegroup_delete']).apply(null, arguments); + }); + + (Module['_sqlite3changeset_concat'] = + function () { + return (Module['_sqlite3changeset_concat'] = + Module['asm']['sqlite3changeset_concat']).apply(null, arguments); + }); + + (Module[ + '_sqlite3changeset_concat_strm' + ] = function () { + return (Module[ + '_sqlite3changeset_concat_strm' + ] = + Module['asm']['sqlite3changeset_concat_strm']).apply(null, arguments); + }); + + (Module['_sqlite3session_config'] = + function () { + return (Module['_sqlite3session_config'] = + Module['asm']['sqlite3session_config']).apply(null, arguments); + }); + + (Module['_sqlite3_sourceid'] = function () { + return (Module['_sqlite3_sourceid'] = + Module['asm']['sqlite3_sourceid']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_pstack_ptr'] = + function () { + return (Module[ + '_sqlite3__wasm_pstack_ptr' + ] = + Module['asm']['sqlite3__wasm_pstack_ptr']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_pstack_restore' + ] = function () { + return (Module[ + '_sqlite3__wasm_pstack_restore' + ] = + Module['asm']['sqlite3__wasm_pstack_restore']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_pstack_alloc'] = + function () { + return (Module[ + '_sqlite3__wasm_pstack_alloc' + ] = + Module['asm']['sqlite3__wasm_pstack_alloc']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_pstack_remaining' + ] = function () { + return (Module[ + '_sqlite3__wasm_pstack_remaining' + ] = + Module['asm']['sqlite3__wasm_pstack_remaining']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_pstack_quota'] = + function () { + return (Module[ + '_sqlite3__wasm_pstack_quota' + ] = + Module['asm']['sqlite3__wasm_pstack_quota']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_db_error'] = + function () { + return (Module['_sqlite3__wasm_db_error'] = + Module['asm']['sqlite3__wasm_db_error']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_test_struct'] = + function () { + return (Module[ + '_sqlite3__wasm_test_struct' + ] = + Module['asm']['sqlite3__wasm_test_struct']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_enum_json'] = + function () { + return (Module['_sqlite3__wasm_enum_json'] = + Module['asm']['sqlite3__wasm_enum_json']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_vfs_unlink'] = + function () { + return (Module[ + '_sqlite3__wasm_vfs_unlink' + ] = + Module['asm']['sqlite3__wasm_vfs_unlink']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_db_vfs'] = function () { + return (Module['_sqlite3__wasm_db_vfs'] = + Module['asm']['sqlite3__wasm_db_vfs']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_db_reset'] = + function () { + return (Module['_sqlite3__wasm_db_reset'] = + Module['asm']['sqlite3__wasm_db_reset']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_db_export_chunked' + ] = function () { + return (Module[ + '_sqlite3__wasm_db_export_chunked' + ] = + Module['asm']['sqlite3__wasm_db_export_chunked']).apply( + null, + arguments, + ); + }); + + (Module['_sqlite3__wasm_db_serialize'] = + function () { + return (Module[ + '_sqlite3__wasm_db_serialize' + ] = + Module['asm']['sqlite3__wasm_db_serialize']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_vfs_create_file' + ] = function () { + return (Module[ + '_sqlite3__wasm_vfs_create_file' + ] = + Module['asm']['sqlite3__wasm_vfs_create_file']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_posix_create_file' + ] = function () { + return (Module[ + '_sqlite3__wasm_posix_create_file' + ] = + Module['asm']['sqlite3__wasm_posix_create_file']).apply( + null, + arguments, + ); + }); + + (Module[ + '_sqlite3__wasm_kvvfsMakeKeyOnPstack' + ] = function () { + return (Module[ + '_sqlite3__wasm_kvvfsMakeKeyOnPstack' + ] = + Module['asm']['sqlite3__wasm_kvvfsMakeKeyOnPstack']).apply( + null, + arguments, + ); + }); + + (Module['_sqlite3__wasm_kvvfs_methods'] = + function () { + return (Module[ + '_sqlite3__wasm_kvvfs_methods' + ] = + Module['asm']['sqlite3__wasm_kvvfs_methods']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_vtab_config'] = + function () { + return (Module[ + '_sqlite3__wasm_vtab_config' + ] = + Module['asm']['sqlite3__wasm_vtab_config']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_db_config_ip'] = + function () { + return (Module[ + '_sqlite3__wasm_db_config_ip' + ] = + Module['asm']['sqlite3__wasm_db_config_ip']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_db_config_pii'] = + function () { + return (Module[ + '_sqlite3__wasm_db_config_pii' + ] = + Module['asm']['sqlite3__wasm_db_config_pii']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_db_config_s'] = + function () { + return (Module[ + '_sqlite3__wasm_db_config_s' + ] = + Module['asm']['sqlite3__wasm_db_config_s']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_config_i'] = + function () { + return (Module['_sqlite3__wasm_config_i'] = + Module['asm']['sqlite3__wasm_config_i']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_config_ii'] = + function () { + return (Module['_sqlite3__wasm_config_ii'] = + Module['asm']['sqlite3__wasm_config_ii']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_config_j'] = + function () { + return (Module['_sqlite3__wasm_config_j'] = + Module['asm']['sqlite3__wasm_config_j']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_qfmt_token'] = + function () { + return (Module[ + '_sqlite3__wasm_qfmt_token' + ] = + Module['asm']['sqlite3__wasm_qfmt_token']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_init_wasmfs'] = + function () { + return (Module[ + '_sqlite3__wasm_init_wasmfs' + ] = + Module['asm']['sqlite3__wasm_init_wasmfs']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_test_intptr'] = + function () { + return (Module[ + '_sqlite3__wasm_test_intptr' + ] = + Module['asm']['sqlite3__wasm_test_intptr']).apply(null, arguments); + }); + + (Module['_sqlite3__wasm_test_voidptr'] = + function () { + return (Module[ + '_sqlite3__wasm_test_voidptr' + ] = + Module['asm']['sqlite3__wasm_test_voidptr']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_test_int64_max' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_int64_max' + ] = + Module['asm']['sqlite3__wasm_test_int64_max']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_test_int64_min' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_int64_min' + ] = + Module['asm']['sqlite3__wasm_test_int64_min']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_test_int64_times2' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_int64_times2' + ] = + Module['asm']['sqlite3__wasm_test_int64_times2']).apply( + null, + arguments, + ); + }); + + (Module[ + '_sqlite3__wasm_test_int64_minmax' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_int64_minmax' + ] = + Module['asm']['sqlite3__wasm_test_int64_minmax']).apply( + null, + arguments, + ); + }); + + (Module['_sqlite3__wasm_test_int64ptr'] = + function () { + return (Module[ + '_sqlite3__wasm_test_int64ptr' + ] = + Module['asm']['sqlite3__wasm_test_int64ptr']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_test_stack_overflow' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_stack_overflow' + ] = + Module['asm']['sqlite3__wasm_test_stack_overflow']).apply( + null, + arguments, + ); + }); + + (Module[ + '_sqlite3__wasm_test_str_hello' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_str_hello' + ] = + Module['asm']['sqlite3__wasm_test_str_hello']).apply(null, arguments); + }); + + (Module[ + '_sqlite3__wasm_SQLTester_strglob' + ] = function () { + return (Module[ + '_sqlite3__wasm_SQLTester_strglob' + ] = + Module['asm']['sqlite3__wasm_SQLTester_strglob']).apply( + null, + arguments, + ); + }); + + var _malloc = (Module['_malloc'] = function () { + return (_malloc = Module['_malloc'] = Module['asm']['malloc']).apply( + null, + arguments, + ); + }); + + (Module['_free'] = function () { + return (Module['_free'] = Module['asm']['free']).apply( + null, + arguments, + ); + }); + + (Module['_realloc'] = function () { + return (Module['_realloc'] = Module['asm']['realloc']).apply( + null, + arguments, + ); + }); + + var _emscripten_builtin_memalign = (Module['_emscripten_builtin_memalign'] = + function () { + return (_emscripten_builtin_memalign = Module[ + '_emscripten_builtin_memalign' + ] = + Module['asm']['emscripten_builtin_memalign']).apply(null, arguments); + }); + + (Module['stackSave'] = function () { + return (Module['stackSave'] = + Module['asm']['stackSave']).apply(null, arguments); + }); + + (Module['stackRestore'] = function () { + return (Module['stackRestore'] = + Module['asm']['stackRestore']).apply(null, arguments); + }); + + (Module['stackAlloc'] = function () { + return (Module['stackAlloc'] = + Module['asm']['stackAlloc']).apply(null, arguments); + }); + + Module['wasmMemory'] = wasmMemory; + + var calledRun; + + dependenciesFulfilled = function runCaller() { + if (!calledRun) run(); + if (!calledRun) dependenciesFulfilled = runCaller; + }; + + function run(args) { + + if (runDependencies > 0) { + return; + } + + preRun(); + + if (runDependencies > 0) { + return; + } + + function doRun() { + if (calledRun) return; + calledRun = true; + Module['calledRun'] = true; + + if (ABORT) return; + + initRuntime(); + + readyPromiseResolve(Module); + if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); + + postRun(); + } + + if (Module['setStatus']) { + Module['setStatus']('Running...'); + setTimeout(function () { + setTimeout(function () { + Module['setStatus'](''); + }, 1); + doRun(); + }, 1); + } else { + doRun(); + } + } + + if (Module['preInit']) { + if (typeof Module['preInit'] == 'function') + Module['preInit'] = [Module['preInit']]; + while (Module['preInit'].length > 0) { + Module['preInit'].pop()(); + } + } + + run(); + + if (!Module.postRun) Module.postRun = []; + Module.postRun.push(function (Module) { + globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( + apiConfig = globalThis.sqlite3ApiConfig || + sqlite3ApiBootstrap.defaultConfig, + ) { + if (sqlite3ApiBootstrap.sqlite3) { + (sqlite3ApiBootstrap.sqlite3.config || console).warn( + 'sqlite3ApiBootstrap() called multiple times.', + 'Config and external initializers are ignored on calls after the first.', + ); + return sqlite3ApiBootstrap.sqlite3; + } + const config = Object.assign( + Object.create(null), + { + exports: undefined, + memory: undefined, + bigIntEnabled: (() => { + if ('undefined' !== typeof Module) { + if (!!Module.HEAPU64) return true; + } + return !!globalThis.BigInt64Array; + })(), + debug: console.debug.bind(console), + warn: console.warn.bind(console), + error: console.error.bind(console), + log: console.log.bind(console), + wasmfsOpfsDir: '/opfs', + + useStdAlloc: false, + }, + apiConfig || {}, + ); + + Object.assign( + config, + { + allocExportName: config.useStdAlloc ? 'malloc' : 'sqlite3_malloc', + deallocExportName: config.useStdAlloc ? 'free' : 'sqlite3_free', + reallocExportName: config.useStdAlloc + ? 'realloc' + : 'sqlite3_realloc', + }, + config, + ); + + ['exports', 'memory', 'wasmfsOpfsDir'].forEach((k) => { + if ('function' === typeof config[k]) { + config[k] = config[k](); + } + }); + + delete globalThis.sqlite3ApiConfig; + delete sqlite3ApiBootstrap.defaultConfig; + + const capi = Object.create(null); + + const wasm = Object.create(null); + + const __rcStr = (rc) => { + return ( + (capi.sqlite3_js_rc_str && capi.sqlite3_js_rc_str(rc)) || + 'Unknown result code #' + rc + ); + }; + + const __isInt = (n) => 'number' === typeof n && n === (n | 0); + + class SQLite3Error extends Error { + constructor(...args) { + let rc; + if (args.length) { + if (__isInt(args[0])) { + rc = args[0]; + if (1 === args.length) { + super(__rcStr(args[0])); + } else { + const rcStr = __rcStr(rc); + if ('object' === typeof args[1]) { + super(rcStr, args[1]); + } else { + args[0] = rcStr + ':'; + super(args.join(' ')); + } + } + } else { + if (2 === args.length && 'object' === typeof args[1]) { + super(...args); + } else { + super(args.join(' ')); + } + } + } + this.resultCode = rc || capi.SQLITE_ERROR; + this.name = 'SQLite3Error'; + } + } + + SQLite3Error.toss = (...args) => { + throw new SQLite3Error(...args); + }; + const toss3 = SQLite3Error.toss; + + if (config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)) { + toss3( + "config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.", + ); + } + + const isInt32 = (n) => { + return ( + 'bigint' !== typeof n && + !!(n === (n | 0) && n <= 2147483647 && n >= -2147483648) + ); + }; + + const bigIntFits64 = function f(b) { + if (!f._max) { + f._max = BigInt('0x7fffffffffffffff'); + f._min = ~f._max; + } + return b >= f._min && b <= f._max; + }; + + const bigIntFits32 = (b) => b >= -0x7fffffffn - 1n && b <= 0x7fffffffn; + + const bigIntFitsDouble = function f(b) { + if (!f._min) { + f._min = Number.MIN_SAFE_INTEGER; + f._max = Number.MAX_SAFE_INTEGER; + } + return b >= f._min && b <= f._max; + }; + + const isTypedArray = (v) => { + return v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT) + ? v + : false; + }; + + const __SAB = + 'undefined' === typeof SharedArrayBuffer + ? function () {} + : SharedArrayBuffer; + + const isSharedTypedArray = (aTypedArray) => + aTypedArray.buffer instanceof __SAB; + + const typedArrayPart = (aTypedArray, begin, end) => { + return isSharedTypedArray(aTypedArray) + ? aTypedArray.slice(begin, end) + : aTypedArray.subarray(begin, end); + }; + + const isBindableTypedArray = (v) => { + return ( + v && + (v instanceof Uint8Array || + v instanceof Int8Array || + v instanceof ArrayBuffer) + ); + }; + + const isSQLableTypedArray = (v) => { + return ( + v && + (v instanceof Uint8Array || + v instanceof Int8Array || + v instanceof ArrayBuffer) + ); + }; + + const affirmBindableTypedArray = (v) => { + return ( + isBindableTypedArray(v) || + toss3('Value is not of a supported TypedArray type.') + ); + }; + + const utf8Decoder = new TextDecoder('utf-8'); + + const typedArrayToString = function (typedArray, begin, end) { + return utf8Decoder.decode(typedArrayPart(typedArray, begin, end)); + }; + + const flexibleString = function (v) { + if (isSQLableTypedArray(v)) { + return typedArrayToString( + v instanceof ArrayBuffer ? new Uint8Array(v) : v, + ); + } else if (Array.isArray(v)) return v.join(''); + else if (wasm.isPtr(v)) v = wasm.cstrToJs(v); + return v; + }; + + class WasmAllocError extends Error { + constructor(...args) { + if (2 === args.length && 'object' === typeof args[1]) { + super(...args); + } else if (args.length) { + super(args.join(' ')); + } else { + super('Allocation failed.'); + } + this.resultCode = capi.SQLITE_NOMEM; + this.name = 'WasmAllocError'; + } + } + + WasmAllocError.toss = (...args) => { + throw new WasmAllocError(...args); + }; + + Object.assign(capi, { + sqlite3_bind_blob: undefined, + + sqlite3_bind_text: undefined, + + sqlite3_create_function_v2: ( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xFunc, + xStep, + xFinal, + xDestroy, + ) => {}, + + sqlite3_create_function: ( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xFunc, + xStep, + xFinal, + ) => {}, + + sqlite3_create_window_function: ( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xStep, + xFinal, + xValue, + xInverse, + xDestroy, + ) => {}, + + sqlite3_prepare_v3: ( + dbPtr, + sql, + sqlByteLen, + prepFlags, + stmtPtrPtr, + strPtrPtr, + ) => {}, + + sqlite3_prepare_v2: ( + dbPtr, + sql, + sqlByteLen, + stmtPtrPtr, + strPtrPtr, + ) => {}, + + sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg) => {}, + + sqlite3_randomness: (n, outPtr) => {}, + }); + + const util = { + affirmBindableTypedArray, + flexibleString, + bigIntFits32, + bigIntFits64, + bigIntFitsDouble, + isBindableTypedArray, + isInt32, + isSQLableTypedArray, + isTypedArray, + typedArrayToString, + isUIThread: () => + globalThis.window === globalThis && !!globalThis.document, + + isSharedTypedArray, + toss: function (...args) { + throw new Error(args.join(' ')); + }, + toss3, + typedArrayPart, + + affirmDbHeader: function (bytes) { + if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); + const header = 'SQLite format 3'; + if (header.length > bytes.byteLength) { + toss3('Input does not contain an SQLite3 database header.'); + } + for (let i = 0; i < header.length; ++i) { + if (header.charCodeAt(i) !== bytes[i]) { + toss3('Input does not contain an SQLite3 database header.'); + } + } + }, + + affirmIsDb: function (bytes) { + if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); + const n = bytes.byteLength; + if (n < 512 || n % 512 !== 0) { + toss3('Byte array size', n, 'is invalid for an SQLite3 db.'); + } + util.affirmDbHeader(bytes); + }, + }; + + Object.assign(wasm, { + ptrSizeof: config.wasmPtrSizeof || 4, + + ptrIR: config.wasmPtrIR || 'i32', + + bigIntEnabled: !!config.bigIntEnabled, + + exports: + config.exports || + toss3('Missing API config.exports (WASM module exports).'), + + memory: + config.memory || + config.exports['memory'] || + toss3( + 'API config object requires a WebAssembly.Memory object', + 'in either config.exports.memory (exported)', + 'or config.memory (imported).', + ), + + alloc: undefined, + + realloc: undefined, + + dealloc: undefined, + }); + + wasm.allocFromTypedArray = function (srcTypedArray) { + if (srcTypedArray instanceof ArrayBuffer) { + srcTypedArray = new Uint8Array(srcTypedArray); + } + affirmBindableTypedArray(srcTypedArray); + const pRet = wasm.alloc(srcTypedArray.byteLength || 1); + wasm + .heapForSize(srcTypedArray.constructor) + .set(srcTypedArray.byteLength ? srcTypedArray : [0], pRet); + return pRet; + }; + + { + const keyAlloc = config.allocExportName, + keyDealloc = config.deallocExportName, + keyRealloc = config.reallocExportName; + for (const key of [keyAlloc, keyDealloc, keyRealloc]) { + const f = wasm.exports[key]; + if (!(f instanceof Function)) + toss3('Missing required exports[', key, '] function.'); + } + + wasm.alloc = function f(n) { + return ( + f.impl(n) || + WasmAllocError.toss('Failed to allocate', n, ' bytes.') + ); + }; + wasm.alloc.impl = wasm.exports[keyAlloc]; + wasm.realloc = function f(m, n) { + const m2 = f.impl(m, n); + return n + ? m2 || WasmAllocError.toss('Failed to reallocate', n, ' bytes.') + : 0; + }; + wasm.realloc.impl = wasm.exports[keyRealloc]; + wasm.dealloc = wasm.exports[keyDealloc]; + } + + wasm.compileOptionUsed = function f(optName) { + if (!arguments.length) { + if (f._result) return f._result; + else if (!f._opt) { + f._rx = /^([^=]+)=(.+)/; + f._rxInt = /^-?\d+$/; + f._opt = function (opt, rv) { + const m = f._rx.exec(opt); + rv[0] = m ? m[1] : opt; + rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true; + }; + } + const rc = {}, + ov = [0, 0]; + let i = 0, + k; + while ((k = capi.sqlite3_compileoption_get(i++))) { + f._opt(k, ov); + rc[ov[0]] = ov[1]; + } + return (f._result = rc); + } else if (Array.isArray(optName)) { + const rc = {}; + optName.forEach((v) => { + rc[v] = capi.sqlite3_compileoption_used(v); + }); + return rc; + } else if ('object' === typeof optName) { + Object.keys(optName).forEach((k) => { + optName[k] = capi.sqlite3_compileoption_used(k); + }); + return optName; + } + return 'string' === typeof optName + ? !!capi.sqlite3_compileoption_used(optName) + : false; + }; + + wasm.pstack = Object.assign(Object.create(null), { + restore: wasm.exports.sqlite3__wasm_pstack_restore, + + alloc: function (n) { + if ('string' === typeof n && !(n = wasm.sizeofIR(n))) { + WasmAllocError.toss( + 'Invalid value for pstack.alloc(', + arguments[0], + ')', + ); + } + return ( + wasm.exports.sqlite3__wasm_pstack_alloc(n) || + WasmAllocError.toss( + 'Could not allocate', + n, + 'bytes from the pstack.', + ) + ); + }, + + allocChunks: function (n, sz) { + if ('string' === typeof sz && !(sz = wasm.sizeofIR(sz))) { + WasmAllocError.toss( + 'Invalid size value for allocChunks(', + arguments[1], + ')', + ); + } + const mem = wasm.pstack.alloc(n * sz); + const rc = []; + let i = 0, + offset = 0; + for (; i < n; ++i, offset += sz) rc.push(mem + offset); + return rc; + }, + + allocPtr: (n = 1, safePtrSize = true) => { + return 1 === n + ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof) + : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof); + }, + + call: function (f) { + const stackPos = wasm.pstack.pointer; + try { + return f(sqlite3); + } finally { + wasm.pstack.restore(stackPos); + } + }, + }); + Object.defineProperties(wasm.pstack, { + pointer: { + configurable: false, + iterable: true, + writeable: false, + get: wasm.exports.sqlite3__wasm_pstack_ptr, + }, + + quota: { + configurable: false, + iterable: true, + writeable: false, + get: wasm.exports.sqlite3__wasm_pstack_quota, + }, + + remaining: { + configurable: false, + iterable: true, + writeable: false, + get: wasm.exports.sqlite3__wasm_pstack_remaining, + }, + }); + + capi.sqlite3_randomness = (...args) => { + if ( + 1 === args.length && + util.isTypedArray(args[0]) && + 1 === args[0].BYTES_PER_ELEMENT + ) { + const ta = args[0]; + if (0 === ta.byteLength) { + wasm.exports.sqlite3_randomness(0, 0); + return ta; + } + const stack = wasm.pstack.pointer; + try { + let n = ta.byteLength, + offset = 0; + const r = wasm.exports.sqlite3_randomness; + const heap = wasm.heap8u(); + const nAlloc = n < 512 ? n : 512; + const ptr = wasm.pstack.alloc(nAlloc); + do { + const j = n > nAlloc ? nAlloc : n; + r(j, ptr); + ta.set(typedArrayPart(heap, ptr, ptr + j), offset); + n -= j; + offset += j; + } while (n > 0); + } catch (e) { + console.error( + 'Highly unexpected (and ignored!) ' + + 'exception in sqlite3_randomness():', + e, + ); + } finally { + wasm.pstack.restore(stack); + } + return ta; + } + wasm.exports.sqlite3_randomness(...args); + }; + + let __wasmfsOpfsDir = undefined; + + capi.sqlite3_wasmfs_opfs_dir = function () { + if (undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir; + + const pdir = config.wasmfsOpfsDir; + if ( + !pdir || + !globalThis.FileSystemHandle || + !globalThis.FileSystemDirectoryHandle || + !globalThis.FileSystemFileHandle + ) { + return (__wasmfsOpfsDir = ''); + } + try { + if ( + pdir && + 0 === + wasm.xCallWrapped( + 'sqlite3__wasm_init_wasmfs', + 'i32', + ['string'], + pdir, + ) + ) { + return (__wasmfsOpfsDir = pdir); + } else { + return (__wasmfsOpfsDir = ''); + } + } catch (e) { + return (__wasmfsOpfsDir = ''); + } + }; + + capi.sqlite3_wasmfs_filename_is_persistent = function (name) { + const p = capi.sqlite3_wasmfs_opfs_dir(); + return p && name ? name.startsWith(p + '/') : false; + }; + + capi.sqlite3_js_db_uses_vfs = function (pDb, vfsName, dbName = 0) { + try { + const pK = capi.sqlite3_vfs_find(vfsName); + if (!pK) return false; + else if (!pDb) { + return pK === capi.sqlite3_vfs_find(0) ? pK : false; + } else { + return pK === capi.sqlite3_js_db_vfs(pDb, dbName) ? pK : false; + } + } catch (e) { + return false; + } + }; + + capi.sqlite3_js_vfs_list = function () { + const rc = []; + let pVfs = capi.sqlite3_vfs_find(0); + while (pVfs) { + const oVfs = new capi.sqlite3_vfs(pVfs); + rc.push(wasm.cstrToJs(oVfs.$zName)); + pVfs = oVfs.$pNext; + oVfs.dispose(); + } + return rc; + }; + + capi.sqlite3_js_db_export = function (pDb, schema = 0) { + pDb = wasm.xWrap.testConvertArg('sqlite3*', pDb); + if (!pDb) toss3('Invalid sqlite3* argument.'); + if (!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.'); + const scope = wasm.scopedAllocPush(); + let pOut; + try { + const pSize = wasm.scopedAlloc(8 + wasm.ptrSizeof); + const ppOut = pSize + 8; + + const zSchema = schema + ? wasm.isPtr(schema) + ? schema + : wasm.scopedAllocCString('' + schema) + : 0; + let rc = wasm.exports.sqlite3__wasm_db_serialize( + pDb, + zSchema, + ppOut, + pSize, + 0, + ); + if (rc) { + toss3( + 'Database serialization failed with code', + sqlite3.capi.sqlite3_js_rc_str(rc), + ); + } + pOut = wasm.peekPtr(ppOut); + const nOut = wasm.peek(pSize, 'i64'); + rc = nOut + ? wasm.heap8u().slice(pOut, pOut + Number(nOut)) + : new Uint8Array(); + return rc; + } finally { + if (pOut) wasm.exports.sqlite3_free(pOut); + wasm.scopedAllocPop(scope); + } + }; + + capi.sqlite3_js_db_vfs = (dbPointer, dbName = 0) => + util.sqlite3__wasm_db_vfs(dbPointer, dbName); + + capi.sqlite3_js_aggregate_context = (pCtx, n) => { + return ( + capi.sqlite3_aggregate_context(pCtx, n) || + (n + ? WasmAllocError.toss( + 'Cannot allocate', + n, + 'bytes for sqlite3_aggregate_context()', + ) + : 0) + ); + }; + + capi.sqlite3_js_posix_create_file = function (filename, data, dataLen) { + let pData; + if (data && wasm.isPtr(data)) { + pData = data; + } else if ( + data instanceof ArrayBuffer || + data instanceof Uint8Array + ) { + pData = wasm.allocFromTypedArray(data); + if (arguments.length < 3 || !util.isInt32(dataLen) || dataLen < 0) { + dataLen = data.byteLength; + } + } else { + SQLite3Error.toss( + 'Invalid 2nd argument for sqlite3_js_posix_create_file().', + ); + } + try { + if (!util.isInt32(dataLen) || dataLen < 0) { + SQLite3Error.toss( + 'Invalid 3rd argument for sqlite3_js_posix_create_file().', + ); + } + const rc = util.sqlite3__wasm_posix_create_file( + filename, + pData, + dataLen, + ); + if (rc) + SQLite3Error.toss( + 'Creation of file failed with sqlite3 result code', + capi.sqlite3_js_rc_str(rc), + ); + } finally { + wasm.dealloc(pData); + } + }; + + capi.sqlite3_js_vfs_create_file = function ( + vfs, + filename, + data, + dataLen, + ) { + config.warn( + 'sqlite3_js_vfs_create_file() is deprecated and', + 'should be avoided because it can lead to C-level crashes.', + 'See its documentation for alternative options.', + ); + let pData; + if (data) { + if (wasm.isPtr(data)) { + pData = data; + } else if (data instanceof ArrayBuffer) { + data = new Uint8Array(data); + } + if (data instanceof Uint8Array) { + pData = wasm.allocFromTypedArray(data); + if ( + arguments.length < 4 || + !util.isInt32(dataLen) || + dataLen < 0 + ) { + dataLen = data.byteLength; + } + } else { + SQLite3Error.toss( + 'Invalid 3rd argument type for sqlite3_js_vfs_create_file().', + ); + } + } else { + pData = 0; + } + if (!util.isInt32(dataLen) || dataLen < 0) { + wasm.dealloc(pData); + SQLite3Error.toss( + 'Invalid 4th argument for sqlite3_js_vfs_create_file().', + ); + } + try { + const rc = util.sqlite3__wasm_vfs_create_file( + vfs, + filename, + pData, + dataLen, + ); + if (rc) + SQLite3Error.toss( + 'Creation of file failed with sqlite3 result code', + capi.sqlite3_js_rc_str(rc), + ); + } finally { + wasm.dealloc(pData); + } + }; + + capi.sqlite3_js_sql_to_string = (sql) => { + if ('string' === typeof sql) { + return sql; + } + const x = flexibleString(v); + return x === v ? undefined : x; + }; + + if (util.isUIThread()) { + const __kvvfsInfo = function (which) { + const rc = Object.create(null); + rc.prefix = 'kvvfs-' + which; + rc.stores = []; + if ('session' === which || '' === which) + rc.stores.push(globalThis.sessionStorage); + if ('local' === which || '' === which) + rc.stores.push(globalThis.localStorage); + return rc; + }; + + capi.sqlite3_js_kvvfs_clear = function (which = '') { + let rc = 0; + const kvinfo = __kvvfsInfo(which); + kvinfo.stores.forEach((s) => { + const toRm = []; + let i; + for (i = 0; i < s.length; ++i) { + const k = s.key(i); + if (k.startsWith(kvinfo.prefix)) toRm.push(k); + } + toRm.forEach((kk) => s.removeItem(kk)); + rc += toRm.length; + }); + return rc; + }; + + capi.sqlite3_js_kvvfs_size = function (which = '') { + let sz = 0; + const kvinfo = __kvvfsInfo(which); + kvinfo.stores.forEach((s) => { + let i; + for (i = 0; i < s.length; ++i) { + const k = s.key(i); + if (k.startsWith(kvinfo.prefix)) { + sz += k.length; + sz += s.getItem(k).length; + } + } + }); + return sz * 2; + }; + } + + capi.sqlite3_db_config = function (pDb, op, ...args) { + if (!this.s) { + this.s = wasm.xWrap('sqlite3__wasm_db_config_s', 'int', [ + 'sqlite3*', + 'int', + 'string:static', + ]); + this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int', [ + 'sqlite3*', + 'int', + '*', + 'int', + 'int', + ]); + this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip', 'int', [ + 'sqlite3*', + 'int', + 'int', + '*', + ]); + } + switch (op) { + case capi.SQLITE_DBCONFIG_ENABLE_FKEY: + case capi.SQLITE_DBCONFIG_ENABLE_TRIGGER: + case capi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: + case capi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: + case capi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: + case capi.SQLITE_DBCONFIG_ENABLE_QPSG: + case capi.SQLITE_DBCONFIG_TRIGGER_EQP: + case capi.SQLITE_DBCONFIG_RESET_DATABASE: + case capi.SQLITE_DBCONFIG_DEFENSIVE: + case capi.SQLITE_DBCONFIG_WRITABLE_SCHEMA: + case capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: + case capi.SQLITE_DBCONFIG_DQS_DML: + case capi.SQLITE_DBCONFIG_DQS_DDL: + case capi.SQLITE_DBCONFIG_ENABLE_VIEW: + case capi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: + case capi.SQLITE_DBCONFIG_TRUSTED_SCHEMA: + case capi.SQLITE_DBCONFIG_STMT_SCANSTATUS: + case capi.SQLITE_DBCONFIG_REVERSE_SCANORDER: + return this.ip(pDb, op, args[0], args[1] || 0); + case capi.SQLITE_DBCONFIG_LOOKASIDE: + return this.pii(pDb, op, args[0], args[1], args[2]); + case capi.SQLITE_DBCONFIG_MAINDBNAME: + return this.s(pDb, op, args[0]); + default: + return capi.SQLITE_MISUSE; + } + }.bind(Object.create(null)); + + capi.sqlite3_value_to_js = function ( + pVal, + throwIfCannotConvert = true, + ) { + let arg; + const valType = capi.sqlite3_value_type(pVal); + switch (valType) { + case capi.SQLITE_INTEGER: + if (wasm.bigIntEnabled) { + arg = capi.sqlite3_value_int64(pVal); + if (util.bigIntFitsDouble(arg)) arg = Number(arg); + } else arg = capi.sqlite3_value_double(pVal); + break; + case capi.SQLITE_FLOAT: + arg = capi.sqlite3_value_double(pVal); + break; + case capi.SQLITE_TEXT: + arg = capi.sqlite3_value_text(pVal); + break; + case capi.SQLITE_BLOB: { + const n = capi.sqlite3_value_bytes(pVal); + const pBlob = capi.sqlite3_value_blob(pVal); + if (n && !pBlob) + sqlite3.WasmAllocError.toss( + 'Cannot allocate memory for blob argument of', + n, + 'byte(s)', + ); + arg = n ? wasm.heap8u().slice(pBlob, pBlob + Number(n)) : null; + break; + } + case capi.SQLITE_NULL: + arg = null; + break; + default: + if (throwIfCannotConvert) { + toss3( + capi.SQLITE_MISMATCH, + 'Unhandled sqlite3_value_type():', + valType, + ); + } + arg = undefined; + } + return arg; + }; + + capi.sqlite3_values_to_js = function ( + argc, + pArgv, + throwIfCannotConvert = true, + ) { + let i; + const tgt = []; + for (i = 0; i < argc; ++i) { + tgt.push( + capi.sqlite3_value_to_js( + wasm.peekPtr(pArgv + wasm.ptrSizeof * i), + throwIfCannotConvert, + ), + ); + } + return tgt; + }; + + capi.sqlite3_result_error_js = function (pCtx, e) { + if (e instanceof WasmAllocError) { + capi.sqlite3_result_error_nomem(pCtx); + } else { + capi.sqlite3_result_error(pCtx, '' + e, -1); + } + }; + + capi.sqlite3_result_js = function (pCtx, val) { + if (val instanceof Error) { + capi.sqlite3_result_error_js(pCtx, val); + return; + } + try { + switch (typeof val) { + case 'undefined': + break; + case 'boolean': + capi.sqlite3_result_int(pCtx, val ? 1 : 0); + break; + case 'bigint': + if (util.bigIntFits32(val)) { + capi.sqlite3_result_int(pCtx, Number(val)); + } else if (util.bigIntFitsDouble(val)) { + capi.sqlite3_result_double(pCtx, Number(val)); + } else if (wasm.bigIntEnabled) { + if (util.bigIntFits64(val)) + capi.sqlite3_result_int64(pCtx, val); + else + toss3( + 'BigInt value', + val.toString(), + 'is too BigInt for int64.', + ); + } else { + toss3('BigInt value', val.toString(), 'is too BigInt.'); + } + break; + case 'number': { + let f; + if (util.isInt32(val)) { + f = capi.sqlite3_result_int; + } else if ( + wasm.bigIntEnabled && + Number.isInteger(val) && + util.bigIntFits64(BigInt(val)) + ) { + f = capi.sqlite3_result_int64; + } else { + f = capi.sqlite3_result_double; + } + f(pCtx, val); + break; + } + case 'string': { + const [p, n] = wasm.allocCString(val, true); + capi.sqlite3_result_text(pCtx, p, n, capi.SQLITE_WASM_DEALLOC); + break; + } + case 'object': + if (null === val) { + capi.sqlite3_result_null(pCtx); + break; + } else if (util.isBindableTypedArray(val)) { + const pBlob = wasm.allocFromTypedArray(val); + capi.sqlite3_result_blob( + pCtx, + pBlob, + val.byteLength, + capi.SQLITE_WASM_DEALLOC, + ); + break; + } + + default: + toss3( + "Don't not how to handle this UDF result value:", + typeof val, + val, + ); + } + } catch (e) { + capi.sqlite3_result_error_js(pCtx, e); + } + }; + + capi.sqlite3_column_js = function ( + pStmt, + iCol, + throwIfCannotConvert = true, + ) { + const v = capi.sqlite3_column_value(pStmt, iCol); + return 0 === v + ? undefined + : capi.sqlite3_value_to_js(v, throwIfCannotConvert); + }; + + const __newOldValue = function (pObj, iCol, impl) { + impl = capi[impl]; + if (!this.ptr) this.ptr = wasm.allocPtr(); + else wasm.pokePtr(this.ptr, 0); + const rc = impl(pObj, iCol, this.ptr); + if (rc) + return SQLite3Error.toss( + rc, + arguments[2] + '() failed with code ' + rc, + ); + const pv = wasm.peekPtr(this.ptr); + return pv ? capi.sqlite3_value_to_js(pv, true) : undefined; + }.bind(Object.create(null)); + + capi.sqlite3_preupdate_new_js = (pDb, iCol) => + __newOldValue(pDb, iCol, 'sqlite3_preupdate_new'); + + capi.sqlite3_preupdate_old_js = (pDb, iCol) => + __newOldValue(pDb, iCol, 'sqlite3_preupdate_old'); + + capi.sqlite3changeset_new_js = (pChangesetIter, iCol) => + __newOldValue(pChangesetIter, iCol, 'sqlite3changeset_new'); + + capi.sqlite3changeset_old_js = (pChangesetIter, iCol) => + __newOldValue(pChangesetIter, iCol, 'sqlite3changeset_old'); + + const sqlite3 = { + WasmAllocError: WasmAllocError, + SQLite3Error: SQLite3Error, + capi, + util, + wasm, + config, + + version: Object.create(null), + + client: undefined, + + asyncPostInit: async function ff() { + if (ff.isReady instanceof Promise) return ff.isReady; + let lia = sqlite3ApiBootstrap.initializersAsync; + delete sqlite3ApiBootstrap.initializersAsync; + const postInit = async () => { + if (!sqlite3.__isUnderTest) { + delete sqlite3.util; + + delete sqlite3.StructBinder; + } + return sqlite3; + }; + const catcher = (e) => { + config.error('an async sqlite3 initializer failed:', e); + throw e; + }; + if (!lia || !lia.length) { + return (ff.isReady = postInit().catch(catcher)); + } + lia = lia.map((f) => { + return f instanceof Function ? async (x) => f(sqlite3) : f; + }); + lia.push(postInit); + let p = Promise.resolve(sqlite3); + while (lia.length) p = p.then(lia.shift()); + return (ff.isReady = p.catch(catcher)); + }, + + scriptInfo: undefined, + }; + try { + sqlite3ApiBootstrap.initializers.forEach((f) => { + f(sqlite3); + }); + } catch (e) { + console.error('sqlite3 bootstrap initializer threw:', e); + throw e; + } + delete sqlite3ApiBootstrap.initializers; + sqlite3ApiBootstrap.sqlite3 = sqlite3; + return sqlite3; + }; + + globalThis.sqlite3ApiBootstrap.initializers = []; + + globalThis.sqlite3ApiBootstrap.initializersAsync = []; + + globalThis.sqlite3ApiBootstrap.defaultConfig = Object.create(null); + + globalThis.sqlite3ApiBootstrap.sqlite3 = undefined; + + globalThis.WhWasmUtilInstaller = function (target) { + if (undefined === target.bigIntEnabled) { + target.bigIntEnabled = !!globalThis['BigInt64Array']; + } + + const toss = (...args) => { + throw new Error(args.join(' ')); + }; + + if (!target.exports) { + Object.defineProperty(target, 'exports', { + enumerable: true, + configurable: true, + get: () => target.instance && target.instance.exports, + }); + } + + const ptrIR = target.pointerIR || 'i32'; + const ptrSizeof = (target.ptrSizeof = + 'i32' === ptrIR + ? 4 + : 'i64' === ptrIR + ? 8 + : toss('Unhandled ptrSizeof:', ptrIR)); + + const cache = Object.create(null); + + cache.heapSize = 0; + + cache.memory = null; + + cache.freeFuncIndexes = []; + + cache.scopedAlloc = []; + + cache.utf8Decoder = new TextDecoder(); + cache.utf8Encoder = new TextEncoder('utf-8'); + + target.sizeofIR = (n) => { + switch (n) { + case 'i8': + return 1; + case 'i16': + return 2; + case 'i32': + case 'f32': + case 'float': + return 4; + case 'i64': + case 'f64': + case 'double': + return 8; + case '*': + return ptrSizeof; + default: + return ('' + n).endsWith('*') ? ptrSizeof : undefined; + } + }; + + const heapWrappers = function () { + if (!cache.memory) { + cache.memory = + target.memory instanceof WebAssembly.Memory + ? target.memory + : target.exports.memory; + } else if (cache.heapSize === cache.memory.buffer.byteLength) { + return cache; + } + + const b = cache.memory.buffer; + cache.HEAP8 = new Int8Array(b); + cache.HEAP8U = new Uint8Array(b); + cache.HEAP16 = new Int16Array(b); + cache.HEAP16U = new Uint16Array(b); + cache.HEAP32 = new Int32Array(b); + cache.HEAP32U = new Uint32Array(b); + if (target.bigIntEnabled) { + cache.HEAP64 = new BigInt64Array(b); + cache.HEAP64U = new BigUint64Array(b); + } + cache.HEAP32F = new Float32Array(b); + cache.HEAP64F = new Float64Array(b); + cache.heapSize = b.byteLength; + return cache; + }; + + target.heap8 = () => heapWrappers().HEAP8; + + target.heap8u = () => heapWrappers().HEAP8U; + + target.heap16 = () => heapWrappers().HEAP16; + + target.heap16u = () => heapWrappers().HEAP16U; + + target.heap32 = () => heapWrappers().HEAP32; + + target.heap32u = () => heapWrappers().HEAP32U; + + target.heapForSize = function (n, unsigned = true) { + const c = + cache.memory && cache.heapSize === cache.memory.buffer.byteLength + ? cache + : heapWrappers(); + switch (n) { + case Int8Array: + return c.HEAP8; + case Uint8Array: + return c.HEAP8U; + case Int16Array: + return c.HEAP16; + case Uint16Array: + return c.HEAP16U; + case Int32Array: + return c.HEAP32; + case Uint32Array: + return c.HEAP32U; + case 8: + return unsigned ? c.HEAP8U : c.HEAP8; + case 16: + return unsigned ? c.HEAP16U : c.HEAP16; + case 32: + return unsigned ? c.HEAP32U : c.HEAP32; + case 64: + if (c.HEAP64) return unsigned ? c.HEAP64U : c.HEAP64; + break; + default: + if (target.bigIntEnabled) { + if (n === globalThis['BigUint64Array']) return c.HEAP64U; + else if (n === globalThis['BigInt64Array']) return c.HEAP64; + break; + } + } + toss( + 'Invalid heapForSize() size: expecting 8, 16, 32,', + 'or (if BigInt is enabled) 64.', + ); + }; + + target.functionTable = function () { + return target.exports.__indirect_function_table; + }; + + target.functionEntry = function (fptr) { + const ft = target.functionTable(); + return fptr < ft.length ? ft.get(fptr) : undefined; + }; + + target.jsFuncToWasm = function f(func, sig) { + if (!f._) { + f._ = { + sigTypes: Object.assign(Object.create(null), { + i: 'i32', + p: 'i32', + P: 'i32', + s: 'i32', + j: 'i64', + f: 'f32', + d: 'f64', + }), + + typeCodes: Object.assign(Object.create(null), { + f64: 0x7c, + f32: 0x7d, + i64: 0x7e, + i32: 0x7f, + }), + + uleb128Encode: function (tgt, method, n) { + if (n < 128) tgt[method](n); + else tgt[method](n % 128 | 128, n >> 7); + }, + + rxJSig: /^(\w)\((\w*)\)$/, + + sigParams: function (sig) { + const m = f._.rxJSig.exec(sig); + return m ? m[2] : sig.substr(1); + }, + + letterType: (x) => + f._.sigTypes[x] || toss('Invalid signature letter:', x), + + pushSigType: (dest, letter) => + dest.push(f._.typeCodes[f._.letterType(letter)]), + }; + } + if ('string' === typeof func) { + const x = sig; + sig = func; + func = x; + } + const sigParams = f._.sigParams(sig); + const wasmCode = [0x01, 0x60]; + f._.uleb128Encode(wasmCode, 'push', sigParams.length); + for (const x of sigParams) f._.pushSigType(wasmCode, x); + if ('v' === sig[0]) wasmCode.push(0); + else { + wasmCode.push(1); + f._.pushSigType(wasmCode, sig[0]); + } + f._.uleb128Encode(wasmCode, 'unshift', wasmCode.length); + wasmCode.unshift( + 0x00, + 0x61, + 0x73, + 0x6d, + 0x01, + 0x00, + 0x00, + 0x00, + 0x01, + ); + wasmCode.push( + 0x02, + 0x07, + + 0x01, + 0x01, + 0x65, + 0x01, + 0x66, + 0x00, + 0x00, + 0x07, + 0x05, + + 0x01, + 0x01, + 0x66, + 0x00, + 0x00, + ); + return new WebAssembly.Instance( + new WebAssembly.Module(new Uint8Array(wasmCode)), + { + e: { f: func }, + }, + ).exports['f']; + }; + + const __installFunction = function f(func, sig, scoped) { + if (scoped && !cache.scopedAlloc.length) { + toss('No scopedAllocPush() scope is active.'); + } + if ('string' === typeof func) { + const x = sig; + sig = func; + func = x; + } + if ('string' !== typeof sig || !(func instanceof Function)) { + toss( + 'Invalid arguments: expecting (function,signature) ' + + 'or (signature,function).', + ); + } + const ft = target.functionTable(); + const oldLen = ft.length; + let ptr; + while (cache.freeFuncIndexes.length) { + ptr = cache.freeFuncIndexes.pop(); + if (ft.get(ptr)) { + ptr = null; + continue; + } else { + break; + } + } + if (!ptr) { + ptr = oldLen; + ft.grow(1); + } + try { + ft.set(ptr, func); + if (scoped) { + cache.scopedAlloc[cache.scopedAlloc.length - 1].push(ptr); + } + return ptr; + } catch (e) { + if (!(e instanceof TypeError)) { + if (ptr === oldLen) cache.freeFuncIndexes.push(oldLen); + throw e; + } + } + + try { + const fptr = target.jsFuncToWasm(func, sig); + ft.set(ptr, fptr); + if (scoped) { + cache.scopedAlloc[cache.scopedAlloc.length - 1].push(ptr); + } + } catch (e) { + if (ptr === oldLen) cache.freeFuncIndexes.push(oldLen); + throw e; + } + return ptr; + }; + + target.installFunction = (func, sig) => + __installFunction(func, sig, false); + + target.scopedInstallFunction = (func, sig) => + __installFunction(func, sig, true); + + target.uninstallFunction = function (ptr) { + if (!ptr && 0 !== ptr) return undefined; + const fi = cache.freeFuncIndexes; + const ft = target.functionTable(); + fi.push(ptr); + const rc = ft.get(ptr); + ft.set(ptr, null); + return rc; + }; + + target.peek = function f(ptr, type = 'i8') { + if (type.endsWith('*')) type = ptrIR; + const c = + cache.memory && cache.heapSize === cache.memory.buffer.byteLength + ? cache + : heapWrappers(); + const list = Array.isArray(ptr) ? [] : undefined; + let rc; + do { + if (list) ptr = arguments[0].shift(); + switch (type) { + case 'i1': + case 'i8': + rc = c.HEAP8[ptr >> 0]; + break; + case 'i16': + rc = c.HEAP16[ptr >> 1]; + break; + case 'i32': + rc = c.HEAP32[ptr >> 2]; + break; + case 'float': + case 'f32': + rc = c.HEAP32F[ptr >> 2]; + break; + case 'double': + case 'f64': + rc = Number(c.HEAP64F[ptr >> 3]); + break; + case 'i64': + if (target.bigIntEnabled) { + rc = BigInt(c.HEAP64[ptr >> 3]); + break; + } + + default: + toss('Invalid type for peek():', type); + } + if (list) list.push(rc); + } while (list && arguments[0].length); + return list || rc; + }; + + target.poke = function (ptr, value, type = 'i8') { + if (type.endsWith('*')) type = ptrIR; + const c = + cache.memory && cache.heapSize === cache.memory.buffer.byteLength + ? cache + : heapWrappers(); + for (const p of Array.isArray(ptr) ? ptr : [ptr]) { + switch (type) { + case 'i1': + case 'i8': + c.HEAP8[p >> 0] = value; + continue; + case 'i16': + c.HEAP16[p >> 1] = value; + continue; + case 'i32': + c.HEAP32[p >> 2] = value; + continue; + case 'float': + case 'f32': + c.HEAP32F[p >> 2] = value; + continue; + case 'double': + case 'f64': + c.HEAP64F[p >> 3] = value; + continue; + case 'i64': + if (c.HEAP64) { + c.HEAP64[p >> 3] = BigInt(value); + continue; + } + + default: + toss('Invalid type for poke(): ' + type); + } + } + return this; + }; + + target.peekPtr = (...ptr) => + target.peek(1 === ptr.length ? ptr[0] : ptr, ptrIR); + + target.pokePtr = (ptr, value = 0) => target.poke(ptr, value, ptrIR); + + target.peek8 = (...ptr) => + target.peek(1 === ptr.length ? ptr[0] : ptr, 'i8'); + + target.poke8 = (ptr, value) => target.poke(ptr, value, 'i8'); + + target.peek16 = (...ptr) => + target.peek(1 === ptr.length ? ptr[0] : ptr, 'i16'); + + target.poke16 = (ptr, value) => target.poke(ptr, value, 'i16'); + + target.peek32 = (...ptr) => + target.peek(1 === ptr.length ? ptr[0] : ptr, 'i32'); + + target.poke32 = (ptr, value) => target.poke(ptr, value, 'i32'); + + target.peek64 = (...ptr) => + target.peek(1 === ptr.length ? ptr[0] : ptr, 'i64'); + + target.poke64 = (ptr, value) => target.poke(ptr, value, 'i64'); + + target.peek32f = (...ptr) => + target.peek(1 === ptr.length ? ptr[0] : ptr, 'f32'); + + target.poke32f = (ptr, value) => target.poke(ptr, value, 'f32'); + + target.peek64f = (...ptr) => + target.peek(1 === ptr.length ? ptr[0] : ptr, 'f64'); + + target.poke64f = (ptr, value) => target.poke(ptr, value, 'f64'); + + target.getMemValue = target.peek; + + target.getPtrValue = target.peekPtr; + + target.setMemValue = target.poke; + + target.setPtrValue = target.pokePtr; + + target.isPtr32 = (ptr) => + 'number' === typeof ptr && ptr === (ptr | 0) && ptr >= 0; + + target.isPtr = target.isPtr32; + + target.cstrlen = function (ptr) { + if (!ptr || !target.isPtr(ptr)) return null; + const h = heapWrappers().HEAP8U; + let pos = ptr; + for (; h[pos] !== 0; ++pos) {} + return pos - ptr; + }; + + const __SAB = + 'undefined' === typeof SharedArrayBuffer + ? function () {} + : SharedArrayBuffer; + const __utf8Decode = function (arrayBuffer, begin, end) { + return cache.utf8Decoder.decode( + arrayBuffer.buffer instanceof __SAB + ? arrayBuffer.slice(begin, end) + : arrayBuffer.subarray(begin, end), + ); + }; + + target.cstrToJs = function (ptr) { + const n = target.cstrlen(ptr); + return n + ? __utf8Decode(heapWrappers().HEAP8U, ptr, ptr + n) + : null === n + ? n + : ''; + }; + + target.jstrlen = function (str) { + if ('string' !== typeof str) return null; + const n = str.length; + let len = 0; + for (let i = 0; i < n; ++i) { + let u = str.charCodeAt(i); + if (u >= 0xd800 && u <= 0xdfff) { + u = + (0x10000 + ((u & 0x3ff) << 10)) | (str.charCodeAt(++i) & 0x3ff); + } + if (u <= 0x7f) ++len; + else if (u <= 0x7ff) len += 2; + else if (u <= 0xffff) len += 3; + else len += 4; + } + return len; + }; + + target.jstrcpy = function ( + jstr, + tgt, + offset = 0, + maxBytes = -1, + addNul = true, + ) { + if ( + !tgt || + (!(tgt instanceof Int8Array) && !(tgt instanceof Uint8Array)) + ) { + toss('jstrcpy() target must be an Int8Array or Uint8Array.'); + } + if (maxBytes < 0) maxBytes = tgt.length - offset; + if (!(maxBytes > 0) || !(offset >= 0)) return 0; + let i = 0, + max = jstr.length; + const begin = offset, + end = offset + maxBytes - (addNul ? 1 : 0); + for (; i < max && offset < end; ++i) { + let u = jstr.charCodeAt(i); + if (u >= 0xd800 && u <= 0xdfff) { + u = + (0x10000 + ((u & 0x3ff) << 10)) | + (jstr.charCodeAt(++i) & 0x3ff); + } + if (u <= 0x7f) { + if (offset >= end) break; + tgt[offset++] = u; + } else if (u <= 0x7ff) { + if (offset + 1 >= end) break; + tgt[offset++] = 0xc0 | (u >> 6); + tgt[offset++] = 0x80 | (u & 0x3f); + } else if (u <= 0xffff) { + if (offset + 2 >= end) break; + tgt[offset++] = 0xe0 | (u >> 12); + tgt[offset++] = 0x80 | ((u >> 6) & 0x3f); + tgt[offset++] = 0x80 | (u & 0x3f); + } else { + if (offset + 3 >= end) break; + tgt[offset++] = 0xf0 | (u >> 18); + tgt[offset++] = 0x80 | ((u >> 12) & 0x3f); + tgt[offset++] = 0x80 | ((u >> 6) & 0x3f); + tgt[offset++] = 0x80 | (u & 0x3f); + } + } + if (addNul) tgt[offset++] = 0; + return offset - begin; + }; + + target.cstrncpy = function (tgtPtr, srcPtr, n) { + if (!tgtPtr || !srcPtr) + toss('cstrncpy() does not accept NULL strings.'); + if (n < 0) n = target.cstrlen(strPtr) + 1; + else if (!(n > 0)) return 0; + const heap = target.heap8u(); + let i = 0, + ch; + for (; i < n && (ch = heap[srcPtr + i]); ++i) { + heap[tgtPtr + i] = ch; + } + if (i < n) heap[tgtPtr + i++] = 0; + return i; + }; + + target.jstrToUintArray = (str, addNul = false) => { + return cache.utf8Encoder.encode(addNul ? str + '\0' : str); + }; + + const __affirmAlloc = (obj, funcName) => { + if ( + !(obj.alloc instanceof Function) || + !(obj.dealloc instanceof Function) + ) { + toss( + 'Object is missing alloc() and/or dealloc() function(s)', + 'required by', + funcName + '().', + ); + } + }; + + const __allocCStr = function ( + jstr, + returnWithLength, + allocator, + funcName, + ) { + __affirmAlloc(target, funcName); + if ('string' !== typeof jstr) return null; + { + const u = cache.utf8Encoder.encode(jstr), + ptr = allocator(u.length + 1), + heap = heapWrappers().HEAP8U; + heap.set(u, ptr); + heap[ptr + u.length] = 0; + return returnWithLength ? [ptr, u.length] : ptr; + } + }; + + target.allocCString = (jstr, returnWithLength = false) => + __allocCStr(jstr, returnWithLength, target.alloc, 'allocCString()'); + + target.scopedAllocPush = function () { + __affirmAlloc(target, 'scopedAllocPush'); + const a = []; + cache.scopedAlloc.push(a); + return a; + }; + + target.scopedAllocPop = function (state) { + __affirmAlloc(target, 'scopedAllocPop'); + const n = arguments.length + ? cache.scopedAlloc.indexOf(state) + : cache.scopedAlloc.length - 1; + if (n < 0) toss('Invalid state object for scopedAllocPop().'); + if (0 === arguments.length) state = cache.scopedAlloc[n]; + cache.scopedAlloc.splice(n, 1); + for (let p; (p = state.pop()); ) { + if (target.functionEntry(p)) { + target.uninstallFunction(p); + } else target.dealloc(p); + } + }; + + target.scopedAlloc = function (n) { + if (!cache.scopedAlloc.length) { + toss('No scopedAllocPush() scope is active.'); + } + const p = target.alloc(n); + cache.scopedAlloc[cache.scopedAlloc.length - 1].push(p); + return p; + }; + + Object.defineProperty(target.scopedAlloc, 'level', { + configurable: false, + enumerable: false, + get: () => cache.scopedAlloc.length, + set: () => toss("The 'active' property is read-only."), + }); + + target.scopedAllocCString = (jstr, returnWithLength = false) => + __allocCStr( + jstr, + returnWithLength, + target.scopedAlloc, + 'scopedAllocCString()', + ); + + const __allocMainArgv = function (isScoped, list) { + const pList = target[isScoped ? 'scopedAlloc' : 'alloc']( + (list.length + 1) * target.ptrSizeof, + ); + let i = 0; + list.forEach((e) => { + target.pokePtr( + pList + target.ptrSizeof * i++, + target[isScoped ? 'scopedAllocCString' : 'allocCString']('' + e), + ); + }); + target.pokePtr(pList + target.ptrSizeof * i, 0); + return pList; + }; + + target.scopedAllocMainArgv = (list) => __allocMainArgv(true, list); + + target.allocMainArgv = (list) => __allocMainArgv(false, list); + + target.cArgvToJs = (argc, pArgv) => { + const list = []; + for (let i = 0; i < argc; ++i) { + const arg = target.peekPtr(pArgv + target.ptrSizeof * i); + list.push(arg ? target.cstrToJs(arg) : null); + } + return list; + }; + + target.scopedAllocCall = function (func) { + target.scopedAllocPush(); + try { + return func(); + } finally { + target.scopedAllocPop(); + } + }; + + const __allocPtr = function (howMany, safePtrSize, method) { + __affirmAlloc(target, method); + const pIr = safePtrSize ? 'i64' : ptrIR; + let m = target[method](howMany * (safePtrSize ? 8 : ptrSizeof)); + target.poke(m, 0, pIr); + if (1 === howMany) { + return m; + } + const a = [m]; + for (let i = 1; i < howMany; ++i) { + m += safePtrSize ? 8 : ptrSizeof; + a[i] = m; + target.poke(m, 0, pIr); + } + return a; + }; + + target.allocPtr = (howMany = 1, safePtrSize = true) => + __allocPtr(howMany, safePtrSize, 'alloc'); + + target.scopedAllocPtr = (howMany = 1, safePtrSize = true) => + __allocPtr(howMany, safePtrSize, 'scopedAlloc'); + + target.xGet = function (name) { + return ( + target.exports[name] || toss('Cannot find exported symbol:', name) + ); + }; + + const __argcMismatch = (f, n) => + toss(f + '() requires', n, 'argument(s).'); + + target.xCall = function (fname, ...args) { + const f = fname instanceof Function ? fname : target.xGet(fname); + if (!(f instanceof Function)) + toss('Exported symbol', fname, 'is not a function.'); + if (f.length !== args.length) + __argcMismatch(f === fname ? f.name : fname, f.length); + return 2 === arguments.length && Array.isArray(arguments[1]) + ? f.apply(null, arguments[1]) + : f.apply(null, args); + }; + + cache.xWrap = Object.create(null); + cache.xWrap.convert = Object.create(null); + + cache.xWrap.convert.arg = new Map(); + + cache.xWrap.convert.result = new Map(); + const xArg = cache.xWrap.convert.arg, + xResult = cache.xWrap.convert.result; + + if (target.bigIntEnabled) { + xArg.set('i64', (i) => BigInt(i)); + } + const __xArgPtr = + 'i32' === ptrIR ? (i) => i | 0 : (i) => BigInt(i) | BigInt(0); + xArg + .set('i32', __xArgPtr) + .set('i16', (i) => (i | 0) & 0xffff) + .set('i8', (i) => (i | 0) & 0xff) + .set('f32', (i) => Number(i).valueOf()) + .set('float', xArg.get('f32')) + .set('f64', xArg.get('f32')) + .set('double', xArg.get('f64')) + .set('int', xArg.get('i32')) + .set('null', (i) => i) + .set(null, xArg.get('null')) + .set('**', __xArgPtr) + .set('*', __xArgPtr); + xResult + .set('*', __xArgPtr) + .set('pointer', __xArgPtr) + .set('number', (v) => Number(v)) + .set('void', (v) => undefined) + .set('null', (v) => v) + .set(null, xResult.get('null')); + + { + const copyToResult = [ + 'i8', + 'i16', + 'i32', + 'int', + 'f32', + 'float', + 'f64', + 'double', + ]; + if (target.bigIntEnabled) copyToResult.push('i64'); + const adaptPtr = xArg.get(ptrIR); + for (const t of copyToResult) { + xArg.set(t + '*', adaptPtr); + xResult.set(t + '*', adaptPtr); + xResult.set(t, xArg.get(t) || toss('Missing arg converter:', t)); + } + } + + const __xArgString = function (v) { + if ('string' === typeof v) return target.scopedAllocCString(v); + return v ? __xArgPtr(v) : null; + }; + xArg + .set('string', __xArgString) + .set('utf8', __xArgString) + .set('pointer', __xArgString); + + xResult + .set('string', (i) => target.cstrToJs(i)) + .set('utf8', xResult.get('string')) + .set('string:dealloc', (i) => { + try { + return i ? target.cstrToJs(i) : null; + } finally { + target.dealloc(i); + } + }) + .set('utf8:dealloc', xResult.get('string:dealloc')) + .set('json', (i) => JSON.parse(target.cstrToJs(i))) + .set('json:dealloc', (i) => { + try { + return i ? JSON.parse(target.cstrToJs(i)) : null; + } finally { + target.dealloc(i); + } + }); + + const AbstractArgAdapter = class { + constructor(opt) { + this.name = opt.name || 'unnamed adapter'; + } + + convertArg(v, argv, argIndex) { + toss('AbstractArgAdapter must be subclassed.'); + } + }; + + xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter { + constructor(opt) { + super(opt); + if (xArg.FuncPtrAdapter.warnOnUse) { + console.warn( + 'xArg.FuncPtrAdapter is an internal-only API', + 'and is not intended to be invoked from', + 'client-level code. Invoked with:', + opt, + ); + } + this.name = opt.name || 'unnamed'; + this.signature = opt.signature; + if (opt.contextKey instanceof Function) { + this.contextKey = opt.contextKey; + if (!opt.bindScope) opt.bindScope = 'context'; + } + this.bindScope = + opt.bindScope || + toss( + 'FuncPtrAdapter options requires a bindScope (explicit or implied).', + ); + if (FuncPtrAdapter.bindScopes.indexOf(opt.bindScope) < 0) { + toss( + 'Invalid options.bindScope (' + + opt.bindMod + + ') for FuncPtrAdapter. ' + + 'Expecting one of: (' + + FuncPtrAdapter.bindScopes.join(', ') + + ')', + ); + } + this.isTransient = 'transient' === this.bindScope; + this.isContext = 'context' === this.bindScope; + this.isPermanent = 'permanent' === this.bindScope; + this.singleton = 'singleton' === this.bindScope ? [] : undefined; + + this.callProxy = + opt.callProxy instanceof Function ? opt.callProxy : undefined; + } + + contextKey(argv, argIndex) { + return this; + } + + contextMap(key) { + const cm = this.__cmap || (this.__cmap = new Map()); + let rc = cm.get(key); + if (undefined === rc) cm.set(key, (rc = [])); + return rc; + } + + convertArg(v, argv, argIndex) { + let pair = this.singleton; + if (!pair && this.isContext) { + pair = this.contextMap(this.contextKey(argv, argIndex)); + } + if (pair && pair[0] === v) return pair[1]; + if (v instanceof Function) { + if (this.callProxy) v = this.callProxy(v); + const fp = __installFunction(v, this.signature, this.isTransient); + if (FuncPtrAdapter.debugFuncInstall) { + FuncPtrAdapter.debugOut( + 'FuncPtrAdapter installed', + this, + this.contextKey(argv, argIndex), + '@' + fp, + v, + ); + } + if (pair) { + if (pair[1]) { + if (FuncPtrAdapter.debugFuncInstall) { + FuncPtrAdapter.debugOut( + 'FuncPtrAdapter uninstalling', + this, + this.contextKey(argv, argIndex), + '@' + pair[1], + v, + ); + } + try { + cache.scopedAlloc[cache.scopedAlloc.length - 1].push( + pair[1], + ); + } catch (e) {} + } + pair[0] = v; + pair[1] = fp; + } + return fp; + } else if (target.isPtr(v) || null === v || undefined === v) { + if (pair && pair[1] && pair[1] !== v) { + if (FuncPtrAdapter.debugFuncInstall) { + FuncPtrAdapter.debugOut( + 'FuncPtrAdapter uninstalling', + this, + this.contextKey(argv, argIndex), + '@' + pair[1], + v, + ); + } + try { + cache.scopedAlloc[cache.scopedAlloc.length - 1].push(pair[1]); + } catch (e) {} + pair[0] = pair[1] = v | 0; + } + return v || 0; + } else { + throw new TypeError( + 'Invalid FuncPtrAdapter argument type. ' + + 'Expecting a function pointer or a ' + + (this.name ? this.name + ' ' : '') + + 'function matching signature ' + + this.signature + + '.', + ); + } + } + }; + + xArg.FuncPtrAdapter.warnOnUse = false; + + xArg.FuncPtrAdapter.debugFuncInstall = false; + + xArg.FuncPtrAdapter.debugOut = console.debug.bind(console); + + xArg.FuncPtrAdapter.bindScopes = [ + 'transient', + 'context', + 'singleton', + 'permanent', + ]; + + const __xArgAdapterCheck = (t) => + xArg.get(t) || toss('Argument adapter not found:', t); + + const __xResultAdapterCheck = (t) => + xResult.get(t) || toss('Result adapter not found:', t); + + cache.xWrap.convertArg = (t, ...args) => __xArgAdapterCheck(t)(...args); + + cache.xWrap.convertArgNoCheck = (t, ...args) => xArg.get(t)(...args); + + cache.xWrap.convertResult = (t, v) => + null === t ? v : t ? __xResultAdapterCheck(t)(v) : undefined; + + cache.xWrap.convertResultNoCheck = (t, v) => + null === t ? v : t ? xResult.get(t)(v) : undefined; + + target.xWrap = function (fArg, resultType, ...argTypes) { + if (3 === arguments.length && Array.isArray(arguments[2])) { + argTypes = arguments[2]; + } + if (target.isPtr(fArg)) { + fArg = + target.functionEntry(fArg) || + toss('Function pointer not found in WASM function table.'); + } + const fIsFunc = fArg instanceof Function; + const xf = fIsFunc ? fArg : target.xGet(fArg); + if (fIsFunc) fArg = xf.name || 'unnamed function'; + if (argTypes.length !== xf.length) __argcMismatch(fArg, xf.length); + if (null === resultType && 0 === xf.length) { + return xf; + } + if (undefined !== resultType && null !== resultType) + __xResultAdapterCheck(resultType); + for (const t of argTypes) { + if (t instanceof AbstractArgAdapter) + xArg.set(t, (...args) => t.convertArg(...args)); + else __xArgAdapterCheck(t); + } + const cxw = cache.xWrap; + if (0 === xf.length) { + return (...args) => + args.length + ? __argcMismatch(fArg, xf.length) + : cxw.convertResult(resultType, xf.call(null)); + } + return function (...args) { + if (args.length !== xf.length) __argcMismatch(fArg, xf.length); + const scope = target.scopedAllocPush(); + try { + let i = 0; + for (; i < args.length; ++i) + args[i] = cxw.convertArgNoCheck(argTypes[i], args[i], args, i); + return cxw.convertResultNoCheck(resultType, xf.apply(null, args)); + } finally { + target.scopedAllocPop(scope); + } + }; + }; + + const __xAdapter = function ( + func, + argc, + typeName, + adapter, + modeName, + xcvPart, + ) { + if ('string' === typeof typeName) { + if (1 === argc) return xcvPart.get(typeName); + else if (2 === argc) { + if (!adapter) { + delete xcvPart.get(typeName); + return func; + } else if (!(adapter instanceof Function)) { + toss(modeName, 'requires a function argument.'); + } + xcvPart.set(typeName, adapter); + return func; + } + } + toss('Invalid arguments to', modeName); + }; + + target.xWrap.resultAdapter = function f(typeName, adapter) { + return __xAdapter( + f, + arguments.length, + typeName, + adapter, + 'resultAdapter()', + xResult, + ); + }; + + target.xWrap.argAdapter = function f(typeName, adapter) { + return __xAdapter( + f, + arguments.length, + typeName, + adapter, + 'argAdapter()', + xArg, + ); + }; + + target.xWrap.FuncPtrAdapter = xArg.FuncPtrAdapter; + + target.xCallWrapped = function (fArg, resultType, argTypes, ...args) { + if (Array.isArray(arguments[3])) args = arguments[3]; + return target + .xWrap(fArg, resultType, argTypes || []) + .apply(null, args || []); + }; + + target.xWrap.testConvertArg = cache.xWrap.convertArg; + + target.xWrap.testConvertResult = cache.xWrap.convertResult; + + return target; + }; + + globalThis.WhWasmUtilInstaller.yawl = function (config) { + const wfetch = () => fetch(config.uri, { credentials: 'same-origin' }); + const wui = this; + const finalThen = function (arg) { + if (config.wasmUtilTarget) { + const toss = (...args) => { + throw new Error(args.join(' ')); + }; + const tgt = config.wasmUtilTarget; + tgt.module = arg.module; + tgt.instance = arg.instance; + + if (!tgt.instance.exports.memory) { + tgt.memory = + (config.imports && + config.imports.env && + config.imports.env.memory) || + toss("Missing 'memory' object!"); + } + if (!tgt.alloc && arg.instance.exports.malloc) { + const exports = arg.instance.exports; + tgt.alloc = function (n) { + return ( + exports.malloc(n) || toss('Allocation of', n, 'bytes failed.') + ); + }; + tgt.dealloc = function (m) { + exports.free(m); + }; + } + wui(tgt); + } + if (config.onload) config.onload(arg, config); + return arg; + }; + const loadWasm = WebAssembly.instantiateStreaming + ? function loadWasmStreaming() { + return WebAssembly.instantiateStreaming( + wfetch(), + config.imports || {}, + ).then(finalThen); + } + : function loadWasmOldSchool() { + return wfetch() + .then((response) => response.arrayBuffer()) + .then((bytes) => + WebAssembly.instantiate(bytes, config.imports || {}), + ) + .then(finalThen); + }; + return loadWasm; + }.bind(globalThis.WhWasmUtilInstaller); + globalThis.Jaccwabyt = function StructBinderFactory(config) { + const toss = (...args) => { + throw new Error(args.join(' ')); + }; + + if ( + !(config.heap instanceof WebAssembly.Memory) && + !(config.heap instanceof Function) + ) { + toss( + 'config.heap must be WebAssembly.Memory instance or a function.', + ); + } + ['alloc', 'dealloc'].forEach(function (k) { + config[k] instanceof Function || + toss("Config option '" + k + "' must be a function."); + }); + const SBF = StructBinderFactory; + const heap = + config.heap instanceof Function + ? config.heap + : () => new Uint8Array(config.heap.buffer), + alloc = config.alloc, + dealloc = config.dealloc, + log = config.log || console.log.bind(console), + memberPrefix = config.memberPrefix || '', + memberSuffix = config.memberSuffix || '', + bigIntEnabled = + undefined === config.bigIntEnabled + ? !!globalThis['BigInt64Array'] + : !!config.bigIntEnabled, + BigInt = globalThis['BigInt'], + BigInt64Array = globalThis['BigInt64Array'], + ptrSizeof = config.ptrSizeof || 4, + ptrIR = config.ptrIR || 'i32'; + if (!SBF.debugFlags) { + SBF.__makeDebugFlags = function (deriveFrom = null) { + if (deriveFrom && deriveFrom.__flags) + deriveFrom = deriveFrom.__flags; + const f = function f(flags) { + if (0 === arguments.length) { + return f.__flags; + } + if (flags < 0) { + delete f.__flags.getter; + delete f.__flags.setter; + delete f.__flags.alloc; + delete f.__flags.dealloc; + } else { + f.__flags.getter = 0 !== (0x01 & flags); + f.__flags.setter = 0 !== (0x02 & flags); + f.__flags.alloc = 0 !== (0x04 & flags); + f.__flags.dealloc = 0 !== (0x08 & flags); + } + return f._flags; + }; + Object.defineProperty(f, '__flags', { + iterable: false, + writable: false, + value: Object.create(deriveFrom), + }); + if (!deriveFrom) f(0); + return f; + }; + SBF.debugFlags = SBF.__makeDebugFlags(); + } + + const isLittleEndian = (function () { + const buffer = new ArrayBuffer(2); + new DataView(buffer).setInt16(0, 256, true); + + return new Int16Array(buffer)[0] === 256; + })(); + + const isFuncSig = (s) => '(' === s[1]; + const isAutoPtrSig = (s) => 'P' === s; + const sigLetter = (s) => (isFuncSig(s) ? 'p' : s[0]); + + const sigIR = function (s) { + switch (sigLetter(s)) { + case 'c': + case 'C': + return 'i8'; + case 'i': + return 'i32'; + case 'p': + case 'P': + case 's': + return ptrIR; + case 'j': + return 'i64'; + case 'f': + return 'float'; + case 'd': + return 'double'; + } + toss('Unhandled signature IR:', s); + }; + + const affirmBigIntArray = BigInt64Array + ? () => true + : () => toss('BigInt64Array is not available.'); + + const sigDVGetter = function (s) { + switch (sigLetter(s)) { + case 'p': + case 'P': + case 's': { + switch (ptrSizeof) { + case 4: + return 'getInt32'; + case 8: + return affirmBigIntArray() && 'getBigInt64'; + } + break; + } + case 'i': + return 'getInt32'; + case 'c': + return 'getInt8'; + case 'C': + return 'getUint8'; + case 'j': + return affirmBigIntArray() && 'getBigInt64'; + case 'f': + return 'getFloat32'; + case 'd': + return 'getFloat64'; + } + toss('Unhandled DataView getter for signature:', s); + }; + + const sigDVSetter = function (s) { + switch (sigLetter(s)) { + case 'p': + case 'P': + case 's': { + switch (ptrSizeof) { + case 4: + return 'setInt32'; + case 8: + return affirmBigIntArray() && 'setBigInt64'; + } + break; + } + case 'i': + return 'setInt32'; + case 'c': + return 'setInt8'; + case 'C': + return 'setUint8'; + case 'j': + return affirmBigIntArray() && 'setBigInt64'; + case 'f': + return 'setFloat32'; + case 'd': + return 'setFloat64'; + } + toss('Unhandled DataView setter for signature:', s); + }; + + const sigDVSetWrapper = function (s) { + switch (sigLetter(s)) { + case 'i': + case 'f': + case 'c': + case 'C': + case 'd': + return Number; + case 'j': + return affirmBigIntArray() && BigInt; + case 'p': + case 'P': + case 's': + switch (ptrSizeof) { + case 4: + return Number; + case 8: + return affirmBigIntArray() && BigInt; + } + break; + } + toss('Unhandled DataView set wrapper for signature:', s); + }; + + const sPropName = (s, k) => s + '::' + k; + + const __propThrowOnSet = function (structName, propName) { + return () => toss(sPropName(structName, propName), 'is read-only.'); + }; + + const __instancePointerMap = new WeakMap(); + + const xPtrPropName = '(pointer-is-external)'; + + const __freeStruct = function (ctor, obj, m) { + if (!m) m = __instancePointerMap.get(obj); + if (m) { + __instancePointerMap.delete(obj); + if (Array.isArray(obj.ondispose)) { + let x; + while ((x = obj.ondispose.shift())) { + try { + if (x instanceof Function) x.call(obj); + else if (x instanceof StructType) x.dispose(); + else if ('number' === typeof x) dealloc(x); + } catch (e) { + console.warn( + 'ondispose() for', + ctor.structName, + '@', + m, + 'threw. NOT propagating it.', + e, + ); + } + } + } else if (obj.ondispose instanceof Function) { + try { + obj.ondispose(); + } catch (e) { + console.warn( + 'ondispose() for', + ctor.structName, + '@', + m, + 'threw. NOT propagating it.', + e, + ); + } + } + delete obj.ondispose; + if (ctor.debugFlags.__flags.dealloc) { + log( + 'debug.dealloc:', + obj[xPtrPropName] ? 'EXTERNAL' : '', + ctor.structName, + 'instance:', + ctor.structInfo.sizeof, + 'bytes @' + m, + ); + } + if (!obj[xPtrPropName]) dealloc(m); + } + }; + + const rop = (v) => { + return { + configurable: false, + writable: false, + iterable: false, + value: v, + }; + }; + + const __allocStruct = function (ctor, obj, m) { + let fill = !m; + if (m) Object.defineProperty(obj, xPtrPropName, rop(m)); + else { + m = alloc(ctor.structInfo.sizeof); + if (!m) toss('Allocation of', ctor.structName, 'structure failed.'); + } + try { + if (ctor.debugFlags.__flags.alloc) { + log( + 'debug.alloc:', + fill ? '' : 'EXTERNAL', + ctor.structName, + 'instance:', + ctor.structInfo.sizeof, + 'bytes @' + m, + ); + } + if (fill) heap().fill(0, m, m + ctor.structInfo.sizeof); + __instancePointerMap.set(obj, m); + } catch (e) { + __freeStruct(ctor, obj, m); + throw e; + } + }; + + const __memoryDump = function () { + const p = this.pointer; + return p + ? new Uint8Array(heap().slice(p, p + this.structInfo.sizeof)) + : null; + }; + + const __memberKey = (k) => memberPrefix + k + memberSuffix; + const __memberKeyProp = rop(__memberKey); + + const __lookupMember = function ( + structInfo, + memberName, + tossIfNotFound = true, + ) { + let m = structInfo.members[memberName]; + if (!m && (memberPrefix || memberSuffix)) { + for (const v of Object.values(structInfo.members)) { + if (v.key === memberName) { + m = v; + break; + } + } + if (!m && tossIfNotFound) { + toss( + sPropName(structInfo.name, memberName), + 'is not a mapped struct member.', + ); + } + } + return m; + }; + + const __memberSignature = function f( + obj, + memberName, + emscriptenFormat = false, + ) { + if (!f._) + f._ = (x) => + x.replace(/[^vipPsjrdcC]/g, '').replace(/[pPscC]/g, 'i'); + const m = __lookupMember(obj.structInfo, memberName, true); + return emscriptenFormat ? f._(m.signature) : m.signature; + }; + + const __ptrPropDescriptor = { + configurable: false, + enumerable: false, + get: function () { + return __instancePointerMap.get(this); + }, + set: () => toss("Cannot assign the 'pointer' property of a struct."), + }; + + const __structMemberKeys = rop(function () { + const a = []; + for (const k of Object.keys(this.structInfo.members)) { + a.push(this.memberKey(k)); + } + return a; + }); + + const __utf8Decoder = new TextDecoder('utf-8'); + const __utf8Encoder = new TextEncoder(); + + const __SAB = + 'undefined' === typeof SharedArrayBuffer + ? function () {} + : SharedArrayBuffer; + const __utf8Decode = function (arrayBuffer, begin, end) { + return __utf8Decoder.decode( + arrayBuffer.buffer instanceof __SAB + ? arrayBuffer.slice(begin, end) + : arrayBuffer.subarray(begin, end), + ); + }; + + const __memberIsString = function ( + obj, + memberName, + tossIfNotFound = false, + ) { + const m = __lookupMember(obj.structInfo, memberName, tossIfNotFound); + return m && 1 === m.signature.length && 's' === m.signature[0] + ? m + : false; + }; + + const __affirmCStringSignature = function (member) { + if ('s' === member.signature) return; + toss( + 'Invalid member type signature for C-string value:', + JSON.stringify(member), + ); + }; + + const __memberToJsString = function f(obj, memberName) { + const m = __lookupMember(obj.structInfo, memberName, true); + __affirmCStringSignature(m); + const addr = obj[m.key]; + + if (!addr) return null; + let pos = addr; + const mem = heap(); + for (; mem[pos] !== 0; ++pos) {} + + return addr === pos ? '' : __utf8Decode(mem, addr, pos); + }; + + const __addOnDispose = function (obj, ...v) { + if (obj.ondispose) { + if (!Array.isArray(obj.ondispose)) { + obj.ondispose = [obj.ondispose]; + } + } else { + obj.ondispose = []; + } + obj.ondispose.push(...v); + }; + + const __allocCString = function (str) { + const u = __utf8Encoder.encode(str); + const mem = alloc(u.length + 1); + if (!mem) toss('Allocation error while duplicating string:', str); + const h = heap(); + + h.set(u, mem); + h[mem + u.length] = 0; + + return mem; + }; + + const __setMemberCString = function (obj, memberName, str) { + const m = __lookupMember(obj.structInfo, memberName, true); + __affirmCStringSignature(m); + + const mem = __allocCString(str); + obj[m.key] = mem; + __addOnDispose(obj, mem); + return obj; + }; + + const StructType = function ctor(structName, structInfo) { + if (arguments[2] !== rop) { + toss( + 'Do not call the StructType constructor', + 'from client-level code.', + ); + } + Object.defineProperties(this, { + structName: rop(structName), + structInfo: rop(structInfo), + }); + }; + + StructType.prototype = Object.create(null, { + dispose: rop(function () { + __freeStruct(this.constructor, this); + }), + lookupMember: rop(function (memberName, tossIfNotFound = true) { + return __lookupMember(this.structInfo, memberName, tossIfNotFound); + }), + memberToJsString: rop(function (memberName) { + return __memberToJsString(this, memberName); + }), + memberIsString: rop(function (memberName, tossIfNotFound = true) { + return __memberIsString(this, memberName, tossIfNotFound); + }), + memberKey: __memberKeyProp, + memberKeys: __structMemberKeys, + memberSignature: rop(function (memberName, emscriptenFormat = false) { + return __memberSignature(this, memberName, emscriptenFormat); + }), + memoryDump: rop(__memoryDump), + pointer: __ptrPropDescriptor, + setMemberCString: rop(function (memberName, str) { + return __setMemberCString(this, memberName, str); + }), + }); + + Object.assign(StructType.prototype, { + addOnDispose: function (...v) { + __addOnDispose(this, ...v); + return this; + }, + }); + + Object.defineProperties(StructType, { + allocCString: rop(__allocCString), + isA: rop((v) => v instanceof StructType), + hasExternalPointer: rop( + (v) => v instanceof StructType && !!v[xPtrPropName], + ), + memberKey: __memberKeyProp, + }); + + const isNumericValue = (v) => + Number.isFinite(v) || v instanceof (BigInt || Number); + + const makeMemberWrapper = function f(ctor, name, descr) { + if (!f._) { + f._ = { getters: {}, setters: {}, sw: {} }; + const a = ['i', 'c', 'C', 'p', 'P', 's', 'f', 'd', 'v()']; + if (bigIntEnabled) a.push('j'); + a.forEach(function (v) { + f._.getters[v] = sigDVGetter(v); + f._.setters[v] = sigDVSetter(v); + f._.sw[v] = sigDVSetWrapper(v); + }); + const rxSig1 = /^[ipPsjfdcC]$/, + rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/; + f.sigCheck = function (obj, name, key, sig) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + toss(obj.structName, 'already has a property named', key + '.'); + } + rxSig1.test(sig) || + rxSig2.test(sig) || + toss( + 'Malformed signature for', + sPropName(obj.structName, name) + ':', + sig, + ); + }; + } + const key = ctor.memberKey(name); + f.sigCheck(ctor.prototype, name, key, descr.signature); + descr.key = key; + descr.name = name; + const sigGlyph = sigLetter(descr.signature); + const xPropName = sPropName(ctor.prototype.structName, key); + const dbg = ctor.prototype.debugFlags.__flags; + + const prop = Object.create(null); + prop.configurable = false; + prop.enumerable = false; + prop.get = function () { + if (dbg.getter) { + log( + 'debug.getter:', + f._.getters[sigGlyph], + 'for', + sigIR(sigGlyph), + xPropName, + '@', + this.pointer, + '+', + descr.offset, + 'sz', + descr.sizeof, + ); + } + let rc = new DataView( + heap().buffer, + this.pointer + descr.offset, + descr.sizeof, + )[f._.getters[sigGlyph]](0, isLittleEndian); + if (dbg.getter) log('debug.getter:', xPropName, 'result =', rc); + return rc; + }; + if (descr.readOnly) { + prop.set = __propThrowOnSet(ctor.prototype.structName, key); + } else { + prop.set = function (v) { + if (dbg.setter) { + log( + 'debug.setter:', + f._.setters[sigGlyph], + 'for', + sigIR(sigGlyph), + xPropName, + '@', + this.pointer, + '+', + descr.offset, + 'sz', + descr.sizeof, + v, + ); + } + if (!this.pointer) { + toss('Cannot set struct property on disposed instance.'); + } + if (null === v) v = 0; + else + while (!isNumericValue(v)) { + if ( + isAutoPtrSig(descr.signature) && + v instanceof StructType + ) { + v = v.pointer || 0; + if (dbg.setter) + log('debug.setter:', xPropName, 'resolved to', v); + break; + } + toss('Invalid value for pointer-type', xPropName + '.'); + } + new DataView( + heap().buffer, + this.pointer + descr.offset, + descr.sizeof, + )[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian); + }; + } + Object.defineProperty(ctor.prototype, key, prop); + }; + + const StructBinder = function StructBinder(structName, structInfo) { + if (1 === arguments.length) { + structInfo = structName; + structName = structInfo.name; + } else if (!structInfo.name) { + structInfo.name = structName; + } + if (!structName) toss('Struct name is required.'); + let lastMember = false; + Object.keys(structInfo.members).forEach((k) => { + const m = structInfo.members[k]; + if (!m.sizeof) toss(structName, 'member', k, 'is missing sizeof.'); + else if (m.sizeof === 1) { + m.signature === 'c' || + m.signature === 'C' || + toss( + 'Unexpected sizeof==1 member', + sPropName(structInfo.name, k), + 'with signature', + m.signature, + ); + } else { + if (0 !== m.sizeof % 4) { + console.warn( + 'Invalid struct member description =', + m, + 'from', + structInfo, + ); + toss( + structName, + 'member', + k, + 'sizeof is not aligned. sizeof=' + m.sizeof, + ); + } + if (0 !== m.offset % 4) { + console.warn( + 'Invalid struct member description =', + m, + 'from', + structInfo, + ); + toss( + structName, + 'member', + k, + 'offset is not aligned. offset=' + m.offset, + ); + } + } + if (!lastMember || lastMember.offset < m.offset) lastMember = m; + }); + if (!lastMember) toss('No member property descriptions found.'); + else if (structInfo.sizeof < lastMember.offset + lastMember.sizeof) { + toss( + 'Invalid struct config:', + structName, + 'max member offset (' + lastMember.offset + ') ', + 'extends past end of struct (sizeof=' + structInfo.sizeof + ').', + ); + } + const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags)); + + const StructCtor = function StructCtor(externalMemory) { + if (!(this instanceof StructCtor)) { + toss( + 'The', + structName, + "constructor may only be called via 'new'.", + ); + } else if (arguments.length) { + if ( + externalMemory !== (externalMemory | 0) || + externalMemory <= 0 + ) { + toss('Invalid pointer value for', structName, 'constructor.'); + } + __allocStruct(StructCtor, this, externalMemory); + } else { + __allocStruct(StructCtor, this); + } + }; + Object.defineProperties(StructCtor, { + debugFlags: debugFlags, + isA: rop((v) => v instanceof StructCtor), + memberKey: __memberKeyProp, + memberKeys: __structMemberKeys, + methodInfoForKey: rop(function (mKey) {}), + structInfo: rop(structInfo), + structName: rop(structName), + }); + StructCtor.prototype = new StructType(structName, structInfo, rop); + Object.defineProperties(StructCtor.prototype, { + debugFlags: debugFlags, + constructor: rop(StructCtor), + }); + Object.keys(structInfo.members).forEach((name) => + makeMemberWrapper(StructCtor, name, structInfo.members[name]), + ); + return StructCtor; + }; + StructBinder.StructType = StructType; + StructBinder.config = config; + StructBinder.allocCString = __allocCString; + if (!StructBinder.debugFlags) { + StructBinder.debugFlags = SBF.__makeDebugFlags(SBF.debugFlags); + } + return StructBinder; + }; + + globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { + const toss = (...args) => { + throw new Error(args.join(' ')); + }; + sqlite3.SQLite3Error.toss; + const capi = sqlite3.capi, + wasm = sqlite3.wasm, + util = sqlite3.util; + globalThis.WhWasmUtilInstaller(wasm); + delete globalThis.WhWasmUtilInstaller; + + wasm.bindingSignatures = [ + ['sqlite3_aggregate_context', 'void*', 'sqlite3_context*', 'int'], + + ['sqlite3_bind_double', 'int', 'sqlite3_stmt*', 'int', 'f64'], + ['sqlite3_bind_int', 'int', 'sqlite3_stmt*', 'int', 'int'], + ['sqlite3_bind_null', undefined, 'sqlite3_stmt*', 'int'], + ['sqlite3_bind_parameter_count', 'int', 'sqlite3_stmt*'], + ['sqlite3_bind_parameter_index', 'int', 'sqlite3_stmt*', 'string'], + [ + 'sqlite3_bind_pointer', + 'int', + 'sqlite3_stmt*', + 'int', + '*', + 'string:static', + '*', + ], + [ + 'sqlite3_busy_handler', + 'int', + [ + 'sqlite3*', + new wasm.xWrap.FuncPtrAdapter({ + signature: 'i(pi)', + contextKey: (argv, argIndex) => argv[0], + }), + '*', + ], + ], + ['sqlite3_busy_timeout', 'int', 'sqlite3*', 'int'], + + ['sqlite3_changes', 'int', 'sqlite3*'], + ['sqlite3_clear_bindings', 'int', 'sqlite3_stmt*'], + ['sqlite3_collation_needed', 'int', 'sqlite3*', '*', '*'], + ['sqlite3_column_blob', '*', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_bytes', 'int', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_count', 'int', 'sqlite3_stmt*'], + ['sqlite3_column_double', 'f64', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_int', 'int', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_name', 'string', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_text', 'string', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_type', 'int', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_value', 'sqlite3_value*', 'sqlite3_stmt*', 'int'], + [ + 'sqlite3_commit_hook', + 'void*', + [ + 'sqlite3*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'sqlite3_commit_hook', + signature: 'i(p)', + contextKey: (argv) => argv[0], + }), + '*', + ], + ], + ['sqlite3_compileoption_get', 'string', 'int'], + ['sqlite3_compileoption_used', 'int', 'string'], + ['sqlite3_complete', 'int', 'string:flexible'], + ['sqlite3_context_db_handle', 'sqlite3*', 'sqlite3_context*'], + + ['sqlite3_data_count', 'int', 'sqlite3_stmt*'], + ['sqlite3_db_filename', 'string', 'sqlite3*', 'string'], + ['sqlite3_db_handle', 'sqlite3*', 'sqlite3_stmt*'], + ['sqlite3_db_name', 'string', 'sqlite3*', 'int'], + ['sqlite3_db_status', 'int', 'sqlite3*', 'int', '*', '*', 'int'], + ['sqlite3_errcode', 'int', 'sqlite3*'], + ['sqlite3_errmsg', 'string', 'sqlite3*'], + ['sqlite3_error_offset', 'int', 'sqlite3*'], + ['sqlite3_errstr', 'string', 'int'], + [ + 'sqlite3_exec', + 'int', + [ + 'sqlite3*', + 'string:flexible', + new wasm.xWrap.FuncPtrAdapter({ + signature: 'i(pipp)', + bindScope: 'transient', + callProxy: (callback) => { + let aNames; + return (pVoid, nCols, pColVals, pColNames) => { + try { + const aVals = wasm.cArgvToJs(nCols, pColVals); + if (!aNames) aNames = wasm.cArgvToJs(nCols, pColNames); + return callback(aVals, aNames) | 0; + } catch (e) { + return e.resultCode || capi.SQLITE_ERROR; + } + }; + }, + }), + '*', + '**', + ], + ], + ['sqlite3_expanded_sql', 'string', 'sqlite3_stmt*'], + ['sqlite3_extended_errcode', 'int', 'sqlite3*'], + ['sqlite3_extended_result_codes', 'int', 'sqlite3*', 'int'], + ['sqlite3_file_control', 'int', 'sqlite3*', 'string', 'int', '*'], + ['sqlite3_finalize', 'int', 'sqlite3_stmt*'], + ['sqlite3_free', undefined, '*'], + ['sqlite3_get_autocommit', 'int', 'sqlite3*'], + ['sqlite3_get_auxdata', '*', 'sqlite3_context*', 'int'], + ['sqlite3_initialize', undefined], + + ['sqlite3_keyword_count', 'int'], + ['sqlite3_keyword_name', 'int', ['int', '**', '*']], + ['sqlite3_keyword_check', 'int', ['string', 'int']], + ['sqlite3_libversion', 'string'], + ['sqlite3_libversion_number', 'int'], + ['sqlite3_limit', 'int', ['sqlite3*', 'int', 'int']], + ['sqlite3_malloc', '*', 'int'], + ['sqlite3_open', 'int', 'string', '*'], + ['sqlite3_open_v2', 'int', 'string', '*', 'int', 'string'], + + [ + 'sqlite3_progress_handler', + undefined, + [ + 'sqlite3*', + 'int', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xProgressHandler', + signature: 'i(p)', + bindScope: 'context', + contextKey: (argv, argIndex) => argv[0], + }), + '*', + ], + ], + ['sqlite3_realloc', '*', '*', 'int'], + ['sqlite3_reset', 'int', 'sqlite3_stmt*'], + + [ + 'sqlite3_result_blob', + undefined, + 'sqlite3_context*', + '*', + 'int', + '*', + ], + ['sqlite3_result_double', undefined, 'sqlite3_context*', 'f64'], + [ + 'sqlite3_result_error', + undefined, + 'sqlite3_context*', + 'string', + 'int', + ], + ['sqlite3_result_error_code', undefined, 'sqlite3_context*', 'int'], + ['sqlite3_result_error_nomem', undefined, 'sqlite3_context*'], + ['sqlite3_result_error_toobig', undefined, 'sqlite3_context*'], + ['sqlite3_result_int', undefined, 'sqlite3_context*', 'int'], + ['sqlite3_result_null', undefined, 'sqlite3_context*'], + [ + 'sqlite3_result_pointer', + undefined, + 'sqlite3_context*', + '*', + 'string:static', + '*', + ], + ['sqlite3_result_subtype', undefined, 'sqlite3_value*', 'int'], + [ + 'sqlite3_result_text', + undefined, + 'sqlite3_context*', + 'string', + 'int', + '*', + ], + ['sqlite3_result_zeroblob', undefined, 'sqlite3_context*', 'int'], + [ + 'sqlite3_rollback_hook', + 'void*', + [ + 'sqlite3*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'sqlite3_rollback_hook', + signature: 'v(p)', + contextKey: (argv) => argv[0], + }), + '*', + ], + ], + [ + 'sqlite3_set_authorizer', + 'int', + [ + 'sqlite3*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'sqlite3_set_authorizer::xAuth', + signature: 'i(pi' + 'ssss)', + contextKey: (argv, argIndex) => argv[0], + callProxy: (callback) => { + return (pV, iCode, s0, s1, s2, s3) => { + try { + s0 = s0 && wasm.cstrToJs(s0); + s1 = s1 && wasm.cstrToJs(s1); + s2 = s2 && wasm.cstrToJs(s2); + s3 = s3 && wasm.cstrToJs(s3); + return callback(pV, iCode, s0, s1, s2, s3) || 0; + } catch (e) { + return e.resultCode || capi.SQLITE_ERROR; + } + }; + }, + }), + '*', + ], + ], + [ + 'sqlite3_set_auxdata', + undefined, + [ + 'sqlite3_context*', + 'int', + '*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xDestroyAuxData', + signature: 'v(*)', + contextKey: (argv, argIndex) => argv[0], + }), + ], + ], + ['sqlite3_shutdown', undefined], + ['sqlite3_sourceid', 'string'], + ['sqlite3_sql', 'string', 'sqlite3_stmt*'], + ['sqlite3_status', 'int', 'int', '*', '*', 'int'], + ['sqlite3_step', 'int', 'sqlite3_stmt*'], + ['sqlite3_stmt_isexplain', 'int', ['sqlite3_stmt*']], + ['sqlite3_stmt_readonly', 'int', ['sqlite3_stmt*']], + ['sqlite3_stmt_status', 'int', 'sqlite3_stmt*', 'int', 'int'], + ['sqlite3_strglob', 'int', 'string', 'string'], + ['sqlite3_stricmp', 'int', 'string', 'string'], + ['sqlite3_strlike', 'int', 'string', 'string', 'int'], + ['sqlite3_strnicmp', 'int', 'string', 'string', 'int'], + [ + 'sqlite3_table_column_metadata', + 'int', + 'sqlite3*', + 'string', + 'string', + 'string', + '**', + '**', + '*', + '*', + '*', + ], + ['sqlite3_total_changes', 'int', 'sqlite3*'], + [ + 'sqlite3_trace_v2', + 'int', + [ + 'sqlite3*', + 'int', + new wasm.xWrap.FuncPtrAdapter({ + name: 'sqlite3_trace_v2::callback', + signature: 'i(ippp)', + contextKey: (argv, argIndex) => argv[0], + }), + '*', + ], + ], + ['sqlite3_txn_state', 'int', ['sqlite3*', 'string']], + + ['sqlite3_uri_boolean', 'int', 'sqlite3_filename', 'string', 'int'], + ['sqlite3_uri_key', 'string', 'sqlite3_filename', 'int'], + ['sqlite3_uri_parameter', 'string', 'sqlite3_filename', 'string'], + ['sqlite3_user_data', 'void*', 'sqlite3_context*'], + ['sqlite3_value_blob', '*', 'sqlite3_value*'], + ['sqlite3_value_bytes', 'int', 'sqlite3_value*'], + ['sqlite3_value_double', 'f64', 'sqlite3_value*'], + ['sqlite3_value_dup', 'sqlite3_value*', 'sqlite3_value*'], + ['sqlite3_value_free', undefined, 'sqlite3_value*'], + ['sqlite3_value_frombind', 'int', 'sqlite3_value*'], + ['sqlite3_value_int', 'int', 'sqlite3_value*'], + ['sqlite3_value_nochange', 'int', 'sqlite3_value*'], + ['sqlite3_value_numeric_type', 'int', 'sqlite3_value*'], + ['sqlite3_value_pointer', '*', 'sqlite3_value*', 'string:static'], + ['sqlite3_value_subtype', 'int', 'sqlite3_value*'], + ['sqlite3_value_text', 'string', 'sqlite3_value*'], + ['sqlite3_value_type', 'int', 'sqlite3_value*'], + ['sqlite3_vfs_find', '*', 'string'], + ['sqlite3_vfs_register', 'int', 'sqlite3_vfs*', 'int'], + ['sqlite3_vfs_unregister', 'int', 'sqlite3_vfs*'], + ]; + + wasm.bindingSignatures.int64 = [ + ['sqlite3_bind_int64', 'int', ['sqlite3_stmt*', 'int', 'i64']], + ['sqlite3_changes64', 'i64', ['sqlite3*']], + ['sqlite3_column_int64', 'i64', ['sqlite3_stmt*', 'int']], + [ + 'sqlite3_create_module', + 'int', + ['sqlite3*', 'string', 'sqlite3_module*', '*'], + ], + [ + 'sqlite3_create_module_v2', + 'int', + ['sqlite3*', 'string', 'sqlite3_module*', '*', '*'], + ], + ['sqlite3_declare_vtab', 'int', ['sqlite3*', 'string:flexible']], + [ + 'sqlite3_deserialize', + 'int', + 'sqlite3*', + 'string', + '*', + 'i64', + 'i64', + 'int', + ], + ['sqlite3_drop_modules', 'int', ['sqlite3*', '**']], + ['sqlite3_last_insert_rowid', 'i64', ['sqlite3*']], + ['sqlite3_malloc64', '*', 'i64'], + ['sqlite3_msize', 'i64', '*'], + ['sqlite3_overload_function', 'int', ['sqlite3*', 'string', 'int']], + ['sqlite3_preupdate_blobwrite', 'int', 'sqlite3*'], + ['sqlite3_preupdate_count', 'int', 'sqlite3*'], + ['sqlite3_preupdate_depth', 'int', 'sqlite3*'], + [ + 'sqlite3_preupdate_hook', + '*', + [ + 'sqlite3*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'sqlite3_preupdate_hook', + signature: 'v(ppippjj)', + contextKey: (argv) => argv[0], + callProxy: (callback) => { + return (p, db, op, zDb, zTbl, iKey1, iKey2) => { + callback( + p, + db, + op, + wasm.cstrToJs(zDb), + wasm.cstrToJs(zTbl), + iKey1, + iKey2, + ); + }; + }, + }), + '*', + ], + ], + ['sqlite3_preupdate_new', 'int', ['sqlite3*', 'int', '**']], + ['sqlite3_preupdate_old', 'int', ['sqlite3*', 'int', '**']], + ['sqlite3_realloc64', '*', '*', 'i64'], + ['sqlite3_result_int64', undefined, '*', 'i64'], + ['sqlite3_result_zeroblob64', 'int', '*', 'i64'], + ['sqlite3_serialize', '*', 'sqlite3*', 'string', '*', 'int'], + ['sqlite3_set_last_insert_rowid', undefined, ['sqlite3*', 'i64']], + ['sqlite3_status64', 'int', 'int', '*', '*', 'int'], + ['sqlite3_total_changes64', 'i64', ['sqlite3*']], + [ + 'sqlite3_update_hook', + '*', + [ + 'sqlite3*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'sqlite3_update_hook', + signature: 'v(iippj)', + contextKey: (argv) => argv[0], + callProxy: (callback) => { + return (p, op, z0, z1, rowid) => { + callback( + p, + op, + wasm.cstrToJs(z0), + wasm.cstrToJs(z1), + rowid, + ); + }; + }, + }), + '*', + ], + ], + ['sqlite3_uri_int64', 'i64', ['sqlite3_filename', 'string', 'i64']], + ['sqlite3_value_int64', 'i64', 'sqlite3_value*'], + ['sqlite3_vtab_collation', 'string', 'sqlite3_index_info*', 'int'], + ['sqlite3_vtab_distinct', 'int', 'sqlite3_index_info*'], + ['sqlite3_vtab_in', 'int', 'sqlite3_index_info*', 'int', 'int'], + ['sqlite3_vtab_in_first', 'int', 'sqlite3_value*', '**'], + ['sqlite3_vtab_in_next', 'int', 'sqlite3_value*', '**'], + + ['sqlite3_vtab_nochange', 'int', 'sqlite3_context*'], + ['sqlite3_vtab_on_conflict', 'int', 'sqlite3*'], + ['sqlite3_vtab_rhs_value', 'int', 'sqlite3_index_info*', 'int', '**'], + ]; + + if (wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add) { + const __ipsProxy = { + signature: 'i(ps)', + callProxy: (callback) => { + return (p, s) => { + try { + return callback(p, wasm.cstrToJs(s)) | 0; + } catch (e) { + return e.resultCode || capi.SQLITE_ERROR; + } + }; + }, + }; + + wasm.bindingSignatures.int64.push( + ...[ + [ + 'sqlite3changegroup_add', + 'int', + ['sqlite3_changegroup*', 'int', 'void*'], + ], + [ + 'sqlite3changegroup_add_strm', + 'int', + [ + 'sqlite3_changegroup*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + ], + ], + [ + 'sqlite3changegroup_delete', + undefined, + ['sqlite3_changegroup*'], + ], + ['sqlite3changegroup_new', 'int', ['**']], + [ + 'sqlite3changegroup_output', + 'int', + ['sqlite3_changegroup*', 'int*', '**'], + ], + [ + 'sqlite3changegroup_output_strm', + 'int', + [ + 'sqlite3_changegroup*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xOutput', + signature: 'i(ppi)', + bindScope: 'transient', + }), + 'void*', + ], + ], + [ + 'sqlite3changeset_apply', + 'int', + [ + 'sqlite3*', + 'int', + 'void*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xFilter', + bindScope: 'transient', + ...__ipsProxy, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xConflict', + signature: 'i(pip)', + bindScope: 'transient', + }), + 'void*', + ], + ], + [ + 'sqlite3changeset_apply_strm', + 'int', + [ + 'sqlite3*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xFilter', + bindScope: 'transient', + ...__ipsProxy, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xConflict', + signature: 'i(pip)', + bindScope: 'transient', + }), + 'void*', + ], + ], + [ + 'sqlite3changeset_apply_v2', + 'int', + [ + 'sqlite3*', + 'int', + 'void*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xFilter', + bindScope: 'transient', + ...__ipsProxy, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xConflict', + signature: 'i(pip)', + bindScope: 'transient', + }), + 'void*', + '**', + 'int*', + 'int', + ], + ], + [ + 'sqlite3changeset_apply_v2_strm', + 'int', + [ + 'sqlite3*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xFilter', + bindScope: 'transient', + ...__ipsProxy, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xConflict', + signature: 'i(pip)', + bindScope: 'transient', + }), + 'void*', + '**', + 'int*', + 'int', + ], + ], + [ + 'sqlite3changeset_concat', + 'int', + ['int', 'void*', 'int', 'void*', 'int*', '**'], + ], + [ + 'sqlite3changeset_concat_strm', + 'int', + [ + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInputA', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInputB', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xOutput', + signature: 'i(ppi)', + bindScope: 'transient', + }), + 'void*', + ], + ], + [ + 'sqlite3changeset_conflict', + 'int', + ['sqlite3_changeset_iter*', 'int', '**'], + ], + ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']], + [ + 'sqlite3changeset_fk_conflicts', + 'int', + ['sqlite3_changeset_iter*', 'int*'], + ], + [ + 'sqlite3changeset_invert', + 'int', + ['int', 'void*', 'int*', '**'], + ], + [ + 'sqlite3changeset_invert_strm', + 'int', + [ + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xOutput', + signature: 'i(ppi)', + bindScope: 'transient', + }), + 'void*', + ], + ], + [ + 'sqlite3changeset_new', + 'int', + ['sqlite3_changeset_iter*', 'int', '**'], + ], + ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']], + [ + 'sqlite3changeset_old', + 'int', + ['sqlite3_changeset_iter*', 'int', '**'], + ], + [ + 'sqlite3changeset_op', + 'int', + ['sqlite3_changeset_iter*', '**', 'int*', 'int*', 'int*'], + ], + [ + 'sqlite3changeset_pk', + 'int', + ['sqlite3_changeset_iter*', '**', 'int*'], + ], + ['sqlite3changeset_start', 'int', ['**', 'int', '*']], + [ + 'sqlite3changeset_start_strm', + 'int', + [ + '**', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + ], + ], + ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']], + [ + 'sqlite3changeset_start_v2_strm', + 'int', + [ + '**', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + 'int', + ], + ], + ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']], + [ + 'sqlite3session_changeset', + 'int', + ['sqlite3_session*', 'int*', '**'], + ], + ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']], + [ + 'sqlite3session_changeset_strm', + 'int', + [ + 'sqlite3_session*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xOutput', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + ], + ], + ['sqlite3session_config', 'int', ['int', 'void*']], + ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']], + + [ + 'sqlite3session_diff', + 'int', + ['sqlite3_session*', 'string', 'string', '**'], + ], + ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']], + ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']], + ['sqlite3session_isempty', 'int', ['sqlite3_session*']], + ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']], + [ + 'sqlite3session_object_config', + 'int', + ['sqlite3_session*', 'int', 'void*'], + ], + [ + 'sqlite3session_patchset', + 'int', + ['sqlite3_session*', '*', '**'], + ], + [ + 'sqlite3session_patchset_strm', + 'int', + [ + 'sqlite3_session*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xOutput', + signature: 'i(ppp)', + bindScope: 'transient', + }), + 'void*', + ], + ], + [ + 'sqlite3session_table_filter', + undefined, + [ + 'sqlite3_session*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xFilter', + ...__ipsProxy, + contextKey: (argv, argIndex) => argv[0], + }), + '*', + ], + ], + ], + ); + } + + wasm.bindingSignatures.wasmInternal = [ + ['sqlite3__wasm_db_reset', 'int', 'sqlite3*'], + ['sqlite3__wasm_db_vfs', 'sqlite3_vfs*', 'sqlite3*', 'string'], + [ + 'sqlite3__wasm_vfs_create_file', + 'int', + 'sqlite3_vfs*', + 'string', + '*', + 'int', + ], + ['sqlite3__wasm_posix_create_file', 'int', 'string', '*', 'int'], + ['sqlite3__wasm_vfs_unlink', 'int', 'sqlite3_vfs*', 'string'], + ['sqlite3__wasm_qfmt_token', 'string:dealloc', 'string', 'int'], + ]; + + sqlite3.StructBinder = globalThis.Jaccwabyt({ + heap: wasm.heap8u, + alloc: wasm.alloc, + dealloc: wasm.dealloc, + bigIntEnabled: wasm.bigIntEnabled, + memberPrefix: '$', + }); + delete globalThis.Jaccwabyt; + + { + const __xString = wasm.xWrap.argAdapter('string'); + wasm.xWrap.argAdapter('string:flexible', (v) => + __xString(util.flexibleString(v)), + ); + + wasm.xWrap.argAdapter( + 'string:static', + function (v) { + if (wasm.isPtr(v)) return v; + v = '' + v; + let rc = this[v]; + return rc || (this[v] = wasm.allocCString(v)); + }.bind(Object.create(null)), + ); + + const __xArgPtr = wasm.xWrap.argAdapter('*'); + const nilType = function () {}; + wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)( + 'sqlite3_context*', + __xArgPtr, + )('sqlite3_value*', __xArgPtr)('void*', __xArgPtr)( + 'sqlite3_changegroup*', + __xArgPtr, + )('sqlite3_changeset_iter*', __xArgPtr)( + 'sqlite3_session*', + __xArgPtr, + )('sqlite3_stmt*', (v) => + __xArgPtr( + v instanceof (sqlite3?.oo1?.Stmt || nilType) ? v.pointer : v, + ), + )('sqlite3*', (v) => + __xArgPtr( + v instanceof (sqlite3?.oo1?.DB || nilType) ? v.pointer : v, + ), + )('sqlite3_index_info*', (v) => + __xArgPtr( + v instanceof (capi.sqlite3_index_info || nilType) ? v.pointer : v, + ), + )('sqlite3_module*', (v) => + __xArgPtr( + v instanceof (capi.sqlite3_module || nilType) ? v.pointer : v, + ), + )('sqlite3_vfs*', (v) => { + if ('string' === typeof v) { + return ( + capi.sqlite3_vfs_find(v) || + sqlite3.SQLite3Error.toss( + capi.SQLITE_NOTFOUND, + 'Unknown sqlite3_vfs name:', + v, + ) + ); + } + return __xArgPtr( + v instanceof (capi.sqlite3_vfs || nilType) ? v.pointer : v, + ); + }); + + const __xRcPtr = wasm.xWrap.resultAdapter('*'); + wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)( + 'sqlite3_context*', + __xRcPtr, + )('sqlite3_stmt*', __xRcPtr)('sqlite3_value*', __xRcPtr)( + 'sqlite3_vfs*', + __xRcPtr, + )('void*', __xRcPtr); + + if (0 === wasm.exports.sqlite3_step.length) { + wasm.xWrap.doArgcCheck = false; + sqlite3.config.warn( + 'Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks.', + ); + } + for (const e of wasm.bindingSignatures) { + capi[e[0]] = wasm.xWrap.apply(null, e); + } + for (const e of wasm.bindingSignatures.wasmInternal) { + util[e[0]] = wasm.xWrap.apply(null, e); + } + + const fI64Disabled = function (fname) { + return () => + toss( + fname + '() is unavailable due to lack', + 'of BigInt support in this build.', + ); + }; + for (const e of wasm.bindingSignatures.int64) { + capi[e[0]] = wasm.bigIntEnabled + ? wasm.xWrap.apply(null, e) + : fI64Disabled(e[0]); + } + + delete wasm.bindingSignatures; + + if (wasm.exports.sqlite3__wasm_db_error) { + const __db_err = wasm.xWrap( + 'sqlite3__wasm_db_error', + 'int', + 'sqlite3*', + 'int', + 'string', + ); + + util.sqlite3__wasm_db_error = function (pDb, resultCode, message) { + if (resultCode instanceof sqlite3.WasmAllocError) { + resultCode = capi.SQLITE_NOMEM; + message = 0; + } else if (resultCode instanceof Error) { + message = message || '' + resultCode; + resultCode = resultCode.resultCode || capi.SQLITE_ERROR; + } + return pDb ? __db_err(pDb, resultCode, message) : resultCode; + }; + } else { + util.sqlite3__wasm_db_error = function (pDb, errCode, msg) { + console.warn( + 'sqlite3__wasm_db_error() is not exported.', + arguments, + ); + return errCode; + }; + } + } + + { + const cJson = wasm.xCall('sqlite3__wasm_enum_json'); + if (!cJson) { + toss( + "Maintenance required: increase sqlite3__wasm_enum_json()'s", + 'static buffer size!', + ); + } + + wasm.ctype = JSON.parse(wasm.cstrToJs(cJson)); + + const defineGroups = [ + 'access', + 'authorizer', + 'blobFinalizers', + 'changeset', + 'config', + 'dataTypes', + 'dbConfig', + 'dbStatus', + 'encodings', + 'fcntl', + 'flock', + 'ioCap', + 'limits', + 'openFlags', + 'prepareFlags', + 'resultCodes', + 'sqlite3Status', + 'stmtStatus', + 'syncFlags', + 'trace', + 'txnState', + 'udfFlags', + 'version', + ]; + if (wasm.bigIntEnabled) { + defineGroups.push('serialize', 'session', 'vtab'); + } + for (const t of defineGroups) { + for (const e of Object.entries(wasm.ctype[t])) { + capi[e[0]] = e[1]; + } + } + if (!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)) { + toss( + 'Internal error: cannot resolve exported function', + 'entry SQLITE_WASM_DEALLOC (==' + capi.SQLITE_WASM_DEALLOC + ').', + ); + } + const __rcMap = Object.create(null); + for (const t of ['resultCodes']) { + for (const e of Object.entries(wasm.ctype[t])) { + __rcMap[e[1]] = e[0]; + } + } + + capi.sqlite3_js_rc_str = (rc) => __rcMap[rc]; + + const notThese = Object.assign(Object.create(null), { + WasmTestStruct: true, + + sqlite3_kvvfs_methods: !util.isUIThread(), + + sqlite3_index_info: !wasm.bigIntEnabled, + sqlite3_index_constraint: !wasm.bigIntEnabled, + sqlite3_index_orderby: !wasm.bigIntEnabled, + sqlite3_index_constraint_usage: !wasm.bigIntEnabled, + }); + for (const s of wasm.ctype.structs) { + if (!notThese[s.name]) { + capi[s.name] = sqlite3.StructBinder(s); + } + } + if (capi.sqlite3_index_info) { + for (const k of [ + 'sqlite3_index_constraint', + 'sqlite3_index_orderby', + 'sqlite3_index_constraint_usage', + ]) { + capi.sqlite3_index_info[k] = capi[k]; + delete capi[k]; + } + capi.sqlite3_vtab_config = wasm.xWrap( + 'sqlite3__wasm_vtab_config', + 'int', + ['sqlite3*', 'int', 'int'], + ); + } + } + + const __dbArgcMismatch = (pDb, f, n) => { + return util.sqlite3__wasm_db_error( + pDb, + capi.SQLITE_MISUSE, + f + '() requires ' + n + ' argument' + (1 === n ? '' : 's') + '.', + ); + }; + + const __errEncoding = (pDb) => { + return util.sqlite3__wasm_db_error( + pDb, + capi.SQLITE_FORMAT, + 'SQLITE_UTF8 is the only supported encoding.', + ); + }; + + const __argPDb = (pDb) => wasm.xWrap.argAdapter('sqlite3*')(pDb); + const __argStr = (str) => (wasm.isPtr(str) ? wasm.cstrToJs(str) : str); + const __dbCleanupMap = function (pDb, mode) { + pDb = __argPDb(pDb); + let m = this.dbMap.get(pDb); + if (!mode) { + this.dbMap.delete(pDb); + return m; + } else if (!m && mode > 0) { + this.dbMap.set(pDb, (m = Object.create(null))); + } + return m; + }.bind( + Object.assign(Object.create(null), { + dbMap: new Map(), + }), + ); + + __dbCleanupMap.addCollation = function (pDb, name) { + const m = __dbCleanupMap(pDb, 1); + if (!m.collation) m.collation = new Set(); + m.collation.add(__argStr(name).toLowerCase()); + }; + + __dbCleanupMap._addUDF = function (pDb, name, arity, map) { + name = __argStr(name).toLowerCase(); + let u = map.get(name); + if (!u) map.set(name, (u = new Set())); + u.add(arity < 0 ? -1 : arity); + }; + + __dbCleanupMap.addFunction = function (pDb, name, arity) { + const m = __dbCleanupMap(pDb, 1); + if (!m.udf) m.udf = new Map(); + this._addUDF(pDb, name, arity, m.udf); + }; + + __dbCleanupMap.addWindowFunc = function (pDb, name, arity) { + const m = __dbCleanupMap(pDb, 1); + if (!m.wudf) m.wudf = new Map(); + this._addUDF(pDb, name, arity, m.wudf); + }; + + __dbCleanupMap.cleanup = function (pDb) { + pDb = __argPDb(pDb); + + const closeArgs = [pDb]; + for (const name of [ + 'sqlite3_busy_handler', + 'sqlite3_commit_hook', + 'sqlite3_preupdate_hook', + 'sqlite3_progress_handler', + 'sqlite3_rollback_hook', + 'sqlite3_set_authorizer', + 'sqlite3_trace_v2', + 'sqlite3_update_hook', + ]) { + const x = wasm.exports[name]; + closeArgs.length = x.length; + try { + capi[name](...closeArgs); + } catch (e) { + console.warn( + 'close-time call of', + name + '(', + closeArgs, + ') threw:', + e, + ); + } + } + const m = __dbCleanupMap(pDb, 0); + if (!m) return; + if (m.collation) { + for (const name of m.collation) { + try { + capi.sqlite3_create_collation_v2( + pDb, + name, + capi.SQLITE_UTF8, + 0, + 0, + 0, + ); + } catch (e) {} + } + delete m.collation; + } + let i; + for (i = 0; i < 2; ++i) { + const fmap = i ? m.wudf : m.udf; + if (!fmap) continue; + const func = i + ? capi.sqlite3_create_window_function + : capi.sqlite3_create_function_v2; + for (const e of fmap) { + const name = e[0], + arities = e[1]; + const fargs = [pDb, name, 0, capi.SQLITE_UTF8, 0, 0, 0, 0, 0]; + if (i) fargs.push(0); + for (const arity of arities) { + try { + fargs[2] = arity; + func.apply(null, fargs); + } catch (e) {} + } + arities.clear(); + } + fmap.clear(); + } + delete m.udf; + delete m.wudf; + }; + + { + const __sqlite3CloseV2 = wasm.xWrap( + 'sqlite3_close_v2', + 'int', + 'sqlite3*', + ); + capi.sqlite3_close_v2 = function (pDb) { + if (1 !== arguments.length) + return __dbArgcMismatch(pDb, 'sqlite3_close_v2', 1); + if (pDb) { + try { + __dbCleanupMap.cleanup(pDb); + } catch (e) {} + } + return __sqlite3CloseV2(pDb); + }; + } + + if (capi.sqlite3session_table_filter) { + const __sqlite3SessionDelete = wasm.xWrap( + 'sqlite3session_delete', + undefined, + ['sqlite3_session*'], + ); + capi.sqlite3session_delete = function (pSession) { + if (1 !== arguments.length) { + return __dbArgcMismatch(pDb, 'sqlite3session_delete', 1); + } else if (pSession) { + capi.sqlite3session_table_filter(pSession, 0, 0); + } + __sqlite3SessionDelete(pSession); + }; + } + + { + const contextKey = (argv, argIndex) => { + return ( + 'argv[' + + argIndex + + ']:' + + argv[0] + + ':' + + wasm.cstrToJs(argv[1]).toLowerCase() + ); + }; + const __sqlite3CreateCollationV2 = wasm.xWrap( + 'sqlite3_create_collation_v2', + 'int', + [ + 'sqlite3*', + 'string', + 'int', + '*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xCompare', + signature: 'i(pipip)', + contextKey, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xDestroy', + signature: 'v(p)', + contextKey, + }), + ], + ); + + capi.sqlite3_create_collation_v2 = function ( + pDb, + zName, + eTextRep, + pArg, + xCompare, + xDestroy, + ) { + if (6 !== arguments.length) + return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6); + else if (0 === (eTextRep & 0xf)) { + eTextRep |= capi.SQLITE_UTF8; + } else if (capi.SQLITE_UTF8 !== (eTextRep & 0xf)) { + return __errEncoding(pDb); + } + try { + const rc = __sqlite3CreateCollationV2( + pDb, + zName, + eTextRep, + pArg, + xCompare, + xDestroy, + ); + if (0 === rc && xCompare instanceof Function) { + __dbCleanupMap.addCollation(pDb, zName); + } + return rc; + } catch (e) { + return util.sqlite3__wasm_db_error(pDb, e); + } + }; + + capi.sqlite3_create_collation = ( + pDb, + zName, + eTextRep, + pArg, + xCompare, + ) => { + return 5 === arguments.length + ? capi.sqlite3_create_collation_v2( + pDb, + zName, + eTextRep, + pArg, + xCompare, + 0, + ) + : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5); + }; + } + + { + const contextKey = function (argv, argIndex) { + return ( + argv[0] + + ':' + + (argv[2] < 0 ? -1 : argv[2]) + + ':' + + argIndex + + ':' + + wasm.cstrToJs(argv[1]).toLowerCase() + ); + }; + + const __cfProxy = Object.assign(Object.create(null), { + xInverseAndStep: { + signature: 'v(pip)', + contextKey, + callProxy: (callback) => { + return (pCtx, argc, pArgv) => { + try { + callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)); + } catch (e) { + capi.sqlite3_result_error_js(pCtx, e); + } + }; + }, + }, + xFinalAndValue: { + signature: 'v(p)', + contextKey, + callProxy: (callback) => { + return (pCtx) => { + try { + capi.sqlite3_result_js(pCtx, callback(pCtx)); + } catch (e) { + capi.sqlite3_result_error_js(pCtx, e); + } + }; + }, + }, + xFunc: { + signature: 'v(pip)', + contextKey, + callProxy: (callback) => { + return (pCtx, argc, pArgv) => { + try { + capi.sqlite3_result_js( + pCtx, + callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)), + ); + } catch (e) { + capi.sqlite3_result_error_js(pCtx, e); + } + }; + }, + }, + xDestroy: { + signature: 'v(p)', + contextKey, + + callProxy: (callback) => { + return (pVoid) => { + try { + callback(pVoid); + } catch (e) { + console.error('UDF xDestroy method threw:', e); + } + }; + }, + }, + }); + + const __sqlite3CreateFunction = wasm.xWrap( + 'sqlite3_create_function_v2', + 'int', + [ + 'sqlite3*', + 'string', + 'int', + 'int', + '*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xFunc', + ...__cfProxy.xFunc, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xStep', + ...__cfProxy.xInverseAndStep, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xFinal', + ...__cfProxy.xFinalAndValue, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xDestroy', + ...__cfProxy.xDestroy, + }), + ], + ); + + const __sqlite3CreateWindowFunction = wasm.xWrap( + 'sqlite3_create_window_function', + 'int', + [ + 'sqlite3*', + 'string', + 'int', + 'int', + '*', + new wasm.xWrap.FuncPtrAdapter({ + name: 'xStep', + ...__cfProxy.xInverseAndStep, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xFinal', + ...__cfProxy.xFinalAndValue, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xValue', + ...__cfProxy.xFinalAndValue, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xInverse', + ...__cfProxy.xInverseAndStep, + }), + new wasm.xWrap.FuncPtrAdapter({ + name: 'xDestroy', + ...__cfProxy.xDestroy, + }), + ], + ); + + capi.sqlite3_create_function_v2 = function f( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xFunc, + xStep, + xFinal, + xDestroy, + ) { + if (f.length !== arguments.length) { + return __dbArgcMismatch( + pDb, + 'sqlite3_create_function_v2', + f.length, + ); + } else if (0 === (eTextRep & 0xf)) { + eTextRep |= capi.SQLITE_UTF8; + } else if (capi.SQLITE_UTF8 !== (eTextRep & 0xf)) { + return __errEncoding(pDb); + } + try { + const rc = __sqlite3CreateFunction( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xFunc, + xStep, + xFinal, + xDestroy, + ); + if ( + 0 === rc && + (xFunc instanceof Function || + xStep instanceof Function || + xFinal instanceof Function || + xDestroy instanceof Function) + ) { + __dbCleanupMap.addFunction(pDb, funcName, nArg); + } + return rc; + } catch (e) { + console.error('sqlite3_create_function_v2() setup threw:', e); + return util.sqlite3__wasm_db_error( + pDb, + e, + 'Creation of UDF threw: ' + e, + ); + } + }; + + capi.sqlite3_create_function = function f( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xFunc, + xStep, + xFinal, + ) { + return f.length === arguments.length + ? capi.sqlite3_create_function_v2( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xFunc, + xStep, + xFinal, + 0, + ) + : __dbArgcMismatch(pDb, 'sqlite3_create_function', f.length); + }; + + capi.sqlite3_create_window_function = function f( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xStep, + xFinal, + xValue, + xInverse, + xDestroy, + ) { + if (f.length !== arguments.length) { + return __dbArgcMismatch( + pDb, + 'sqlite3_create_window_function', + f.length, + ); + } else if (0 === (eTextRep & 0xf)) { + eTextRep |= capi.SQLITE_UTF8; + } else if (capi.SQLITE_UTF8 !== (eTextRep & 0xf)) { + return __errEncoding(pDb); + } + try { + const rc = __sqlite3CreateWindowFunction( + pDb, + funcName, + nArg, + eTextRep, + pApp, + xStep, + xFinal, + xValue, + xInverse, + xDestroy, + ); + if ( + 0 === rc && + (xStep instanceof Function || + xFinal instanceof Function || + xValue instanceof Function || + xInverse instanceof Function || + xDestroy instanceof Function) + ) { + __dbCleanupMap.addWindowFunc(pDb, funcName, nArg); + } + return rc; + } catch (e) { + console.error('sqlite3_create_window_function() setup threw:', e); + return util.sqlite3__wasm_db_error( + pDb, + e, + 'Creation of UDF threw: ' + e, + ); + } + }; + + capi.sqlite3_create_function_v2.udfSetResult = + capi.sqlite3_create_function.udfSetResult = + capi.sqlite3_create_window_function.udfSetResult = + capi.sqlite3_result_js; + + capi.sqlite3_create_function_v2.udfConvertArgs = + capi.sqlite3_create_function.udfConvertArgs = + capi.sqlite3_create_window_function.udfConvertArgs = + capi.sqlite3_values_to_js; + + capi.sqlite3_create_function_v2.udfSetError = + capi.sqlite3_create_function.udfSetError = + capi.sqlite3_create_window_function.udfSetError = + capi.sqlite3_result_error_js; + } + + { + const __flexiString = (v, n) => { + if ('string' === typeof v) { + n = -1; + } else if (util.isSQLableTypedArray(v)) { + n = v.byteLength; + v = util.typedArrayToString( + v instanceof ArrayBuffer ? new Uint8Array(v) : v, + ); + } else if (Array.isArray(v)) { + v = v.join(''); + n = -1; + } + return [v, n]; + }; + + const __prepare = { + basic: wasm.xWrap('sqlite3_prepare_v3', 'int', [ + 'sqlite3*', + 'string', + 'int', + 'int', + '**', + '**', + ]), + + full: wasm.xWrap('sqlite3_prepare_v3', 'int', [ + 'sqlite3*', + '*', + 'int', + 'int', + '**', + '**', + ]), + }; + + capi.sqlite3_prepare_v3 = function f( + pDb, + sql, + sqlLen, + prepFlags, + ppStmt, + pzTail, + ) { + if (f.length !== arguments.length) { + return __dbArgcMismatch(pDb, 'sqlite3_prepare_v3', f.length); + } + const [xSql, xSqlLen] = __flexiString(sql, sqlLen); + switch (typeof xSql) { + case 'string': + return __prepare.basic( + pDb, + xSql, + xSqlLen, + prepFlags, + ppStmt, + null, + ); + case 'number': + return __prepare.full( + pDb, + xSql, + xSqlLen, + prepFlags, + ppStmt, + pzTail, + ); + default: + return util.sqlite3__wasm_db_error( + pDb, + capi.SQLITE_MISUSE, + 'Invalid SQL argument type for sqlite3_prepare_v2/v3().', + ); + } + }; + + capi.sqlite3_prepare_v2 = function f( + pDb, + sql, + sqlLen, + ppStmt, + pzTail, + ) { + return f.length === arguments.length + ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) + : __dbArgcMismatch(pDb, 'sqlite3_prepare_v2', f.length); + }; + } + + { + const __bindText = wasm.xWrap('sqlite3_bind_text', 'int', [ + 'sqlite3_stmt*', + 'int', + 'string', + 'int', + '*', + ]); + const __bindBlob = wasm.xWrap('sqlite3_bind_blob', 'int', [ + 'sqlite3_stmt*', + 'int', + '*', + 'int', + '*', + ]); + + capi.sqlite3_bind_text = function f( + pStmt, + iCol, + text, + nText, + xDestroy, + ) { + if (f.length !== arguments.length) { + return __dbArgcMismatch( + capi.sqlite3_db_handle(pStmt), + 'sqlite3_bind_text', + f.length, + ); + } else if (wasm.isPtr(text) || null === text) { + return __bindText(pStmt, iCol, text, nText, xDestroy); + } else if (text instanceof ArrayBuffer) { + text = new Uint8Array(text); + } else if (Array.isArray(pMem)) { + text = pMem.join(''); + } + let p, n; + try { + if (util.isSQLableTypedArray(text)) { + p = wasm.allocFromTypedArray(text); + n = text.byteLength; + } else if ('string' === typeof text) { + [p, n] = wasm.allocCString(text); + } else { + return util.sqlite3__wasm_db_error( + capi.sqlite3_db_handle(pStmt), + capi.SQLITE_MISUSE, + 'Invalid 3rd argument type for sqlite3_bind_text().', + ); + } + return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); + } catch (e) { + wasm.dealloc(p); + return util.sqlite3__wasm_db_error( + capi.sqlite3_db_handle(pStmt), + e, + ); + } + }; + + capi.sqlite3_bind_blob = function f( + pStmt, + iCol, + pMem, + nMem, + xDestroy, + ) { + if (f.length !== arguments.length) { + return __dbArgcMismatch( + capi.sqlite3_db_handle(pStmt), + 'sqlite3_bind_blob', + f.length, + ); + } else if (wasm.isPtr(pMem) || null === pMem) { + return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy); + } else if (pMem instanceof ArrayBuffer) { + pMem = new Uint8Array(pMem); + } else if (Array.isArray(pMem)) { + pMem = pMem.join(''); + } + let p, n; + try { + if (util.isBindableTypedArray(pMem)) { + p = wasm.allocFromTypedArray(pMem); + n = nMem >= 0 ? nMem : pMem.byteLength; + } else if ('string' === typeof pMem) { + [p, n] = wasm.allocCString(pMem); + } else { + return util.sqlite3__wasm_db_error( + capi.sqlite3_db_handle(pStmt), + capi.SQLITE_MISUSE, + 'Invalid 3rd argument type for sqlite3_bind_blob().', + ); + } + return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); + } catch (e) { + wasm.dealloc(p); + return util.sqlite3__wasm_db_error( + capi.sqlite3_db_handle(pStmt), + e, + ); + } + }; + } + + { + capi.sqlite3_config = function (op, ...args) { + if (arguments.length < 2) return capi.SQLITE_MISUSE; + switch (op) { + case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN: + case capi.SQLITE_CONFIG_MEMSTATUS: + case capi.SQLITE_CONFIG_SMALL_MALLOC: + case capi.SQLITE_CONFIG_SORTERREF_SIZE: + case capi.SQLITE_CONFIG_STMTJRNL_SPILL: + case capi.SQLITE_CONFIG_URI: + return wasm.exports.sqlite3__wasm_config_i(op, args[0]); + case capi.SQLITE_CONFIG_LOOKASIDE: + return wasm.exports.sqlite3__wasm_config_ii( + op, + args[0], + args[1], + ); + case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: + return wasm.exports.sqlite3__wasm_config_j(op, args[0]); + case capi.SQLITE_CONFIG_GETMALLOC: + case capi.SQLITE_CONFIG_GETMUTEX: + case capi.SQLITE_CONFIG_GETPCACHE2: + case capi.SQLITE_CONFIG_GETPCACHE: + case capi.SQLITE_CONFIG_HEAP: + case capi.SQLITE_CONFIG_LOG: + case capi.SQLITE_CONFIG_MALLOC: + case capi.SQLITE_CONFIG_MMAP_SIZE: + case capi.SQLITE_CONFIG_MULTITHREAD: + case capi.SQLITE_CONFIG_MUTEX: + case capi.SQLITE_CONFIG_PAGECACHE: + case capi.SQLITE_CONFIG_PCACHE2: + case capi.SQLITE_CONFIG_PCACHE: + case capi.SQLITE_CONFIG_PCACHE_HDRSZ: + case capi.SQLITE_CONFIG_PMASZ: + case capi.SQLITE_CONFIG_SERIALIZED: + case capi.SQLITE_CONFIG_SINGLETHREAD: + case capi.SQLITE_CONFIG_SQLLOG: + case capi.SQLITE_CONFIG_WIN32_HEAPSIZE: + default: + return capi.SQLITE_NOTFOUND; + } + }; + } + + { + const __autoExtFptr = new Set(); + + capi.sqlite3_auto_extension = function (fPtr) { + if (fPtr instanceof Function) { + fPtr = wasm.installFunction('i(ppp)', fPtr); + } else if (1 !== arguments.length || !wasm.isPtr(fPtr)) { + return capi.SQLITE_MISUSE; + } + const rc = wasm.exports.sqlite3_auto_extension(fPtr); + if (fPtr !== arguments[0]) { + if (0 === rc) __autoExtFptr.add(fPtr); + else wasm.uninstallFunction(fPtr); + } + return rc; + }; + + capi.sqlite3_cancel_auto_extension = function (fPtr) { + if (!fPtr || 1 !== arguments.length || !wasm.isPtr(fPtr)) return 0; + return wasm.exports.sqlite3_cancel_auto_extension(fPtr); + }; + + capi.sqlite3_reset_auto_extension = function () { + wasm.exports.sqlite3_reset_auto_extension(); + for (const fp of __autoExtFptr) wasm.uninstallFunction(fp); + __autoExtFptr.clear(); + }; + } + + const pKvvfs = capi.sqlite3_vfs_find('kvvfs'); + if (pKvvfs) { + if (util.isUIThread()) { + const kvvfsMethods = new capi.sqlite3_kvvfs_methods( + wasm.exports.sqlite3__wasm_kvvfs_methods(), + ); + delete capi.sqlite3_kvvfs_methods; + + const kvvfsMakeKey = + wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack, + pstack = wasm.pstack; + + const kvvfsStorage = (zClass) => + 115 === wasm.peek(zClass) ? sessionStorage : localStorage; + + const kvvfsImpls = { + xRead: (zClass, zKey, zBuf, nBuf) => { + const stack = pstack.pointer, + astack = wasm.scopedAllocPush(); + try { + const zXKey = kvvfsMakeKey(zClass, zKey); + if (!zXKey) return -3; + const jKey = wasm.cstrToJs(zXKey); + const jV = kvvfsStorage(zClass).getItem(jKey); + if (!jV) return -1; + const nV = jV.length; + if (nBuf <= 0) return nV; + else if (1 === nBuf) { + wasm.poke(zBuf, 0); + return nV; + } + const zV = wasm.scopedAllocCString(jV); + if (nBuf > nV + 1) nBuf = nV + 1; + wasm.heap8u().copyWithin(zBuf, zV, zV + nBuf - 1); + wasm.poke(zBuf + nBuf - 1, 0); + return nBuf - 1; + } catch (e) { + console.error('kvstorageRead()', e); + return -2; + } finally { + pstack.restore(stack); + wasm.scopedAllocPop(astack); + } + }, + xWrite: (zClass, zKey, zData) => { + const stack = pstack.pointer; + try { + const zXKey = kvvfsMakeKey(zClass, zKey); + if (!zXKey) return 1; + const jKey = wasm.cstrToJs(zXKey); + kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData)); + return 0; + } catch (e) { + console.error('kvstorageWrite()', e); + return capi.SQLITE_IOERR; + } finally { + pstack.restore(stack); + } + }, + xDelete: (zClass, zKey) => { + const stack = pstack.pointer; + try { + const zXKey = kvvfsMakeKey(zClass, zKey); + if (!zXKey) return 1; + kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey)); + return 0; + } catch (e) { + console.error('kvstorageDelete()', e); + return capi.SQLITE_IOERR; + } finally { + pstack.restore(stack); + } + }, + }; + for (const k of Object.keys(kvvfsImpls)) { + kvvfsMethods[kvvfsMethods.memberKey(k)] = wasm.installFunction( + kvvfsMethods.memberSignature(k), + kvvfsImpls[k], + ); + } + } else { + capi.sqlite3_vfs_unregister(pKvvfs); + } + } + + wasm.xWrap.FuncPtrAdapter.warnOnUse = true; + + const StructBinder = sqlite3.StructBinder; + const installMethod = function callee( + tgt, + name, + func, + applyArgcCheck = callee.installMethodArgcCheck, + ) { + if (!(tgt instanceof StructBinder.StructType)) { + toss('Usage error: target object is-not-a StructType.'); + } else if (!(func instanceof Function) && !wasm.isPtr(func)) { + toss('Usage errror: expecting a Function or WASM pointer to one.'); + } + if (1 === arguments.length) { + return (n, f) => callee(tgt, n, f, applyArgcCheck); + } + if (!callee.argcProxy) { + callee.argcProxy = function (tgt, funcName, func, sig) { + return function (...args) { + if (func.length !== arguments.length) { + toss( + 'Argument mismatch for', + tgt.structInfo.name + + '::' + + funcName + + ': Native signature is:', + sig, + ); + } + return func.apply(this, args); + }; + }; + + callee.removeFuncList = function () { + if (this.ondispose.__removeFuncList) { + this.ondispose.__removeFuncList.forEach((v, ndx) => { + if ('number' === typeof v) { + try { + wasm.uninstallFunction(v); + } catch (e) {} + } + }); + delete this.ondispose.__removeFuncList; + } + }; + } + const sigN = tgt.memberSignature(name); + if (sigN.length < 2) { + toss( + 'Member', + name, + 'does not have a function pointer signature:', + sigN, + ); + } + const memKey = tgt.memberKey(name); + const fProxy = + applyArgcCheck && !wasm.isPtr(func) + ? callee.argcProxy(tgt, memKey, func, sigN) + : func; + if (wasm.isPtr(fProxy)) { + if (fProxy && !wasm.functionEntry(fProxy)) { + toss('Pointer', fProxy, 'is not a WASM function table entry.'); + } + tgt[memKey] = fProxy; + } else { + const pFunc = wasm.installFunction( + fProxy, + tgt.memberSignature(name, true), + ); + tgt[memKey] = pFunc; + if (!tgt.ondispose || !tgt.ondispose.__removeFuncList) { + tgt.addOnDispose( + 'ondispose.__removeFuncList handler', + callee.removeFuncList, + ); + tgt.ondispose.__removeFuncList = []; + } + tgt.ondispose.__removeFuncList.push(memKey, pFunc); + } + return (n, f) => callee(tgt, n, f, applyArgcCheck); + }; + installMethod.installMethodArgcCheck = false; + + const installMethods = function ( + structInstance, + methods, + applyArgcCheck = installMethod.installMethodArgcCheck, + ) { + const seen = new Map(); + for (const k of Object.keys(methods)) { + const m = methods[k]; + const prior = seen.get(m); + if (prior) { + const mkey = structInstance.memberKey(k); + structInstance[mkey] = + structInstance[structInstance.memberKey(prior)]; + } else { + installMethod(structInstance, k, m, applyArgcCheck); + seen.set(m, k); + } + } + return structInstance; + }; + + StructBinder.StructType.prototype.installMethod = function callee( + name, + func, + applyArgcCheck = installMethod.installMethodArgcCheck, + ) { + return arguments.length < 3 && name && 'object' === typeof name + ? installMethods(this, ...arguments) + : installMethod(this, ...arguments); + }; + + StructBinder.StructType.prototype.installMethods = function ( + methods, + applyArgcCheck = installMethod.installMethodArgcCheck, + ) { + return installMethods(this, methods, applyArgcCheck); + }; + }); + + globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { + sqlite3.version = { + libVersion: '3.46.1', + libVersionNumber: 3046001, + sourceId: + '2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33', + downloadVersion: 3460100, + }; + }); + + globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { + const toss3 = (...args) => { + throw new sqlite3.SQLite3Error(...args); + }; + + const capi = sqlite3.capi, + wasm = sqlite3.wasm, + util = sqlite3.util; + + const __ptrMap = new WeakMap(); + + const __stmtMap = new WeakMap(); + + const getOwnOption = (opts, p, dflt) => { + const d = Object.getOwnPropertyDescriptor(opts, p); + return d ? d.value : dflt; + }; + + const checkSqlite3Rc = function (dbPtr, sqliteResultCode) { + if (sqliteResultCode) { + if (dbPtr instanceof DB) dbPtr = dbPtr.pointer; + toss3( + sqliteResultCode, + 'sqlite3 result code', + sqliteResultCode + ':', + dbPtr + ? capi.sqlite3_errmsg(dbPtr) + : capi.sqlite3_errstr(sqliteResultCode), + ); + } + return arguments[0]; + }; + + const __dbTraceToConsole = wasm.installFunction( + 'i(ippp)', + function (t, c, p, x) { + if (capi.SQLITE_TRACE_STMT === t) { + console.log( + 'SQL TRACE #' + ++this.counter + ' via sqlite3@' + c + ':', + wasm.cstrToJs(x), + ); + } + }.bind({ counter: 0 }), + ); + + const __vfsPostOpenSql = Object.create(null); + + const dbCtorHelper = function ctor(...args) { + if (!ctor._name2vfs) { + ctor._name2vfs = Object.create(null); + const isWorkerThread = + 'function' === typeof importScripts + ? (n) => + toss3( + 'The VFS for', + n, + 'is only available in the main window thread.', + ) + : false; + ctor._name2vfs[':localStorage:'] = { + vfs: 'kvvfs', + filename: isWorkerThread || (() => 'local'), + }; + ctor._name2vfs[':sessionStorage:'] = { + vfs: 'kvvfs', + filename: isWorkerThread || (() => 'session'), + }; + } + const opt = ctor.normalizeArgs(...args); + let fn = opt.filename, + vfsName = opt.vfs, + flagsStr = opt.flags; + if ( + ('string' !== typeof fn && 'number' !== typeof fn) || + 'string' !== typeof flagsStr || + (vfsName && + 'string' !== typeof vfsName && + 'number' !== typeof vfsName) + ) { + sqlite3.config.error('Invalid DB ctor args', opt, arguments); + toss3('Invalid arguments for DB constructor.'); + } + let fnJs = 'number' === typeof fn ? wasm.cstrToJs(fn) : fn; + const vfsCheck = ctor._name2vfs[fnJs]; + if (vfsCheck) { + vfsName = vfsCheck.vfs; + fn = fnJs = vfsCheck.filename(fnJs); + } + let pDb, + oflags = 0; + if (flagsStr.indexOf('c') >= 0) { + oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; + } + if (flagsStr.indexOf('w') >= 0) oflags |= capi.SQLITE_OPEN_READWRITE; + if (0 === oflags) oflags |= capi.SQLITE_OPEN_READONLY; + oflags |= capi.SQLITE_OPEN_EXRESCODE; + const stack = wasm.pstack.pointer; + try { + const pPtr = wasm.pstack.allocPtr(); + let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0); + pDb = wasm.peekPtr(pPtr); + checkSqlite3Rc(pDb, rc); + capi.sqlite3_extended_result_codes(pDb, 1); + if (flagsStr.indexOf('t') >= 0) { + capi.sqlite3_trace_v2( + pDb, + capi.SQLITE_TRACE_STMT, + __dbTraceToConsole, + pDb, + ); + } + } catch (e) { + if (pDb) capi.sqlite3_close_v2(pDb); + throw e; + } finally { + wasm.pstack.restore(stack); + } + this.filename = fnJs; + __ptrMap.set(this, pDb); + __stmtMap.set(this, Object.create(null)); + try { + const pVfs = + capi.sqlite3_js_db_vfs(pDb) || + toss3('Internal error: cannot get VFS for new db handle.'); + const postInitSql = __vfsPostOpenSql[pVfs]; + if (postInitSql) { + if (postInitSql instanceof Function) { + postInitSql(this, sqlite3); + } else { + checkSqlite3Rc( + pDb, + capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0), + ); + } + } + } catch (e) { + this.close(); + throw e; + } + }; + + dbCtorHelper.setVfsPostOpenSql = function (pVfs, sql) { + __vfsPostOpenSql[pVfs] = sql; + }; + + dbCtorHelper.normalizeArgs = function ( + filename = ':memory:', + flags = 'c', + vfs = null, + ) { + const arg = {}; + if ( + 1 === arguments.length && + arguments[0] && + 'object' === typeof arguments[0] + ) { + Object.assign(arg, arguments[0]); + if (undefined === arg.flags) arg.flags = 'c'; + if (undefined === arg.vfs) arg.vfs = null; + if (undefined === arg.filename) arg.filename = ':memory:'; + } else { + arg.filename = filename; + arg.flags = flags; + arg.vfs = vfs; + } + return arg; + }; + + const DB = function (...args) { + dbCtorHelper.apply(this, args); + }; + DB.dbCtorHelper = dbCtorHelper; + + const BindTypes = { + null: 1, + number: 2, + string: 3, + boolean: 4, + blob: 5, + }; + BindTypes['undefined'] == BindTypes.null; + if (wasm.bigIntEnabled) { + BindTypes.bigint = BindTypes.number; + } + + const Stmt = function () { + if (BindTypes !== arguments[2]) { + toss3( + capi.SQLITE_MISUSE, + 'Do not call the Stmt constructor directly. Use DB.prepare().', + ); + } + this.db = arguments[0]; + __ptrMap.set(this, arguments[1]); + this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer); + }; + + const affirmDbOpen = function (db) { + if (!db.pointer) toss3('DB has been closed.'); + return db; + }; + + const affirmColIndex = function (stmt, ndx) { + if (ndx !== (ndx | 0) || ndx < 0 || ndx >= stmt.columnCount) { + toss3('Column index', ndx, 'is out of range.'); + } + return stmt; + }; + + const parseExecArgs = function (db, args) { + const out = Object.create(null); + out.opt = Object.create(null); + switch (args.length) { + case 1: + if ( + 'string' === typeof args[0] || + util.isSQLableTypedArray(args[0]) + ) { + out.sql = args[0]; + } else if (Array.isArray(args[0])) { + out.sql = args[0]; + } else if (args[0] && 'object' === typeof args[0]) { + out.opt = args[0]; + out.sql = out.opt.sql; + } + break; + case 2: + out.sql = args[0]; + out.opt = args[1]; + break; + default: + toss3('Invalid argument count for exec().'); + } + out.sql = util.flexibleString(out.sql); + if ('string' !== typeof out.sql) { + toss3('Missing SQL argument or unsupported SQL value type.'); + } + const opt = out.opt; + switch (opt.returnValue) { + case 'resultRows': + if (!opt.resultRows) opt.resultRows = []; + out.returnVal = () => opt.resultRows; + break; + case 'saveSql': + if (!opt.saveSql) opt.saveSql = []; + out.returnVal = () => opt.saveSql; + break; + case undefined: + case 'this': + out.returnVal = () => db; + break; + default: + toss3('Invalid returnValue value:', opt.returnValue); + } + if (!opt.callback && !opt.returnValue && undefined !== opt.rowMode) { + if (!opt.resultRows) opt.resultRows = []; + out.returnVal = () => opt.resultRows; + } + if (opt.callback || opt.resultRows) { + switch (undefined === opt.rowMode ? 'array' : opt.rowMode) { + case 'object': + out.cbArg = (stmt, cache) => { + if (!cache.columnNames) + cache.columnNames = stmt.getColumnNames([]); + + const row = stmt.get([]); + const rv = Object.create(null); + for (const i in cache.columnNames) + rv[cache.columnNames[i]] = row[i]; + return rv; + }; + break; + case 'array': + out.cbArg = (stmt) => stmt.get([]); + break; + case 'stmt': + if (Array.isArray(opt.resultRows)) { + toss3( + 'exec(): invalid rowMode for a resultRows array: must', + "be one of 'array', 'object',", + 'a result column number, or column name reference.', + ); + } + out.cbArg = (stmt) => stmt; + break; + default: + if (util.isInt32(opt.rowMode)) { + out.cbArg = (stmt) => stmt.get(opt.rowMode); + break; + } else if ( + 'string' === typeof opt.rowMode && + opt.rowMode.length > 1 && + '$' === opt.rowMode[0] + ) { + const $colName = opt.rowMode.substr(1); + out.cbArg = (stmt) => { + const rc = stmt.get(Object.create(null))[$colName]; + return undefined === rc + ? toss3( + capi.SQLITE_NOTFOUND, + 'exec(): unknown result column:', + $colName, + ) + : rc; + }; + break; + } + toss3('Invalid rowMode:', opt.rowMode); + } + } + return out; + }; + + const __selectFirstRow = (db, sql, bind, ...getArgs) => { + const stmt = db.prepare(sql); + try { + const rc = stmt.bind(bind).step() + ? stmt.get(...getArgs) + : undefined; + stmt.reset(); + return rc; + } finally { + stmt.finalize(); + } + }; + + const __selectAll = (db, sql, bind, rowMode) => + db.exec({ + sql, + bind, + rowMode, + returnValue: 'resultRows', + }); + + DB.checkRc = (db, resultCode) => checkSqlite3Rc(db, resultCode); + + DB.prototype = { + isOpen: function () { + return !!this.pointer; + }, + + affirmOpen: function () { + return affirmDbOpen(this); + }, + + close: function () { + if (this.pointer) { + if (this.onclose && this.onclose.before instanceof Function) { + try { + this.onclose.before(this); + } catch (e) {} + } + const pDb = this.pointer; + Object.keys(__stmtMap.get(this)).forEach((k, s) => { + if (s && s.pointer) { + try { + s.finalize(); + } catch (e) {} + } + }); + __ptrMap.delete(this); + __stmtMap.delete(this); + capi.sqlite3_close_v2(pDb); + if (this.onclose && this.onclose.after instanceof Function) { + try { + this.onclose.after(this); + } catch (e) {} + } + delete this.filename; + } + }, + + changes: function (total = false, sixtyFour = false) { + const p = affirmDbOpen(this).pointer; + if (total) { + return sixtyFour + ? capi.sqlite3_total_changes64(p) + : capi.sqlite3_total_changes(p); + } else { + return sixtyFour + ? capi.sqlite3_changes64(p) + : capi.sqlite3_changes(p); + } + }, + + dbFilename: function (dbName = 'main') { + return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName); + }, + + dbName: function (dbNumber = 0) { + return capi.sqlite3_db_name(affirmDbOpen(this).pointer, dbNumber); + }, + + dbVfsName: function (dbName = 0) { + let rc; + const pVfs = capi.sqlite3_js_db_vfs( + affirmDbOpen(this).pointer, + dbName, + ); + if (pVfs) { + const v = new capi.sqlite3_vfs(pVfs); + try { + rc = wasm.cstrToJs(v.$zName); + } finally { + v.dispose(); + } + } + return rc; + }, + + prepare: function (sql) { + affirmDbOpen(this); + const stack = wasm.pstack.pointer; + let ppStmt, pStmt; + try { + ppStmt = wasm.pstack.alloc(8); + DB.checkRc( + this, + capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null), + ); + pStmt = wasm.peekPtr(ppStmt); + } finally { + wasm.pstack.restore(stack); + } + if (!pStmt) toss3('Cannot prepare empty SQL.'); + const stmt = new Stmt(this, pStmt, BindTypes); + __stmtMap.get(this)[pStmt] = stmt; + return stmt; + }, + + exec: function () { + affirmDbOpen(this); + const arg = parseExecArgs(this, arguments); + if (!arg.sql) { + return toss3('exec() requires an SQL string.'); + } + const opt = arg.opt; + const callback = opt.callback; + const resultRows = Array.isArray(opt.resultRows) + ? opt.resultRows + : undefined; + let stmt; + let bind = opt.bind; + let evalFirstResult = !!( + arg.cbArg || + opt.columnNames || + resultRows + ); + const stack = wasm.scopedAllocPush(); + const saveSql = Array.isArray(opt.saveSql) + ? opt.saveSql + : undefined; + try { + const isTA = util.isSQLableTypedArray(arg.sql); + let sqlByteLen = isTA + ? arg.sql.byteLength + : wasm.jstrlen(arg.sql); + const ppStmt = wasm.scopedAlloc( + 2 * wasm.ptrSizeof + (sqlByteLen + 1), + ); + const pzTail = ppStmt + wasm.ptrSizeof; + let pSql = pzTail + wasm.ptrSizeof; + const pSqlEnd = pSql + sqlByteLen; + if (isTA) wasm.heap8().set(arg.sql, pSql); + else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false); + wasm.poke(pSql + sqlByteLen, 0); + while (pSql && wasm.peek(pSql, 'i8')) { + wasm.pokePtr([ppStmt, pzTail], 0); + DB.checkRc( + this, + capi.sqlite3_prepare_v3( + this.pointer, + pSql, + sqlByteLen, + 0, + ppStmt, + pzTail, + ), + ); + const pStmt = wasm.peekPtr(ppStmt); + pSql = wasm.peekPtr(pzTail); + sqlByteLen = pSqlEnd - pSql; + if (!pStmt) continue; + if (saveSql) saveSql.push(capi.sqlite3_sql(pStmt).trim()); + stmt = new Stmt(this, pStmt, BindTypes); + if (bind && stmt.parameterCount) { + stmt.bind(bind); + bind = null; + } + if (evalFirstResult && stmt.columnCount) { + let gotColNames = Array.isArray(opt.columnNames) ? 0 : 1; + evalFirstResult = false; + if (arg.cbArg || resultRows) { + const cbArgCache = Object.create(null); + for (; stmt.step(); stmt._lockedByExec = false) { + if (0 === gotColNames++) { + stmt.getColumnNames( + (cbArgCache.columnNames = opt.columnNames || []), + ); + } + stmt._lockedByExec = true; + const row = arg.cbArg(stmt, cbArgCache); + if (resultRows) resultRows.push(row); + if (callback && false === callback.call(opt, row, stmt)) { + break; + } + } + stmt._lockedByExec = false; + } + if (0 === gotColNames) { + stmt.getColumnNames(opt.columnNames); + } + } else { + stmt.step(); + } + stmt.reset().finalize(); + stmt = null; + } + } finally { + wasm.scopedAllocPop(stack); + if (stmt) { + delete stmt._lockedByExec; + stmt.finalize(); + } + } + return arg.returnVal(); + }, + + createFunction: function f(name, xFunc, opt) { + const isFunc = (f) => f instanceof Function; + switch (arguments.length) { + case 1: + opt = name; + name = opt.name; + xFunc = opt.xFunc || 0; + break; + case 2: + if (!isFunc(xFunc)) { + opt = xFunc; + xFunc = opt.xFunc || 0; + } + break; + } + if (!opt) opt = {}; + if ('string' !== typeof name) { + toss3('Invalid arguments: missing function name.'); + } + let xStep = opt.xStep || 0; + let xFinal = opt.xFinal || 0; + const xValue = opt.xValue || 0; + const xInverse = opt.xInverse || 0; + let isWindow = undefined; + if (isFunc(xFunc)) { + isWindow = false; + if (isFunc(xStep) || isFunc(xFinal)) { + toss3('Ambiguous arguments: scalar or aggregate?'); + } + xStep = xFinal = null; + } else if (isFunc(xStep)) { + if (!isFunc(xFinal)) { + toss3('Missing xFinal() callback for aggregate or window UDF.'); + } + xFunc = null; + } else if (isFunc(xFinal)) { + toss3('Missing xStep() callback for aggregate or window UDF.'); + } else { + toss3('Missing function-type properties.'); + } + if (false === isWindow) { + if (isFunc(xValue) || isFunc(xInverse)) { + toss3( + 'xValue and xInverse are not permitted for non-window UDFs.', + ); + } + } else if (isFunc(xValue)) { + if (!isFunc(xInverse)) { + toss3('xInverse must be provided if xValue is.'); + } + isWindow = true; + } else if (isFunc(xInverse)) { + toss3('xValue must be provided if xInverse is.'); + } + const pApp = opt.pApp; + if ( + undefined !== pApp && + null !== pApp && + ('number' !== typeof pApp || !util.isInt32(pApp)) + ) { + toss3( + 'Invalid value for pApp property. Must be a legal WASM pointer value.', + ); + } + const xDestroy = opt.xDestroy || 0; + if (xDestroy && !isFunc(xDestroy)) { + toss3('xDestroy property must be a function.'); + } + let fFlags = 0; + if (getOwnOption(opt, 'deterministic')) + fFlags |= capi.SQLITE_DETERMINISTIC; + if (getOwnOption(opt, 'directOnly')) + fFlags |= capi.SQLITE_DIRECTONLY; + if (getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS; + name = name.toLowerCase(); + const xArity = xFunc || xStep; + const arity = getOwnOption(opt, 'arity'); + const arityArg = + 'number' === typeof arity + ? arity + : xArity.length + ? xArity.length - 1 + : 0; + let rc; + if (isWindow) { + rc = capi.sqlite3_create_window_function( + this.pointer, + name, + arityArg, + capi.SQLITE_UTF8 | fFlags, + pApp || 0, + xStep, + xFinal, + xValue, + xInverse, + xDestroy, + ); + } else { + rc = capi.sqlite3_create_function_v2( + this.pointer, + name, + arityArg, + capi.SQLITE_UTF8 | fFlags, + pApp || 0, + xFunc, + xStep, + xFinal, + xDestroy, + ); + } + DB.checkRc(this, rc); + return this; + }, + + selectValue: function (sql, bind, asType) { + return __selectFirstRow(this, sql, bind, 0, asType); + }, + + selectValues: function (sql, bind, asType) { + const stmt = this.prepare(sql), + rc = []; + try { + stmt.bind(bind); + while (stmt.step()) rc.push(stmt.get(0, asType)); + stmt.reset(); + } finally { + stmt.finalize(); + } + return rc; + }, + + selectArray: function (sql, bind) { + return __selectFirstRow(this, sql, bind, []); + }, + + selectObject: function (sql, bind) { + return __selectFirstRow(this, sql, bind, {}); + }, + + selectArrays: function (sql, bind) { + return __selectAll(this, sql, bind, 'array'); + }, + + selectObjects: function (sql, bind) { + return __selectAll(this, sql, bind, 'object'); + }, + + openStatementCount: function () { + return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0; + }, + + transaction: function (callback) { + let opener = 'BEGIN'; + if (arguments.length > 1) { + if (/[^a-zA-Z]/.test(arguments[0])) { + toss3( + capi.SQLITE_MISUSE, + 'Invalid argument for BEGIN qualifier.', + ); + } + opener += ' ' + arguments[0]; + callback = arguments[1]; + } + affirmDbOpen(this).exec(opener); + try { + const rc = callback(this); + this.exec('COMMIT'); + return rc; + } catch (e) { + this.exec('ROLLBACK'); + throw e; + } + }, + + savepoint: function (callback) { + affirmDbOpen(this).exec('SAVEPOINT oo1'); + try { + const rc = callback(this); + this.exec('RELEASE oo1'); + return rc; + } catch (e) { + this.exec('ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1'); + throw e; + } + }, + + checkRc: function (resultCode) { + return checkSqlite3Rc(this, resultCode); + }, + }; + + const affirmStmtOpen = function (stmt) { + if (!stmt.pointer) toss3('Stmt has been closed.'); + return stmt; + }; + + const isSupportedBindType = function (v) { + let t = BindTypes[null === v || undefined === v ? 'null' : typeof v]; + switch (t) { + case BindTypes.boolean: + case BindTypes.null: + case BindTypes.number: + case BindTypes.string: + return t; + case BindTypes.bigint: + if (wasm.bigIntEnabled) return t; + + default: + return util.isBindableTypedArray(v) ? BindTypes.blob : undefined; + } + }; + + const affirmSupportedBindType = function (v) { + return ( + isSupportedBindType(v) || + toss3('Unsupported bind() argument type:', typeof v) + ); + }; + + const affirmParamIndex = function (stmt, key) { + const n = + 'number' === typeof key + ? key + : capi.sqlite3_bind_parameter_index(stmt.pointer, key); + if (0 === n || !util.isInt32(n)) { + toss3('Invalid bind() parameter name: ' + key); + } else if (n < 1 || n > stmt.parameterCount) + toss3('Bind index', key, 'is out of range.'); + return n; + }; + + const affirmNotLockedByExec = function (stmt, currentOpName) { + if (stmt._lockedByExec) { + toss3( + 'Operation is illegal when statement is locked:', + currentOpName, + ); + } + return stmt; + }; + + const bindOne = function f(stmt, ndx, bindType, val) { + affirmNotLockedByExec(affirmStmtOpen(stmt), 'bind()'); + if (!f._) { + f._tooBigInt = (v) => + toss3( + 'BigInt value is too big to store without precision loss:', + v, + ); + f._ = { + string: function (stmt, ndx, val, asBlob) { + const [pStr, n] = wasm.allocCString(val, true); + const f = asBlob + ? capi.sqlite3_bind_blob + : capi.sqlite3_bind_text; + return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_WASM_DEALLOC); + }, + }; + } + affirmSupportedBindType(val); + ndx = affirmParamIndex(stmt, ndx); + let rc = 0; + switch ( + null === val || undefined === val ? BindTypes.null : bindType + ) { + case BindTypes.null: + rc = capi.sqlite3_bind_null(stmt.pointer, ndx); + break; + case BindTypes.string: + rc = f._.string(stmt, ndx, val, false); + break; + case BindTypes.number: { + let m; + if (util.isInt32(val)) m = capi.sqlite3_bind_int; + else if ('bigint' === typeof val) { + if (!util.bigIntFits64(val)) { + f._tooBigInt(val); + } else if (wasm.bigIntEnabled) { + m = capi.sqlite3_bind_int64; + } else if (util.bigIntFitsDouble(val)) { + val = Number(val); + m = capi.sqlite3_bind_double; + } else { + f._tooBigInt(val); + } + } else { + val = Number(val); + if (wasm.bigIntEnabled && Number.isInteger(val)) { + m = capi.sqlite3_bind_int64; + } else { + m = capi.sqlite3_bind_double; + } + } + rc = m(stmt.pointer, ndx, val); + break; + } + case BindTypes.boolean: + rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0); + break; + case BindTypes.blob: { + if ('string' === typeof val) { + rc = f._.string(stmt, ndx, val, true); + break; + } else if (val instanceof ArrayBuffer) { + val = new Uint8Array(val); + } else if (!util.isBindableTypedArray(val)) { + toss3( + 'Binding a value as a blob requires', + 'that it be a string, Uint8Array, Int8Array, or ArrayBuffer.', + ); + } + const pBlob = wasm.alloc(val.byteLength || 1); + wasm.heap8().set(val.byteLength ? val : [0], pBlob); + rc = capi.sqlite3_bind_blob( + stmt.pointer, + ndx, + pBlob, + val.byteLength, + capi.SQLITE_WASM_DEALLOC, + ); + break; + } + default: + sqlite3.config.warn('Unsupported bind() argument type:', val); + toss3('Unsupported bind() argument type: ' + typeof val); + } + if (rc) DB.checkRc(stmt.db.pointer, rc); + stmt._mayGet = false; + return stmt; + }; + + Stmt.prototype = { + finalize: function () { + if (this.pointer) { + affirmNotLockedByExec(this, 'finalize()'); + const rc = capi.sqlite3_finalize(this.pointer); + delete __stmtMap.get(this.db)[this.pointer]; + __ptrMap.delete(this); + delete this._mayGet; + delete this.parameterCount; + delete this._lockedByExec; + delete this.db; + return rc; + } + }, + + clearBindings: function () { + affirmNotLockedByExec(affirmStmtOpen(this), 'clearBindings()'); + capi.sqlite3_clear_bindings(this.pointer); + this._mayGet = false; + return this; + }, + + reset: function (alsoClearBinds) { + affirmNotLockedByExec(this, 'reset()'); + if (alsoClearBinds) this.clearBindings(); + const rc = capi.sqlite3_reset(affirmStmtOpen(this).pointer); + this._mayGet = false; + checkSqlite3Rc(this.db, rc); + return this; + }, + + bind: function () { + affirmStmtOpen(this); + let ndx, arg; + switch (arguments.length) { + case 1: + ndx = 1; + arg = arguments[0]; + break; + case 2: + ndx = arguments[0]; + arg = arguments[1]; + break; + default: + toss3('Invalid bind() arguments.'); + } + if (undefined === arg) { + return this; + } else if (!this.parameterCount) { + toss3('This statement has no bindable parameters.'); + } + this._mayGet = false; + if (null === arg) { + return bindOne(this, ndx, BindTypes.null, arg); + } else if (Array.isArray(arg)) { + if (1 !== arguments.length) { + toss3( + 'When binding an array, an index argument is not permitted.', + ); + } + arg.forEach((v, i) => + bindOne(this, i + 1, affirmSupportedBindType(v), v), + ); + return this; + } else if (arg instanceof ArrayBuffer) { + arg = new Uint8Array(arg); + } + if ('object' === typeof arg && !util.isBindableTypedArray(arg)) { + if (1 !== arguments.length) { + toss3( + 'When binding an object, an index argument is not permitted.', + ); + } + Object.keys(arg).forEach((k) => + bindOne(this, k, affirmSupportedBindType(arg[k]), arg[k]), + ); + return this; + } else { + return bindOne(this, ndx, affirmSupportedBindType(arg), arg); + } + }, + + bindAsBlob: function (ndx, arg) { + affirmStmtOpen(this); + if (1 === arguments.length) { + arg = ndx; + ndx = 1; + } + const t = affirmSupportedBindType(arg); + if ( + BindTypes.string !== t && + BindTypes.blob !== t && + BindTypes.null !== t + ) { + toss3('Invalid value type for bindAsBlob()'); + } + return bindOne(this, ndx, BindTypes.blob, arg); + }, + + step: function () { + affirmNotLockedByExec(this, 'step()'); + const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer); + switch (rc) { + case capi.SQLITE_DONE: + return (this._mayGet = false); + case capi.SQLITE_ROW: + return (this._mayGet = true); + default: + this._mayGet = false; + sqlite3.config.warn( + 'sqlite3_step() rc=', + rc, + capi.sqlite3_js_rc_str(rc), + 'SQL =', + capi.sqlite3_sql(this.pointer), + ); + DB.checkRc(this.db.pointer, rc); + } + }, + + stepReset: function () { + this.step(); + return this.reset(); + }, + + stepFinalize: function () { + try { + const rc = this.step(); + this.reset(); + return rc; + } finally { + try { + this.finalize(); + } catch (e) {} + } + }, + + get: function (ndx, asType) { + if (!affirmStmtOpen(this)._mayGet) { + toss3('Stmt.step() has not (recently) returned true.'); + } + if (Array.isArray(ndx)) { + let i = 0; + const n = this.columnCount; + while (i < n) { + ndx[i] = this.get(i++); + } + return ndx; + } else if (ndx && 'object' === typeof ndx) { + let i = 0; + const n = this.columnCount; + while (i < n) { + ndx[capi.sqlite3_column_name(this.pointer, i)] = this.get(i++); + } + return ndx; + } + affirmColIndex(this, ndx); + switch ( + undefined === asType + ? capi.sqlite3_column_type(this.pointer, ndx) + : asType + ) { + case capi.SQLITE_NULL: + return null; + case capi.SQLITE_INTEGER: { + if (wasm.bigIntEnabled) { + const rc = capi.sqlite3_column_int64(this.pointer, ndx); + if ( + rc >= Number.MIN_SAFE_INTEGER && + rc <= Number.MAX_SAFE_INTEGER + ) { + return Number(rc).valueOf(); + } + return rc; + } else { + const rc = capi.sqlite3_column_double(this.pointer, ndx); + if ( + rc > Number.MAX_SAFE_INTEGER || + rc < Number.MIN_SAFE_INTEGER + ) { + toss3( + 'Integer is out of range for JS integer range: ' + rc, + ); + } + + return util.isInt32(rc) ? rc | 0 : rc; + } + } + case capi.SQLITE_FLOAT: + return capi.sqlite3_column_double(this.pointer, ndx); + case capi.SQLITE_TEXT: + return capi.sqlite3_column_text(this.pointer, ndx); + case capi.SQLITE_BLOB: { + const n = capi.sqlite3_column_bytes(this.pointer, ndx), + ptr = capi.sqlite3_column_blob(this.pointer, ndx), + rc = new Uint8Array(n); + + if (n) rc.set(wasm.heap8u().slice(ptr, ptr + n), 0); + + if (n && this.db._blobXfer instanceof Array) { + this.db._blobXfer.push(rc.buffer); + } + return rc; + } + default: + toss3( + "Don't know how to translate", + 'type of result column #' + ndx + '.', + ); + } + toss3('Not reached.'); + }, + + getInt: function (ndx) { + return this.get(ndx, capi.SQLITE_INTEGER); + }, + + getFloat: function (ndx) { + return this.get(ndx, capi.SQLITE_FLOAT); + }, + + getString: function (ndx) { + return this.get(ndx, capi.SQLITE_TEXT); + }, + + getBlob: function (ndx) { + return this.get(ndx, capi.SQLITE_BLOB); + }, + + getJSON: function (ndx) { + const s = this.get(ndx, capi.SQLITE_STRING); + return null === s ? s : JSON.parse(s); + }, + + getColumnName: function (ndx) { + return capi.sqlite3_column_name( + affirmColIndex(affirmStmtOpen(this), ndx).pointer, + ndx, + ); + }, + + getColumnNames: function (tgt = []) { + affirmColIndex(affirmStmtOpen(this), 0); + const n = this.columnCount; + for (let i = 0; i < n; ++i) { + tgt.push(capi.sqlite3_column_name(this.pointer, i)); + } + return tgt; + }, + + getParamIndex: function (name) { + return affirmStmtOpen(this).parameterCount + ? capi.sqlite3_bind_parameter_index(this.pointer, name) + : undefined; + }, + }; + + { + const prop = { + enumerable: true, + get: function () { + return __ptrMap.get(this); + }, + set: () => toss3('The pointer property is read-only.'), + }; + Object.defineProperty(Stmt.prototype, 'pointer', prop); + Object.defineProperty(DB.prototype, 'pointer', prop); + } + + Object.defineProperty(Stmt.prototype, 'columnCount', { + enumerable: false, + get: function () { + return capi.sqlite3_column_count(this.pointer); + }, + set: () => toss3('The columnCount property is read-only.'), + }); + + sqlite3.oo1 = { + DB, + Stmt, + }; + + if (util.isUIThread()) { + sqlite3.oo1.JsStorageDb = function (storageName = 'session') { + const opt = dbCtorHelper.normalizeArgs(...arguments); + storageName = opt.filename; + if ('session' !== storageName && 'local' !== storageName) { + toss3("JsStorageDb db name must be one of 'session' or 'local'."); + } + opt.vfs = 'kvvfs'; + dbCtorHelper.call(this, opt); + }; + const jdb = sqlite3.oo1.JsStorageDb; + jdb.prototype = Object.create(DB.prototype); + + jdb.clearStorage = capi.sqlite3_js_kvvfs_clear; + + jdb.prototype.clearStorage = function () { + return jdb.clearStorage(affirmDbOpen(this).filename); + }; + + jdb.storageSize = capi.sqlite3_js_kvvfs_size; + + jdb.prototype.storageSize = function () { + return jdb.storageSize(affirmDbOpen(this).filename); + }; + } + }); + + globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { + const util = sqlite3.util; + sqlite3.initWorker1API = function () { + const toss = (...args) => { + throw new Error(args.join(' ')); + }; + if (!(globalThis.WorkerGlobalScope instanceof Function)) { + toss('initWorker1API() must be run from a Worker thread.'); + } + const sqlite3 = this.sqlite3 || toss('Missing this.sqlite3 object.'); + const DB = sqlite3.oo1.DB; + + const getDbId = function (db) { + let id = wState.idMap.get(db); + if (id) return id; + id = 'db#' + ++wState.idSeq + '@' + db.pointer; + + wState.idMap.set(db, id); + return id; + }; + + const wState = { + dbList: [], + + idSeq: 0, + + idMap: new WeakMap(), + + xfer: [], + open: function (opt) { + const db = new DB(opt); + this.dbs[getDbId(db)] = db; + if (this.dbList.indexOf(db) < 0) this.dbList.push(db); + return db; + }, + close: function (db, alsoUnlink) { + if (db) { + delete this.dbs[getDbId(db)]; + const filename = db.filename; + const pVfs = util.sqlite3__wasm_db_vfs(db.pointer, 0); + db.close(); + const ddNdx = this.dbList.indexOf(db); + if (ddNdx >= 0) this.dbList.splice(ddNdx, 1); + if (alsoUnlink && filename && pVfs) { + util.sqlite3__wasm_vfs_unlink(pVfs, filename); + } + } + }, + + post: function (msg, xferList) { + if (xferList && xferList.length) { + globalThis.postMessage(msg, Array.from(xferList)); + xferList.length = 0; + } else { + globalThis.postMessage(msg); + } + }, + + dbs: Object.create(null), + + getDb: function (id, require = true) { + return ( + this.dbs[id] || + (require ? toss('Unknown (or closed) DB ID:', id) : undefined) + ); + }, + }; + + const affirmDbOpen = function (db = wState.dbList[0]) { + return db && db.pointer ? db : toss('DB is not opened.'); + }; + + const getMsgDb = function (msgData, affirmExists = true) { + const db = wState.getDb(msgData.dbId, false) || wState.dbList[0]; + return affirmExists ? affirmDbOpen(db) : db; + }; + + const getDefaultDbId = function () { + return wState.dbList[0] && getDbId(wState.dbList[0]); + }; + + const wMsgHandler = { + open: function (ev) { + const oargs = Object.create(null), + args = ev.args || Object.create(null); + if (args.simulateError) { + toss('Throwing because of simulateError flag.'); + } + const rc = Object.create(null); + oargs.vfs = args.vfs; + oargs.filename = args.filename || ''; + const db = wState.open(oargs); + rc.filename = db.filename; + rc.persistent = !!sqlite3.capi.sqlite3_js_db_uses_vfs( + db.pointer, + 'opfs', + ); + rc.dbId = getDbId(db); + rc.vfs = db.dbVfsName(); + return rc; + }, + + close: function (ev) { + const db = getMsgDb(ev, false); + const response = { + filename: db && db.filename, + }; + if (db) { + const doUnlink = + ev.args && 'object' === typeof ev.args + ? !!ev.args.unlink + : false; + wState.close(db, doUnlink); + } + return response; + }, + + exec: function (ev) { + const rc = + 'string' === typeof ev.args + ? { sql: ev.args } + : ev.args || Object.create(null); + if ('stmt' === rc.rowMode) { + toss( + "Invalid rowMode for 'exec': stmt mode", + 'does not work in the Worker API.', + ); + } else if (!rc.sql) { + toss("'exec' requires input SQL."); + } + const db = getMsgDb(ev); + if (rc.callback || Array.isArray(rc.resultRows)) { + db._blobXfer = wState.xfer; + } + const theCallback = rc.callback; + let rowNumber = 0; + const hadColNames = !!rc.columnNames; + if ('string' === typeof theCallback) { + if (!hadColNames) rc.columnNames = []; + + rc.callback = function (row, stmt) { + wState.post( + { + type: theCallback, + columnNames: rc.columnNames, + rowNumber: ++rowNumber, + row: row, + }, + wState.xfer, + ); + }; + } + try { + const changeCount = !!rc.countChanges + ? db.changes(true, 64 === rc.countChanges) + : undefined; + db.exec(rc); + if (undefined !== changeCount) { + rc.changeCount = + db.changes(true, 64 === rc.countChanges) - changeCount; + } + if (rc.callback instanceof Function) { + rc.callback = theCallback; + + wState.post({ + type: theCallback, + columnNames: rc.columnNames, + rowNumber: null, + row: undefined, + }); + } + } finally { + delete db._blobXfer; + if (rc.callback) rc.callback = theCallback; + } + return rc; + }, + + 'config-get': function () { + const rc = Object.create(null), + src = sqlite3.config; + ['bigIntEnabled'].forEach(function (k) { + if (Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k]; + }); + rc.version = sqlite3.version; + rc.vfsList = sqlite3.capi.sqlite3_js_vfs_list(); + rc.opfsEnabled = !!sqlite3.opfs; + return rc; + }, + + export: function (ev) { + const db = getMsgDb(ev); + const response = { + byteArray: sqlite3.capi.sqlite3_js_db_export(db.pointer), + filename: db.filename, + mimetype: 'application/x-sqlite3', + }; + wState.xfer.push(response.byteArray.buffer); + return response; + }, + + toss: function (ev) { + toss('Testing worker exception'); + }, + + 'opfs-tree': async function (ev) { + if (!sqlite3.opfs) toss('OPFS support is unavailable.'); + const response = await sqlite3.opfs.treeList(); + return response; + }, + }; + + globalThis.onmessage = async function (ev) { + ev = ev.data; + let result, + dbId = ev.dbId, + evType = ev.type; + const arrivalTime = performance.now(); + try { + if ( + wMsgHandler.hasOwnProperty(evType) && + wMsgHandler[evType] instanceof Function + ) { + result = await wMsgHandler[evType](ev); + } else { + toss('Unknown db worker message type:', ev.type); + } + } catch (err) { + evType = 'error'; + result = { + operation: ev.type, + message: err.message, + errorClass: err.name, + input: ev, + }; + if (err.stack) { + result.stack = + 'string' === typeof err.stack + ? err.stack.split(/\n\s*/) + : err.stack; + } + } + if (!dbId) { + dbId = result.dbId || getDefaultDbId(); + } + + wState.post( + { + type: evType, + dbId: dbId, + messageId: ev.messageId, + workerReceivedTime: arrivalTime, + workerRespondTime: performance.now(), + departureTime: ev.departureTime, + + result: result, + }, + wState.xfer, + ); + }; + globalThis.postMessage({ + type: 'sqlite3-api', + result: 'worker1-ready', + }); + }.bind({ sqlite3 }); + }); + globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { + const wasm = sqlite3.wasm, + capi = sqlite3.capi, + toss = sqlite3.util.toss3; + const vfs = Object.create(null); + sqlite3.vfs = vfs; + + capi.sqlite3_vfs.prototype.registerVfs = function (asDefault = false) { + if (!(this instanceof sqlite3.capi.sqlite3_vfs)) { + toss('Expecting a sqlite3_vfs-type argument.'); + } + const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0); + if (rc) { + toss('sqlite3_vfs_register(', this, ') failed with rc', rc); + } + if (this.pointer !== capi.sqlite3_vfs_find(this.$zName)) { + toss( + 'BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS', + this, + ); + } + return this; + }; + + vfs.installVfs = function (opt) { + let count = 0; + const propList = ['io', 'vfs']; + for (const key of propList) { + const o = opt[key]; + if (o) { + ++count; + o.struct.installMethods(o.methods, !!o.applyArgcCheck); + if ('vfs' === key) { + if (!o.struct.$zName && 'string' === typeof o.name) { + o.struct.addOnDispose( + (o.struct.$zName = wasm.allocCString(o.name)), + ); + } + o.struct.registerVfs(!!o.asDefault); + } + } + } + if (!count) + toss( + 'Misuse: installVfs() options object requires at least', + 'one of:', + propList, + ); + return this; + }; + }); + globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { + const wasm = sqlite3.wasm, + capi = sqlite3.capi, + toss = sqlite3.util.toss3; + const vtab = Object.create(null); + sqlite3.vtab = vtab; + + const sii = capi.sqlite3_index_info; + + sii.prototype.nthConstraint = function (n, asPtr = false) { + if (n < 0 || n >= this.$nConstraint) return false; + const ptr = + this.$aConstraint + + sii.sqlite3_index_constraint.structInfo.sizeof * n; + return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr); + }; + + sii.prototype.nthConstraintUsage = function (n, asPtr = false) { + if (n < 0 || n >= this.$nConstraint) return false; + const ptr = + this.$aConstraintUsage + + sii.sqlite3_index_constraint_usage.structInfo.sizeof * n; + return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr); + }; + + sii.prototype.nthOrderBy = function (n, asPtr = false) { + if (n < 0 || n >= this.$nOrderBy) return false; + const ptr = + this.$aOrderBy + sii.sqlite3_index_orderby.structInfo.sizeof * n; + return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr); + }; + + const __xWrapFactory = function (methodName, StructType) { + return function (ptr, removeMapping = false) { + if (0 === arguments.length) ptr = new StructType(); + if (ptr instanceof StructType) { + this.set(ptr.pointer, ptr); + return ptr; + } else if (!wasm.isPtr(ptr)) { + sqlite3.SQLite3Error.toss( + 'Invalid argument to', + methodName + '()', + ); + } + let rc = this.get(ptr); + if (removeMapping) this.delete(ptr); + return rc; + }.bind(new Map()); + }; + + const StructPtrMapper = function (name, StructType) { + const __xWrap = __xWrapFactory(name, StructType); + + return Object.assign(Object.create(null), { + StructType, + + create: (ppOut) => { + const rc = __xWrap(); + wasm.pokePtr(ppOut, rc.pointer); + return rc; + }, + + get: (pCObj) => __xWrap(pCObj), + + unget: (pCObj) => __xWrap(pCObj, true), + + dispose: (pCObj) => { + const o = __xWrap(pCObj, true); + if (o) o.dispose(); + }, + }); + }; + + vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab); + + vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor); + + vtab.xIndexInfo = (pIdxInfo) => new capi.sqlite3_index_info(pIdxInfo); + + vtab.xError = function f(methodName, err, defaultRc) { + if (f.errorReporter instanceof Function) { + try { + f.errorReporter( + 'sqlite3_module::' + methodName + '(): ' + err.message, + ); + } catch (e) {} + } + let rc; + if (err instanceof sqlite3.WasmAllocError) rc = capi.SQLITE_NOMEM; + else if (arguments.length > 2) rc = defaultRc; + else if (err instanceof sqlite3.SQLite3Error) rc = err.resultCode; + return rc || capi.SQLITE_ERROR; + }; + vtab.xError.errorReporter = console.error.bind(console) ; + + vtab.xRowid = (ppRowid64, value) => wasm.poke(ppRowid64, value, 'i64'); + + vtab.setupModule = function (opt) { + let createdMod = false; + const mod = + this instanceof capi.sqlite3_module + ? this + : opt.struct || (createdMod = new capi.sqlite3_module()); + try { + const methods = opt.methods || toss("Missing 'methods' object."); + for (const e of Object.entries({ + xConnect: 'xCreate', + xDisconnect: 'xDestroy', + })) { + const k = e[0], + v = e[1]; + if (true === methods[k]) methods[k] = methods[v]; + else if (true === methods[v]) methods[v] = methods[k]; + } + if (opt.catchExceptions) { + const fwrap = function (methodName, func) { + if (['xConnect', 'xCreate'].indexOf(methodName) >= 0) { + return function (pDb, pAux, argc, argv, ppVtab, pzErr) { + try { + return func(...arguments) || 0; + } catch (e) { + if (!(e instanceof sqlite3.WasmAllocError)) { + wasm.dealloc(wasm.peekPtr(pzErr)); + wasm.pokePtr(pzErr, wasm.allocCString(e.message)); + } + return vtab.xError(methodName, e); + } + }; + } else { + return function (...args) { + try { + return func(...args) || 0; + } catch (e) { + return vtab.xError(methodName, e); + } + }; + } + }; + const mnames = [ + 'xCreate', + 'xConnect', + 'xBestIndex', + 'xDisconnect', + 'xDestroy', + 'xOpen', + 'xClose', + 'xFilter', + 'xNext', + 'xEof', + 'xColumn', + 'xRowid', + 'xUpdate', + 'xBegin', + 'xSync', + 'xCommit', + 'xRollback', + 'xFindFunction', + 'xRename', + 'xSavepoint', + 'xRelease', + 'xRollbackTo', + 'xShadowName', + ]; + const remethods = Object.create(null); + for (const k of mnames) { + const m = methods[k]; + if (!(m instanceof Function)) continue; + else if ('xConnect' === k && methods.xCreate === m) { + remethods[k] = methods.xCreate; + } else if ('xCreate' === k && methods.xConnect === m) { + remethods[k] = methods.xConnect; + } else { + remethods[k] = fwrap(k, m); + } + } + mod.installMethods(remethods, false); + } else { + mod.installMethods(methods, !!opt.applyArgcCheck); + } + if (0 === mod.$iVersion) { + let v; + if ('number' === typeof opt.iVersion) v = opt.iVersion; + else if (mod.$xShadowName) v = 3; + else if (mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) + v = 2; + else v = 1; + mod.$iVersion = v; + } + } catch (e) { + if (createdMod) createdMod.dispose(); + throw e; + } + return mod; + }; + + capi.sqlite3_module.prototype.setupModule = function (opt) { + return vtab.setupModule.call(this, opt); + }; + }); + globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { + const installOpfsVfs = function callee(options) { + if (!globalThis.SharedArrayBuffer || !globalThis.Atomics) { + return Promise.reject( + new Error( + 'Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. ' + + 'The server must emit the COOP/COEP response headers to enable those. ' + + 'See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep', + ), + ); + } else if ('undefined' === typeof WorkerGlobalScope) { + return Promise.reject( + new Error( + 'The OPFS sqlite3_vfs cannot run in the main thread ' + + 'because it requires Atomics.wait().', + ), + ); + } else if ( + !globalThis.FileSystemHandle || + !globalThis.FileSystemDirectoryHandle || + !globalThis.FileSystemFileHandle || + !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || + !navigator?.storage?.getDirectory + ) { + return Promise.reject(new Error('Missing required OPFS APIs.')); + } + if (!options || 'object' !== typeof options) { + options = Object.create(null); + } + const urlParams = new URL(globalThis.location.href).searchParams; + if (urlParams.has('opfs-disable')) { + return Promise.resolve(sqlite3); + } + if (undefined === options.verbose) { + options.verbose = urlParams.has('opfs-verbose') + ? +urlParams.get('opfs-verbose') || 2 + : 1; + } + if (undefined === options.sanityChecks) { + options.sanityChecks = urlParams.has('opfs-sanity-check'); + } + if (undefined === options.proxyUri) { + options.proxyUri = callee.defaultProxyUri; + } + + if ('function' === typeof options.proxyUri) { + options.proxyUri = options.proxyUri(); + } + const thePromise = new Promise(function ( + promiseResolve_, + promiseReject_, + ) { + const loggers = [ + sqlite3.config.error, + sqlite3.config.warn, + sqlite3.config.log, + ]; + const logImpl = (level, ...args) => { + if (options.verbose > level) + loggers[level]('OPFS syncer:', ...args); + }; + const log = (...args) => logImpl(2, ...args); + const warn = (...args) => logImpl(1, ...args); + const error = (...args) => logImpl(0, ...args); + const toss = sqlite3.util.toss; + const capi = sqlite3.capi; + const util = sqlite3.util; + const wasm = sqlite3.wasm; + const sqlite3_vfs = capi.sqlite3_vfs; + const sqlite3_file = capi.sqlite3_file; + const sqlite3_io_methods = capi.sqlite3_io_methods; + + const opfsUtil = Object.create(null); + + const thisThreadHasOPFS = () => { + return ( + globalThis.FileSystemHandle && + globalThis.FileSystemDirectoryHandle && + globalThis.FileSystemFileHandle && + globalThis.FileSystemFileHandle.prototype + .createSyncAccessHandle && + navigator?.storage?.getDirectory + ); + }; + + opfsUtil.metrics = { + dump: function () { + let k, + n = 0, + t = 0, + w = 0; + for (k in state.opIds) { + const m = metrics[k]; + n += m.count; + t += m.time; + w += m.wait; + m.avgTime = m.count && m.time ? m.time / m.count : 0; + m.avgWait = m.count && m.wait ? m.wait / m.count : 0; + } + sqlite3.config.log( + globalThis.location.href, + 'metrics for', + globalThis.location.href, + ':', + metrics, + '\nTotal of', + n, + 'op(s) for', + t, + 'ms (incl. ' + w + ' ms of waiting on the async side)', + ); + sqlite3.config.log('Serialization metrics:', metrics.s11n); + W.postMessage({ type: 'opfs-async-metrics' }); + }, + reset: function () { + let k; + const r = (m) => (m.count = m.time = m.wait = 0); + for (k in state.opIds) { + r((metrics[k] = Object.create(null))); + } + let s = (metrics.s11n = Object.create(null)); + s = s.serialize = Object.create(null); + s.count = s.time = 0; + s = metrics.s11n.deserialize = Object.create(null); + s.count = s.time = 0; + }, + }; + const opfsIoMethods = new sqlite3_io_methods(); + const opfsVfs = new sqlite3_vfs().addOnDispose(() => + opfsIoMethods.dispose(), + ); + let promiseWasRejected = undefined; + const promiseReject = (err) => { + promiseWasRejected = true; + opfsVfs.dispose(); + return promiseReject_(err); + }; + const promiseResolve = () => { + promiseWasRejected = false; + return promiseResolve_(sqlite3); + }; + const W = new Worker( + new URL('sqlite3-opfs-async-proxy.js', import.meta.url), + ); + setTimeout(() => { + if (undefined === promiseWasRejected) { + promiseReject( + new Error( + 'Timeout while waiting for OPFS async proxy worker.', + ), + ); + } + }, 4000); + W._originalOnError = W.onerror; + W.onerror = function (err) { + error('Error initializing OPFS asyncer:', err); + promiseReject( + new Error( + 'Loading OPFS async Worker failed for unknown reasons.', + ), + ); + }; + const pDVfs = capi.sqlite3_vfs_find(null); + const dVfs = pDVfs ? new sqlite3_vfs(pDVfs) : null; + opfsIoMethods.$iVersion = 1; + opfsVfs.$iVersion = 2; + opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; + opfsVfs.$mxPathname = 1024; + opfsVfs.$zName = wasm.allocCString('opfs'); + + opfsVfs.$xDlOpen = + opfsVfs.$xDlError = + opfsVfs.$xDlSym = + opfsVfs.$xDlClose = + null; + opfsVfs.addOnDispose( + '$zName', + opfsVfs.$zName, + 'cleanup default VFS wrapper', + () => (dVfs ? dVfs.dispose() : null), + ); + + const state = Object.create(null); + state.verbose = options.verbose; + state.littleEndian = (() => { + const buffer = new ArrayBuffer(2); + new DataView(buffer).setInt16(0, 256, true); + + return new Int16Array(buffer)[0] === 256; + })(); + + state.asyncIdleWaitTime = 150; + + state.asyncS11nExceptions = 1; + + state.fileBufferSize = 1024 * 64; + state.sabS11nOffset = state.fileBufferSize; + + state.sabS11nSize = opfsVfs.$mxPathname * 2; + + state.sabIO = new SharedArrayBuffer( + state.fileBufferSize + state.sabS11nSize, + ); + state.opIds = Object.create(null); + const metrics = Object.create(null); + { + let i = 0; + + state.opIds.whichOp = i++; + + state.opIds.rc = i++; + + state.opIds.xAccess = i++; + state.opIds.xClose = i++; + state.opIds.xDelete = i++; + state.opIds.xDeleteNoWait = i++; + state.opIds.xFileSize = i++; + state.opIds.xLock = i++; + state.opIds.xOpen = i++; + state.opIds.xRead = i++; + state.opIds.xSleep = i++; + state.opIds.xSync = i++; + state.opIds.xTruncate = i++; + state.opIds.xUnlock = i++; + state.opIds.xWrite = i++; + state.opIds.mkdir = i++; + state.opIds['opfs-async-metrics'] = i++; + state.opIds['opfs-async-shutdown'] = i++; + + state.opIds.retry = i++; + state.sabOP = new SharedArrayBuffer(i * 4); + opfsUtil.metrics.reset(); + } + + state.sq3Codes = Object.create(null); + [ + 'SQLITE_ACCESS_EXISTS', + 'SQLITE_ACCESS_READWRITE', + 'SQLITE_BUSY', + 'SQLITE_CANTOPEN', + 'SQLITE_ERROR', + 'SQLITE_IOERR', + 'SQLITE_IOERR_ACCESS', + 'SQLITE_IOERR_CLOSE', + 'SQLITE_IOERR_DELETE', + 'SQLITE_IOERR_FSYNC', + 'SQLITE_IOERR_LOCK', + 'SQLITE_IOERR_READ', + 'SQLITE_IOERR_SHORT_READ', + 'SQLITE_IOERR_TRUNCATE', + 'SQLITE_IOERR_UNLOCK', + 'SQLITE_IOERR_WRITE', + 'SQLITE_LOCK_EXCLUSIVE', + 'SQLITE_LOCK_NONE', + 'SQLITE_LOCK_PENDING', + 'SQLITE_LOCK_RESERVED', + 'SQLITE_LOCK_SHARED', + 'SQLITE_LOCKED', + 'SQLITE_MISUSE', + 'SQLITE_NOTFOUND', + 'SQLITE_OPEN_CREATE', + 'SQLITE_OPEN_DELETEONCLOSE', + 'SQLITE_OPEN_MAIN_DB', + 'SQLITE_OPEN_READONLY', + ].forEach((k) => { + if (undefined === (state.sq3Codes[k] = capi[k])) { + toss('Maintenance required: not found:', k); + } + }); + state.opfsFlags = Object.assign(Object.create(null), { + OPFS_UNLOCK_ASAP: 0x01, + + OPFS_UNLINK_BEFORE_OPEN: 0x02, + + defaultUnlockAsap: false, + }); + + const opRun = (op, ...args) => { + const opNdx = state.opIds[op] || toss('Invalid op ID:', op); + state.s11n.serialize(...args); + Atomics.store(state.sabOPView, state.opIds.rc, -1); + Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); + Atomics.notify(state.sabOPView, state.opIds.whichOp); + const t = performance.now(); + while ( + 'not-equal' !== + Atomics.wait(state.sabOPView, state.opIds.rc, -1) + ) {} + + const rc = Atomics.load(state.sabOPView, state.opIds.rc); + metrics[op].wait += performance.now() - t; + if (rc && state.asyncS11nExceptions) { + const err = state.s11n.deserialize(); + if (err) error(op + '() async error:', ...err); + } + return rc; + }; + + opfsUtil.debug = { + asyncShutdown: () => { + warn( + 'Shutting down OPFS async listener. The OPFS VFS will no longer work.', + ); + opRun('opfs-async-shutdown'); + }, + asyncRestart: () => { + warn( + 'Attempting to restart OPFS VFS async listener. Might work, might not.', + ); + W.postMessage({ type: 'opfs-async-restart' }); + }, + }; + + const initS11n = () => { + if (state.s11n) return state.s11n; + const textDecoder = new TextDecoder(), + textEncoder = new TextEncoder('utf-8'), + viewU8 = new Uint8Array( + state.sabIO, + state.sabS11nOffset, + state.sabS11nSize, + ), + viewDV = new DataView( + state.sabIO, + state.sabS11nOffset, + state.sabS11nSize, + ); + state.s11n = Object.create(null); + + const TypeIds = Object.create(null); + TypeIds.number = { + id: 1, + size: 8, + getter: 'getFloat64', + setter: 'setFloat64', + }; + TypeIds.bigint = { + id: 2, + size: 8, + getter: 'getBigInt64', + setter: 'setBigInt64', + }; + TypeIds.boolean = { + id: 3, + size: 4, + getter: 'getInt32', + setter: 'setInt32', + }; + TypeIds.string = { id: 4 }; + + const getTypeId = (v) => + TypeIds[typeof v] || + toss( + 'Maintenance required: this value type cannot be serialized.', + v, + ); + const getTypeIdById = (tid) => { + switch (tid) { + case TypeIds.number.id: + return TypeIds.number; + case TypeIds.bigint.id: + return TypeIds.bigint; + case TypeIds.boolean.id: + return TypeIds.boolean; + case TypeIds.string.id: + return TypeIds.string; + default: + toss('Invalid type ID:', tid); + } + }; + + state.s11n.deserialize = function (clear = false) { + ++metrics.s11n.deserialize.count; + const t = performance.now(); + const argc = viewU8[0]; + const rc = argc ? [] : null; + if (argc) { + const typeIds = []; + let offset = 1, + i, + n, + v; + for (i = 0; i < argc; ++i, ++offset) { + typeIds.push(getTypeIdById(viewU8[offset])); + } + for (i = 0; i < argc; ++i) { + const t = typeIds[i]; + if (t.getter) { + v = viewDV[t.getter](offset, state.littleEndian); + offset += t.size; + } else { + n = viewDV.getInt32(offset, state.littleEndian); + offset += 4; + v = textDecoder.decode(viewU8.slice(offset, offset + n)); + offset += n; + } + rc.push(v); + } + } + if (clear) viewU8[0] = 0; + + metrics.s11n.deserialize.time += performance.now() - t; + return rc; + }; + + state.s11n.serialize = function (...args) { + const t = performance.now(); + ++metrics.s11n.serialize.count; + if (args.length) { + const typeIds = []; + let i = 0, + offset = 1; + viewU8[0] = args.length & 0xff; + for (; i < args.length; ++i, ++offset) { + typeIds.push(getTypeId(args[i])); + viewU8[offset] = typeIds[i].id; + } + for (i = 0; i < args.length; ++i) { + const t = typeIds[i]; + if (t.setter) { + viewDV[t.setter](offset, args[i], state.littleEndian); + offset += t.size; + } else { + const s = textEncoder.encode(args[i]); + viewDV.setInt32(offset, s.byteLength, state.littleEndian); + offset += 4; + viewU8.set(s, offset); + offset += s.byteLength; + } + } + } else { + viewU8[0] = 0; + } + metrics.s11n.serialize.time += performance.now() - t; + }; + return state.s11n; + }; + + const randomFilename = function f(len = 16) { + if (!f._chars) { + f._chars = + 'abcdefghijklmnopqrstuvwxyz' + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + + '012346789'; + f._n = f._chars.length; + } + const a = []; + let i = 0; + for (; i < len; ++i) { + const ndx = (Math.random() * (f._n * 64)) % f._n | 0; + a[i] = f._chars[ndx]; + } + return a.join(''); + }; + + const __openFiles = Object.create(null); + + const opTimer = Object.create(null); + opTimer.op = undefined; + opTimer.start = undefined; + const mTimeStart = (op) => { + opTimer.start = performance.now(); + opTimer.op = op; + ++metrics[op].count; + }; + const mTimeEnd = () => + (metrics[opTimer.op].time += performance.now() - opTimer.start); + + const ioSyncWrappers = { + xCheckReservedLock: function (pFile, pOut) { + { + wasm.poke(pOut, 0, 'i32'); + } + return 0; + }, + xClose: function (pFile) { + mTimeStart('xClose'); + let rc = 0; + const f = __openFiles[pFile]; + if (f) { + delete __openFiles[pFile]; + rc = opRun('xClose', pFile); + if (f.sq3File) f.sq3File.dispose(); + } + mTimeEnd(); + return rc; + }, + xDeviceCharacteristics: function (pFile) { + return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; + }, + xFileControl: function (pFile, opId, pArg) { + return capi.SQLITE_NOTFOUND; + }, + xFileSize: function (pFile, pSz64) { + mTimeStart('xFileSize'); + let rc = opRun('xFileSize', pFile); + if (0 == rc) { + try { + const sz = state.s11n.deserialize()[0]; + wasm.poke(pSz64, sz, 'i64'); + } catch (e) { + error('Unexpected error reading xFileSize() result:', e); + rc = state.sq3Codes.SQLITE_IOERR; + } + } + mTimeEnd(); + return rc; + }, + xLock: function (pFile, lockType) { + mTimeStart('xLock'); + const f = __openFiles[pFile]; + let rc = 0; + + if (!f.lockType) { + rc = opRun('xLock', pFile, lockType); + if (0 === rc) f.lockType = lockType; + } else { + f.lockType = lockType; + } + mTimeEnd(); + return rc; + }, + xRead: function (pFile, pDest, n, offset64) { + mTimeStart('xRead'); + const f = __openFiles[pFile]; + let rc; + try { + rc = opRun('xRead', pFile, n, Number(offset64)); + if (0 === rc || capi.SQLITE_IOERR_SHORT_READ === rc) { + wasm.heap8u().set(f.sabView.subarray(0, n), pDest); + } + } catch (e) { + error('xRead(', arguments, ') failed:', e, f); + rc = capi.SQLITE_IOERR_READ; + } + mTimeEnd(); + return rc; + }, + xSync: function (pFile, flags) { + mTimeStart('xSync'); + ++metrics.xSync.count; + const rc = opRun('xSync', pFile, flags); + mTimeEnd(); + return rc; + }, + xTruncate: function (pFile, sz64) { + mTimeStart('xTruncate'); + const rc = opRun('xTruncate', pFile, Number(sz64)); + mTimeEnd(); + return rc; + }, + xUnlock: function (pFile, lockType) { + mTimeStart('xUnlock'); + const f = __openFiles[pFile]; + let rc = 0; + if (capi.SQLITE_LOCK_NONE === lockType && f.lockType) { + rc = opRun('xUnlock', pFile, lockType); + } + if (0 === rc) f.lockType = lockType; + mTimeEnd(); + return rc; + }, + xWrite: function (pFile, pSrc, n, offset64) { + mTimeStart('xWrite'); + const f = __openFiles[pFile]; + let rc; + try { + f.sabView.set(wasm.heap8u().subarray(pSrc, pSrc + n)); + rc = opRun('xWrite', pFile, n, Number(offset64)); + } catch (e) { + error('xWrite(', arguments, ') failed:', e, f); + rc = capi.SQLITE_IOERR_WRITE; + } + mTimeEnd(); + return rc; + }, + }; + + const vfsSyncWrappers = { + xAccess: function (pVfs, zName, flags, pOut) { + mTimeStart('xAccess'); + const rc = opRun('xAccess', wasm.cstrToJs(zName)); + wasm.poke(pOut, rc ? 0 : 1, 'i32'); + mTimeEnd(); + return 0; + }, + xCurrentTime: function (pVfs, pOut) { + wasm.poke( + pOut, + 2440587.5 + new Date().getTime() / 86400000, + 'double', + ); + return 0; + }, + xCurrentTimeInt64: function (pVfs, pOut) { + wasm.poke( + pOut, + 2440587.5 * 86400000 + new Date().getTime(), + 'i64', + ); + return 0; + }, + xDelete: function (pVfs, zName, doSyncDir) { + mTimeStart('xDelete'); + const rc = opRun( + 'xDelete', + wasm.cstrToJs(zName), + doSyncDir, + false, + ); + mTimeEnd(); + return rc; + }, + xFullPathname: function (pVfs, zName, nOut, pOut) { + const i = wasm.cstrncpy(pOut, zName, nOut); + return i < nOut ? 0 : capi.SQLITE_CANTOPEN; + }, + xGetLastError: function (pVfs, nOut, pOut) { + warn('OPFS xGetLastError() has nothing sensible to return.'); + return 0; + }, + + xOpen: function f(pVfs, zName, pFile, flags, pOutFlags) { + mTimeStart('xOpen'); + let opfsFlags = 0; + if (0 === zName) { + zName = randomFilename(); + } else if (wasm.isPtr(zName)) { + if (capi.sqlite3_uri_boolean(zName, 'opfs-unlock-asap', 0)) { + opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP; + } + if ( + capi.sqlite3_uri_boolean(zName, 'delete-before-open', 0) + ) { + opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN; + } + zName = wasm.cstrToJs(zName); + } + const fh = Object.create(null); + fh.fid = pFile; + fh.filename = zName; + fh.sab = new SharedArrayBuffer(state.fileBufferSize); + fh.flags = flags; + const rc = opRun('xOpen', pFile, zName, flags, opfsFlags); + if (!rc) { + if (fh.readOnly) { + wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, 'i32'); + } + __openFiles[pFile] = fh; + fh.sabView = state.sabFileBufView; + fh.sq3File = new sqlite3_file(pFile); + fh.sq3File.$pMethods = opfsIoMethods.pointer; + fh.lockType = capi.SQLITE_LOCK_NONE; + } + mTimeEnd(); + return rc; + }, + }; + + if (dVfs) { + opfsVfs.$xRandomness = dVfs.$xRandomness; + opfsVfs.$xSleep = dVfs.$xSleep; + } + if (!opfsVfs.$xRandomness) { + vfsSyncWrappers.xRandomness = function (pVfs, nOut, pOut) { + const heap = wasm.heap8u(); + let i = 0; + for (; i < nOut; ++i) + heap[pOut + i] = (Math.random() * 255000) & 0xff; + return i; + }; + } + if (!opfsVfs.$xSleep) { + vfsSyncWrappers.xSleep = function (pVfs, ms) { + Atomics.wait(state.sabOPView, state.opIds.xSleep, 0, ms); + return 0; + }; + } + + opfsUtil.getResolvedPath = function (filename, splitIt) { + const p = new URL(filename, 'file://irrelevant').pathname; + return splitIt ? p.split('/').filter((v) => !!v) : p; + }; + + opfsUtil.getDirForFilename = async function f( + absFilename, + createDirs = false, + ) { + const path = opfsUtil.getResolvedPath(absFilename, true); + const filename = path.pop(); + let dh = opfsUtil.rootDirectory; + for (const dirName of path) { + if (dirName) { + dh = await dh.getDirectoryHandle(dirName, { + create: !!createDirs, + }); + } + } + return [dh, filename]; + }; + + opfsUtil.mkdir = async function (absDirName) { + try { + await opfsUtil.getDirForFilename( + absDirName + '/filepart', + true, + ); + return true; + } catch (e) { + return false; + } + }; + + opfsUtil.entryExists = async function (fsEntryName) { + try { + const [dh, fn] = await opfsUtil.getDirForFilename(fsEntryName); + await dh.getFileHandle(fn); + return true; + } catch (e) { + return false; + } + }; + + opfsUtil.randomFilename = randomFilename; + + opfsUtil.treeList = async function () { + const doDir = async function callee(dirHandle, tgt) { + tgt.name = dirHandle.name; + tgt.dirs = []; + tgt.files = []; + for await (const handle of dirHandle.values()) { + if ('directory' === handle.kind) { + const subDir = Object.create(null); + tgt.dirs.push(subDir); + await callee(handle, subDir); + } else { + tgt.files.push(handle.name); + } + } + }; + const root = Object.create(null); + await doDir(opfsUtil.rootDirectory, root); + return root; + }; + + opfsUtil.rmfr = async function () { + const dir = opfsUtil.rootDirectory, + opt = { recurse: true }; + for await (const handle of dir.values()) { + dir.removeEntry(handle.name, opt); + } + }; + + opfsUtil.unlink = async function ( + fsEntryName, + recursive = false, + throwOnError = false, + ) { + try { + const [hDir, filenamePart] = await opfsUtil.getDirForFilename( + fsEntryName, + false, + ); + await hDir.removeEntry(filenamePart, { recursive }); + return true; + } catch (e) { + if (throwOnError) { + throw new Error( + 'unlink(', + arguments[0], + ') failed: ' + e.message, + { + cause: e, + }, + ); + } + return false; + } + }; + + opfsUtil.traverse = async function (opt) { + const defaultOpt = { + recursive: true, + directory: opfsUtil.rootDirectory, + }; + if ('function' === typeof opt) { + opt = { callback: opt }; + } + opt = Object.assign(defaultOpt, opt || {}); + const doDir = async function callee(dirHandle, depth) { + for await (const handle of dirHandle.values()) { + if (false === opt.callback(handle, dirHandle, depth)) + return false; + else if (opt.recursive && 'directory' === handle.kind) { + if (false === (await callee(handle, depth + 1))) break; + } + } + }; + doDir(opt.directory, 0); + }; + + const importDbChunked = async function (filename, callback) { + const [hDir, fnamePart] = await opfsUtil.getDirForFilename( + filename, + true, + ); + const hFile = await hDir.getFileHandle(fnamePart, { + create: true, + }); + let sah = await hFile.createSyncAccessHandle(); + let nWrote = 0, + chunk, + checkedHeader = false; + try { + sah.truncate(0); + while (undefined !== (chunk = await callback())) { + if (chunk instanceof ArrayBuffer) + chunk = new Uint8Array(chunk); + if (0 === nWrote && chunk.byteLength >= 15) { + util.affirmDbHeader(chunk); + checkedHeader = true; + } + sah.write(chunk, { at: nWrote }); + nWrote += chunk.byteLength; + } + if (nWrote < 512 || 0 !== nWrote % 512) { + toss( + 'Input size', + nWrote, + 'is not correct for an SQLite database.', + ); + } + if (!checkedHeader) { + const header = new Uint8Array(20); + sah.read(header, { at: 0 }); + util.affirmDbHeader(header); + } + sah.write(new Uint8Array([1, 1]), { at: 18 }); + return nWrote; + } catch (e) { + await sah.close(); + sah = undefined; + await hDir.removeEntry(fnamePart).catch(() => {}); + throw e; + } finally { + if (sah) await sah.close(); + } + }; + + opfsUtil.importDb = async function (filename, bytes) { + if (bytes instanceof Function) { + return importDbChunked(filename, bytes); + } + if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); + util.affirmIsDb(bytes); + const n = bytes.byteLength; + const [hDir, fnamePart] = await opfsUtil.getDirForFilename( + filename, + true, + ); + let sah, + nWrote = 0; + try { + const hFile = await hDir.getFileHandle(fnamePart, { + create: true, + }); + sah = await hFile.createSyncAccessHandle(); + sah.truncate(0); + nWrote = sah.write(bytes, { at: 0 }); + if (nWrote != n) { + toss( + 'Expected to write ' + + n + + ' bytes but wrote ' + + nWrote + + '.', + ); + } + sah.write(new Uint8Array([1, 1]), { at: 18 }); + return nWrote; + } catch (e) { + if (sah) { + await sah.close(); + sah = undefined; + } + await hDir.removeEntry(fnamePart).catch(() => {}); + throw e; + } finally { + if (sah) await sah.close(); + } + }; + + if (sqlite3.oo1) { + const OpfsDb = function (...args) { + const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); + opt.vfs = opfsVfs.$zName; + sqlite3.oo1.DB.dbCtorHelper.call(this, opt); + }; + OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); + sqlite3.oo1.OpfsDb = OpfsDb; + OpfsDb.importDb = opfsUtil.importDb; + sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenSql( + opfsVfs.pointer, + function (oo1Db, sqlite3) { + sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); + sqlite3.capi.sqlite3_exec( + oo1Db, + [ + 'pragma journal_mode=DELETE;', + + 'pragma cache_size=-16384;', + ], + 0, + 0, + 0, + ); + }, + ); + } + + const sanityCheck = function () { + const scope = wasm.scopedAllocPush(); + const sq3File = new sqlite3_file(); + try { + const fid = sq3File.pointer; + const openFlags = + capi.SQLITE_OPEN_CREATE | + capi.SQLITE_OPEN_READWRITE | + capi.SQLITE_OPEN_MAIN_DB; + const pOut = wasm.scopedAlloc(8); + const dbFile = '/sanity/check/file' + randomFilename(8); + const zDbFile = wasm.scopedAllocCString(dbFile); + let rc; + state.s11n.serialize('This is ä string.'); + rc = state.s11n.deserialize(); + log('deserialize() says:', rc); + if ('This is ä string.' !== rc[0]) toss('String d13n error.'); + vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut, 'i32'); + log('xAccess(', dbFile, ') exists ?=', rc); + rc = vfsSyncWrappers.xOpen( + opfsVfs.pointer, + zDbFile, + fid, + openFlags, + pOut, + ); + log( + 'open rc =', + rc, + 'state.sabOPView[xOpen] =', + state.sabOPView[state.opIds.xOpen], + ); + if (0 !== rc) { + error('open failed with code', rc); + return; + } + vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut, 'i32'); + if (!rc) toss('xAccess() failed to detect file.'); + rc = ioSyncWrappers.xSync(sq3File.pointer, 0); + if (rc) toss('sync failed w/ rc', rc); + rc = ioSyncWrappers.xTruncate(sq3File.pointer, 1024); + if (rc) toss('truncate failed w/ rc', rc); + wasm.poke(pOut, 0, 'i64'); + rc = ioSyncWrappers.xFileSize(sq3File.pointer, pOut); + if (rc) toss('xFileSize failed w/ rc', rc); + log('xFileSize says:', wasm.peek(pOut, 'i64')); + rc = ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1); + if (rc) toss('xWrite() failed!'); + const readBuf = wasm.scopedAlloc(16); + rc = ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); + wasm.poke(readBuf + 6, 0); + let jRead = wasm.cstrToJs(readBuf); + log('xRead() got:', jRead); + if ('sanity' !== jRead) toss('Unexpected xRead() value.'); + if (vfsSyncWrappers.xSleep) { + log('xSleep()ing before close()ing...'); + vfsSyncWrappers.xSleep(opfsVfs.pointer, 2000); + log('waking up from xSleep()'); + } + rc = ioSyncWrappers.xClose(fid); + log('xClose rc =', rc, 'sabOPView =', state.sabOPView); + log('Deleting file:', dbFile); + vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234); + vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut, 'i32'); + if (rc) + toss( + 'Expecting 0 from xAccess(', + dbFile, + ') after xDelete().', + ); + warn('End of OPFS sanity checks.'); + } finally { + sq3File.dispose(); + wasm.scopedAllocPop(scope); + } + }; + + W.onmessage = function ({ data }) { + switch (data.type) { + case 'opfs-unavailable': + promiseReject(new Error(data.payload.join(' '))); + break; + case 'opfs-async-loaded': + W.postMessage({ type: 'opfs-async-init', args: state }); + break; + case 'opfs-async-inited': { + if (true === promiseWasRejected) { + break; + } + try { + sqlite3.vfs.installVfs({ + io: { struct: opfsIoMethods, methods: ioSyncWrappers }, + vfs: { struct: opfsVfs, methods: vfsSyncWrappers }, + }); + state.sabOPView = new Int32Array(state.sabOP); + state.sabFileBufView = new Uint8Array( + state.sabIO, + 0, + state.fileBufferSize, + ); + state.sabS11nView = new Uint8Array( + state.sabIO, + state.sabS11nOffset, + state.sabS11nSize, + ); + initS11n(); + if (options.sanityChecks) { + warn( + 'Running sanity checks because of opfs-sanity-check URL arg...', + ); + sanityCheck(); + } + if (thisThreadHasOPFS()) { + navigator.storage + .getDirectory() + .then((d) => { + W.onerror = W._originalOnError; + delete W._originalOnError; + sqlite3.opfs = opfsUtil; + opfsUtil.rootDirectory = d; + log('End of OPFS sqlite3_vfs setup.', opfsVfs); + promiseResolve(); + }) + .catch(promiseReject); + } else { + promiseResolve(); + } + } catch (e) { + error(e); + promiseReject(e); + } + break; + } + default: { + const errMsg = + 'Unexpected message from the OPFS async worker: ' + + JSON.stringify(data); + error(errMsg); + promiseReject(new Error(errMsg)); + break; + } + } + }; + }); + return thePromise; + }; + installOpfsVfs.defaultProxyUri = 'sqlite3-opfs-async-proxy.js'; + globalThis.sqlite3ApiBootstrap.initializersAsync.push( + async (sqlite3) => { + try { + let proxyJs = installOpfsVfs.defaultProxyUri; + if (sqlite3.scriptInfo.sqlite3Dir) { + installOpfsVfs.defaultProxyUri = + sqlite3.scriptInfo.sqlite3Dir + proxyJs; + } + return installOpfsVfs().catch((e) => { + sqlite3.config.warn( + 'Ignoring inability to install OPFS sqlite3_vfs:', + e.message, + ); + }); + } catch (e) { + sqlite3.config.error('installOpfsVfs() exception:', e); + return Promise.reject(e); + } + }, + ); + }); + + globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { + const toss = sqlite3.util.toss; + const toss3 = sqlite3.util.toss3; + const initPromises = Object.create(null); + const capi = sqlite3.capi; + const util = sqlite3.util; + const wasm = sqlite3.wasm; + + const SECTOR_SIZE = 4096; + const HEADER_MAX_PATH_SIZE = 512; + const HEADER_FLAGS_SIZE = 4; + const HEADER_DIGEST_SIZE = 8; + const HEADER_CORPUS_SIZE = HEADER_MAX_PATH_SIZE + HEADER_FLAGS_SIZE; + const HEADER_OFFSET_FLAGS = HEADER_MAX_PATH_SIZE; + const HEADER_OFFSET_DIGEST = HEADER_CORPUS_SIZE; + const HEADER_OFFSET_DATA = SECTOR_SIZE; + + const PERSISTENT_FILE_TYPES = + capi.SQLITE_OPEN_MAIN_DB | + capi.SQLITE_OPEN_MAIN_JOURNAL | + capi.SQLITE_OPEN_SUPER_JOURNAL | + capi.SQLITE_OPEN_WAL; + + const OPAQUE_DIR_NAME = '.opaque'; + + const getRandomName = () => Math.random().toString(36).slice(2); + + const textDecoder = new TextDecoder(); + const textEncoder = new TextEncoder(); + + const optionDefaults = Object.assign(Object.create(null), { + name: 'opfs-sahpool', + directory: undefined, + initialCapacity: 6, + clearOnInit: false, + + verbosity: 2, + }); + + const loggers = [ + sqlite3.config.error, + sqlite3.config.warn, + sqlite3.config.log, + ]; + sqlite3.config.log; + const warn = sqlite3.config.warn; + sqlite3.config.error; + + const __mapVfsToPool = new Map(); + const getPoolForVfs = (pVfs) => __mapVfsToPool.get(pVfs); + const setPoolForVfs = (pVfs, pool) => { + if (pool) __mapVfsToPool.set(pVfs, pool); + else __mapVfsToPool.delete(pVfs); + }; + + const __mapSqlite3File = new Map(); + const getPoolForPFile = (pFile) => __mapSqlite3File.get(pFile); + const setPoolForPFile = (pFile, pool) => { + if (pool) __mapSqlite3File.set(pFile, pool); + else __mapSqlite3File.delete(pFile); + }; + + const ioMethods = { + xCheckReservedLock: function (pFile, pOut) { + const pool = getPoolForPFile(pFile); + pool.log('xCheckReservedLock'); + pool.storeErr(); + wasm.poke32(pOut, 1); + return 0; + }, + xClose: function (pFile) { + const pool = getPoolForPFile(pFile); + pool.storeErr(); + const file = pool.getOFileForS3File(pFile); + if (file) { + try { + pool.log(`xClose ${file.path}`); + pool.mapS3FileToOFile(pFile, false); + file.sah.flush(); + if (file.flags & capi.SQLITE_OPEN_DELETEONCLOSE) { + pool.deletePath(file.path); + } + } catch (e) { + return pool.storeErr(e, capi.SQLITE_IOERR); + } + } + return 0; + }, + xDeviceCharacteristics: function (pFile) { + return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; + }, + xFileControl: function (pFile, opId, pArg) { + return capi.SQLITE_NOTFOUND; + }, + xFileSize: function (pFile, pSz64) { + const pool = getPoolForPFile(pFile); + pool.log(`xFileSize`); + const file = pool.getOFileForS3File(pFile); + const size = file.sah.getSize() - HEADER_OFFSET_DATA; + + wasm.poke64(pSz64, BigInt(size)); + return 0; + }, + xLock: function (pFile, lockType) { + const pool = getPoolForPFile(pFile); + pool.log(`xLock ${lockType}`); + pool.storeErr(); + const file = pool.getOFileForS3File(pFile); + file.lockType = lockType; + return 0; + }, + xRead: function (pFile, pDest, n, offset64) { + const pool = getPoolForPFile(pFile); + pool.storeErr(); + const file = pool.getOFileForS3File(pFile); + pool.log(`xRead ${file.path} ${n} @ ${offset64}`); + try { + const nRead = file.sah.read( + wasm.heap8u().subarray(pDest, pDest + n), + { at: HEADER_OFFSET_DATA + Number(offset64) }, + ); + if (nRead < n) { + wasm.heap8u().fill(0, pDest + nRead, pDest + n); + return capi.SQLITE_IOERR_SHORT_READ; + } + return 0; + } catch (e) { + return pool.storeErr(e, capi.SQLITE_IOERR); + } + }, + xSectorSize: function (pFile) { + return SECTOR_SIZE; + }, + xSync: function (pFile, flags) { + const pool = getPoolForPFile(pFile); + pool.log(`xSync ${flags}`); + pool.storeErr(); + const file = pool.getOFileForS3File(pFile); + + try { + file.sah.flush(); + return 0; + } catch (e) { + return pool.storeErr(e, capi.SQLITE_IOERR); + } + }, + xTruncate: function (pFile, sz64) { + const pool = getPoolForPFile(pFile); + pool.log(`xTruncate ${sz64}`); + pool.storeErr(); + const file = pool.getOFileForS3File(pFile); + + try { + file.sah.truncate(HEADER_OFFSET_DATA + Number(sz64)); + return 0; + } catch (e) { + return pool.storeErr(e, capi.SQLITE_IOERR); + } + }, + xUnlock: function (pFile, lockType) { + const pool = getPoolForPFile(pFile); + pool.log('xUnlock'); + const file = pool.getOFileForS3File(pFile); + file.lockType = lockType; + return 0; + }, + xWrite: function (pFile, pSrc, n, offset64) { + const pool = getPoolForPFile(pFile); + pool.storeErr(); + const file = pool.getOFileForS3File(pFile); + pool.log(`xWrite ${file.path} ${n} ${offset64}`); + try { + const nBytes = file.sah.write( + wasm.heap8u().subarray(pSrc, pSrc + n), + { at: HEADER_OFFSET_DATA + Number(offset64) }, + ); + return n === nBytes ? 0 : toss('Unknown write() failure.'); + } catch (e) { + return pool.storeErr(e, capi.SQLITE_IOERR); + } + }, + }; + + const opfsIoMethods = new capi.sqlite3_io_methods(); + opfsIoMethods.$iVersion = 1; + sqlite3.vfs.installVfs({ + io: { struct: opfsIoMethods, methods: ioMethods }, + }); + + const vfsMethods = { + xAccess: function (pVfs, zName, flags, pOut) { + const pool = getPoolForVfs(pVfs); + pool.storeErr(); + try { + const name = pool.getPath(zName); + wasm.poke32(pOut, pool.hasFilename(name) ? 1 : 0); + } catch (e) { + wasm.poke32(pOut, 0); + } + return 0; + }, + xCurrentTime: function (pVfs, pOut) { + wasm.poke( + pOut, + 2440587.5 + new Date().getTime() / 86400000, + 'double', + ); + return 0; + }, + xCurrentTimeInt64: function (pVfs, pOut) { + wasm.poke(pOut, 2440587.5 * 86400000 + new Date().getTime(), 'i64'); + return 0; + }, + xDelete: function (pVfs, zName, doSyncDir) { + const pool = getPoolForVfs(pVfs); + pool.log(`xDelete ${wasm.cstrToJs(zName)}`); + pool.storeErr(); + try { + pool.deletePath(pool.getPath(zName)); + return 0; + } catch (e) { + pool.storeErr(e); + return capi.SQLITE_IOERR_DELETE; + } + }, + xFullPathname: function (pVfs, zName, nOut, pOut) { + const i = wasm.cstrncpy(pOut, zName, nOut); + return i < nOut ? 0 : capi.SQLITE_CANTOPEN; + }, + xGetLastError: function (pVfs, nOut, pOut) { + const pool = getPoolForVfs(pVfs); + const e = pool.popErr(); + pool.log(`xGetLastError ${nOut} e =`, e); + if (e) { + const scope = wasm.scopedAllocPush(); + try { + const [cMsg, n] = wasm.scopedAllocCString(e.message, true); + wasm.cstrncpy(pOut, cMsg, nOut); + if (n > nOut) wasm.poke8(pOut + nOut - 1, 0); + } catch (e) { + return capi.SQLITE_NOMEM; + } finally { + wasm.scopedAllocPop(scope); + } + } + return e ? e.sqlite3Rc || capi.SQLITE_IOERR : 0; + }, + + xOpen: function f(pVfs, zName, pFile, flags, pOutFlags) { + const pool = getPoolForVfs(pVfs); + try { + pool.log(`xOpen ${wasm.cstrToJs(zName)} ${flags}`); + + const path = + zName && wasm.peek8(zName) + ? pool.getPath(zName) + : getRandomName(); + let sah = pool.getSAHForPath(path); + if (!sah && flags & capi.SQLITE_OPEN_CREATE) { + if (pool.getFileCount() < pool.getCapacity()) { + sah = pool.nextAvailableSAH(); + pool.setAssociatedPath(sah, path, flags); + } else { + toss('SAH pool is full. Cannot create file', path); + } + } + if (!sah) { + toss('file not found:', path); + } + + const file = { path, flags, sah }; + pool.mapS3FileToOFile(pFile, file); + file.lockType = capi.SQLITE_LOCK_NONE; + const sq3File = new capi.sqlite3_file(pFile); + sq3File.$pMethods = opfsIoMethods.pointer; + sq3File.dispose(); + wasm.poke32(pOutFlags, flags); + return 0; + } catch (e) { + pool.storeErr(e); + return capi.SQLITE_CANTOPEN; + } + }, + }; + + const createOpfsVfs = function (vfsName) { + if (sqlite3.capi.sqlite3_vfs_find(vfsName)) { + toss3('VFS name is already registered:', vfsName); + } + const opfsVfs = new capi.sqlite3_vfs(); + + const pDVfs = capi.sqlite3_vfs_find(null); + const dVfs = pDVfs ? new capi.sqlite3_vfs(pDVfs) : null; + opfsVfs.$iVersion = 2; + opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; + opfsVfs.$mxPathname = HEADER_MAX_PATH_SIZE; + opfsVfs.addOnDispose( + (opfsVfs.$zName = wasm.allocCString(vfsName)), + () => setPoolForVfs(opfsVfs.pointer, 0), + ); + + if (dVfs) { + opfsVfs.$xRandomness = dVfs.$xRandomness; + opfsVfs.$xSleep = dVfs.$xSleep; + dVfs.dispose(); + } + if (!opfsVfs.$xRandomness && !vfsMethods.xRandomness) { + vfsMethods.xRandomness = function (pVfs, nOut, pOut) { + const heap = wasm.heap8u(); + let i = 0; + for (; i < nOut; ++i) + heap[pOut + i] = (Math.random() * 255000) & 0xff; + return i; + }; + } + if (!opfsVfs.$xSleep && !vfsMethods.xSleep) { + vfsMethods.xSleep = (pVfs, ms) => 0; + } + sqlite3.vfs.installVfs({ + vfs: { struct: opfsVfs, methods: vfsMethods }, + }); + return opfsVfs; + }; + + class OpfsSAHPool { + vfsDir; + + #dhVfsRoot; + + #dhOpaque; + + #dhVfsParent; + + #mapSAHToName = new Map(); + + #mapFilenameToSAH = new Map(); + + #availableSAH = new Set(); + + #mapS3FileToOFile_ = new Map(); + + #apBody = new Uint8Array(HEADER_CORPUS_SIZE); + + #dvBody; + + #cVfs; + + #verbosity; + + constructor(options = Object.create(null)) { + this.#verbosity = options.verbosity ?? optionDefaults.verbosity; + this.vfsName = options.name || optionDefaults.name; + this.#cVfs = createOpfsVfs(this.vfsName); + setPoolForVfs(this.#cVfs.pointer, this); + this.vfsDir = options.directory || '.' + this.vfsName; + this.#dvBody = new DataView( + this.#apBody.buffer, + this.#apBody.byteOffset, + ); + this.isReady = this.reset( + !!(options.clearOnInit ?? optionDefaults.clearOnInit), + ).then(() => { + if (this.$error) throw this.$error; + return this.getCapacity() + ? Promise.resolve(undefined) + : this.addCapacity( + options.initialCapacity || optionDefaults.initialCapacity, + ); + }); + } + + #logImpl(level, ...args) { + if (this.#verbosity > level) + loggers[level](this.vfsName + ':', ...args); + } + log(...args) { + this.#logImpl(2, ...args); + } + warn(...args) { + this.#logImpl(1, ...args); + } + error(...args) { + this.#logImpl(0, ...args); + } + + getVfs() { + return this.#cVfs; + } + + getCapacity() { + return this.#mapSAHToName.size; + } + + getFileCount() { + return this.#mapFilenameToSAH.size; + } + + getFileNames() { + const rc = []; + const iter = this.#mapFilenameToSAH.keys(); + for (const n of iter) rc.push(n); + return rc; + } + + async addCapacity(n) { + for (let i = 0; i < n; ++i) { + const name = getRandomName(); + const h = await this.#dhOpaque.getFileHandle(name, { + create: true, + }); + const ah = await h.createSyncAccessHandle(); + this.#mapSAHToName.set(ah, name); + this.setAssociatedPath(ah, '', 0); + } + return this.getCapacity(); + } + + async reduceCapacity(n) { + let nRm = 0; + for (const ah of Array.from(this.#availableSAH)) { + if (nRm === n || this.getFileCount() === this.getCapacity()) { + break; + } + const name = this.#mapSAHToName.get(ah); + + ah.close(); + await this.#dhOpaque.removeEntry(name); + this.#mapSAHToName.delete(ah); + this.#availableSAH.delete(ah); + ++nRm; + } + return nRm; + } + + releaseAccessHandles() { + for (const ah of this.#mapSAHToName.keys()) ah.close(); + this.#mapSAHToName.clear(); + this.#mapFilenameToSAH.clear(); + this.#availableSAH.clear(); + } + + async acquireAccessHandles(clearFiles) { + const files = []; + for await (const [name, h] of this.#dhOpaque) { + if ('file' === h.kind) { + files.push([name, h]); + } + } + return Promise.all( + files.map(async ([name, h]) => { + try { + const ah = await h.createSyncAccessHandle(); + this.#mapSAHToName.set(ah, name); + if (clearFiles) { + ah.truncate(HEADER_OFFSET_DATA); + this.setAssociatedPath(ah, '', 0); + } else { + const path = this.getAssociatedPath(ah); + if (path) { + this.#mapFilenameToSAH.set(path, ah); + } else { + this.#availableSAH.add(ah); + } + } + } catch (e) { + this.storeErr(e); + this.releaseAccessHandles(); + throw e; + } + }), + ); + } + + getAssociatedPath(sah) { + sah.read(this.#apBody, { at: 0 }); + + const flags = this.#dvBody.getUint32(HEADER_OFFSET_FLAGS); + if ( + this.#apBody[0] && + (flags & capi.SQLITE_OPEN_DELETEONCLOSE || + (flags & PERSISTENT_FILE_TYPES) === 0) + ) { + warn( + `Removing file with unexpected flags ${flags.toString(16)}`, + this.#apBody, + ); + this.setAssociatedPath(sah, '', 0); + return ''; + } + + const fileDigest = new Uint32Array(HEADER_DIGEST_SIZE / 4); + sah.read(fileDigest, { at: HEADER_OFFSET_DIGEST }); + const compDigest = this.computeDigest(this.#apBody); + if (fileDigest.every((v, i) => v === compDigest[i])) { + const pathBytes = this.#apBody.findIndex((v) => 0 === v); + if (0 === pathBytes) { + sah.truncate(HEADER_OFFSET_DATA); + } + return pathBytes + ? textDecoder.decode(this.#apBody.subarray(0, pathBytes)) + : ''; + } else { + warn('Disassociating file with bad digest.'); + this.setAssociatedPath(sah, '', 0); + return ''; + } + } + + setAssociatedPath(sah, path, flags) { + const enc = textEncoder.encodeInto(path, this.#apBody); + if (HEADER_MAX_PATH_SIZE <= enc.written + 1) { + toss('Path too long:', path); + } + this.#apBody.fill(0, enc.written, HEADER_MAX_PATH_SIZE); + this.#dvBody.setUint32(HEADER_OFFSET_FLAGS, flags); + + const digest = this.computeDigest(this.#apBody); + sah.write(this.#apBody, { at: 0 }); + sah.write(digest, { at: HEADER_OFFSET_DIGEST }); + sah.flush(); + + if (path) { + this.#mapFilenameToSAH.set(path, sah); + this.#availableSAH.delete(sah); + } else { + sah.truncate(HEADER_OFFSET_DATA); + this.#availableSAH.add(sah); + } + } + + computeDigest(byteArray) { + let h1 = 0xdeadbeef; + let h2 = 0x41c6ce57; + for (const v of byteArray) { + h1 = 31 * h1 + v * 307; + h2 = 31 * h2 + v * 307; + } + return new Uint32Array([h1 >>> 0, h2 >>> 0]); + } + + async reset(clearFiles) { + await this.isReady; + let h = await navigator.storage.getDirectory(); + let prev; + for (const d of this.vfsDir.split('/')) { + if (d) { + prev = h; + h = await h.getDirectoryHandle(d, { create: true }); + } + } + this.#dhVfsRoot = h; + this.#dhVfsParent = prev; + this.#dhOpaque = await this.#dhVfsRoot.getDirectoryHandle( + OPAQUE_DIR_NAME, + { create: true }, + ); + this.releaseAccessHandles(); + return this.acquireAccessHandles(clearFiles); + } + + getPath(arg) { + if (wasm.isPtr(arg)) arg = wasm.cstrToJs(arg); + return ( + arg instanceof URL ? arg : new URL(arg, 'file://localhost/') + ).pathname; + } + + deletePath(path) { + const sah = this.#mapFilenameToSAH.get(path); + if (sah) { + this.#mapFilenameToSAH.delete(path); + this.setAssociatedPath(sah, '', 0); + } + return !!sah; + } + + storeErr(e, code) { + if (e) { + e.sqlite3Rc = code || capi.SQLITE_IOERR; + this.error(e); + } + this.$error = e; + return code; + } + + popErr() { + const rc = this.$error; + this.$error = undefined; + return rc; + } + + nextAvailableSAH() { + const [rc] = this.#availableSAH.keys(); + return rc; + } + + getOFileForS3File(pFile) { + return this.#mapS3FileToOFile_.get(pFile); + } + + mapS3FileToOFile(pFile, file) { + if (file) { + this.#mapS3FileToOFile_.set(pFile, file); + setPoolForPFile(pFile, this); + } else { + this.#mapS3FileToOFile_.delete(pFile); + setPoolForPFile(pFile, false); + } + } -// Emscripten "legalizes" 64-bit integer arguments by passing them as -// two 32-bit signed integers. -function delegalize(lo32, hi32) { - return (hi32 * 0x100000000) + lo32 + (lo32 < 0 ? 2**32 : 0); -} + hasFilename(name) { + return this.#mapFilenameToSAH.has(name); + } -// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. + getSAHForPath(path) { + return this.#mapFilenameToSAH.get(path); + } -const DEFAULT_TEMPORARY_FILES = 10; -const LOCK_NOTIFY_INTERVAL = 1000; + async removeVfs() { + if (!this.#cVfs.pointer || !this.#dhOpaque) return false; + capi.sqlite3_vfs_unregister(this.#cVfs.pointer); + this.#cVfs.dispose(); + try { + this.releaseAccessHandles(); + await this.#dhVfsRoot.removeEntry(OPAQUE_DIR_NAME, { + recursive: true, + }); + this.#dhOpaque = undefined; + await this.#dhVfsParent.removeEntry(this.#dhVfsRoot.name, { + recursive: true, + }); + this.#dhVfsRoot = this.#dhVfsParent = undefined; + } catch (e) { + sqlite3.config.error(this.vfsName, 'removeVfs() failed:', e); + } + return true; + } -const DB_RELATED_FILE_SUFFIXES = ['', '-journal', '-wal']; + exportFile(name) { + const sah = + this.#mapFilenameToSAH.get(name) || toss('File not found:', name); + const n = sah.getSize() - HEADER_OFFSET_DATA; + const b = new Uint8Array(n > 0 ? n : 0); + if (n > 0) { + const nRead = sah.read(b, { at: HEADER_OFFSET_DATA }); + if (nRead != n) { + toss( + 'Expected to read ' + n + ' bytes but read ' + nRead + '.', + ); + } + } + return b; + } -const finalizationRegistry = new FinalizationRegistry(releaser => releaser()); + async importDbChunked(name, callback) { + const sah = + this.#mapFilenameToSAH.get(name) || + this.nextAvailableSAH() || + toss('No available handles to import to.'); + sah.truncate(0); + let nWrote = 0, + chunk, + checkedHeader = false; + try { + while (undefined !== (chunk = await callback())) { + if (chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk); + if (0 === nWrote && chunk.byteLength >= 15) { + util.affirmDbHeader(chunk); + checkedHeader = true; + } + sah.write(chunk, { at: HEADER_OFFSET_DATA + nWrote }); + nWrote += chunk.byteLength; + } + if (nWrote < 512 || 0 !== nWrote % 512) { + toss( + 'Input size', + nWrote, + 'is not correct for an SQLite database.', + ); + } + if (!checkedHeader) { + const header = new Uint8Array(20); + sah.read(header, { at: 0 }); + util.affirmDbHeader(header); + } + sah.write(new Uint8Array([1, 1]), { + at: HEADER_OFFSET_DATA + 18, + }); + } catch (e) { + this.setAssociatedPath(sah, '', 0); + throw e; + } + this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB); + return nWrote; + } -class File { - /** @type {string} */ path - /** @type {number} */ flags; - /** @type {FileSystemSyncAccessHandle} */ accessHandle; + importDb(name, bytes) { + if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); + else if (bytes instanceof Function) + return this.importDbChunked(name, bytes); + const sah = + this.#mapFilenameToSAH.get(name) || + this.nextAvailableSAH() || + toss('No available handles to import to.'); + const n = bytes.byteLength; + if (n < 512 || n % 512 != 0) { + toss('Byte array size is invalid for an SQLite db.'); + } + const header = 'SQLite format 3'; + for (let i = 0; i < header.length; ++i) { + if (header.charCodeAt(i) !== bytes[i]) { + toss('Input does not contain an SQLite database header.'); + } + } + const nWrote = sah.write(bytes, { at: HEADER_OFFSET_DATA }); + if (nWrote != n) { + this.setAssociatedPath(sah, '', 0); + toss( + 'Expected to write ' + n + ' bytes but wrote ' + nWrote + '.', + ); + } else { + sah.write(new Uint8Array([1, 1]), { + at: HEADER_OFFSET_DATA + 18, + }); + this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB); + } + return nWrote; + } + } - /** @type {PersistentFile?} */ persistentFile; + class OpfsSAHPoolUtil { + #p; - constructor(path, flags) { - this.path = path; - this.flags = flags; - } -} + constructor(sahPool) { + this.#p = sahPool; + this.vfsName = sahPool.vfsName; + } -class PersistentFile { - /** @type {FileSystemFileHandle} */ fileHandle - /** @type {FileSystemSyncAccessHandle} */ accessHandle = null + async addCapacity(n) { + return this.#p.addCapacity(n); + } - // The following properties are for main database files. + async reduceCapacity(n) { + return this.#p.reduceCapacity(n); + } - /** @type {boolean} */ isLockBusy = false; - /** @type {boolean} */ isFileLocked = false; - /** @type {boolean} */ isRequestInProgress = false; - /** @type {function} */ handleLockReleaser = null; + getCapacity() { + return this.#p.getCapacity(this.#p); + } - /** @type {BroadcastChannel} */ handleRequestChannel; - /** @type {boolean} */ isHandleRequested = false; + getFileCount() { + return this.#p.getFileCount(); + } + getFileNames() { + return this.#p.getFileNames(); + } - constructor(fileHandle) { - this.fileHandle = fileHandle; - } -} + async reserveMinimumCapacity(min) { + const c = this.#p.getCapacity(); + return c < min ? this.#p.addCapacity(min - c) : c; + } -class OPFSCoopSyncVFS extends FacadeVFS { - /** @type {Map} */ mapIdToFile = new Map(); - - lastError = null; - log = null; //function(...args) { console.log(`[${contextName}]`, ...args) }; - - /** @type {Map} */ persistentFiles = new Map(); - /** @type {Map} */ boundAccessHandles = new Map(); - /** @type {Set} */ unboundAccessHandles = new Set(); - /** @type {Set} */ accessiblePaths = new Set(); - releaser = null; - - static async create(name, module) { - const vfs = new OPFSCoopSyncVFS(name, module); - await Promise.all([ - vfs.isReady(), - vfs.#initialize(DEFAULT_TEMPORARY_FILES), - ]); - return vfs; - } + exportFile(name) { + return this.#p.exportFile(name); + } - constructor(name, module) { - super(name, module); - } + importDb(name, bytes) { + return this.#p.importDb(name, bytes); + } - async #initialize(nTemporaryFiles) { - // Delete temporary directories no longer in use. - const root = await navigator.storage.getDirectory(); - // @ts-ignore - for await (const entry of root.values()) { - if (entry.kind === 'directory' && entry.name.startsWith('.ahp-')) { - // A lock with the same name as the directory protects it from - // being deleted. - await navigator.locks.request(entry.name, { ifAvailable: true }, async lock => { - if (lock) { - this.log?.(`Deleting temporary directory ${entry.name}`); - await root.removeEntry(entry.name, { recursive: true }); - } else { - this.log?.(`Temporary directory ${entry.name} is in use`); + async wipeFiles() { + return this.#p.reset(true); } - }); - } - } - // Create our temporary directory. - const tmpDirName = `.ahp-${Math.random().toString(36).slice(2)}`; - this.releaser = await new Promise(resolve => { - navigator.locks.request(tmpDirName, () => { - return new Promise(release => { - resolve(release); - }); - }); - }); - finalizationRegistry.register(this, this.releaser); - const tmpDir = await root.getDirectoryHandle(tmpDirName, { create: true }); + unlink(filename) { + return this.#p.deletePath(filename); + } - // Populate temporary directory. - for (let i = 0; i < nTemporaryFiles; i++) { - const tmpFile = await tmpDir.getFileHandle(`${i}.tmp`, { create: true }); - const tmpAccessHandle = await tmpFile.createSyncAccessHandle(); - this.unboundAccessHandles.add(tmpAccessHandle); - } - } + async removeVfs() { + return this.#p.removeVfs(); + } + } - /** - * @param {string?} zName - * @param {number} fileId - * @param {number} flags - * @param {DataView} pOutFlags - * @returns {number} - */ - jOpen(zName, fileId, flags, pOutFlags) { - try { - const url = new URL(zName || Math.random().toString(36).slice(2), 'file://'); - const path = url.pathname; - - if (flags & SQLITE_OPEN_MAIN_DB) { - const persistentFile = this.persistentFiles.get(path); - if (persistentFile?.isRequestInProgress) { - // Should not reach here unless SQLite itself retries an open. - // Otherwise, asynchronous operations started on a previous - // open try should have completed. - return SQLITE_BUSY; - } else if (!persistentFile) { - // This is the usual starting point for opening a database. - // Register a Promise that resolves when the database and related - // files are ready to be used. - this.log?.(`creating persistent file for ${path}`); - const create = !!(flags & SQLITE_OPEN_CREATE); - this._module.retryOps.push((async () => { - try { - // Get the path directory handle. - let dirHandle = await navigator.storage.getDirectory(); - const directories = path.split('/').filter(d => d); - const filename = directories.pop(); - for (const directory of directories) { - dirHandle = await dirHandle.getDirectoryHandle(directory, { create }); - } + const apiVersionCheck = async () => { + const dh = await navigator.storage.getDirectory(); + const fn = '.opfs-sahpool-sync-check-' + getRandomName(); + const fh = await dh.getFileHandle(fn, { create: true }); + const ah = await fh.createSyncAccessHandle(); + const close = ah.close(); + await close; + await dh.removeEntry(fn); + if (close?.then) { + toss( + 'The local OPFS API is too old for opfs-sahpool:', + 'it has an async FileSystemSyncAccessHandle.close() method.', + ); + } + return true; + }; + + sqlite3.installOpfsSAHPoolVfs = async function ( + options = Object.create(null), + ) { + const vfsName = options.name || optionDefaults.name; + if (initPromises[vfsName]) { + return initPromises[vfsName]; + } + if ( + !globalThis.FileSystemHandle || + !globalThis.FileSystemDirectoryHandle || + !globalThis.FileSystemFileHandle || + !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || + !navigator?.storage?.getDirectory + ) { + return (initPromises[vfsName] = Promise.reject( + new Error('Missing required OPFS APIs.'), + )); + } - // Get file handles for the database and related files, - // and create persistent file instances. - for (const suffix of DB_RELATED_FILE_SUFFIXES) { - const fileHandle = await dirHandle.getFileHandle(filename + suffix, { create }); - await this.#createPersistentFile(fileHandle); + return (initPromises[vfsName] = apiVersionCheck() + .then(async function () { + if (options.$testThrowInInit) { + throw options.$testThrowInInit; } + const thePool = new OpfsSAHPool(options); + return thePool.isReady + .then(async () => { + const poolUtil = new OpfsSAHPoolUtil(thePool); + if (sqlite3.oo1) { + const oo1 = sqlite3.oo1; + const theVfs = thePool.getVfs(); + const OpfsSAHPoolDb = function (...args) { + const opt = oo1.DB.dbCtorHelper.normalizeArgs(...args); + opt.vfs = theVfs.$zName; + oo1.DB.dbCtorHelper.call(this, opt); + }; + OpfsSAHPoolDb.prototype = Object.create(oo1.DB.prototype); + + poolUtil.OpfsSAHPoolDb = OpfsSAHPoolDb; + oo1.DB.dbCtorHelper.setVfsPostOpenSql( + theVfs.pointer, + function (oo1Db, sqlite3) { + sqlite3.capi.sqlite3_exec( + oo1Db, + [ + 'pragma journal_mode=DELETE;', + 'pragma cache_size=-16384;', + ], + 0, + 0, + 0, + ); + }, + ); + } + thePool.log('VFS initialized.'); + return poolUtil; + }) + .catch(async (e) => { + await thePool.removeVfs().catch(() => {}); + throw e; + }); + }) + .catch((err) => { + return (initPromises[vfsName] = Promise.reject(err)); + })); + }; + }); + if ('undefined' !== typeof Module) { + const SABC = Object.assign( + Object.create(null), + { + exports: + 'undefined' === typeof wasmExports ? Module['asm'] : wasmExports, + memory: Module.wasmMemory, + }, + globalThis.sqlite3ApiConfig || {}, + ); + + globalThis.sqlite3ApiConfig = SABC; + let sqlite3; + try { + sqlite3 = globalThis.sqlite3ApiBootstrap(); + } catch (e) { + console.error('sqlite3ApiBootstrap() error:', e); + throw e; + } finally { + delete globalThis.sqlite3ApiBootstrap; + delete globalThis.sqlite3ApiConfig; + } - // Get access handles for the files. - const file = new File(path, flags); - file.persistentFile = this.persistentFiles.get(path); - await this.#requestAccessHandle(file); - } catch (e) { - // Use an invalid persistent file to signal this error - // for the retried open. - const persistentFile = new PersistentFile(null); - this.persistentFiles.set(path, persistentFile); - console.error(e); - } - })()); - return SQLITE_BUSY; - } else if (!persistentFile.fileHandle) { - // The asynchronous open operation failed. - this.persistentFiles.delete(path); - return SQLITE_CANTOPEN; - } else if (!persistentFile.accessHandle) { - // This branch is reached if the database was previously opened - // and closed. - this._module.retryOps.push((async () => { - const file = new File(path, flags); - file.persistentFile = this.persistentFiles.get(path); - await this.#requestAccessHandle(file); - })()); - return SQLITE_BUSY; - } - } - - if (!this.accessiblePaths.has(path) && - !(flags & SQLITE_OPEN_CREATE)) { - throw new Error(`File ${path} not found`); - } - - const file = new File(path, flags); - this.mapIdToFile.set(fileId, file); - - if (this.persistentFiles.has(path)) { - file.persistentFile = this.persistentFiles.get(path); - } else if (this.boundAccessHandles.has(path)) { - // This temporary file was previously created and closed. Reopen - // the same access handle. - file.accessHandle = this.boundAccessHandles.get(path); - } else if (this.unboundAccessHandles.size) { - // Associate an unbound access handle to this file. - file.accessHandle = this.unboundAccessHandles.values().next().value; - file.accessHandle.truncate(0); - this.unboundAccessHandles.delete(file.accessHandle); - this.boundAccessHandles.set(path, file.accessHandle); - } - this.accessiblePaths.add(path); - - pOutFlags.setInt32(0, flags, true); - return SQLITE_OK; - } catch (e) { - this.lastError = e; - return SQLITE_CANTOPEN; - } - } - - /** - * @param {string} zName - * @param {number} syncDir - * @returns {number} - */ - jDelete(zName, syncDir) { - try { - const url = new URL(zName, 'file://'); - const path = url.pathname; - if (this.persistentFiles.has(path)) { - const persistentFile = this.persistentFiles.get(path); - persistentFile.accessHandle.truncate(0); + Module.sqlite3 = sqlite3; } else { - this.boundAccessHandles.get(path)?.truncate(0); + console.warn( + 'This is not running in an Emscripten module context, so', + 'globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack', + 'of config info for the WASM environment.', + 'It must be called manually.', + ); } - this.accessiblePaths.delete(path); - return SQLITE_OK; - } catch (e) { - this.lastError = e; - return SQLITE_IOERR_DELETE; - } - } - - /** - * @param {string} zName - * @param {number} flags - * @param {DataView} pResOut - * @returns {number} - */ - jAccess(zName, flags, pResOut) { - try { - const url = new URL(zName, 'file://'); - const path = url.pathname; - pResOut.setInt32(0, this.accessiblePaths.has(path) ? 1 : 0, true); - return SQLITE_OK; - } catch (e) { - this.lastError = e; - return SQLITE_IOERR_ACCESS; - } - } + }); - /** - * @param {number} fileId - * @returns {number} - */ - jClose(fileId) { - try { - const file = this.mapIdToFile.get(fileId); - this.mapIdToFile.delete(fileId); + return sqlite3InitModule.ready; + }; +})(); - if (file?.flags & SQLITE_OPEN_MAIN_DB) { - if (file.persistentFile?.handleLockReleaser) { - this.#releaseAccessHandle(file); - } - } else if (file?.flags & SQLITE_OPEN_DELETEONCLOSE) { - file.accessHandle.truncate(0); - this.accessiblePaths.delete(file.path); - if (!this.persistentFiles.has(file.path)) { - this.boundAccessHandles.delete(file.path); - this.unboundAccessHandles.add(file.accessHandle); - } - } - return SQLITE_OK; - } catch (e) { - this.lastError = e; - return SQLITE_IOERR_CLOSE; - } +const toExportForESM = (function () { + const originalInit = sqlite3InitModule; + if (!originalInit) { + throw new Error( + 'Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build.', + ); } - /** - * @param {number} fileId - * @param {Uint8Array} pData - * @param {number} iOffset - * @returns {number} - */ - jRead(fileId, pData, iOffset) { - try { - const file = this.mapIdToFile.get(fileId); - - // On Chrome (at least), passing pData to accessHandle.read() is - // an error because pData is a Proxy of a Uint8Array. Calling - // subarray() produces a real Uint8Array and that works. - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - const bytesRead = accessHandle.read(pData.subarray(), { at: iOffset }); + const initModuleState = (globalThis.sqlite3InitModuleState = Object.assign( + Object.create(null), + { + moduleScript: globalThis?.document?.currentScript, + isWorker: 'undefined' !== typeof WorkerGlobalScope, + location: globalThis.location, + urlParams: globalThis?.location?.href + ? new URL(globalThis.location.href).searchParams + : new URLSearchParams(), + }, + )); + initModuleState.debugModule = initModuleState.urlParams.has( + 'sqlite3.debugModule', + ) + ? (...args) => console.warn('sqlite3.debugModule:', ...args) + : () => {}; + + if (initModuleState.urlParams.has('sqlite3.dir')) { + initModuleState.sqlite3Dir = + initModuleState.urlParams.get('sqlite3.dir') + '/'; + } else if (initModuleState.moduleScript) { + const li = initModuleState.moduleScript.src.split('/'); + li.pop(); + initModuleState.sqlite3Dir = li.join('/') + '/'; + } + + globalThis.sqlite3InitModule = function ff(...args) { + return originalInit(...args) + .then((EmscriptenModule) => { + const s = EmscriptenModule.sqlite3; + s.scriptInfo = initModuleState; + + if (ff.__isUnderTest) s.__isUnderTest = true; + const f = s.asyncPostInit; + delete s.asyncPostInit; + return f(); + }) + .catch((e) => { + console.error('Exception loading sqlite3 module:', e); + throw e; + }); + }; + globalThis.sqlite3InitModule.ready = originalInit.ready; - // Opening a database file performs one read without a xLock call. - if ((file.flags & SQLITE_OPEN_MAIN_DB) && !file.persistentFile.isFileLocked) { - this.#releaseAccessHandle(file); + if (globalThis.sqlite3InitModuleState.moduleScript) { + const sim = globalThis.sqlite3InitModuleState; + let src = sim.moduleScript.src.split('/'); + src.pop(); + sim.scriptDir = src.join('/') + '/'; + } + initModuleState.debugModule('sqlite3InitModuleState =', initModuleState); + return globalThis.sqlite3InitModule; +})(); +sqlite3InitModule = toExportForESM; +var sqlite3InitModule$1 = sqlite3InitModule; + +/* + 2022-08-24 + + The author disclaims copyright to this source code. In place of a + legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + + *********************************************************************** + + This file implements a Promise-based proxy for the sqlite3 Worker + API #1. It is intended to be included either from the main thread or + a Worker, but only if (A) the environment supports nested Workers + and (B) it's _not_ a Worker which loads the sqlite3 WASM/JS + module. This file's features will load that module and provide a + slightly simpler client-side interface than the slightly-lower-level + Worker API does. + + This script necessarily exposes one global symbol, but clients may + freely `delete` that symbol after calling it. +*/ + +globalThis.sqlite3Worker1Promiser = function callee( + config = callee.defaultConfig, +) { + if (1 === arguments.length && 'function' === typeof arguments[0]) { + const f = config; + config = Object.assign(Object.create(null), callee.defaultConfig); + config.onready = f; + } else { + config = Object.assign(Object.create(null), callee.defaultConfig, config); + } + const handlerMap = Object.create(null); + const noop = function () {}; + const err = config.onerror || noop; + const debug = config.debug || noop; + const idTypeMap = config.generateMessageId ? undefined : Object.create(null); + const genMsgId = + config.generateMessageId || + function (msg) { + return ( + msg.type + '#' + (idTypeMap[msg.type] = (idTypeMap[msg.type] || 0) + 1) + ); + }; + const toss = (...args) => { + throw new Error(args.join(' ')); + }; + if (!config.worker) config.worker = callee.defaultConfig.worker; + if ('function' === typeof config.worker) config.worker = config.worker(); + let dbId; + let promiserFunc; + config.worker.onmessage = function (ev) { + ev = ev.data; + debug('worker1.onmessage', ev); + let msgHandler = handlerMap[ev.messageId]; + if (!msgHandler) { + if (ev && 'sqlite3-api' === ev.type && 'worker1-ready' === ev.result) { + if (config.onready) config.onready(promiserFunc); + return; } - - if (bytesRead < pData.byteLength) { - pData.fill(0, bytesRead); - return SQLITE_IOERR_SHORT_READ; + msgHandler = handlerMap[ev.type]; + if (msgHandler && msgHandler.onrow) { + msgHandler.onrow(ev); + return; } - return SQLITE_OK; - } catch (e) { - this.lastError = e; - return SQLITE_IOERR_READ; - } - } - - /** - * @param {number} fileId - * @param {Uint8Array} pData - * @param {number} iOffset - * @returns {number} - */ - jWrite(fileId, pData, iOffset) { - try { - const file = this.mapIdToFile.get(fileId); - - // On Chrome (at least), passing pData to accessHandle.write() is - // an error because pData is a Proxy of a Uint8Array. Calling - // subarray() produces a real Uint8Array and that works. - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - const nBytes = accessHandle.write(pData.subarray(), { at: iOffset }); - if (nBytes !== pData.byteLength) throw new Error('short write'); - return SQLITE_OK; - } catch (e) { - this.lastError = e; - return SQLITE_IOERR_WRITE; + if (config.onunhandled) config.onunhandled(arguments[0]); + else err('sqlite3Worker1Promiser() unhandled worker message:', ev); + return; } - } - - /** - * @param {number} fileId - * @param {number} iSize - * @returns {number} - */ - jTruncate(fileId, iSize) { - try { - const file = this.mapIdToFile.get(fileId); - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - accessHandle.truncate(iSize); - return SQLITE_OK; - } catch (e) { - this.lastError = e; - return SQLITE_IOERR_TRUNCATE; + delete handlerMap[ev.messageId]; + switch (ev.type) { + case 'error': + msgHandler.reject(ev); + return; + case 'open': + if (!dbId) dbId = ev.dbId; + break; + case 'close': + if (ev.dbId === dbId) dbId = undefined; + break; } - } - - /** - * @param {number} fileId - * @param {number} flags - * @returns {number} - */ - jSync(fileId, flags) { try { - const file = this.mapIdToFile.get(fileId); - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - accessHandle.flush(); - return SQLITE_OK; + msgHandler.resolve(ev); } catch (e) { - this.lastError = e; - return SQLITE_IOERR_FSYNC; + msgHandler.reject(e); } - } - - /** - * @param {number} fileId - * @param {DataView} pSize64 - * @returns {number} - */ - jFileSize(fileId, pSize64) { - try { - const file = this.mapIdToFile.get(fileId); - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - const size = accessHandle.getSize(); - pSize64.setBigInt64(0, BigInt(size), true); - return SQLITE_OK; - } catch (e) { - this.lastError = e; - return SQLITE_IOERR_FSTAT; + }; + return (promiserFunc = function () { + let msg; + if (1 === arguments.length) { + msg = arguments[0]; + } else if (2 === arguments.length) { + msg = Object.create(null); + msg.type = arguments[0]; + msg.args = arguments[1]; + msg.dbId = msg.args.dbId; + } else { + toss('Invalid arguments for sqlite3Worker1Promiser()-created factory.'); } - } - - /** - * @param {number} fileId - * @param {number} lockType - * @returns {number} - */ - jLock(fileId, lockType) { - const file = this.mapIdToFile.get(fileId); - if (file.persistentFile.isRequestInProgress) { - file.persistentFile.isLockBusy = true; - return SQLITE_BUSY; - } - - file.persistentFile.isFileLocked = true; - if (!file.persistentFile.handleLockReleaser) { - // Start listening for notifications from other connections. - // This is before we actually get access handles, but waiting to - // listen until then allows a race condition where notifications - // are missed. - file.persistentFile.handleRequestChannel.onmessage = () => { - this.log?.(`received notification for ${file.path}`); - if (file.persistentFile.isFileLocked) { - // We're still using the access handle, so mark it to be - // released when we're done. - file.persistentFile.isHandleRequested = true; - } else { - // Release the access handles immediately. - this.#releaseAccessHandle(file); - } - file.persistentFile.handleRequestChannel.onmessage = null; - }; - - this.#requestAccessHandle(file); - this.log?.('returning SQLITE_BUSY'); - file.persistentFile.isLockBusy = true; - return SQLITE_BUSY; + if (!msg.dbId && msg.type !== 'open') msg.dbId = dbId; + msg.messageId = genMsgId(msg); + msg.departureTime = performance.now(); + const proxy = Object.create(null); + proxy.message = msg; + let rowCallbackId; + if ('exec' === msg.type && msg.args) { + if ('function' === typeof msg.args.callback) { + rowCallbackId = msg.messageId + ':row'; + proxy.onrow = msg.args.callback; + msg.args.callback = rowCallbackId; + handlerMap[rowCallbackId] = proxy; + } else if ('string' === typeof msg.args.callback) { + toss( + 'exec callback may not be a string when using the Promise interface.', + ); + } } - file.persistentFile.isLockBusy = false; - return SQLITE_OK; - } - /** - * @param {number} fileId - * @param {number} lockType - * @returns {number} - */ - jUnlock(fileId, lockType) { - const file = this.mapIdToFile.get(fileId); - if (lockType === SQLITE_LOCK_NONE) { - // Don't change any state if this unlock is because xLock returned - // SQLITE_BUSY. - if (!file.persistentFile.isLockBusy) { - if (file.persistentFile.isHandleRequested) { - // Another connection wants the access handle. - this.#releaseAccessHandle(file); - this.isHandleRequested = false; - } - file.persistentFile.isFileLocked = false; - } - } - return SQLITE_OK; - } - - /** - * @param {number} fileId - * @param {number} op - * @param {DataView} pArg - * @returns {number|Promise} - */ - jFileControl(fileId, op, pArg) { - try { - const file = this.mapIdToFile.get(fileId); - switch (op) { - case SQLITE_FCNTL_PRAGMA: - const key = extractString(pArg, 4); - const value = extractString(pArg, 8); - this.log?.('xFileControl', file.path, 'PRAGMA', key, value); - switch (key.toLowerCase()) { - case 'journal_mode': - if (value && - !['off', 'memory', 'delete', 'wal'].includes(value.toLowerCase())) { - throw new Error('journal_mode must be "off", "memory", "delete", or "wal"'); - } - break; - } - break; + let p = new Promise(function (resolve, reject) { + proxy.resolve = resolve; + proxy.reject = reject; + handlerMap[msg.messageId] = proxy; + debug( + 'Posting', + msg.type, + 'message to Worker dbId=' + (dbId || 'default') + ':', + msg, + ); + config.worker.postMessage(msg); + }); + if (rowCallbackId) p = p.finally(() => delete handlerMap[rowCallbackId]); + return p; + }); +}; + +globalThis.sqlite3Worker1Promiser.defaultConfig = { + worker: function () { + return new Worker( + new URL('sqlite3-worker1-bundler-friendly.mjs', import.meta.url), + { + type: 'module', + }, + ); + }, + onerror: (...args) => console.error('worker1 promiser error', ...args), +}; + +sqlite3Worker1Promiser.v2 = function (config) { + let oldFunc; + if ('function' == typeof config) { + oldFunc = config; + config = {}; + } else if ('function' === typeof config?.onready) { + oldFunc = config.onready; + delete config.onready; + } + const promiseProxy = Object.create(null); + config = Object.assign(config || Object.create(null), { + onready: async function (func) { + try { + if (oldFunc) await oldFunc(func); + promiseProxy.resolve(func); + } catch (e) { + promiseProxy.reject(e); } - } catch (e) { - this.lastError = e; - return SQLITE_IOERR; - } - return SQLITE_NOTFOUND; - } + }, + }); + const p = new Promise(function (resolve, reject) { + promiseProxy.resolve = resolve; + promiseProxy.reject = reject; + }); + try { + this.original(config); + } catch (e) { + promiseProxy.reject(e); + } + return p; +}.bind({ + original: sqlite3Worker1Promiser, +}); - /** - * @param {Uint8Array} zBuf - * @returns - */ - jGetLastError(zBuf) { - if (this.lastError) { - console.error(this.lastError); - const outputArray = zBuf.subarray(0, zBuf.byteLength - 1); - const { written } = new TextEncoder().encodeInto(this.lastError.message, outputArray); - zBuf[written] = 0; - } - return SQLITE_OK - } +sqlite3Worker1Promiser.v2; - /** - * @param {FileSystemFileHandle} fileHandle - * @returns {Promise} - */ - async #createPersistentFile(fileHandle) { - const persistentFile = new PersistentFile(fileHandle); - const root = await navigator.storage.getDirectory(); - const relativePath = await root.resolve(fileHandle); - const path = `/${relativePath.join('/')}`; - persistentFile.handleRequestChannel = new BroadcastChannel(`ahp:${path}`); - this.persistentFiles.set(path, persistentFile); - - const f = await fileHandle.getFile(); - if (f.size) { - this.accessiblePaths.add(path); - } - return persistentFile; - } +const log = console.log; +const err_log = console.error; - /** - * @param {File} file - */ - #requestAccessHandle(file) { - console.assert(!file.persistentFile.handleLockReleaser); - if (!file.persistentFile.isRequestInProgress) { - file.persistentFile.isRequestInProgress = true; - this._module.retryOps.push((async () => { - // Acquire the Web Lock. - file.persistentFile.handleLockReleaser = await this.#acquireLock(file.persistentFile); - - // Get access handles for the database and releated files in parallel. - this.log?.(`creating access handles for ${file.path}`); - await Promise.all(DB_RELATED_FILE_SUFFIXES.map(async suffix => { - const persistentFile = this.persistentFiles.get(file.path + suffix); - if (persistentFile) { - persistentFile.accessHandle = - await persistentFile.fileHandle.createSyncAccessHandle(); - } - })); - file.persistentFile.isRequestInProgress = false; - })()); - return this._module.retryOps.at(-1); - } - return Promise.resolve(); +class SQLiteError extends Error { + constructor(message, code) { + super(message); + this.code = code; } +} - /** - * @param {File} file - */ - async #releaseAccessHandle(file) { - DB_RELATED_FILE_SUFFIXES.forEach(async suffix => { - const persistentFile = this.persistentFiles.get(file.path + suffix); - if (persistentFile) { - persistentFile.accessHandle?.close(); - persistentFile.accessHandle = null; - } - }); - this.log?.(`access handles closed for ${file.path}`); - - file.persistentFile.handleLockReleaser?.(); - file.persistentFile.handleLockReleaser = null; - this.log?.(`lock released for ${file.path}`); +class SQLite { + #module; + #sqlite3; + constructor(sqlite3) { + if (typeof sqlite3 === "undefined") { + throw new Error( + "`sqliteObject` must be defined before calling constructor", + ); + } + this.sqlite3 = sqlite3; } - /** - * @param {PersistentFile} persistentFile - * @returns {Promise} lock releaser - */ - #acquireLock(persistentFile) { - return new Promise(resolve => { - // Tell other connections we want the access handle. - const lockName = persistentFile.handleRequestChannel.name; - const notify = () => { - this.log?.(`notifying for ${lockName}`); - persistentFile.handleRequestChannel.postMessage(null); - }; - const notifyId = setInterval(notify, LOCK_NOTIFY_INTERVAL); - setTimeout(notify); - - this.log?.(`lock requested: ${lockName}`); - navigator.locks.request(lockName, lock => { - // We have the lock. Stop asking other connections for it. - this.log?.(`lock acquired: ${lockName}`, lock); - clearInterval(notifyId); - return new Promise(resolve); - }); + static async init_module(opts) { + return await sqlite3InitModule$1({ + print: log, + printErr: err_log, + ...opts, }); } -} -function extractString(dataView, offset) { - const p = dataView.getUint32(offset, true); - if (p) { - const chars = new Uint8Array(dataView.buffer, p); - return new TextDecoder().decode(chars.subarray(0, chars.indexOf(0))); + version() { + return this.sqlite3.version; } - return null; -} - -var Module = (() => { - var _scriptDir = import.meta.url; - - return ( -function(moduleArg = {}) { - -var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject;});var moduleOverrides=Object.assign({},Module);var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href;}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src;}if(_scriptDir){scriptDirectory=_scriptDir;}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1);}else {scriptDirectory="";}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)};}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror();};xhr.onerror=onerror;xhr.send(null);};}}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(typeof WebAssembly!="object"){abort("no native wasm support detected");}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text);}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift());}}callRuntimeCallbacks(__ATPRERUN__);}function initRuntime(){if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;callRuntimeCallbacks(__ATINIT__);}function preMain(){callRuntimeCallbacks(__ATMAIN__);}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift());}}callRuntimeCallbacks(__ATPOSTRUN__);}function addOnPreRun(cb){__ATPRERUN__.unshift(cb);}function addOnInit(cb){__ATINIT__.unshift(cb);}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb);}var runDependencies=0;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies);}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies);}if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback();}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what);}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var wasmBinaryFile;if(Module["locateFile"]){wasmBinaryFile="wa-sqlite.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile);}}else {wasmBinaryFile=new URL("wa-sqlite.wasm",import.meta.url).href;}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw "both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw "failed to load wasm binary file at '"+binaryFile+"'"}return response["arrayBuffer"]()}).catch(()=>getBinarySync(binaryFile))}}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(instance=>instance).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason);})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["ja"];updateMemoryViews();wasmTable=wasmExports["bf"];addOnInit(wasmExports["ka"]);removeRunDependency();return wasmExports}addRunDependency();function receiveInstantiationResult(result){receiveInstance(result["instance"]);}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e);}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return {}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status;}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module);}};function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`);}}var noExitRuntime=Module["noExitRuntime"]||true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`);}}var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023);}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var ___assert_fail=(condition,filename,line,func)=>{abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"]);};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1);}else if(last===".."){parts.splice(i,1);up++;}else if(up){parts.splice(i,1);up--;}}if(allowAboveRoot){for(;up;up--){parts.unshift("..");}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path=".";}if(path&&trailingSlash){path+="/";}return (isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return "."}if(dir){dir=dir.substr(0,dir.length-1);}return root+dir},basename:path=>{if(path==="/")return "/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else abort("initRandomDevice");};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return ""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path);}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return (resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return [];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i;}else {len+=3;}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023;}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u;}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63;}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;}else {if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n";}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n";}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true);}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops);},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false;},close(stream){stream.tty.ops.fsync(stream.tty);},fsync(stream){stream.tty.ops.fsync(stream.tty);},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[];}},ioctl_tcgets(tty){return {c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return [24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[];}else {if(val!=0)tty.output.push(val);}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[];}}}};var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={};}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null;}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream;}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream;}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp;}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;}else {var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)));}node.usedBytes=newSize;}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096;}else if(FS.isFile(node.mode)){attr.size=node.usedBytes;}else if(FS.isLink(node.mode)){attr.size=node.link.length;}else {attr.size=0;}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode;}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp;}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size);}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name);}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir;},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now();},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now();},readdir(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key);}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset);}else {for(var i=0;i0||position+length{var dep=getUniqueRunDependency(`al ${url}`);readAsync(url,arrayBuffer=>{assert(arrayBuffer,`Loading data file "${url}" failed (no arrayBuffer).`);onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency();},event=>{if(onerror){onerror();}else {throw `Loading data file "${url}" failed.`}});if(dep)addRunDependency();};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn);var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true;}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn);}if(onload)onload();removeRunDependency();}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency();})){return}finish(byteArray);}addRunDependency();if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror);}else {processData(url);}};var FS_modeStringToFlags=str=>{var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return {path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return {path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent;}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node;},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next;}else {var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next;}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node);},isRoot(node){return node===node.parent},isMountpoint(node){return !!node.mounted},isFile(mode){return (mode&61440)===32768},isDir(mode){return (mode&61440)===16384},isLink(mode){return (mode&61440)===40960},isChrdev(mode){return (mode&61440)===8192},isBlkdev(mode){return (mode&61440)===24576},isFIFO(mode){return (mode&61440)===4096},isSocket(mode){return (mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w";}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name);}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else {if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){if(!FS.FSStream){FS.FSStream=function(){this.shared={};};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get(){return this.node},set(val){this.node=val;}},isRead:{get(){return (this.flags&2097155)!==1}},isWrite:{get(){return (this.flags&2097155)!==0}},isAppend:{get(){return this.flags&1024}},flags:{get(){return this.shared.flags},set(val){this.shared.flags=val;}},position:{get(){return this.shared.position},set(val){this.shared.position=val;}}});}stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd();}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null;},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream);}},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops};},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts);}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false;}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null);}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done);});},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot;}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount);}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current);}current=next;}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1);},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;i0,ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0);}else if(opts.encoding==="binary"){ret=buf;}FS.close(stream);return ret},writeFile(path,data,opts={}){opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn);}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn);}else {throw new Error("Unsupported data type")}FS.close(stream);},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path;},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user");},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength;}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp");},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd");},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"]);}else {FS.symlink("/dev/tty","/dev/stdin");}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"]);}else {FS.symlink("/dev/tty","/dev/stdout");}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"]);}else {FS.symlink("/dev/tty1","/dev/stderr");}FS.open("/dev/stdin",0);FS.open("/dev/stdout",1);FS.open("/dev/stderr",1);},ensureErrnoError(){if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno;};this.setErrno(errno);this.message="FS error";};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack="";});},staticInit(){FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS};},init(input,output,error){FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams();},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter;};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined");}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end);}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed");}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true;};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength();}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength();}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray};}else {var properties={isDevice:false,url:url};}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents;}else if(properties.url){node.contents=null;node.url=properties.url;}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)};});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return {ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd();}else {var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path;}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){try{var stat=func(path);}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return -54}throw e}HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags);},varargs:undefined,get(){var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret},getp(){return SYSCALLS.get()},getStr(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream}};function ___syscall_chmod(path,mode){try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return -28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return -44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return -2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var setErrNo=value=>{HEAP32[___errno_location()>>2]=value;return value};function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return -28}while(FS.streams[arg]){arg++;}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.getp();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return -28;case 9:setErrNo(28);return -1;default:{return -28}}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function ___syscall_ftruncate64(fd,length_low,length_high){var length=convertI32PairToI53Checked(length_low,length_high);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function ___syscall_getcwd(buf,size){try{if(size===0)return -28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(sizeHEAPU32[ptr>>2]+HEAP32[ptr+4>>2]*4294967296;function ___syscall_utimensat(dirfd,path,times,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);if(!times){var atime=Date.now();var mtime=atime;}else {var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>2];atime=seconds*1e3+nanoseconds/(1e3*1e3);times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>2];mtime=seconds*1e3+nanoseconds/(1e3*1e3);}FS.utime(path,atime,mtime);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst;}function __mmap_js(len,prot,flags,fd,offset_low,offset_high,allocated,addr){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset_low,offset_high){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset);}FS.munmap(stream);}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return -e.errno}}var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};var __tzset_js=(timezone,daylight,tzname)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=stringToNewUTF8(winterName);var summerNamePtr=stringToNewUTF8(summerName);if(summerOffset>2]=winterNamePtr;HEAPU32[tzname+4>>2]=summerNamePtr;}else {HEAPU32[tzname>>2]=summerNamePtr;HEAPU32[tzname+4>>2]=winterNamePtr;}};var _emscripten_date_now=()=>Date.now();var _emscripten_get_now;_emscripten_get_now=()=>performance.now();var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x];}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`);}getEnvStrings.strings=strings;}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>0]=str.charCodeAt(i);}HEAP8[buffer>>0]=0;};var _environ_get=(__environ,environ_buf)=>{var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1;});return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4;}HEAP8[pbuf>>0]=type;HEAP16[pbuf+2>>1]=flags;tempI64=[rightsBase>>>0,(tempDouble=rightsBase,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+8>>2]=tempI64[0],HEAP32[pbuf+12>>2]=tempI64[1];tempI64=[rightsInheriting>>>0,(tempDouble=rightsInheriting,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+16>>2]=tempI64[0],HEAP32[pbuf+20>>2]=tempI64[1];return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return -1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops&&stream.stream_ops.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return -1;ret+=curr;}return ret};function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var adapters_support=function(){const handleAsync=typeof Asyncify==="object"?Asyncify.handleAsync.bind(Asyncify):null;Module["handleAsync"]=handleAsync;const targets=new Map;Module["setCallback"]=(key,target)=>targets.set(key,target);Module["getCallback"]=key=>targets.get(key);Module["deleteCallback"]=key=>targets.delete(key);adapters_support=function(isAsync,key,...args){const receiver=targets.get(key);let methodName=null;const f=typeof receiver==="function"?receiver:receiver[methodName=UTF8ToString(args.shift())];if(isAsync){if(handleAsync){return handleAsync(()=>f.apply(receiver,args))}throw new Error("Synchronous WebAssembly cannot call async function")}const result=f.apply(receiver,args);if(typeof result?.then=="function"){console.error("unexpected Promise",f);throw new Error(`${methodName} unexpectedly returned a Promise`)}return result};};function _ipp(...args){return adapters_support(false,...args)}function _ipp_async(...args){return adapters_support(true,...args)}function _ippipppp(...args){return adapters_support(false,...args)}function _ippipppp_async(...args){return adapters_support(true,...args)}function _ippp(...args){return adapters_support(false,...args)}function _ippp_async(...args){return adapters_support(true,...args)}function _ipppi(...args){return adapters_support(false,...args)}function _ipppi_async(...args){return adapters_support(true,...args)}function _ipppiii(...args){return adapters_support(false,...args)}function _ipppiii_async(...args){return adapters_support(true,...args)}function _ipppiiip(...args){return adapters_support(false,...args)}function _ipppiiip_async(...args){return adapters_support(true,...args)}function _ipppip(...args){return adapters_support(false,...args)}function _ipppip_async(...args){return adapters_support(true,...args)}function _ipppj(...args){return adapters_support(false,...args)}function _ipppj_async(...args){return adapters_support(true,...args)}function _ipppp(...args){return adapters_support(false,...args)}function _ipppp_async(...args){return adapters_support(true,...args)}function _ippppi(...args){return adapters_support(false,...args)}function _ippppi_async(...args){return adapters_support(true,...args)}function _ippppij(...args){return adapters_support(false,...args)}function _ippppij_async(...args){return adapters_support(true,...args)}function _ippppip(...args){return adapters_support(false,...args)}function _ippppip_async(...args){return adapters_support(true,...args)}function _ipppppip(...args){return adapters_support(false,...args)}function _ipppppip_async(...args){return adapters_support(true,...args)}function _vppp(...args){return adapters_support(false,...args)}function _vppp_async(...args){return adapters_support(true,...args)}function _vpppip(...args){return adapters_support(false,...args)}function _vpppip_async(...args){return adapters_support(true,...args)}var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true;}quit_(code,new ExitStatus(code));};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status);};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e);};var uleb128Encode=(n,target)=>{if(n<128){target.push(n);}else {target.push(n%128|128,n>>7);}};var sigToWasmTypes=sig=>{var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64","e":"externref","p":"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var sigRet=sig.slice(0,1);var sigParam=sig.slice(1);var typeCodes={"i":127,"p":127,"j":126,"f":125,"d":124,"e":111};target.push(96);uleb128Encode(sigParam.length,target);for(var i=0;i{if(typeof WebAssembly.Function=="function"){return new WebAssembly.Function(sigToWasmTypes(sig),func)}var typeSectionBody=[1];generateFuncType(sig,typeSectionBody);var bytes=[0,97,115,109,1,0,0,0,1];uleb128Encode(typeSectionBody.length,bytes);bytes.push.apply(bytes,typeSectionBody);bytes.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);var module=new WebAssembly.Module(new Uint8Array(bytes));var instance=new WebAssembly.Instance(module,{"e":{"f":func}});var wrappedFunc=instance.exports["f"];return wrappedFunc};var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var updateTableMap=(offset,count)=>{if(functionsInTableMap){for(var i=offset;i{if(!functionsInTableMap){functionsInTableMap=new WeakMap;updateTableMap(0,wasmTable.length);}return functionsInTableMap.get(func)||0};var freeTableIndexes=[];var getEmptyTableSlot=()=>{if(freeTableIndexes.length){return freeTableIndexes.pop()}try{wasmTable.grow(1);}catch(err){if(!(err instanceof RangeError)){throw err}throw "Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."}return wasmTable.length-1};var setWasmTableEntry=(idx,func)=>wasmTable.set(idx,func);var addFunction=(func,sig)=>{var rtn=getFunctionAddress(func);if(rtn){return rtn}var ret=getEmptyTableSlot();try{setWasmTableEntry(ret,func);}catch(err){if(!(err instanceof TypeError)){throw err}var wrapped=convertJsFunctionToWasm(func,sig);setWasmTableEntry(ret,wrapped);}functionsInTableMap.set(func,ret);return ret};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer);};var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={"string":str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str);}return ret},"array":arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return function(){return ccall(ident,returnType,argTypes,arguments)}};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647;}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2;}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647;}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023;}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var AsciiToString=ptr=>{var str="";while(1){var ch=HEAPU8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch);}};var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit);}return str};var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023);}else {str+=String.fromCharCode(utf32);}}return str};function intArrayToString(array){var ret=[];for(var i=0;i255){chr&=255;}ret.push(String.fromCharCode(chr));}return ret.join("")}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this;}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev;};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return (this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode;}},write:{get:function(){return (this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode;}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();adapters_support();var wasmImports={a:___assert_fail,Y:___syscall_chmod,$:___syscall_faccessat,Z:___syscall_fchmod,X:___syscall_fchown32,b:___syscall_fcntl64,W:___syscall_fstat64,y:___syscall_ftruncate64,Q:___syscall_getcwd,U:___syscall_lstat64,N:___syscall_mkdirat,T:___syscall_newfstatat,M:___syscall_openat,K:___syscall_readlinkat,J:___syscall_rmdir,V:___syscall_stat64,G:___syscall_unlinkat,F:___syscall_utimensat,w:__localtime_js,u:__mmap_js,v:__munmap_js,H:__tzset_js,n:_emscripten_date_now,m:_emscripten_get_now,D:_emscripten_resize_heap,O:_environ_get,P:_environ_sizes_get,o:_fd_close,E:_fd_fdstat_get,L:_fd_read,x:_fd_seek,S:_fd_sync,I:_fd_write,s:_ipp,t:_ipp_async,fa:_ippipppp,ia:_ippipppp_async,i:_ippp,j:_ippp_async,c:_ipppi,d:_ipppi_async,ca:_ipppiii,da:_ipppiii_async,ea:_ipppiiip,ga:_ipppiiip_async,g:_ipppip,h:_ipppip_async,z:_ipppj,A:_ipppj_async,e:_ipppp,f:_ipppp_async,aa:_ippppi,ba:_ippppi_async,B:_ippppij,C:_ippppij_async,p:_ippppip,q:_ippppip_async,ha:_ipppppip,r:_ipppppip_async,k:_vppp,l:_vppp_async,R:_vpppip,_:_vpppip_async};var wasmExports=createWasm();Module["_sqlite3_status64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_status64"]=wasmExports["la"])(a0,a1,a2,a3);Module["_sqlite3_status"]=(a0,a1,a2,a3)=>(Module["_sqlite3_status"]=wasmExports["ma"])(a0,a1,a2,a3);Module["_sqlite3_db_status"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_db_status"]=wasmExports["na"])(a0,a1,a2,a3,a4);Module["_sqlite3_msize"]=a0=>(Module["_sqlite3_msize"]=wasmExports["oa"])(a0);Module["_sqlite3_vfs_find"]=a0=>(Module["_sqlite3_vfs_find"]=wasmExports["pa"])(a0);Module["_sqlite3_vfs_register"]=(a0,a1)=>(Module["_sqlite3_vfs_register"]=wasmExports["qa"])(a0,a1);Module["_sqlite3_vfs_unregister"]=a0=>(Module["_sqlite3_vfs_unregister"]=wasmExports["ra"])(a0);Module["_sqlite3_release_memory"]=a0=>(Module["_sqlite3_release_memory"]=wasmExports["sa"])(a0);Module["_sqlite3_soft_heap_limit64"]=(a0,a1)=>(Module["_sqlite3_soft_heap_limit64"]=wasmExports["ta"])(a0,a1);Module["_sqlite3_memory_used"]=()=>(Module["_sqlite3_memory_used"]=wasmExports["ua"])();Module["_sqlite3_hard_heap_limit64"]=(a0,a1)=>(Module["_sqlite3_hard_heap_limit64"]=wasmExports["va"])(a0,a1);Module["_sqlite3_memory_highwater"]=a0=>(Module["_sqlite3_memory_highwater"]=wasmExports["wa"])(a0);Module["_sqlite3_malloc"]=a0=>(Module["_sqlite3_malloc"]=wasmExports["xa"])(a0);Module["_sqlite3_malloc64"]=(a0,a1)=>(Module["_sqlite3_malloc64"]=wasmExports["ya"])(a0,a1);Module["_sqlite3_free"]=a0=>(Module["_sqlite3_free"]=wasmExports["za"])(a0);Module["_sqlite3_realloc"]=(a0,a1)=>(Module["_sqlite3_realloc"]=wasmExports["Aa"])(a0,a1);Module["_sqlite3_realloc64"]=(a0,a1,a2)=>(Module["_sqlite3_realloc64"]=wasmExports["Ba"])(a0,a1,a2);Module["_sqlite3_str_vappendf"]=(a0,a1,a2)=>(Module["_sqlite3_str_vappendf"]=wasmExports["Ca"])(a0,a1,a2);Module["_sqlite3_str_append"]=(a0,a1,a2)=>(Module["_sqlite3_str_append"]=wasmExports["Da"])(a0,a1,a2);Module["_sqlite3_str_appendchar"]=(a0,a1,a2)=>(Module["_sqlite3_str_appendchar"]=wasmExports["Ea"])(a0,a1,a2);Module["_sqlite3_str_appendall"]=(a0,a1)=>(Module["_sqlite3_str_appendall"]=wasmExports["Fa"])(a0,a1);Module["_sqlite3_str_appendf"]=(a0,a1,a2)=>(Module["_sqlite3_str_appendf"]=wasmExports["Ga"])(a0,a1,a2);Module["_sqlite3_str_finish"]=a0=>(Module["_sqlite3_str_finish"]=wasmExports["Ha"])(a0);Module["_sqlite3_str_errcode"]=a0=>(Module["_sqlite3_str_errcode"]=wasmExports["Ia"])(a0);Module["_sqlite3_str_length"]=a0=>(Module["_sqlite3_str_length"]=wasmExports["Ja"])(a0);Module["_sqlite3_str_value"]=a0=>(Module["_sqlite3_str_value"]=wasmExports["Ka"])(a0);Module["_sqlite3_str_reset"]=a0=>(Module["_sqlite3_str_reset"]=wasmExports["La"])(a0);Module["_sqlite3_str_new"]=a0=>(Module["_sqlite3_str_new"]=wasmExports["Ma"])(a0);Module["_sqlite3_vmprintf"]=(a0,a1)=>(Module["_sqlite3_vmprintf"]=wasmExports["Na"])(a0,a1);Module["_sqlite3_mprintf"]=(a0,a1)=>(Module["_sqlite3_mprintf"]=wasmExports["Oa"])(a0,a1);Module["_sqlite3_vsnprintf"]=(a0,a1,a2,a3)=>(Module["_sqlite3_vsnprintf"]=wasmExports["Pa"])(a0,a1,a2,a3);Module["_sqlite3_snprintf"]=(a0,a1,a2,a3)=>(Module["_sqlite3_snprintf"]=wasmExports["Qa"])(a0,a1,a2,a3);Module["_sqlite3_log"]=(a0,a1,a2)=>(Module["_sqlite3_log"]=wasmExports["Ra"])(a0,a1,a2);Module["_sqlite3_randomness"]=(a0,a1)=>(Module["_sqlite3_randomness"]=wasmExports["Sa"])(a0,a1);Module["_sqlite3_stricmp"]=(a0,a1)=>(Module["_sqlite3_stricmp"]=wasmExports["Ta"])(a0,a1);Module["_sqlite3_strnicmp"]=(a0,a1,a2)=>(Module["_sqlite3_strnicmp"]=wasmExports["Ua"])(a0,a1,a2);Module["_sqlite3_os_init"]=()=>(Module["_sqlite3_os_init"]=wasmExports["Va"])();Module["_sqlite3_os_end"]=()=>(Module["_sqlite3_os_end"]=wasmExports["Wa"])();Module["_sqlite3_serialize"]=(a0,a1,a2,a3)=>(Module["_sqlite3_serialize"]=wasmExports["Xa"])(a0,a1,a2,a3);Module["_sqlite3_prepare_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare_v2"]=wasmExports["Ya"])(a0,a1,a2,a3,a4);Module["_sqlite3_step"]=a0=>(Module["_sqlite3_step"]=wasmExports["Za"])(a0);Module["_sqlite3_column_int64"]=(a0,a1)=>(Module["_sqlite3_column_int64"]=wasmExports["_a"])(a0,a1);Module["_sqlite3_reset"]=a0=>(Module["_sqlite3_reset"]=wasmExports["$a"])(a0);Module["_sqlite3_exec"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_exec"]=wasmExports["ab"])(a0,a1,a2,a3,a4);Module["_sqlite3_column_int"]=(a0,a1)=>(Module["_sqlite3_column_int"]=wasmExports["bb"])(a0,a1);Module["_sqlite3_finalize"]=a0=>(Module["_sqlite3_finalize"]=wasmExports["cb"])(a0);Module["_sqlite3_deserialize"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_deserialize"]=wasmExports["db"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_database_file_object"]=a0=>(Module["_sqlite3_database_file_object"]=wasmExports["eb"])(a0);Module["_sqlite3_backup_init"]=(a0,a1,a2,a3)=>(Module["_sqlite3_backup_init"]=wasmExports["fb"])(a0,a1,a2,a3);Module["_sqlite3_backup_step"]=(a0,a1)=>(Module["_sqlite3_backup_step"]=wasmExports["gb"])(a0,a1);Module["_sqlite3_backup_finish"]=a0=>(Module["_sqlite3_backup_finish"]=wasmExports["hb"])(a0);Module["_sqlite3_backup_remaining"]=a0=>(Module["_sqlite3_backup_remaining"]=wasmExports["ib"])(a0);Module["_sqlite3_backup_pagecount"]=a0=>(Module["_sqlite3_backup_pagecount"]=wasmExports["jb"])(a0);Module["_sqlite3_clear_bindings"]=a0=>(Module["_sqlite3_clear_bindings"]=wasmExports["kb"])(a0);Module["_sqlite3_value_blob"]=a0=>(Module["_sqlite3_value_blob"]=wasmExports["lb"])(a0);Module["_sqlite3_value_text"]=a0=>(Module["_sqlite3_value_text"]=wasmExports["mb"])(a0);Module["_sqlite3_value_bytes"]=a0=>(Module["_sqlite3_value_bytes"]=wasmExports["nb"])(a0);Module["_sqlite3_value_bytes16"]=a0=>(Module["_sqlite3_value_bytes16"]=wasmExports["ob"])(a0);Module["_sqlite3_value_double"]=a0=>(Module["_sqlite3_value_double"]=wasmExports["pb"])(a0);Module["_sqlite3_value_int"]=a0=>(Module["_sqlite3_value_int"]=wasmExports["qb"])(a0);Module["_sqlite3_value_int64"]=a0=>(Module["_sqlite3_value_int64"]=wasmExports["rb"])(a0);Module["_sqlite3_value_subtype"]=a0=>(Module["_sqlite3_value_subtype"]=wasmExports["sb"])(a0);Module["_sqlite3_value_pointer"]=(a0,a1)=>(Module["_sqlite3_value_pointer"]=wasmExports["tb"])(a0,a1);Module["_sqlite3_value_text16"]=a0=>(Module["_sqlite3_value_text16"]=wasmExports["ub"])(a0);Module["_sqlite3_value_text16be"]=a0=>(Module["_sqlite3_value_text16be"]=wasmExports["vb"])(a0);Module["_sqlite3_value_text16le"]=a0=>(Module["_sqlite3_value_text16le"]=wasmExports["wb"])(a0);Module["_sqlite3_value_type"]=a0=>(Module["_sqlite3_value_type"]=wasmExports["xb"])(a0);Module["_sqlite3_value_encoding"]=a0=>(Module["_sqlite3_value_encoding"]=wasmExports["yb"])(a0);Module["_sqlite3_value_nochange"]=a0=>(Module["_sqlite3_value_nochange"]=wasmExports["zb"])(a0);Module["_sqlite3_value_frombind"]=a0=>(Module["_sqlite3_value_frombind"]=wasmExports["Ab"])(a0);Module["_sqlite3_value_dup"]=a0=>(Module["_sqlite3_value_dup"]=wasmExports["Bb"])(a0);Module["_sqlite3_value_free"]=a0=>(Module["_sqlite3_value_free"]=wasmExports["Cb"])(a0);Module["_sqlite3_result_blob"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_blob"]=wasmExports["Db"])(a0,a1,a2,a3);Module["_sqlite3_result_blob64"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_result_blob64"]=wasmExports["Eb"])(a0,a1,a2,a3,a4);Module["_sqlite3_result_double"]=(a0,a1)=>(Module["_sqlite3_result_double"]=wasmExports["Fb"])(a0,a1);Module["_sqlite3_result_error"]=(a0,a1,a2)=>(Module["_sqlite3_result_error"]=wasmExports["Gb"])(a0,a1,a2);Module["_sqlite3_result_error16"]=(a0,a1,a2)=>(Module["_sqlite3_result_error16"]=wasmExports["Hb"])(a0,a1,a2);Module["_sqlite3_result_int"]=(a0,a1)=>(Module["_sqlite3_result_int"]=wasmExports["Ib"])(a0,a1);Module["_sqlite3_result_int64"]=(a0,a1,a2)=>(Module["_sqlite3_result_int64"]=wasmExports["Jb"])(a0,a1,a2);Module["_sqlite3_result_null"]=a0=>(Module["_sqlite3_result_null"]=wasmExports["Kb"])(a0);Module["_sqlite3_result_pointer"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_pointer"]=wasmExports["Lb"])(a0,a1,a2,a3);Module["_sqlite3_result_subtype"]=(a0,a1)=>(Module["_sqlite3_result_subtype"]=wasmExports["Mb"])(a0,a1);Module["_sqlite3_result_text"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text"]=wasmExports["Nb"])(a0,a1,a2,a3);Module["_sqlite3_result_text64"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_result_text64"]=wasmExports["Ob"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_result_text16"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16"]=wasmExports["Pb"])(a0,a1,a2,a3);Module["_sqlite3_result_text16be"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16be"]=wasmExports["Qb"])(a0,a1,a2,a3);Module["_sqlite3_result_text16le"]=(a0,a1,a2,a3)=>(Module["_sqlite3_result_text16le"]=wasmExports["Rb"])(a0,a1,a2,a3);Module["_sqlite3_result_value"]=(a0,a1)=>(Module["_sqlite3_result_value"]=wasmExports["Sb"])(a0,a1);Module["_sqlite3_result_error_toobig"]=a0=>(Module["_sqlite3_result_error_toobig"]=wasmExports["Tb"])(a0);Module["_sqlite3_result_zeroblob"]=(a0,a1)=>(Module["_sqlite3_result_zeroblob"]=wasmExports["Ub"])(a0,a1);Module["_sqlite3_result_zeroblob64"]=(a0,a1,a2)=>(Module["_sqlite3_result_zeroblob64"]=wasmExports["Vb"])(a0,a1,a2);Module["_sqlite3_result_error_code"]=(a0,a1)=>(Module["_sqlite3_result_error_code"]=wasmExports["Wb"])(a0,a1);Module["_sqlite3_result_error_nomem"]=a0=>(Module["_sqlite3_result_error_nomem"]=wasmExports["Xb"])(a0);Module["_sqlite3_user_data"]=a0=>(Module["_sqlite3_user_data"]=wasmExports["Yb"])(a0);Module["_sqlite3_context_db_handle"]=a0=>(Module["_sqlite3_context_db_handle"]=wasmExports["Zb"])(a0);Module["_sqlite3_vtab_nochange"]=a0=>(Module["_sqlite3_vtab_nochange"]=wasmExports["_b"])(a0);Module["_sqlite3_vtab_in_first"]=(a0,a1)=>(Module["_sqlite3_vtab_in_first"]=wasmExports["$b"])(a0,a1);Module["_sqlite3_vtab_in_next"]=(a0,a1)=>(Module["_sqlite3_vtab_in_next"]=wasmExports["ac"])(a0,a1);Module["_sqlite3_aggregate_context"]=(a0,a1)=>(Module["_sqlite3_aggregate_context"]=wasmExports["bc"])(a0,a1);Module["_sqlite3_get_auxdata"]=(a0,a1)=>(Module["_sqlite3_get_auxdata"]=wasmExports["cc"])(a0,a1);Module["_sqlite3_set_auxdata"]=(a0,a1,a2,a3)=>(Module["_sqlite3_set_auxdata"]=wasmExports["dc"])(a0,a1,a2,a3);Module["_sqlite3_column_count"]=a0=>(Module["_sqlite3_column_count"]=wasmExports["ec"])(a0);Module["_sqlite3_data_count"]=a0=>(Module["_sqlite3_data_count"]=wasmExports["fc"])(a0);Module["_sqlite3_column_blob"]=(a0,a1)=>(Module["_sqlite3_column_blob"]=wasmExports["gc"])(a0,a1);Module["_sqlite3_column_bytes"]=(a0,a1)=>(Module["_sqlite3_column_bytes"]=wasmExports["hc"])(a0,a1);Module["_sqlite3_column_bytes16"]=(a0,a1)=>(Module["_sqlite3_column_bytes16"]=wasmExports["ic"])(a0,a1);Module["_sqlite3_column_double"]=(a0,a1)=>(Module["_sqlite3_column_double"]=wasmExports["jc"])(a0,a1);Module["_sqlite3_column_text"]=(a0,a1)=>(Module["_sqlite3_column_text"]=wasmExports["kc"])(a0,a1);Module["_sqlite3_column_value"]=(a0,a1)=>(Module["_sqlite3_column_value"]=wasmExports["lc"])(a0,a1);Module["_sqlite3_column_text16"]=(a0,a1)=>(Module["_sqlite3_column_text16"]=wasmExports["mc"])(a0,a1);Module["_sqlite3_column_type"]=(a0,a1)=>(Module["_sqlite3_column_type"]=wasmExports["nc"])(a0,a1);Module["_sqlite3_column_name"]=(a0,a1)=>(Module["_sqlite3_column_name"]=wasmExports["oc"])(a0,a1);Module["_sqlite3_column_name16"]=(a0,a1)=>(Module["_sqlite3_column_name16"]=wasmExports["pc"])(a0,a1);Module["_sqlite3_bind_blob"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_blob"]=wasmExports["qc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_blob64"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_bind_blob64"]=wasmExports["rc"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_bind_double"]=(a0,a1,a2)=>(Module["_sqlite3_bind_double"]=wasmExports["sc"])(a0,a1,a2);Module["_sqlite3_bind_int"]=(a0,a1,a2)=>(Module["_sqlite3_bind_int"]=wasmExports["tc"])(a0,a1,a2);Module["_sqlite3_bind_int64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_bind_int64"]=wasmExports["uc"])(a0,a1,a2,a3);Module["_sqlite3_bind_null"]=(a0,a1)=>(Module["_sqlite3_bind_null"]=wasmExports["vc"])(a0,a1);Module["_sqlite3_bind_pointer"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_pointer"]=wasmExports["wc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_text"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_text"]=wasmExports["xc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_text64"]=(a0,a1,a2,a3,a4,a5,a6)=>(Module["_sqlite3_bind_text64"]=wasmExports["yc"])(a0,a1,a2,a3,a4,a5,a6);Module["_sqlite3_bind_text16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_bind_text16"]=wasmExports["zc"])(a0,a1,a2,a3,a4);Module["_sqlite3_bind_value"]=(a0,a1,a2)=>(Module["_sqlite3_bind_value"]=wasmExports["Ac"])(a0,a1,a2);Module["_sqlite3_bind_zeroblob"]=(a0,a1,a2)=>(Module["_sqlite3_bind_zeroblob"]=wasmExports["Bc"])(a0,a1,a2);Module["_sqlite3_bind_zeroblob64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_bind_zeroblob64"]=wasmExports["Cc"])(a0,a1,a2,a3);Module["_sqlite3_bind_parameter_count"]=a0=>(Module["_sqlite3_bind_parameter_count"]=wasmExports["Dc"])(a0);Module["_sqlite3_bind_parameter_name"]=(a0,a1)=>(Module["_sqlite3_bind_parameter_name"]=wasmExports["Ec"])(a0,a1);Module["_sqlite3_bind_parameter_index"]=(a0,a1)=>(Module["_sqlite3_bind_parameter_index"]=wasmExports["Fc"])(a0,a1);Module["_sqlite3_db_handle"]=a0=>(Module["_sqlite3_db_handle"]=wasmExports["Gc"])(a0);Module["_sqlite3_stmt_readonly"]=a0=>(Module["_sqlite3_stmt_readonly"]=wasmExports["Hc"])(a0);Module["_sqlite3_stmt_isexplain"]=a0=>(Module["_sqlite3_stmt_isexplain"]=wasmExports["Ic"])(a0);Module["_sqlite3_stmt_explain"]=(a0,a1)=>(Module["_sqlite3_stmt_explain"]=wasmExports["Jc"])(a0,a1);Module["_sqlite3_stmt_busy"]=a0=>(Module["_sqlite3_stmt_busy"]=wasmExports["Kc"])(a0);Module["_sqlite3_next_stmt"]=(a0,a1)=>(Module["_sqlite3_next_stmt"]=wasmExports["Lc"])(a0,a1);Module["_sqlite3_stmt_status"]=(a0,a1,a2)=>(Module["_sqlite3_stmt_status"]=wasmExports["Mc"])(a0,a1,a2);Module["_sqlite3_sql"]=a0=>(Module["_sqlite3_sql"]=wasmExports["Nc"])(a0);Module["_sqlite3_expanded_sql"]=a0=>(Module["_sqlite3_expanded_sql"]=wasmExports["Oc"])(a0);Module["_sqlite3_value_numeric_type"]=a0=>(Module["_sqlite3_value_numeric_type"]=wasmExports["Pc"])(a0);Module["_sqlite3_blob_open"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_blob_open"]=wasmExports["Qc"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_blob_close"]=a0=>(Module["_sqlite3_blob_close"]=wasmExports["Rc"])(a0);Module["_sqlite3_blob_read"]=(a0,a1,a2,a3)=>(Module["_sqlite3_blob_read"]=wasmExports["Sc"])(a0,a1,a2,a3);Module["_sqlite3_blob_write"]=(a0,a1,a2,a3)=>(Module["_sqlite3_blob_write"]=wasmExports["Tc"])(a0,a1,a2,a3);Module["_sqlite3_blob_bytes"]=a0=>(Module["_sqlite3_blob_bytes"]=wasmExports["Uc"])(a0);Module["_sqlite3_blob_reopen"]=(a0,a1,a2)=>(Module["_sqlite3_blob_reopen"]=wasmExports["Vc"])(a0,a1,a2);Module["_sqlite3_set_authorizer"]=(a0,a1,a2)=>(Module["_sqlite3_set_authorizer"]=wasmExports["Wc"])(a0,a1,a2);Module["_sqlite3_strglob"]=(a0,a1)=>(Module["_sqlite3_strglob"]=wasmExports["Xc"])(a0,a1);Module["_sqlite3_strlike"]=(a0,a1,a2)=>(Module["_sqlite3_strlike"]=wasmExports["Yc"])(a0,a1,a2);Module["_sqlite3_errmsg"]=a0=>(Module["_sqlite3_errmsg"]=wasmExports["Zc"])(a0);Module["_sqlite3_auto_extension"]=a0=>(Module["_sqlite3_auto_extension"]=wasmExports["_c"])(a0);Module["_sqlite3_cancel_auto_extension"]=a0=>(Module["_sqlite3_cancel_auto_extension"]=wasmExports["$c"])(a0);Module["_sqlite3_reset_auto_extension"]=()=>(Module["_sqlite3_reset_auto_extension"]=wasmExports["ad"])();Module["_sqlite3_prepare"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare"]=wasmExports["bd"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare_v3"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_prepare_v3"]=wasmExports["cd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_prepare16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare16"]=wasmExports["dd"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare16_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_prepare16_v2"]=wasmExports["ed"])(a0,a1,a2,a3,a4);Module["_sqlite3_prepare16_v3"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_prepare16_v3"]=wasmExports["fd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_get_table"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_get_table"]=wasmExports["gd"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_free_table"]=a0=>(Module["_sqlite3_free_table"]=wasmExports["hd"])(a0);Module["_sqlite3_create_module"]=(a0,a1,a2,a3)=>(Module["_sqlite3_create_module"]=wasmExports["id"])(a0,a1,a2,a3);Module["_sqlite3_create_module_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_module_v2"]=wasmExports["jd"])(a0,a1,a2,a3,a4);Module["_sqlite3_drop_modules"]=(a0,a1)=>(Module["_sqlite3_drop_modules"]=wasmExports["kd"])(a0,a1);Module["_sqlite3_declare_vtab"]=(a0,a1)=>(Module["_sqlite3_declare_vtab"]=wasmExports["ld"])(a0,a1);Module["_sqlite3_vtab_on_conflict"]=a0=>(Module["_sqlite3_vtab_on_conflict"]=wasmExports["md"])(a0);Module["_sqlite3_vtab_config"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_config"]=wasmExports["nd"])(a0,a1,a2);Module["_sqlite3_vtab_collation"]=(a0,a1)=>(Module["_sqlite3_vtab_collation"]=wasmExports["od"])(a0,a1);Module["_sqlite3_vtab_in"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_in"]=wasmExports["pd"])(a0,a1,a2);Module["_sqlite3_vtab_rhs_value"]=(a0,a1,a2)=>(Module["_sqlite3_vtab_rhs_value"]=wasmExports["qd"])(a0,a1,a2);Module["_sqlite3_vtab_distinct"]=a0=>(Module["_sqlite3_vtab_distinct"]=wasmExports["rd"])(a0);Module["_sqlite3_keyword_name"]=(a0,a1,a2)=>(Module["_sqlite3_keyword_name"]=wasmExports["sd"])(a0,a1,a2);Module["_sqlite3_keyword_count"]=()=>(Module["_sqlite3_keyword_count"]=wasmExports["td"])();Module["_sqlite3_keyword_check"]=(a0,a1)=>(Module["_sqlite3_keyword_check"]=wasmExports["ud"])(a0,a1);Module["_sqlite3_complete"]=a0=>(Module["_sqlite3_complete"]=wasmExports["vd"])(a0);Module["_sqlite3_complete16"]=a0=>(Module["_sqlite3_complete16"]=wasmExports["wd"])(a0);Module["_sqlite3_libversion"]=()=>(Module["_sqlite3_libversion"]=wasmExports["xd"])();Module["_sqlite3_libversion_number"]=()=>(Module["_sqlite3_libversion_number"]=wasmExports["yd"])();Module["_sqlite3_threadsafe"]=()=>(Module["_sqlite3_threadsafe"]=wasmExports["zd"])();Module["_sqlite3_initialize"]=()=>(Module["_sqlite3_initialize"]=wasmExports["Ad"])();Module["_sqlite3_shutdown"]=()=>(Module["_sqlite3_shutdown"]=wasmExports["Bd"])();Module["_sqlite3_config"]=(a0,a1)=>(Module["_sqlite3_config"]=wasmExports["Cd"])(a0,a1);Module["_sqlite3_db_mutex"]=a0=>(Module["_sqlite3_db_mutex"]=wasmExports["Dd"])(a0);Module["_sqlite3_db_release_memory"]=a0=>(Module["_sqlite3_db_release_memory"]=wasmExports["Ed"])(a0);Module["_sqlite3_db_cacheflush"]=a0=>(Module["_sqlite3_db_cacheflush"]=wasmExports["Fd"])(a0);Module["_sqlite3_db_config"]=(a0,a1,a2)=>(Module["_sqlite3_db_config"]=wasmExports["Gd"])(a0,a1,a2);Module["_sqlite3_last_insert_rowid"]=a0=>(Module["_sqlite3_last_insert_rowid"]=wasmExports["Hd"])(a0);Module["_sqlite3_set_last_insert_rowid"]=(a0,a1,a2)=>(Module["_sqlite3_set_last_insert_rowid"]=wasmExports["Id"])(a0,a1,a2);Module["_sqlite3_changes64"]=a0=>(Module["_sqlite3_changes64"]=wasmExports["Jd"])(a0);Module["_sqlite3_changes"]=a0=>(Module["_sqlite3_changes"]=wasmExports["Kd"])(a0);Module["_sqlite3_total_changes64"]=a0=>(Module["_sqlite3_total_changes64"]=wasmExports["Ld"])(a0);Module["_sqlite3_total_changes"]=a0=>(Module["_sqlite3_total_changes"]=wasmExports["Md"])(a0);Module["_sqlite3_txn_state"]=(a0,a1)=>(Module["_sqlite3_txn_state"]=wasmExports["Nd"])(a0,a1);Module["_sqlite3_close"]=a0=>(Module["_sqlite3_close"]=wasmExports["Od"])(a0);Module["_sqlite3_close_v2"]=a0=>(Module["_sqlite3_close_v2"]=wasmExports["Pd"])(a0);Module["_sqlite3_busy_handler"]=(a0,a1,a2)=>(Module["_sqlite3_busy_handler"]=wasmExports["Qd"])(a0,a1,a2);Module["_sqlite3_progress_handler"]=(a0,a1,a2,a3)=>(Module["_sqlite3_progress_handler"]=wasmExports["Rd"])(a0,a1,a2,a3);Module["_sqlite3_busy_timeout"]=(a0,a1)=>(Module["_sqlite3_busy_timeout"]=wasmExports["Sd"])(a0,a1);Module["_sqlite3_interrupt"]=a0=>(Module["_sqlite3_interrupt"]=wasmExports["Td"])(a0);Module["_sqlite3_is_interrupted"]=a0=>(Module["_sqlite3_is_interrupted"]=wasmExports["Ud"])(a0);Module["_sqlite3_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_create_function"]=wasmExports["Vd"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_create_function_v2"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(Module["_sqlite3_create_function_v2"]=wasmExports["Wd"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);Module["_sqlite3_create_window_function"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(Module["_sqlite3_create_window_function"]=wasmExports["Xd"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);Module["_sqlite3_create_function16"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_sqlite3_create_function16"]=wasmExports["Yd"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_sqlite3_overload_function"]=(a0,a1,a2)=>(Module["_sqlite3_overload_function"]=wasmExports["Zd"])(a0,a1,a2);Module["_sqlite3_trace_v2"]=(a0,a1,a2,a3)=>(Module["_sqlite3_trace_v2"]=wasmExports["_d"])(a0,a1,a2,a3);Module["_sqlite3_commit_hook"]=(a0,a1,a2)=>(Module["_sqlite3_commit_hook"]=wasmExports["$d"])(a0,a1,a2);Module["_sqlite3_update_hook"]=(a0,a1,a2)=>(Module["_sqlite3_update_hook"]=wasmExports["ae"])(a0,a1,a2);Module["_sqlite3_rollback_hook"]=(a0,a1,a2)=>(Module["_sqlite3_rollback_hook"]=wasmExports["be"])(a0,a1,a2);Module["_sqlite3_autovacuum_pages"]=(a0,a1,a2,a3)=>(Module["_sqlite3_autovacuum_pages"]=wasmExports["ce"])(a0,a1,a2,a3);Module["_sqlite3_wal_autocheckpoint"]=(a0,a1)=>(Module["_sqlite3_wal_autocheckpoint"]=wasmExports["de"])(a0,a1);Module["_sqlite3_wal_hook"]=(a0,a1,a2)=>(Module["_sqlite3_wal_hook"]=wasmExports["ee"])(a0,a1,a2);Module["_sqlite3_wal_checkpoint_v2"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_wal_checkpoint_v2"]=wasmExports["fe"])(a0,a1,a2,a3,a4);Module["_sqlite3_wal_checkpoint"]=(a0,a1)=>(Module["_sqlite3_wal_checkpoint"]=wasmExports["ge"])(a0,a1);Module["_sqlite3_error_offset"]=a0=>(Module["_sqlite3_error_offset"]=wasmExports["he"])(a0);Module["_sqlite3_errmsg16"]=a0=>(Module["_sqlite3_errmsg16"]=wasmExports["ie"])(a0);Module["_sqlite3_errcode"]=a0=>(Module["_sqlite3_errcode"]=wasmExports["je"])(a0);Module["_sqlite3_extended_errcode"]=a0=>(Module["_sqlite3_extended_errcode"]=wasmExports["ke"])(a0);Module["_sqlite3_system_errno"]=a0=>(Module["_sqlite3_system_errno"]=wasmExports["le"])(a0);Module["_sqlite3_errstr"]=a0=>(Module["_sqlite3_errstr"]=wasmExports["me"])(a0);Module["_sqlite3_limit"]=(a0,a1,a2)=>(Module["_sqlite3_limit"]=wasmExports["ne"])(a0,a1,a2);Module["_sqlite3_open"]=(a0,a1)=>(Module["_sqlite3_open"]=wasmExports["oe"])(a0,a1);Module["_sqlite3_open_v2"]=(a0,a1,a2,a3)=>(Module["_sqlite3_open_v2"]=wasmExports["pe"])(a0,a1,a2,a3);Module["_sqlite3_open16"]=(a0,a1)=>(Module["_sqlite3_open16"]=wasmExports["qe"])(a0,a1);Module["_sqlite3_create_collation"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_collation"]=wasmExports["re"])(a0,a1,a2,a3,a4);Module["_sqlite3_create_collation_v2"]=(a0,a1,a2,a3,a4,a5)=>(Module["_sqlite3_create_collation_v2"]=wasmExports["se"])(a0,a1,a2,a3,a4,a5);Module["_sqlite3_create_collation16"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_collation16"]=wasmExports["te"])(a0,a1,a2,a3,a4);Module["_sqlite3_collation_needed"]=(a0,a1,a2)=>(Module["_sqlite3_collation_needed"]=wasmExports["ue"])(a0,a1,a2);Module["_sqlite3_collation_needed16"]=(a0,a1,a2)=>(Module["_sqlite3_collation_needed16"]=wasmExports["ve"])(a0,a1,a2);Module["_sqlite3_get_clientdata"]=(a0,a1)=>(Module["_sqlite3_get_clientdata"]=wasmExports["we"])(a0,a1);Module["_sqlite3_set_clientdata"]=(a0,a1,a2,a3)=>(Module["_sqlite3_set_clientdata"]=wasmExports["xe"])(a0,a1,a2,a3);Module["_sqlite3_get_autocommit"]=a0=>(Module["_sqlite3_get_autocommit"]=wasmExports["ye"])(a0);Module["_sqlite3_table_column_metadata"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(Module["_sqlite3_table_column_metadata"]=wasmExports["ze"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);Module["_sqlite3_sleep"]=a0=>(Module["_sqlite3_sleep"]=wasmExports["Ae"])(a0);Module["_sqlite3_extended_result_codes"]=(a0,a1)=>(Module["_sqlite3_extended_result_codes"]=wasmExports["Be"])(a0,a1);Module["_sqlite3_file_control"]=(a0,a1,a2,a3)=>(Module["_sqlite3_file_control"]=wasmExports["Ce"])(a0,a1,a2,a3);Module["_sqlite3_test_control"]=(a0,a1)=>(Module["_sqlite3_test_control"]=wasmExports["De"])(a0,a1);Module["_sqlite3_create_filename"]=(a0,a1,a2,a3,a4)=>(Module["_sqlite3_create_filename"]=wasmExports["Ee"])(a0,a1,a2,a3,a4);Module["_sqlite3_free_filename"]=a0=>(Module["_sqlite3_free_filename"]=wasmExports["Fe"])(a0);Module["_sqlite3_uri_parameter"]=(a0,a1)=>(Module["_sqlite3_uri_parameter"]=wasmExports["Ge"])(a0,a1);Module["_sqlite3_uri_key"]=(a0,a1)=>(Module["_sqlite3_uri_key"]=wasmExports["He"])(a0,a1);Module["_sqlite3_uri_boolean"]=(a0,a1,a2)=>(Module["_sqlite3_uri_boolean"]=wasmExports["Ie"])(a0,a1,a2);Module["_sqlite3_uri_int64"]=(a0,a1,a2,a3)=>(Module["_sqlite3_uri_int64"]=wasmExports["Je"])(a0,a1,a2,a3);Module["_sqlite3_filename_database"]=a0=>(Module["_sqlite3_filename_database"]=wasmExports["Ke"])(a0);Module["_sqlite3_filename_journal"]=a0=>(Module["_sqlite3_filename_journal"]=wasmExports["Le"])(a0);Module["_sqlite3_filename_wal"]=a0=>(Module["_sqlite3_filename_wal"]=wasmExports["Me"])(a0);Module["_sqlite3_db_name"]=(a0,a1)=>(Module["_sqlite3_db_name"]=wasmExports["Ne"])(a0,a1);Module["_sqlite3_db_filename"]=(a0,a1)=>(Module["_sqlite3_db_filename"]=wasmExports["Oe"])(a0,a1);Module["_sqlite3_db_readonly"]=(a0,a1)=>(Module["_sqlite3_db_readonly"]=wasmExports["Pe"])(a0,a1);Module["_sqlite3_compileoption_used"]=a0=>(Module["_sqlite3_compileoption_used"]=wasmExports["Qe"])(a0);Module["_sqlite3_compileoption_get"]=a0=>(Module["_sqlite3_compileoption_get"]=wasmExports["Re"])(a0);Module["_sqlite3_sourceid"]=()=>(Module["_sqlite3_sourceid"]=wasmExports["Se"])();var ___errno_location=()=>(___errno_location=wasmExports["Te"])();var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["Ue"])(a0);Module["_free"]=a0=>(Module["_free"]=wasmExports["Ve"])(a0);Module["_RegisterExtensionFunctions"]=a0=>(Module["_RegisterExtensionFunctions"]=wasmExports["We"])(a0);Module["_getSqliteFree"]=()=>(Module["_getSqliteFree"]=wasmExports["Xe"])();var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["Ye"])(a0,a1);Module["_libauthorizer_set_authorizer"]=(a0,a1,a2)=>(Module["_libauthorizer_set_authorizer"]=wasmExports["Ze"])(a0,a1,a2);Module["_libfunction_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(Module["_libfunction_create_function"]=wasmExports["_e"])(a0,a1,a2,a3,a4,a5,a6,a7);Module["_libprogress_progress_handler"]=(a0,a1,a2,a3)=>(Module["_libprogress_progress_handler"]=wasmExports["$e"])(a0,a1,a2,a3);Module["_libvfs_vfs_register"]=(a0,a1,a2,a3,a4,a5)=>(Module["_libvfs_vfs_register"]=wasmExports["af"])(a0,a1,a2,a3,a4,a5);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["cf"])(a0,a1);var getTempRet0=()=>(getTempRet0=wasmExports["df"])();var stackSave=()=>(stackSave=wasmExports["ef"])();var stackRestore=a0=>(stackRestore=wasmExports["ff"])(a0);var stackAlloc=a0=>(stackAlloc=wasmExports["gf"])(a0);Module["_sqlite3_version"]=3232;Module["getTempRet0"]=getTempRet0;Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["addFunction"]=addFunction;Module["setValue"]=setValue;Module["getValue"]=getValue;Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;Module["intArrayFromString"]=intArrayFromString;Module["intArrayToString"]=intArrayToString;Module["AsciiToString"]=AsciiToString;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;Module["UTF32ToString"]=UTF32ToString;Module["stringToUTF32"]=stringToUTF32;Module["writeArrayToMemory"]=writeArrayToMemory;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller;};function callMain(){var entryFunction=_main;var argc=0;var argv=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain();postRun();}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("");},1);doRun();},1);}else {doRun();}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()();}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;let pAsyncFlags=0;Module["set_authorizer"]=function(db,xAuthorizer,pApp){if(pAsyncFlags){Module["deleteCallback"](pAsyncFlags);Module["_sqlite3_free"](pAsyncFlags);pAsyncFlags=0;}pAsyncFlags=Module["_sqlite3_malloc"](4);setValue(pAsyncFlags,xAuthorizer instanceof AsyncFunction?1:0,"i32");const result=ccall("libauthorizer_set_authorizer","number",["number","number","number"],[db,xAuthorizer?1:0,pAsyncFlags]);if(!result&&xAuthorizer){Module["setCallback"](pAsyncFlags,(_,iAction,p3,p4,p5,p6)=>xAuthorizer(pApp,iAction,p3,p4,p5,p6));}return result};})();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;const FUNC_METHODS=["xFunc","xStep","xFinal"];const mapFunctionNameToKey=new Map;Module["create_function"]=function(db,zFunctionName,nArg,eTextRep,pApp,xFunc,xStep,xFinal){const pAsyncFlags=Module["_sqlite3_malloc"](4);const target={xFunc:xFunc,xStep:xStep,xFinal:xFinal};setValue(pAsyncFlags,FUNC_METHODS.reduce((mask,method,i)=>{if(target[method]instanceof AsyncFunction){return mask|1<xProgress(pApp));}};})();(function(){const VFS_METHODS=["xOpen","xDelete","xAccess","xFullPathname","xRandomness","xSleep","xCurrentTime","xGetLastError","xCurrentTimeInt64","xClose","xRead","xWrite","xTruncate","xSync","xFileSize","xLock","xUnlock","xCheckReservedLock","xFileControl","xSectorSize","xDeviceCharacteristics","xShmMap","xShmLock","xShmBarrier","xShmUnmap"];const mapVFSNameToKey=new Map;Module["vfs_register"]=function(vfs,makeDefault){let methodMask=0;let asyncMask=0;VFS_METHODS.forEach((method,i)=>{if(vfs[method]){methodMask|=1< { - console.log(row); + return db.exec(query, { + callback: (row) => { + log(`exec'd ${row}`); + }, }); } catch (error) { - console.log("exec err"); throw error; } } finalize(stmt) { - try { - return this.sqlite3.finalize(stmt); - } catch (error) { - console.log("stmt error"); - throw error; - } + return this.sqlite3.capi.sqlite3_finalize(stmt); } changes(db) { - return this.sqlite3.changes(db); + return this.sqlite3.capi.sqlite3_changes(db); } clear_bindings(stmt) { - try { - return this.sqlite3.clear_bindings(stmt); - } catch (error) { - console.log("sqlite3.clear_bindings error"); - throw error; - } + return this.sqlite3.capi.sqlite3_clear_bindings(stmt); } - async close(db) { - try { - return this.sqlite3.close(db); - } catch (error) { - console.log("sqlite3.close error"); - throw error; - } + reset(stmt) { + return this.sqlite3.capi.sqlite3_reset(stmt); } - column(stmt, i) { - return this.sqlite3.column(stmt, i); + close(db) { + return this.sqlite3.capi.sqlite3_close_v2(db.pointer); } - async prepare(database, sql, options) { - try { - return await this.sqlite3.statements(database, sql, options); - } catch (error) { - console.log("sqlite prepare error"); - throw error; - } + db_handle(stmt) { + return this.sqlite3.capi.sqlite3_db_handle(stmt); } - // there should be a way to do this from Rust - // If we pass the statement we get from 'next' - // it does not work. - async get_stmt_from_iterator(iterator) { - try { - const stmt = await iterator.next(); - return stmt; - } catch (error) { - console.log("sqlite prepare error"); - throw error; - } + prepare_v3(db, sql, nByte, prepFlags, ppStmt, pzTail) { + return this.sqlite3.capi.sqlite3_prepare_v3( + db.pointer, + sql, + nByte, + prepFlags, + ppStmt, + pzTail, + ); } - async step(stmt) { - try { - return await this.sqlite3.step(stmt); - } catch (error) { - console.log("sqlite step error"); - throw error; + into_statement(pStmt) { + const BindTypes = { + null: 1, + number: 2, + string: 3, + boolean: 4, + blob: 5, + }; + BindTypes["undefined"] == BindTypes.null; + if (wasm.bigIntEnabled) { + BindTypes.bigint = BindTypes.number; } + + new Stmt(this, pStmt, BindTypes); } - column_name(stmt, idx) { - return this.sqlite3.column_name(stmt, idx); + step(stmt) { + return this.sqlite3.capi.sqlite3_step(stmt); } - column_count(stmt) { - return this.sqlite3.column_count(stmt); + column_value(stmt, i) { + return this.sqlite3.capi.sqlite3_column_value(stmt, i); } - async batch_execute(database, query) { - try { - return await this.sqlite3.exec(database, query); - } catch (error) { - console.log("batch exec err"); - throw error; - } + column_name(stmt, idx) { + return this.sqlite3.capi.sqlite3_column_name(stmt, idx); + } + + column_count(stmt) { + return this.sqlite3.capi.sqlite3_column_count(stmt); } create_function( @@ -3046,7 +14653,7 @@ class SQLite { xFinal, ) { try { - this.sqlite3.create_function( + this.sqlite3.capi.sqlite3_create_function( database, functionName, nArg, @@ -3062,20 +14669,21 @@ class SQLite { throw error; } } + //TODO: At some point need a way to register functions from rust //but for just libxmtp this is fine. register_diesel_sql_functions(database) { try { - this.sqlite3.create_function( + this.sqlite3.capi.sqlite3_create_function( database, "diesel_manage_updated_at", 1, - SQLITE_UTF8, + this.sqlite3.capi.SQLITE_UTF8, 0, async (context, values) => { const table_name = this.sqlite3.value_text(values[0]); - await this.sqlite3.exec( + database.exec( context, `CREATE TRIGGER __diesel_manage_updated_at_${table_name} AFTER UPDATE ON ${table_name} @@ -3088,12 +14696,11 @@ class SQLite { SET updated_at = CURRENT_TIMESTAMP WHERE ROWID = new.ROWID; END`, - (row, columns) => { - console.log(`------------------------------------`); - console.log(`Created trigger for ${table_name}`); - console.log(row); - console.log(columns); - console.log(`------------------------------------`); + (row) => { + log(`------------------------------------`); + log(`Created trigger for ${table_name}`); + log(row); + log(`------------------------------------`); }, ); }, @@ -3104,6 +14711,10 @@ class SQLite { } } + value_free(value) { + return this.sqlite3.capi.sqlite3_value_free(value); + } + /* serialize(database, zSchema, size, flags) { return this.module._sqlite3_serialize(database, zSchema, size, flags); @@ -3111,4 +14722,4 @@ class SQLite { */ } -export { SQLite }; +export { SQLite, SQLiteError }; diff --git a/diesel-wasm-sqlite/tests/row.rs b/diesel-wasm-sqlite/tests/row.rs new file mode 100644 index 000000000..429f819aa --- /dev/null +++ b/diesel-wasm-sqlite/tests/row.rs @@ -0,0 +1,210 @@ +use diesel::Connection; +use diesel_wasm_sqlite::{connection::WasmSqliteConnection, test_common::connection, WasmSqlite}; +use wasm_bindgen_test::*; +wasm_bindgen_test_configure!(run_in_dedicated_worker); + +// test copied from diesel +#[wasm_bindgen_test] +async fn fun_with_row_iters() { + diesel_wasm_sqlite::init_sqlite().await; + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + + diesel::table! { + #[allow(unused_parens)] + users(id) { + id -> Integer, + name -> Text, + } + } + + use diesel::connection::LoadConnection; + use diesel::deserialize::{FromSql, FromSqlRow}; + use diesel::prelude::*; + use diesel::row::{Field, Row}; + use diesel::sql_types; + + let conn: &mut WasmSqliteConnection = &mut connection().await; + + diesel::sql_query("CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);") + .execute(conn) + .unwrap(); + + diesel::insert_into(users::table) + .values(vec![ + (users::id.eq(1), users::name.eq("Sean")), + (users::id.eq(2), users::name.eq("Tess")), + ]) + .execute(conn) + .unwrap(); + + let query = users::table.select((users::id, users::name)); + + let expected = vec![(1, String::from("Sean")), (2, String::from("Tess"))]; + let row_iter = conn.load(query).unwrap(); + for (row, expected) in row_iter.zip(&expected) { + let row = row.expect("Unwrap failed"); + + let deserialized = <(i32, String) as FromSqlRow< + (sql_types::Integer, sql_types::Text), + _, + >>::build_from_row(&row) + .unwrap(); + + assert_eq!(&deserialized, expected); + } + + { + let collected_rows = conn.load(query).unwrap().collect::>(); + + for (row, expected) in collected_rows.iter().zip(&expected) { + let deserialized = row + .as_ref() + .map(|row| { + <(i32, String) as FromSqlRow< + (sql_types::Integer, sql_types::Text), + _, + >>::build_from_row(row).unwrap() + }) + .unwrap(); + + assert_eq!(&deserialized, expected); + } + } + + let mut row_iter = conn.load(query).unwrap(); + + let first_row = row_iter.next().unwrap().unwrap(); + let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); + let first_values = (first_fields.0.value(), first_fields.1.value()); + + assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(first_values); + assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(first_fields); + + let second_row = row_iter.next().unwrap().unwrap(); + let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap()); + let second_values = (second_fields.0.value(), second_fields.1.value()); + + assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(second_values); + assert!(row_iter.next().unwrap().is_err()); + std::mem::drop(second_fields); + + assert!(row_iter.next().is_none()); + + let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); + let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap()); + + let first_values = (first_fields.0.value(), first_fields.1.value()); + let second_values = (second_fields.0.value(), second_fields.1.value()); + + assert_eq!( + >::from_nullable_sql(first_values.0) + .unwrap(), + expected[0].0 + ); + assert_eq!( + >::from_nullable_sql(first_values.1) + .unwrap(), + expected[0].1 + ); + + assert_eq!( + >::from_nullable_sql(second_values.0) + .unwrap(), + expected[1].0 + ); + assert_eq!( + >::from_nullable_sql(second_values.1) + .unwrap(), + expected[1].1 + ); + + let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); + let first_values = (first_fields.0.value(), first_fields.1.value()); + + assert_eq!( + >::from_nullable_sql(first_values.0) + .unwrap(), + expected[0].0 + ); + assert_eq!( + >::from_nullable_sql(first_values.1) + .unwrap(), + expected[0].1 + ); +} + +// not sure if we need to replicate parallel test for wasm +/* +crate::define_sql_function! {fn sleep(a: diesel::sql_types::Integer) -> diesel::sql_types::Integer} +#[test] +fn parallel_iter_with_error() { + use crate::WasmSqliteConnection; + use diesel::connection::Connection; + use diesel::connection::LoadConnection; + use diesel::connection::SimpleConnection; + use diesel::expression_methods::ExpressionMethods; + use std::sync::{Arc, Barrier}; + use std::time::Duration; + + let temp_dir = tempfile::tempdir().unwrap(); + let db_path = format!("{}/test.db", temp_dir.path().display()); + let mut conn1 = SqliteConnection::establish(&db_path).unwrap(); + let mut conn2 = SqliteConnection::establish(&db_path).unwrap(); + + crate::table! { + users { + id -> Integer, + name -> Text, + } + } + + conn1 + .batch_execute("CREATE TABLE users(id INTEGER NOT NULL PRIMARY KEY, name TEXT)") + .unwrap(); + + let barrier = Arc::new(Barrier::new(2)); + let barrier2 = barrier.clone(); + + // we unblock the main thread from the sleep function + sleep_utils::register_impl(&mut conn2, move |a: i32| { + barrier.wait(); + std::thread::sleep(Duration::from_secs(a as u64)); + a + }) + .unwrap(); + + // spawn a background thread that locks the database file + let handle = std::thread::spawn(move || { + use crate::query_dsl::RunQueryDsl; + + conn2 + .immediate_transaction(|conn| diesel::select(sleep(1)).execute(conn)) + .unwrap(); + }); + barrier2.wait(); + + // execute some action that also requires a lock + let mut iter = conn1 + .load( + diesel::insert_into(users::table) + .values((users::id.eq(1), users::name.eq("John"))) + .returning(users::id), + ) + .unwrap(); + + // get the first iterator result, that should return the lock error + let n = iter.next().unwrap(); + assert!(n.is_err()); + + // check that the iterator is now empty + let n = iter.next(); + assert!(n.is_none()); + + // join the background thread + handle.join().unwrap(); +} +*/ diff --git a/diesel-wasm-sqlite/tests/web.rs b/diesel-wasm-sqlite/tests/web.rs index da34cc14b..958e6e696 100755 --- a/diesel-wasm-sqlite/tests/web.rs +++ b/diesel-wasm-sqlite/tests/web.rs @@ -1,22 +1,18 @@ +//! Integration-like tests with a persistent database #![recursion_limit = "256"] #![cfg(target_arch = "wasm32")] -use diesel_async::RunQueryDsl; -use diesel_wasm_sqlite::{ - connection::{AsyncConnection, SimpleAsyncConnection, WasmSqliteConnection}, - WasmSqlite, DebugQueryWrapper -}; -use diesel_migrations::embed_migrations; -use diesel_migrations::EmbeddedMigrations; +use diesel::connection::LoadConnection; +use diesel::deserialize::FromSqlRow; +use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; +use diesel_wasm_sqlite::{connection::WasmSqliteConnection, DebugQueryWrapper, WasmSqlite}; use wasm_bindgen_test::*; use web_sys::console; -use chrono::{NaiveDate, NaiveDateTime}; use diesel::debug_query; use diesel::insert_into; use diesel::prelude::*; use serde::Deserialize; -use std::error::Error; wasm_bindgen_test_configure!(run_in_dedicated_worker); @@ -44,6 +40,7 @@ pub struct BookForm { } #[derive(Queryable, Selectable, PartialEq, Debug)] +#[diesel(table_name = books)] pub struct Book { id: i32, title: String, @@ -52,51 +49,34 @@ pub struct Book { } async fn establish_connection() -> WasmSqliteConnection { + diesel_wasm_sqlite::init_sqlite().await; + let rng: u16 = rand::random(); - let result = WasmSqliteConnection::establish(&format!("test-{}", rng)).await; + let result = WasmSqliteConnection::establish(&format!("test-{}", rng)); let mut conn = result.unwrap(); - // conn.run_pending_migrations(MIGRATIONS); - //TODO: we can use `embed_migrations` to run our migrations - - conn.batch_execute( - " - CREATE TABLE books ( - id INTEGER PRIMARY KEY, - title TEXT NOT NULL, - author TEXT - ) - ", - ) - .await - .expect("Batch exec failed to run"); + tracing::info!("running migrations..."); + conn.run_pending_migrations(MIGRATIONS).unwrap(); conn } -async fn insert_books( - conn: &mut WasmSqliteConnection, - new_books: Vec, -) -> QueryResult { +fn insert_books(conn: &mut WasmSqliteConnection, new_books: Vec) -> QueryResult { use schema::books::dsl::*; let query = insert_into(books).values(new_books); let sql = DebugQueryWrapper::<_, WasmSqlite>::new(&query).to_string(); tracing::info!("QUERY = {}", sql); - let rows_changed = query.execute(conn).await.unwrap(); + let rows_changed = query.execute(conn)?; Ok(rows_changed) } - -async fn insert_book( - conn: &mut WasmSqliteConnection, - new_book: BookForm, -) -> QueryResult { +fn insert_book(conn: &mut WasmSqliteConnection, new_book: BookForm) -> QueryResult { use schema::books::dsl::*; let query = insert_into(books).values(new_book); let sql = debug_query::(&query).to_string(); tracing::info!("QUERY = {}", sql); - let rows_changed = query.execute(conn).await.unwrap(); + let rows_changed = query.execute(conn).unwrap(); Ok(rows_changed) } - +/* #[wasm_bindgen_test] fn examine_sql_from_insert_default_values() { use schema::books::dsl::*; @@ -106,15 +86,16 @@ fn examine_sql_from_insert_default_values() { assert_eq!(sql, debug_query::(&query).to_string()); console::log_1(&debug_query::(&query).to_string().into()); } +*/ #[wasm_bindgen_test] async fn test_orm_insert() { console_error_panic_hook::set_once(); tracing_wasm::set_as_global_default(); - + let mut conn = establish_connection().await; - let changed = insert_books( + let rows_changed = insert_books( &mut conn, vec![ BookForm { @@ -149,20 +130,25 @@ async fn test_orm_insert() { }, ], ) - .await.unwrap(); + .unwrap(); assert_eq!(rows_changed, 6); - tracing::info!("{} rows changed", changed); + tracing::info!("{} rows changed", rows_changed); console::log_1(&"Showing Users".into()); - - let books = schema::books::table - .limit(5) - .select(Book::as_select()) - .load(&mut conn) - .await - .unwrap(); - tracing::info!("BOOKS??? {:?}----------", books); - - // console::log_1(&debug_query::(&query).to_string().into()); + let book = schema::books::table + .select(schema::books::title) + .load::(&mut conn); + tracing::info!("Loaded book {:?}", book); + let query = schema::books::table.limit(5).select(Book::as_select()); + let books = conn.load(query).unwrap().collect::>(); + /* + for row in books.iter() { + let deserialized_book = row.as_ref().map(|row| { + Book::build_from_row(row).unwrap() + }); + tracing::debug!("BOOK: {:?}", deserialized_book); + } + */ + // console::log_1(&debug_query::(&query).o_string().into()); // .load(&mut conn) // .await // .expect("Error loading users"); @@ -173,58 +159,3 @@ async fn test_orm_insert() { } */ } - -/* -#[wasm_bindgen_test] -async fn test_establish_and_exec() { - let rng: u16 = rand::random(); - let result = WasmSqliteConnection::establish("test-15873").await; - let mut conn = result.unwrap(); - console::log_1(&"CONNECTED".into()); - - let raw = conn.raw_connection; - - console::log_1(&"CREATE".into()); - raw.exec( - " - CREATE TABLE books ( - id INTEGER PRIMARY KEY, - title TEXT NOT NULL, - author TEXT NOT NULL, - published_year INTEGER, - genre TEXT - );", - ) - .await; - - console::log_1(&"INSERT".into()); - raw.exec( - " - INSERT INTO books (title, author, published_year, genre) VALUES - ('To Kill a Mockingbird', 'Harper Lee', 1960, 'Fiction'), - ('1984', 'George Orwell', 1949, 'Dystopian'), - ('The Great Gatsby', 'F. Scott Fitzgerald', 1925, 'Classics'), - ('Pride and Prejudice', 'Jane Austen', 1813, 'Romance'); - ", - ) - .await; - - console::log_1(&"SELECT ALL".into()); - raw.exec("SELECT * FROM books").await; - - console::log_1(&"SELECT title, author FROM books WHERE published_year > 1950;".into()); - raw.exec( - " - - SELECT title, published_year FROM books WHERE author = 'George Orwell'; - ", - ) - .await; - - console::log_1( - &"SELECT title, published_year FROM books WHERE author = 'George Orwell';".into(), - ); - raw.exec("SELECT title, author FROM books WHERE published_year > 1950;".into()) - .await; -} -*/ diff --git a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql b/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql index e6b55d875..fd3df8b20 100644 --- a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql +++ b/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql @@ -1,7 +1,5 @@ --- Your SQL goes here - CREATE TABLE books ( id SERIAL PRIMARY KEY, title TEXT NOT NULL, - author TEXT, + author TEXT ) diff --git a/diesel-wasm-sqlite/yarn.lock b/diesel-wasm-sqlite/yarn.lock index 4986db559..ad0011cfa 100644 --- a/diesel-wasm-sqlite/yarn.lock +++ b/diesel-wasm-sqlite/yarn.lock @@ -94,20 +94,26 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^3.1.0": - version: 3.1.0 - resolution: "@rollup/pluginutils@npm:3.1.0" +"@rollup/plugin-typescript@npm:^11.1.6": + version: 11.1.6 + resolution: "@rollup/plugin-typescript@npm:11.1.6" dependencies: - "@types/estree": "npm:0.0.39" - estree-walker: "npm:^1.0.1" - picomatch: "npm:^2.2.2" + "@rollup/pluginutils": "npm:^5.1.0" + resolve: "npm:^1.22.1" peerDependencies: - rollup: ^1.20.0||^2.0.0 - checksum: 10/3b69f02893eea42455fb97b81f612ac6bfadf94ac73bebd481ea13e90a693eef52c163210a095b12e574a25603af5e55f86a020889019167f331aa8dd3ff30e0 + rollup: ^2.14.0||^3.0.0||^4.0.0 + tslib: "*" + typescript: ">=3.7.0" + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + checksum: 10/4ae4d6cfc929393171288df2f18b5eb837fa53d8689118d9661b3064567341f6f6cf8389af55f1d5f015e3682abf30a64ab609fdf75ecb5a84224505e407eb69 languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.1": +"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0": version: 5.1.0 resolution: "@rollup/pluginutils@npm:5.1.0" dependencies: @@ -235,10 +241,12 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:0.0.39": - version: 0.0.39 - resolution: "@types/estree@npm:0.0.39" - checksum: 10/9f0f20990dbf725470564d4d815d3758ac688b790f601ea98654b6e0b9797dc3c80306fb525abdacd9e75e014e3d09ad326098eaa2ed1851e4823a8e278538aa +"@sqlite.org/sqlite-wasm@npm:latest": + version: 3.46.1-build1 + resolution: "@sqlite.org/sqlite-wasm@npm:3.46.1-build1" + bin: + sqlite-wasm: bin/index.js + checksum: 10/cbb6dda0570a73f6614e53a8d46714fbe4e2a935d6668fd19e6dcba23569b4e07b90bc598fddc03a45677a1b35be9415517871c274da78c0ad22f8efe2e6bf14 languageName: node linkType: hard @@ -291,18 +299,6 @@ __metadata: languageName: node linkType: hard -"@xmtp/wa-sqlite@npm:>=1.0.3": - version: 1.0.3 - resolution: "@xmtp/wa-sqlite@npm:1.0.3" - dependenciesMeta: - monaco-editor@0.34.1: - unplugged: true - web-test-runner-jasmine@0.0.6: - unplugged: true - checksum: 10/16f0a79ea4a6a39ae3c38bddf20a83d8ca990a1366800c315059c28f0c712d127c76c64144a87757648343785bd1106096d92288fa6c5b3f97a9d3c81c5e6047 - languageName: node - linkType: hard - "abbrev@npm:^2.0.0": version: 2.0.0 resolution: "abbrev@npm:2.0.0" @@ -507,9 +503,9 @@ __metadata: resolution: "diesel-wasm-sqlite@workspace:." dependencies: "@rollup/plugin-node-resolve": "npm:^15.2.3" - "@xmtp/wa-sqlite": "npm:>=1.0.3" + "@rollup/plugin-typescript": "npm:^11.1.6" + "@sqlite.org/sqlite-wasm": "npm:latest" rollup: "npm:^4.19.0" - rollup-plugin-base64: "npm:^1.0.1" rollup-plugin-copy: "npm:^3.5.0" languageName: unknown linkType: soft @@ -567,13 +563,6 @@ __metadata: languageName: node linkType: hard -"estree-walker@npm:^1.0.1": - version: 1.0.1 - resolution: "estree-walker@npm:1.0.1" - checksum: 10/1cf11a0aff7613aa765dc535ed1d83e2a1986207d2353f4795df309a2c55726de3ca4948df635c09969a739dc59e8e2d69f88d3b3d2c6dfc5701257aafd1d11b - languageName: node - linkType: hard - "estree-walker@npm:^2.0.2": version: 2.0.2 resolution: "estree-walker@npm:2.0.2" @@ -1224,7 +1213,7 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.2.2, picomatch@npm:^2.3.1": +"picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc @@ -1295,15 +1284,6 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-base64@npm:^1.0.1": - version: 1.0.1 - resolution: "rollup-plugin-base64@npm:1.0.1" - dependencies: - "@rollup/pluginutils": "npm:^3.1.0" - checksum: 10/1f4ebf46a9ec5220ba9b596820e56d6a7a1b77d567097b8713a63ef669b02b1d296d6e77f48c01e43de7c98c751b5ee5683b4b1f7e4cb4b76a4fe55109654862 - languageName: node - linkType: hard - "rollup-plugin-copy@npm:^3.5.0": version: 3.5.0 resolution: "rollup-plugin-copy@npm:3.5.0" From 44a8839d5b5f8bf05186658695ca6221ebbf34dc Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 26 Aug 2024 11:10:56 -0400 Subject: [PATCH 05/97] fix branch in readme --- diesel-wasm-sqlite/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diesel-wasm-sqlite/README.md b/diesel-wasm-sqlite/README.md index d6bd44bc0..eedd3d0de 100644 --- a/diesel-wasm-sqlite/README.md +++ b/diesel-wasm-sqlite/README.md @@ -10,7 +10,7 @@ the library. ```toml [dependencies] diesel = { version = "2.2" } -diesel-wasm-sqlite = { git = "https://github.com/xmtp/libxmtp", branch = "insipx/abandon-async" } +diesel-wasm-sqlite = { git = "https://github.com/xmtp/libxmtp", branch = "wasm-backend" } wasm-bindgen = "0.2" ``` From d43b8910f3744075200ca0099d7f46fd834f6d93 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 26 Aug 2024 16:22:56 -0400 Subject: [PATCH 06/97] Organize wasm tests (#995) * organize wasm tests so they all run * make test organization much better, fix tests * fix workflow file --- .github/workflows/release-cli.yml | 1 + .github/workflows/test-wasm.yml | 31 +++- diesel-wasm-sqlite/Cargo.lock | 11 ++ diesel-wasm-sqlite/Cargo.toml | 4 +- diesel-wasm-sqlite/build.rs | 1 + diesel-wasm-sqlite/package.js | 4 + diesel-wasm-sqlite/package.json | 2 +- diesel-wasm-sqlite/src/connection/mod.rs | 6 +- diesel-wasm-sqlite/src/connection/stmt.rs | 2 +- diesel-wasm-sqlite/src/ffi.rs | 3 + diesel-wasm-sqlite/src/lib.rs | 13 -- diesel-wasm-sqlite/src/query_builder/mod.rs | 2 +- .../src/query_builder/query_fragment_impls.rs | 11 +- diesel-wasm-sqlite/src/sqlite_fixes.rs | 169 +++++++++++++++++- .../src/wa-sqlite-diesel-bundle.js | 4 + diesel-wasm-sqlite/tests/common/mod.rs | 42 +++++ .../tests/dedicated_web_worker.rs | 17 ++ .../2024-08-20-203551_create_books/down.sql | 0 .../2024-08-20-203551_create_books/up.sql | 2 +- diesel-wasm-sqlite/tests/{ => test}/row.rs | 7 +- diesel-wasm-sqlite/tests/{ => test}/web.rs | 153 ++++++++-------- 21 files changed, 373 insertions(+), 112 deletions(-) create mode 100644 diesel-wasm-sqlite/tests/common/mod.rs create mode 100755 diesel-wasm-sqlite/tests/dedicated_web_worker.rs rename diesel-wasm-sqlite/tests/{web => }/migrations/2024-08-20-203551_create_books/down.sql (100%) rename diesel-wasm-sqlite/tests/{web => }/migrations/2024-08-20-203551_create_books/up.sql (63%) rename diesel-wasm-sqlite/tests/{ => test}/row.rs (95%) rename diesel-wasm-sqlite/tests/{ => test}/web.rs (52%) diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index d15be2764..ccf6435be 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -44,6 +44,7 @@ jobs: - name: Configure x86_64-unknown-linux-musl toolchain if: ${{ matrix.target == 'x86_64-unknown-linux-musl' }} run: | + sudo apt-get update sudo apt-get install -y musl-tools - name: Install openssl windows diff --git a/.github/workflows/test-wasm.yml b/.github/workflows/test-wasm.yml index aa74e889e..b60d7d721 100644 --- a/.github/workflows/test-wasm.yml +++ b/.github/workflows/test-wasm.yml @@ -1,4 +1,4 @@ -name: Test DIesel WASM Backend +name: Test Diesel WASM Backend on: push: branches: @@ -6,7 +6,7 @@ on: pull_request: # only run tests when related changes are made paths: - - ".github/workflows/test-workspace.yml" + - ".github/workflows/test-wasm.yml" - "dev/**" - "diesel-wasm-sqlite/**" - "Cargo.toml" @@ -15,18 +15,39 @@ on: jobs: test: name: Test - runs-on: warp-ubuntu-latest-x64-16x + # running with macos since it contains the safari driver + runs-on: warp-macos-13-arm64-6x steps: - name: Checkout uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: brew install --cask firefox - name: Update rust toolchains run: rustup update - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: Setup node and yarn + uses: actions/setup-node@v4 + with: + node-version-file: ".node-version" + cache-dependency-path: "diesel-wasm-sqlite/yarn.lock" + cache: "yarn" + env: + SKIP_YARN_COREPACK_CHECK: "1" + - name: Enable corepack + run: corepack enable + - name: Run Yarn install + uses: borales/actions-yarn@v5 + with: + cmd: --cwd diesel-wasm-sqlite/ install - name: Cache uses: Swatinem/rust-cache@v2 with: workspaces: | . - - name: Run cargo test on main workspace - run: wasm-pack test --manifest-path diesel-wasm-sqlite/Cargo.toml --features test-util --features unsafe-debug-query + - run: wasm-pack test --headless --safari --features unsafe-debug-query + working-directory: diesel-wasm-sqlite + - run: wasm-pack test --headless --chrome --features unsafe-debug-query + working-directory: diesel-wasm-sqlite + - run: wasm-pack test --headless --firefox --features unsafe-debug-query + working-directory: diesel-wasm-sqlite diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index ae8ddc8bf..c2556b308 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -114,6 +114,16 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "ctor" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "darling" version = "0.20.10" @@ -166,6 +176,7 @@ version = "0.1.1" dependencies = [ "chrono", "console_error_panic_hook", + "ctor", "diesel", "diesel_derives", "diesel_migrations", diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index e83253ce3..f69a49156 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -8,7 +8,7 @@ resolver = "2" talc = { version = "4.4", default-features = false, features = ["lock_api"] } diesel = { version = "2.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } diesel_derives = "2.2" -wasm-bindgen = "0.2.92" +wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" js-sys = { version = "0.3" } tracing = "0.1" @@ -27,6 +27,7 @@ chrono = { version = "0.4", features = ["wasmbind", "serde"] } diesel_migrations = "2.2" diesel = { version = "2.2", features = ["chrono"]} tracing-wasm = { version = "0.2" } +ctor = "0.2" [lib] @@ -38,7 +39,6 @@ r2d2 = ["diesel/r2d2"] # enables a `DebugQueryWrapper` for diesel # but is unsafe because of mem::transmute unsafe-debug-query = [] -test-util = ["unsafe-debug-query"] [build] target = "wasm32-unknown-unknown" diff --git a/diesel-wasm-sqlite/build.rs b/diesel-wasm-sqlite/build.rs index f6e5b3913..c3f197ab1 100644 --- a/diesel-wasm-sqlite/build.rs +++ b/diesel-wasm-sqlite/build.rs @@ -5,6 +5,7 @@ fn main() { println!("cargo::rerun-if-changed=package.js"); println!("cargo::rerun-if-changed=package.json"); + Command::new("yarn").args(["install"]).status().unwrap(); Command::new("yarn") .args(["run", "build"]) .status() diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index d322767dc..d2b30155b 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -34,6 +34,10 @@ export class SQLite { return this.sqlite3.version; } + filename(db, name) { + return this.sqlite3.capi.sqlite3_db_filename(db, name); + } + extended_errcode(connection) { return this.sqlite3.capi.sqlite3_extended_errcode(connection); } diff --git a/diesel-wasm-sqlite/package.json b/diesel-wasm-sqlite/package.json index f8d2b750c..889f11777 100644 --- a/diesel-wasm-sqlite/package.json +++ b/diesel-wasm-sqlite/package.json @@ -12,7 +12,7 @@ }, "packageManager": "yarn@4.3.1", "engines": { - "node": ">=20" + "node": ">=18" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index 06087d907..6c8ca78dc 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -305,6 +305,10 @@ impl WasmSqliteConnection { fn establish_inner(database_url: &str) -> Result { let sqlite3 = crate::get_sqlite_unchecked(); let raw_connection = RawConnection::establish(database_url).unwrap(); + tracing::debug!( + "Established database at {}", + sqlite3.filename(&raw_connection.internal_connection, "main".into()) + ); sqlite3 .register_diesel_sql_functions(&raw_connection.internal_connection) .map_err(WasmSqliteError::from)?; @@ -322,6 +326,6 @@ pub struct Nothing; impl Instrumentation for Nothing { fn on_connection_event(&mut self, event: diesel::connection::InstrumentationEvent<'_>) { - tracing::info!("Inst. Event {:?}", event); + tracing::trace!("{:?}", event); } } diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 64e076160..428d4163c 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -184,7 +184,7 @@ impl Statement { impl Drop for Statement { fn drop(&mut self) { let sqlite3 = crate::get_sqlite_unchecked(); - tracing::info!("Statement dropped & finalized!"); + tracing::trace!("Statement dropped & finalized!"); let _ = sqlite3 .finalize(&self.inner_statement) .expect("Error finalized SQLite prepared statement"); diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 527547501..6c42cd38a 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -167,6 +167,9 @@ extern "C" { #[wasm_bindgen(method)] pub fn version(this: &SQLite) -> JsValue; + #[wasm_bindgen(method)] + pub fn filename(this: &SQLite, db: &JsValue, name: String) -> String; + #[wasm_bindgen(method)] pub fn errstr(this: &SQLite, code: i32) -> String; diff --git a/diesel-wasm-sqlite/src/lib.rs b/diesel-wasm-sqlite/src/lib.rs index 5fb80d088..0bbd97545 100755 --- a/diesel-wasm-sqlite/src/lib.rs +++ b/diesel-wasm-sqlite/src/lib.rs @@ -15,9 +15,6 @@ pub use query_builder::insert_with_default_sqlite::unsafe_debug_query::DebugQuer #[cfg(not(target_arch = "wasm32"))] compile_error!("This crate only suports the `wasm32-unknown-unknown` target"); -#[cfg(any(test))] -pub use test_common::*; - use wasm_bindgen::JsValue; pub use backend::{SqliteType, WasmSqlite}; @@ -53,13 +50,3 @@ impl From for WasmSqliteError { WasmSqliteError::Js(err) } } - -#[cfg(any(test, feature = "test-util"))] -pub mod test_common { - use super::connection::WasmSqliteConnection; - use diesel::Connection; - pub async fn connection() -> WasmSqliteConnection { - crate::init_sqlite().await; - WasmSqliteConnection::establish(":memory:").unwrap() - } -} diff --git a/diesel-wasm-sqlite/src/query_builder/mod.rs b/diesel-wasm-sqlite/src/query_builder/mod.rs index bfeff776c..09232cbb9 100644 --- a/diesel-wasm-sqlite/src/query_builder/mod.rs +++ b/diesel-wasm-sqlite/src/query_builder/mod.rs @@ -6,7 +6,7 @@ use diesel::result::QueryResult; pub(super) mod insert_with_default_sqlite; mod limit_offset; -mod query_fragment_impls; +// mod query_fragment_impls; // mod returning; /// Constructs SQL queries for use with the SQLite backend diff --git a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs index d09773d6a..129c0bf2c 100644 --- a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs +++ b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs @@ -1,13 +1,13 @@ -/* -// use diesel::query_builder::into_conflict_clause::OnConflictSelectWrapper; -// use diesel::query_builder::where_clause::BoxedWhereClause; +use crate::WasmSqlite; +use diesel::query_builder::into_conflict_clause::OnConflictSelectWrapper; +use diesel::query_builder::where_clause::BoxedWhereClause; +use diesel::query_builder::where_clause::WhereClause; use diesel::query_builder::AstPass; use diesel::query_builder::BoxedSelectStatement; use diesel::query_builder::QueryFragment; use diesel::query_builder::SelectStatement; -// use diesel::query_builder::WhereClause; -use crate::storage::wasm_sqlite::WasmSqlite; use diesel::result::QueryResult; +use diesel::QueryId; // The corresponding impl for`NoWhereClause` is missing because of // https://www.sqlite.org/lang_UPSERT.html (Parsing Ambiguity) @@ -38,4 +38,3 @@ where }) } } -*/ diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs index 3a7afdc4c..f752df2ac 100644 --- a/diesel-wasm-sqlite/src/sqlite_fixes.rs +++ b/diesel-wasm-sqlite/src/sqlite_fixes.rs @@ -4,7 +4,7 @@ use diesel::{ query_builder::AstPass, query_builder::NoFromClause, query_builder::QueryFragment, - AppearsOnTable, Column, Expression, QueryResult, + AppearsOnTable, Column, Expression, QueryId, QueryResult, }; impl InsertValues @@ -37,13 +37,49 @@ where Ok(()) } } -/* + +#[derive(Debug, Copy, Clone, QueryId)] +pub struct InsertOrIgnore; + +impl QueryFragment for InsertOrIgnore { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + out.push_sql("INSERT OR IGNORE"); + Ok(()) + } +} + +#[derive(Debug, Copy, Clone, QueryId)] +pub struct Replace; + +impl QueryFragment for Replace { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + out.push_sql("REPLACE"); + Ok(()) + } +} + mod parenthesis_wrapper { + use super::*; + use crate::WasmSqlite; - use diesel::helper_types::{Distinct, Except, Intersect, Union}; - use diesel::query_builder::ParenthesisWrapper; + // use diesel::query_builder::combination_clause::SupportsCombinationClause; use diesel::query_builder::{AstPass, QueryFragment}; + #[derive(Debug, Copy, Clone, QueryId)] + /// Wrapper used to wrap rhs sql in parenthesis when supported by backend + pub struct ParenthesisWrapper(T); + + #[derive(Debug, Copy, Clone, QueryId)] + /// Keep duplicate rows in the result + pub struct All; + + impl QueryFragment for All { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + out.push_sql("ALL "); + Ok(()) + } + } + impl> QueryFragment for ParenthesisWrapper { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { // SQLite does not support parenthesis around this clause @@ -55,10 +91,133 @@ mod parenthesis_wrapper { Ok(()) } } - + /* impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} + */ +} + +// Anything commented here are implementation present in diesel +// but not possible because parts of it exist as private types in diesel. + +/* +impl<'b, Changes, Output> UpdateAndFetchResults for SqliteConnection +where + Changes: Copy + Identifiable, + Changes: AsChangeset::Table> + IntoUpdateTarget, + Changes::Table: FindDsl, + Update: ExecuteDsl, + Find: LoadQuery<'b, SqliteConnection, Output>, + ::AllColumns: ValidGrouping<()>, + <::AllColumns as ValidGrouping<()>>::IsAggregate: + MixedAggregates, +{ + fn update_and_fetch(&mut self, changeset: Changes) -> QueryResult { + crate::update(changeset).set(changeset).execute(self)?; + Changes::table().find(changeset.id()).get_result(self) + } +} +*/ +/* +impl AsExpression for now { + type Expression = Coerce; + + fn as_expression(self) -> Self::Expression { + Coerce::new(self) + } +} + +impl AsExpression> for now { + type Expression = Coerce>; + + fn as_expression(self) -> Self::Expression { + Coerce::new(self) + } +} +*/ + +/* +use diesel::dsl; +use diesel::expression::grouped::Grouped; +use diesel::expression::AsExpression; +use diesel::operators::*; +use diesel::sql_types::SqlType; + +/// Sqlite specific methods which are present on all expressions. +pub trait SqliteExpressionMethods: Expression + Sized { + /// Creates a Sqlite `IS` expression. + /// + /// The `IS` operator work like = except when one or both of the operands are NULL. + /// In this case, if both operands are NULL, then the `IS` operator evaluates to true. + /// If one operand is NULL and the other is not, then the `IS` operator evaluates to false. + /// It is not possible for an `IS` expression to evaluate to NULL. + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # run_test().unwrap(); + /// # } + /// # + /// # fn run_test() -> QueryResult<()> { + /// # use schema::animals::dsl::*; + /// # let connection = &mut establish_connection(); + /// let jack_is_a_dog = animals + /// .select(name) + /// .filter(species.is("dog")) + /// .get_results::>(connection)?; + /// assert_eq!(vec![Some("Jack".to_string())], jack_is_a_dog); + /// # Ok(()) + /// # } + /// ``` + fn is(self, other: T) -> dsl::Is + where + Self::SqlType: SqlType, + T: AsExpression, + { + Grouped(Is::new(self, other.as_expression())) + } + + /// Creates a Sqlite `IS NOT` expression. + /// + /// The `IS NOT` operator work like != except when one or both of the operands are NULL. + /// In this case, if both operands are NULL, then the `IS NOT` operator evaluates to false. + /// If one operand is NULL and the other is not, then the `IS NOT` operator is true. + /// It is not possible for an `IS NOT` expression to evaluate to NULL. + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # run_test().unwrap(); + /// # } + /// # + /// # fn run_test() -> QueryResult<()> { + /// # use schema::animals::dsl::*; + /// # let connection = &mut establish_connection(); + /// let jack_is_not_a_spider = animals + /// .select(name) + /// .filter(species.is_not("spider")) + /// .get_results::>(connection)?; + /// assert_eq!(vec![Some("Jack".to_string())], jack_is_not_a_spider); + /// # Ok(()) + /// # } + /// ``` + #[allow(clippy::wrong_self_convention)] // This is named after the sql operator + fn is_not(self, other: T) -> dsl::IsNot + where + Self::SqlType: SqlType, + T: AsExpression, + { + Grouped(IsNot::new(self, other.as_expression())) + } } + +impl SqliteExpressionMethods for T {} */ diff --git a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js index 38da2f941..f6d2fbe51 100644 --- a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js @@ -14440,6 +14440,10 @@ class SQLite { return this.sqlite3.version; } + filename(db, name) { + return this.sqlite3.capi.sqlite3_db_filename(db, name); + } + extended_errcode(connection) { return this.sqlite3.capi.sqlite3_extended_errcode(connection); } diff --git a/diesel-wasm-sqlite/tests/common/mod.rs b/diesel-wasm-sqlite/tests/common/mod.rs new file mode 100644 index 000000000..6a3418476 --- /dev/null +++ b/diesel-wasm-sqlite/tests/common/mod.rs @@ -0,0 +1,42 @@ +//! Common utilities/imports amongst WebAssembly tests +use prelude::*; + +use tokio::sync::OnceCell; + +static INIT: OnceCell<()> = OnceCell::const_new(); + +pub async fn init() { + INIT.get_or_init(|| async { + console::log_1(&"INIT".into()); + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + diesel_wasm_sqlite::init_sqlite().await; + }) + .await; +} + +pub async fn connection() -> WasmSqliteConnection { + diesel_wasm_sqlite::init_sqlite().await; + WasmSqliteConnection::establish(":memory:").unwrap() +} + +// re-exports used in tests +#[allow(unused)] +pub mod prelude { + pub(crate) use super::init; + pub(crate) use diesel::{ + connection::{Connection, LoadConnection}, + debug_query, + deserialize::{self, FromSql, FromSqlRow}, + insert_into, + prelude::*, + sql_types::{Integer, Nullable, Text}, + }; + pub(crate) use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; + pub(crate) use diesel_wasm_sqlite::{ + connection::WasmSqliteConnection, DebugQueryWrapper, WasmSqlite, + }; + pub(crate) use serde::Deserialize; + pub(crate) use wasm_bindgen_test::*; + pub(crate) use web_sys::console; +} diff --git a/diesel-wasm-sqlite/tests/dedicated_web_worker.rs b/diesel-wasm-sqlite/tests/dedicated_web_worker.rs new file mode 100755 index 000000000..7c904c52a --- /dev/null +++ b/diesel-wasm-sqlite/tests/dedicated_web_worker.rs @@ -0,0 +1,17 @@ +//! Integration Test Organization in rust is little bit non-standard comapred to normal +//! organization in a library/binary. +//! In order to avoid being compiled as a test, common functions must be defined in +//! `common/mod.rs` +//! +//! Tests are separated into separate files in the module `test`. +#![recursion_limit = "256"] +#![cfg(target_arch = "wasm32")] + +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + +mod common; + +mod test { + mod row; + mod web; +} diff --git a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/down.sql b/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/down.sql similarity index 100% rename from diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/down.sql rename to diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/down.sql diff --git a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql b/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql similarity index 63% rename from diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql rename to diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql index fd3df8b20..dc1583510 100644 --- a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql +++ b/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql @@ -1,5 +1,5 @@ CREATE TABLE books ( - id SERIAL PRIMARY KEY, + id INTEGER PRIMARY KEY NOT NULL, title TEXT NOT NULL, author TEXT ) diff --git a/diesel-wasm-sqlite/tests/row.rs b/diesel-wasm-sqlite/tests/test/row.rs similarity index 95% rename from diesel-wasm-sqlite/tests/row.rs rename to diesel-wasm-sqlite/tests/test/row.rs index 429f819aa..193e0da66 100644 --- a/diesel-wasm-sqlite/tests/row.rs +++ b/diesel-wasm-sqlite/tests/test/row.rs @@ -1,14 +1,9 @@ -use diesel::Connection; -use diesel_wasm_sqlite::{connection::WasmSqliteConnection, test_common::connection, WasmSqlite}; -use wasm_bindgen_test::*; -wasm_bindgen_test_configure!(run_in_dedicated_worker); +use crate::common::{connection, prelude::*}; // test copied from diesel #[wasm_bindgen_test] async fn fun_with_row_iters() { diesel_wasm_sqlite::init_sqlite().await; - console_error_panic_hook::set_once(); - tracing_wasm::set_as_global_default(); diesel::table! { #[allow(unused_parens)] diff --git a/diesel-wasm-sqlite/tests/web.rs b/diesel-wasm-sqlite/tests/test/web.rs similarity index 52% rename from diesel-wasm-sqlite/tests/web.rs rename to diesel-wasm-sqlite/tests/test/web.rs index 958e6e696..0679a1ba0 100755 --- a/diesel-wasm-sqlite/tests/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -1,22 +1,7 @@ -//! Integration-like tests with a persistent database -#![recursion_limit = "256"] -#![cfg(target_arch = "wasm32")] +//! General tests for migrations/diesel ORM/persistant databases +use crate::common::prelude::*; -use diesel::connection::LoadConnection; -use diesel::deserialize::FromSqlRow; -use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; -use diesel_wasm_sqlite::{connection::WasmSqliteConnection, DebugQueryWrapper, WasmSqlite}; -use wasm_bindgen_test::*; -use web_sys::console; - -use diesel::debug_query; -use diesel::insert_into; -use diesel::prelude::*; -use serde::Deserialize; - -wasm_bindgen_test_configure!(run_in_dedicated_worker); - -pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/web/migrations/"); +pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/migrations/"); mod schema { diesel::table! { @@ -39,11 +24,14 @@ pub struct BookForm { // published_year: NaiveDateTime, } -#[derive(Queryable, Selectable, PartialEq, Debug)] +#[derive(Queryable, QueryableByName, Selectable, PartialEq, Debug)] #[diesel(table_name = books)] -pub struct Book { +pub struct StoredBook { + #[diesel(sql_type = Integer)] id: i32, + #[diesel(sql_type = Text)] title: String, + #[diesel(sql_type = Nullable)] author: Option, // published_year: NaiveDateTime, } @@ -90,72 +78,97 @@ fn examine_sql_from_insert_default_values() { #[wasm_bindgen_test] async fn test_orm_insert() { - console_error_panic_hook::set_once(); - tracing_wasm::set_as_global_default(); - + init().await; let mut conn = establish_connection().await; - - let rows_changed = insert_books( - &mut conn, + let new_books = vec![ + BookForm { + title: "Game of Thrones".into(), + author: Some("George R.R".into()), + // published_year: NaiveDate::from_ymd_opt(2015, 5, 3).unwrap(), + }, + BookForm { + title: "The Hobbit".into(), + author: Some("J.R.R. Tolkien".into()), + // published_year: NaiveDate::from_ymd_opt(1937, 9, 21).unwrap(), + }, + BookForm { + title: "To Kill a Mockingbird".into(), + author: Some("Harper Lee".into()), + // published_year: NaiveDate::from_ymd_opt(1960, 7, 11).unwrap(), + }, + BookForm { + title: "1984".into(), + author: Some("George Orwell".into()), + // published_year: NaiveDate::from_ymd_opt(1949, 6, 8).unwrap(), + }, + BookForm { + title: "Pride and Prejudice".into(), + author: Some("Jane Austen".into()), + // published_year: NaiveDate::from_ymd_opt(1813, 1, 28).unwrap(), + }, + BookForm { + title: "Moby-Dick".into(), + author: Some("Herman Melville".into()), + // published_year: NaiveDate::from_ymd_opt(1851, 10, 18).unwrap(), + }, + ]; + let rows_changed = insert_books(&mut conn, new_books).unwrap(); + assert_eq!(rows_changed, 6); + tracing::info!("{} rows changed", rows_changed); + console::log_1(&"Showing Users".into()); + let title = schema::books::table + .select(schema::books::title) + .filter(schema::books::id.eq(2)) + .first::(&mut conn) + .unwrap(); + assert_eq!(title, "The Hobbit"); + + let author = schema::books::table + .select(schema::books::author) + .filter(schema::books::id.eq(1)) + .first::>(&mut conn) + .unwrap(); + assert_eq!(author, Some("George R.R".into())); + + let id = schema::books::table + .select(schema::books::id) + .filter(schema::books::id.eq(1)) + .first::(&mut conn) + .unwrap(); + assert_eq!(id, 1); + + let loaded_books = schema::books::dsl::books + .select(StoredBook::as_select()) + .limit(5) + .load(&mut conn); + assert_eq!( + loaded_books.unwrap(), vec![ - BookForm { + StoredBook { + id: 1, title: "Game of Thrones".into(), author: Some("George R.R".into()), - // published_year: NaiveDate::from_ymd_opt(2015, 5, 3).unwrap(), }, - BookForm { + StoredBook { + id: 2, title: "The Hobbit".into(), author: Some("J.R.R. Tolkien".into()), - // published_year: NaiveDate::from_ymd_opt(1937, 9, 21).unwrap(), }, - BookForm { + StoredBook { + id: 3, title: "To Kill a Mockingbird".into(), author: Some("Harper Lee".into()), - // published_year: NaiveDate::from_ymd_opt(1960, 7, 11).unwrap(), }, - BookForm { + StoredBook { + id: 4, title: "1984".into(), author: Some("George Orwell".into()), - // published_year: NaiveDate::from_ymd_opt(1949, 6, 8).unwrap(), }, - BookForm { + StoredBook { + id: 5, title: "Pride and Prejudice".into(), author: Some("Jane Austen".into()), - // published_year: NaiveDate::from_ymd_opt(1813, 1, 28).unwrap(), }, - BookForm { - title: "Moby-Dick".into(), - author: Some("Herman Melville".into()), - // published_year: NaiveDate::from_ymd_opt(1851, 10, 18).unwrap(), - }, - ], + ] ) - .unwrap(); - assert_eq!(rows_changed, 6); - tracing::info!("{} rows changed", rows_changed); - console::log_1(&"Showing Users".into()); - let book = schema::books::table - .select(schema::books::title) - .load::(&mut conn); - tracing::info!("Loaded book {:?}", book); - let query = schema::books::table.limit(5).select(Book::as_select()); - let books = conn.load(query).unwrap().collect::>(); - /* - for row in books.iter() { - let deserialized_book = row.as_ref().map(|row| { - Book::build_from_row(row).unwrap() - }); - tracing::debug!("BOOK: {:?}", deserialized_book); - } - */ - // console::log_1(&debug_query::(&query).o_string().into()); - // .load(&mut conn) - // .await - // .expect("Error loading users"); - - /* - for book in books { - console::log_1(&format!("{}", book.title).into()); - } - */ } From bb18b61df2e310b7c23ad222cb2c167fa9b28ae9 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 27 Aug 2024 15:07:51 -0400 Subject: [PATCH 07/97] add metadata for crates remove rollup plugin typescript organize JS into one folder --- diesel-wasm-sqlite/.gitignore | 1 + diesel-wasm-sqlite/Cargo.lock | 2 +- diesel-wasm-sqlite/Cargo.toml | 9 ++++++- diesel-wasm-sqlite/build.rs | 16 ++++++------- diesel-wasm-sqlite/package.json | 1 - diesel-wasm-sqlite/rollup.config.js | 14 +++++++++-- diesel-wasm-sqlite/src/ffi.rs | 7 +++--- .../src/{ => js}/sqlite3-opfs-async-proxy.js | 0 diesel-wasm-sqlite/src/js/sqlite3.wasm | Bin 0 -> 939204 bytes .../src/{ => js}/wa-sqlite-diesel-bundle.js | 0 diesel-wasm-sqlite/yarn.lock | 22 +----------------- 11 files changed, 34 insertions(+), 38 deletions(-) rename diesel-wasm-sqlite/src/{ => js}/sqlite3-opfs-async-proxy.js (100%) create mode 100644 diesel-wasm-sqlite/src/js/sqlite3.wasm rename diesel-wasm-sqlite/src/{ => js}/wa-sqlite-diesel-bundle.js (100%) diff --git a/diesel-wasm-sqlite/.gitignore b/diesel-wasm-sqlite/.gitignore index f93dc9153..63e51e284 100644 --- a/diesel-wasm-sqlite/.gitignore +++ b/diesel-wasm-sqlite/.gitignore @@ -6,3 +6,4 @@ !.yarn/releases !.yarn/sdks !.yarn/versions +node_modules/** diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index c2556b308..acb70ecf9 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -172,7 +172,7 @@ dependencies = [ [[package]] name = "diesel-wasm-sqlite" -version = "0.1.1" +version = "0.0.1" dependencies = [ "chrono", "console_error_panic_hook", diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index f69a49156..c390eedfe 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -1,8 +1,15 @@ [package] name = "diesel-wasm-sqlite" -version = "0.1.1" +version = "0.0.1" edition = "2021" resolver = "2" +authors = ["XMTP Labs "] +description = "SQLite WebAssembly backend for Diesel" +homepage = "https://xmtp.org/" +repository = "https://github.com/xmtp/libxmtp" +license = "MIT" +keywords = ["orm", "database", "sql", "wasm"] +categories = ["database", "wasm"] [dependencies] talc = { version = "4.4", default-features = false, features = ["lock_api"] } diff --git a/diesel-wasm-sqlite/build.rs b/diesel-wasm-sqlite/build.rs index c3f197ab1..7684ecf6c 100644 --- a/diesel-wasm-sqlite/build.rs +++ b/diesel-wasm-sqlite/build.rs @@ -1,15 +1,15 @@ use std::env; -use std::process::Command; +// use std::process::Command; fn main() { - println!("cargo::rerun-if-changed=package.js"); - println!("cargo::rerun-if-changed=package.json"); +// println!("cargo::rerun-if-changed=package.js"); +// println!("cargo::rerun-if-changed=package.json"); - Command::new("yarn").args(["install"]).status().unwrap(); - Command::new("yarn") - .args(["run", "build"]) - .status() - .unwrap(); + // Command::new("yarn").args(["install"]).status().unwrap(); + // Command::new("yarn") + // .args(["run", "build"]) + // .status() + // .unwrap(); let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); if target_arch != "wasm32" { diff --git a/diesel-wasm-sqlite/package.json b/diesel-wasm-sqlite/package.json index 889f11777..21afc9243 100644 --- a/diesel-wasm-sqlite/package.json +++ b/diesel-wasm-sqlite/package.json @@ -16,7 +16,6 @@ }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "rollup": "^4.19.0", "rollup-plugin-copy": "^3.5.0" } diff --git a/diesel-wasm-sqlite/rollup.config.js b/diesel-wasm-sqlite/rollup.config.js index 1b4c72408..e61d08116 100644 --- a/diesel-wasm-sqlite/rollup.config.js +++ b/diesel-wasm-sqlite/rollup.config.js @@ -1,15 +1,25 @@ import { defineConfig } from "rollup"; import { nodeResolve } from "@rollup/plugin-node-resolve"; +import copy from "rollup-plugin-copy"; export default defineConfig([ { input: "package.js", output: { - file: "src/wa-sqlite-diesel-bundle.js", + file: "src/js/wa-sqlite-diesel-bundle.js", format: "es", }, plugins: [ nodeResolve(), + copy({ + targets: [ + { + src: + "./node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm/sqlite3.wasm", + dest: "src/js", + }, + ], + }), ], // external: ["@sqlite.org/sqlite-wasm"], }, @@ -17,7 +27,7 @@ export default defineConfig([ input: "./node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-opfs-async-proxy.js", output: { - file: "src/sqlite3-opfs-async-proxy.js", + file: "src/js/sqlite3-opfs-async-proxy.js", format: "es", }, }, diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 6c42cd38a..a338e13cb 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -28,8 +28,7 @@ pub(super) static SQLITE: OnceCell = OnceCell::const_new(); // have to go through JS/browser at all. /// the raw WASM bytes -pub(super) const WASM: &[u8] = - include_bytes!("../node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm/sqlite3.wasm"); +pub(super) const WASM: &[u8] = include_bytes!("js/sqlite3.wasm"); /// Options for instantiating memory constraints #[derive(Serialize, Deserialize)] @@ -103,7 +102,7 @@ pub async fn init_sqlite() { let opts = serde_wasm_bindgen::to_value(&Opts { wasm_binary: WASM, wasm_memory: mem, - proxy_uri: wasm_bindgen::link_to!(module = "/src/sqlite3-opfs-async-proxy.js"), + proxy_uri: wasm_bindgen::link_to!(module = "/src/js/sqlite3-opfs-async-proxy.js"), }) .expect("serialization must be infallible for const struct"); let opts = Object::from(opts); @@ -140,7 +139,7 @@ struct Version { } /// Direct Sqlite3 bindings -#[wasm_bindgen(module = "/src/wa-sqlite-diesel-bundle.js")] +#[wasm_bindgen(module = "/src/js/wa-sqlite-diesel-bundle.js")] extern "C" { #[derive(Debug)] pub type SQLite; diff --git a/diesel-wasm-sqlite/src/sqlite3-opfs-async-proxy.js b/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js similarity index 100% rename from diesel-wasm-sqlite/src/sqlite3-opfs-async-proxy.js rename to diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js diff --git a/diesel-wasm-sqlite/src/js/sqlite3.wasm b/diesel-wasm-sqlite/src/js/sqlite3.wasm new file mode 100644 index 0000000000000000000000000000000000000000..c31c0ce353a1dae8d3562241e52ae402f63b3ba3 GIT binary patch literal 939204 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

i?^%<`4{>TpxDBw?_A?(pPwC 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

  • )CxTU+WMIgM#dw!k1K4M}?pMV$xu zBugBE8&)oQW=z8C3HMm~9A&RR`BmnHw;m$41B}=7T8`W^ryo%P_l3AnwueHPcCQqw z@L(rN7$&`zch=(C8oI^`-)OzcAMTD>Jpy}Zq198hfzCT9_G9Ms90|2JxX-!tGFHig zD!PK4eK>wt`4uKp{v9E7mN24=WG0Ah5ma}wFfS(ys}%*ghl|C7a(aUg?>}o&yZJYK zZ;JEiq$WXs2El|(4EJq(;;9Sr+{Mc9Wktpl#(941&1_{z%m`fF%@dG5yKaIw!QlOX zgpWN#qM)|9hh17~899roJ-`zN-r%9mc#VV4$H9ndmxcrn=b(1IGpj^VkGE+u`*Pwm z;Td)wlF!{AR^enFo<*xB2+})Ws;c~d`+n7M!q>>Rroc9?#*137=OktPf3KI%;1H>f z0a|h-e*^oxeW0pf4dqqGLi~8x3vYui2l!y77r5iT;3<{Aus!wVWbM3G_$eI9|o((qWtl zq+U526dmA9fp z7cDnv4EAu-2U}bS`%_SfyBJp}rRq?ByTkr+a#Bpa2_y^2;dZ9CK-u#Z8N=eR&rHKC z(>0}MRL=!Y+-m#AEt)5ZjWK^MDmV4RvTHnAyt@_&ZVejb1>r|}^owB}_;Pv^V_a-u z7sj|W44c=1YME2)Fi)2dxl9DWmaNM0^7VZLCSaJSctd^m!F5V7TqEn@rF}rnE9>j! zjn`x`F#1WA2IVYqsZ4Kd`-}i2PS@&;@b^pltMzH5j%l+O>_cvsU+-hA&YC$Uaj|!K zcSLX_X6fGZ(-0rHGkFvN#;$9JH5xJBGp$_B;8s`x`(I!tz0^6He*WqF44}`Z6@BD1 zOmTwQygOsbCA*f83?Gp4xKau~pG!JfB&D(_uum|26y~8DMpT^vZR9QBwoHn>EiaEp zqnSBtBHU?&Tew5mCy!VdvQNvgaEJWa9W;kyqx^<`Wt`=Xh#35L8xeXmBLeGa;hU}| z-Nw|z$+VPr1}G0G3x9f5Zj;#;NZB~{X=}_nGaNp?)$?Bc|8cyhZtBJ{p7L1Ec-#P zg$u!Am|L2udmGs57I#v+v){7gxyo#12ffm!l^jtMD$5AXq4Dr_`i@Lf4#vE=_@X7_YZZjF6pb0*fKqqF`i(_rezm@v`0O}7aGJ*5Ewu~3lbn)CW zZ*Cxi5zq-Vo=q7o#h{GL+Mcz@m9V$7~NCI^1q70ddRb90cp0bdn=K4KC-u z@BzCUQ6lZAwswWOx@s{I2~gtVk43CEI~PMRc{Fw>9(OPkk89-+tHV)7Ac%8y?JHUs z5ve%A3A#oogxZb(gpm?T{T!{w zSaOue+VaqfZVgh2QhLf`G0C?8Wr+NX{PWxjRyJd5M2%O$oR=9tPPi<*g;!<9Z!tG^L*&Dor=wp`&=~)O$mQpA z@xBLPgFjM`Iw}thsdQ5r*H`OC<3TzykA+E+;3)*?`=*E3i)K@@LeE%6x|LF#uLe@_2W|Zl}RQVa)Q(RXhE*IE-X;YgmEI+Yin6 zItR?+3vq*&OZv7>6>qGej13IV@SSolhvq>n>35U`Eu?WC1;pE*ZayDsKFMF1(Mq(W z`;ZI;&|(i9AOl5wAem)P`7eEQ0gex-)f0z4GdmtF?KD`*YOOyZlr3|>dZA%4zPa?z zMYUAz2u?Vc2*8`*=5`0N0Me(5Y8eFU1#*xi;-k5!z?`yu2`EqJdnBjit)Kn8w1fp7 zXK5SALia8$WSfP-G#{xL42LX82bHUMMz#UqDZ+M7ZEnYPc)1L7^CabGii$}9aAs+} zq-C39GAFDUkL`J~CrD0NuXnH&{TUT21m!j{EJ%+_!m`m-h1# zP3+^1zxpFt(Z0x$3B6TB-9>5d#!aQY$><@jpYvlcZVo>~axgrLrL3`dI?AfkUD!c& zR%#n*-NjRC&oGl*L-AgaXC~bPz5aC{D3d2Y)0|S0HRc|&6wpu@oVNHMP`Ni0f>Pt6 z06@eTQ1cbm8zW$OkxVd{Hf|n%j7F!$w?D*I4t>)kRAOXf@@<(EZ>#BWG9_;l%*zZF zIJ83snp4}tGZ%3*h@%2*Z+)%8f=C~LjyUF@U4SOR57Yr1B8<_5H{3Gf_`R+AT%kP^ zdo#}Q(mkyqhd~U_WMXGltB&E!if2~&ptSA^A2>}ahHxfLp=be@n)m7bL4tUaFdJdx z^MU5`B%i)?ub(`3PrEvExQ+I=$+#na8fP4{0&Qk05fkH#AKdJg5BnQW-#)mQPaET- zf37Um(~XM8%EPo80mHYM8XF}tPPn6iZ8`xs4Xk7pto-M45+mARY*?KkJLU3%9U?Q; zIhVHOIv~j9#YYVGvd++;D@_+QrZv5jWpQa^>=y98g&fg08)PMpo^j-Q3R;!CmUz9! zH)bu*Q3Vp9Ez;h6wRjjNMuL(V6N|1iJ(!+n57HhCJ2EWbz$C!vYvA%KmzzYUoz9X( zCYqk9b~XcNg2SCkJY?2WT5QVW~VzbvbJ#PNNm^3q9m0h5V3? z)9GZ~#~*bYZetXkDTX?3mnW#M4}xKy=;xU)*9X!(q19lR)0w+sRl-GrX^F#CUz~H< z(c+Zj@OpnSguHH>+k?IA5RTt=bx`d*>Z#KWlu;a!ii`ncP>`bhVe>AFnRC>h;udhE z^eGj~xJ$7=x@?fxw_Y?Li2`&q3-cpIya2Fpg%NgH1|{Q7B&Nfh2Znr1FwD!8cWjo5oKlbu@lQINOYnt7g>CB~B0%m3D4w22A*_ z;(ljVq?m)^elD3m5a*Kxepy&ApsxmXVGHRNrH$n9dzAMv5pI=V!b^YvbMY`70LZ^! z3KSKbO+nV;67m}1PE{>~3WM@dG|$mB;BbFm_eF?6)-vQr#?x>$Z4C?$I?dS6vy&@3 z3k{4`mPOitO^v;5xJ`qpg^0{8AJ)MJ{__@)qpjw0tiUB)1&RPoT`I&-wLN-}5Or=8D4peSU5y9FSb+6|pcaa@zLDxR=I3r;)xr0;3 z=)}&Thi}G~!;M9XmCWn30bX76DC5(-(=I>lltIe8P6)fLto+Z!9#dzaS*iag^nVX> zKZ5^ z1$op6LE&4b`cHg+p2~MF45*kJT`<8KGM1>;&MC7FZ1B( zv9KSH(sFqfDz1#N6NLe0Aa*jJqYZWfb+DA}tPP%>3jJmm11?I@JzXeaC84Kh7}c0|%sR7!j?%q%x}dit~X5Ru}-E@CTW{OrQqAkwre z$C!3iB@q~Yb;|u!kE!oMtEW^BwshOwHFvfjCtb!P7lbC74Dp>}Fho7#Yp|Aqcjo@4yz(q_!a%x6v936Lno5sT2g-}eXYCjp}@Buc- zIi5%-YI$xQi}1K@2Lgh2kbA7soVV9CJ()g~gsypoKhjGB;(^t(`?PtGGd*!8jvl zg-hxEl-BY{bsbcZY4pa<1cmoy&#o1q4;tJ?QFW5in$C8|{g8`_*xn z=0rDj!PXhiGb8rstL!}}XfK{>UKkBX_;`s?b9^2X@Ip)UH-nfuqAiws*$c2GvqtMHz_oA=$0I&L z!KtnBB!y6Lr8}0L9%ye1DYq%m(_MDY@2BpPr~pEgFDakl+pKN^x6+}02Va9A+7M~s>HpQE#zI*e(Z`U zFi!(j)svOl^6;$G8lGD%4EJf>%wJVaXDbNH#&j2MUYN}u^j>!WZL4;fnNg%WU!#qQ zNr+^_h3Lt)&W7YCKV#4_Qp+)37iB8v zRu>)_u2$#fqP&d)ZiC2VSDxul<9)!t9T-sc1aGs9H7;5n^wgON$e>$A)ErI&i$p=t zPTNAV@ZZ5oDHv6zx8CA-M()b!roxLUf1*B`;R8^)akaG$9zO^fK~IRMWsf&pRiUE@ z0fBgK(DFs)L;d;;jP_$dpqr)+;T=YMJRCmLGUG;;8I7C%K(!<_O*0e9{$hf$*VtuT zsa0b{b_bicSP1~I7azvIpPwa0$77;Ev%?=7Q?e&Mud`)TydZ0ya#fy&N=GJDZrAko zJj2KxkRss-k(VDGWjERKyh?KvXeNgn3SSTl!VghRz9DIx4NRrX^YS`dgXSDwmMrlA zs^N+3B&tp(sj#?nG_<=q!tck9GL+GvqFqN^&GY1meY)~xin~qc6|8n2qw9KU8P$GQcm_}7y`^O$ zS<#C{`T0AJwWk5dctjN3;Pozum(@Dk;yrrc z?rJS3ltK0Nt7|;8kHPTk7-UQ}Tk4P|5l__IoRzj2?%yuLVT(Pra+U}}6 z3*+Q=%WyG0Gjp_Gx%9RObitdgWvl8^h;O zxX67lMH=q~x;ryYTx^di-R1zlxUL~Sa$`hu*=Dqj&*R>ar)h(V{Cdb(f(F?OB1F?} z`7X2HiZ_H29@aI6qqZ57a@&3R-})w4HFScBlscf*=Hb!NIUYG( zhFmH`+e;`Kjn_gvoCoT_w)~&i;TUYc3Y0lTtkHWFQgh|q{Ve&g$1nmyWYZDpGI}hw zcMdSPX`X~%cc}A}@OpvX{0%Y~$6zXqhxYLj+}YI&%N3ZN6Fa9ZO8 zh(!QX6)Uj_z0o2(juT)56gy(WXFr|GSad=NHf9zJY5ojN!S}`)J<;;^?34nU+R!mV z%>Gy)SgUXt2hGB{HpIEc%AYwAe;Ef}DD0}GM<1tzV9pnvXLAVV{8-FJ^nk4mxl^wY zt~B=IOD?<-E-4l%7PjFjI!Wazv+|UkK(5c-;RWJTfeQ%qAYq`I$DW=?Kxt3cd+)1H zKT_{NH#<`AaV)VslrKWWZLdy0GR#q6n5v7PS(vQ_4;%H@tJcKnd7fwnHcg-qtkM*4 zD4;oLamP7uHmptll1x61t9 z`-Z18Enu-TF5vByah`(z+$I}ixCWcvBj?7r3Q%;aA=R8efHY=$t>F$^>V}H65aKUn zO%^-HA_X(7xxEGTmkO%<y`6JDu439>gGF8 zGoF0M@DlG`sFc(>5hIr4Z_gBqwG2Q)f>pg37*k(3R6Us!(nO$h5b=vg30f9cp;Hj+ z7DvX&5xleqaO%@peEv5I*O4Im2KC&jhfX=Ek#KAJh*jVkstlTp%r7xqe${xk#T{`Z z1=fYB(1W@86$vryO%9G9hXtsX49vTC)Me=NY4ZlKGi4q zXsOUhw%MuMn+ueXb9ssJhTsn5jRB}!h0YUtFbk`c8$_<;>ArCu0GR?4hdFM+$uftl zWqrgeaxQL)N!aMbH6aFZaCdb{mR09emk8Z3ON`Tm0Bb;=F9OzRa4UDu{2BeoIR@?E z7uW$A5)wPi$SLI%&Ov|JbA*4Ea=HCDjUHf^e*>a>0?VMf@nPCv*}`)iM%8~|Q^lIf{FS2Y~T{hP%P>2{nppf~C7MB>KNu-mp z(9K;Zy;$vmw>EVHCkOj&^FWs7hMB^qmN8C3#*=IYL7jz)nk9KN_I+GvSkgRS4KIKU zXP}ls?qC6^)2q&icW25k^fQH95|Pac5Kg!Jd-RKA^#YY=Vpn=ETM83q&W2Hg&89kB z^(^6xs1ARnq4-`p^9SgH+$Jk5Ayir%>lCGC{0e6SbU~%iC1fd0%~$6hlYES{%`tEl zgn)2JfJm|!=}cKsf;Vmj01lmqSTl6AT-O>Nv@|xGFLgil>IV8`2_t$J2yo@_5ffAMqH3ecCsEjDu`s;@ zGTRy{D#V_C?3fKrz=gG1Q>sl4G!#gNGKrZXHS=hVz0DXQ3XVByo+Yu}B_c(FEWM~D z)VMN-4|dV`P*6y#jpT~SG`N}xG!J0{x#d4SA>26trG#3X_0G)@411U6`ri?Pz)x(k ziP&X7Ir;B4QSg{~G&5~D9T#S>`EV1F!8+GiQ#s7B2y3d2-~=j&axh2Y#8o5rZ0QM2 zc|5in|4Sg??WjCzV8PbH+9~u&7FeC%VZ~_2%`e!Fh8{0mFWyq|*+>e_C zKjPVcGCTUaK0c_0FrFdAYe+*z_%~hI3=uQ*!>FJI1#n!Y${!G_!R7=XW*XmaFEmiK~mXXT$g710I4A zsr!MF=fv;2Kay>Y3m`iHrV|MXOI3elX*Gl#6@@an6zR0EnCZpz0krWTTero;)H+UW z(pjhUr2mD?kvMgQt>2`@=@$|b;@f^k~l{L_wwyK@C%%|B`ZG}}? zL#FNzr(hRGjcWB4R3je^hi$I3gO$YsO@S}+7fK?7zCIYv47XD{mZ;T=I?RG)XJ>?a zM&!Z9x=Cja?;ta*-7snkc4vwNZV#MqVUzfQ-#1`d#dhZo8z6AJcGxTJhe|uHRuw*a z7bV;JMGFQ%>dzC+L8C4Y9{p?pg}RV2juTIhRRfXU70QqV);G8Fm2pXPcU(Guwxq#; z2)i!lm5Ji>=&*4qY8+|e3E<%WQ=>BH@)&w(3VjkzusuECGGFxtsdVCECec_B2pAIz z+1J64El5z~5Am?<#-JrF1|jNaR*w(I%HhCP^UQ*K?BP!LY#+qN9Co{{1EY) zuHKr#g_K2^55HI3SglDY3S+OMg|!Vmy73(i++#p+4rdyC6LcxSxVA_Qx~igKr!4Ah zUBoiM!$sYp3-v}dPP@s_IgttOYRG_Yodo~hlKHpAwmKXs4160NxGO9iHncqcUo{8~ z6Xz*|$eENHCZoJS1FqBn(J}$~qZ%sk&z6bQ5DEq{3r)XX=4x758*uCg7TF35-q)bv zS+pby$>48^Q_yrZ!ENEYL`-OuJCGTLQMLnPH@_QA+I2@glXVxaRa?fkz^;SEkMsIe zwLEcA^`;a4i)OV#-6jZenPg?^?>r_PZv0cnnLed#H){YqfD|=>=EDT)xZhwKH@F?z zaJcZOrbT;=j!v5_>vph?53NlcmSKBfXxSf{RVR^!eHw5G@#LI&Ok`kgq5W;=6HgC( zM2!;)&|uLwu4iHG2>+~RgJq_fqV~!(Jx%diPYYN*r=iRkSE)`K72ntD030T&??Ms0 z#e{Z@EIR8ewXuBS?h5e*yhcugiYl4X;|Au&Hc&+e#_l|&mjqy(5)H)jopd3RsPS@O zkh8Y{2mtTg5DOpzbald-L)_J)1i)WVTM43@lS3GZxDOZT=zs-^sVHbAnR<~HYAi@4o%#SE7aY*Qa<+h)bO1Vpl=*<8kKI(!btpsw<^+nDTB>PW{_S>5Y3*5zc zbOz;Q-2sO9F%if7PwBckXpjoM%FRw%JVL5K=b~aUic>H5UB9sye>)xWx#O`9)sIt7jw`fK7#>v4?uwYJ8Bm}Hg9f>w!^*J1`t*|2~#%9ac z3TQf*V21pBZoC@-fsNC*27|x+Wdbyl*25F~-qa`9^ycGT+i30E?wT^viSjTp+Spvw z3H5w9JDM)zjueuFSohD;p>R4ewWqI$sqd?GKwFKZ6BQ?5m{<_zWN@=f+WTWaAB9(< zxDs#$H;VFA3Vl$Oewr?PxTXNBo9A=G6%2TWRM_&>#y3@?b18hj8S-{BS8TT35$>BezZjuf<9 zc81gp1T>GXv3-G$RdfM9R&ZnSQ4QxZ@YHIVH|JP!^-5$tA6>$${eve9OI^$>PKg+m zZ^j4d`05IVhsSHmY>}5EX#J#K8!9m;T2O}r|JW7i(Cb`E--k5w(pTFsxboL12x{{% z5E8FwH@c1opE~&m!SY!Jyws6@FkqJfIt3nhKd6Asru&$(Bi*M>J;IA6b9LYp(*kbQ zqy6^LCEk`W80Z)e1@G)Z1)Yk+z}|pjG`hNP@+y|lUG3U5GDqSJ$(XkYyk-SW<~bDO zIrz=~JZx;(>A>lE6*c8*P%8o~e5Z1bNWhKUr<(A17^4m`n&=Ry>rw9*&3rbjn7Lmg zyTM){h&6h`wDxOaM5bD741wpIevh6UE?c7G_U*GKbH*TT2@o~gXlZ6Y&qbIy;vCT- z3G>-D%kf*9T*+tSu$IWwjCA8dM#E?jv0;Q9vas7ZG`WM z3OWrq3t#jWj({OsuUlPcw%#aNuYw%PHsB5^J!IX3^~F41DJl1!<;pvjoyY`aiXy7B2$jx@Cp) z<#SbN`r?rVip}@e3b5bYuBO^WqKm7`#e?a9Qk(}C;=`UK>SqCWE zB|U5(*!@<#hrBH~Au*nz2b!1GP(UaZn0W@;6{8Q0s_xepIM#t?#vFQj8;C>}L%c1y;!p@0teDK;iu618ns$w-;cPYh_!nj`1j}%x2}<)MCD3MO z(41Iyz+d|!BbD#KYoCNEDAZQ!Qa;t?uy zzR4@3Bas=xa1mr&tq2?OafRtDA>FT_4TfIkrn>cx#BQJY{+t_I1Rt!^JjNxCWI}pb zER$mhKG%Gm`JT=r%~uGP&4-1emXmq+77w=TewtHUFX}&n?LHK8)kV_kgy6PZ&Qoa% zRSGjiyJ+9*8Dp8;74^(jL+x;!fTJ?LSBe=?p^tVc;lrsvRi`;Q5KAbZ-h~mXxT=( zy^Nj;b4nOy&;%38GRW{VD>DW4F)&!?{>;H+k+@Q%m$RWNwt&jA5zEeM%zt7BH7)>F zzDUD{Z=?63JlujVNc?VfvjR3$^r1(;&cRO3(9t6jZ7~X zms2m1OtTDHI~&{@L}@7S0o9Gzyr1i^TZ>%E&nv7uIDNDq9!oYh>S+I3fmkEmQ2z`g z)osD7%U|x(Smb=rGBcxFrq(63BhCU3Wq7}|`{DB8UPB9=O*gZDPrqmbhlqGK(`Vya z946>QBI?aXR>{j>H?;5=@ERSBu!sp=2H{X?t-RdmcIOqw+E%3A76xvVxa@tC8-l^RlB^ z+Z=)%tFi;Dkg4*0r72M>rdhf`PWnT-Gx$1IvV%{hzbL@JZ?-!J7!Jc6X%?cIzi;L< zl7?v&ehH(EO$QP8OCDp0oYmqd`-ZfTR@6FFqjzdClJZwD4^~m-0Z!=o_lm@{d{@)M z{eJ2YP~+$1#VM@fIEs;@G;M`*LcDlar)lrKX!SJsRa5l+aw}&EVhydL?&x9w0E-v3 zu1PP7GFZ?WhSW#}*i*w|SOy^?l=8<~{#eZ)`}p9g86`$RF%6!DB%{;{JIybl)L7i# zo}aElY&3pKzJ2lpcnJYU#f z52S^VD{N$QUChOqi9H%|IoHHRU1hA9MY$s@FIO&~i*C6e7SNNqv0W+liKMS!o;I~g z6|f9D7fu{Pc&ryD1r&GttSU_}`oSfBAL0U!1L*uRaGCpWqpTc=e*bI*W3a|`i+i6h zDzpP@hUTrVfE$Oi`FbHeyXpVdIu$RUiHH`t)Ig`|v(9MvQrF4x1g49&4Ty5$^?6vJQ8Ly_QK8R2(iXXNFR0@?5P(vtTC5-_ButPjBthp2pj}WJTrldS0Yem;G*gvxb?|V zI~(VqWN5*H9$0C zetQnKevWjrP%*%yHK4@DDn0VCf}eqpJ)m@0CMu>X!VfZNCNoQZxa)O3$dL}c;Br{3A?o7x6)+A#Xk|7gtz7$Eg2`RT#2e+I$?kZ1JYG(A95Itz2 z8A!yapeW#7_uvk4OCSgV6_7yK7!j3&%EhDGpxcdZ6;N?YS+F_3-~au(*IJW_x({Ji zcYl}n^1RRedEV!>3zb9o-E2pi*QT-cGtsz?v!=Rpb@BuCUE$n_2WfwqFhRbg9DLf; z`%1jqz)2L724%~C=tGbvNTnklLf_t?3cl@?rQD83n<5oyhGOP;Rh)RGQ_{i>uIIPl z--oi+$uymBfcC?bq1RVhxH2J}YKyBei74Ii+jw|_Ni4{r>f=4mQ=lY9FVg@Z5ez1F zF`#p-3OctDf}-9qXT|~!h26b*HEY7jsJ*riG1BMbB*H8w5r$R1uKJ8CN3<|og%l@2 z9ZY=!4C?&kG_=ci+&t`#r zT)||F>t!{u4bos5qLhirpE(xzyOn! zgYVKExhPi^nca~{?#8bfWwF`0Q5~8Npg#URXTRRKcS)AKcNkp?{<_l~UVd)0k5;EN zn-ogE+hOj{n|9f<87e^{f6ad-kyG5isj2%^%Ee3S||N9mbklELeltBl6( zLAzD`KkX-WMvOZ~tQ(I|J8!aoAnTD)@3Lka@pLCc#8lHPPX zpAdjQA%L66!;f^HIbUs?u6DPd4$aMbrDFK3*8}v57ND?%VZ0jWbpbE5syo;3K~N%(xR+JzVC6 zLk`*MC0rA@4r_1-rDj`AEEXD%r;$5bZFVG{k8MG;#O7M+md*Ae;GOx!3@5UWXw!F3mR zsfa&H%D{9rdi*LvLHv;z7(QS^W;BSHaQwARjvpCUM8sC6NvAWB5$EV!ycNG3TyLrU ziMn$yY-xj~x0yLVcR9DvL?MQLPz>u@M?)cB@?!o;@wlS}5OWIOKYp88EVHK$uwN`s zk<{Hn;vFBzQ%<)07V#x6mf17ESXaZ{tQ)i}(;T!|QG~ijo1}=*Iff8SDIKH}vl2o61CX-$)sr>;nlZ zUkCxq9XeE|CGeXN2W1!gk8=YyaPBwY2U~79jDIt1E-Aa<3T&F)S?mkQ1E#+A_#IK2 zo%hsiKw(st2`pi$egy-So4X4v=8#Jhs8sQr0`a4+$thN-y!*7WhJcl+z6lmIey5RN zTr@2is$H|?cX15ZO_@+pEbxrt){^GBr$}@wgE^}eopKr9ryV*d+DDi;2`-L7mGXFh z{(2v=R^I2beG&U$rrVROLe7)tlfV?nn`ag43N3XEo4kA-Au<6I#8SBFs0`y7BQ z&f@eozF-BH+wCc5oQlzyx6u; z`5B^@&Ss1wQuJSAs;gTUVK#tye;vhk@>uL}H9GvzDb+ska_aYnBX?7}l^yXZ`J0Q_ z1?j;QuJF7`| z0$7$Z^gL4-?73RNM|eO-VPiWT85_u9dG$4F#xWZ7+&H`8V|^KK^}M)qbRxTtge`O2 zM)Y-oIxE|71uf~{_(F|A2xQ!aR+F5dQ3zZkQ%Gnj#Z+kwD3W_4SLd#ABY17JVMC92 zDN=>T1Z$2GUc}@hCtWp0&)(Sa85vQDQXNb_PEM#vPqb*SKzSzX*!^*|*>%H)$x159 zRr{Y&?R15grHhxEW`)r>o;$thFs=kN40rfDHX2KRn%^39TMRkSHXw>Y0sLgCw#N=@ ztUQSs$NGCZo}qYspyyAMd|euw?>|(!=^G-M$4@>21LXjLgy#wYW(ZSjhop-U?Z#T8=pv#of_*Ev&Tv*>{11Z@vT}i z%dz-t5^D?ncA<;LaNm`?4TF-$Wm1? zU(nwPcB^nQs*z*`cf-ivT?jpfNeVsctp%r2A`2^oqhH z#2K2UE9>>=Gj1Ld0D4StXK|0LTV#=}KSz&tasO4&AG9!wkcX)-5IQg({Y5sNpsBMb z&0PoyI#KVDmtT^TMLNHlh5Gbpjd)!+qKojckL;h=(JPdqr5OSYF`{Ue4FjoJVK(FM zgJhKS6f@;yK&zSz3=jpGXFH7McUWOSg=ag@HLIKZk$S!~oFurU66;8C*d|ffAJlZ` zP4-xTIs7YI{DB^j(YE4=25h1-iD=2dLOZEf1bhc=lk6Xg)F?K0Fk&Xla>gjv80%&r%VyB#2)6Q6sDjReST=IHh8G}+%TuX1rT3L{*%fmF0+9i z!4sTljHUQ`y8%k4dj$&Fqn1~@d~pfc*teNtHX-1Ral@zp|N3= z>>u_M_Wn?foT%E*exiaoQTv(9gifO+kYp0Z?v%3NE5e)yD}*>D+7P}$u@puaPWE#@ zM5{BXIEz_qGQVX!!E!y|=L400%1n08eM+E>3CnOM%T$!53nS_&LpoMxK6#m%(Rx>4rB zXfI{WmnlP1V|1+CfzyTqBm||W)r$G zv#Mc4}FHEr6WD%}H5NBVz#!C&GWMwuF=hsNvCEhf~0*zI8j^0Cs;vQ3vJ0qSn#uTC4VQ^Sv$7Vg1es>*61}wpgJKMwb^Hy21wpP>^t?xhBg}IMX?1 z@N@GSF#2R{t&G_caHfQv(G-u8j2NV?p4TnsL4O>gE8{d1VXHx((e;%%mykW&g zVOubSF$IwL{a6#wjGxy#=lRPk?T6>kgE?au+8koJ*SoZamTLA9EwnnonbJlQzpY?R12V=sH27b9=eV zW^=e*?xL$cObI`zEahl`xakUI9|kaq2FPBY4HlQ5>y!&F%rj#|wH{`dF_1A~bXYP# z;W5qH2_6hDC7FvZ_nOmj3d!N>Y;m>o^VY)uBr(J?ykgi+p=!_U^EG)EX*8u!5G|!F z;IO@H%OimVxKDbdFlkc=Ziw^QpUc?b32*E)=pLT|>dgd|k+m(m&QWaOW1Q;>FYLpl z2{`CoTbtDW=-d!P!(T+-Bt zMb5DOgEVO5uj6x+LJJ|q|D?NDopcp>EXHL3>}-caF${L6Ckc31wzyjmC|lf%-ZOvN_~ zArC*(OwQfY64L_l+hjuRXfX<-L=4OyNVc(^Ko|e6B}orir&Ec+6-$^>@8pH`jyI`R z(6{ad80sd2Wc2Mb&CmSW?C>NG-4L2&Ur~2e9A*>;-H|}7#BdcF&`BQax5ty1Nbx)l z7-MZB1@|$}8RcVgYygFWoYJTHp$4IxXR8^5o0bSy5(gUY$e@4hvkZCx+eS(AM5~1~ zFhjt0u=u1r1dil_%k^2^(=VT=QJhRZ7{k@;_U_NhN~x}SMuF0~rAW38a#N263*=b+ zgl5`I&1q~XSbhksVBzm(fa@%yow+MClR5VxsNLa@_`p;EtCG{o$92_tqB*OVJjrJo z%|KoZsPC0sr>Yx~R7uyir^C}cF`AAvvscWmA*vgGo;iId*MJE#`XXlo{sYX77Otwt zSO@~#9W!V&tnVxhYTtA*4W*+4q_&22m4@lg?$^_N9@rCTl%2ivMN2aNaJu2LalWU^ zW>K^iD$#LfF6)K|uIT{C%s6klIs|gx&TeA*jFcY|iH~;uiCqPXeCg7-Z<6Gx9 z9_7Y^81C`*K?+ZEqfC<>1E-gW)dmCXy~n{x9^3+8oXj;^Q2x{z^Q6$GdiBWOlHd2X}*BZN{nJ-gz{9M^d7!4V_NAdCLm)h2!VP5=Ywkp z6cxA0u@GNn8nT{uek7p`afmBtKH|7=i_Cenuwd(p`{%1V9;Xq=iCqRi3N#p%E2Rce zR*G-em*hE)3o#Vpo{z)>k^#s*Bl>Xf1PK62R2UH2f!}R_xeWv$%$2W{_-c1WATg0$ z?HAwe@Zgd5Rua*6wPzw%fD!ZL(b#9s<>Ox}a{+)7;(Q>ydt?Fv$;KRn;f-dIKjTMM zr*43vd*?9U4&a3G_m6)oTMyxxU$!_^VQtOg{o|iw_sjEGRa%S-1D{#1j9uN0;{>*o z96z_{ZZ0_r0ezxOsy@;FA9K!!>l9n=MtoaA<>2Ws&kT~9)Dx0#E*O5%%9fqvGc zKl+tYj{<$@m)m;IfV!IHqI<-4wK|%^{e}7|XxRsV7-U+)a&GX!BHP8OB-mcN(1%dK z!{$h&E|+jc7Z}I5=zI9hQtZC@Iza%X9}b#Q5l+ng-^`O*~duwBED zLAOpZ>W-=~k3SYia0!%IPnRLzfj>26t9CIYdMqY@Q)BhSAnLPO@6rDipxQ9Ng;)Dmtdgct)Hi10&I8 zUO+J+qVhYdh3oVg7yl3|%&;5OKsqpz>zG9A{`hyHMyj=;UN?OlI7yRsCWYJkX2VuK z2J=733%ihoQGs@re4SiquSNmgN9}X{<6ObFe#D>~a|N-Q>{?)CwAn1pytVD%*$5$; zfl0MJ7P#zMCE@SZA^cef{G_khAkDs>ss5Pk3NZ)+c@q+TRE?-E40IYiw2*E6As3j z!8|CTVAXs5o#D8l<

    Y1oQ>%r#{=$HaHDyJ)@UMV;qYD?nd)SJK_;5?eBdWzMx>_ zU=+ovFTd_nUgI6XHsj5DyO!1SNk7zQ84WJVA!gLP7#3G=n52CIM(nAH~ zU|Zb`bEDc5(w=|VvtD(rH^aUWli}y6D1~u%s(iF$ygg70|KQ;)1QpUID}C5&DS3w5 zuz#GE8PMQ(;k#`LvdI?V@6+peVTxf?sScE_Q_JU6Bv%UDiTnun?7@Th(HDt+h|&qm zH`jUWli?^Bc?r3}M`6NXZ6O&Ac+4P>d4N>03Jii#AqY6(r2G^s238^H8mZvt!pHJo ztlNL3Y#RP6zy2j(Sq)`KMKurB#k3sx=urv~SZ=`x?UeJF5idDbK+nSVkn}yQG78cj0te!_P3Hn5Ab~~tToAGE;(O8Z_ zb_!*P4QUl-fn{(tt8dl??~*a+o>96xGCi+c%GP4{jB>G=Cdw0cBtM_Yqvz4kh;})E zIUPGgc9YV%UMPBoc!eq0%6P@O^X$&!l9?7pB2*5V5*lnq%^o+C>brtvPy<6pT1I?e z!Z{at(f*tBq_^{d4f$H56ClC(zpmg}W==Nk*fSlJ8n%Fx+s$73Bex+CWoLxwC0NRm z#)}6booc_-7u>klz7a>Py<^B9>8;<;d&LcdmzvTQODnXvE+$658nj0=XI0q7r6f$T z{I?YQQbl054W7nzhBcusG7qyqWyE}_n#?a$rSe7kViI0vh!Tg@dO+cIe^GmOdKo7T zWal@F31k5VsCEPhUIv;F4B*%Gz(W*88eZmWo8>8N3%8RZar_1=3E=@&t3g<(Q`cSn zgv%T*4$-dm(H65$>F&;oPw4GC&4!vaZ9nXsnF-j| zlsK6c?oC$Xu?iUI9!G2Un<7;O+eRfcq|!9|V~G!2jR5^)SlP=X=e8f6i}Hu_{2 zU(K)_5y0WdcHky82_NfRIW51EkAlqyL7@{^GL&^~R`<6bt>_lc;484jXxRIBJAmvw zIG40{0^3X3$HSQ<;gjM!Y>u5{*F(?%_QDy#Ohh%K3463Kk3lJ(Ds{b|1F54y_Mxtp zpt)b`lSCvrLeYa6(Fw3?5IUB2x-Dg44a{`bK~Nsxs7qMAVu{20VA34<;uv(p;Q1L@ z0pLo)%{&xLJK|Z6BNwVX%|m#e9^-9_eZehNqP!~<|JT6`^!`>E} zi@W`B(7@2H|YphqQaq-sm zDX5kXuP@`gUNlHL++)`ZY;-uGmgUD%%jhxGLWr;%sY@KnNl`Di1xh!2I=b1EtBmOg z=*nP^P*~XYdlDV>D4~(h4?C|Km(IL&2F3D{4oXMKc~GgnG)40$>`t{WHn?LfK{y93 z!W{2sPo~qbFug++g#w?=(qlV-2A1%Ga^iq@NRjUlULTN{o#|KFKreioIt}U$9wW*s zTFSIPym@|lZ113mRhz=tOHi}@+HZkV7Jq?Q>7IULrzqh+goy8PiyJUz3()t5+X_9- zi#lrJo}9o-Bo{(@AR*yZGyX2vKea1p$i46|*9GVZg_B98>^9O?N)2?7y5DBDfg*)eqvEF(tvZ?}cpSf-k(FyOL#x*q>FK0DHdK@S(<4R}U}cdb4S z_^qJHp{t8oT;DK%HNs?kmrfqFFUjr_QYdQ7WrHDuWZ zJa;9O(xiRo3SE{fpw~j&-lZDi6yNy6H6<{=Ll)Mj0v;%O@Ad7#%EVIfT_3L6)$w;= zD+mo5KfnVN4iSpux2;$pW})3_HNByyKJyIDo2*;=`Crj%N$92!l#{XV9Phi}b_k7u zID6s=X@BZZka@(1y6Q{aBVtgRlnVdbr})veS5b680zivKKX`D(ma{%f?d$J}s#lHQ zTY?@_qQMhohR-_=pR=+VW``s?{*k2M4(Obp3&^i2N+d)_M2*!kNDY_YS3rb$Knla5 zYMS~z@;(~dx;bs7{W^w}ptFmQOZsPOo{=i6@f-E*{TGI%Ba7>dEDZrq->ZtxqmU{O zy#^;R^72j=9tJmSwr!u3b}*Q}PdMM=)iNNn~W!qoKD?ea4zn<`WSD$ zgvbL8l+y1$_fzM34*Yv}g3EK79!=r*&xhIH7z~BQRSZ7ts1n+6N5lV5ZjJV%sPxBw zX|Rj5f-Q`JMw;rX`uXiwse*H?e!ko&rPCK-amt{(>VAc6cLL2Wdqq+2DgH^O z@PpFL<=Bm0`!QA#xk_V{qGepLUuIq0Jbjtc6xi%)`-%Ai4M8^=KfoII6}VklhaL;h zApUxB=Q#x7mdeIua3k2d^PjBsGXF2uU9xql>stg&4T-fix+XdMQy2}_A*83~Dka8b z)hM&fT7A+Q)HcWg<%)_ud{EI|eEa1;vJM*f*41&7a3f?(xqDukCc0M2dbFSXPf}(l z_HBK+?V~nce&YVrJ?Wx!;F>RjC1MJyCe96zE|q3*2r10v=A-ey2S)e56ntiop2AY; z6J|GoCSR$1r6iQAF%`5KgTaOk?31v(Rr%ExsCL|YK`3(pp_g;u`N9zVGq5l#{wBVm z-|7QYS(JR2e~dlZ&2Qx{*phegl=M|pt znG_Ur?0{NrcOl>&Dl$4?lS7W#n+(+6_}}BSG3v(<^nb0Nt9Os98ckFlLH-p$*sQSW zp}?=qM9Hg0nKgsqT~|?D!3QX#ESvi7>p1)`3wJ$*zO?xDKYp%1UCIILRq& z3;bq0`in{ii(YoDuft3wYQrdS44m5E{|X)rFwmF9l@$zjY;Vi!t-%}k7!_h$ujbTK z>hE{LOzWsSF9CV8Z#euyJ(y7?^f%s8QhYIZ0VzU(+4xYFi2x)hDfd}CR6URsHjs(` zdp1oxS9&G5K&f2g^uQQWqW}W)RJl{_V%^4{cJ^`mEvmWKlNx4(emKBITyHO_&w}=+ z+@$c+p{m+`51?UQc@hXYkl@ECouD^&eMHfy$4^oHh(7+s{_1SPTR+R>hcj)EIisZ@ zj8$Z;(8}nGp3!U=>+EzT)U zmNBb>*9k;uR9l!bJYsqLgR9fk@jaYZ>%@;C1HcNfMXt9=k7&%A1S%q=e2HL77&zE8 z_(B{>8G%J{LyKKbM6GOJV^{)=@+7G@#32_Kk+SJemU@ECuap#c|oofw5i z!)cIw^lm>^qt83Q1N;!2eJIf>z;j-aLzT^S01K*Wu@ee}l0#*PrT7ZIA*R^L(tl-})%Yu8u|I2pJ6AIn*BR8iD_ha#cFSv7^ zDNs961Zp#QX(^AcNe#P~r!3t6((!*tb{sN6Ky&YnM#~oBePY%?vOPTzki+3CdkdTR z0$(7(aWGR#v`Y%QBr2?xWo%50a8WeNnIOvgJ8Dd{L7N>ma7nB=B>iqu~ZG}(YH zd7@;CO(ydEzZ6%QfPIrX3=O1ea{9?M$GjjA)l^LRe%lJj4i8)mSwKm&X}W7^rPr%?#+Gdjg#_PtfG<(I)Cy6GFM% zfwOXl_ZS^;Jyx6JMJHV64!dH_+`JaGY548x0nx^_C5|{Zm7qcYcwoH+mL{&3qtxIY zgyUjEy9f|~_}kpZ_h&qpDA5g&8`U^_cW*A{4R`*)wf*D6->!3L4b=5ToG>tB1V-i_ ze?3PA6oVum)^AxC`yVOZU{zJLuq1)8gd(;9y%+Lv{G<+g8j}u=0{AvW%bt%Ls}@FQzFy-YuR_uXm&Y4x7SfEI?(( zTB>C&$pN2{fw;YeCP7zI{f^a#hi~d;|NWVlV(E$fX1Z|0d+)sKhKH)VukAMs5_09- z7}+$xd(eX(+)CVX|LT!x4cRn(o|i((VLk051hk*vo30Wl=K?WZrCg2Ug+Bw%l8deY z5PIW3cdQIv{Q^ZX&UW2_h@A10MRDG)D9+5!6vqZG)5_MV2CV9S9;bfIm0@KI=f=v3 zdqt_Ma||pV6#Sa~_D^F>Rqbb?Gy%yUk}he|luJ6TctZNWvOcIcm9ESCJGEax47Pm0 zN$acYDaBvM&(d)(G!P|CA0E>`&SPLlXSBt_b*aI7$R%v|Ly{i$6lsRV6!qyqUPSX-!fyT#l2IE zTAf^mTlSO>ydUlF(FzWpxo0OGRxK4?|DYCK(>U#x-^G?}H=Re=hd7TwIWdOq5>T(w z4X`=zs{O;ig5{#ivBq6ZR7*-#jAA3|wQzwC4azdhaflO03>DSNJ+U5#&I$h0V? z{JO6CMmC@X-`@MPUTQDCV|azlfm^D-bQSftH&>hf=@FR?D)jKODws6WSujb8n+@ul zRPmx!!>3feD8?g} zjclCdZg$hfU=tm6ho zvXp87vPrfbBZIzJjsH=sKd67#yfNe$IkZkdXRDnJ<80kyx5ln$W`vsuHGv0*P>8#^ zRdNgWMFftt^xq09IESbZt6nhUTE@cX*SQ8$9%uLcV8bh+849^6HqFAputh-K}#}5Q( za89=ZGM1y*S4xpSDSuqG8Wi7unC~5EGfyaPKF|4fK{hBw<}RAv+;1;u_{n=?xUfH` z1*18~aJw>8wcJn~AhUTT5<6crhH^EBTh;;4PUI-*4q+w|eMZuz+WT1+{m+n5Ch&(G((}8aQeu z7+CVhf$sP}4;6lr8J(M`OtYf?o9eSvH3nQ%Q&5KB62qar638e)-2QQ2u5{k@XpZm8 zQ|Nb}1~t8M?h!IiW2mGnlZ7k{zMYHcTsPw#$LLAv2z2o(>1y{0oPgd!cwq{VIK1Y#md;%)5X zPb`wL$g)F~wE_C-b>wmq94~$3q9W zJO)OWguTY6;xghZwa(OxP;_Sn^Z9`_$%%`~s$PpO5)-;D2JP?%2HPE@{yR}g=?;ltHkFs0=i z26yQb(H#I#y*=$EJpoaf2m&Zecr`HKYqyOF95t%MP~dg|uFv-CA9QyqV;tVXSoHIj|eR6Rd1juB;m%7=MJjrFvU_fBe26r4&MQGZTmLsJJcPB8%f5D+6N#J$0pk zmK0>;N*Tmb`&VoRchAH4t5CB8f}GA8VEIjiz9a`I&y{sZg%A9y{PU|W31YB6K7-$^ zG&56=LvaB*bC~e7IDC+S@ZmwjtBC!8F^SetPwO-LP9PLIH~jMWZqB7=Wa*bC1UOhw z8CmN5IRi=SV>62tsDYl)(&>fldvJR`&de&72#^sKQekMqC4tU?G6htWzVW;^fTpS% zcQp!J94z$isVi|JGVXeO*KpgD(!FZ3FCVlSNJBqJGMVYnX28NN%_v;c%+@Dk>TB2C zT=+y$PMuLVP^ZC!Y)d%suD?y+1##c<&qY<0RFogI^LyL5GL%7+%Q}j&0d0(#OUxMI ztV4WH35FIRNzOrOFj9Gr%Pn~x+M%=%YF!$?Ayq(7RJsjxgYLYLEH;@N+P9RI{=(P3 z_EHb+fCoW0O9oQXy9&Swdyxe2m9qu3m~=rN^e7`8%SG?5hu_y}?sQKxx67+z`QL~K zSU0`{&y0XKGs@4w%)=$Flk7?=C1wx79E>63FJsofjj1SyVb~%WT--k-^W%`F8)NFj zADa7kU@+v_sH2%Rxu{LDQGVfa5uj9KRp^)s0M$`NwTK3y8M-rZcuWWF@5^}C`SFJ# z3p7DhX3u;v7mf3?j5tu!*W;BEpmLqfE5V8RJ#)JrP;~AEQVD_&C1Qw_B(BX}FmXLB z1dsuc%?*bUi|ax7E*|Du<URxQkY72TsB$$6(pc%`3#K#=|Fz zUt3Vthy9JG@HrwKxM~7YPfY)hbC7mIk-}W4Hz1YL_aYjCggpG6YboYj3{ zJ_9*Ffesp>J)A*>>B!Z;mXmIv1sG_W-jk&Q5-4^cnyCx&{}NpbKsfcXte1`L*$R)@ zZLW{87iFUV=bY0F!WIBwDbFW^Vz46{so(_QVdrB*O>5s5K8Zr2>Y~0Eh z*v6Co)Zrqrx_K1hs&}h1%IHX8q+4MkbIX0A(lgy69-p0i{G2LZP8#p6{ zpj%LxKdHI0c5k4YauVDLf$rtu6di`&D!`EFYRI9~E)lVGKdv%b{-Gs}`mPygKJ{Q{ z6ior7{I}w6tBcq`1H~ET$~v-9S~K#UpEtRIU0-E6vtDgIIS=&NLCKr8XJC?zUM2?Y zXx9j1gCyrgrMMBeaBXxGe|B&ngwtoXpemzq+N#>XvG_XDttU`v#%CbCaO41?pBJ&= zNxj2(11@la9;j0QJtY+ut(j@^k7=^eYQo&RO^v(boOQCDOtqI0&g!lq3`~r@n@>)x zs_eFc(e2q*U?XfuYtFl_a(596kriIPkw+-VaC@_hz(tvrB^p?PgY=pBq724M<6lY2 zr40eF)C&W{z%CY%!A2~}mWBJu_?;s!EK~Ea83NU<_yiU`&VK-xo%1`ZdSRuvyxdz_ z9Q2lYeFBHe?PpQxn4Bg)!9Biz>@H}*@>b9cY83d%Hs|rXN?NML zb4vN6=}No^9Fo=zwv2s?@kmFT#$#JfRARCzL?c{Bl%^Ts)E`m_KtU?o($OK>U(FoL zmfuXUZ?T;bG$0zBgqI5^CZM_5jlgV`IZOgT>$vruV(G;Ep>4pn(>*}aJhsP!dCGI9 zPFX3>Lr`G2HZZ|p2-}vHG6KSl(2SP4x0bEx;~JSu40dvFpLRqwfk`;S-3?#BXWV3a zTrWNqk`rcxw`WJYcr!I`(r{U|wlw#(p5fj3EP^dy><-Z|I71uESg((ZEUl?vW*z2R z<>H!NtbDAu#noQK$Wo-3O#vc4t}pKPD(ssHy1jh^0^oyOGc#fP zz?xMge1T09EtVzflN*o(Z>|=HTfcq%KfqsQ#{(gWk?-D35n%wv!h&nJl@3xbqNgEI z>-9zDWpGHubeHKb&c3>H4Q^N zJY67CAj)I%YwS^5Bzq&1P1OVO_y^*x^o0-kb2YDbxHes!uELdViyZpd#se1luStq1 ztIYVoNKn=-iiuHyJV}{=kz!&hvc_N5X9>&!nf@pA3@lp}%zk1*SP(EF1~$vp9N;up zbyL!LW;LtAm}N9o`+*q5?X??<+FtuqtvPOuFw=Qj z)w9n7o&6q_qBs8N3JNUa)*FQz*^QKEJ=32*qb`tVbQz^V4{1#gC0zf#@%v?PG{0}k zpGdT5*@p*$x zk9h^ji6{QbxrSJyq5;W*e6_T4cc^wW@wzyKzIzDtRBdwx|2Hwbyd}7Bp5gb6`x6xCLc#gH&uhkX0JM% zp~#U(=IGX0gg>FUCo8F02qr)ZT_9i?44kgeAy)3FOhbDl*< z^U=!jRlsJ}YTC~NZ`>?<03zb6frkOdj}rR8xx@v4nsK_~(DL|)*^k14*oHi!9Hv?N zhg%l#Kscu7(?PQFRu~!LsGu3kcJB)25z&2*yT`{RVLd?rQH{=gP}9=B z*p0Q%Z`q8+$+b`>-M}#EuLHX?3Mtrqj)h!* z+;kQOcdLI+#Z$iTg z!{(9#&r3)vz1m*k*>Vo{r-`9pkajpgwkP)gWuN2?cN*Kxw2mSNrtBv?%FU%?^^^D@ z&vKm)E;i+ZG>0qe*J2Uz6PY+JR}X@3T%q(}TeX*wUxs&g*nXMdBO5S5F@~6=vtdri z{rHQo?R}|Fc>%_RJLsC;xAJ{xO7HaYYkDv8hnYD2mMjc*{OUK@00`x9>?2;#hl6>3 zUG>d=T+{ou^6^cKW@tvuHDFQc>vVlBEpqvq-Yw1Lp!CN0M@Os^JK+0}9kxw8<`k); zR-BufQJQ&rodE(`-7Sn%Rk4$NUsiVkZx0#LlAYqMk(SE#xal?SUd6S6z@VW%yIGG? z&KT%0=(5YZu^^q+ELd*_E-Fd0i~wKmIUv4A-oct^y32)PV~12C5tZFC;vSL@SXbjS zE7oM`S>f&Qgdm{ed4rE+uq-!I!@TT_<&0$ZP>eWY1q&VC_`G(LNlIT*?zh5 z_`&h?+V&o%Hfk=P^jJ9s0qcc&V%&jd`HF+9JxmHM5@?mZH?-4xVt>7y^c*Nq8=g5` zsTb@eVG#Y(H5IKv*L&*b%9brDB{8GB`JDjhQ{23RPony=0a2M%Ggo7L6;~90C2cx; zNYO-QH4_@`XRx*@g_C>JqwOj~YmS-mB{M_G@2t z8<4J2zh$p0&%0#hfDb)k@FFQd{WHqyK0wD4hbI_AD*1uhGG0X9-1L~~X;d%aVyB)_ z3a_eR?}C-m2da98UDWZBdt0yzPehT*dZU8(G(x`XHLfmd1FK2Tt9?6U4TPl+zA#hk6)8&6Fl00ywEi5OehiGt#EPgp<(j==76W?{Yyi>s&4F>(25C-B#>tK z^NCRP0pUnD?8*7|EZ~;;pf-$Ot2#oOeMl*aN*Os`EBOxl%epO41^eaeyO>mXJ8NE6 z3rmN^l5CI)4uDmDp_@_HksJj!1KHa?(e=shZNg%eizPtDjl+2Sc;{O|O4#j{3@1#s zL&5Oo^RcJzY?Dv?x>0PnReiE9vh0cQ-7WB;yfOYs9>`pJ+g6Namwz&btQgBJ{gJT9 zDYtE{<|K}9

    =Pt~n1NwlDMC^i@7emJ7qa*7P4*hSZNYBbe%45WfX1D<%j@vUokEB0EUzA4xnG|tc?}yF7+*syNsCaLElAS`B zWdR$%LA+>o7?0&Y^{~G*Kj;(}&rAQ~pBk~d53eqj;Hc%xvi%vA6M)F2&HCLF%7e56 z_vg|sE(Mx>b5|g_eD7)!(3m1er-{s@*2lk8IP`d#W8Eq06wb-b)upo=V)k9w(0$6ih zbtt05w!PR%RuNLiC0^Czlqsd80z* z5zA>Xblmr}7O(Lo>%Cj}g-{2A!|{I{fi2~U$sU<}_Gmwwdp=k;jGSigcltR)KlG2l zF=_F&ybmBa-Q=}(HlyIZDe9QPE1r8~(T#fR_Lj}#$RyOU7OmCg!fGnJsZGfC)|@Aj zAI&SEtnM|Qa+*DkKkH4-<2N(^cf6SVPjr~;sw=q&PdI?%mSN_+E%6=D;5MYC58O%g zRSCL$+mMZt)ZOqO!g8luq15T8=ihic^m_@Viiu24E&yAMS>S&+Kz>PsL--}2np_))1Y*4`D$@WKI+-x-9@Czb3<_zd*Gz7x@0m;_A;!%v zi1zz(7#1Fb}Lz z10f=_nxzaX0Po)z%{+&EMuwBM;1Jr0UE>+|Ya4*?8n&Impqq4zl&ge3k)6@I8+ zsKm4@?47Ffh`{RAgNkEAdlRJN(o4o~F?dG9-P@4T+xt^k)79ND`T!dq5opi&06Uhk zUK9XfzH3|=+aqN63V)V2x*4ovdR6Xfv??G5iAG*=y} z-n9ttchZzyquL$10b7RdvXs~GiT!7x46IELw|Dbe!rVu-^iNKaoyH13xsOu@9|gwt92YkKdq;v@I=g^I0C|C@g#6;mXI2+Uf$a$WUc z4x|JpHiZgwbyd9qCbF}P0Nh?anb2YK`WGiKt=xC_dpa#qy2o##!selBCuP)P!YM6^9O;%1>_R0jhbquZ7n|BUQZqbBCIu( z$Ng0bxVG=Tv;F!AEXs&K$c1kCS-~}mxP5r>1Xc9bsBrcW-}bQxgzo1H0qSg917aeMh@8#y{oEl{03Hjd^Z6`~-yKgs~ zPigKKMmjdcxp>I+oEK(*d5`rrx*#ST+kB)_|9LC494oI3!=0F7v6)ndK)NxA!V>%CW_Msk*wraY?%d)tpBeu`)b(a%q- z?E8IY=d%`4d`PHYv=<)M8^*^1sThvcHFPkl2Mjv25SByiAJLC0sr?1MPkZW;kW$hG zg8LMDm_DPuuag+uU1`x9x`6iz3Sje$_1=9{)KSgp5+~%)mQQ;NQ&?#)0gJg?xJdh6 z+;W9AEVnP`5Q>+ZBhMP^1_Fo^i=0FepA8x^E&=#)NAO2bn+j8~{OJxgU@}&Es=^$c zhnL$yf-#c0ehl1y<6ldeJhK3tvKIkdsJM?a1Mfx!P@!Np_Y_*k_oYW|{NRxLoHPh( zYvX<=@8{`jPIAU&OZ)AwK0G*~;AEEILT0(r{t}i^;<^QvMN~HJLB=OE6rY-VyBM{R zRG>2H^E+tC#MSOLmx=^Z*%sO*YEwp?{5F3xFD`;T3(xWtEl9p&+cS;QfPEY%FS&+9Md=t*<)C zl$kt_w<6}}df)HkDzY4b*qI&lz3JDt2ju2!)8p-Fn9mLw%0-ilu;W{TQKouEDi9`v zMRAY42h{fK(4#LETzD3H+S^>jk*v+vUsWHN>}!s%_f9X;Y^!R&3XsTC)gv!H3qrt7Pqe8UnaNSK7h)u-k!|47Z_gP7SW8QY)OZjyBS>{o>l$D)5n^3}ow0TOB4*cbYu* zYp0lKj_pLL*nve;W^bX%z2Us=eWwR4uUX7=uXt=GNZr2j&t#})&=P`Dy{rKo ze$s=WTb4uk<=&E341N5v;iTBb#-dc*_|MUzhf@pSif!wx z!m)>EE*}4c)%dS!zzdEGy#iqh+m7bxT2FVerpYu++09wXSl(7mH3m_tB(QWG>`h}_ zP*VWLQQNL4a88>mq$b)AhD7>lU>9!hW&oefRfeN4V8wK@0}Q7;cu{kOYF*g8IiBVF ztfgXiO(fw$7GHV2z0h_t%?ffVVY2#E>VZ{W(=R$;^iKG%j60jxq&kq%G# zyd*rSeS))Y=cdbMr+giUbVO*ga}tYmXLC{Z&dw-_wY_NOzri2Nfu?E=m=zjP07zC8 zhYqnzssSH{e>N8?F)t+f$@6!uNxXa{bEN=Js zsnH~w3lX^&aMS=gI8ru+l$jd(e?3#UHf;ivr5-_V0Z-5yBI`K~qWvhBiYB9m0#1{> zdR_G%MHi5Qzr1fTeW{V|o;1xeIhA|i!}|c%MU#DCS#z1YrCYN8F#75DI+{Ot6 zpk>C0OS99i-a5kmQ>~iry|KBlD65uCf+nf*F`O4|VH*)Rbo7MkmAa(Z5 z-|rNca(e4Z`{~cayyAF6S-Edr4U$IaQlo3iFs@3Lz z@%>h`g|Z9Q_yl@cH6chL{b8n^gN6O`gz+S2(DQ zNDf2|dHdZ@S9~qJWD1jgpGs58)fVi4)bKL)XOQ``hiCW!7lK37cii57xZ@H9K+6H` z#YGCTyWsJ8`^9B-NW;$Rl>Vq4b=G2NQ+@2=Szhc4WO&YQ8zi#pqRJ5u6Df;KaHah! zz8#jPWc7PT{Heo?)HF$= z@y2E#8(}#cSE*zKz~;QBVYsUqF-qg`v#8iE^>cxM*?`)G+Z;^e{Uaynozmp(X{yL( z^^tk3JZ>fH)PBBod%c*GLx?*t}O z#UNPbSV~-}(MYj*7?q`fx1L0i&OlBP%6ui*DyVtu0+$I7^M(q|ewxYk3( z0`9;Jg?<&zxTwbcq$l=2zBrwjyRd#&;$R(u_EcaLBp@NKr{>8TLnC6@Qifu za5@8wG?7s2qS>R{SNICua#4t14kmMdUvp`Dmj=sgc;9J9#YpZMl+%G^(@P3QQ!F%~ z!?xdpKaq#JGk8k+3I~5^m|~i+Qt;200;qDQ0~Rs-S^CyFr@l6QYWo2G3v^}@5Q9=o zy$gV7!!qdU>L&k#GvX~|*EwuJpJ;~!Fc0M~9<`saRxGP4(?~>10!#=quLx0Wju9>alVclL+UXpe*k0Ntx>mtaeTJAo_}!c|4pENMYG3hbC(f35!VEE0cnUpk zZmRe$BDK7$`SKnZHC@l!EWe*d}vigPW2ONiU$*39THd zrC0b`(k5oA`fEMzD~_UBH0KjXqi!`%H83;nuf=iG{Xlv+|Bq(w2%ab>F&0jhoPI`x z*2vaeq+Y>W;NJ_R#pbe|7@N1l-mrpPdxoO1}Dx1cYo||)B)F$+H zgTII_$m!!KTcR{&0MBX~_96zS>3Ip9hxM{DN0kuZ(bThgJMBkcD3EjPa2h}JV~e)S z_}{Y1a|=5BAKD5FXofUbVeBp}N)1dZFb!A+)!EYVLeYp|!Y1zm{JYve%BGcGv30nA zG+p-E#)q%Z-lv}XYyBlKeFAWSC=t)6U?{BGR^sF5j7AURb;r*E{VC;m_jnn^v*4Og z9#t@Sb)l_>G{)T{G*$znUi${XOpwpn2jMo_?{VV5H$ym5#*y3ekstAK`{}j!=Jokt zx3-aC9Gp}2t*3an{q&VYsyOtICh%@!zr^ds4He1wye+ z$#BZ7O?5grshtxITmbg5JB2|8v00B(I_qtigK)d`y~YP##BXZ(2vKwG$KdhHbq$>S%(f=*3pMmlTmc>BQ1sn(emG6vCmhwV~|i6We| z%!EAsjKsn67=UpDFCVLZlm&-LAbYsxbak~s;N!O^*Q8rl;sVTPAq2~UZcLGO&9vX1 zd3bO$yyq=^L}}&T^`cYI46JbjPU7X=ea8zl2o3{oIE#^1tE3%)oBoe8>PK zny#QpVisFx;qX%Jj3f;bCeEH!!3Cy~-B-7S({_x>(SqpuLR?NKZuub9pwiGM86m8d z2(`nzX}^!zUZ_(YVY68#S5y@N(Ec@eTwaO7QYOuECidDRY|6H@GI_^9E7@{*i?a^P z1ltyJ)+P_Zy}d5YMiTd0xH@vwKLx#C9O;Shf}4X?z<}qg$zp?$m=PWHECsRXq|zwE zc(72=0u%(#?) zuMejvuO%2OBkaj9D3m3F2)x1zSglep-mWO6=*PPH{`djU@Al`xae#@3{reY!XTM}-ePzPx4* zZo&2<;v`GY_fBI}ok~VwCRS=-!F<`$8*{th$j7Rirc3*a(^ZUL!ZW}jpphdpV(nh) zT!P%?Od=l*lF6UuYJsfmRXkOQI16PZw1n2thH;XcB<9k|s@BzRb4LM20GEoN2*!_k(<%!^B zJS*xnwYzPI;N${XY2`R01e{1yf}-s~!rD$z@_;uD$Zs|41of?G!JH+ix1z74CGq*R zOAqrYUQJ+dqSJ@bOw-H>E=gp4PQcyQkn{H7V*3OrDDQ%3%23=F00Pp0S+C=3mmV_d zS1(4Zzc8O10v03;3&_7OTo?8zm-g>gY3MgjVhWcQAy7dkrk`Z*W%R!Q`R)K2Z#%9g6~0g+JrXOJDKdlU z{`QqDkH*OyBMmwuxF9U9YK`>U*M3Gb$y!&khZ@Ls1BOgBXEsrT>$f(9K3*B@>~4TT zhjGH9#|DK$0&kiP>ggh>iBjJUH3TPDnN3#7y`QxsSr;?a!4yGIW@{*iDG@$0gIfot zX(xx;qz?9r&BCPCfe}!`xk-Elij9`4C2>zE@+&FEqCR(;24y$VBlua05Yv4i`OqSs zI;5P#@$J8WE`t^P1#f{V`C+c8C9K2XEZ$&R|E#CeDI}wwQ#i%LQBV6VW>=y4_1-i(4F+l?r;x@` zAc#iCP#=u;mNI~43(+PpV-ht^uFEE?#_!J4LKW7XV{&fMvFtvKhmza3lYAK`(hFQ& z!`cBcOz|ucb~Y=K1kBsJSR#gXCCr3$>-e`jH?$X!Pe(aHl=0%6p6!X*UA&&Q6$GKx z(ByK=QL7Z7;&;a_N)CY`whR~z)1FeBZQrSL0&}Hfbg;3$Frr~}5B|Ulf*F8?69PDV z2DQ@^vxU~!86V^ugDO0#b=7Nsw08dojK#p4h~o|E`A@R$E0q0%8bIuvTAC!3Wg>5O zhp;GT%jA&-Fj_=k$&S{%#%val&$wPbNHu(PS(@>n1}Xp;0$4COMbWNwht%rM`2#^1 zgTrB6z`73-wXxnP3a-e)I{ zR-+<-Yx1EJ*#j;jvwlrcWB68F!)w?X@37Db**zCELk_To-IN+fSI>*t^bb}#8$sar z=6Fz=vQN+znLNH16z`W;F5)?-wkO97@uewWNQ-%TOkS38O94&*mt{&>1y%?g8vmLe z8&1MhR5SFFT0Q(gJ+I-3@^n0BGT9awV4)#cC@(N6diNu>#@4CCqEKWQgZ5?Yh$N$! zzo)amj*IKu^A-Nz{#@Pu!SD6Pk5GWlSFjQe(x4fJ45LJQ7-_!g#>}1WdhyG$RQ*(Q zVF!dmF-L;kk)`Y|m4UvY0F(MY9-+VkskvR8>ODWW*w*Nv$4?4bXqRgs01+)SB0+>y z6X-$9l%Kk&Kf3+cEgIO`tBLO2UUq#IfBzV@~M8$#MQ{M&k4r6mAi&mxDX9hD^{?GpB>@|rDHEVDs0h?%1W z*;ZC$0Yu7oHzFr56Jjk@8?|B#62QN~`pjUdJ@c;qO~{9e_Av_oj?*o0!!?%KnQcu& zrS%0)ZY#N8!GhTw9HQ)|k0+-lZEgw&FQO2#x1=i2749Sym!Qq9NP$E#%1PJd5t=A6JZ3~a;=5Gsvb6vZz7-VdCXJ^buem~FP?EbS#~pFX{r?tFChvg4I_FW60ku~@O*p!f0wrtF164J z_b5RWhJUEqd!sFh_B?MI9-_?}B>d8o$~=rfaM9}a+b_n9+B0S8!2m`ya4xh6P&>%r zO1`Rgm5$Ym#&*kSsc}_W=EXtAtcP(vV%}!NuXMy^xcb1cqFn4wtwkEji@vn9WBX!l z|5Y$hQgemyj`U1p48WR*PP#nUjAa3E-2hH}vtvF#g*`sXpVVtzqElFBtyf_J{A>05VVTJ#2 z?~Nx6t5(@1#qT})Nj3+9d_8}^M(A`0-X>QArT#Ao67Vc4a^7TysTFBAnyn?Rt3XuN zY;%(P(qyN+#^8xhktWhLMuh-?k3mFda$Zw6eTmE#;AI^X+|sQ(w?=)?WL7`-K?!~r z75}z($*QxKT?J@2uFwW=C&h`pj0}PgHd-dd@(GA0IAIJD@__suvo3x{Bi+hBFF zLx2MeLrQBt$w{sHB1<5O2tErpcKnXF3>3p4nmvkUMlbJThYfg-jmGW}F76441P}b1 z8JetL;F90K?1W`83v_1KA&`1*d}ct>nBL7l=hUyCs8ML>ULFHmN1LcQ^DmHEp2~{u z)5{@(`3U;Qe8Vw6yJ-&(RTb5-6&p|(Zzzs>hyzx!KIdy)Mmj5`as*kZ8&xoU#y1@P z;NWr2LF%}F;Xr)=p!jH(Tm%5YfGm5)w>kB%itNh&laM&A9pbQM5 z?tXhPZwqRnZqP1hIDjSua@<(959F2pvr5+B=1C|pFfP2E4U{Iwr9>`o)41K+hCKa7 zseh5=z8H}7epc%XX+0)yzkRo4k6lvO3{@IWc2ydMwIQm0L0Qi8?j$N^K!>ssMjgr` z4Cg4z_bn*9JV)7ni<{s1=}MH-GW5UGHVXPCKS&3z)ppGl}vX{ z37A;@Vj`0u_SyeI4^O6ibzS$Dmlu~776$oW>Q)Tex1x0~aAVop=7W|JL`z^a(?F4j z6kdxsvvf5x8~^5Tn#@t@+j}2^<$8}={e=$ZZ+&RBw7~|LEze~h5nw>hC_?`K-~)PW_Q-p)-3sO$Q`OV|4p8Cr)RtrfM(u)C0*aWAmnxG~>-xgjeaxYlC)GQ+fP8 z5S)cFEZDv7TBSWgI6vW4SRLAHkW6cyCgD)H#Nass8dKhwd@l3c{oS=qz>%>Mz-5;A z+hV@}36|+dklx#@MH)jf(*Hy2MxH>)@(8IA8kCk_L3yGUv7L6KwRJWRNQ`m`r_RJU zg=~dyg#hKWC{QnelgdJ~{)CRy%Ei_L(?rK%HcgFD=*DEOHhPy(lba@ICV7cHcDb|x z95@{G$-L3E2EzTM?Zq}eAiraTzRM%DI2@kdVkj_o&byGwOADO!;%>d+H>iEMr~j_; zZTr24v4?JrVzcl0{N!^FdSTtZIa(b{!L-?Nt#b)2*pp_-2_7A*8@^?ozxLk$1CtC& zo9KcZ?#Zl{Ih)W&Sqfvi@2<}>0D8xLd5?wBwEQ~TOYOUly0ZdH2e+-FtcDFAV8VRS z5y=1#lvA|ut%qriM=&vlQ1cY5#u=MJr^bO z&0o+S1Hz7tHD!*EWf z5Ne2yGtR)=8;b_SP}m|6(gGhX$4w?FT%xep10`@ok#peC@LE@|bBrbm^Xd=(c)Mq! zga)_NfCeToocL#5tv>(}o=aQ828;)PPuC(0DKQS0W0HT`kaiB?EHytw&Y<^!t!HuR zufZ(jv=3fJ`ldM=Vo4VnDB=NB1-nVm92PEXif?@~77bUw0EY06X;J5>6jfY!S?g{s7Ow_2meTs;p7vp zQ4)qgZY)_sM>t|Q7P4?(8cByJR}6WJD#FiOQQ?D8ysIh_bCI4cU*G_ka`dU?k~0Q(H?r>j!qq>wQ)W>>lB9ECsTxRB8%+8m{k&Cbr#nWjaryQ{GK$;-xva#%PAS6KvD10__rU>QP{RK^ku zwIpdrIqkLYtZ!x-oPU%kgws55V*Flwf80l)I$|##%tf@0WyXsN@Z{l{-b^9(#J{2t z_n2NrB+JA#$Ee}Y;x0peBqD5)&%#yS&%WzLxQbFr#Bb^w9;ut&ea+y$8|qiQl*4V8 zxbV&Ur%N|1zT$@EyT|`wS{E*uqHrcSv>Tum2y?#a@SHu52hY0H0JkgIQdBU+ z)Llh>@`~t25C0!)?*eVvRTk*3$KL0$*FL9KRh_Dwq$MduiW1zb_28#Gny)6xnA?Q4Di~?hO{oY~v zwmSWGso(N+bq6)-jfv=fuEft3pKM@}!4=ql@G0TccJU>kC533~Pl1+hgK!|S%OKPA zEUgDW)i%&3BbPnAu=bfwap!E*tYDZz3OtqRAz_XAhuy-Ey@CYUpt^dm$u1}_1w*5} zHQC--_3uL%wk_@joNuAvGX;2hsvGfdF}K=#uA0(i4_Wz+AK-grd+)&Q{OsmvJbYqqx*uPbwL;OsdO9)`>-C(r+bUa{yP4Q>V5 zkfE{OXL&;jhj*eICXzIh_Hhu{UzySok7m6T1!0BBq(3n?6wIW@xE4c z`MhZ#x$z8p7txpkxoKzB{Jx*70S4BqX|ndCuQBbCyi!c>LJi{u`U1~wN3^>|gKzYP zi3G1rNBm|eWxQA2Ex&bd{sU^Gyknmi{Jj7dqKUw z0;ue_K#uwq&xy?1_*4Jhd?&32InGGCS3E_f5l*VnQR_WjXEX8;H?=kU2d5hS{l4L> zJxiBkZ1Te(Y(ztBs_jrKo{#kEFT^>CMg3-OCo}%n@{`X8N}fv5hRq=eV+zZ-d%pJB zN1{OLa?DA`#l)MLvowEh5&u9`AzUPD3m@%Ypa3&S&O=bnitYLtC^O_C4(Z{0iKKDs z090hf>yL7Zw|v^{+ts3LiPqsapF*LQvh>?KErprLgpBjfV=rc}>0Y$K5_F9Y>0yO$ zu2K=xWtAE!4Nc}kS@iJov812LAVaTidmP+A`?02!)$b25I+w(De!Npp)LD@J7(!Npc~;K@#OT9w^ZX(+fZ<1nPl4 z$#@Y~P^2z8+d<%wVk(0pq9$eUVP8@MAsGMpSg{eNkww`I6LWS@6E?LbbE}J1MlRWZ zlw*r2GE-%whD?*7T$px&L{ga;+bUj$q+`x@M{j#yA(#R#X=SK%Ehz?H)`|E0oGOeU z6=+wzVQp*L`X($V+}Wn8`6;nipzA>C7khvn2&qL(U2y~wIo4n~tHtewLSY;}30VqV z=yu};&}w@J@2Q^=3L(UrBLmbnQ}+;E_Qt0~bjU1Xj=~kg7R^y9tLh!S(?l9O&M^3q z+?07YlBDlr+0K2&kq}lz)3RaHHPs1{lW(= ziPq+3>Ymbp>nGXXEE+L>{CG^1ss6nwpu*^)HX=Q|2X|&^2lY4T$tZTx_qEM28=A@_ zI?%8&v-ZP(P+Rm8SiA;F2RO-ZW6X zNs~M6lWdA&KXOhy&rlg=Or-t?JQ6_D#R_mh6Q|&CXp4G;HpF_}XuJAbIL>$Qn~X-n z<=LVh!KWhRngLEv<_-wC{G1Y9T@Vi|@U*MoV*8~i^YBGm2Z2rURbF3K{c9*;;$-mq zrcB%=J|N`&;-bjx$r_(wtINsPj))xr??iN2()JNTo7i!HzdF~^{&8BhU!D)@8zaV1 z4W@9&T6r>+g(YdohYT&tG+8UcOj+3a?)ecqA@gT)g>MsvCi#fyu&^FGzY8PAFup(Qo zMO+f^FGxvON^#QjtQ(|HmQuS&vl1&n^xuDcpP4~&b_@Nt&-Fm!-Od~8dxCK|egjda zgI5IBvSZ)Y0-PM%6@WQu=)NSHQ7$lT9C-8Xw}F3%5D{;K#K7FSdX%$|SX0$f-KrAclbtr&_LER&+fOcFKTSe#-M0=K3*sndI$zzp6X z5f_kTX{Ezs%FtU)!mPS057D0UKIibjtv%xl7?3Nh_P#Ri-$YqgsqCP5??T7HN1%Di`Rx zPdx7Bu>c6iM0<2{_QZ_(x`_e-ZIk=M?h`3%Z^@wrrd3!?44zavSWsW>B&ty2%iEdF zbqpS$C!Istv8ews#QvL6)oC+OiE(c7iid{DKyC>g+s;MV&AAHHgCI7OG`6|wr>0S7 zEJ)Jeq#h~yf`#jay1@t|cwZ27VURc9&_zO)a?thQr=#w$Bzj@nmJu`CP!wc^(UpgY zVT5U%sNV8;)(F<1f%KsWygH1#^`j;OBD8Ps^sQnKzr9=kE+Jb;Gwo+HY~6XLEYDQK zBQ6v{)PrL-ZrICX&zIfU$8*jv2nuo~pVlP=<5ji5qLBOf?Cc4pR^!ODXPWGI#AWtI zV5gYXm5o_@!59>>l*j|owdGdhKp0pWJ=v?Au`h|`taL>f?MeR)%v^#huznD;U2Fxo zS&%TNGIJvQAwBS77A29I1&Ee{MWl>brI*h0D#F=`;2L=35IHUF(ZU0V+)Y;lenXYm zPrdq8^AUR(aYTeE#Q8#`Lvo5pbipgZVIZ2>n!jamcpSmMW^gMdba?1d4<#D3Irt`C zk@Yi~qC{hi-b)A2?e&vsR6Uu$wlW$-Q9$Q02zC&_8JlJ_8d`(VA6?6gz{;Dmq>7N?inQbBUw6W4Q9-*`?_BQVZ)(& z5T84VXSxH%D2A=VA1fM?-NO|Fn}HDUfiP6^y??_+^EMe=*M0r-178^Ngx$sZRiN2M z1AFesgV);u2idxhIW}XofxiY4ak4abI(sR{_Jmz!z^3A)@UUgfvv0dWBuHKc2NvF!Xu$8s>Xu&_nC6W=0gVM94xIx;lLS zgyzb>xR6{Sh+i24Ar=Dk?H$qwAbu|@mWSSqxJONMwU}nhC0X7+jNEax+ZHbd;n<1h z#v8bz+;CF&OwWVRlbkns5v8Pk(R|mxCCw2)7AL)f>Eyc}275J? zpBe1VUIWb0&K^~P-na%NTOrc3u=7}R@scEYjiYt0Ebr%$HXm<*qJT;mbmzT#+>YoM zMP(kj|BB*6emRaiXjs1+W=>fpX4cGKl7F226Fn@n*K{2~U{8HO!jJ}GPLJwD-E83K zKhTR(HZ3<>xwj>jfMyCoK%+^0nkf5fqZ5Frt7f_8Nm=~kyRdtn&+K%zoTAETaL0{A=BzmhiI&vP0u7P^eszh+3v{M*toe!dWqq+p>AkkICiKJYr z43y(#0@xjp&7)}?QXasuGN%EEu*eVukJCFs(AFQp| zD>@fIpHd8+v3P2Ma7AKA*u;5r0Tbj1d^5yx!)9$N_j zQB3GMv{vg3f$_Y~{3kidd1$GSZ%4X-pgQe}UUca#mc6ovMUw}+a;cnZ)tv2wEUt>j zDk4zUKL-|TFHl9UQyrJK7~$7aWgJmZxv`j&M<;G+p6tZ-E(Ww=qE(uEsz$L$#x6%eh_}L+Q7(jFa7MG#oP8t~ zgsJBvYR8YxV;Z5LLLxZ1CkqiUvqrH1~BLTUuX0vg-zMR3Tv7eb73#NSxkAMSrN9+tCF^Z|d@9bKN>;}W$Y6AAsc)?>5>Ac}fv>^O8 zV+$FLZ4s!HIk`028mqFIYlG|FZaqP^g(XfZ2{<($)kb2GpfsaRCHta@MKFPv9s{M9 zMhjln&g~|2qjGn=u#XK}?~jny#9EjeMze$n8=5oNB|Ec>6$QUl$RKCF4!}Tbdte;_ z&umFYOC3D=uj3>Q_t8$5w^<51PLw3G{L2De(xHp8))jr&6+NzXmGF_JWHj)*esdOu z-74zErb5R|W;15_@uho@9?x&(7&u@ADf4F*_3~gqBq6aZN6{(3hrbw%S32z^et!n` za3EHkHa7SS=@$!NSh@yAMYQ+1GM2?uFY4T&@Qdxkm(d(+;~L(rf_KuZS?1;Q%K&Wc zF7x8BRS0K=SrO!73th49rzf!wRe0dBnkVB@Z`@vD;gK@a@B0+b3_C^W;2#P_l zs&=TL81;l=+$qWM#b0=JK}WyoiFTar$CD9WaB^fL!+{jem*K4BpnNXULQp<*54QCR-G*s|MS)7-%l>QM2GKh=8J%EI2>FX)Z_|^j9SV97 zCbigp?y+cd+Wy04N3Y*NB1#b`+T$|h@0T#ljv9cz)#xIAZ7?EWxGxqUHc1E5^IeC= zH)W%S?|ev#qoTwGL3%-bU?~5Xq;dvGn*ixDiM<=#I@HR%x!FlSW+3;VAADq~zollY z+ygD|K(oR>heuCo#xCDwT;t<%i0I8XzVy2NnTalMm9J$BS=k6>Y<;d-JA8MkU!@CD&3(-IKRZ-b3ffBT^n;^O=nE9nWbT`o?SeE+*1l_8 zr*zje@dAdCB#+KeQn!yjRvL;{ux9JuvI?e#>&sIHHXVffcW(@)%Ld}m997~iPTTEt z?00i!5rqjw9a3p8$s6<#(eY0ano~D{knR2VfK_a{v|<0Ns9m2xzJ+RKvDP@|wT2wE;L z>v&0GRE>hD$Gk4K)NL3s6e!G%upnYAdtpHRqEn&zi%<#4X*0kH`O_v%ZKElKSGX4k zm@js+6y9J+VQ%+T#0i|l6VRv&(r)hvRC7)&DW$u6;{ z)g&A)_;zng!=XG{hAv_g!6GKqfPO9xhLmMlkuq4Di=lqE52xfGj2f*c|1q2dA9&TN z68chejx^{TNBES0&E1$3RT-N#2DYua@Pr(!xrDBRgZ*09$j+azoj(7InsXJQPvUv& z*!hS%|2R2%D8Y*UCK7O*q%x(jmo>Z6qCrWT9fw9WxGIBBjLR*?B0Y{raj<((`<>Wd zHk0PAs^0NOR8ScpP2m%zsHO+UXTb5dHfLA^nV5^p}@2Ed9; z%hxG^LdjIVkv)U^gY-XFYaqQed;ltu;z1x=pvGPKc++Szcw?ellnBGFr3)iIa3p|4 zDY~EgHX>w5IO6J1jw7rHm_zy1i)Ld_5*}f<0LIEkb$weLRsye&U*9e`bjwW#Q?j(~ z@F4$?=W&-x52SJ50+p<_Lt(m=+EOgb1Hi8H4FvL=EIE>YgvX_s!xD&8jmQ+E!^#ef zp&`jv47$jyBWeI|3>{GHIw&V*Mg(@b9R@Pw5fv0nM<_-H2sdbYyaFqljux{TeVfmx z>@UhJh1jLWC&_9;c-MlOL7-NPuM~8Q;kic_OCy}F{A81u|AEYsN@Q!7h7}CgI2SwO z>qyi4N1$dJGNeRW!YUhOs{PiERd%iTZsl^ai<#uZk%Fj8kHre9c$QYPRB$<(Cm#(S zqih@?*zQ=IIqIr(mlulfn(#H-P~=vt>l> zurDBYOtK?;NVCj50?EKW?5SfWEd<@Cr=VBk83GezGR7&xE_7z2CW!hdNSz*@mKMKZxA3g%k7wIHV(TeW_LiM*oV;q&v3w(*q;D4o|Odd zh>aoilZVA#1~2skZGi($k(=vB0`ieiPOUFA-!oD92Pm#6vyXqGK*M>2=VNk(${iM# zy|_vZJ$v@H2qK%q%9LknW3iBGp>xS_Bv!marTaa^8teS^1Vw; zFqUdDK$b#fcoa~Xmh4a`E1x#hrm&|UWuee;V#W*z|DCcI`)!j{67G>=TGIOL=nPI5=omUdwsp=fm$RaV>fidUA+&DUu#n$9V zkBI~ky9_@|B!~$wyPMgdzHV%Y==iL)txBlV?1Ay-eT~9n_X=aL#)y6$x8p4i){Ie?OTVPbIJm)AgI*e_D14j;nngc@eJzqyZj7&(a zSeLD&6wr6fh_i05EE~w!R=vG6Ud6i<8<`OoTQ-J49bI^COinSDbh>gXKhdSb@{#Pbt>{y(E9 zX&mr|EXc#FgJUw#!>b{kgQC4^KKc9w_jUgMh<>*tO%9c^al3%XS4)76LfbYdK#{8tRM=Na@T2~b|WZ|0=xOH%=+*kgN0 zzN^bj48YS3jB9d zn}=WzIPya`0t|w{m=sauH2o4WV)cCtwzp^RZAb64JrOLI=k@J-5#tIUoBbBPSZK@46dW19YX$6Aw zf#@H=E{N}mb=x1_)qeYR{oF071uhFSgsqqLL&Qd0i_m6MV`zFIYo659cMR8>#;Xz} ze?4L`d^D1CfVkmXMhud^Z7vEwn^HTeD-)m$Rm45xA6AsC@Wp)t;oZ7g%c4y4Wp{Y9zMgvw0@8UnVCF*29R>=^FR*SO**6im47apBMu++j z(J2e}Fi@NHg7T`++FhEjzkoF${obi3;D!r(t)@gvhwde1qp}`9tA5-xWVFA3LBc z_<>+yo5qxDx66&BQSh>!0=jfS2$lX2;63f`;uBH+ezL8Uk%aa>5|xrmdJ1^ zY5Ot~Erv~Wxe{z}rHz~}UHv83%WV*jZ<3#17JGoH@wIl%k_kc9l3l>pA=IvCI_k{c zy8cSRiA;A6AlS6l075s0s*=lwG%lgNkqZ!7vtS76Iu+L=H2bF z#dU^>h{LeSMea(t@B&)$M(7SIi6{2}h3m}Nvp2qX$s76`j(11tAlFm6=6%KE@+1;u zsI3U9Xt4@-Fq=tgQZNtDl7W2MU?(UsUj#lw5GMRFpQzWRH@OZR1Ky<*r2tD10Ayti z9UnX(NnUedYnx;#fryiQrZ&ffV5A~BO}=L4@i|SlCWJF_qex~t_Tu9N*_f0ca*%X& zeS*_Tqa$SVh>6A^;0i!n2zJ26OX+{Qxn|9SQr^VKP{evQbJc}exd$i(gB48OmZDUL z+k-1zI%<6GX4 z?dhSdTbJ{^TG+JdjQCH=!lu~|RV~|(@@YzWa>d5}8lDFoHpDoQY71sAUklzq=^|=F zvIN-%8_uVvote9WYfEDgxYHR%#DD9ly$URGaw+*0y=Usv~`i<8ypbScKm2+V)j1WodyY?Gp(Rh2#^32He6_fqwhp47G`M6s6Ea zV&y?Ldc29GUP$f4vP*x&1tT{!z2jYDn%^-PZV60YiZdUL>GatMg$uQrADDw!(h$>z z;{lT%VmFHLIE?hp+ACFk`EV<7s64M};$eadf4!>T=J(rkY!cKY{vtX#3i1^N2mj5q zPu-o}?kC72fu)h4-(Un~x z*tuYgIXgL>5-R@8VkGo=7M5y)o=Ij2dzictI;FXTk<~!wyj~>NM=_1>@FA7l_1l{H zJ8?Maf8qumzI-sGwz7OF3U;t2t5bn*jrO^-4+<@bpVWVi)`=HEJSBuvdS|ENDE*-o zF@6pwnFT|L13rUMa#?D^q?jg`VzmM@p-!j4%-IQMD(Ve4GvM~i_jb6p$v3?bwjv3F zfJ>E1$${@~dW;-tluTM|#a*eh_R$O5cfT#3fY@xqPA;wGIf={7MzMtcwnIu%b|N2^ zfh*V|m_P`(<^y5#dA#?xKZc;nUJDvr^85k^O;4Yj&|%}1rgWH)L3Ra^C>`sZf}&4= zKSQ*J3vnibXq2;lA_>>S)^JZXjC0XN_}EsSfP59boBEfg7p>LMfkjElHf|y=+Ocjw zs)2|*ePhe$vb$!{w&59_raCl(cY7+sWFd33h2r}a@zo?b_l)cx?Hl~!?r!(AfaYyQ z{jI?`vV6(NH+(l3)w5Zvul})6GJMzKzqAg`BtR}xJwvf7$d)8&VQYZ^0^qf^Fm+*- z0^vY&f?#o6Yolvw49+2XTbUaoQ>Psop@q09=*NMJo<8E;LV#RebM-&v79M( z!iIpH?Ma(p9w&lQyyJ~fiX_R9t$xSLQVlkWD}IYPu~A*$V;x~;4eEEZnK6g^msA2+ zQg;CQz||=n)Va?9JzN@@hjxPck0Nyj%P)lkkLZe@O;XuDati}();FdS8Z4=FAt#){ zvU|RWbw$s$1THU-RFci6S{$uq6AX(Gw<>mq*x4S(dWthBV_;6)^T}OJSb3If?1ibu z_D{pjP-VZw9zn5Senph+bL*Nmpn|u2P?rJG>)1Bb@aM3)(ybdmSn7nezK_Q7!~}Qv z9hAMhi0MIF5M4w;6sjfDiDnA@R=@&-v!Q4SBWK$8ftQ1gvuI{M6AaD{jN4B? zY>988KM{vm_Svv7P6g^YmyUF?Sg$^g0?9j=F*hlKtoulmBVA5nR@CnScm%E=ShiUhMekD44b<+@6kicc+Jezw++Ty#4|dJh@wD%4@8iiuA$s zoHB(`Z-^SzxDgP1AOA?~?fz8MWSA*2l>-?j;%4v!sK9SmL-=l#X_G(}_3u-9mcxxE zw_C_HeSM!_V+-}$E2eY}LJ{Ry+ufd(I4d`cLwwiay!5h1eFnNOCMj<`hK~pu+i#yL zhv~I4+oT@fL&v}5b6$ALG_*(RzZ8nG*g%>TWr>}#|4OV z6`LZ+`P!xhdjdz-un~BjBo_wM!$=Rk;T|AGy#Q_^)>=Jb;jn)1JFUKO0J))+pf@Zx zR8W`Ug;PM^#5cvVZl@%5hVxi>iWjH_{#_gkAElj@4|{&=w|~L|NlK8*O9wFDq(`vt z<`UjswUHl~`7>3hOFf~>CW2r1m&l|87 zD^`&Sx&rX3C#9+&RBlK|+OWLr^Y)={yP$DkMuhMv8>rah6CUitn9Wn=o+b;~K|(N& zpeqFIWo;Nh!+;d19leRgG{G|NfWK3dYrazx`@n2ezXTxZ%b0w#@?5&MYb156svn+u zTGq^?VdFrIN=Jq;j84euG)~7IN_#i%WK0ej0f;Ho6yX4_{@v6Xu9lDI<`?p)_QjBH zwBe2QmGTRIQE|o9ygDbjJ3fCQ7KFvQKO?UU{{q0_8P*Gk@uW*szk*2EOMo@6hFXP` zWzX@Vrns)bJg|D*!KU0Br7`N)=VWM|L-+KOwK_}tCA{W1^0K!*b6^1LA#kz*=C&tubagwfS73hH@3%;v>DAEG!mZ^P=e1WNK$>z zsVHUrGLzwbHPTmmL;ZeWvu==F4lKKxCs{Kow?=6Qz!(qQ@+e-eT!-q{-hji7VH_Fb zO;9Cmix&{)Rb9ce%!yG(QNo?sP@L60oXWB7#C6m;jG{I$Pa+dl&s~QsJF_3`_LSAI zdA1G+6oyv;TZd!pA+vo-#*7F;+I!Wlx7}U80g3@!IgXFlb1Fp#hyQa8SF9gQ?(z}{ zo+jr=d7V=t2^7rAt@9fw9lGxv5l7e3Qjr19)6vc$l&BY6-k1*#=QB#LvDB-LcGLC<+ppVRreyH)& zAV6W2qOW8!lk!UO);|Ivvwbv8-6zBdjQGJx-BOVju;Ly9P^yVcRSQ+QhX(`AtPDLx zr?iuvKkhlD_E%NPWq$t|acQ}#o)X9+7V#?I$;hwnUH}K-8kQg4*M2yaQp(Z3flwCY zQo+*xM1m~HC12fU1w5Ym8F)3HWB)FCL;q1Z2ibL? zv7JeCSiuJd=|Vc+;MHPAcUVCPRMFIk2kyj!lXkovd0hVHi3I@mw5J(}!624coz7q2 znaS^%0Vf$K%%+nJ^hIjk@ueK=+?`~Ah0O>PgkvRG?ya3346$)G3hihsu)@i}Pa^dtii>l6saoB-jrFq83kvaWWZlk-b#PC1_dU?5VY z90?d*3j!d*-V%l!%{fQeL2-luf;)rwpFYCi?~0BVI$R4=^m!u#SsBm8I!q>k_Zh=q zazd})3fPGu0b~-kdato!Q(a3kqss%hgnpiK7t--;(pn;qBOHoT`OwPy1~#MF7na?wGYvGS?}c*dMIeBvdj*>OtnG{%;|T0EaB4-$_*L)OYv%;W4E9_@;XMV$Je z1rz2G*3*#)EDS$95oo^J$n1q{2zN-+RrQ`pj7TEyy%p(|m;gfQRe~47D%b#mbm)^% zujhc*v=QXAI>bkJ4c=VlFZ0AB8{hg`hIHIYUa( z<62DUpng-iuYQv+Ou)If_XMXIC18;^WM8YJL9r+O@h6EjDeO^UA1aSTLyWR>4`g87 zB6}6}?|K4o5a+eDb+FcuQ`{KxWrScc@z{Rq9sI@k2abp1sO;Vduw~s506`K^1SR2| zBm~LuFZUZCnz-0(vuw86#>D!D0#Lr1`%iYQ-ZFPJ{?e`mO4a{%f^$Xgzq97G*us~m?+BY*vNfjf6 z=yZIQPJMR~NeL`|j1pkkSvSCVIY}!)XgG;G28~571@LId=u5{5+S5GgW+G7NNseV! z-BLGoN$6Mm_OHfi8^;yC@BGVT>it;$xU!1S3kugAz4JlP7z;c=gub|y;CXKDvdsg5 z3~eN!ahun;w~S5X3m5gBZIEQ$yd#6oR^bRWCRP2 z*kyx=fMU(k?5UC5K0wevJjeu$sJ$N)3$5hiFT-F^zY;L;?unnNm%@;qI~5dzSd8H( z^{8MX0Ge$P-c8ocqiqwCuu$P90py8{zA=>{Ri8i_XU3g5y84e3+A2V%}9gzFtlMCDOkQp%{TMpGo=!k=*eVSVsUfU8Wbd{eHF7DPpYYtjW zod%KU8P2WM;F4m0QdR@`>5Q$XPbQTgvG12HRK&4BzU{NVZ5~6%&*Z+DU&J9+|6ixl zoH8T4o@=9GBRHx8FtX*+OMG?v<_j2Kkg0ev(8$_f#wPZ&xE7oO;B{UOJLbp0eB43J zrvbfnuDX`tCE7^)IsaNcC*GDn+_U2v-j~&e7upwk{YR$ai909Tyt_x*hO?zY$m*CLVZriXl(Nk0z^r zlwt486fL0GZdyJf5djp5;1)pbU^%iI;}u}}-2u8v)Z;J6b5MkJ+}wG4eII^7p8p?c zT+j|x&AR%7^3*u+uB59fKHJU7FrC;@_S)Wz@dT)GL4q$cbGC-qgzvJKsNl`eo8Tme zWY{1WuX7yzh~4FhT>n?EJ&}DsQ!9678~KVyC%WdBj}z@9YfAOs`3`qvI_c*JY0Ucb zUQOCOZ!im+&$onm_&T_5sVfm%A~z-xRoq5@i;H|+<~2lSa!v9V-e#jLGi3Ew{B9VB zBbLfbA=C4^YXM>AN?hAGsV?>aP+lw1y3TPk&r@yF5fMYS0bYrqu}<@!Gbkj#;P^CV zKnSJQwU|j!gB}V{%7zlTdB=n#3X~N^_5>R~c0s_iXTlgVp}GVJ^Fu6<sl;F%Klk zQhm1|(hA6HpXq5MgzD0^X!~984=bS212DvVgNi*}{yicpD zS0v*Hn1H*Vx46~`q`&DY#zklv1(@Rg__@h#z4VUnN6NimW^6Z!^}XyGS~wG8c%#~Wuc~&j z-x;H32#0xpXb&`rm|0Z}zCWKmCm|tbHZm=%*Q`ZRL;UVV{RrES6Hd_!BdzLtSfeg> z$n=hNKX3$1e}xK!jz)$DYmQGh%#8hZ$L{PVVT9(fmRHcs3v0T{iTVWfUK=ETsr1CZ4i)`}(GW;+GreG~3clQIeF! zm=e!K1N{1!s-Obg!;+6T6O^_V&%IH??@#CJ?-s6_n8g5^kI6$JBt8&nls*XIGXBV6 z=Jg5B&y8;%&>zM+1RCi5f;9B614qoM8r96gn?Not*Bra$7r&MPQtIvSOpCk>U3L?Y zh%p{+!+%75%Y*d?^|{b4g(7j(70?ARQ5BCYr8AV!J1KouGAcn7$#LNdA}LKLXGCD$ zL=Hxl+Gti3&551h7>1y><2z>vuj^-qQFa6`WNHN#I+{-f{Q?=+ z;@e#K5u|zI)EU-#{rN5LF4egD?H62d;Ax1s7Pzyj7=Z^5hxnE??jp9;coUN!TMz?1 z2J6f$uZ;jNs+!H!@74XEy2F*n;)H{TrnFCup-4|4T|ZKIC#`WLou+jjt?{#0pbMRJe#6M=Jx-kFlqwi7CEKM_ znOB%3QMKg*j4LAESQ;IFEM`EFJh%zu)<7N3)rC=&0GG}gO-h(3i|qWN3h;FA(Ud`0 zT^MxN&;hvt6k4^w%?Mm>SNsV zz-G8-zdf6t;~_5T%;f>=Xwyl4AfiH80G1>SVgzcqKvNhP0^<1t*7WPQD|XJv(G`mk ziLEJeV+{^)*sB6e9SX#NKbK+vNaU!lXZKJya zcm?h1xBoGyge*CzOFa=1H|Q-IglJm*YX5Y35qk(KR^atPtI+bHO(nKu5HnmQh>9s^ zEjVpd(Sq2tZ+So1NZ%X*&#WUl5vLifFff!a+Y^6e7e^0L;Fc6h#?4z4$8}ZhPW66iq`E?|nQJY#JLfxr56J| z@uM9Ooc4w*6aGgmNgPPmmRx@4m52(gF)WK0L*U`W)2S20k8Xx8l~LWghjh`I(K;H&wO@>@*4 znr<$d3f3|lRr|HK&?-@8teO#!p~c~p!O)2h+Nx>1P70W5FDA4CIe?+u zMC2abb%_KAH4~6HpG@AY{uvX4F(|AYpQN?2%g8Dmn%koUpWmrUlf)>m(9JFAf{C3d zL$I|06Pw>h%4(74co8sx6z{8ET&$S~yBbwJb}b`>YZS2vY%lE!T~H0Xo~YSFPMYW| zIRoUxhF*t0D5<_hmsGJ|OgjKvN*I2y{9<3zyP%vK&ryA&`|sxeBdYGtw4c0yt^VUd z(;cemjO?lQZ~rXV0Wa%V!6Tp6EJ$#mQU;9EMJH0uDKg03x}NtU-u?$)zkeHn1rn|M zgpVVP$O7fDa7;V{=qJQ;>R}LxR)CV|o%&lO&PU%(@1k<<_1|M(S$h{7H}!QRQ3}(( z27>ongEoJ9wJjFa^*dR`WTe%LxHs|F26<-7qOEn+FyYhCiVu<1!ElUbDGr(=ORU&T zgq(XMp*IXQ2gphHv@yV-Wp{IW$GiZs1%`|OjrXj2LB@))#s~p0@11i;_eImDydcZ2%-m*nAQEzs6n>=Z z@AcA&3$$H_9o=}|9=JucxS z1)!Uu8Arl2t&;O$6GsUKK}rgMgpa{-H4bMf>yKBM_^XP5?KM@^=W)5kt0pgDlJ>f0 zfJ3&rr~bdSZ@brH!b}=_#Y{<4syw-?^f{pre13k!Cg3*=gD9zq-6C^^0U3MiU<3aa zPUv|l)Lx^8jE?)g>b2Dq7rUEO{*jPySj&QhghFt5i20%+ng~+1u_oUz_+jb^S!4}( z9k|BCHfLi2#NRX#os!ZI6?X9*e^#%ZH}QoF*Q5_0(LWW#GPoPc4fxW>vQg(3xsI$j zQa=s1k2jt?ehc-@Hk)Jgj2*=(xt>rTHXdXHNhIzT6Bs($fGjp3mRV&gs{bw3@0bS! zV2E$0`#D^G=CW$82sv6Ye39VOVf$dl34w%^>L-hx-!d{R6Yu{VhQ|ekXq2(*MoCFt zrs zR0DEon7D9dhCov9rEXK{&Ze+$T3O*6)2*2R@Bs_qY+ricVa0)DSXNQ~{Rex}eigF#EQX(94#wQ?bU6rKkqW)3Y zmA70k<_7Y0r?Ybe2*~HEV}nkIM9u&qRs(t&@?b}AnWsy_tfBPbIE2dmk%z1TJ%6im zxx0ZtTbO8olc7t;Tt!@l7Pb9AF+;ju4Yu=+qzo!xmqPC{=mpY? z);Kw>OCBE6^;8Xawvb+kN<*BpbS)1@P=3VE09xga5CeB+MG_l=-C9k^Iay#Rd4#5H zU<6WS({sNV0ZSYI?7aT4fVch@&Cd1y*b#cwX_8~6K9yaQk z&8CKcmjN`S?-Yy#+kPOKANxUgSv#1jyz6l|XDCmU-E-$fjeGR7f$Q1Hfb_t>!ThUT-Qmfg6?M;W_&w-KDHd1su zdi1uaq{FjIj+r%}7(kbCkMvEkuRtbPLIL^$j;#Ip{J=I!f+1)|K&on7WSC*SaMF;A z`p=PVDR;v6VFIF*%g$Lwpf(dR4eyet5=#+sjS&z$kAsN~fsXNE{7XWCcVIuUr+RE= zqZAC;Wzxu}CcVXG5Hxx;rVrbmhvRCb(2{hMbZWFWcip<;Ja1Vqn=wvz*|;FOGRB*` zP#}I?|3Nj%z0LIaZm|YEnzw+tgleey#Kz>cK>4J=JY2O3VeX3^`?n#0rrXn}z*KuF zQZEHH-ZMqv)I4q9?^U(n-62G*7C#0why-s}4{4!*S42)P+opb3K2D9GnfEA}j*y!Q zg3IWjOK z43_``87ln4h1U(ny>tmrDzIC-GMAbP_|b~i=#pZ|Gu2kPaa@S zu`*(NjQ)wGELd9Y6)aNu{TzGhN@H_T`tG&;193D_Ts+!~Ts&=kEJT`G{SowdGp}+q zEoxxRn}Y~bLe5V^cF#d_Q1M#gH?5DwH_La$MFxQB4N!Y4&5M`zqFf>^a{?2z{8>L6 zY8`Nj<&N4*KbME4WKEYr6cJ76bZMIS;HyElI26orDYF1JXTbj{E5ckObhYQOnaDVv z^sJ61etjW^o2uTAbOG-=o8=P)_q^)q{Yeg<#pe; z^BsT|6A^o55~hMZ1({L?T2_~3%sfEPKX(MId6g;*A`sHlo+(6vjNO4|aaR%RoZ#wG zY0d+t0Mp2o10sVW(8+(&&d_6bXmO!{I^=mlNB!9uU4Z_9N?m$raZu#5v+NxH1LFPm z?btKs=jM8BqnVjG=`E*owGb9NR9jx?8{6Gmm^cvv-LT>Y76D$YgWi&Da1}}d!h4l& zh$!?9xFdWcSR57KTRg$aLmDP;Do9{V(I5R5QC@z)JmX=Prc1(j?}TP>r({Ol(oquI zpaA9Eq?hDd1LxPklRz^Gub=7n%VK7x7yki*9@*!lOSMbSa8wPJ$6JnmEMwY`hQR>{ z2n)CDo2Ub)Eg2U+fFa%rLxut~05|ZFfDD?m~P|MquP!Z*`+ab>pqWai!f#T`b&8z4lvl#W`-QxeKFGt zbyMlB*B*P2*+zU4<3K+JH$FNrDOI9AHBtxIpcC6MH{q89(G`SeSk&@#4#mF`c%3bT zK8=wx7d~0mJ@mS~N}1N=otd`Uon6W=*1P@y=Pl_UL5y_mV?>ISZ=FvCJLHA^skssd zBl;PBIHcTYT3W9*zF{YN8gAWwFmSww;46Po{`$~otgQPX5Z32V`9q-wCowyiN;|QA zu?hsG0r@UWOVj7H_XQor^YyFZsNM+K$7Z9^vt%j&U&P~ha)x&T!QfH>U3NkIGvT7V zl*hS0@1*5me~Ty_$@dyyQ0DNjLxB9iS%GpE%57$$hk~$7CtI(`!G6z|j)Y9#CZ2qii6$ENCPoa>EUP8ZJD;nsDf; zCD=o$6CWc;xYL~n$?2$4Hxa{#I4@!9wYSrarEGXB8sHOej?VW9bY1W${K&Aslj}1I z$#5{pQ<7M<#|8fpXbbbDG-vF0nHihwN1#(df3x~`OwoM(T3|2Gn}{?(6Ou)wP?Ty8 zZ8Y>KFfc14_l%826kgL~B0=89CAB310DF~q0QN~>s0ia#E~xK##xQ3-rVGRR7{qKS z679?yUD=G6ST_M0l4AApBt0;$5H_;CpXc;=s$U9Cc@Zoki%zCLd+`&hlJ2hZPU}X8 zTONv%%qQ_64$v45#5A=2}hD$=3f(D_FHIa@%KuMY;<}PP`GdHu5n#hF>N}aNhcjoJISz`p?=7&<*QwGJXo<^h& zn+6_A-~<@ZvS0i~X(or{t-t`-xbPdPWAKOuxrIp}&e5FDQ0LN&c?Vf| z9fPT=+b1Im(rC=!ujz5iTCiovve0~mN$^663b(&WRx~}O(GJ^r4F%EcCuyc->L&%; zYVmOKeGYiFcnE2JW1jTg)ATAo<)Ny&p#x3n+j9&)+HFR;FOpq_rH9eXCA4RnYsMs^ zSn-%Jg7Qw#8@+gN+6eZx_;LAyym z+B=Sh)VM@OEU>PYGDi7JkH{WL!DqmLt9m0Q^C-Rf_N{#TT!He!v0uyW!0otsX%rqSymkDxe2fS#} zGnq)^1j-A>dY9;!NTtRL>Q9dzccMG?TTUw1xD*zws~wCLtBLh)dTv+9GT)SPP2OQC zD9aW(RoE^W8T@74Z|bjMmxfot`Seszl9d1)zovDA^lor4(onLj;H_CQX5jGym%+ed ze>3rj3Q$srJnPx|B?ItTf5@>gKXV!n)0bG!x9|TQ1r?;DM+z)pe5H>a0GsKEJHiwj z-%Co9R9FxrU@$r{Th4~?RA;KZU!5CQS3h^WfhDz^e;2_Wy#Q$C0z?=l?UFbr#t(N* z`PF!9b{}g0-)Eo-FPX>+D)Ml?WGJMMNCATZb*$>-N99jsZ8LP`EHS6_>LA~ z#GoB*k6qd-tnD~hAL4~tBr)t^^JSc`oZp>st^p<{)Un4+IQZ~dq`a1NpkeY%|NScY^?1KNvwnRzh{RL1K>H>KaKO9)MF&=4OcBYPO`w$ ztibM!e~u%!;l~JGM^{i*4kkD#)xUL!_lsWSf>9r@yKXlDQW%C^$i4s?Jz4TJOYJKR zedNwUb9k49eFzXawPP+_HHx$;WX7OYnu(ge^;09GLcvDy=vq)jBrQ_v*eq-NVIHuq zC145@Cn~UGvBrobB49{Rf7M+7PdG`mg zO!V?B%d^TQYB|@4z08*fKM*AW-0W*ikgurX$B#ySoGyVt@P&|KF*ePxF?w%DG<@!O z_U$j+ONkhK9q0iWYY&q()0Z$84d-Zkr`eTL5x**Vgwc!ki;>c1yG z9YU(-p+ihj9!c=(d{vZ{4pcw$l+oh}_-U@Z@HE$wBOWFI!9QBCaaUjz2rFYu+Tpd} zfO$#bY5s&9gFLYF(BirM`T3dI0+WXS&G+U{{tsxg2D+Aj{_OlbR-gF&pNwPa&#^%; zeeB2TS;V0Z&>xGqUkrU#IGJm2{ZQ8AXjEUQq@;|j2ae>>YQ%y4JJfeH>U<5C)Y*I>uji}D$jLP=%{gOI{%bYk8 zLM56FZZ~u52B|JF9cIXSh`4Ex0Am+g2X8dz2JskqQA2nPYDOCudALhsqR$}t3I*~KmML~So5oSi#yZ%rCUUGu ziY*IewlW*4yD;Ax#uLym|0W66 zKn47MTYi8xSL;E+P>b+HZ=c6z%c&M>K%Vaq-hx=)6g>M5G1F;8(I#Ffe+UCh6h4C@ z33;Er)akJXl;4&#n}yWid{9KA$RO)r`Iqnu87!tf7j;mg)t{QXf*i4)KNRMeWGYc| z0yUBauiH($$mPF#_PPi~8Ug9}u|I8SAFCNn6j&aG71HjrkECl1k0G6o{hZ@aMW(CV` zJC1Q=&VwM}0|@=3K&hq#eA+MKR=SAEn*neb%Rsn+xJ%~18>>OKkp6_pw2mHaVqQ>p zq0dN{d9b(Fx$)ma@4xxV@_3%`&o#O$@*cn&h;z3Sq4~)C#`_WJcRU|2JuQp>9{k=P z3oemxJ=Twvp4>gwzGb|0SJ(7`_TTaHrMC$=Uwaci4fjW(%NW4*)Q?!Q_BTG^Tch}5 zg1N_$qM%3bJ{tNFhbkdXI9v`L*+xgfE~A5UfwMP((?88E7DWblqW4Sf{Vz1nVR=F= zh!yR67xTgs)I#x0%cqA(2)I9s1xy&C8!KT0!b~#c6drA(PFS@U0(JN?3;JqGH35Gp zc=VIDb54_s54&T8Kvx!b(l66W9kaX~HpxWjxN8Lc-6ZjejkVlj?sl_*TKM|ibm4BY z`7ykAxLCL@l=)aA-HCQZ8B=Z)9khg3BJQMw^25Wf=rUqls4l68vwhbizQZS)IQ77p zkB8v(z658NqjwmrEw>$MAw8Vc&XxS|kw}jZz^9m1q>c;QKYA@qD217#R{QN62u?O? z^`ymM2m?q-LdogO-N6E8*DZ4T}4>PIF?aL6dX!(N#3i!tqTKca#_xfG)C=aJ)yY~e}XPJ*M4 zc|u_$PE)&~#0H*LrHNEj!?Sl*q-DTXg_w#K5P+=ox zvobd{s$P2^Mx}v1fvjo#xF723=Wz~*_Vc0clZqOs0b{b4Jay(ifBhBG(ntLAdA@vz zFMR!yl>SrDP}ivB60vGu@fL=wFWFYHkU<9W$KDJpQYS7>Hbrypl<`iVST`+fUW}x} z1YmU)+x3$C<6Kh)g>Z=_xdI!KH6dcEF~W^WPh?Nexuc19qg}c$A14!1QR3(^IK^Sk ztl{GZW}@g&0m&KH3_`DxoHl-q?~`|ONqL5euXMibShD_jWbxjSk=HvoJQF2=GOlx@ zMQNjd6ddFD%kkNge$ZL8KU)J3;w5X(S)oa|v~_bffNjoD*M^MO#7NF_c<7U&3X}B` z;y_@7=SL+EVhT@^sTh|vMFdVM0lMcj8;O$pu3R$8$8)t|G zhqVb(Lw3(hLlKysviy1x+5}AoGK^psV^~)ud=brxqM@FKcE3V~#YtiWCGtY3M9R7b zv78uyNWKDCL7d6py@t$3cG^a0bk#oc>B58EWEYY=O~3;b@#|@j_;;Z-7fRo3Mu{um`<~ z1JITJ)hg)V`dHTg73<4+_y2gp8Me ziH_t}8J(H0qb-3p(iM1%XakiX(mJ8dWa|X>h^ruXqEb^dQhx=F)I=so6xc|Cwv*SU zTUp-0%Cbpo0@6j=JHmcD%WcTR+1kN9f)~) zB|tdX3+^C>cO5^b_6<%j1&_uQY9(@Te!`eT7Pwbp_sLHqnJ{;yYb_O4#mB1Wp&Sm0 zG4cMnW^w^l8jcsShr5A8E$dV@#0DgUkV?6=VP~dh(`=v`?&zHM90(Mm2Xa3Q zqdl8n=j^=&t+#(`eDr?6U2x9b4K;f^)`a8hisH_kfa%XtfQ_^Im>5zL;up*(M?cm$ zgBAgY@`E80L)mxBcnG)h0+(4QZow)I1Pfvx3^_UJB=+1o<}Mh`EH$0SKtbuAhg1<{K)rz|hZ0MA)Rp-lNAd_7mo&K8 z5=Er`-k7EHuk{ek#zq#={_}A z+Q0fMyG%#jB#|3f{SY_U=o?Q~Q2!}I45P%eGFvMAKQ%K@=nV31$T5e%^nf`a_9r(K-a^?c9UyHyu(OIW(YGPqvU6Dn_^(Zh4^)hn#wYr z;ioG1un*XL3hSm0MKUww1ESc8{+UizU|m=Mt*BnVxaBl1hVSTMCOVIo%mLVLA4LuU zwov&OA6CaI5JY3?Wi0*r=Q-*a{s2W?*_KWq8A5GL;z9(kM;u9E-$Y6Ed1>%0IH^ofijz4Q#EUrjr7;x)P_R$MfHBqz z&Y}`|d+y=@O&^>92kWq6gj4ikJj@z4>hX{laO(LL#lxU9ngGE1d%uv?@o)kdChKti z4%(fBfHZ?kvYjdI-!7Z#=|qVn+-Fr#bVW7B6OYh>LysIxpW&Gig&c&9!%!iptd7i5 z)yx?Gf%; zX!G^I&g*YfO4|rRdMl=YcoD3u0Sz>UrXeA^w4eTRYM+`js!^t@PtD6#t|4U`&?ObI%M#e5&b&iBX$vo9&{rk26A5@+s^I5-1_Ozxzc?>c z%oirYgEoZ6h_+IdW`iS!I$TN#htSMofIR0ok;ac2!NACMw@k<}8!L7tcpmA{v)og$ z->PcdYqnY`Lh8VM&KV@8M-uGW4X zjzK>wU4lIji#ymQ&VBOF!A%xDxtf!g25J*49O7Bjs(3@*&-Lzyho2?jRgLj- zlx22T(A)z`N~>&OR=fu_-9t54arU^(px9fywEnkjJ@EiWSjze$w+`wF<=q>$Frl@p z$o?;|0{pr=W}kOxavh|777=|9_QjBt~xwvK%T!`-&6hr9+zPj6d|`htFx;E{ zAVJhFRJliP`2$eB-rX*08Ztcs2j?VI7#ZmoL4;ejDmP|Gu;Bv)n2K&j*j#Gh3JVgc z4V-L8vIeZadMuyTB4#j|xJ6zm zI}oO?-)9gf)(Ffko&n-?90D5zEMSvW*G72#Mu6bu)A5)?rE$1VwyNd;gyg$xHs$Z(P+wyOR*kEugQsNU9J zaa?TH)wG}4*$u<+VIY@?FDfjgSFFc8dbv_nj~&5pkpIeZIep;!iwzEmL8fXzv%hAC z5BXHgP0kOD6G1l}COe6@&eab^ymxBV?uw8m?!-53r68pD;H7~6BDhMhW|h}# z-71A8%%sSc0!s@FeL!^?<#YsKc1XFmqpU_3T<8I&s0}gbF7CZ~FTlJ^!>tt`nqu$w z{ve65d-L{t0So^=YunpjT77J77Xn4X_<8|FIs|;3<$-OW4{84O=hzAQ?N^{<)&9g>sG5vE#b{&oLT$lmEw%O{ zVoCdHy-n&bpXQ8!+VGL=Y@oiVy4GqB$)w2 z5I5Q!2SHFOv}<^En}b2~itoL%7)?Lk5+*kyDOzrU{hkLC+al_^F&0MhG>0VSLn_jC zhz~N0T*p<$^aa4gO0holZ(15QRhIl<2nc>*Swab>21#7&QcQyGS_DGJgJ@LN{{^W* z?@TP&O!dE=EDyL540b!2(|?S5%fabIPw+w8OEC8%>sd)~!>eIUBIkN5V}P6LT!1PE zE?`tRE&x`dFs#fvgClR!+z5fv$e>rqZ+V(uQQen!0q<$sh-fY*)K=*LB1#>?=3cogs5o&7K^gXVm8fXKkIa>>ybdqAXK#GC>V zW{Hz5CXpUQFdxAOm{>oUMiFV>l-816Lv4|Tr=nPRj00r97F(Boc4iQ6V&wE%%BioI zu1#zw_cnV58ui>5G~;rV5ZFH@=$7v;32dpC@$6p~>xwb~swD6+dLXeYXrAgwDD`nEeA{33ul77xPI#M5JkHPH73gY5HK3aHuye?u&#jdIhUb z_??SVznlP13}%8ywo7Mb(G=ptYHD+B`T!VS+(k>ELTv6MKW&+UWQlRsNso#Su3_Q(t_V`)_43L+l*0L;qgrA5GR(L&*PkTyKgpWJezLzy?3dFL?j%M0del91skK6<~K~};ZuVitS2ukOH3Ga(p+FM>ugD}q-Jj%!@LD}oF*iylW(4etm?|u>ezXFtMF(gsKz6)BRUT~@yh}7$ z;r>!&*D>(|Zp*bOx>|Csrt&wzQuR}ZE{~R)hPWKX3>*#?Y>EXdnlm*#9m99Zr36so zEyLFZ`wC}YR03NAF!E00>4Q*%x6Y68T0}9AAL1?iaZ7{EDaf*yylIga&)TCyUr{`d z5gvQ3EWPtRplu_JSm%e1TLMh4&dyJ3${s^v$xsY78#)C%0YBx14c)z6wSdONUcrz@IP6LEw-hV-JP73>*;5q#9+FdA)0Fwy%<>2=XM zAg~<6L8#Jxif2drX%{8IyL#gd?NO=0Y_ky)8($?E&F19a49c*IE!r8ax*nUuES!)j zWQC2A?&PF*vY;cq?izC$BA6KQ_V$~93tf$Eb_Y&uHaS_wcPMW2h);t68(oAwhL2(k zV(Z$G)EJ2)94M(J=jhYDj)# z(y;mgFWxh!{rTF2@lWGJ>cw*Z*FQu+OhK%=C7~cJNUy$qUh+n%vP9kn_J>(QKjrF-MidgS8Jct>mmwt;jRx`G!e z={j<=#7|K!HrZv<&g!ZB{&l@xO0OS%jr$?uaGBL5`B;dgO*n4Y1sD-nH1!)7T!0m*A~#t}k7lz-uMU=b0-Kzu-Z z>2T~by>hV*h@mS)uSOgc-;Ib`K!yOSL6gk~fNue6YXe&HpPty%DDx_SYHfIgV%3-o zvcB_THvA#&8>?o)geR+sJvW zqC^bx@0W6pusk{xuhK;+pHkl}(Lln5fv_cZK+qH(%h)1aOI|zA0zBa`fX}*4Rn;#} z>xn3}i|v@=+So5KR$?~#?aLo=KkJ)!A7P(ouE_jQNp!3k>@n@}SFl|5M_4trk;!G2 z>(pswr=1o@XIF`4+8%;zD|}FV`6}I|Gaaaj9)_c28EQ5M!A3I&Y0V*S7^xVHj$Z!> zjBtfzVktMJezCE15fq=G$nRWxEcxj%`v#VS0@!BAkNKoJVAqex(REe&_>L(?)d`~p z234W(`awjIubb~)7c@4GLur5M%dT{C&70_g{8%3b>9)At&ks!VFyRknw~n6F|cadHZk_8BfMfCY(VufI`T%e8zdFyoT*P zHv)knB`c$In)62N2PxPjQy6SiY#kTGH$_?xSWR}&a2!>N+|DCd8xdwm>BylQ#^+9h zI+=$FM^YuWA|$GSb4nyo)swAJm?r~+q-VikL#RBRMt#*@IP}j7?f{KQDi;z7O-aIZ zrWZC0E6(`%_iTcFAOmJyUwYjLH*;dM5sjEO|6+SJ#9(6Z9EW2gTy3*@$|4?UwmB!T zQFza;hd204k&r8j`-zw8V9)0v++nwHswM~mMm_?EMZh1!9gXe0C|2Ro@^Jg&F3us5 z?Sx|ZJBxjvs9^bseB&`!LTq=^I(n~%a^SV}A040OT*ven6Ty*s zJdNGL>dwN{Qa5A|CS3cY(q3Mluon65yP1t$926Y8qqIP}CF)HU^O|0T%Z7&uCJEMs18V zj!3X)Yj>p859__LD{;B~Et0E-CL)Cuir~i@XllLgMP0k#-^+p{*9nh-;AG7;0~i*g z=$6f8c*2V9;~F{S^CgUBP47eO@{mqzIf8S>g~zo~vpiw)>~*-a84a2>M&e46@lGb_ zpnk@w-iv5H=JQU(jq^bjow7taoQIM5C$UfJwR+9*%WJR8qFJ6|SPzBQZTDSt7ju4h zXgkmHOsPF$&Yr{+mg`GMVXKp0M_GJny@7g%2!Wsug(8WJ)(^_6VHBGh?z+h%&&E-_ zq^JF}#50)irR}TEnv@u24iT*X*xNOIA+;o6K0Xit@ER&7H%(!-d^tp(t8-_ z9t1|6-1GS^FKgFv*auJ?YE~!<`f?imfzv!3M+EY-M1}zaBmo%1L$S;DvQD}30!N}s zDDW#N4PVNqA-~*l(N1uxfav(rOb4a06X3vWo7GPaf%EwKStJM#W5IZN=;=x4ieO|! zw6pdT{{V%@ zqJ~66I8AlzkZ5H3v(L>O6vi5{D2VqJ*a$mfL}7-MvjJaBfupYRh!ypW74;)l)HhaS zAun5-4PelokQEHBEKfub3DrLZk;ockQkLl1c8RkJolCqD7h(;lE3Co-OAa-Q@M?Sk z8`*{+bEar@B&*P{N|4hNY+3tf7nu^vCMJ+;*#;+LT)0SBdRm`5o!`DNdMYm`-pnp; zqcc7Ye@Zt9o7DSfb8N>Nv9IECtzbGAPKLNkD^Bn-bJ*FW2{=KE!*zo9M zGz)jWix0R8u9&Dz4E0#QC8i}mkgDJ_m^*}H!o?}~WL)cz9HWYCr@_%YLtWuPt|c}R z4On5K!S?4e!~xm>9~UZ|pNHF>)k1K!c$*KN7rpa%b)CU3R9EqD6oZ>jijyFnmI62p z8)fEQxZPYF$PAbuY=k6Dp%a@#^6dQ97N=c)t15=kW>M<%m?cgItJ;^l$X7XjdogFL z<;j9SbvDZy5;k7h{v+0+=C^MmE^?^sFLWg)s4_u%3nh1le#s%Za;5+8$J z-y4GvNEsLZmV_TOHr93K6vQd0qd9IDT1r_n($8?PV9VjI={OI4A*i-a4rezDj_{W(U$biRV2&$O`ZC z0V5sofpp5J@)h2Z3!zzYRjK;vVz8UW=hR&=ssx}^!M!jQ8Ei2T*jh4-JSoZ94Rzs0 z7I!g*Fsmcuo9rWkfak58fhY%a&1n9> zpGxcera{peQ3SRB5Xshb9Lr@_P>mHU5Uc-W>m?;*cA@1Pid}~glb}WDB}Qaig0KPF z4i})Ee*2Ksy$%U{=V!490h<8G6q3xJX>xEt4rU2aKaaQK*nsv_mOHSz%&EOP)M?u5 z(O!5WY%dnhw+PS7q+>+`694hoP=Hpf&qZyCMKxFrRCW$YKVPVq$X`{ozp_}|ji+5)ElHv@y^{$PuJp8ER>8hj zv<$8Vi5a}4`^~wl-Mow;mojAoUEsaB8dxF5&f&m}(+OyA@t!-i zOYs3_eD!S%F-!?=Xiso>2vS0N5UOaqOfVwUzxNX*XJy^Wm?bD)$*ONpcRtT)S$TD9 zy0O63oy!mA@~GlIT6yiOVDZ%*sg>$~L~qX8*G}5kk{kEz?0K5Sg{+e%zK7m^P~TOg zlN^ogCR##7fWYR0BEx`i!co|1TUEb-pN8Ayd%ph3KHed-b2ZXRN zm~410iCwE4>qGR;`s@wZ7wk-qF-S%?$8p1!L7r_lCn$*229Nm*AM68Uf{${+t|f$o zY~DgGJR4gOy3xc~*sb2>fq)xe>W;o$QNYTeKbsLsryd0Qg3RrMz}9sO5aZ&}lMhg( z*@*PJw^H?HT`S}*3%hZN#IFu4fKdX1%mtDVDQEK&2*ODGjG2I+>*VSvSZ5OB7h-qU zOk%KRcLzI5@99*a0d)XAst_my3lj5gia0(*X2Mxi%1W)h;6gl{{Q7DFu`z~);UZZm zGHJgxz#Fy+h&#fboiI%mY-5fazykcocZ7)-1$LV6_hW{euqm9)c}6*q=$tarLe-c+=Bp!XIiKf}i!C*4Nq3WZMO63Z!`jWy1Mlyaq_QB_M-W03uOHDL+0&y^Cuk+2AuTpoD*31fBneO`pGhzgu{&Vb7Uq>h6nvO zHvp;AhqVi0X&)%A%MOMJTR`;PKTW1Di{pE$@{0y6O%YW;wiylpCrG#B7KnxEE*!POY?;h8GDir|6Dr+Im@ zKz9+9`s&6Y*9x`pfCJxFIS|n$W@PD>%M>9C>A%MgfKPZ-iYvz-TUvXvf%t?g+ew-3 z`bodK^M)5;Zv+h0Cm0&pR#H0)QS%pe-U(~cDtZk(guz?OiEXiAFqh3?D+W=wimiN1 zUfT;tEtRPh^p_aQS!LF|ZH-Gl$o?#oF`xhpFV_e%_;rIS`G}?D#TCQQ?Dt^^@YK2p zj>-?PuYLTlFg93kGJy>IaTwxe`?08cQ<9YR@rXyztcI@zU?EO`h0hG3jl*oVG@w7R zEyLPvcn&d0vxZQr;Z)}g8kRv`C>oHB+>x8wU~_TS_fQ2mYm!_t#v>@EJrq;@I-H_` zWDePQxSNeW9j!&Eo+mq(5|VLtpB9uAb?mXh)1(Y1e8^BZ(i8X@5z@ZFm3p^UY4xB7 zjYA*E5OU0E9F{$+I8&mkv`A(2q$L1(s9u`xi!F=Qv-1sBw@ak*xY95Jk9Hu%?RV-s)TV+hY7vAq3ww$%_jgkg|PLb+&Et4l&O0FFz79-n}aRfkjnhD^zb zX#y#^yUXMs-mF{%5N5=x>H@)Q7#L{|VG2p3x{30Lbd)#oF0kwI%*|tu#u~!)WbaEC zTn8Wt#ZtJ9C2#A~YxT-K%?k69>`}yzWP3OvK!%3CqB)EP)Le=KTAcybC_BEC{Tkgv zmy$>3S6;@kp!P@(gMZbZm<&GcRQ47~=|%CJ2b(%HaWc(YGY*-$jZV8J$R5PM&#G8wKd-~a6wK!cQaiOM=ULCTO_P-@kTLUw^~mC7FvOe=73F~znS zGQ*yrFo;wQ(pXLiX@U485*JZcCgZk|X{Hu;{ z`}lU4E9kDba6!kB=K(we@d{#ImmlCF_N4v}s%sE7cPtSUC&{02(l;?%DTU#hR6T)@ zw-2cbnzhMAw3F$KtuLA$t~=Q!>Sn-KvTM8|fAf<*){_B5^Q$B=@i7UlcTbG1DK1p+ zo-`UdoZQEQVk(?8JvzJSVVZ;s3nB3Y+@JEO)x2opVe*4H`jUAy4cb z08x+A+;WD?Kni<4f;%`&b61&0o5*r<7?B^RKDBH)@a$HV>JWhYk;ci&(uy#dATD=` z$C>3a%cEYg+D9BC8mDa_bxtEFiGf}n$;|~V!ZbAv`SKqy1wrtsn?G79-$?Y*DfVWh|K$Gl5}HmLDCY)- zzFOUV4-`T{30iaQsy{&yR8Ii;an9b8MzR!MgBaMHa%Hp(gF3pWOq~4EUoyB%2PR-xIfI~ttm~0v zt#ylOag<&M7ZM{Nd)T3g3p2(iTmi?1pNa5vR?K)rcS#@u+`6R5IUVVCB@F3qr|aMM|Nqr^y4XvJF>(af zmycdU4wuCg`Isc5ZHTs0x-km0J)x)q(AXOh1`aLJd?3Kr2?1_xz~Y^ho(~G3c4eQm z=FFgy!+xDAu@gvzRJPkVpE^RQ1KLHFEF}kC5Qj30G@~oahstxe0~Fd`Mbz@4hKIlU z%3}Dul03WkT0O7)Pu*9x4Zj7C3fh5VAnTt#Par$lBAL&;ZCGx@djAV>VTQEm_Ba4_ z>*Wjm6;Gg{?3=(bxfjt%wck>aL#9f6zTeNyYqQ7fm*kT7_z4Ss)axWKdbSVPe_ehe zU4Ls%XUNA&=@fB@vV9Br`{;7j8|5xM9lxs|nT&}w!veM+coP}&Jn-zC1KiUc8vd>} zO7TWiQPKZhaE5)rzIU%4Z7qYnT;ZkfLfEE@L5(r0?_vo?=Jf&}bNXCJ%4O}-67NwI zus6MwhkHB)I}e5Tw$w4$z`#yy0bpN(?G5Wo`R9Cn;AoCxm4Bd@`jVr_Q-18@NA($U z3B+I)jwys*L{_&~MoEA=$aEMIvVBuym2=XuMjQf^!({jIarRN<-iE(r6T42n>c$wA zpHc4XC6o!?WTcL_8|t%j%cX^mq=?$rDNPJs(cX;^?N14xB)k2C5Q_R?8tJ0nyTt#p zz1Y(eOIgoI`qS^m9xasX>#>5=T{9N|o2)t};eR*J_4T&6t!zxQ16 z4HVUHsIcyOzH`OkX>M~8Xh!mrO+vATfcf_YYpiR~`X$g>I;2cRKn9;2V=z2-9>IIH ztBLs3OI8KF_pQ|zi)KG_Asliq{9r#Gj)i+0G`iT758QAHQ?X*UMc-cp?rIFzibr|J z{UpV`ki-74kcuvJflns|qH5hL1rAk}pBm;~$$lB;7>r{D{8^K|&ceWg#@z^jaC=NN zdtDwLuw%EP!ci+N=;nT>f&4z8M{RUws2GES8eD9o+th;uVRTUz z5ERD^xxrAin?Zc@->cu4q;k8YUIcREy+TVs?*gc{0`nc;8m?9kB*RnNKo0nNq;Oh= zOPS-=Ubod={+(|na#cgA*x({Ty?CbmOm^VEC zJMO~~GP+=zZmRCsHQ~G5t+;zAZq|poODnWV*#Or{)CqhFqXYY6=xl4wQ9Hl~jLR*C zSSKRRA<>?VR6%x#FuCVyy_U+p#8((#^6cy}n|K*EXw_F3Ag(Vw%0Tc^p%xHZ>YSC1 z@oG{6fPjE|c78meRFVaAI3T@_=En(I9Y{l8q~(PvYdF1BHGC(0LmTfQIl>#SLd4yE zeNZuQP>KhM`MQGY$-W-={_1qu%Pa~Rx-C7?pnmQJ?v#=+1BPQnoTB~uLMo_~E{4ww z+9*)EBGRhsj$aYpAjwBRB63Yj9*f)U%_=|$k(5)SGm*Z!kure%hQMtdbD%8cprF1Z z*|YudP3DW?44X3$n<#Nthcl{-XQ3V$5ig5|+AdWAlh*gkc&2qhYwoB+=Ho!IQIafZl`+ z!<1<=UeJrvRrodp_|X(&gdKlYO&Bw&g(Q8iax|Vb`6Ub0=j8X!zT?&4Wzm* zzuMz0#0Ur%$4;pF@LQ-B9um?hEq);FCG98v4p8El?quZt>bW`qqU6g%B)rZI)wcl^H_j@I2pQ1iW@kcEyriS)M)xfxZHEbsD-)CFP*q@vq|@ z6*^tKsQc{T1+=~dvj>GCq3S*Qc@yq~y0pfXx;(FJaoC1wke=`sf!p+^i+El8z-SQ^ zj=fht#b7|PGtFWmd`dV7ZcQsq75M*VyNbjKx=|i8J3I5M2OY7%IrxhwD+S>h1?DRa z-9F=!(J3yUN7@G=aqb*HY$$n6Kt!UW>qn|!1nRoXQlo>7+wS)SwauRs3y_gRl7TG(*P zaA@4dC`l?eW*d*kUoCcx7pE>sp89n4wi-(TYtfEk0_2z@*KX6b)w&&(TM_bzv`tve zEGQ4iwRK?2a@n3fu5hgzOEcQUd`Gx2u3o!{!)zYgGg(A7IZJz0>qkbT#1Sa& zw|~Y@4HZ6MitgYb@2YQEAt?()Id!=D@6F9+z5IRJJdF6}TBYN-;rm+N$S+->x`%LR zS+xqW??pV;>xMYl(;03DS|#V`QzJ&T;H0alVX9Gu8s~)=A`Lhu9SyE>`vnk{+9lT7 z67b1Kq7bJ-+53ua#|`TWky*cBGsy-h$PQp=xM6U7@r%ekk3{N)+>B?RdlQg25>>k6 zexLg(UjZ)V`_0gJmBWB77}!@KzzO8j?LMd(b;5vW;o2}cF1wb6%X1`KfZP2>_5yA! zFlB+-lmS*fGim|rHpLhToW=R(G3yN!4cMZPgono}nZ55elL5FigC-GLVNR>J#69-~ z@dy_!48cO+t*4iOpXsJs!jO!VqWxx5HIO_gr>BV8Kk@_TzcC3U!f za`Ur1XeU36e1CJ@98k)d4v+ zvBiZQQ#yZcjPvFB^_V?YfPTTvZ4gNSM0vgERH_<6|H^DA>(YAhRSzR^R6Q0IzV4n* z?1Q^qPn?oiMsH*hbIXtzWfSyFklJu`g_tDx$EbJ_VidYT>DF|6)T76A`8u z`BMzYI1ZV*ALOzWCtYDAl%oO99m=UZ2}2AKb!sz#fJDZFG-q}f0-F*SBpw8Vk(-zn z>F0d>Dqah$dN}x>YSncJHbYi@=&Cn|>r1+o;|9Cm?P%8dkj|mSeR7T=slCYCET#6c zUV-4NIW0s41Phe8x5u$UQWXprVR!$Vrje7}37iMD)|4Y#8Qw?gA28E)L2Gy(HAX7khiq4*L zBCF{gNRoFt*5uhEOHdIC#0M9acgUw#r)bsMik+#iSKeIPppUY|Pq$e(~8Jc@$@o#lEK zI2;74D5lk$dJQL*#53Qq7GHVgjLbaAy+@CHrB>z%UJTsDlfkJw_l+ z&ZTQk`Up{o2InOZKlbD7;y8n3zJOMJs#Ag(q!TZqcS`SlF_tMFm$=wq0LC&^mkHu= zdFrVI!(!9}FdFUZ-J{4`WmMtdT)@$XH0RIaR`uE$Zw{fdvu#9e*S6o@gBik!PM|mg zcxHeYVVH0&dV_blwU-a^oC1U$rgPy=o(xQf-v|40lp8QURDOsRFtL2R^=)0gwf41O z)CR!78Omv0D3&`JA}ZzY?7Ljre5h;SIKadjOf_5(gq@8SxWCb!$F4}$1^xqPtVanY zs~)25NBRuF*frw4yG9(jYM`TD?bG8o4xXxHuZ1jo>lw3QtS>{hXZ6C`k?bSn4%2BM zxtkipDTA$Bm+%PPB`l`cx9D_Kv=SkZ=Y<_AXxd|UH)Ec|m(!iJ!K$hhmv~;#`lm)E zp$veJyM^5aUo?#t*7|uqPkqLy^P@lif$N@EUgUQd?1Gx(P@)!PxqZXqdHaPgF$}j# z{VNf}xXLxf$8G0h`BwYUPx|d5+U*@NptGY;z?e*p13U8O@iZsm*-nU|WLLLOjlqH< zMf(?o)tCj-;8>jY!4ITgcscm>#!qJLn?LC+fsH<7-atjiYHz>%+qvPRG?tJ3`;sEz zw=zn2W5|!V&eFu@_B%AMjv_5$aJa~&fN*{H2~z{ga08^K9z0jNQO}M*w$7hSsp0B< zhHSMa(sO_G<7Km(tCBV3%} zuUTn6!V+<%)iPt(P?}CWYUzcd{p)ztQHr>(#}{5+Lie{y?tl|F10Q?3 zGN!CNhSG=Ls=k05G@k!O$`Yj`rS7OHj?n%$xWO0N1*ql_{3uRC_qB!Ywb{JSUGz21 zz`mos-Ua#Q_Ih5U+!{MnEi#)L|NLLVSmE>49o=|9Qm~cTyOSsBG-+cQ!lCY7`mvAL zGztnE9I>lslpH$>Q?noas~k?r?fA(CNGyc*S73#(8PWYBw;9d%R9_t;u)$dChm3z~ z{EafgI3-W^P|4%IHR!$c`-Y^oRj3+#DEXG|ck&pf0K8 zm}ksdH&E0>I0$F+hjAbCG(W7}#XFJn3cq17Kp7^yOe$yfZchGl^?8npFmw&isqXgB z6_+Y&_NfWFX>d=wFf~TG4-vuK_p}t_=$C0Y&4JLECd@H%cuDgX1g7_z4naL%(!Qx5 z=KOhPzpn*&y6S|x;1I=H>yeC?v#1Tq8#@Bjh-y2ol)@Y#viQ zMZF{S>#F8)P6SPl`^c{VI*tGBV$zpsV`{J9>=Vvjv;Ztf}_@m4VlkO z0)(_K$2Q$Gy4)A9pfO=_vI3z+;#X{Ri!j$n^2<mISuqds1b!!sAxqG9zPw3x_)*$~6r-MJyPoDO`kkI?WjP*LT~ zzF_G^sU$QxxW?z;@a@^x#Jjj#;`IjY2YVg~ohaFhx1bS7%b{wKahbLd_PdhL4j&*y zg$P1wxO2qf@bBQ*!GAPvpV2;(C}(I>aL{961P~fI4gDu1W8mo^}IY5mp!C=+dqcx(rbil zF|IgANEg=L_G*59WoRaksmgRgx`bZAfmoP0OkBh^*Qnr>gV=#J2)cLfgZ7v4aRKmw zq#3!PIwT{4LP^#3-3jo^O>CO&Vs;*`*D{4p(@29vkwQNZN1NB^2|@Y;&!Beh56q+4*y>SqX(Z0QZAA zn4pu=wO@&73udkSlIM{YT}~mAYpeR2=|oI2?XQam3NDVv|3@Cqy5Prosx3FqvjmD7 z(6d+oQwZ-pv64GFPetCIr61%s>JC}ZY(%FRh+9s0&-{RyFB8l(RAok6E=W+Si8EfC z8FK?22yxf5D3lA{^5=Q#iesRPm!Cw1x>OrcE#9MUGS4j5Bd+110dgtB%CZKw?L zhKR|Z#NgQ|-m3IM$I+M&JLo$0_|h17M4?xk+L*W02>GO{t-U zm5wyL#@3N7oZy*wvBiqf1HOvu=1CGiT}eTM5pth}xV?dnbo*laA4SCozPJe^(HDT( zM*wRNiWCk$*C3L?hn<2>h#wlm(QY-{r2;4=x{WROG(8MyO@47w4D{HKw>n3NoUvF- zvwyl7JWM_iakp!s3iCzgsUZdY z6%_*+2U}42L#S7u41Kd;?}OXB7?y|{=`-puE>n!)+VwAI0?Xt0rVYt-g9RODVLPn? zQsZvu!=MgGfmt0PB+?t@Lh;I+Y7Ouhek5-v*b5>Tlja}EIwL&5y8EERgD`=NLoIbXaa5&VG@oTy9!q5ND`@3 zzlxr0|C{b5W&4`jLiqOG3i$EA>|!ch0TWw=x{g-4)C|65^&ZZ1k+s1Zb`2Gmy}!Gm zc<7B4k6sR z<9~@@N%4>p9#EQZ#eM@n>hxh8-fHh|4#3q96G#y^&9))T0IwVr3hV2ND6BI#yOE>Z zFn&pwEEr{i-!I940oNPTa&D+L7TgCrqQQ8 z{;FW|$#QiYB+*$kyKrR2gzB-GSE!y5a%Gnun1C3e@g!HPKS#B-vw9RcZS8T8cmn-* z`oVxQ&=HaIf~p1-+1^+EDlTNYfeCCoTG{WC9Ia=`9fcbuTndN;3t=k^EK63lh~N*W zuYB&ZXdl;Wc(4ZTrx09FeI8E^C`HD7*;RM{8}^#qyTTsU6=w?$$DivzW${1PIa8cu z4QPBMtD$*<3k|3OfEYPSsQxiR6v&M;b6GP$EGS`&yHW!b?j)Kw10d`rIT9C!V^sK{ z;z3%tP?6a{DWdS?Fd!&b=;H-fW>JK#x8hSHqhOU2X!C zq(ir~&3l?OgZAI%vx%~!Hh{ku^OGU02Hbml#kF9Xv4bjYUhD} zYEbQ&xhokf)~TKI=Fpe$+API9t#_ElSXVCo*;CnpJ@hwfXy?xptzI9G&Mp-z8p=8x$%9{o@G-rjxAavWnrUUJeMNn zj0+dBW=`xD#DAQk7A5$T!uMcXH@;982d5s;`D6BiIdm}gM?KF<>OiX^#BNB$8palk z5IfP)Aiel=wx-pe9YtJ@wd_qNKHe!%j5!o>02zL9_uvZi*ncUC%HSswfAwz{+dQ-f z=?5PFwz64bpBWlVC+JvL7F3luUWzk;oJHgY@k+Tx8@r~ZTRMDVEvyDP6I8N*oWT`> z4DPPU%Fwj~&AXV!TrKD7oj@bvAfZ@5E-(+?r>JzNq{3t0Nt{KA4NrLv6!`uK)C9!N z2r-482F`o)c_IlRF`nPSJNfA{+f(pymOWS}vR!V+%$+?#KAXd#0DJ(vjz|UOo;g0R zj8bKNYz7nRa1N^#^GSpOeO&TVjpj>)q>(A=O4xs)PpE70BjqTy|LCjYd~9CbfiB|@ z51vw(Lfe#Fi_9*USpkUI6*z%5#(bRE&Og$C*p6WvO?XUgV-_)dzgX)JVtl2kD2Pu_i!+P+v$O0 z(Ks&15dIr%hC;t~4C~bU@AeBG@Ae4)G+q}pG2eiLucvPl>$1tie7O2D&`s~cJ8|`y zbRWATWtSp43)ApHWM?A^nx(LdRRkDvikI*L*cwA-4)TzadqpWdP{RwnguI;Gh9;X` z=kz=2v8-&S z40>c87)Txm3G%X!P@E$kCr}6S`3@bvcnWu+4V%R4fC~4vSBE?2MT7IsmygGt~^RlAL6d}0|3&842gUXC?0UW!r_%j(!B9vI!LvlO57nCP0uJKU}N zlrXcFqO(V2IGu!_!AbfBVV_cCi6Nnl8$Hw_D;a}b62M`YqIl5)1XpphhF!AT8Kby> z0nwd>5)yJXNrR1uDdPq~!_%8}&DE;gOu{BR2W27!_tT~UN}9utAxR7%aLg2@ggACQ z;1keevmvA4rMH45f#guIc$RtGg9)S}MQa($uE{ntEhd?%OoPHh264K>)a(jQ@DO;4 zpq6K$fIMu|Op@eY7OT&?*aJ^$ILh;CLJ~C}TxKa#DS1d}N>f_YvMg|H6S=?xq1(r* zfVW+peWs@OSMUg0OY-`vz|sDQ{-SUq>YeM?ITwzH>p0%P0TWm#D#>aJyj69!)$x2& zV`2;>X8v6gsCGFg?t+Xkp~%Z<737yu@33{9nNgRS3Jx+7*AhX{34;X&j1~}TBP39l z>5!?=N!b_$hn2Zn%f}RD>TZE6rQ?qzXW&d8+J&_H!ab=t<6{i67Ih%mlS6V;{FB;$ zr23h`j>?Fc(%1t49GWG081oi!j>H3@2Hx9hduJk`Jsv+$?8>WVj@o}bgszrF1PV`u zXl2!+%qb8X^!`d)-y<8en;j4^cOgMxh?13>vVz1mB-Flum(oUn*yVO3@;iYZwR7%H#1AsJ) z8bp)QBkIZ1#MGc(Tv^4=gDKK*5DF}`tfwv#;UcjTb_$KMI}VqvIzq#D#G)TUNJ-BL zg<|cCgu6Ps=zJF6=sI@|L5bf%m4i^mAGzwXr*v#5+sJ=+TS>c;tcSY7sEiAlXhU1+scv4BmaTp_c0~K_J?w_2phAt2L}_qE7S0lKF=?QphqxE~*e+#m ze3InyP}F6#m(bF9zWPwKX)}6Ckfj*|N;7c}5Xi-T#5%T9FngOpV5Gvt(cOCW?XVpp*&ZRV(@tL4=JoL2_8s5cC3pyl>Xjoj zAih<8Qw>jzO{`^7ox2?)nE3MHX1NUy4osOn@3PGl>a^fluepq{3qkK*bGf0uWzw-S z_k)e7lmN<6#RY8ruoayy_drZAfNEfVL#JP@FXQI#;V;0gP1ugHy8g3apiu<4Ib4n1 zD*z|_0Jdqg;lr_z{TY{qgEAFO^(ablxlAQuV^l;4a^;rTN&BP)5{`!cHAl+ohoeG9 z_)vp6NPX2uCIFE_t}whbC~QonMHsxqnqxnW*AhD+IcUBRfg{6+(Mc0WvfJCV1* z-~{%-O_V9WV9qj(hz?QD5Iy3o^@wKUjVWQbJ0%ka=!B-=F7oMj1beky^;PeWS6mv-p6aAh$$RsR6R(2f5|GYOM6MP>7$jTH) zvK&HkHOLykePVfI2$4O3Tx$OYEs=?LFJuig!B5_S#x6DPd*eNPV_&l0mXHj*x;kaI zKW{+u%_TI_T+#j*!|&Axk7SLgid+fm=w?H(joC0RnL{{>N;Q)fLyzh4r6(%G9all+;20g%2GK%O^%lzK*%Iv&EJNGBHiM(q zhqUVWC4Y(!I!_4KPunhXQJB;VYCb*a9QxI3CfzB8^&ur%B1emoN|nYzClh9Cs%{Dg!BQpJLVD0 zD{{Khbf6xm69P9%6{*mmOWJ6;V>(2%fLyzoX2hw}MyVhWw{Yy^?-HX;2Qk84L-i-3 z(BkAoAjscYg%ngHt1fA1t_!%J&>>O(TY)r|Ux=MZ;|d?4E<#uZeSufV%X;a2DsvPu zwk|LlUO?pVxm4Q0nKzyl0ILHM=|v_1q0_Ew4c+M(j*r3o=!vrY7AP0G`$EcM0ff@f*xnswTJGeoGuML z!%u+0Vz`71L}>b%ydK*(h(pGWs=FbvsYLRBTKzEjEcVq7+nT0V?_OgHn5k##0T3Iu z&rL-O>0RTZb!*#m&)jQOVp!mQ3-@JpqUrr1PN8T7fe+)K3c!SR%)|Qt9pue(Q{sFfi z>9yzU@@ycjYs%o|i?EG>IfpS(5yY-%u-yjNf%cnt9~9I2WotJt^3svM|Zq6Ntd z7_8FK$4S)Uzn8)9N)Y#6{=MSnH7v=Ghj-+P5Y@EJ3%uw$BAmje8|mZ;VNL95zoL4& z3Zk;lw;^S8Kim{{0i2hS<(6Smmh)xx#(Po*qc|gXpQ!v$MQ2Mvf#l>xl0ify&@CeH z+K_e(>$Bv(Djj(^`VBbP{tUlp8#c}}%V|IyDFqTRg#3o-vKsh7rh(*pY%!|+@nA?0 zDy5-}DSBACNW>+U87FO#RfUqq;25}hA9M##b!ajTkb&rv@R|{=&%<-QOK)s@nE49U zG~(G+2k5z)Jm~dWBp$#@Q#nT_6&cebEd&z9{!7tj7Bk_y(-_&>kEEIK=sw!ilvsTOG*oUaJ{1tUJIUpy~LN>t<#PCCi(8l}8G|^a}nOhx;V&@xtmeyp&AT}%%3m({|4d$rd zZ3fUT{-3283BvULm$skG?}W`ToPSS}e@Qa2^Y za|Miq4#w??9j_sadA7epHB~K5&*Eu;g#?rH%Un$j4OFX-)r=>S#yV47;doBPXv35L zfD8~XYxqrPmKSsh=gb8AvWu7|UTH!!T8(iEE^wd;7cAleQ088pUiv0#=AD)<<+)<8 zLDKP=q^z9yJyOm;8O_(xq6&H-+woN9S-F zV8`9x0r4^5G%g_{{<#b9IE&5ds;7mMg-hSU?VZC`H7aA4w}eDkY>6nR^$Oly%Jo?o z{FZ32la$*!75VMvakt&BO~Zr2*@@uj@CJ^RCvD_eah0LY{O z^3Xu4*)1%8=$*!WAIBcTGKTM!?e0QoZ#M9R=#V0hb;fz0K7%Od|I;#Jdkk+G=OdF! zO&U&b@4!gL8}g{MDj!Il;QV8jMqa%yr&s69>XM!kfYbc!X;qftVfK_nRD zdZ}hGkYbn|Gh+czg?30=tgJ`%L$P4g`Jwu)jKz?m<~@y$+xLXn-L+85MOLDEy_Y*S zm$5!5XNP4(Vr{SO+gaZ&~Af`88&!vQfaeK7YVr6zH zJkS6%0`>wW>!_x@{*dcj33o8JiJB5qWr{FVRUnu^%oerY0w4M-YF8iH2yIEN1Oub) zUz^E;6D*LvNjo9%_)lpkXl+S55mFsyt5_vP28imT3&)6={E@BvJ_6QVwsLaOF0Auh zph=c|upnH>kHne?hj0+%R`uJF>I&j%ZG_LP-~K3CK%5+|%%V7-PLtRkfiarSdxrP) zIktNKSZ;JBwtEZ$wuOv^=r}`Q&;hR$Md_wM=vKHC9b6)YM<5dau89dhx%7-3PUvlC z^z2-T31ar>e&(4uKKmr!Z|IN&hn?u!{UF~Ze)-@~&V9Efv}v_rw3> zn_VrQW77ktkY11zti-|*#mQ4>SFga1nNbcuACA!3l?2NhHsEt;FWz?+8Xzwv9x*Td zOl>6&o=`MAgDp%;Py_|Ft^j9VJ8AZa8+){I*{dM?S!9peRL!GD|LpNK4Z>0y&>2*y zlDh}P6f!(+42DL>s-(-7<+UkWPw4A1LyuR&CUt=Fy8EIsJ*RL>91{Ep+c*570BQeu zfi<)$hPj5pBscKXv2AS$4lx~(lgKY!4g5kunLaIoo_vV`)eYJJDnVD>*zw|9WRHPs>1#O(w1DJ%=ilCP3GMuE>xL0=>SlsXaAy&$iCkYArD(xs@S?e3uF0ku>2M(ju zix*JMWeNSm#)#wcf*Phv_*}@ooZ^9<(hcn_v6)x9h^r)u$0h1LFzZ7uWsmDowa25W zfG@Rh(?+L?GoYs9aficE+KSsE^NTrg14+riaU4e>6ksvO<(1~D88$b2X7~)qvij-R zP_YL1Pw>6+{tg`PdBngB$Jx3UIH+mG!{|v0Ft)_utp!9~DE>ek*;HSp;7@^7hyW}V z&^%es7c=2zkgNcvB<Wf=@(p&K+-A97AGl|#V~>IoF%^g5ae z)g}45LRK*zC?ghkN%d~;sp6kU|G|eQ@XWo$!V=ePhUe!EoG=JJ{ zP=j$K=y6;hqI9{~A;n1V@b2K2&H1L0m2JkFTeErZi`apmquf1_bFI(UTm4C8fP*_6 z73PAKqiAyfsSF0SdG2N0$rdT^%t&LcqB@Dk-#;qSL*2m#W>{ ztlD-cCyTlzQEz4o9MT2VI)<@j%lol4Z(^%Ep5$~0hF=}mcw zLJLSEL5>cO#HE$DYGz`azlG0JpV1YRswF(6kwP@$jee>*ns#e(^mGtIi3jeQ;>UdX zjrmsl_o0Bep}jZ>lv#<}txVW$n`61jghI@bHX~bfp@kcV&EXxLSFUpBiH%uSz&$2x zsaG*~Yg)ldgCqzO&mm?yHA_pK0@~nqU0A9xy*#g05Wc@`XOq+@D0ZT1boSW81qjDR z`}BHOTOj>n+r6qL+wM^^?-FhonE;K%wtJp=d+fSD4JNj~@HP@9oIKO#K_}Mq1my2($OXfgg|E@6hk*Uskwk_4T$Ka8G7*@N(!Fb2nAG@}n_(AC9` z^yY{EkXc%<0n7u^WWB#{vVGVx)W8VmjT+Zu&Rf303s@h1&iaCOW*4K|Z`@V;j<-dx zAc`7KC?oSuI-rin_sw>F0ilV=5F0E&$MiqY=G$t+z%@;XScYprBaDY5Ga;VHq-`z+ zyK0Z=LXP+H>irYZq`KN+mp6g(nVw?WQ|TJ-$+(0>HWJnQ4$Gyes->VUj4x&;pZ=J8*1_raR>hi9TE{Q zQ%po2td#P0XkCmCxu*{zt&%S>r9j;Q(7>CW_9b`qi7ihcv;-8>N{TOeom>N5jK!O4LV|4`;6fLGO7m%+Xq4qJ*tguz3z8f&O!Tt_fbx@P z02q#m%y3b{G5OT^xuDMu^la$DY)+62deW4pk~9I&FgRl)Gyd7-@iF?fw-7QAeajJG zoq0)XJ$6MKEAvMpl(agZ&Aat=RmuJK zk%Y3O_Q*)3IfEmR2B@B}r8wzzQdDE5XXMwo^^(_$;96=0=jDBC?AsRLQG zKf}i0hk<8r!C$qI<$1m=Widh-!5_lg`~?_B@T>tmD;kY83;yKGiZ}^WX+X8>#84zgZi^h$`!~ zR0WmOTU|f0@PJDzbKi-Nfw)~w9LQ4X&!A3&!$|G@wwIC40PEqOf}q@ZMS$>(Ni}g~ zEC;!cAIdwvnf3+r*1LkP1Xx^CQfn;b1{e=dmDJBQm%f)A?u?9?nD-V!Y{h}=rtzy=edUNkd-31O=&0rmJ=i*9eiF%MWjcr0N#jIWcA@ z#XI9vLqLZTZ|~Js@T5IXk<*bIA5gRSK~e=Zhf;P2c!CI~CBjv#ALob$$n`pB!KJZ4 zjXK(S6Yh(QC9_5-mP>eSoXnX9$;itlE%`9?EWRw8ayqMMxzs*DRTOKP061uQsP7!h zT-#kN#UfW)4#CPe0^)%1W(+l1U0Oo$=aJhu80Vg(Rq*n&b51s?$M@ok#|ua(a!>od z2&;0>U2p}}@G03tZ0+Vau8{fP!3(2%0nw*0()d>0RBB%~rw3^w>6rsJCq1&$_`!iX?fr~q52nS&_k=G83IpK82M?#`R)JPbo_F;3 z@G&&EHe9v)c!pT?Wj=aUxl#QHISynRd-}&QoDCjN6sxh(KK>HA5aJVpPt*j&aZ`hE z9#llaW9nP10N-n%wLP#{@Z}_ehT}Ia>`LMXoq{@}wDg~5$+Vcnc>{#fi-(P@@IF_mTwvDPOD%}wwd4+fJcRbb09_9F?m$!WRX3El0*_1

    H$_EtHh9SQ`;;YS4wn5F$_+yYJ~(lrP(A_eU1|5;d9#)K2w`Bk%P&w z%jMK#l-(fbPoc!=2kn6OJTNO6=scOiE?p~zV0;^*=36YXFIown@(;o4kk@)LN>^ml z4~Z^5Hkeh(km6V=ycHZPm1-?o5e^3dPL*#3+}r_Rk3~{7@3qI|g{=kLxq%sp8^!&T zxK;cI4SiF7>5g0%6=MW5%Z2iAUtlD zP=}DOvG`rl$Iv2U8gQgy{E?mKXn*wH`Ftw*xTT05r?Hu{L*3j zcW(f)Ao)}uE3u1y3S8>=m1VoOJ#Qok$NeXD3uq=@?Bp?*2qZ#Xxbyhrf zl%5jBl42Y<^|p?}YM-ykBdZ|vmZ_&eG=Avv%bB5Mj+E@~Xjc=zG%Q>5z!#x8>=nM% zJm!Wkn1$@2U%g`y3&oYFp(rVGgGeHDN$|toqAE>q{E2<__T2s}-{#JrZ8wl_0FjGS zTiA!`6(A8k8cvm62NHaErXJw&nAzzbN{p_yzYaaANwLZs6bz?qs2hts^mO2HL@*1= z78APVcp_G+7qe3zV{YnuYnx{hoYixgVp${9W71=Q0pey2_{5nchjE_T83JORk zC~bBP>e98BRw+eA-_`4_U(yqJ)M<2yD9OeUS)bj=tGKaT#Z`T{9g(UULIypm^Kf9F zT(Nbg9(owvRy*2)c9Pmswzz5ae>O7Gr6%3q8`g`7OFf@Pu)LMF89$ zz$KKZ^lF2-ke+QHs8fMiW^})seuCvOICLEgQ!q~!7Y6O3KQEHy0WViO)#@52O2#_N zKPJhmH{~oB@=@x&srdvPYN{S=$(B;Vfshc{I|mvu@Yxj1NM{PdG?*ImoK9Q(ge;wF zspKV_4Wx$0aVTKpcKhM!HLk!^Ii>BAAdh~1iRM_WKDuJnEH{mgO1wpSkD}@f)>Qah zpb%o}-6p_>iyjpo3ucO9m!d@@hwG`6CLmrXuoBbUGSMIc)d3G4B5!rs&@{3#LeyT@ zaX?i!c@Bl7a3AS(Su#~g^KoGG1wg@vZFkZ0pu&aGNmAuzV6>Mvxy4d2GwVpHQb^L1{lQw%T6z=+_(lcHfSE z`>LFi)O(i#2h8#Ro45}7bg54Nq8gt3@}IxOeB98 z(hO?l49u1TGPr=FhOApdfTJ}aoZWPW^k%S~4lW=KsDE;cQh_Z5>Db7a>nbyC`fx8+ zjYFbBqtGtjMPz9q89OHu*26PVCM(|N2t_b}`9@?7tclYv>8dzGqQe<}s)oqL5j5Z~ zEPx_=VK=1H4_P#7tIgEd8v&CF0z=eRiDRn~D;4Ko$H~=jVo$N;r9u1X%dy_n49wQ5 z;qk5_;LLr_>S-`JiD zRhm&E@2D5PRR*-P);hiS++*~ zJf#p>RbT03$z0sn5cGFY5}{DhO)@~h8>8ZYUWW%Sdz9G6+2CVv))#H7{Z_w8{IY$P zG&vJX&43?sJV-K(X&(*rcYxxn3^V)y3f{ot5LMbH@p9tZ1{RS2zLBs3c{CRTu2JGC zBr%6-n$@shR%&6ZU10G57w;lP?X(l7G35jYatct0Ec!PXpD%V+Wi`Y^^aAk|nji~L zrl<-8k}si{3zn4SfvU2aOr4*r^B2XrrS-sYrx#IMxV-oxt8`o49-UTGxvM_OlwXK` z;NEgNpmEi2-~pF(rFvIR@%oP0^lxRk)R$I(}oLc|45*tuH0MqRwiX zW;iu4_UD%8VPz68gw4r~rkp*PycaYA1zH(43{Ud`idg#b_|JAK@pPMYHvUS)Sz%wH z{ojljjZv{oM35q=&a~y}v|NkO+&SuK`B202_a*@Ga#Nh~x>eb|4ffp1axT08Y3?Gl z5!3A_f6H-MGsi;gw9|Nq;of4lvfW{m`$*9}Lg%Jz(WB=TJetjb)_q6*bEqq-{rF-; zfx_l2g)qa%RtK(pM~jF`Je5=7$6lekmmld~oKzeu(9KeMdB8LJ!k44Ps%wUib9MQm zR23{Pf&y{x9AsWjf&J5TYEG8XhUN3Ynh2v!d~Lj4ALl_Fge@zz)8sub_W>ZZ#ho zX)K*7aIU2*kCeit!>X}Qur2rs_`>32PPU$!i^f!rZqqtQqRD1$$ru_g_m(ETfiDj- zR4pN1+m)3{T{}%zGxdhvQI2nzlTezS>lYJ?`QrwO1>%#-C^XgQ3Qs!*T~l5V85j(B zd}2q$6$*$#NXaHIwj#F6$a3X0I2MkMwFvTF82`>J&Ss}>yWqL!0^tH z^X&y@^=RYNE@Ws4etCCx8^?aLWUib{3ws<+;0v)W$sep3RX}spm|vJp26HqLv1rJS zMTJEDz!Khf6gS_FkdG#WIU1y+k|@YGC51_kBEImFUPIiV}BJk zO`F_h1p5K7yZ@JZ9MA=3wR^sskwxfk$7gv%T)OdYu9Y{K)OGhfiK#dl3PKm*lv<_m z>PzfGlb&RKxA+g64iFcjgeE_=sLGNz=P4G}Z(|vGev5yKRQ9>UKkcgVdokSSevjSX z+BfIze*h%x=Mgez@cxGfEJ`0{M5q`HJS?5y5Qu^3AeKEH0&=BS|48<)fOs31PowmQ z3QZL|MoV#JuJad>G>9P&6kBO!BCnWf;+}&cw-3GB4H`z4nM|Cla(kUQA98!TnzC^V z1UTjhZU;d)i6N@XZqr&c%_DaJOQIOsB7&7c?xiHDX4yh}HF_9FlxZ=9%XgvugBbit zS|l~d@|g?mhw0dEPIkXPl^$ubR<6>)c){|RJam0L>D74I+JI?w*e;fwCJQac3h*G{ z0K8GLcES3aUb7BlzyTv`$BUGQ?T%OC`ki#@HnU@FGXwi^Bxw-p&&Gh+_1w_s$hnP& zpr068lYu`mPqeUZl9Fo9IDvlE{)MmsAdF{&6{77W-yM0vnlRg5lSS4fO6)GQdl?j< z=NG};5trYv2zE~0i7i$L_-;zn#AQ1S$N^F`iyl@r;f3xRnmX-R%{D#n*y{l(GcLt) z!##`#Z%rWljvaX0aACeOQ_C3gstidqi62ph3Xrk55W3_bV)V3*Xt4dLQ{d0`a3D8Q zeyLR)r_OL3J^UiJupdv;#%TQCs-MBUVYNVqPzAO}!hvxhJc|;gj0FSTP^tybk;iM9 zitl7*fZ;_L^zH(ZOFLIE)^9yF){Ms`X(hMKL;4}901!MwQ_`{uoBmKiWcur-mvS2> zUi~~7^id&M)fdEGz(|YP^v92tPj%20xfFx-;MMG}0y_K+wUUyP+Ws`Z(kz<7RGchN zN-1VOg(R@VAWJ3JQZz={CpXJ$GlbfOu=N}w>!zvXsPpP7VR=${e;64+0f^)YFlcKG zlhR{82MasFEaC@KRTu_*cO+PR~6$A*E3rM7;ngv$VOG}M;1}6 z2{KyjWO+aqXDg|aEut>1p&93^(GBPr&BW8V2xpEBmhy1yyVr?WhaXRw5h{J@^wQRM zH0tYeaO#3m9TLmcN{BY`ghe;g?NCX`+T zSlq{AC@9>GmoeFex9XuIpF5rCnTN2e6&J-LUVp_Y4CJ-@s{f(MAe|^`!A&JB%`d=l z_>9Oqu4$TOl)^e2f2Pt;d9q=W+C0sSKyHE#d-l|}o8R}o^v)I@ZTpd!rm_VMgS*kI8a3_r(CmS*a?D- zyg^)0G41xJJ_u%}STYthgG>cV23>o4jM+YP4-G$_-K2rcv|q-@yjNa|DJBzuNuU!F zyp)9K!ML((36J5Owef$qgV+hJa*@BFX1|O#LIq{5KoXXYdH%J7GpcC5_^FWDk zglH>4gQ1g--<|J@B`2Eh(FK3$Vn`QQon03U6eZ8|Y*`Q2geS0E8BX-N(K*wxqEr5b z0mYrei2kF6=wGn7#d5$1aiw+%!g%zkfn*{@cTLrm5FKnHO(WDn%;V0oZS(QR@||Wm zNC@qIl}smuH2B5}^3frM+$dR3epB;>pHx!_!ABUIvQC%5^I%E^ds^Y|QF<^|xzpqG~f0@HjwV>)^zs z`t#%!)fO3lZSlXJ&Gq&&&N&S1#SR4R)|#be52S~f(Je@~zy~hF0w(XU8Ax1$%|_7z z{1UTOf{zu6{+q$6RSN(`fmJd+D2NSrb6*n$`_AULmz&yIYufFY%BumZdSg? zqXaso#EU#iF*T@~T2XGf2Nk8yH~3;q_=;-HHyU#E3sc3jV&w0Mb zV}8cVoT%tMAao(}TRTp7?9C|AmRAQ}@0!0Ql`sj_B5|30pV!u19*tT&><+9+BLom_G=%`y}@PJ8<&}xr&8i+ zsF%~Jd~m|v{2~UtP4n`)PI@qFM9O37E*Ae2OXHLiWIyz#i8NfhOir9uzk9 zIm)7=3~g2aV8;KiqN4B|@mQXVY68|Oarw}%tVhsmKQC!ipB(u^iTNs$)=8MUhA-S@ z7bZ(I?#?@hcYY2=*GD5%}4)+2;fA*26U7f|l!`{ZDSUc>HlZ>8)()_x{2mlcN>0Q=wBhq(8Ps zQH>1yE-$j+F^;~QL-n`?r9it?RMXd3go^Jge5Za^?+Bgq^%LN$Wl+A%Q7GT=eK>jb zQ{DTAtB=FVd^@#QS7(>1KiJUY#uxfeG9VIEu?Pi~DXUGK+02g(w1z>_ zOh)ZDNeio-tccaD=7ZatqwAGj8n=t($+YGxO`Hf+kF?xb4uP$5K^(UF%MnS3sRbM0 z=skre%Q*y=VcmyVM}G^8KHlDb&ja~5Agks0NT~GHW#V)xBpW@2`Z(e!8;(Ur?^6*N zxmb+P#p3&pbHZN(2!SnGp`sG!>#7=z+A9bmsx-#S4AnEfZDi^&`2u=T_|hZ8k+ks9 z2-n(jGl7w6^lzN;dR9-MRep=$=}G!pO!@-fCYsgmH~x|%Kv~~J{|?m!LcgfK%z-V8 zguf_nInZ^AAT%@+!GsYk0-AjibP?3av9S$c))4m>37|KHdWJ zM=e6@Dc7t5rVJ8&0Zeo4l3$UaeOl9G#ND{I4Rkn%E`C7+7ZEV?!`XL?423}uV5-~vd6n1!!=ZHfcmRV8mhASqX(>_-+1X4DO;STXdjg}~F#}8F`F0A;`zLw|= zu7msAUiE_`)676@vBKvXv;~gn(Zx)lc+~zl@IWyMM0bQg#HkSN|I0$fAs}z=J&Am zLcluA+Htddp?dien08$(ln=nUr7ys`s2WjyaB&*-s&E5zq}EM)n_%cS zvKTS1kulaX(0Obz^s-1Mvs5|wZJ8Rd3+4?}!A}CWOe_RSyB`wE_%&|W`pZmZ zOUSE@CnTOn{<$Ivaioyq5z|jBdWvd<``J}n7Z)G|NN@IslTRSHCD9>RUtk0$D)Hnn zjs?->_MFUQd<1lY!9x^} zq|49@o}bysyv5WWtL6NA{;Ec6n*15s-%#yuhd+ZZxx;}&3>W$22}D>9DB>*}QlOFl@}?Xv zr-I4QUq<{Enn*H6ejS_9e_e5JQ`6wDl{q|$sn!&Nd zP5En!|HN@X!LjJp^_L%oSp|31zUAXY`k>MP_p6tH5!%lH&C?7WK9wH}h4}U#Q)Pdi z{eh99WgExa-@A}k*Q({?A8h~hH(k{p2WbP~vqg0lwU;6rTq17Y6x9P1k!L_GZG}IP z#-MLfE=c)UAW;-22YIJ-+>Cf=RQ(lngR9$>CYz3G(i>s5?R$?h5 z-Sv8*48iqS>sVhF{2o?3#GbM5k?ZwSK2s~vHV(x+NLfPf1#7{&LUV0q*gR5;xZ ziGM|)35u|lGz^b+ct-|hF*N8Ml^|SwT}WTHRxW}U0d8=yzVCA=1h5rQi|;BCJiw>$ z2``=+-6T9hiC)Sinmsly3e@HlsbBYTtKc;bF?^Wyo8N+yE$*ps{C*m{7lsF8YZ{qx z`yN~1P!yT^w0VVbw9yK&F<_GhTcp1YccJ_4sGG)|Z$KrhMBX{qMfJYezzUv9d9Y*r zWbh6~Fj4(NOpeZwTOuLJZJh{*gaJS&@W%?8a4c{xNQm`r{R1#* z;x;3?1R%01&5}la%dMeQ577UqsJhX>U}k9|Ek(ye*1Ws*ufnD@nX%7R-QuihHr;&+ zPF%gz9SQW~*>W=W0)QF;RXJJ2GV1IhTq3v(mD>`)WoknUaeZKGs(K4Q6zc<$H+&9_ zTh9H`uvi$@P4d9uw{%4QMQI{9>Mx>X7^m8lo~myp!5ZiqcIeoe>l6za@M;(X3lro6 z&Dxa2ss$A8>l2qOir0UGCLEx9>Cd)3ue|>02R@ zd3|p6&BD_hVsWhcnhqjf2J~i^-j6|2m?$sDI(y&&PTOVAG?$CZ&d!|U985kU%O0Cy znbq%ocM;cgMxWo?5e5F?O(e}xTCs3U95Cxg3!C}jbYS*iNIbqPcQ1S&KLl!-V-Avh zP(KiMD+&gycLb9%NmEb6O}Ld8-M(A$k~hh9F|d_{24dyE>S?qkKcgD@`6$$r z6`&frhrhoWS5$P!Z|2jI&K7=Hu;_z2_kI{Bi+HQQQ$v;vip2a2z-Fc?h(V6Ky}y1l zn|>zrV@0Zf?fugl)qM&-7FF6U@f+kEtaoEOt_qQyswe7q$F$yG_8;76|2$w@_~^#r z5s;lsgU{GTsI5<~d+x_hEzyaS`VXo*^&Pj;Nc9%k&K9DL2pjSQig!ENQ6&H+c;3uR zp@7G+eKD8e^*mLL75@NsRiwZo5uqGyI{fPC11i9I-X1!~H&UrIX2eW#t-?BIR^?dXPf%cB4s^G#QXM2SlQ?8bg}_!ISnafY}0#A6N65djwi<;#aN87C*S zi;rlq1yS<;rjimD&wri|*9)!m`7}N-ZWaiz8Y?!c6M}>g+rFQ;Q|YYjrc(@*q^{!f zgZihqVg>{KDuS=Y_)n9^ux3|({i)X$Jk#!UMN&PhAs+-Z@43~qX5SMW@RvN5Td+{s z2#+|qBKd36iUwzT(X3!T4w9_uBLl11Zq#n^+~iVX@cwnd0|RNJ9$2undq zdo*|N&3VKNClOh0$y&?S;iH+ie)CR~fGy9^Ad@&uD!|HN<|uJTt77He| z;`+~{CnokR0!Aq{M=qcWG`BX1n|e-sOn1YFQHJy{(;(guK1jEh#tw;Q{R}Oqi%zVS zDyzEE2n8zTf(6We=Mb2J%C&R%VP$Z;Xk%P<==%sTglv3O>Mq27=y&uQ@_05qrt4DXVT}hcvyXD?t3wy|*>Xg7!H2_jTj7n+~dH zb69ruXKQy!tEf+#Wu%%1e686wbzaBwHVBqJG2E%o+4oekdo$-Vul6+AZGrQ-6< zu|=AQ!uo4eJjz_CdB9+KQQbP{tVti23_Y6UI*>*%7w(K*Eod|+hkpn4$5n+O4E`Z; zYIR67%Cw(U(6|M+tDo%6i@hs-x2^eXQvr8j-F`I9Oelpa=c$j~N+i5ttaWZ)Vl188XE+j-hgR4k(5 z8KPF-@jg-^)hlnANRexSpU*UshLJ6}>|Ho1JF*m$Q-CvrQio7|G-sn2?{JoghoClv zcp8bQ@fK;f@?6V{OEnZgcx0)3QT1DMZodUPD1qFic@0ne_S6Q@sJ|2F4Ccbzh$Xr%V71b zyJ@ztQzrew7Im8(HV;;w6kk?CIiuTd0oH4-Tg=@>*>F5i zNz?5Mp7tIcL_mvq@GltaS;Y&UCWxxr5-qrig9`9}7Y+b?FM1ysUm3#Na3Hp8Hc;Ih zthsY6mX6^lMUetOZ<|#J^4Ld;_adhw%sIP-F(wmUL@4koj8E9(Tuct@4A}wzOA*U? z!Gx*)0N_8L^#nI&jNxQ9R<3$8Q24-b$wkskQOMBq*6Qve@lwKnNnbPGiJ-WpJO#m~ zt>nO2ftYSaSVm;9?K#%tjF~>-w#uG#O)b7=m-IW=#MxupO+&b#rk*gM!AWAEo+I7#%N)%Ys+t4HvC za4CjOW{-M><6opd_|(mB3AAq+)S%^O=B`|iJx9%4oz(C#dEU$O&^Lx^h9EZSU_^E+QuceLlRuI@s*~LZ6prSA9mA>x;4W|DqgU zw-}yf0N$^{w1AiBHki6;90O(8KApblMmc|STEgbLVU_!qE@^wQi%Y_V{@dZk?}4T3 zS8gO;=O~uq(s?&n`|!cE52kOr!HNei9@~j(q{n716ll>+fISDi3Tx0T7IK#LSqlYZcOwj2hvpT+>h#!a5WfOW)w> zm9j5}VeZfOCSncBJ0832W<^otOkn}kn0_+ug9QfQ#eWAb=bqhN| z7lP8dKxY0np;=bXV5=7LYg@u!6v)l@h{h>_GHFwc0p%7nkm2oW}+|jvvNWKo`N}?GJ=cKUMJdjbc3i zqkB@{_nP6UZzpK|^~ZuDga}BdKtVngfPgJSHwuL$*?E@$fVNrygf=w+Y@Q)w+H(lV zo$m`+Nbw#}+PQA@MEHg9Z?%8j;*DC~(jAD_?+od#*ZYlf&8CmU3ymEJ&w{+rSckUP z$k+oC0*iH8f(tmNWE70ac!9}u@$H;^cg%IUi=#b3TP~THy11I|9Zr*;(t|MqOd(jK zQyyb(*E;cSx(A^G5srj63zEp^c^8+U~OuB^sSr~r(c%8(ocANQw7|L+Rt zcEDG*pE_f%kwq+hsvy{UPkRIRG1X`y#W7zt#3};e$w(SP=BdRK0mZp)`qXRd zhx}qa&4Hi0nIgb5d_XW#=h|S%X@v-jFV+mv(8DSbUl9$dkY#ui>81HIe=(XIjQG&0xvXkyhX&n^vHplthx^^V65mDaiUsON z7G{>PMWI0_p{dF#NL86QH zg6bh&<}c>4_k-L3wxEU+TR$;?;09V^>zMTV&^<+KUp!{@IGPT?O#=c@o4QWtP$VNR zUD!=s{@pRZi4rWZ258(zHaaz&%vR|e3VdvUSHlvAacMo(A2(Rxrg%(oi4c7Zh!6_a z`NiVsPxNI#RKzicOrEj9AKi+%xO_1AxX9PXCY%r5qVAx#OLgqY?ighpTZ{8y>}lq` zNspztkGa1h_N9l!A--i>dBsop4XcRNPf|a1XK`15<&D(M(H~8-SDMqp09lDB+#VFNQ?lo8Hrm--c!V_cAe@FbdN!t8|+ODFYbvBetC7hZK( zo+_;}R~%#+m%YgSIh;u>FKyThhUNQYIl7fV)J6J^-%YpnOvKS))5-Zow*K@ze6xP< z-s)n!W=tF^So29V1Y+p|D@cD6+*AWXTx@7a94g>Ihm0rgmqFh4kNo6OydZ*d0Vah# zO3XK^ISxXxvT+l9f6k8QW)4EHmhzvrx%xdkLG~XmN9a!PV7J%IZfmzY*Zh?~tWk0a zn;BDbiH0~!4cE}ALBOATcx*p8NQG#8kJ2nhyrK?Vch1vxp z^m@87YsQyuO8MkeMr4BIIB=`#92Qe@>LMJ32HG&C#!O%1)_Fc1CNRo(8iokSO3I+T z2d_Lnw|ziM^JD4;*qf)1CCW^k7G&`FgNb{L8MjMDB_e7M@Acy!r<-uJy$cfvVitR; zj=xXCbtk#Ik<3l!v2GUyltJ0kj)YC)Np$7D!3^K<_h|%3Xlqg%e|hku@qnZYoc~oW z8f}8zv8z8pzFc4|3&cvn^bV~+1}GWHpGe13WL_PNBReee2N_#EQhmDM{Uya{4N-(b1Ng7NtR zpC7-zE2}?>6d~ZB9HwcdeVQpD{dm~6G9dJmOM_&Kz5Tqk?WXp%SI@g5s> zcb77=xJ#r$aq_OQ5wom^71(=0a)n^;V$5TT!dXPSLQB zZ;$7RJ7{dR8eKMw#kJ-+-E0;~7)lE>bDR_qy?P zr*Qc%WFSM1zouO<{3zH0@hfk1*6Idr+PLeq zc`8K835bd$6#SFUdc#ByAgBQAEe8PMDfYx68$j%G4jc{kDaX(0ECY)91R>Kz-?TC+ zr*YNK<`7$kFS9n%At?PK6E@J1csR%yLzBz6gL0LXi&RfqD&2^gHfq$b4MVwMIwAT% z*X)0CE~V;^RF_05!{{2vz10y6V=bIURCkt}{m&Dza2i9YC##=uMA1L3eK?SezZrjc zqu_4poDRES*uC$InQ!Oa?qbZ%xdh&?7JI#4OHzgIrUj*>AhLlGH^rpVBCj{-W>?RX z-q76=5t|nyA_naOF?j}r-{dvxBV5ER@9F2N2q?-RSRE~ zhSm{!?fvlM)Zt+r-FyR6dt&+Thm!j}Q7rp{(* zxHSWwxj_6oOcQDc&A=@#P;x1SQ8DkuCZ5cBaXL>pn_YyvGL8Y7BjwO8)7a~6pFiXx zqI>d)3I9TYwP+Z6#}M||XG+W{8@@Cz@QN9F&vq}mvmlEEci#g})JO3iqT@$+jz4en z;Q=B?<6{nweoS$cT=yN-E;Ep(jHPa2wyNsCk#!@zBxbvVaG~#5={Do#)+i9C>A4E( zgxrQR{JRy@3mRoo-2*%Sq!=cNzwC3QSE_!4v{kep=3*zz!c6;w{@hj!y3q&1|5G1A z2Hi%VxA;vfKC6$-0Y7GJYw_|TQn@e$zKMttjX(-TAiNszK@YKSK4BkDmPo0^zIwBgVX8Wev1TS>eksg%m~z!sl2rNzIO1mO z#iL`sXs5s#W^)|9X*aPasLZnQVBMkW6VMUNHqd@@zCd7L({nxp9)*<^!vmi}dkqhK zbGQ!}_ZA=#B3kwkd_*%3RQzNNo+)WOYCQViWV8@8Z!4-#dAVLEQX%+c#kjjjFz`o!uER)UKv>7>@Oet)L+1FZ1%r_^Y{n+G%>(jfLN(RV6^ z;FV}&WogQsC~?Rjk7JX`c9Ddyhu`2g>Fo{`Ag#-1^)1kJ3FQF#Y=9`G{rEyG&c$T! zNE$;u5r^xl4*>K5wxrxn-4F(tt?L3`c3|mJkeF%e_qr#@BoU&A77;2`|5d>j+<8m- zAx=SFJ!07@r2%xCFbVo&W1iQW*hbTCqCuwMZO1Be7Ri$JTb>IBKdbYBQ{Jg=pN_*! zcrS0zyoCcA>fnyK-U36Hj}+x%!PtQu#bAi7dZ9{?5~?}$SP{8(#_n&SL_lePPKu9( z%9BkHaV|Fe0Er?4XCs)9Uhz;CGErxvKja{w`Yyz00xmJu-sQ(@qZ@5>b$i=UdZYyVPlQK;8Trov@yZi`_q=K zNRP82S0lGsPNh7-4H#7bzbQ2hYU6Tal#9zvA?bP6k6EKJA+354ms6w5RCzq@_&qcp z^TW5;E5N`OgOxZECTfUK(Qv{aTlZ|WK%>H0h+yB|*E&^#{;GfVj1T|dkHocR8k(|t z#=-`S&S$tzu_mw|L3U(ezHlibY@Im5EK>6!gzJyKnneN^(!Ny;h|*&Bb9WYia!%t? z#1ahVm&*Ny{&#(eT2^Pi?B{18!e$NOSRSlDyg$}|Qz_5BgE~wCgHdk8fXr$B5X%E3 zaA87SJ794F%jDXHjpbqiken9Q>|=*KKtrU%BA6zgBsB@N>Re3F%WMu2r*-8)9K31{ zT0b-+DH;>oKKWL5>=!}gY#O484wyK(BV*aJS!{n-%Iv>E=QjD2>G67WBEFi6wfMmW zRy&(AEqee>7wQdNgWlt$j)KXWo~*u{(hLm0=F8X!gqmL)W%0RJm$6HjeMT2-RzCDO zjJAFmyY8l|Ul`0WZHyrL>vB)Qp=pj>oL{FOfGssi@>W!Sh)sH9l=hZf_g?C@hM^w!wW?~589MuQX z#-u3w)x0_*eMMfFba6}QRvCHedJjPfkXUIzrom9{%cJ{6LyZ40*&C5va}}frgjNV7 zKc4N_M7T62qqZZdWT15}Vs&XF7hzUz!ct_H<1TV)5@3E!TF(gckRyEM)?vo+`;(yu zlq`8`_dOXbAOiumBNJF!?);=DoC~8N`szv^=B&QluW5HSH~&JBvv`LR>7ysaB`E+| z6^1}cvjM`{$%@wRX(<|J-}i{zLGMtFTFV)a$V^LaEj|`jUs!ysdxZ01(!B`Sayk~( zR!*q9L_=c1vF4#YunsyyfCYk`rf$x)Y7j~Brm+p_g~4YyUHg+rbB=GtbE$#7+JZn? z$we%aw@oM6k%k!{NK#4RG1BwXrnf-{$wjM1EnG>&5opo&AQ_6<9Il3r*VYLw6h1fk%VufZ4XL`B%^imK|rZDxz(~v$KvFhLWt4in47eNis;9N|a<66iG4i zSi9rEHOXe0skAo6WHXb6d}~Z9hJP*HMMbm&CctC^D2g4nl{-5E)jExBB^n-UTg?)5 zAC4@x^8xK+Z7ZNZG_E?0apg0ttFTU=tZ_xkuhzI)F&SlV|Inje=Wv2?0|w^MN3x@p zhDVk;S?B<&0tho4*krgR&@j;(oyRx@dsgECCMCRiR*40gN+>}|;gZ*k%%a6)kjP#& zg_xd^B||OjNMrtFQ>)AwlCMO)@bf<%#=<9Up;=XjRUI9=xl)JFd&FWY)RB$k0rR*B zQ=)<^p?CxM5xWYOCc6ri8~>HFn;6t&__(AL*4Ag!cN6`YLp(rRjHRUihf@m?Iwd%O zgi=Dx>W~7PqBy1CGAk1|a3ps>X1}YOiR5lFpBo0OU~5$a=a)kxqAyzKwz>$akmDR< zCixI<6fLR}M9a(o{H0+oXVp<5TV&FL#n$3r)Qx`0`gVLEQK9?T?!hAPIcO0>i+)dH zQHP5jynR*RVs{rAY{3T)kf{ zrjbd!^E*u9m1(Yqk(2JsjJYBmo_pj{eg#1u@?|)EfY}{=Qnm^R%v1qTjNE)TwVQYF zU%8_1Uapx#kbjqCa=rRXzpb|+Iq$6quyT^@Rj^%AN*5-`xiCdD6OqyitSrSo&pC`=+ zmZh zVZ5$dH#T@SHn`sk?mLoT>ICJ;mq3K=Od|qqt)uq*_*SEQ=%_tklEYEkLDnN2Ll_G; zYYD-q*kFR_!q$SOlD9JiX|w?NacCdM+iCg3jm)&NF;C}V0GT|UND4=jq@1=kAKh6X z=8^>I!&P)2Bmn{_dEJ-6s|AD@x-iaA9TMeJLeqk2GxkQ3fFR9m(~d-m71I!9a=blK zjufo)W*`kSQxV>6pUeMJ%*8R~p*Gu6e)^dMs=Ax}P25Xn5 zEL!?m^e>n=!;jVL1!UcLdjOOcsgAe|T588Q>S+Wt#L9Zr>n#agq5+IDOQVTCM|W*8 zYO9FQEq+{Pa~A=+`M$eeC#lpv2C+ixQ%aC0GkQ4G3cb5;k zt2fnj*KVpAbnfbRe>&J#n#&;$3?{^HRI8_`n~VbzX($^>(E?fh*)KQvGY-X75W%oc z#OfwiK{Vx11Bx((lC_OTwU8W+(>XLr(=jcBvb4-*=+TtLM=kijb7Mb5Lx|KSQv&lP zSFEm&^99Q4m&r&JG;miee?RZ`+v*6>ftT)7WBS!oPiky)U1Y;pbz`XFZ*rXN&G*s7 zolI|c3)LYqc5;S}<_^=Q$C(k_63Kv+2Di?KbEwXTp~VAIB(DimPa9N0mFn{9*XP3| zAzD;(3xS9hvLnmTiOH*wjPWbtl9Nz8g2bnHxM=WXnxDi1+HnDXruwCCgZFC{RlhM` zmx>xr?L`YhP)r~{upRJQQ7-|Gtw$@4O#Vow9UL;bx@}%!qY(Je(N}ebVsM31M7Mgc z9(xD-PnMZQn`PlxqnxML>c@$z=jqt#RKLj?5ct8voMsvvq3egY86s`B>vx<{UEP9C zbk$$>RZP0cW|J4fj=oUkw(@-7N)5D6! zUmu8wgE-+~)Y=XsKHWO{bj#?|exJjo>f7Vve)}=A4t6~cAon-|*6XW)`uBO=seZ+C zMnF<bl3KYnf>)GcB5Z2@<$PH<(bdx5WpRBLFioI5W_JQmmIRK&$Y-7nDAvz+bIqH6C z4>G*-&ODqP<`| z;$L9c^iU+%&te*;-z3)Pn0NuR9jGaL4zyzC$I)scp_NzzO9P=M5<&$cgN~q@2%0b* zT>h>tP5Fr*$bJ)Pux|6#*O+K5AlpHcXyCN?Ym2WPj(GO%ukD|Fa4>2hw(L$Hqg_x9 zXzi3^t0Zh6;flF=86kou)~1|ncY%yOYC0jKF7`0_R<`uOH{N^0_3!z+?CEpHz7Xvw z%i`UR>=6ciLey3L;3s(Hh#tXWQ{vg<|I)~(Ir?W7*YDh1IX5@gnd>6cCh9Nov^zQ5 zot@xRg{k_5U(2einHAiI7hf|cZ&PYOSjiycW-F|it;PL;U^@7g%Wr&8;FAxT{KpFP%?R*ci zY?k?)s_*?Z#a%-l(fBs|up0JL^=tlx;n_W@i1)#Xnqr9|b#`XkLQh{=dD(At_oJ&D z6)gQu)n9!07;F&i0K+uVV-VtI)G=HZQ}vr)Wyc8r2n`5xTBJxI<*e3@5}boX=bNWS zd|1QhpyNtO%_*r(defVipphTB;gfxWr7iVlJ@q3(#@nYPla1|VtVx5t1pAba|v;AAo6 zyRo0Q{QhX>$iz-MXYw$J|1-jFH>mL?G_OYCEc<>aSrPQqq?zX}rVATDFk?dBYF<{@q@bz zvI!s#$;R1Dv`Cxevn}geZUzAYxeauW?KNfn-hYGk;$irUNS{8d(puJEfvi|^GH*9a zUaZ?WhqEn<)MbQiu^Y=`u6HQ5!t0<&mPc5y!IOg7VH3*~QN`|E$1(z;S#=7LLGQt- zcgqK|<@&`hJwQ?(4N}%p{FyZ{hwpIO1(!phz`VnRsR`fOZlHL=n+%f3Ssm}IF_%vm zOm43K;(uU zW&FE$zctbAhhBCx@jwl**A9xIzziu<93y4I6GNAos;ti+JY@BKA1SZ$YGb|f$&cq( z?LJIr*#NYPGX%y;%-^krez`Y1Oi}mgjeVckC9sjJqPhi_nvzR#r`ydg98Q}kuGUx` zrRW3CGN6`BPx>5|r@j~0HpQPfuK@P8v~th;{^f?Row+X=q!}DdgH$Q++s{uPSUUQl zm;ULk6Z>?JfIMNQ{#Mb%ykLfs5WC!xjT$r(h4b&^`Y6`Qis4%cEKdTZ0*r(>E2&kS#g_OR3_tLD!!TYj%P%cuZD9qD4Vcmgqz|O0Y5|Bgxt23 zJ8{i$49AY_+(dUl0~m2U?2IcCng7WyIzxsOgYS&ZV&L`FZSz4It7u4K7$+8&X+J-C zHJfN=;m(glWEa6Y!MmD+Jx~lL?8bL!kilI|?h@*q2m)s2n!!tmP;g7Ug2*!t#t7ot z@S%zQX9V^udt-{uU@~|*6lB~%1Y;=M$DYt?&?8tcYW@2HTGjJg99!% zOkLLXIF@I7f7fXjxZ3%@H^VKmib-M6H%y8v?Dn-xsvk^BeBhlEzkLlpG`wo(ad;J_ z&mv?BG?{9F!(^|TmE*B6EXpC;5S*T{Eob2Wfh>)#o$XXQu=UZW;J^*ng9WqIQXZJ5 zbe+h%7zhILUNVNftjmEl6URl~iPg9?aYE!h*$xP%VS}ecmqxvL5bs4^vMmMjy0EL< z7kM`Z@=n@~@6aH1HOR|R+AKYe26s|wJ&kk&V2%ywfd?QXFB2+{m^}|LmRt13uZh2Q zmZHkIta|Z$@9$l?Ti7AN-7GKmJn> zT)OzXDX$70um6ohD1xzHF?&j*Xxv0RUmxI=k0@>~Be2UM)?at)f!i0ZnB^43v^^pK zh%##2Vesis3w2bdx3M+M-<5KVOC2~=Pd<0K)&+IdVT^*<$;5V}(0kmyW1vF)xk!>B zM*U3&^Kv2F=5NHcs6y2=Z^Tr1Aj3DCYiJQIQsKv(=KY7gOf0jPKFFxN8Ed?gM1UD_No98tjd^Wms zf0SAurG&#>LH@CZ@wjruu{f&t-QpDvZ8}sneZQH$$K%nkIc0?c?K;`ZDR8i@A;INf z6qu(52UO2KsYTcNH~u-V?|z}9zn|`ty6{P}7K_&Zhkh7F2RkL3AIPY zuc!^`>?G3{XV&Xt`ij`Xv7Y&!%}3c-jk-lo8hkna_sg76QcohnSL9Kn*Ix1<1^AkRD&;J9wgnQ^5@kaR zIA&nC7qH@!244MSB%l$SZ{eGU%gO^9O8%Q5MZU!JYUZSVSoNc;H))jVwCUaz+Fz`j zBVkx+%(2yT^eVX)OXkObfza?+h@qyc@C4}|iBCfABDSXHA>`8E_P9_f%4F`mb=JU@#O#DHXD$2M?y!l0u# z3NHKefRiQkCveAizYINNi!Cp7EJs2Ze=gCcd&n=sQ44(n>?B5HZyp%pG^~PXsY^yx zU?is4QQIDHXo9J%W7;l3Khui1#7ZuSD)VK)!&9;xQ3C<^R2038f=}qxc8No>T-obJ z&x9`hP90|2V##42sj9cd9L4~xf#H6KaS~qDjFSdqu>a@dOi&(7tsW;taO^l6eu_FV z8Ycz6w{ZeW$GOA6dtm?g>~@(8D$33L8U=ad+rR#a&n+Mjl^`uffC9yh#OYK5c3XK% zT3&e&V1%GBZRfbAkGM3>_9fd*lC!c6^EC&)(1*$WZxT3AL1+tKd!;Hp`-GzhWg5(u z%w1R{;NmoSooqAnFf;8!P<8vTD>9luVks(o(vB8-5)eFJa4sFy276|c8e-e6hBJd#3h?!yrUGM#?ApRU#@mcP|AFHL* z!KKb`oi9uo0D-B>AdFmv!E<#kSF~()G7};hpb%>&|^k-~Rpke(z{)dM*ht6qz!q5uw5a zzjsNY^IVo1*qD%l9!L`Vg?SJ482Y!>z!?aSc{;(}3MV18E^L?!zy!IfKRQ{Lobz0N z`JW)$j3tb(#)a_^ObDZMf6MyJ$Rn=_dxN{iW{+d@Mn{WK*4_*4xPd@Lp{Z3%HtKd=(79AX}KD=ddJj6^eRZn&MJigL> z7s2)Rr>HLOB1X7=-9IK63RZery&__=_^|qIt-0!z$mhG*{?;r!HNV4!s3fN6wq(Vs z1dApfAIvm|-|*_jm0M6KR*L?NXBf=f6j`nqI>Bv`T{Ac5&n%Gr)ldIS_0D!z27!+F z?lK&5MmSHG;0b(x8rE9kK8XtusS_*z%y$DO_V?nr>9eVy#Tw|0Rl`}&7C=OJ}>O7FQPTB?$a%2zA@#C;NJF(+gHwGHrZnO)1P@V0GSi%Q2Y4$>wE#+xFUTmTmju& z##LG(vPPjNrWo5|F?L;$j2dn@dvQS9sz`JFuKAR^hMgO;tOJujpz9pY?-Ceg8e?OfNSpma^*4 zB9s$Md#D`5sYxLbcECc!s6iSGLohamL z@9g5@kr!OUzaKZK6=hMVvtSw@H=F<*BixT^?)YKjsx>N)vR290!8Sr)^pZ0+If&NB zSmxE;C+}L2by5M-LBtw+!AYnx*Xh;!(L$z8kPk~j>0yXNfYAv^C7_0iL9@M!===db zFnhCX9y*yeC~mJoakMu4c2F1v<+p=bWrW+gG3a}j@zm8P2#7u2ea|JGynugZF1V)p z^LhA51G%E99=1Ep=w>BGz)DqZ@03U=khH+Vl5OL?w!}n#Za0W`yYV|zw{@(D83Es6*GEh z{NgO#9bpHiQo=?X2Nw|GVFSonTPx-$@K|LXP1K*vF5q=>S*VWEME%eP@2c0$FCes( zJUcREMhb!Dx@@bSBS%IMz{FAHT~jeIi1r3!z4%373p?shIcxl2oFU+7o2ImWiHAw3 zL)Kytn?Pp}8+za$q;enwG!&Xii$kU9B78Z-zezvQ8U!)K!bo0VqDR(*h#~B{bt!O( z>MxdW0z`?e#V3|Us4%cX5YpgU#5jM53&_r~NtExjlg3OjnV}x#%%(I>BfejW@SMrs zyYjT#Kz53*O{-YC4|S+;WXju(KnDb{_FWv$U@7p+=al~bKvf=a7pen?E~qCWkCSFL zdUb$TR0<3guJXgj=P0haX-I>+^f&xEV?})$iUxc(sfPT3%D*>ncEp^Hy+%3m=UMdz z23Dkz^e#xlNPZW~QGb2?-{*Yza|?Mpiah3UQ$r=VQlenoYM&DtoH-W<~2Xd)so_MehBPamY-|7B87Z`sq!kc>)VRPN(2DOGA^b>SvRJ0VPpHwsu z3f*Hi>QV%JzNpJ~e_sHX$7* zb^!wB=HIuv;S&z04A@2WBMneu0%~s`+Lze$nzf=dHYKV*?RG^cIvzXRdC4wfwFd}= z`Mc-!@(N-p|@^nafmI}g85O+vARlGIY}Ca-By=L(F(nAxF5sxyt&k+#;R zWYZCbF@fwkqGlTV?cwqf$ENPu>;1xTZz~kgFrN%SxxS!L01tBmD;+08PZtVDp#%Jv zg{u=-g)3=I`KGjv0Z}S^x+O@JoFierCUOgQGp==v+hPzEXy5n+GSFVp=_F484Nkyi zX!zM1#D~>5VV>U+mPx{XKwG_G{)kYr=rc{FMlfj@CG7`z6P5s3d=OSkcG}Vb%!Cr< zhFoeuzgS`h!n#1bf%sc=`Z1@dva%BFxKI!x7l)Gxs%Z~5XD=S%T$=zy7gS7(1)+y{ zKu$XUp*=gV+k_WJ7~R3~bD|Qo@-Xy=rsybRHQd584vJm;0s+wP61}s5Q>d_P*G6Fg zc|yHQEF+i6Gq)+dPvYU{#)N~Ll*LN}42X*eX2dRi`1r-wsAuHKzgG6X)oZ=Bja8En zXfkAQS^wRnk_UoKEFV`PEkek&X|^YEYg$P$DghwX7O^YTV7j~2`-g9t^Ar9FVnyX? zHM+qJv6op!P(|74cIRiNS*5k28b1P6zF3jS{)K~|M`AvpL(#-HUT&f1{0MLy9 z27kI2vG@fMaCHHZ|9-Hb&ZsFNdy?){6E8zSb4{J(S(lDR!Gop=<|KANP1WfTz62$@ zkQ!w0)D#DGXhhXJ$3QWxB(M9|uye>)oS`L@eHB;H!_K8{IO=FKSwhv=UKaw?ARrw? zjCPqjxX8!n88k%07QO%W{Q{mIsq2KLCp4Ifz~AI=YlsQ;xw%3lG*_d-Ak8%6rlv%+jH$aDo8HMAz5|TZ9_a)dd{87U*S{n;8kXvF&7h`X)MTW9 zi0uYazvY_T)>%}vOooMU8d;)j=Sz0daF*kDlA*2YWIoo(FnXX{MC2QkFNkZ!19TDF zJj37JmFvORmoeYPSZ%7n5j2X3A8W8Q7Kt#;^2DfsJP6Cbe+t?PGbklYK`ENs0Cxxc zlPvmESn7IL!3KODAgUZi5`Z(&!@$gd`78q^v+m9qCm_Dt*FtfP+bJa!E zBJ@JII|&Tg>Lku>ksF0k&di5Ony>+dY~ls0oV2#^J>u-vfX&rNW8o&dbcd9=29OZQ#U={g%y$GwX(ne-nGy@%kwx18hHz zuctIyf*k=NM1NUCQ)+-QGJLDlTRy?!G~OD9x=un#OdU#G#?G$XUb3vPrnA?xf6D=g zhe@)w{1rbMbiCHK)#lqB%r?j$D9uD%NAd zupgPefM8@01!2bOl@?WL(P5W{$7N|0*ej?U1B9L?ga3R_$%#c#$V&qrL3d=(+1nmh zR8*f1(_iS68vIynX|d7L{SJXPRqvuyNddfg`hQVT@B71#0>E%_z${LUEXI8Zn8wII zV`H!zPjuw%Cb3(~6J8=bU`<5lC(lXNcupvoJSV-wV=>Z^(jqC&6YvSxC<7zuR_Mp! zu|w^o`MSW-dTO)*Niv~KQLNpLXnXZlFf6o=RwqUyMj!5!-HD0GUTDO{a1xcSyNyFF z>aYD~a%rST;SqTIEAqN41w<)zRJC+i2CHKr6|$2w3OHePRxq{gTU6hLEcIzrYS59r zD30IK>i3s0(ug8qlC?}v+U5egmnDH0_KlbV3XGW>@1J3rFY6(dlE zwysvTfNk`;UB#`^_+ zo}gdWVMiE|5_o(|dIX8RrzR&W*=`>}zWbN(!-=h$;8 zHBtx3vY$?F5U}o|#t(qG05-%LF^Gs>3u{NZl!vSL5GA6Xibi3E$Jde<+_&U+Hnr~( zsL!c>gPDCSz*;SuqsBd#7sfdSOUA&&e+O6~MhCoLj@MKkIftbNu~1uQ8PgNuZMz(S z3RsZQZ&qFzN$h|!pn=>AF)+S0w1fT`>)`;IOo$=lFT}u;@-jNfG&)ZY49Jq#U zVX;a@`3J(m1U?xo!zP&P>ig0s-cf-c_#meaxWcMBq)AGJZ-Mu19UHEz?>}xGSQV*> z@k&AKRh4#n*wLKa!T{2iV&W;4l`Odn`WUB8^~s*l49wRKFgcWcsktT#V9gxH#lf}{ zQfINNUxwooO>DT-7p0sfCWU!p`3?^5{eo0-Q2VA?Mo|=YS+;v6FN_*`xxcuR!CuX= zoe7t>^5ZgJU(Q@Vit?xP`*Q2y7sOQk_JVrVz(pl-%tcHTQuXe@j|QdFQV1Uqag#R* zAQtpfnz)=AE>S9)Zez+V=`xXay<(iGDKe9s`fvu90WU^W1w!Z06^}X=p&DDQRi)*x4BUya%2P_e|q?lCHh-HkGNxpi^dGzJyP|IQ&i5PCa ziY3U8O-!#ggt>E<2J36EEar)s3otaXcf>*g6DOb03FVJ2k-S(8x|t!vY_YiN{9wvz zyRs^s4W_j(4>1y|n8uO~m$C~t7?#9M0sCn+PU7_-ZNM<-vZA*@OdBjlm@`QRZIMbW zDB*WgR0{Kyzy{La7>4-B?h1C{KT~AIA0L)&#r;gM%J;@9 zUAMaYj|a0YKU{mFX@9m=l_zgVr}8!xiq35X(eLIgWerqqYeO1TQzz;_)0$50cI$5a z>Z64pg1Z#U^)3~WcX%^$fz(vVAMKMA!h*SKeGlz(LSp^Ms!B-9-Cpv z<)W8HFC!k1tvn~v>@4q)GSa^>Ini?JiSeGG<%F>?3?8fc8l-PlHphEjMf zf;uRzr8Bx1c72c&z9Xs1RVP#&i1(b(=VZAg{fmUrvFsnN#zGIs2S3>Gi||X729fYt z=x+RqV&kz9C1aGEeZG?tb>eSi;(}$4%zJqBk-bYr<0vSAvL-_wmbxBraBVzTphGmk zAVf>Czg&b7Kzk)DhEA7tdCg!#0jqzKzn)bBWVpH%b3heMX40$&h^6f8$`WcHY_Z@JPMSWaLtr!4I_9UzRaDKj%6-6$@=nYZaUNtW05kV`v z!{g<@y)R6jc8ru9^QWKa9dyrWL8|_ADCr*jsG{(*aoDvGu=o^Y%zF4{<;-GrhqELw z47Bk`J_Ep-YD8B5Ht*vtDw^M<=)C%&yCcR@45MIBLR&GDJoYK!4AvdgY+PR|4{Aqe z?q@x7R;5+5bJ!pKN%X}ofmEZ)LUpf^0!lLYF{n$ZC5l28{h=WI=|QQt3ml@mFbTcR z^w$lh!+f*p>87h7c?#tOmt!k0TY<2UHW))p!`0v;TZD~<3hjqqGJt&i7_fHhZKA7r+}{>gYTyO#|%qh~pYfW?3l z4%#lA(sao&3k%dox-_SqM3*)VWaD$Y2M@->Mm;=5Qc*0~b_7>Pv5kX@r?afTos9R4 zXC;X?0|8Fm-9M>+TL1L^gNYyQpJGo>X<|`{fq?Z!sW#RXoUo&9py2vG$0YLI?tX+C z86{koj)CwxG#1St2dj>mSJ?hW<&(x(kHNFc

    pc4Yb&x2=Eau??GOcy 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μe>2%t5S#m+t>bQBv*Qy146>`4FU}QxR(5tft{E6 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

    eYpwWRpPNr#E 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

    i?^%<`4{>TpxDBw?_A?(pPwC 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

  • )CxTU+WMIgM#dw!k1K4M}?pMV$xu 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

    pc4Yb&x2=Eau??GOcy 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μe>2%t5S#m+t>bQBv*Qy146>`4FU}QxR(5tft{E6 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

    eYpwWRpPNr#E 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

    cz*r&RHEbae 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 diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js deleted file mode 100644 index 44ad73da3..000000000 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ /dev/null @@ -1,14738 +0,0 @@ -/* - ** LICENSE for the sqlite3 WebAssembly/JavaScript APIs. - ** - ** This bundle (typically released as sqlite3.js or sqlite3.mjs) - ** is an amalgamation of JavaScript source code from two projects: - ** - ** 1) https://emscripten.org: the Emscripten "glue code" is covered by - ** the terms of the MIT license and University of Illinois/NCSA - ** Open Source License, as described at: - ** - ** https://emscripten.org/docs/introducing_emscripten/emscripten_license.html - ** - ** 2) https://sqlite.org: all code and documentation labeled as being - ** from this source are released under the same terms as the sqlite3 - ** C library: - ** - ** 2022-10-16 - ** - ** The author disclaims copyright to this source code. In place of a - ** legal notice, here is a blessing: - ** - ** * May you do good and not evil. - ** * May you find forgiveness for yourself and forgive others. - ** * May you share freely, never taking more than you give. - */ -/* - ** This code was built from sqlite3 version... - ** - ** SQLITE_VERSION "3.46.1" - ** SQLITE_VERSION_NUMBER 3046001 - ** SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33" - ** - ** Using the Emscripten SDK version 3.1.30. - */ - -var sqlite3InitModule = (() => { - var _scriptDir = import.meta.url; - - return function (config) { - var sqlite3InitModule = config || {}; - - var Module = - typeof sqlite3InitModule != 'undefined' ? sqlite3InitModule : {}; - - var readyPromiseResolve, readyPromiseReject; - Module['ready'] = new Promise(function (resolve, reject) { - readyPromiseResolve = resolve; - readyPromiseReject = reject; - }); - - const sqlite3InitModuleState = - globalThis.sqlite3InitModuleState || - Object.assign(Object.create(null), { - debugModule: () => {}, - }); - delete globalThis.sqlite3InitModuleState; - sqlite3InitModuleState.debugModule( - 'globalThis.location =', - globalThis.location, - ); - - const xNameOfInstantiateWasm = 'emscripten-bug-17951'; - Module[xNameOfInstantiateWasm] = function callee(imports, onSuccess) { - imports.env.foo = function () {}; - const uri = Module.locateFile( - callee.uri, - 'undefined' === typeof scriptDirectory ? '' : scriptDirectory, - ); - sqlite3InitModuleState.debugModule('instantiateWasm() uri =', uri); - const wfetch = () => fetch(uri, { credentials: 'same-origin' }); - const loadWasm = WebAssembly.instantiateStreaming - ? async () => { - return WebAssembly.instantiateStreaming(wfetch(), imports).then( - (arg) => onSuccess(arg.instance, arg.module), - ); - } - : async () => { - return wfetch() - .then((response) => response.arrayBuffer()) - .then((bytes) => WebAssembly.instantiate(bytes, imports)) - .then((arg) => onSuccess(arg.instance, arg.module)); - }; - loadWasm(); - return {}; - }; - - Module[xNameOfInstantiateWasm].uri = 'sqlite3.wasm'; - - var moduleOverrides = Object.assign({}, Module); - var thisProgram = './this.program'; - - var ENVIRONMENT_IS_WEB = typeof window == 'object'; - var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'; - - typeof process == 'object' && - typeof process.versions == 'object' && - typeof process.versions.node == 'string'; - - var scriptDirectory = ''; - function locateFile(path) { - if (Module['locateFile']) { - return Module['locateFile'](path, scriptDirectory); - } - return scriptDirectory + path; - } - - var read_, readAsync, readBinary; - - if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { - if (ENVIRONMENT_IS_WORKER) { - scriptDirectory = self.location.href; - } else if (typeof document != 'undefined' && document.currentScript) { - scriptDirectory = document.currentScript.src; - } - - if (_scriptDir) { - scriptDirectory = _scriptDir; - } - - if (scriptDirectory.indexOf('blob:') !== 0) { - scriptDirectory = scriptDirectory.substr( - 0, - scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1, - ); - } else { - scriptDirectory = ''; - } - - { - read_ = (url) => { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - xhr.send(null); - return xhr.responseText; - }; - - if (ENVIRONMENT_IS_WORKER) { - readBinary = (url) => { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - xhr.responseType = 'arraybuffer'; - xhr.send(null); - return new Uint8Array(xhr.response); - }; - } - - readAsync = (url, onload, onerror) => { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.responseType = 'arraybuffer'; - xhr.onload = () => { - if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { - onload(xhr.response); - return; - } - onerror(); - }; - xhr.onerror = onerror; - xhr.send(null); - }; - } - } - - var out = Module['print'] || console.log.bind(console); - var err = Module['printErr'] || console.warn.bind(console); - - Object.assign(Module, moduleOverrides); - - moduleOverrides = null; - - if (Module['arguments']) Module['arguments']; - - if (Module['thisProgram']) thisProgram = Module['thisProgram']; - - if (Module['quit']) Module['quit']; - - var wasmBinary; - if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; - Module['noExitRuntime'] || true; - - if (typeof WebAssembly != 'object') { - abort('no native wasm support detected'); - } - - var wasmMemory; - - var ABORT = false; - - function assert(condition, text) { - if (!condition) { - abort(text); - } - } - - var UTF8Decoder = - typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; - - function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) { - var endIdx = idx + maxBytesToRead; - var endPtr = idx; - - while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; - - if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { - return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); - } - var str = ''; - - while (idx < endPtr) { - var u0 = heapOrArray[idx++]; - if (!(u0 & 0x80)) { - str += String.fromCharCode(u0); - continue; - } - var u1 = heapOrArray[idx++] & 63; - if ((u0 & 0xe0) == 0xc0) { - str += String.fromCharCode(((u0 & 31) << 6) | u1); - continue; - } - var u2 = heapOrArray[idx++] & 63; - if ((u0 & 0xf0) == 0xe0) { - u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; - } else { - u0 = - ((u0 & 7) << 18) | - (u1 << 12) | - (u2 << 6) | - (heapOrArray[idx++] & 63); - } - - if (u0 < 0x10000) { - str += String.fromCharCode(u0); - } else { - var ch = u0 - 0x10000; - str += String.fromCharCode( - 0xd800 | (ch >> 10), - 0xdc00 | (ch & 0x3ff), - ); - } - } - return str; - } - - function UTF8ToString(ptr, maxBytesToRead) { - return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; - } - - function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { - if (!(maxBytesToWrite > 0)) return 0; - - var startIdx = outIdx; - var endIdx = outIdx + maxBytesToWrite - 1; - for (var i = 0; i < str.length; ++i) { - var u = str.charCodeAt(i); - if (u >= 0xd800 && u <= 0xdfff) { - var u1 = str.charCodeAt(++i); - u = (0x10000 + ((u & 0x3ff) << 10)) | (u1 & 0x3ff); - } - if (u <= 0x7f) { - if (outIdx >= endIdx) break; - heap[outIdx++] = u; - } else if (u <= 0x7ff) { - if (outIdx + 1 >= endIdx) break; - heap[outIdx++] = 0xc0 | (u >> 6); - heap[outIdx++] = 0x80 | (u & 63); - } else if (u <= 0xffff) { - if (outIdx + 2 >= endIdx) break; - heap[outIdx++] = 0xe0 | (u >> 12); - heap[outIdx++] = 0x80 | ((u >> 6) & 63); - heap[outIdx++] = 0x80 | (u & 63); - } else { - if (outIdx + 3 >= endIdx) break; - heap[outIdx++] = 0xf0 | (u >> 18); - heap[outIdx++] = 0x80 | ((u >> 12) & 63); - heap[outIdx++] = 0x80 | ((u >> 6) & 63); - heap[outIdx++] = 0x80 | (u & 63); - } - } - - heap[outIdx] = 0; - return outIdx - startIdx; - } - - function stringToUTF8(str, outPtr, maxBytesToWrite) { - return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); - } - - function lengthBytesUTF8(str) { - var len = 0; - for (var i = 0; i < str.length; ++i) { - var c = str.charCodeAt(i); - if (c <= 0x7f) { - len++; - } else if (c <= 0x7ff) { - len += 2; - } else if (c >= 0xd800 && c <= 0xdfff) { - len += 4; - ++i; - } else { - len += 3; - } - } - return len; - } - - var HEAP8, - HEAPU8, - HEAP16, - HEAP32, - HEAPU32; - - function updateMemoryViews() { - var b = wasmMemory.buffer; - Module['HEAP8'] = HEAP8 = new Int8Array(b); - Module['HEAP16'] = HEAP16 = new Int16Array(b); - Module['HEAP32'] = HEAP32 = new Int32Array(b); - Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); - Module['HEAPU16'] = new Uint16Array(b); - Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); - Module['HEAPF32'] = new Float32Array(b); - Module['HEAPF64'] = new Float64Array(b); - Module['HEAP64'] = new BigInt64Array(b); - Module['HEAPU64'] = new BigUint64Array(b); - } - - var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216; - - if (Module['wasmMemory']) { - wasmMemory = Module['wasmMemory']; - } else { - wasmMemory = new WebAssembly.Memory({ - initial: INITIAL_MEMORY / 65536, - - maximum: 2147483648 / 65536, - }); - } - - updateMemoryViews(); - - INITIAL_MEMORY = wasmMemory.buffer.byteLength; - - var __ATPRERUN__ = []; - var __ATINIT__ = []; - var __ATPOSTRUN__ = []; - - function preRun() { - if (Module['preRun']) { - if (typeof Module['preRun'] == 'function') - Module['preRun'] = [Module['preRun']]; - while (Module['preRun'].length) { - addOnPreRun(Module['preRun'].shift()); - } - } - - callRuntimeCallbacks(__ATPRERUN__); - } - - function initRuntime() { - - if (!Module['noFSInit'] && !FS.init.initialized) FS.init(); - FS.ignorePermissions = false; - callRuntimeCallbacks(__ATINIT__); - } - - function postRun() { - if (Module['postRun']) { - if (typeof Module['postRun'] == 'function') - Module['postRun'] = [Module['postRun']]; - while (Module['postRun'].length) { - addOnPostRun(Module['postRun'].shift()); - } - } - - callRuntimeCallbacks(__ATPOSTRUN__); - } - - function addOnPreRun(cb) { - __ATPRERUN__.unshift(cb); - } - - function addOnInit(cb) { - __ATINIT__.unshift(cb); - } - - function addOnPostRun(cb) { - __ATPOSTRUN__.unshift(cb); - } - - var runDependencies = 0; - var dependenciesFulfilled = null; - - function getUniqueRunDependency(id) { - return id; - } - - function addRunDependency(id) { - runDependencies++; - - if (Module['monitorRunDependencies']) { - Module['monitorRunDependencies'](runDependencies); - } - } - - function removeRunDependency(id) { - runDependencies--; - - if (Module['monitorRunDependencies']) { - Module['monitorRunDependencies'](runDependencies); - } - - if (runDependencies == 0) { - if (dependenciesFulfilled) { - var callback = dependenciesFulfilled; - dependenciesFulfilled = null; - callback(); - } - } - } - - function abort(what) { - if (Module['onAbort']) { - Module['onAbort'](what); - } - - what = 'Aborted(' + what + ')'; - - err(what); - - ABORT = true; - - what += '. Build with -sASSERTIONS for more info.'; - - var e = new WebAssembly.RuntimeError(what); - - readyPromiseReject(e); - - throw e; - } - - var dataURIPrefix = 'data:application/octet-stream;base64,'; - - function isDataURI(filename) { - return filename.startsWith(dataURIPrefix); - } - - var wasmBinaryFile; - if (Module['locateFile']) { - wasmBinaryFile = 'sqlite3.wasm'; - if (!isDataURI(wasmBinaryFile)) { - wasmBinaryFile = locateFile(wasmBinaryFile); - } - } else { - wasmBinaryFile = new URL('sqlite3.wasm', import.meta.url).href; - } - - function getBinary(file) { - try { - if (file == wasmBinaryFile && wasmBinary) { - return new Uint8Array(wasmBinary); - } - if (readBinary) { - return readBinary(file); - } - throw 'both async and sync fetching of the wasm failed'; - } catch (err) { - abort(err); - } - } - - function getBinaryPromise() { - if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { - if (typeof fetch == 'function') { - return fetch(wasmBinaryFile, { credentials: 'same-origin' }) - .then(function (response) { - if (!response['ok']) { - throw ( - "failed to load wasm binary file at '" + wasmBinaryFile + "'" - ); - } - return response['arrayBuffer'](); - }) - .catch(function () { - return getBinary(wasmBinaryFile); - }); - } - } - - return Promise.resolve().then(function () { - return getBinary(wasmBinaryFile); - }); - } - - function createWasm() { - var info = { - env: asmLibraryArg, - wasi_snapshot_preview1: asmLibraryArg, - }; - - function receiveInstance(instance, module) { - var exports = instance.exports; - - Module['asm'] = exports; - - Module['asm']['__indirect_function_table']; - - addOnInit(Module['asm']['__wasm_call_ctors']); - - removeRunDependency(); - } - - addRunDependency(); - - function receiveInstantiationResult(result) { - receiveInstance(result['instance']); - } - - function instantiateArrayBuffer(receiver) { - return getBinaryPromise() - .then(function (binary) { - return WebAssembly.instantiate(binary, info); - }) - .then(function (instance) { - return instance; - }) - .then(receiver, function (reason) { - err('failed to asynchronously prepare wasm: ' + reason); - - abort(reason); - }); - } - - function instantiateAsync() { - if ( - !wasmBinary && - typeof WebAssembly.instantiateStreaming == 'function' && - !isDataURI(wasmBinaryFile) && - typeof fetch == 'function' - ) { - return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then( - function (response) { - var result = WebAssembly.instantiateStreaming(response, info); - - return result.then(receiveInstantiationResult, function (reason) { - err('wasm streaming compile failed: ' + reason); - err('falling back to ArrayBuffer instantiation'); - return instantiateArrayBuffer(receiveInstantiationResult); - }); - }, - ); - } else { - return instantiateArrayBuffer(receiveInstantiationResult); - } - } - - if (Module['instantiateWasm']) { - try { - var exports = Module['instantiateWasm'](info, receiveInstance); - return exports; - } catch (e) { - err('Module.instantiateWasm callback failed with error: ' + e); - - readyPromiseReject(e); - } - } - - instantiateAsync().catch(readyPromiseReject); - return {}; - } - - var tempDouble; - var tempI64; - - function callRuntimeCallbacks(callbacks) { - while (callbacks.length > 0) { - callbacks.shift()(Module); - } - } - - var PATH = { - isAbs: (path) => path.charAt(0) === '/', - splitPath: (filename) => { - var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; - return splitPathRe.exec(filename).slice(1); - }, - normalizeArray: (parts, allowAboveRoot) => { - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - if (allowAboveRoot) { - for (; up; up--) { - parts.unshift('..'); - } - } - return parts; - }, - normalize: (path) => { - var isAbsolute = PATH.isAbs(path), - trailingSlash = path.substr(-1) === '/'; - - path = PATH.normalizeArray( - path.split('/').filter((p) => !!p), - !isAbsolute, - ).join('/'); - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - return (isAbsolute ? '/' : '') + path; - }, - dirname: (path) => { - var result = PATH.splitPath(path), - root = result[0], - dir = result[1]; - if (!root && !dir) { - return '.'; - } - if (dir) { - dir = dir.substr(0, dir.length - 1); - } - return root + dir; - }, - basename: (path) => { - if (path === '/') return '/'; - path = PATH.normalize(path); - path = path.replace(/\/$/, ''); - var lastSlash = path.lastIndexOf('/'); - if (lastSlash === -1) return path; - return path.substr(lastSlash + 1); - }, - join: function () { - var paths = Array.prototype.slice.call(arguments); - return PATH.normalize(paths.join('/')); - }, - join2: (l, r) => { - return PATH.normalize(l + '/' + r); - }, - }; - - function getRandomDevice() { - if ( - typeof crypto == 'object' && - typeof crypto['getRandomValues'] == 'function' - ) { - var randomBuffer = new Uint8Array(1); - return () => { - crypto.getRandomValues(randomBuffer); - return randomBuffer[0]; - }; - } else return () => abort('randomDevice'); - } - - var PATH_FS = { - resolve: function () { - var resolvedPath = '', - resolvedAbsolute = false; - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = i >= 0 ? arguments[i] : FS.cwd(); - - if (typeof path != 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - return ''; - } - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = PATH.isAbs(path); - } - - resolvedPath = PATH.normalizeArray( - resolvedPath.split('/').filter((p) => !!p), - !resolvedAbsolute, - ).join('/'); - return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'; - }, - relative: (from, to) => { - from = PATH_FS.resolve(from).substr(1); - to = PATH_FS.resolve(to).substr(1); - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - return outputParts.join('/'); - }, - }; - - function intArrayFromString(stringy, dontAddNull, length) { - var len = lengthBytesUTF8(stringy) + 1; - var u8array = new Array(len); - var numBytesWritten = stringToUTF8Array( - stringy, - u8array, - 0, - u8array.length, - ); - u8array.length = numBytesWritten; - return u8array; - } - var TTY = { - ttys: [], - init: function () {}, - shutdown: function () {}, - register: function (dev, ops) { - TTY.ttys[dev] = { input: [], output: [], ops: ops }; - FS.registerDevice(dev, TTY.stream_ops); - }, - stream_ops: { - open: function (stream) { - var tty = TTY.ttys[stream.node.rdev]; - if (!tty) { - throw new FS.ErrnoError(43); - } - stream.tty = tty; - stream.seekable = false; - }, - close: function (stream) { - stream.tty.ops.fsync(stream.tty); - }, - fsync: function (stream) { - stream.tty.ops.fsync(stream.tty); - }, - read: function (stream, buffer, offset, length, pos) { - if (!stream.tty || !stream.tty.ops.get_char) { - throw new FS.ErrnoError(60); - } - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = stream.tty.ops.get_char(stream.tty); - } catch (e) { - throw new FS.ErrnoError(29); - } - if (result === undefined && bytesRead === 0) { - throw new FS.ErrnoError(6); - } - if (result === null || result === undefined) break; - bytesRead++; - buffer[offset + i] = result; - } - if (bytesRead) { - stream.node.timestamp = Date.now(); - } - return bytesRead; - }, - write: function (stream, buffer, offset, length, pos) { - if (!stream.tty || !stream.tty.ops.put_char) { - throw new FS.ErrnoError(60); - } - try { - for (var i = 0; i < length; i++) { - stream.tty.ops.put_char(stream.tty, buffer[offset + i]); - } - } catch (e) { - throw new FS.ErrnoError(29); - } - if (length) { - stream.node.timestamp = Date.now(); - } - return i; - }, - }, - default_tty_ops: { - get_char: function (tty) { - if (!tty.input.length) { - var result = null; - if ( - typeof window != 'undefined' && - typeof window.prompt == 'function' - ) { - result = window.prompt('Input: '); - if (result !== null) { - result += '\n'; - } - } else if (typeof readline == 'function') { - result = readline(); - if (result !== null) { - result += '\n'; - } - } - if (!result) { - return null; - } - tty.input = intArrayFromString(result); - } - return tty.input.shift(); - }, - put_char: function (tty, val) { - if (val === null || val === 10) { - out(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } else { - if (val != 0) tty.output.push(val); - } - }, - fsync: function (tty) { - if (tty.output && tty.output.length > 0) { - out(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } - }, - }, - default_tty1_ops: { - put_char: function (tty, val) { - if (val === null || val === 10) { - err(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } else { - if (val != 0) tty.output.push(val); - } - }, - fsync: function (tty) { - if (tty.output && tty.output.length > 0) { - err(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } - }, - }, - }; - - function zeroMemory(address, size) { - HEAPU8.fill(0, address, address + size); - return address; - } - - function alignMemory(size, alignment) { - return Math.ceil(size / alignment) * alignment; - } - function mmapAlloc(size) { - size = alignMemory(size, 65536); - var ptr = _emscripten_builtin_memalign(65536, size); - if (!ptr) return 0; - return zeroMemory(ptr, size); - } - var MEMFS = { - ops_table: null, - mount: function (mount) { - return MEMFS.createNode(null, '/', 16384 | 511, 0); - }, - createNode: function (parent, name, mode, dev) { - if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { - throw new FS.ErrnoError(63); - } - if (!MEMFS.ops_table) { - MEMFS.ops_table = { - dir: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - lookup: MEMFS.node_ops.lookup, - mknod: MEMFS.node_ops.mknod, - rename: MEMFS.node_ops.rename, - unlink: MEMFS.node_ops.unlink, - rmdir: MEMFS.node_ops.rmdir, - readdir: MEMFS.node_ops.readdir, - symlink: MEMFS.node_ops.symlink, - }, - stream: { - llseek: MEMFS.stream_ops.llseek, - }, - }, - file: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - }, - stream: { - llseek: MEMFS.stream_ops.llseek, - read: MEMFS.stream_ops.read, - write: MEMFS.stream_ops.write, - allocate: MEMFS.stream_ops.allocate, - mmap: MEMFS.stream_ops.mmap, - msync: MEMFS.stream_ops.msync, - }, - }, - link: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - readlink: MEMFS.node_ops.readlink, - }, - stream: {}, - }, - chrdev: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - }, - stream: FS.chrdev_stream_ops, - }, - }; - } - var node = FS.createNode(parent, name, mode, dev); - if (FS.isDir(node.mode)) { - node.node_ops = MEMFS.ops_table.dir.node; - node.stream_ops = MEMFS.ops_table.dir.stream; - node.contents = {}; - } else if (FS.isFile(node.mode)) { - node.node_ops = MEMFS.ops_table.file.node; - node.stream_ops = MEMFS.ops_table.file.stream; - node.usedBytes = 0; - - node.contents = null; - } else if (FS.isLink(node.mode)) { - node.node_ops = MEMFS.ops_table.link.node; - node.stream_ops = MEMFS.ops_table.link.stream; - } else if (FS.isChrdev(node.mode)) { - node.node_ops = MEMFS.ops_table.chrdev.node; - node.stream_ops = MEMFS.ops_table.chrdev.stream; - } - node.timestamp = Date.now(); - - if (parent) { - parent.contents[name] = node; - parent.timestamp = node.timestamp; - } - return node; - }, - getFileDataAsTypedArray: function (node) { - if (!node.contents) return new Uint8Array(0); - if (node.contents.subarray) - return node.contents.subarray(0, node.usedBytes); - return new Uint8Array(node.contents); - }, - expandFileStorage: function (node, newCapacity) { - var prevCapacity = node.contents ? node.contents.length : 0; - if (prevCapacity >= newCapacity) return; - - var CAPACITY_DOUBLING_MAX = 1024 * 1024; - newCapacity = Math.max( - newCapacity, - (prevCapacity * - (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> - 0, - ); - if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); - var oldContents = node.contents; - node.contents = new Uint8Array(newCapacity); - if (node.usedBytes > 0) - node.contents.set(oldContents.subarray(0, node.usedBytes), 0); - }, - resizeFileStorage: function (node, newSize) { - if (node.usedBytes == newSize) return; - if (newSize == 0) { - node.contents = null; - node.usedBytes = 0; - } else { - var oldContents = node.contents; - node.contents = new Uint8Array(newSize); - if (oldContents) { - node.contents.set( - oldContents.subarray(0, Math.min(newSize, node.usedBytes)), - ); - } - node.usedBytes = newSize; - } - }, - node_ops: { - getattr: function (node) { - var attr = {}; - - attr.dev = FS.isChrdev(node.mode) ? node.id : 1; - attr.ino = node.id; - attr.mode = node.mode; - attr.nlink = 1; - attr.uid = 0; - attr.gid = 0; - attr.rdev = node.rdev; - if (FS.isDir(node.mode)) { - attr.size = 4096; - } else if (FS.isFile(node.mode)) { - attr.size = node.usedBytes; - } else if (FS.isLink(node.mode)) { - attr.size = node.link.length; - } else { - attr.size = 0; - } - attr.atime = new Date(node.timestamp); - attr.mtime = new Date(node.timestamp); - attr.ctime = new Date(node.timestamp); - - attr.blksize = 4096; - attr.blocks = Math.ceil(attr.size / attr.blksize); - return attr; - }, - setattr: function (node, attr) { - if (attr.mode !== undefined) { - node.mode = attr.mode; - } - if (attr.timestamp !== undefined) { - node.timestamp = attr.timestamp; - } - if (attr.size !== undefined) { - MEMFS.resizeFileStorage(node, attr.size); - } - }, - lookup: function (parent, name) { - throw FS.genericErrors[44]; - }, - mknod: function (parent, name, mode, dev) { - return MEMFS.createNode(parent, name, mode, dev); - }, - rename: function (old_node, new_dir, new_name) { - if (FS.isDir(old_node.mode)) { - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) {} - if (new_node) { - for (var i in new_node.contents) { - throw new FS.ErrnoError(55); - } - } - } - - delete old_node.parent.contents[old_node.name]; - old_node.parent.timestamp = Date.now(); - old_node.name = new_name; - new_dir.contents[new_name] = old_node; - new_dir.timestamp = old_node.parent.timestamp; - old_node.parent = new_dir; - }, - unlink: function (parent, name) { - delete parent.contents[name]; - parent.timestamp = Date.now(); - }, - rmdir: function (parent, name) { - var node = FS.lookupNode(parent, name); - for (var i in node.contents) { - throw new FS.ErrnoError(55); - } - delete parent.contents[name]; - parent.timestamp = Date.now(); - }, - readdir: function (node) { - var entries = ['.', '..']; - for (var key in node.contents) { - if (!node.contents.hasOwnProperty(key)) { - continue; - } - entries.push(key); - } - return entries; - }, - symlink: function (parent, newname, oldpath) { - var node = MEMFS.createNode(parent, newname, 511 | 40960, 0); - node.link = oldpath; - return node; - }, - readlink: function (node) { - if (!FS.isLink(node.mode)) { - throw new FS.ErrnoError(28); - } - return node.link; - }, - }, - stream_ops: { - read: function (stream, buffer, offset, length, position) { - var contents = stream.node.contents; - if (position >= stream.node.usedBytes) return 0; - var size = Math.min(stream.node.usedBytes - position, length); - if (size > 8 && contents.subarray) { - buffer.set(contents.subarray(position, position + size), offset); - } else { - for (var i = 0; i < size; i++) - buffer[offset + i] = contents[position + i]; - } - return size; - }, - write: function (stream, buffer, offset, length, position, canOwn) { - if (buffer.buffer === HEAP8.buffer) { - canOwn = false; - } - - if (!length) return 0; - var node = stream.node; - node.timestamp = Date.now(); - - if (buffer.subarray && (!node.contents || node.contents.subarray)) { - if (canOwn) { - node.contents = buffer.subarray(offset, offset + length); - node.usedBytes = length; - return length; - } else if (node.usedBytes === 0 && position === 0) { - node.contents = buffer.slice(offset, offset + length); - node.usedBytes = length; - return length; - } else if (position + length <= node.usedBytes) { - node.contents.set( - buffer.subarray(offset, offset + length), - position, - ); - return length; - } - } - - MEMFS.expandFileStorage(node, position + length); - if (node.contents.subarray && buffer.subarray) { - node.contents.set( - buffer.subarray(offset, offset + length), - position, - ); - } else { - for (var i = 0; i < length; i++) { - node.contents[position + i] = buffer[offset + i]; - } - } - node.usedBytes = Math.max(node.usedBytes, position + length); - return length; - }, - llseek: function (stream, offset, whence) { - var position = offset; - if (whence === 1) { - position += stream.position; - } else if (whence === 2) { - if (FS.isFile(stream.node.mode)) { - position += stream.node.usedBytes; - } - } - if (position < 0) { - throw new FS.ErrnoError(28); - } - return position; - }, - allocate: function (stream, offset, length) { - MEMFS.expandFileStorage(stream.node, offset + length); - stream.node.usedBytes = Math.max( - stream.node.usedBytes, - offset + length, - ); - }, - mmap: function (stream, length, position, prot, flags) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - var ptr; - var allocated; - var contents = stream.node.contents; - - if (!(flags & 2) && contents.buffer === HEAP8.buffer) { - allocated = false; - ptr = contents.byteOffset; - } else { - if (position > 0 || position + length < contents.length) { - if (contents.subarray) { - contents = contents.subarray(position, position + length); - } else { - contents = Array.prototype.slice.call( - contents, - position, - position + length, - ); - } - } - allocated = true; - ptr = mmapAlloc(length); - if (!ptr) { - throw new FS.ErrnoError(48); - } - HEAP8.set(contents, ptr); - } - return { ptr: ptr, allocated: allocated }; - }, - msync: function (stream, buffer, offset, length, mmapFlags) { - MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false); - - return 0; - }, - }, - }; - - function asyncLoad(url, onload, onerror, noRunDep) { - var dep = getUniqueRunDependency('al ' + url) ; - readAsync( - url, - (arrayBuffer) => { - assert( - arrayBuffer, - 'Loading data file "' + url + '" failed (no arrayBuffer).', - ); - onload(new Uint8Array(arrayBuffer)); - if (dep) removeRunDependency(); - }, - (event) => { - if (onerror) { - onerror(); - } else { - throw 'Loading data file "' + url + '" failed.'; - } - }, - ); - if (dep) addRunDependency(); - } - - var FS = { - root: null, - mounts: [], - devices: {}, - streams: [], - nextInode: 1, - nameTable: null, - currentPath: '/', - initialized: false, - ignorePermissions: true, - ErrnoError: null, - genericErrors: {}, - filesystems: null, - syncFSRequests: 0, - lookupPath: (path, opts = {}) => { - path = PATH_FS.resolve(path); - - if (!path) return { path: '', node: null }; - - var defaults = { - follow_mount: true, - recurse_count: 0, - }; - opts = Object.assign(defaults, opts); - - if (opts.recurse_count > 8) { - throw new FS.ErrnoError(32); - } - - var parts = path.split('/').filter((p) => !!p); - - var current = FS.root; - var current_path = '/'; - - for (var i = 0; i < parts.length; i++) { - var islast = i === parts.length - 1; - if (islast && opts.parent) { - break; - } - - current = FS.lookupNode(current, parts[i]); - current_path = PATH.join2(current_path, parts[i]); - - if (FS.isMountpoint(current)) { - if (!islast || (islast && opts.follow_mount)) { - current = current.mounted.root; - } - } - - if (!islast || opts.follow) { - var count = 0; - while (FS.isLink(current.mode)) { - var link = FS.readlink(current_path); - current_path = PATH_FS.resolve(PATH.dirname(current_path), link); - - var lookup = FS.lookupPath(current_path, { - recurse_count: opts.recurse_count + 1, - }); - current = lookup.node; - - if (count++ > 40) { - throw new FS.ErrnoError(32); - } - } - } - } - - return { path: current_path, node: current }; - }, - getPath: (node) => { - var path; - while (true) { - if (FS.isRoot(node)) { - var mount = node.mount.mountpoint; - if (!path) return mount; - return mount[mount.length - 1] !== '/' - ? mount + '/' + path - : mount + path; - } - path = path ? node.name + '/' + path : node.name; - node = node.parent; - } - }, - hashName: (parentid, name) => { - var hash = 0; - - for (var i = 0; i < name.length; i++) { - hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; - } - return ((parentid + hash) >>> 0) % FS.nameTable.length; - }, - hashAddNode: (node) => { - var hash = FS.hashName(node.parent.id, node.name); - node.name_next = FS.nameTable[hash]; - FS.nameTable[hash] = node; - }, - hashRemoveNode: (node) => { - var hash = FS.hashName(node.parent.id, node.name); - if (FS.nameTable[hash] === node) { - FS.nameTable[hash] = node.name_next; - } else { - var current = FS.nameTable[hash]; - while (current) { - if (current.name_next === node) { - current.name_next = node.name_next; - break; - } - current = current.name_next; - } - } - }, - lookupNode: (parent, name) => { - var errCode = FS.mayLookup(parent); - if (errCode) { - throw new FS.ErrnoError(errCode, parent); - } - var hash = FS.hashName(parent.id, name); - for (var node = FS.nameTable[hash]; node; node = node.name_next) { - var nodeName = node.name; - if (node.parent.id === parent.id && nodeName === name) { - return node; - } - } - - return FS.lookup(parent, name); - }, - createNode: (parent, name, mode, rdev) => { - var node = new FS.FSNode(parent, name, mode, rdev); - - FS.hashAddNode(node); - - return node; - }, - destroyNode: (node) => { - FS.hashRemoveNode(node); - }, - isRoot: (node) => { - return node === node.parent; - }, - isMountpoint: (node) => { - return !!node.mounted; - }, - isFile: (mode) => { - return (mode & 61440) === 32768; - }, - isDir: (mode) => { - return (mode & 61440) === 16384; - }, - isLink: (mode) => { - return (mode & 61440) === 40960; - }, - isChrdev: (mode) => { - return (mode & 61440) === 8192; - }, - isBlkdev: (mode) => { - return (mode & 61440) === 24576; - }, - isFIFO: (mode) => { - return (mode & 61440) === 4096; - }, - isSocket: (mode) => { - return (mode & 49152) === 49152; - }, - flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 }, - modeStringToFlags: (str) => { - var flags = FS.flagModes[str]; - if (typeof flags == 'undefined') { - throw new Error('Unknown file open mode: ' + str); - } - return flags; - }, - flagsToPermissionString: (flag) => { - var perms = ['r', 'w', 'rw'][flag & 3]; - if (flag & 512) { - perms += 'w'; - } - return perms; - }, - nodePermissions: (node, perms) => { - if (FS.ignorePermissions) { - return 0; - } - - if (perms.includes('r') && !(node.mode & 292)) { - return 2; - } else if (perms.includes('w') && !(node.mode & 146)) { - return 2; - } else if (perms.includes('x') && !(node.mode & 73)) { - return 2; - } - return 0; - }, - mayLookup: (dir) => { - var errCode = FS.nodePermissions(dir, 'x'); - if (errCode) return errCode; - if (!dir.node_ops.lookup) return 2; - return 0; - }, - mayCreate: (dir, name) => { - try { - var node = FS.lookupNode(dir, name); - return 20; - } catch (e) {} - return FS.nodePermissions(dir, 'wx'); - }, - mayDelete: (dir, name, isdir) => { - var node; - try { - node = FS.lookupNode(dir, name); - } catch (e) { - return e.errno; - } - var errCode = FS.nodePermissions(dir, 'wx'); - if (errCode) { - return errCode; - } - if (isdir) { - if (!FS.isDir(node.mode)) { - return 54; - } - if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { - return 10; - } - } else { - if (FS.isDir(node.mode)) { - return 31; - } - } - return 0; - }, - mayOpen: (node, flags) => { - if (!node) { - return 44; - } - if (FS.isLink(node.mode)) { - return 32; - } else if (FS.isDir(node.mode)) { - if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) { - return 31; - } - } - return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); - }, - MAX_OPEN_FDS: 4096, - nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => { - for (var fd = fd_start; fd <= fd_end; fd++) { - if (!FS.streams[fd]) { - return fd; - } - } - throw new FS.ErrnoError(33); - }, - getStream: (fd) => FS.streams[fd], - createStream: (stream, fd_start, fd_end) => { - if (!FS.FSStream) { - FS.FSStream = function () { - this.shared = {}; - }; - FS.FSStream.prototype = {}; - Object.defineProperties(FS.FSStream.prototype, { - object: { - get: function () { - return this.node; - }, - - set: function (val) { - this.node = val; - }, - }, - isRead: { - get: function () { - return (this.flags & 2097155) !== 1; - }, - }, - isWrite: { - get: function () { - return (this.flags & 2097155) !== 0; - }, - }, - isAppend: { - get: function () { - return this.flags & 1024; - }, - }, - flags: { - get: function () { - return this.shared.flags; - }, - - set: function (val) { - this.shared.flags = val; - }, - }, - position: { - get: function () { - return this.shared.position; - }, - - set: function (val) { - this.shared.position = val; - }, - }, - }); - } - - stream = Object.assign(new FS.FSStream(), stream); - var fd = FS.nextfd(fd_start, fd_end); - stream.fd = fd; - FS.streams[fd] = stream; - return stream; - }, - closeStream: (fd) => { - FS.streams[fd] = null; - }, - chrdev_stream_ops: { - open: (stream) => { - var device = FS.getDevice(stream.node.rdev); - - stream.stream_ops = device.stream_ops; - - if (stream.stream_ops.open) { - stream.stream_ops.open(stream); - } - }, - llseek: () => { - throw new FS.ErrnoError(70); - }, - }, - major: (dev) => dev >> 8, - minor: (dev) => dev & 0xff, - makedev: (ma, mi) => (ma << 8) | mi, - registerDevice: (dev, ops) => { - FS.devices[dev] = { stream_ops: ops }; - }, - getDevice: (dev) => FS.devices[dev], - getMounts: (mount) => { - var mounts = []; - var check = [mount]; - - while (check.length) { - var m = check.pop(); - - mounts.push(m); - - check.push.apply(check, m.mounts); - } - - return mounts; - }, - syncfs: (populate, callback) => { - if (typeof populate == 'function') { - callback = populate; - populate = false; - } - - FS.syncFSRequests++; - - if (FS.syncFSRequests > 1) { - err( - 'warning: ' + - FS.syncFSRequests + - ' FS.syncfs operations in flight at once, probably just doing extra work', - ); - } - - var mounts = FS.getMounts(FS.root.mount); - var completed = 0; - - function doCallback(errCode) { - FS.syncFSRequests--; - return callback(errCode); - } - - function done(errCode) { - if (errCode) { - if (!done.errored) { - done.errored = true; - return doCallback(errCode); - } - return; - } - if (++completed >= mounts.length) { - doCallback(null); - } - } - - mounts.forEach((mount) => { - if (!mount.type.syncfs) { - return done(null); - } - mount.type.syncfs(mount, populate, done); - }); - }, - mount: (type, opts, mountpoint) => { - var root = mountpoint === '/'; - var pseudo = !mountpoint; - var node; - - if (root && FS.root) { - throw new FS.ErrnoError(10); - } else if (!root && !pseudo) { - var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - - mountpoint = lookup.path; - node = lookup.node; - - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - - if (!FS.isDir(node.mode)) { - throw new FS.ErrnoError(54); - } - } - - var mount = { - type: type, - opts: opts, - mountpoint: mountpoint, - mounts: [], - }; - - var mountRoot = type.mount(mount); - mountRoot.mount = mount; - mount.root = mountRoot; - - if (root) { - FS.root = mountRoot; - } else if (node) { - node.mounted = mount; - - if (node.mount) { - node.mount.mounts.push(mount); - } - } - - return mountRoot; - }, - unmount: (mountpoint) => { - var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - - if (!FS.isMountpoint(lookup.node)) { - throw new FS.ErrnoError(28); - } - - var node = lookup.node; - var mount = node.mounted; - var mounts = FS.getMounts(mount); - - Object.keys(FS.nameTable).forEach((hash) => { - var current = FS.nameTable[hash]; - - while (current) { - var next = current.name_next; - - if (mounts.includes(current.mount)) { - FS.destroyNode(current); - } - - current = next; - } - }); - - node.mounted = null; - - var idx = node.mount.mounts.indexOf(mount); - node.mount.mounts.splice(idx, 1); - }, - lookup: (parent, name) => { - return parent.node_ops.lookup(parent, name); - }, - mknod: (path, mode, dev) => { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name = PATH.basename(path); - if (!name || name === '.' || name === '..') { - throw new FS.ErrnoError(28); - } - var errCode = FS.mayCreate(parent, name); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.mknod) { - throw new FS.ErrnoError(63); - } - return parent.node_ops.mknod(parent, name, mode, dev); - }, - create: (path, mode) => { - mode = mode !== undefined ? mode : 438; - mode &= 4095; - mode |= 32768; - return FS.mknod(path, mode, 0); - }, - mkdir: (path, mode) => { - mode = mode !== undefined ? mode : 511; - mode &= 511 | 512; - mode |= 16384; - return FS.mknod(path, mode, 0); - }, - mkdirTree: (path, mode) => { - var dirs = path.split('/'); - var d = ''; - for (var i = 0; i < dirs.length; ++i) { - if (!dirs[i]) continue; - d += '/' + dirs[i]; - try { - FS.mkdir(d, mode); - } catch (e) { - if (e.errno != 20) throw e; - } - } - }, - mkdev: (path, mode, dev) => { - if (typeof dev == 'undefined') { - dev = mode; - mode = 438; - } - mode |= 8192; - return FS.mknod(path, mode, dev); - }, - symlink: (oldpath, newpath) => { - if (!PATH_FS.resolve(oldpath)) { - throw new FS.ErrnoError(44); - } - var lookup = FS.lookupPath(newpath, { parent: true }); - var parent = lookup.node; - if (!parent) { - throw new FS.ErrnoError(44); - } - var newname = PATH.basename(newpath); - var errCode = FS.mayCreate(parent, newname); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.symlink) { - throw new FS.ErrnoError(63); - } - return parent.node_ops.symlink(parent, newname, oldpath); - }, - rename: (old_path, new_path) => { - var old_dirname = PATH.dirname(old_path); - var new_dirname = PATH.dirname(new_path); - var old_name = PATH.basename(old_path); - var new_name = PATH.basename(new_path); - - var lookup, old_dir, new_dir; - - lookup = FS.lookupPath(old_path, { parent: true }); - old_dir = lookup.node; - lookup = FS.lookupPath(new_path, { parent: true }); - new_dir = lookup.node; - - if (!old_dir || !new_dir) throw new FS.ErrnoError(44); - - if (old_dir.mount !== new_dir.mount) { - throw new FS.ErrnoError(75); - } - - var old_node = FS.lookupNode(old_dir, old_name); - - var relative = PATH_FS.relative(old_path, new_dirname); - if (relative.charAt(0) !== '.') { - throw new FS.ErrnoError(28); - } - - relative = PATH_FS.relative(new_path, old_dirname); - if (relative.charAt(0) !== '.') { - throw new FS.ErrnoError(55); - } - - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) {} - - if (old_node === new_node) { - return; - } - - var isdir = FS.isDir(old_node.mode); - var errCode = FS.mayDelete(old_dir, old_name, isdir); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - - errCode = new_node - ? FS.mayDelete(new_dir, new_name, isdir) - : FS.mayCreate(new_dir, new_name); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!old_dir.node_ops.rename) { - throw new FS.ErrnoError(63); - } - if ( - FS.isMountpoint(old_node) || - (new_node && FS.isMountpoint(new_node)) - ) { - throw new FS.ErrnoError(10); - } - - if (new_dir !== old_dir) { - errCode = FS.nodePermissions(old_dir, 'w'); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - } - - FS.hashRemoveNode(old_node); - - try { - old_dir.node_ops.rename(old_node, new_dir, new_name); - } catch (e) { - throw e; - } finally { - FS.hashAddNode(old_node); - } - }, - rmdir: (path) => { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name = PATH.basename(path); - var node = FS.lookupNode(parent, name); - var errCode = FS.mayDelete(parent, name, true); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.rmdir) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - parent.node_ops.rmdir(parent, name); - FS.destroyNode(node); - }, - readdir: (path) => { - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - if (!node.node_ops.readdir) { - throw new FS.ErrnoError(54); - } - return node.node_ops.readdir(node); - }, - unlink: (path) => { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - if (!parent) { - throw new FS.ErrnoError(44); - } - var name = PATH.basename(path); - var node = FS.lookupNode(parent, name); - var errCode = FS.mayDelete(parent, name, false); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.unlink) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - parent.node_ops.unlink(parent, name); - FS.destroyNode(node); - }, - readlink: (path) => { - var lookup = FS.lookupPath(path); - var link = lookup.node; - if (!link) { - throw new FS.ErrnoError(44); - } - if (!link.node_ops.readlink) { - throw new FS.ErrnoError(28); - } - return PATH_FS.resolve( - FS.getPath(link.parent), - link.node_ops.readlink(link), - ); - }, - stat: (path, dontFollow) => { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - var node = lookup.node; - if (!node) { - throw new FS.ErrnoError(44); - } - if (!node.node_ops.getattr) { - throw new FS.ErrnoError(63); - } - return node.node_ops.getattr(node); - }, - lstat: (path) => { - return FS.stat(path, true); - }, - chmod: (path, mode, dontFollow) => { - var node; - if (typeof path == 'string') { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - node.node_ops.setattr(node, { - mode: (mode & 4095) | (node.mode & ~4095), - timestamp: Date.now(), - }); - }, - lchmod: (path, mode) => { - FS.chmod(path, mode, true); - }, - fchmod: (fd, mode) => { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - FS.chmod(stream.node, mode); - }, - chown: (path, uid, gid, dontFollow) => { - var node; - if (typeof path == 'string') { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - node.node_ops.setattr(node, { - timestamp: Date.now(), - }); - }, - lchown: (path, uid, gid) => { - FS.chown(path, uid, gid, true); - }, - fchown: (fd, uid, gid) => { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - FS.chown(stream.node, uid, gid); - }, - truncate: (path, len) => { - if (len < 0) { - throw new FS.ErrnoError(28); - } - var node; - if (typeof path == 'string') { - var lookup = FS.lookupPath(path, { follow: true }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - if (FS.isDir(node.mode)) { - throw new FS.ErrnoError(31); - } - if (!FS.isFile(node.mode)) { - throw new FS.ErrnoError(28); - } - var errCode = FS.nodePermissions(node, 'w'); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - node.node_ops.setattr(node, { - size: len, - timestamp: Date.now(), - }); - }, - ftruncate: (fd, len) => { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(28); - } - FS.truncate(stream.node, len); - }, - utime: (path, atime, mtime) => { - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - node.node_ops.setattr(node, { - timestamp: Math.max(atime, mtime), - }); - }, - open: (path, flags, mode) => { - if (path === '') { - throw new FS.ErrnoError(44); - } - flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; - mode = typeof mode == 'undefined' ? 438 : mode; - if (flags & 64) { - mode = (mode & 4095) | 32768; - } else { - mode = 0; - } - var node; - if (typeof path == 'object') { - node = path; - } else { - path = PATH.normalize(path); - try { - var lookup = FS.lookupPath(path, { - follow: !(flags & 131072), - }); - node = lookup.node; - } catch (e) {} - } - - var created = false; - if (flags & 64) { - if (node) { - if (flags & 128) { - throw new FS.ErrnoError(20); - } - } else { - node = FS.mknod(path, mode, 0); - created = true; - } - } - if (!node) { - throw new FS.ErrnoError(44); - } - - if (FS.isChrdev(node.mode)) { - flags &= ~512; - } - - if (flags & 65536 && !FS.isDir(node.mode)) { - throw new FS.ErrnoError(54); - } - - if (!created) { - var errCode = FS.mayOpen(node, flags); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - } - - if (flags & 512 && !created) { - FS.truncate(node, 0); - } - - flags &= ~(128 | 512 | 131072); - - var stream = FS.createStream({ - node: node, - path: FS.getPath(node), - flags: flags, - seekable: true, - position: 0, - stream_ops: node.stream_ops, - - ungotten: [], - error: false, - }); - - if (stream.stream_ops.open) { - stream.stream_ops.open(stream); - } - if (Module['logReadFiles'] && !(flags & 1)) { - if (!FS.readFiles) FS.readFiles = {}; - if (!(path in FS.readFiles)) { - FS.readFiles[path] = 1; - } - } - return stream; - }, - close: (stream) => { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (stream.getdents) stream.getdents = null; - try { - if (stream.stream_ops.close) { - stream.stream_ops.close(stream); - } - } catch (e) { - throw e; - } finally { - FS.closeStream(stream.fd); - } - stream.fd = null; - }, - isClosed: (stream) => { - return stream.fd === null; - }, - llseek: (stream, offset, whence) => { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (!stream.seekable || !stream.stream_ops.llseek) { - throw new FS.ErrnoError(70); - } - if (whence != 0 && whence != 1 && whence != 2) { - throw new FS.ErrnoError(28); - } - stream.position = stream.stream_ops.llseek(stream, offset, whence); - stream.ungotten = []; - return stream.position; - }, - read: (stream, buffer, offset, length, position) => { - if (length < 0 || position < 0) { - throw new FS.ErrnoError(28); - } - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 1) { - throw new FS.ErrnoError(8); - } - if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(31); - } - if (!stream.stream_ops.read) { - throw new FS.ErrnoError(28); - } - var seeking = typeof position != 'undefined'; - if (!seeking) { - position = stream.position; - } else if (!stream.seekable) { - throw new FS.ErrnoError(70); - } - var bytesRead = stream.stream_ops.read( - stream, - buffer, - offset, - length, - position, - ); - if (!seeking) stream.position += bytesRead; - return bytesRead; - }, - write: (stream, buffer, offset, length, position, canOwn) => { - if (length < 0 || position < 0) { - throw new FS.ErrnoError(28); - } - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(8); - } - if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(31); - } - if (!stream.stream_ops.write) { - throw new FS.ErrnoError(28); - } - if (stream.seekable && stream.flags & 1024) { - FS.llseek(stream, 0, 2); - } - var seeking = typeof position != 'undefined'; - if (!seeking) { - position = stream.position; - } else if (!stream.seekable) { - throw new FS.ErrnoError(70); - } - var bytesWritten = stream.stream_ops.write( - stream, - buffer, - offset, - length, - position, - canOwn, - ); - if (!seeking) stream.position += bytesWritten; - return bytesWritten; - }, - allocate: (stream, offset, length) => { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (offset < 0 || length <= 0) { - throw new FS.ErrnoError(28); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(8); - } - if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (!stream.stream_ops.allocate) { - throw new FS.ErrnoError(138); - } - stream.stream_ops.allocate(stream, offset, length); - }, - mmap: (stream, length, position, prot, flags) => { - if ( - (prot & 2) !== 0 && - (flags & 2) === 0 && - (stream.flags & 2097155) !== 2 - ) { - throw new FS.ErrnoError(2); - } - if ((stream.flags & 2097155) === 1) { - throw new FS.ErrnoError(2); - } - if (!stream.stream_ops.mmap) { - throw new FS.ErrnoError(43); - } - return stream.stream_ops.mmap(stream, length, position, prot, flags); - }, - msync: (stream, buffer, offset, length, mmapFlags) => { - if (!stream.stream_ops.msync) { - return 0; - } - return stream.stream_ops.msync( - stream, - buffer, - offset, - length, - mmapFlags, - ); - }, - munmap: (stream) => 0, - ioctl: (stream, cmd, arg) => { - if (!stream.stream_ops.ioctl) { - throw new FS.ErrnoError(59); - } - return stream.stream_ops.ioctl(stream, cmd, arg); - }, - readFile: (path, opts = {}) => { - opts.flags = opts.flags || 0; - opts.encoding = opts.encoding || 'binary'; - if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { - throw new Error('Invalid encoding type "' + opts.encoding + '"'); - } - var ret; - var stream = FS.open(path, opts.flags); - var stat = FS.stat(path); - var length = stat.size; - var buf = new Uint8Array(length); - FS.read(stream, buf, 0, length, 0); - if (opts.encoding === 'utf8') { - ret = UTF8ArrayToString(buf, 0); - } else if (opts.encoding === 'binary') { - ret = buf; - } - FS.close(stream); - return ret; - }, - writeFile: (path, data, opts = {}) => { - opts.flags = opts.flags || 577; - var stream = FS.open(path, opts.flags, opts.mode); - if (typeof data == 'string') { - var buf = new Uint8Array(lengthBytesUTF8(data) + 1); - var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); - FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn); - } else if (ArrayBuffer.isView(data)) { - FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); - } else { - throw new Error('Unsupported data type'); - } - FS.close(stream); - }, - cwd: () => FS.currentPath, - chdir: (path) => { - var lookup = FS.lookupPath(path, { follow: true }); - if (lookup.node === null) { - throw new FS.ErrnoError(44); - } - if (!FS.isDir(lookup.node.mode)) { - throw new FS.ErrnoError(54); - } - var errCode = FS.nodePermissions(lookup.node, 'x'); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - FS.currentPath = lookup.path; - }, - createDefaultDirectories: () => { - FS.mkdir('/tmp'); - FS.mkdir('/home'); - FS.mkdir('/home/web_user'); - }, - createDefaultDevices: () => { - FS.mkdir('/dev'); - - FS.registerDevice(FS.makedev(1, 3), { - read: () => 0, - write: (stream, buffer, offset, length, pos) => length, - }); - FS.mkdev('/dev/null', FS.makedev(1, 3)); - - TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); - TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); - FS.mkdev('/dev/tty', FS.makedev(5, 0)); - FS.mkdev('/dev/tty1', FS.makedev(6, 0)); - - var random_device = getRandomDevice(); - FS.createDevice('/dev', 'random', random_device); - FS.createDevice('/dev', 'urandom', random_device); - - FS.mkdir('/dev/shm'); - FS.mkdir('/dev/shm/tmp'); - }, - createSpecialDirectories: () => { - FS.mkdir('/proc'); - var proc_self = FS.mkdir('/proc/self'); - FS.mkdir('/proc/self/fd'); - FS.mount( - { - mount: () => { - var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73); - node.node_ops = { - lookup: (parent, name) => { - var fd = +name; - var stream = FS.getStream(fd); - if (!stream) throw new FS.ErrnoError(8); - var ret = { - parent: null, - mount: { mountpoint: 'fake' }, - node_ops: { readlink: () => stream.path }, - }; - ret.parent = ret; - return ret; - }, - }; - return node; - }, - }, - {}, - '/proc/self/fd', - ); - }, - createStandardStreams: () => { - if (Module['stdin']) { - FS.createDevice('/dev', 'stdin', Module['stdin']); - } else { - FS.symlink('/dev/tty', '/dev/stdin'); - } - if (Module['stdout']) { - FS.createDevice('/dev', 'stdout', null, Module['stdout']); - } else { - FS.symlink('/dev/tty', '/dev/stdout'); - } - if (Module['stderr']) { - FS.createDevice('/dev', 'stderr', null, Module['stderr']); - } else { - FS.symlink('/dev/tty1', '/dev/stderr'); - } - - FS.open('/dev/stdin', 0); - FS.open('/dev/stdout', 1); - FS.open('/dev/stderr', 1); - }, - ensureErrnoError: () => { - if (FS.ErrnoError) return; - FS.ErrnoError = function ErrnoError(errno, node) { - this.node = node; - this.setErrno = function (errno) { - this.errno = errno; - }; - this.setErrno(errno); - this.message = 'FS error'; - }; - FS.ErrnoError.prototype = new Error(); - FS.ErrnoError.prototype.constructor = FS.ErrnoError; - - [44].forEach((code) => { - FS.genericErrors[code] = new FS.ErrnoError(code); - FS.genericErrors[code].stack = ''; - }); - }, - staticInit: () => { - FS.ensureErrnoError(); - - FS.nameTable = new Array(4096); - - FS.mount(MEMFS, {}, '/'); - - FS.createDefaultDirectories(); - FS.createDefaultDevices(); - FS.createSpecialDirectories(); - - FS.filesystems = { - MEMFS: MEMFS, - }; - }, - init: (input, output, error) => { - FS.init.initialized = true; - - FS.ensureErrnoError(); - - Module['stdin'] = input || Module['stdin']; - Module['stdout'] = output || Module['stdout']; - Module['stderr'] = error || Module['stderr']; - - FS.createStandardStreams(); - }, - quit: () => { - FS.init.initialized = false; - - for (var i = 0; i < FS.streams.length; i++) { - var stream = FS.streams[i]; - if (!stream) { - continue; - } - FS.close(stream); - } - }, - getMode: (canRead, canWrite) => { - var mode = 0; - if (canRead) mode |= 292 | 73; - if (canWrite) mode |= 146; - return mode; - }, - findObject: (path, dontResolveLastLink) => { - var ret = FS.analyzePath(path, dontResolveLastLink); - if (!ret.exists) { - return null; - } - return ret.object; - }, - analyzePath: (path, dontResolveLastLink) => { - try { - var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - path = lookup.path; - } catch (e) {} - var ret = { - isRoot: false, - exists: false, - error: 0, - name: null, - path: null, - object: null, - parentExists: false, - parentPath: null, - parentObject: null, - }; - try { - var lookup = FS.lookupPath(path, { parent: true }); - ret.parentExists = true; - ret.parentPath = lookup.path; - ret.parentObject = lookup.node; - ret.name = PATH.basename(path); - lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - ret.exists = true; - ret.path = lookup.path; - ret.object = lookup.node; - ret.name = lookup.node.name; - ret.isRoot = lookup.path === '/'; - } catch (e) { - ret.error = e.errno; - } - return ret; - }, - createPath: (parent, path, canRead, canWrite) => { - parent = typeof parent == 'string' ? parent : FS.getPath(parent); - var parts = path.split('/').reverse(); - while (parts.length) { - var part = parts.pop(); - if (!part) continue; - var current = PATH.join2(parent, part); - try { - FS.mkdir(current); - } catch (e) {} - parent = current; - } - return current; - }, - createFile: (parent, name, properties, canRead, canWrite) => { - var path = PATH.join2( - typeof parent == 'string' ? parent : FS.getPath(parent), - name, - ); - var mode = FS.getMode(canRead, canWrite); - return FS.create(path, mode); - }, - createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { - var path = name; - if (parent) { - parent = typeof parent == 'string' ? parent : FS.getPath(parent); - path = name ? PATH.join2(parent, name) : parent; - } - var mode = FS.getMode(canRead, canWrite); - var node = FS.create(path, mode); - if (data) { - if (typeof data == 'string') { - var arr = new Array(data.length); - for (var i = 0, len = data.length; i < len; ++i) - arr[i] = data.charCodeAt(i); - data = arr; - } - - FS.chmod(node, mode | 146); - var stream = FS.open(node, 577); - FS.write(stream, data, 0, data.length, 0, canOwn); - FS.close(stream); - FS.chmod(node, mode); - } - return node; - }, - createDevice: (parent, name, input, output) => { - var path = PATH.join2( - typeof parent == 'string' ? parent : FS.getPath(parent), - name, - ); - var mode = FS.getMode(!!input, !!output); - if (!FS.createDevice.major) FS.createDevice.major = 64; - var dev = FS.makedev(FS.createDevice.major++, 0); - - FS.registerDevice(dev, { - open: (stream) => { - stream.seekable = false; - }, - close: (stream) => { - if (output && output.buffer && output.buffer.length) { - output(10); - } - }, - read: (stream, buffer, offset, length, pos) => { - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = input(); - } catch (e) { - throw new FS.ErrnoError(29); - } - if (result === undefined && bytesRead === 0) { - throw new FS.ErrnoError(6); - } - if (result === null || result === undefined) break; - bytesRead++; - buffer[offset + i] = result; - } - if (bytesRead) { - stream.node.timestamp = Date.now(); - } - return bytesRead; - }, - write: (stream, buffer, offset, length, pos) => { - for (var i = 0; i < length; i++) { - try { - output(buffer[offset + i]); - } catch (e) { - throw new FS.ErrnoError(29); - } - } - if (length) { - stream.node.timestamp = Date.now(); - } - return i; - }, - }); - return FS.mkdev(path, mode, dev); - }, - forceLoadFile: (obj) => { - if (obj.isDevice || obj.isFolder || obj.link || obj.contents) - return true; - if (typeof XMLHttpRequest != 'undefined') { - throw new Error( - 'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.', - ); - } else if (read_) { - try { - obj.contents = intArrayFromString(read_(obj.url), true); - obj.usedBytes = obj.contents.length; - } catch (e) { - throw new FS.ErrnoError(29); - } - } else { - throw new Error('Cannot load without read() or XMLHttpRequest.'); - } - }, - createLazyFile: (parent, name, url, canRead, canWrite) => { - function LazyUint8Array() { - this.lengthKnown = false; - this.chunks = []; - } - LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) { - if (idx > this.length - 1 || idx < 0) { - return undefined; - } - var chunkOffset = idx % this.chunkSize; - var chunkNum = (idx / this.chunkSize) | 0; - return this.getter(chunkNum)[chunkOffset]; - }; - LazyUint8Array.prototype.setDataGetter = - function LazyUint8Array_setDataGetter(getter) { - this.getter = getter; - }; - LazyUint8Array.prototype.cacheLength = - function LazyUint8Array_cacheLength() { - var xhr = new XMLHttpRequest(); - xhr.open('HEAD', url, false); - xhr.send(null); - if ( - !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) - ) - throw new Error( - "Couldn't load " + url + '. Status: ' + xhr.status, - ); - var datalength = Number(xhr.getResponseHeader('Content-length')); - var header; - var hasByteServing = - (header = xhr.getResponseHeader('Accept-Ranges')) && - header === 'bytes'; - var usesGzip = - (header = xhr.getResponseHeader('Content-Encoding')) && - header === 'gzip'; - - var chunkSize = 1024 * 1024; - - if (!hasByteServing) chunkSize = datalength; - - var doXHR = (from, to) => { - if (from > to) - throw new Error( - 'invalid range (' + - from + - ', ' + - to + - ') or no bytes requested!', - ); - if (to > datalength - 1) - throw new Error( - 'only ' + datalength + ' bytes available! programmer error!', - ); - - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - if (datalength !== chunkSize) - xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to); - - xhr.responseType = 'arraybuffer'; - if (xhr.overrideMimeType) { - xhr.overrideMimeType('text/plain; charset=x-user-defined'); - } - - xhr.send(null); - if ( - !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) - ) - throw new Error( - "Couldn't load " + url + '. Status: ' + xhr.status, - ); - if (xhr.response !== undefined) { - return new Uint8Array(xhr.response || []); - } - return intArrayFromString(xhr.responseText || ''); - }; - var lazyArray = this; - lazyArray.setDataGetter((chunkNum) => { - var start = chunkNum * chunkSize; - var end = (chunkNum + 1) * chunkSize - 1; - end = Math.min(end, datalength - 1); - if (typeof lazyArray.chunks[chunkNum] == 'undefined') { - lazyArray.chunks[chunkNum] = doXHR(start, end); - } - if (typeof lazyArray.chunks[chunkNum] == 'undefined') - throw new Error('doXHR failed!'); - return lazyArray.chunks[chunkNum]; - }); - - if (usesGzip || !datalength) { - chunkSize = datalength = 1; - datalength = this.getter(0).length; - chunkSize = datalength; - out( - 'LazyFiles on gzip forces download of the whole file when length is accessed', - ); - } - - this._length = datalength; - this._chunkSize = chunkSize; - this.lengthKnown = true; - }; - if (typeof XMLHttpRequest != 'undefined') { - if (!ENVIRONMENT_IS_WORKER) - throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; - var lazyArray = new LazyUint8Array(); - Object.defineProperties(lazyArray, { - length: { - get: function () { - if (!this.lengthKnown) { - this.cacheLength(); - } - return this._length; - }, - }, - chunkSize: { - get: function () { - if (!this.lengthKnown) { - this.cacheLength(); - } - return this._chunkSize; - }, - }, - }); - - var properties = { isDevice: false, contents: lazyArray }; - } else { - var properties = { isDevice: false, url: url }; - } - - var node = FS.createFile(parent, name, properties, canRead, canWrite); - - if (properties.contents) { - node.contents = properties.contents; - } else if (properties.url) { - node.contents = null; - node.url = properties.url; - } - - Object.defineProperties(node, { - usedBytes: { - get: function () { - return this.contents.length; - }, - }, - }); - - var stream_ops = {}; - var keys = Object.keys(node.stream_ops); - keys.forEach((key) => { - var fn = node.stream_ops[key]; - stream_ops[key] = function forceLoadLazyFile() { - FS.forceLoadFile(node); - return fn.apply(null, arguments); - }; - }); - function writeChunks(stream, buffer, offset, length, position) { - var contents = stream.node.contents; - if (position >= contents.length) return 0; - var size = Math.min(contents.length - position, length); - if (contents.slice) { - for (var i = 0; i < size; i++) { - buffer[offset + i] = contents[position + i]; - } - } else { - for (var i = 0; i < size; i++) { - buffer[offset + i] = contents.get(position + i); - } - } - return size; - } - - stream_ops.read = (stream, buffer, offset, length, position) => { - FS.forceLoadFile(node); - return writeChunks(stream, buffer, offset, length, position); - }; - - stream_ops.mmap = (stream, length, position, prot, flags) => { - FS.forceLoadFile(node); - var ptr = mmapAlloc(length); - if (!ptr) { - throw new FS.ErrnoError(48); - } - writeChunks(stream, HEAP8, ptr, length, position); - return { ptr: ptr, allocated: true }; - }; - node.stream_ops = stream_ops; - return node; - }, - createPreloadedFile: ( - parent, - name, - url, - canRead, - canWrite, - onload, - onerror, - dontCreateFile, - canOwn, - preFinish, - ) => { - var fullname = name - ? PATH_FS.resolve(PATH.join2(parent, name)) - : parent; - function processData(byteArray) { - function finish(byteArray) { - if (preFinish) preFinish(); - if (!dontCreateFile) { - FS.createDataFile( - parent, - name, - byteArray, - canRead, - canWrite, - canOwn, - ); - } - if (onload) onload(); - removeRunDependency(); - } - if ( - Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => { - if (onerror) onerror(); - removeRunDependency(); - }) - ) { - return; - } - finish(byteArray); - } - addRunDependency(); - if (typeof url == 'string') { - asyncLoad(url, (byteArray) => processData(byteArray), onerror); - } else { - processData(url); - } - }, - indexedDB: () => { - return ( - window.indexedDB || - window.mozIndexedDB || - window.webkitIndexedDB || - window.msIndexedDB - ); - }, - DB_NAME: () => { - return 'EM_FS_' + window.location.pathname; - }, - DB_VERSION: 20, - DB_STORE_NAME: 'FILE_DATA', - saveFilesToDB: (paths, onload, onerror) => { - onload = onload || (() => {}); - onerror = onerror || (() => {}); - var indexedDB = FS.indexedDB(); - try { - var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); - } catch (e) { - return onerror(e); - } - openRequest.onupgradeneeded = () => { - out('creating db'); - var db = openRequest.result; - db.createObjectStore(FS.DB_STORE_NAME); - }; - openRequest.onsuccess = () => { - var db = openRequest.result; - var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite'); - var files = transaction.objectStore(FS.DB_STORE_NAME); - var ok = 0, - fail = 0, - total = paths.length; - function finish() { - if (fail == 0) onload(); - else onerror(); - } - paths.forEach((path) => { - var putRequest = files.put( - FS.analyzePath(path).object.contents, - path, - ); - putRequest.onsuccess = () => { - ok++; - if (ok + fail == total) finish(); - }; - putRequest.onerror = () => { - fail++; - if (ok + fail == total) finish(); - }; - }); - transaction.onerror = onerror; - }; - openRequest.onerror = onerror; - }, - loadFilesFromDB: (paths, onload, onerror) => { - onload = onload || (() => {}); - onerror = onerror || (() => {}); - var indexedDB = FS.indexedDB(); - try { - var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); - } catch (e) { - return onerror(e); - } - openRequest.onupgradeneeded = onerror; - openRequest.onsuccess = () => { - var db = openRequest.result; - try { - var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly'); - } catch (e) { - onerror(e); - return; - } - var files = transaction.objectStore(FS.DB_STORE_NAME); - var ok = 0, - fail = 0, - total = paths.length; - function finish() { - if (fail == 0) onload(); - else onerror(); - } - paths.forEach((path) => { - var getRequest = files.get(path); - getRequest.onsuccess = () => { - if (FS.analyzePath(path).exists) { - FS.unlink(path); - } - FS.createDataFile( - PATH.dirname(path), - PATH.basename(path), - getRequest.result, - true, - true, - true, - ); - ok++; - if (ok + fail == total) finish(); - }; - getRequest.onerror = () => { - fail++; - if (ok + fail == total) finish(); - }; - }); - transaction.onerror = onerror; - }; - openRequest.onerror = onerror; - }, - }; - var SYSCALLS = { - DEFAULT_POLLMASK: 5, - calculateAt: function (dirfd, path, allowEmpty) { - if (PATH.isAbs(path)) { - return path; - } - - var dir; - if (dirfd === -100) { - dir = FS.cwd(); - } else { - var dirstream = SYSCALLS.getStreamFromFD(dirfd); - dir = dirstream.path; - } - if (path.length == 0) { - if (!allowEmpty) { - throw new FS.ErrnoError(44); - } - return dir; - } - return PATH.join2(dir, path); - }, - doStat: function (func, path, buf) { - try { - var stat = func(path); - } catch (e) { - if ( - e && - e.node && - PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node)) - ) { - return -54; - } - throw e; - } - HEAP32[buf >> 2] = stat.dev; - HEAP32[(buf + 8) >> 2] = stat.ino; - HEAP32[(buf + 12) >> 2] = stat.mode; - HEAPU32[(buf + 16) >> 2] = stat.nlink; - HEAP32[(buf + 20) >> 2] = stat.uid; - HEAP32[(buf + 24) >> 2] = stat.gid; - HEAP32[(buf + 28) >> 2] = stat.rdev; - (tempI64 = [ - stat.size >>> 0, - ((tempDouble = stat.size), - +Math.abs(tempDouble) >= 1.0 - ? tempDouble > 0.0 - ? (Math.min( - +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, - ) | - 0) >>> - 0 - : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, - ) >>> 0 - : 0), - ]), - (HEAP32[(buf + 40) >> 2] = tempI64[0]), - (HEAP32[(buf + 44) >> 2] = tempI64[1]); - HEAP32[(buf + 48) >> 2] = 4096; - HEAP32[(buf + 52) >> 2] = stat.blocks; - var atime = stat.atime.getTime(); - var mtime = stat.mtime.getTime(); - var ctime = stat.ctime.getTime(); - (tempI64 = [ - Math.floor(atime / 1000) >>> 0, - ((tempDouble = Math.floor(atime / 1000)), - +Math.abs(tempDouble) >= 1.0 - ? tempDouble > 0.0 - ? (Math.min( - +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, - ) | - 0) >>> - 0 - : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, - ) >>> 0 - : 0), - ]), - (HEAP32[(buf + 56) >> 2] = tempI64[0]), - (HEAP32[(buf + 60) >> 2] = tempI64[1]); - HEAPU32[(buf + 64) >> 2] = (atime % 1000) * 1000; - (tempI64 = [ - Math.floor(mtime / 1000) >>> 0, - ((tempDouble = Math.floor(mtime / 1000)), - +Math.abs(tempDouble) >= 1.0 - ? tempDouble > 0.0 - ? (Math.min( - +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, - ) | - 0) >>> - 0 - : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, - ) >>> 0 - : 0), - ]), - (HEAP32[(buf + 72) >> 2] = tempI64[0]), - (HEAP32[(buf + 76) >> 2] = tempI64[1]); - HEAPU32[(buf + 80) >> 2] = (mtime % 1000) * 1000; - (tempI64 = [ - Math.floor(ctime / 1000) >>> 0, - ((tempDouble = Math.floor(ctime / 1000)), - +Math.abs(tempDouble) >= 1.0 - ? tempDouble > 0.0 - ? (Math.min( - +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, - ) | - 0) >>> - 0 - : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, - ) >>> 0 - : 0), - ]), - (HEAP32[(buf + 88) >> 2] = tempI64[0]), - (HEAP32[(buf + 92) >> 2] = tempI64[1]); - HEAPU32[(buf + 96) >> 2] = (ctime % 1000) * 1000; - (tempI64 = [ - stat.ino >>> 0, - ((tempDouble = stat.ino), - +Math.abs(tempDouble) >= 1.0 - ? tempDouble > 0.0 - ? (Math.min( - +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, - ) | - 0) >>> - 0 - : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, - ) >>> 0 - : 0), - ]), - (HEAP32[(buf + 104) >> 2] = tempI64[0]), - (HEAP32[(buf + 108) >> 2] = tempI64[1]); - return 0; - }, - doMsync: function (addr, stream, len, flags, offset) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (flags & 2) { - return 0; - } - var buffer = HEAPU8.slice(addr, addr + len); - FS.msync(stream, buffer, offset, len, flags); - }, - varargs: undefined, - get: function () { - SYSCALLS.varargs += 4; - var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]; - return ret; - }, - getStr: function (ptr) { - var ret = UTF8ToString(ptr); - return ret; - }, - getStreamFromFD: function (fd) { - var stream = FS.getStream(fd); - if (!stream) throw new FS.ErrnoError(8); - return stream; - }, - }; - function ___syscall_chmod(path, mode) { - try { - path = SYSCALLS.getStr(path); - FS.chmod(path, mode); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_faccessat(dirfd, path, amode, flags) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - if (amode & ~7) { - return -28; - } - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - if (!node) { - return -44; - } - var perms = ''; - if (amode & 4) perms += 'r'; - if (amode & 2) perms += 'w'; - if (amode & 1) perms += 'x'; - if (perms && FS.nodePermissions(node, perms)) { - return -2; - } - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_fchmod(fd, mode) { - try { - FS.fchmod(fd, mode); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_fchown32(fd, owner, group) { - try { - FS.fchown(fd, owner, group); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function setErrNo(value) { - HEAP32[___errno_location() >> 2] = value; - return value; - } - - function ___syscall_fcntl64(fd, cmd, varargs) { - SYSCALLS.varargs = varargs; - try { - var stream = SYSCALLS.getStreamFromFD(fd); - switch (cmd) { - case 0: { - var arg = SYSCALLS.get(); - if (arg < 0) { - return -28; - } - var newStream; - newStream = FS.createStream(stream, arg); - return newStream.fd; - } - case 1: - case 2: - return 0; - case 3: - return stream.flags; - case 4: { - var arg = SYSCALLS.get(); - stream.flags |= arg; - return 0; - } - case 5: { - var arg = SYSCALLS.get(); - var offset = 0; - - HEAP16[(arg + offset) >> 1] = 2; - return 0; - } - case 6: - case 7: - return 0; - case 16: - case 8: - return -28; - case 9: - setErrNo(28); - return -1; - default: { - return -28; - } - } - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_fstat64(fd, buf) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - return SYSCALLS.doStat(FS.stat, stream.path, buf); - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - var MAX_INT53 = 9007199254740992; - - var MIN_INT53 = -9007199254740992; - function bigintToI53Checked(num) { - return num < MIN_INT53 || num > MAX_INT53 ? NaN : Number(num); - } - - function ___syscall_ftruncate64(fd, length) { - try { - length = bigintToI53Checked(length); - if (isNaN(length)) return -61; - FS.ftruncate(fd, length); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_getcwd(buf, size) { - try { - if (size === 0) return -28; - var cwd = FS.cwd(); - var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; - if (size < cwdLengthInBytes) return -68; - stringToUTF8(cwd, buf, size); - return cwdLengthInBytes; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_ioctl(fd, op, varargs) { - SYSCALLS.varargs = varargs; - try { - var stream = SYSCALLS.getStreamFromFD(fd); - switch (op) { - case 21509: - case 21505: { - if (!stream.tty) return -59; - return 0; - } - case 21510: - case 21511: - case 21512: - case 21506: - case 21507: - case 21508: { - if (!stream.tty) return -59; - return 0; - } - case 21519: { - if (!stream.tty) return -59; - var argp = SYSCALLS.get(); - HEAP32[argp >> 2] = 0; - return 0; - } - case 21520: { - if (!stream.tty) return -59; - return -28; - } - case 21531: { - var argp = SYSCALLS.get(); - return FS.ioctl(stream, op, argp); - } - case 21523: { - if (!stream.tty) return -59; - return 0; - } - case 21524: { - if (!stream.tty) return -59; - return 0; - } - default: - return -28; - } - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_lstat64(path, buf) { - try { - path = SYSCALLS.getStr(path); - return SYSCALLS.doStat(FS.lstat, path, buf); - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_mkdirat(dirfd, path, mode) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - - path = PATH.normalize(path); - if (path[path.length - 1] === '/') - path = path.substr(0, path.length - 1); - FS.mkdir(path, mode, 0); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_newfstatat(dirfd, path, buf, flags) { - try { - path = SYSCALLS.getStr(path); - var nofollow = flags & 256; - var allowEmpty = flags & 4096; - flags = flags & ~6400; - path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); - return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_openat(dirfd, path, flags, varargs) { - SYSCALLS.varargs = varargs; - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - var mode = varargs ? SYSCALLS.get() : 0; - return FS.open(path, flags, mode).fd; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_readlinkat(dirfd, path, buf, bufsize) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - if (bufsize <= 0) return -28; - var ret = FS.readlink(path); - - var len = Math.min(bufsize, lengthBytesUTF8(ret)); - var endChar = HEAP8[buf + len]; - stringToUTF8(ret, buf, bufsize + 1); - - HEAP8[buf + len] = endChar; - return len; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_rmdir(path) { - try { - path = SYSCALLS.getStr(path); - FS.rmdir(path); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_stat64(path, buf) { - try { - path = SYSCALLS.getStr(path); - return SYSCALLS.doStat(FS.stat, path, buf); - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function ___syscall_unlinkat(dirfd, path, flags) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - if (flags === 0) { - FS.unlink(path); - } else if (flags === 512) { - FS.rmdir(path); - } else { - abort('Invalid flags passed to unlinkat'); - } - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function readI53FromI64(ptr) { - return HEAPU32[ptr >> 2] + HEAP32[(ptr + 4) >> 2] * 4294967296; - } - - function ___syscall_utimensat(dirfd, path, times, flags) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path, true); - if (!times) { - var atime = Date.now(); - var mtime = atime; - } else { - var seconds = readI53FromI64(times); - var nanoseconds = HEAP32[(times + 8) >> 2]; - atime = seconds * 1000 + nanoseconds / (1000 * 1000); - times += 16; - seconds = readI53FromI64(times); - nanoseconds = HEAP32[(times + 8) >> 2]; - mtime = seconds * 1000 + nanoseconds / (1000 * 1000); - } - FS.utime(path, atime, mtime); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - var nowIsMonotonic = true; - function __emscripten_get_now_is_monotonic() { - return nowIsMonotonic; - } - - function __isLeapYear(year) { - return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); - } - - var __MONTH_DAYS_LEAP_CUMULATIVE = [ - 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, - ]; - - var __MONTH_DAYS_REGULAR_CUMULATIVE = [ - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, - ]; - function __yday_from_date(date) { - var isLeapYear = __isLeapYear(date.getFullYear()); - var monthDaysCumulative = isLeapYear - ? __MONTH_DAYS_LEAP_CUMULATIVE - : __MONTH_DAYS_REGULAR_CUMULATIVE; - var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; - - return yday; - } - function __localtime_js(time, tmPtr) { - var date = new Date(readI53FromI64(time) * 1000); - HEAP32[tmPtr >> 2] = date.getSeconds(); - HEAP32[(tmPtr + 4) >> 2] = date.getMinutes(); - HEAP32[(tmPtr + 8) >> 2] = date.getHours(); - HEAP32[(tmPtr + 12) >> 2] = date.getDate(); - HEAP32[(tmPtr + 16) >> 2] = date.getMonth(); - HEAP32[(tmPtr + 20) >> 2] = date.getFullYear() - 1900; - HEAP32[(tmPtr + 24) >> 2] = date.getDay(); - - var yday = __yday_from_date(date) | 0; - HEAP32[(tmPtr + 28) >> 2] = yday; - HEAP32[(tmPtr + 36) >> 2] = -(date.getTimezoneOffset() * 60); - - var start = new Date(date.getFullYear(), 0, 1); - var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); - var winterOffset = start.getTimezoneOffset(); - var dst = - (summerOffset != winterOffset && - date.getTimezoneOffset() == Math.min(winterOffset, summerOffset)) | 0; - HEAP32[(tmPtr + 32) >> 2] = dst; - } - - function __mmap_js(len, prot, flags, fd, off, allocated, addr) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var res = FS.mmap(stream, len, off, prot, flags); - var ptr = res.ptr; - HEAP32[allocated >> 2] = res.allocated; - HEAPU32[addr >> 2] = ptr; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function __munmap_js(addr, len, prot, flags, fd, offset) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - if (prot & 2) { - SYSCALLS.doMsync(addr, stream, len, flags, offset); - } - FS.munmap(stream); - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return -e.errno; - } - } - - function allocateUTF8(str) { - var size = lengthBytesUTF8(str) + 1; - var ret = _malloc(size); - if (ret) stringToUTF8Array(str, HEAP8, ret, size); - return ret; - } - function __tzset_js(timezone, daylight, tzname) { - var currentYear = new Date().getFullYear(); - var winter = new Date(currentYear, 0, 1); - var summer = new Date(currentYear, 6, 1); - var winterOffset = winter.getTimezoneOffset(); - var summerOffset = summer.getTimezoneOffset(); - - var stdTimezoneOffset = Math.max(winterOffset, summerOffset); - - HEAPU32[timezone >> 2] = stdTimezoneOffset * 60; - - HEAP32[daylight >> 2] = Number(winterOffset != summerOffset); - - function extractZone(date) { - var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/); - return match ? match[1] : 'GMT'; - } - var winterName = extractZone(winter); - var summerName = extractZone(summer); - var winterNamePtr = allocateUTF8(winterName); - var summerNamePtr = allocateUTF8(summerName); - if (summerOffset < winterOffset) { - HEAPU32[tzname >> 2] = winterNamePtr; - HEAPU32[(tzname + 4) >> 2] = summerNamePtr; - } else { - HEAPU32[tzname >> 2] = summerNamePtr; - HEAPU32[(tzname + 4) >> 2] = winterNamePtr; - } - } - - function _emscripten_date_now() { - return Date.now(); - } - - var _emscripten_get_now; - _emscripten_get_now = () => performance.now(); - function getHeapMax() { - return 2147483648; - } - - function emscripten_realloc_buffer(size) { - var b = wasmMemory.buffer; - try { - wasmMemory.grow((size - b.byteLength + 65535) >>> 16); - updateMemoryViews(); - return 1; - } catch (e) {} - } - function _emscripten_resize_heap(requestedSize) { - var oldSize = HEAPU8.length; - requestedSize = requestedSize >>> 0; - - var maxHeapSize = getHeapMax(); - if (requestedSize > maxHeapSize) { - return false; - } - - let alignUp = (x, multiple) => - x + ((multiple - (x % multiple)) % multiple); - - for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { - var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); - - overGrownHeapSize = Math.min( - overGrownHeapSize, - requestedSize + 100663296, - ); - - var newSize = Math.min( - maxHeapSize, - alignUp(Math.max(requestedSize, overGrownHeapSize), 65536), - ); - - var replacement = emscripten_realloc_buffer(newSize); - if (replacement) { - return true; - } - } - return false; - } - - var ENV = {}; - - function getExecutableName() { - return thisProgram || './this.program'; - } - function getEnvStrings() { - if (!getEnvStrings.strings) { - var lang = - ( - (typeof navigator == 'object' && - navigator.languages && - navigator.languages[0]) || - 'C' - ).replace('-', '_') + '.UTF-8'; - var env = { - USER: 'web_user', - LOGNAME: 'web_user', - PATH: '/', - PWD: '/', - HOME: '/home/web_user', - LANG: lang, - _: getExecutableName(), - }; - - for (var x in ENV) { - if (ENV[x] === undefined) delete env[x]; - else env[x] = ENV[x]; - } - var strings = []; - for (var x in env) { - strings.push(x + '=' + env[x]); - } - getEnvStrings.strings = strings; - } - return getEnvStrings.strings; - } - - function writeAsciiToMemory(str, buffer, dontAddNull) { - for (var i = 0; i < str.length; ++i) { - HEAP8[buffer++ >> 0] = str.charCodeAt(i); - } - - HEAP8[buffer >> 0] = 0; - } - - function _environ_get(__environ, environ_buf) { - var bufSize = 0; - getEnvStrings().forEach(function (string, i) { - var ptr = environ_buf + bufSize; - HEAPU32[(__environ + i * 4) >> 2] = ptr; - writeAsciiToMemory(string, ptr); - bufSize += string.length + 1; - }); - return 0; - } - - function _environ_sizes_get(penviron_count, penviron_buf_size) { - var strings = getEnvStrings(); - HEAPU32[penviron_count >> 2] = strings.length; - var bufSize = 0; - strings.forEach(function (string) { - bufSize += string.length + 1; - }); - HEAPU32[penviron_buf_size >> 2] = bufSize; - return 0; - } - - function _fd_close(fd) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - FS.close(stream); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return e.errno; - } - } - - function _fd_fdstat_get(fd, pbuf) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - - var type = stream.tty - ? 2 - : FS.isDir(stream.mode) - ? 3 - : FS.isLink(stream.mode) - ? 7 - : 4; - HEAP8[pbuf >> 0] = type; - - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return e.errno; - } - } - - function doReadv(stream, iov, iovcnt, offset) { - var ret = 0; - for (var i = 0; i < iovcnt; i++) { - var ptr = HEAPU32[iov >> 2]; - var len = HEAPU32[(iov + 4) >> 2]; - iov += 8; - var curr = FS.read(stream, HEAP8, ptr, len, offset); - if (curr < 0) return -1; - ret += curr; - if (curr < len) break; - } - return ret; - } - - function _fd_read(fd, iov, iovcnt, pnum) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var num = doReadv(stream, iov, iovcnt); - HEAPU32[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return e.errno; - } - } - - function _fd_seek(fd, offset, whence, newOffset) { - try { - offset = bigintToI53Checked(offset); - if (isNaN(offset)) return 61; - var stream = SYSCALLS.getStreamFromFD(fd); - FS.llseek(stream, offset, whence); - (tempI64 = [ - stream.position >>> 0, - ((tempDouble = stream.position), - +Math.abs(tempDouble) >= 1.0 - ? tempDouble > 0.0 - ? (Math.min( - +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, - ) | - 0) >>> - 0 - : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, - ) >>> 0 - : 0), - ]), - (HEAP32[newOffset >> 2] = tempI64[0]), - (HEAP32[(newOffset + 4) >> 2] = tempI64[1]); - if (stream.getdents && offset === 0 && whence === 0) - stream.getdents = null; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return e.errno; - } - } - - function _fd_sync(fd) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - if (stream.stream_ops && stream.stream_ops.fsync) { - return stream.stream_ops.fsync(stream); - } - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return e.errno; - } - } - - function doWritev(stream, iov, iovcnt, offset) { - var ret = 0; - for (var i = 0; i < iovcnt; i++) { - var ptr = HEAPU32[iov >> 2]; - var len = HEAPU32[(iov + 4) >> 2]; - iov += 8; - var curr = FS.write(stream, HEAP8, ptr, len, offset); - if (curr < 0) return -1; - ret += curr; - } - return ret; - } - - function _fd_write(fd, iov, iovcnt, pnum) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var num = doWritev(stream, iov, iovcnt); - HEAPU32[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; - return e.errno; - } - } - - var FSNode = function (parent, name, mode, rdev) { - if (!parent) { - parent = this; - } - this.parent = parent; - this.mount = parent.mount; - this.mounted = null; - this.id = FS.nextInode++; - this.name = name; - this.mode = mode; - this.node_ops = {}; - this.stream_ops = {}; - this.rdev = rdev; - }; - var readMode = 292 | 73; - var writeMode = 146; - Object.defineProperties(FSNode.prototype, { - read: { - get: function () { - return (this.mode & readMode) === readMode; - }, - set: function (val) { - val ? (this.mode |= readMode) : (this.mode &= ~readMode); - }, - }, - write: { - get: function () { - return (this.mode & writeMode) === writeMode; - }, - set: function (val) { - val ? (this.mode |= writeMode) : (this.mode &= ~writeMode); - }, - }, - isFolder: { - get: function () { - return FS.isDir(this.mode); - }, - }, - isDevice: { - get: function () { - return FS.isChrdev(this.mode); - }, - }, - }); - FS.FSNode = FSNode; - FS.staticInit(); - - var asmLibraryArg = { - __syscall_chmod: ___syscall_chmod, - __syscall_faccessat: ___syscall_faccessat, - __syscall_fchmod: ___syscall_fchmod, - __syscall_fchown32: ___syscall_fchown32, - __syscall_fcntl64: ___syscall_fcntl64, - __syscall_fstat64: ___syscall_fstat64, - __syscall_ftruncate64: ___syscall_ftruncate64, - __syscall_getcwd: ___syscall_getcwd, - __syscall_ioctl: ___syscall_ioctl, - __syscall_lstat64: ___syscall_lstat64, - __syscall_mkdirat: ___syscall_mkdirat, - __syscall_newfstatat: ___syscall_newfstatat, - __syscall_openat: ___syscall_openat, - __syscall_readlinkat: ___syscall_readlinkat, - __syscall_rmdir: ___syscall_rmdir, - __syscall_stat64: ___syscall_stat64, - __syscall_unlinkat: ___syscall_unlinkat, - __syscall_utimensat: ___syscall_utimensat, - _emscripten_get_now_is_monotonic: __emscripten_get_now_is_monotonic, - _localtime_js: __localtime_js, - _mmap_js: __mmap_js, - _munmap_js: __munmap_js, - _tzset_js: __tzset_js, - emscripten_date_now: _emscripten_date_now, - emscripten_get_now: _emscripten_get_now, - emscripten_resize_heap: _emscripten_resize_heap, - environ_get: _environ_get, - environ_sizes_get: _environ_sizes_get, - fd_close: _fd_close, - fd_fdstat_get: _fd_fdstat_get, - fd_read: _fd_read, - fd_seek: _fd_seek, - fd_sync: _fd_sync, - fd_write: _fd_write, - memory: wasmMemory, - }; - createWasm(); - - (Module['___wasm_call_ctors'] = function () { - return (Module['___wasm_call_ctors'] = - Module['asm']['__wasm_call_ctors']).apply(null, arguments); - }); - - (Module['_sqlite3_status64'] = function () { - return (Module['_sqlite3_status64'] = - Module['asm']['sqlite3_status64']).apply(null, arguments); - }); - - (Module['_sqlite3_status'] = function () { - return (Module['_sqlite3_status'] = - Module['asm']['sqlite3_status']).apply(null, arguments); - }); - - (Module['_sqlite3_db_status'] = function () { - return (Module['_sqlite3_db_status'] = - Module['asm']['sqlite3_db_status']).apply(null, arguments); - }); - - (Module['_sqlite3_msize'] = function () { - return (Module['_sqlite3_msize'] = - Module['asm']['sqlite3_msize']).apply(null, arguments); - }); - - (Module['_sqlite3_vfs_find'] = function () { - return (Module['_sqlite3_vfs_find'] = - Module['asm']['sqlite3_vfs_find']).apply(null, arguments); - }); - - (Module['_sqlite3_initialize'] = function () { - return (Module['_sqlite3_initialize'] = - Module['asm']['sqlite3_initialize']).apply(null, arguments); - }); - - (Module['_sqlite3_malloc'] = function () { - return (Module['_sqlite3_malloc'] = - Module['asm']['sqlite3_malloc']).apply(null, arguments); - }); - - (Module['_sqlite3_free'] = function () { - return (Module['_sqlite3_free'] = - Module['asm']['sqlite3_free']).apply(null, arguments); - }); - - (Module['_sqlite3_vfs_register'] = function () { - return (Module['_sqlite3_vfs_register'] = - Module['asm']['sqlite3_vfs_register']).apply(null, arguments); - }); - - (Module['_sqlite3_vfs_unregister'] = - function () { - return (Module['_sqlite3_vfs_unregister'] = - Module['asm']['sqlite3_vfs_unregister']).apply(null, arguments); - }); - - (Module['_sqlite3_malloc64'] = function () { - return (Module['_sqlite3_malloc64'] = - Module['asm']['sqlite3_malloc64']).apply(null, arguments); - }); - - (Module['_sqlite3_realloc'] = function () { - return (Module['_sqlite3_realloc'] = - Module['asm']['sqlite3_realloc']).apply(null, arguments); - }); - - (Module['_sqlite3_realloc64'] = function () { - return (Module['_sqlite3_realloc64'] = - Module['asm']['sqlite3_realloc64']).apply(null, arguments); - }); - - (Module['_sqlite3_value_text'] = function () { - return (Module['_sqlite3_value_text'] = - Module['asm']['sqlite3_value_text']).apply(null, arguments); - }); - - (Module['_sqlite3_randomness'] = function () { - return (Module['_sqlite3_randomness'] = - Module['asm']['sqlite3_randomness']).apply(null, arguments); - }); - - (Module['_sqlite3_stricmp'] = function () { - return (Module['_sqlite3_stricmp'] = - Module['asm']['sqlite3_stricmp']).apply(null, arguments); - }); - - (Module['_sqlite3_strnicmp'] = function () { - return (Module['_sqlite3_strnicmp'] = - Module['asm']['sqlite3_strnicmp']).apply(null, arguments); - }); - - (Module['_sqlite3_uri_parameter'] = - function () { - return (Module['_sqlite3_uri_parameter'] = - Module['asm']['sqlite3_uri_parameter']).apply(null, arguments); - }); - - var ___errno_location = (Module['___errno_location'] = function () { - return (___errno_location = Module['___errno_location'] = - Module['asm']['__errno_location']).apply(null, arguments); - }); - - (Module['_sqlite3_uri_boolean'] = function () { - return (Module['_sqlite3_uri_boolean'] = - Module['asm']['sqlite3_uri_boolean']).apply(null, arguments); - }); - - (Module['_sqlite3_serialize'] = function () { - return (Module['_sqlite3_serialize'] = - Module['asm']['sqlite3_serialize']).apply(null, arguments); - }); - - (Module['_sqlite3_prepare_v2'] = function () { - return (Module['_sqlite3_prepare_v2'] = - Module['asm']['sqlite3_prepare_v2']).apply(null, arguments); - }); - - (Module['_sqlite3_step'] = function () { - return (Module['_sqlite3_step'] = - Module['asm']['sqlite3_step']).apply(null, arguments); - }); - - (Module['_sqlite3_column_int64'] = function () { - return (Module['_sqlite3_column_int64'] = - Module['asm']['sqlite3_column_int64']).apply(null, arguments); - }); - - (Module['_sqlite3_reset'] = function () { - return (Module['_sqlite3_reset'] = - Module['asm']['sqlite3_reset']).apply(null, arguments); - }); - - (Module['_sqlite3_exec'] = function () { - return (Module['_sqlite3_exec'] = - Module['asm']['sqlite3_exec']).apply(null, arguments); - }); - - (Module['_sqlite3_column_int'] = function () { - return (Module['_sqlite3_column_int'] = - Module['asm']['sqlite3_column_int']).apply(null, arguments); - }); - - (Module['_sqlite3_finalize'] = function () { - return (Module['_sqlite3_finalize'] = - Module['asm']['sqlite3_finalize']).apply(null, arguments); - }); - - (Module['_sqlite3_file_control'] = function () { - return (Module['_sqlite3_file_control'] = - Module['asm']['sqlite3_file_control']).apply(null, arguments); - }); - - (Module['_sqlite3_column_name'] = function () { - return (Module['_sqlite3_column_name'] = - Module['asm']['sqlite3_column_name']).apply(null, arguments); - }); - - (Module['_sqlite3_column_text'] = function () { - return (Module['_sqlite3_column_text'] = - Module['asm']['sqlite3_column_text']).apply(null, arguments); - }); - - (Module['_sqlite3_column_type'] = function () { - return (Module['_sqlite3_column_type'] = - Module['asm']['sqlite3_column_type']).apply(null, arguments); - }); - - (Module['_sqlite3_errmsg'] = function () { - return (Module['_sqlite3_errmsg'] = - Module['asm']['sqlite3_errmsg']).apply(null, arguments); - }); - - (Module['_sqlite3_deserialize'] = function () { - return (Module['_sqlite3_deserialize'] = - Module['asm']['sqlite3_deserialize']).apply(null, arguments); - }); - - (Module['_sqlite3_clear_bindings'] = - function () { - return (Module['_sqlite3_clear_bindings'] = - Module['asm']['sqlite3_clear_bindings']).apply(null, arguments); - }); - - (Module['_sqlite3_value_blob'] = function () { - return (Module['_sqlite3_value_blob'] = - Module['asm']['sqlite3_value_blob']).apply(null, arguments); - }); - - (Module['_sqlite3_value_bytes'] = function () { - return (Module['_sqlite3_value_bytes'] = - Module['asm']['sqlite3_value_bytes']).apply(null, arguments); - }); - - (Module['_sqlite3_value_double'] = function () { - return (Module['_sqlite3_value_double'] = - Module['asm']['sqlite3_value_double']).apply(null, arguments); - }); - - (Module['_sqlite3_value_int'] = function () { - return (Module['_sqlite3_value_int'] = - Module['asm']['sqlite3_value_int']).apply(null, arguments); - }); - - (Module['_sqlite3_value_int64'] = function () { - return (Module['_sqlite3_value_int64'] = - Module['asm']['sqlite3_value_int64']).apply(null, arguments); - }); - - (Module['_sqlite3_value_subtype'] = - function () { - return (Module['_sqlite3_value_subtype'] = - Module['asm']['sqlite3_value_subtype']).apply(null, arguments); - }); - - (Module['_sqlite3_value_pointer'] = - function () { - return (Module['_sqlite3_value_pointer'] = - Module['asm']['sqlite3_value_pointer']).apply(null, arguments); - }); - - (Module['_sqlite3_value_type'] = function () { - return (Module['_sqlite3_value_type'] = - Module['asm']['sqlite3_value_type']).apply(null, arguments); - }); - - (Module['_sqlite3_value_nochange'] = - function () { - return (Module['_sqlite3_value_nochange'] = - Module['asm']['sqlite3_value_nochange']).apply(null, arguments); - }); - - (Module['_sqlite3_value_frombind'] = - function () { - return (Module['_sqlite3_value_frombind'] = - Module['asm']['sqlite3_value_frombind']).apply(null, arguments); - }); - - (Module['_sqlite3_value_dup'] = function () { - return (Module['_sqlite3_value_dup'] = - Module['asm']['sqlite3_value_dup']).apply(null, arguments); - }); - - (Module['_sqlite3_value_free'] = function () { - return (Module['_sqlite3_value_free'] = - Module['asm']['sqlite3_value_free']).apply(null, arguments); - }); - - (Module['_sqlite3_result_blob'] = function () { - return (Module['_sqlite3_result_blob'] = - Module['asm']['sqlite3_result_blob']).apply(null, arguments); - }); - - (Module['_sqlite3_result_error_toobig'] = - function () { - return (Module[ - '_sqlite3_result_error_toobig' - ] = - Module['asm']['sqlite3_result_error_toobig']).apply(null, arguments); - }); - - (Module['_sqlite3_result_error_nomem'] = - function () { - return (Module[ - '_sqlite3_result_error_nomem' - ] = - Module['asm']['sqlite3_result_error_nomem']).apply(null, arguments); - }); - - (Module['_sqlite3_result_double'] = - function () { - return (Module['_sqlite3_result_double'] = - Module['asm']['sqlite3_result_double']).apply(null, arguments); - }); - - (Module['_sqlite3_result_error'] = function () { - return (Module['_sqlite3_result_error'] = - Module['asm']['sqlite3_result_error']).apply(null, arguments); - }); - - (Module['_sqlite3_result_int'] = function () { - return (Module['_sqlite3_result_int'] = - Module['asm']['sqlite3_result_int']).apply(null, arguments); - }); - - (Module['_sqlite3_result_int64'] = function () { - return (Module['_sqlite3_result_int64'] = - Module['asm']['sqlite3_result_int64']).apply(null, arguments); - }); - - (Module['_sqlite3_result_null'] = function () { - return (Module['_sqlite3_result_null'] = - Module['asm']['sqlite3_result_null']).apply(null, arguments); - }); - - (Module['_sqlite3_result_pointer'] = - function () { - return (Module['_sqlite3_result_pointer'] = - Module['asm']['sqlite3_result_pointer']).apply(null, arguments); - }); - - (Module['_sqlite3_result_subtype'] = - function () { - return (Module['_sqlite3_result_subtype'] = - Module['asm']['sqlite3_result_subtype']).apply(null, arguments); - }); - - (Module['_sqlite3_result_text'] = function () { - return (Module['_sqlite3_result_text'] = - Module['asm']['sqlite3_result_text']).apply(null, arguments); - }); - - (Module['_sqlite3_result_zeroblob'] = - function () { - return (Module['_sqlite3_result_zeroblob'] = - Module['asm']['sqlite3_result_zeroblob']).apply(null, arguments); - }); - - (Module['_sqlite3_result_zeroblob64'] = - function () { - return (Module[ - '_sqlite3_result_zeroblob64' - ] = - Module['asm']['sqlite3_result_zeroblob64']).apply(null, arguments); - }); - - (Module['_sqlite3_result_error_code'] = - function () { - return (Module[ - '_sqlite3_result_error_code' - ] = - Module['asm']['sqlite3_result_error_code']).apply(null, arguments); - }); - - (Module['_sqlite3_user_data'] = function () { - return (Module['_sqlite3_user_data'] = - Module['asm']['sqlite3_user_data']).apply(null, arguments); - }); - - (Module['_sqlite3_context_db_handle'] = - function () { - return (Module[ - '_sqlite3_context_db_handle' - ] = - Module['asm']['sqlite3_context_db_handle']).apply(null, arguments); - }); - - (Module['_sqlite3_vtab_nochange'] = - function () { - return (Module['_sqlite3_vtab_nochange'] = - Module['asm']['sqlite3_vtab_nochange']).apply(null, arguments); - }); - - (Module['_sqlite3_vtab_in_first'] = - function () { - return (Module['_sqlite3_vtab_in_first'] = - Module['asm']['sqlite3_vtab_in_first']).apply(null, arguments); - }); - - (Module['_sqlite3_vtab_in_next'] = function () { - return (Module['_sqlite3_vtab_in_next'] = - Module['asm']['sqlite3_vtab_in_next']).apply(null, arguments); - }); - - (Module['_sqlite3_aggregate_context'] = - function () { - return (Module[ - '_sqlite3_aggregate_context' - ] = - Module['asm']['sqlite3_aggregate_context']).apply(null, arguments); - }); - - (Module['_sqlite3_get_auxdata'] = function () { - return (Module['_sqlite3_get_auxdata'] = - Module['asm']['sqlite3_get_auxdata']).apply(null, arguments); - }); - - (Module['_sqlite3_set_auxdata'] = function () { - return (Module['_sqlite3_set_auxdata'] = - Module['asm']['sqlite3_set_auxdata']).apply(null, arguments); - }); - - (Module['_sqlite3_column_count'] = function () { - return (Module['_sqlite3_column_count'] = - Module['asm']['sqlite3_column_count']).apply(null, arguments); - }); - - (Module['_sqlite3_data_count'] = function () { - return (Module['_sqlite3_data_count'] = - Module['asm']['sqlite3_data_count']).apply(null, arguments); - }); - - (Module['_sqlite3_column_blob'] = function () { - return (Module['_sqlite3_column_blob'] = - Module['asm']['sqlite3_column_blob']).apply(null, arguments); - }); - - (Module['_sqlite3_column_bytes'] = function () { - return (Module['_sqlite3_column_bytes'] = - Module['asm']['sqlite3_column_bytes']).apply(null, arguments); - }); - - (Module['_sqlite3_column_double'] = - function () { - return (Module['_sqlite3_column_double'] = - Module['asm']['sqlite3_column_double']).apply(null, arguments); - }); - - (Module['_sqlite3_column_value'] = function () { - return (Module['_sqlite3_column_value'] = - Module['asm']['sqlite3_column_value']).apply(null, arguments); - }); - - (Module['_sqlite3_bind_blob'] = function () { - return (Module['_sqlite3_bind_blob'] = - Module['asm']['sqlite3_bind_blob']).apply(null, arguments); - }); - - (Module['_sqlite3_bind_double'] = function () { - return (Module['_sqlite3_bind_double'] = - Module['asm']['sqlite3_bind_double']).apply(null, arguments); - }); - - (Module['_sqlite3_bind_int'] = function () { - return (Module['_sqlite3_bind_int'] = - Module['asm']['sqlite3_bind_int']).apply(null, arguments); - }); - - (Module['_sqlite3_bind_int64'] = function () { - return (Module['_sqlite3_bind_int64'] = - Module['asm']['sqlite3_bind_int64']).apply(null, arguments); - }); - - (Module['_sqlite3_bind_null'] = function () { - return (Module['_sqlite3_bind_null'] = - Module['asm']['sqlite3_bind_null']).apply(null, arguments); - }); - - (Module['_sqlite3_bind_pointer'] = function () { - return (Module['_sqlite3_bind_pointer'] = - Module['asm']['sqlite3_bind_pointer']).apply(null, arguments); - }); - - (Module['_sqlite3_bind_text'] = function () { - return (Module['_sqlite3_bind_text'] = - Module['asm']['sqlite3_bind_text']).apply(null, arguments); - }); - - (Module[ - '_sqlite3_bind_parameter_count' - ] = function () { - return (Module[ - '_sqlite3_bind_parameter_count' - ] = - Module['asm']['sqlite3_bind_parameter_count']).apply(null, arguments); - }); - - (Module[ - '_sqlite3_bind_parameter_index' - ] = function () { - return (Module[ - '_sqlite3_bind_parameter_index' - ] = - Module['asm']['sqlite3_bind_parameter_index']).apply(null, arguments); - }); - - (Module['_sqlite3_db_handle'] = function () { - return (Module['_sqlite3_db_handle'] = - Module['asm']['sqlite3_db_handle']).apply(null, arguments); - }); - - (Module['_sqlite3_stmt_readonly'] = - function () { - return (Module['_sqlite3_stmt_readonly'] = - Module['asm']['sqlite3_stmt_readonly']).apply(null, arguments); - }); - - (Module['_sqlite3_stmt_isexplain'] = - function () { - return (Module['_sqlite3_stmt_isexplain'] = - Module['asm']['sqlite3_stmt_isexplain']).apply(null, arguments); - }); - - (Module['_sqlite3_stmt_status'] = function () { - return (Module['_sqlite3_stmt_status'] = - Module['asm']['sqlite3_stmt_status']).apply(null, arguments); - }); - - (Module['_sqlite3_sql'] = function () { - return (Module['_sqlite3_sql'] = - Module['asm']['sqlite3_sql']).apply(null, arguments); - }); - - (Module['_sqlite3_expanded_sql'] = function () { - return (Module['_sqlite3_expanded_sql'] = - Module['asm']['sqlite3_expanded_sql']).apply(null, arguments); - }); - - (Module['_sqlite3_preupdate_old'] = - function () { - return (Module['_sqlite3_preupdate_old'] = - Module['asm']['sqlite3_preupdate_old']).apply(null, arguments); - }); - - (Module['_sqlite3_preupdate_count'] = - function () { - return (Module['_sqlite3_preupdate_count'] = - Module['asm']['sqlite3_preupdate_count']).apply(null, arguments); - }); - - (Module['_sqlite3_preupdate_depth'] = - function () { - return (Module['_sqlite3_preupdate_depth'] = - Module['asm']['sqlite3_preupdate_depth']).apply(null, arguments); - }); - - (Module['_sqlite3_preupdate_blobwrite'] = - function () { - return (Module[ - '_sqlite3_preupdate_blobwrite' - ] = - Module['asm']['sqlite3_preupdate_blobwrite']).apply(null, arguments); - }); - - (Module['_sqlite3_preupdate_new'] = - function () { - return (Module['_sqlite3_preupdate_new'] = - Module['asm']['sqlite3_preupdate_new']).apply(null, arguments); - }); - - (Module['_sqlite3_value_numeric_type'] = - function () { - return (Module[ - '_sqlite3_value_numeric_type' - ] = - Module['asm']['sqlite3_value_numeric_type']).apply(null, arguments); - }); - - (Module['_sqlite3_set_authorizer'] = - function () { - return (Module['_sqlite3_set_authorizer'] = - Module['asm']['sqlite3_set_authorizer']).apply(null, arguments); - }); - - (Module['_sqlite3_strglob'] = function () { - return (Module['_sqlite3_strglob'] = - Module['asm']['sqlite3_strglob']).apply(null, arguments); - }); - - (Module['_sqlite3_strlike'] = function () { - return (Module['_sqlite3_strlike'] = - Module['asm']['sqlite3_strlike']).apply(null, arguments); - }); - - (Module['_sqlite3_auto_extension'] = - function () { - return (Module['_sqlite3_auto_extension'] = - Module['asm']['sqlite3_auto_extension']).apply(null, arguments); - }); - - (Module[ - '_sqlite3_cancel_auto_extension' - ] = function () { - return (Module[ - '_sqlite3_cancel_auto_extension' - ] = - Module['asm']['sqlite3_cancel_auto_extension']).apply(null, arguments); - }); - - (Module[ - '_sqlite3_reset_auto_extension' - ] = function () { - return (Module[ - '_sqlite3_reset_auto_extension' - ] = - Module['asm']['sqlite3_reset_auto_extension']).apply(null, arguments); - }); - - (Module['_sqlite3_prepare_v3'] = function () { - return (Module['_sqlite3_prepare_v3'] = - Module['asm']['sqlite3_prepare_v3']).apply(null, arguments); - }); - - (Module['_sqlite3_create_module'] = - function () { - return (Module['_sqlite3_create_module'] = - Module['asm']['sqlite3_create_module']).apply(null, arguments); - }); - - (Module['_sqlite3_create_module_v2'] = - function () { - return (Module[ - '_sqlite3_create_module_v2' - ] = - Module['asm']['sqlite3_create_module_v2']).apply(null, arguments); - }); - - (Module['_sqlite3_drop_modules'] = function () { - return (Module['_sqlite3_drop_modules'] = - Module['asm']['sqlite3_drop_modules']).apply(null, arguments); - }); - - (Module['_sqlite3_declare_vtab'] = function () { - return (Module['_sqlite3_declare_vtab'] = - Module['asm']['sqlite3_declare_vtab']).apply(null, arguments); - }); - - (Module['_sqlite3_vtab_on_conflict'] = - function () { - return (Module[ - '_sqlite3_vtab_on_conflict' - ] = - Module['asm']['sqlite3_vtab_on_conflict']).apply(null, arguments); - }); - - (Module['_sqlite3_vtab_collation'] = - function () { - return (Module['_sqlite3_vtab_collation'] = - Module['asm']['sqlite3_vtab_collation']).apply(null, arguments); - }); - - (Module['_sqlite3_vtab_in'] = function () { - return (Module['_sqlite3_vtab_in'] = - Module['asm']['sqlite3_vtab_in']).apply(null, arguments); - }); - - (Module['_sqlite3_vtab_rhs_value'] = - function () { - return (Module['_sqlite3_vtab_rhs_value'] = - Module['asm']['sqlite3_vtab_rhs_value']).apply(null, arguments); - }); - - (Module['_sqlite3_vtab_distinct'] = - function () { - return (Module['_sqlite3_vtab_distinct'] = - Module['asm']['sqlite3_vtab_distinct']).apply(null, arguments); - }); - - (Module['_sqlite3_keyword_name'] = function () { - return (Module['_sqlite3_keyword_name'] = - Module['asm']['sqlite3_keyword_name']).apply(null, arguments); - }); - - (Module['_sqlite3_keyword_count'] = - function () { - return (Module['_sqlite3_keyword_count'] = - Module['asm']['sqlite3_keyword_count']).apply(null, arguments); - }); - - (Module['_sqlite3_keyword_check'] = - function () { - return (Module['_sqlite3_keyword_check'] = - Module['asm']['sqlite3_keyword_check']).apply(null, arguments); - }); - - (Module['_sqlite3_complete'] = function () { - return (Module['_sqlite3_complete'] = - Module['asm']['sqlite3_complete']).apply(null, arguments); - }); - - (Module['_sqlite3_libversion'] = function () { - return (Module['_sqlite3_libversion'] = - Module['asm']['sqlite3_libversion']).apply(null, arguments); - }); - - (Module['_sqlite3_libversion_number'] = - function () { - return (Module[ - '_sqlite3_libversion_number' - ] = - Module['asm']['sqlite3_libversion_number']).apply(null, arguments); - }); - - (Module['_sqlite3_shutdown'] = function () { - return (Module['_sqlite3_shutdown'] = - Module['asm']['sqlite3_shutdown']).apply(null, arguments); - }); - - (Module['_sqlite3_last_insert_rowid'] = - function () { - return (Module[ - '_sqlite3_last_insert_rowid' - ] = - Module['asm']['sqlite3_last_insert_rowid']).apply(null, arguments); - }); - - (Module[ - '_sqlite3_set_last_insert_rowid' - ] = function () { - return (Module[ - '_sqlite3_set_last_insert_rowid' - ] = - Module['asm']['sqlite3_set_last_insert_rowid']).apply(null, arguments); - }); - - (Module['_sqlite3_changes64'] = function () { - return (Module['_sqlite3_changes64'] = - Module['asm']['sqlite3_changes64']).apply(null, arguments); - }); - - (Module['_sqlite3_changes'] = function () { - return (Module['_sqlite3_changes'] = - Module['asm']['sqlite3_changes']).apply(null, arguments); - }); - - (Module['_sqlite3_total_changes64'] = - function () { - return (Module['_sqlite3_total_changes64'] = - Module['asm']['sqlite3_total_changes64']).apply(null, arguments); - }); - - (Module['_sqlite3_total_changes'] = - function () { - return (Module['_sqlite3_total_changes'] = - Module['asm']['sqlite3_total_changes']).apply(null, arguments); - }); - - (Module['_sqlite3_txn_state'] = function () { - return (Module['_sqlite3_txn_state'] = - Module['asm']['sqlite3_txn_state']).apply(null, arguments); - }); - - (Module['_sqlite3_close_v2'] = function () { - return (Module['_sqlite3_close_v2'] = - Module['asm']['sqlite3_close_v2']).apply(null, arguments); - }); - - (Module['_sqlite3_busy_handler'] = function () { - return (Module['_sqlite3_busy_handler'] = - Module['asm']['sqlite3_busy_handler']).apply(null, arguments); - }); - - (Module['_sqlite3_progress_handler'] = - function () { - return (Module[ - '_sqlite3_progress_handler' - ] = - Module['asm']['sqlite3_progress_handler']).apply(null, arguments); - }); - - (Module['_sqlite3_busy_timeout'] = function () { - return (Module['_sqlite3_busy_timeout'] = - Module['asm']['sqlite3_busy_timeout']).apply(null, arguments); - }); - - (Module['_sqlite3_create_function'] = - function () { - return (Module['_sqlite3_create_function'] = - Module['asm']['sqlite3_create_function']).apply(null, arguments); - }); - - (Module['_sqlite3_create_function_v2'] = - function () { - return (Module[ - '_sqlite3_create_function_v2' - ] = - Module['asm']['sqlite3_create_function_v2']).apply(null, arguments); - }); - - (Module[ - '_sqlite3_create_window_function' - ] = function () { - return (Module[ - '_sqlite3_create_window_function' - ] = - Module['asm']['sqlite3_create_window_function']).apply(null, arguments); - }); - - (Module['_sqlite3_overload_function'] = - function () { - return (Module[ - '_sqlite3_overload_function' - ] = - Module['asm']['sqlite3_overload_function']).apply(null, arguments); - }); - - (Module['_sqlite3_trace_v2'] = function () { - return (Module['_sqlite3_trace_v2'] = - Module['asm']['sqlite3_trace_v2']).apply(null, arguments); - }); - - (Module['_sqlite3_commit_hook'] = function () { - return (Module['_sqlite3_commit_hook'] = - Module['asm']['sqlite3_commit_hook']).apply(null, arguments); - }); - - (Module['_sqlite3_update_hook'] = function () { - return (Module['_sqlite3_update_hook'] = - Module['asm']['sqlite3_update_hook']).apply(null, arguments); - }); - - (Module['_sqlite3_rollback_hook'] = - function () { - return (Module['_sqlite3_rollback_hook'] = - Module['asm']['sqlite3_rollback_hook']).apply(null, arguments); - }); - - (Module['_sqlite3_preupdate_hook'] = - function () { - return (Module['_sqlite3_preupdate_hook'] = - Module['asm']['sqlite3_preupdate_hook']).apply(null, arguments); - }); - - (Module['_sqlite3_error_offset'] = function () { - return (Module['_sqlite3_error_offset'] = - Module['asm']['sqlite3_error_offset']).apply(null, arguments); - }); - - (Module['_sqlite3_errcode'] = function () { - return (Module['_sqlite3_errcode'] = - Module['asm']['sqlite3_errcode']).apply(null, arguments); - }); - - (Module['_sqlite3_extended_errcode'] = - function () { - return (Module[ - '_sqlite3_extended_errcode' - ] = - Module['asm']['sqlite3_extended_errcode']).apply(null, arguments); - }); - - (Module['_sqlite3_errstr'] = function () { - return (Module['_sqlite3_errstr'] = - Module['asm']['sqlite3_errstr']).apply(null, arguments); - }); - - (Module['_sqlite3_limit'] = function () { - return (Module['_sqlite3_limit'] = - Module['asm']['sqlite3_limit']).apply(null, arguments); - }); - - (Module['_sqlite3_open'] = function () { - return (Module['_sqlite3_open'] = - Module['asm']['sqlite3_open']).apply(null, arguments); - }); - - (Module['_sqlite3_open_v2'] = function () { - return (Module['_sqlite3_open_v2'] = - Module['asm']['sqlite3_open_v2']).apply(null, arguments); - }); - - (Module['_sqlite3_create_collation'] = - function () { - return (Module[ - '_sqlite3_create_collation' - ] = - Module['asm']['sqlite3_create_collation']).apply(null, arguments); - }); - - (Module['_sqlite3_create_collation_v2'] = - function () { - return (Module[ - '_sqlite3_create_collation_v2' - ] = - Module['asm']['sqlite3_create_collation_v2']).apply(null, arguments); - }); - - (Module['_sqlite3_collation_needed'] = - function () { - return (Module[ - '_sqlite3_collation_needed' - ] = - Module['asm']['sqlite3_collation_needed']).apply(null, arguments); - }); - - (Module['_sqlite3_get_autocommit'] = - function () { - return (Module['_sqlite3_get_autocommit'] = - Module['asm']['sqlite3_get_autocommit']).apply(null, arguments); - }); - - (Module[ - '_sqlite3_table_column_metadata' - ] = function () { - return (Module[ - '_sqlite3_table_column_metadata' - ] = - Module['asm']['sqlite3_table_column_metadata']).apply(null, arguments); - }); - - (Module[ - '_sqlite3_extended_result_codes' - ] = function () { - return (Module[ - '_sqlite3_extended_result_codes' - ] = - Module['asm']['sqlite3_extended_result_codes']).apply(null, arguments); - }); - - (Module['_sqlite3_uri_key'] = function () { - return (Module['_sqlite3_uri_key'] = - Module['asm']['sqlite3_uri_key']).apply(null, arguments); - }); - - (Module['_sqlite3_uri_int64'] = function () { - return (Module['_sqlite3_uri_int64'] = - Module['asm']['sqlite3_uri_int64']).apply(null, arguments); - }); - - (Module['_sqlite3_db_name'] = function () { - return (Module['_sqlite3_db_name'] = - Module['asm']['sqlite3_db_name']).apply(null, arguments); - }); - - (Module['_sqlite3_db_filename'] = function () { - return (Module['_sqlite3_db_filename'] = - Module['asm']['sqlite3_db_filename']).apply(null, arguments); - }); - - (Module['_sqlite3_compileoption_used'] = - function () { - return (Module[ - '_sqlite3_compileoption_used' - ] = - Module['asm']['sqlite3_compileoption_used']).apply(null, arguments); - }); - - (Module['_sqlite3_compileoption_get'] = - function () { - return (Module[ - '_sqlite3_compileoption_get' - ] = - Module['asm']['sqlite3_compileoption_get']).apply(null, arguments); - }); - - (Module['_sqlite3session_diff'] = function () { - return (Module['_sqlite3session_diff'] = - Module['asm']['sqlite3session_diff']).apply(null, arguments); - }); - - (Module['_sqlite3session_attach'] = - function () { - return (Module['_sqlite3session_attach'] = - Module['asm']['sqlite3session_attach']).apply(null, arguments); - }); - - (Module['_sqlite3session_create'] = - function () { - return (Module['_sqlite3session_create'] = - Module['asm']['sqlite3session_create']).apply(null, arguments); - }); - - (Module['_sqlite3session_delete'] = - function () { - return (Module['_sqlite3session_delete'] = - Module['asm']['sqlite3session_delete']).apply(null, arguments); - }); - - (Module['_sqlite3session_table_filter'] = - function () { - return (Module[ - '_sqlite3session_table_filter' - ] = - Module['asm']['sqlite3session_table_filter']).apply(null, arguments); - }); - - (Module['_sqlite3session_changeset'] = - function () { - return (Module[ - '_sqlite3session_changeset' - ] = - Module['asm']['sqlite3session_changeset']).apply(null, arguments); - }); - - (Module[ - '_sqlite3session_changeset_strm' - ] = function () { - return (Module[ - '_sqlite3session_changeset_strm' - ] = - Module['asm']['sqlite3session_changeset_strm']).apply(null, arguments); - }); - - (Module[ - '_sqlite3session_patchset_strm' - ] = function () { - return (Module[ - '_sqlite3session_patchset_strm' - ] = - Module['asm']['sqlite3session_patchset_strm']).apply(null, arguments); - }); - - (Module['_sqlite3session_patchset'] = - function () { - return (Module['_sqlite3session_patchset'] = - Module['asm']['sqlite3session_patchset']).apply(null, arguments); - }); - - (Module['_sqlite3session_enable'] = - function () { - return (Module['_sqlite3session_enable'] = - Module['asm']['sqlite3session_enable']).apply(null, arguments); - }); - - (Module['_sqlite3session_indirect'] = - function () { - return (Module['_sqlite3session_indirect'] = - Module['asm']['sqlite3session_indirect']).apply(null, arguments); - }); - - (Module['_sqlite3session_isempty'] = - function () { - return (Module['_sqlite3session_isempty'] = - Module['asm']['sqlite3session_isempty']).apply(null, arguments); - }); - - (Module['_sqlite3session_memory_used'] = - function () { - return (Module[ - '_sqlite3session_memory_used' - ] = - Module['asm']['sqlite3session_memory_used']).apply(null, arguments); - }); - - (Module[ - '_sqlite3session_object_config' - ] = function () { - return (Module[ - '_sqlite3session_object_config' - ] = - Module['asm']['sqlite3session_object_config']).apply(null, arguments); - }); - - (Module[ - '_sqlite3session_changeset_size' - ] = function () { - return (Module[ - '_sqlite3session_changeset_size' - ] = - Module['asm']['sqlite3session_changeset_size']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_start'] = - function () { - return (Module['_sqlite3changeset_start'] = - Module['asm']['sqlite3changeset_start']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_start_v2'] = - function () { - return (Module[ - '_sqlite3changeset_start_v2' - ] = - Module['asm']['sqlite3changeset_start_v2']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_start_strm'] = - function () { - return (Module[ - '_sqlite3changeset_start_strm' - ] = - Module['asm']['sqlite3changeset_start_strm']).apply(null, arguments); - }); - - (Module[ - '_sqlite3changeset_start_v2_strm' - ] = function () { - return (Module[ - '_sqlite3changeset_start_v2_strm' - ] = - Module['asm']['sqlite3changeset_start_v2_strm']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_next'] = - function () { - return (Module['_sqlite3changeset_next'] = - Module['asm']['sqlite3changeset_next']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_op'] = function () { - return (Module['_sqlite3changeset_op'] = - Module['asm']['sqlite3changeset_op']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_pk'] = function () { - return (Module['_sqlite3changeset_pk'] = - Module['asm']['sqlite3changeset_pk']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_old'] = function () { - return (Module['_sqlite3changeset_old'] = - Module['asm']['sqlite3changeset_old']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_new'] = function () { - return (Module['_sqlite3changeset_new'] = - Module['asm']['sqlite3changeset_new']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_conflict'] = - function () { - return (Module[ - '_sqlite3changeset_conflict' - ] = - Module['asm']['sqlite3changeset_conflict']).apply(null, arguments); - }); - - (Module[ - '_sqlite3changeset_fk_conflicts' - ] = function () { - return (Module[ - '_sqlite3changeset_fk_conflicts' - ] = - Module['asm']['sqlite3changeset_fk_conflicts']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_finalize'] = - function () { - return (Module[ - '_sqlite3changeset_finalize' - ] = - Module['asm']['sqlite3changeset_finalize']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_invert'] = - function () { - return (Module['_sqlite3changeset_invert'] = - Module['asm']['sqlite3changeset_invert']).apply(null, arguments); - }); - - (Module[ - '_sqlite3changeset_invert_strm' - ] = function () { - return (Module[ - '_sqlite3changeset_invert_strm' - ] = - Module['asm']['sqlite3changeset_invert_strm']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_apply_v2'] = - function () { - return (Module[ - '_sqlite3changeset_apply_v2' - ] = - Module['asm']['sqlite3changeset_apply_v2']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_apply'] = - function () { - return (Module['_sqlite3changeset_apply'] = - Module['asm']['sqlite3changeset_apply']).apply(null, arguments); - }); - - (Module[ - '_sqlite3changeset_apply_v2_strm' - ] = function () { - return (Module[ - '_sqlite3changeset_apply_v2_strm' - ] = - Module['asm']['sqlite3changeset_apply_v2_strm']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_apply_strm'] = - function () { - return (Module[ - '_sqlite3changeset_apply_strm' - ] = - Module['asm']['sqlite3changeset_apply_strm']).apply(null, arguments); - }); - - (Module['_sqlite3changegroup_new'] = - function () { - return (Module['_sqlite3changegroup_new'] = - Module['asm']['sqlite3changegroup_new']).apply(null, arguments); - }); - - (Module['_sqlite3changegroup_add'] = - function () { - return (Module['_sqlite3changegroup_add'] = - Module['asm']['sqlite3changegroup_add']).apply(null, arguments); - }); - - (Module['_sqlite3changegroup_output'] = - function () { - return (Module[ - '_sqlite3changegroup_output' - ] = - Module['asm']['sqlite3changegroup_output']).apply(null, arguments); - }); - - (Module['_sqlite3changegroup_add_strm'] = - function () { - return (Module[ - '_sqlite3changegroup_add_strm' - ] = - Module['asm']['sqlite3changegroup_add_strm']).apply(null, arguments); - }); - - (Module[ - '_sqlite3changegroup_output_strm' - ] = function () { - return (Module[ - '_sqlite3changegroup_output_strm' - ] = - Module['asm']['sqlite3changegroup_output_strm']).apply(null, arguments); - }); - - (Module['_sqlite3changegroup_delete'] = - function () { - return (Module[ - '_sqlite3changegroup_delete' - ] = - Module['asm']['sqlite3changegroup_delete']).apply(null, arguments); - }); - - (Module['_sqlite3changeset_concat'] = - function () { - return (Module['_sqlite3changeset_concat'] = - Module['asm']['sqlite3changeset_concat']).apply(null, arguments); - }); - - (Module[ - '_sqlite3changeset_concat_strm' - ] = function () { - return (Module[ - '_sqlite3changeset_concat_strm' - ] = - Module['asm']['sqlite3changeset_concat_strm']).apply(null, arguments); - }); - - (Module['_sqlite3session_config'] = - function () { - return (Module['_sqlite3session_config'] = - Module['asm']['sqlite3session_config']).apply(null, arguments); - }); - - (Module['_sqlite3_sourceid'] = function () { - return (Module['_sqlite3_sourceid'] = - Module['asm']['sqlite3_sourceid']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_pstack_ptr'] = - function () { - return (Module[ - '_sqlite3__wasm_pstack_ptr' - ] = - Module['asm']['sqlite3__wasm_pstack_ptr']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_pstack_restore' - ] = function () { - return (Module[ - '_sqlite3__wasm_pstack_restore' - ] = - Module['asm']['sqlite3__wasm_pstack_restore']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_pstack_alloc'] = - function () { - return (Module[ - '_sqlite3__wasm_pstack_alloc' - ] = - Module['asm']['sqlite3__wasm_pstack_alloc']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_pstack_remaining' - ] = function () { - return (Module[ - '_sqlite3__wasm_pstack_remaining' - ] = - Module['asm']['sqlite3__wasm_pstack_remaining']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_pstack_quota'] = - function () { - return (Module[ - '_sqlite3__wasm_pstack_quota' - ] = - Module['asm']['sqlite3__wasm_pstack_quota']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_db_error'] = - function () { - return (Module['_sqlite3__wasm_db_error'] = - Module['asm']['sqlite3__wasm_db_error']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_test_struct'] = - function () { - return (Module[ - '_sqlite3__wasm_test_struct' - ] = - Module['asm']['sqlite3__wasm_test_struct']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_enum_json'] = - function () { - return (Module['_sqlite3__wasm_enum_json'] = - Module['asm']['sqlite3__wasm_enum_json']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_vfs_unlink'] = - function () { - return (Module[ - '_sqlite3__wasm_vfs_unlink' - ] = - Module['asm']['sqlite3__wasm_vfs_unlink']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_db_vfs'] = function () { - return (Module['_sqlite3__wasm_db_vfs'] = - Module['asm']['sqlite3__wasm_db_vfs']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_db_reset'] = - function () { - return (Module['_sqlite3__wasm_db_reset'] = - Module['asm']['sqlite3__wasm_db_reset']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_db_export_chunked' - ] = function () { - return (Module[ - '_sqlite3__wasm_db_export_chunked' - ] = - Module['asm']['sqlite3__wasm_db_export_chunked']).apply( - null, - arguments, - ); - }); - - (Module['_sqlite3__wasm_db_serialize'] = - function () { - return (Module[ - '_sqlite3__wasm_db_serialize' - ] = - Module['asm']['sqlite3__wasm_db_serialize']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_vfs_create_file' - ] = function () { - return (Module[ - '_sqlite3__wasm_vfs_create_file' - ] = - Module['asm']['sqlite3__wasm_vfs_create_file']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_posix_create_file' - ] = function () { - return (Module[ - '_sqlite3__wasm_posix_create_file' - ] = - Module['asm']['sqlite3__wasm_posix_create_file']).apply( - null, - arguments, - ); - }); - - (Module[ - '_sqlite3__wasm_kvvfsMakeKeyOnPstack' - ] = function () { - return (Module[ - '_sqlite3__wasm_kvvfsMakeKeyOnPstack' - ] = - Module['asm']['sqlite3__wasm_kvvfsMakeKeyOnPstack']).apply( - null, - arguments, - ); - }); - - (Module['_sqlite3__wasm_kvvfs_methods'] = - function () { - return (Module[ - '_sqlite3__wasm_kvvfs_methods' - ] = - Module['asm']['sqlite3__wasm_kvvfs_methods']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_vtab_config'] = - function () { - return (Module[ - '_sqlite3__wasm_vtab_config' - ] = - Module['asm']['sqlite3__wasm_vtab_config']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_db_config_ip'] = - function () { - return (Module[ - '_sqlite3__wasm_db_config_ip' - ] = - Module['asm']['sqlite3__wasm_db_config_ip']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_db_config_pii'] = - function () { - return (Module[ - '_sqlite3__wasm_db_config_pii' - ] = - Module['asm']['sqlite3__wasm_db_config_pii']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_db_config_s'] = - function () { - return (Module[ - '_sqlite3__wasm_db_config_s' - ] = - Module['asm']['sqlite3__wasm_db_config_s']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_config_i'] = - function () { - return (Module['_sqlite3__wasm_config_i'] = - Module['asm']['sqlite3__wasm_config_i']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_config_ii'] = - function () { - return (Module['_sqlite3__wasm_config_ii'] = - Module['asm']['sqlite3__wasm_config_ii']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_config_j'] = - function () { - return (Module['_sqlite3__wasm_config_j'] = - Module['asm']['sqlite3__wasm_config_j']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_qfmt_token'] = - function () { - return (Module[ - '_sqlite3__wasm_qfmt_token' - ] = - Module['asm']['sqlite3__wasm_qfmt_token']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_init_wasmfs'] = - function () { - return (Module[ - '_sqlite3__wasm_init_wasmfs' - ] = - Module['asm']['sqlite3__wasm_init_wasmfs']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_test_intptr'] = - function () { - return (Module[ - '_sqlite3__wasm_test_intptr' - ] = - Module['asm']['sqlite3__wasm_test_intptr']).apply(null, arguments); - }); - - (Module['_sqlite3__wasm_test_voidptr'] = - function () { - return (Module[ - '_sqlite3__wasm_test_voidptr' - ] = - Module['asm']['sqlite3__wasm_test_voidptr']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_test_int64_max' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_int64_max' - ] = - Module['asm']['sqlite3__wasm_test_int64_max']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_test_int64_min' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_int64_min' - ] = - Module['asm']['sqlite3__wasm_test_int64_min']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_test_int64_times2' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_int64_times2' - ] = - Module['asm']['sqlite3__wasm_test_int64_times2']).apply( - null, - arguments, - ); - }); - - (Module[ - '_sqlite3__wasm_test_int64_minmax' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_int64_minmax' - ] = - Module['asm']['sqlite3__wasm_test_int64_minmax']).apply( - null, - arguments, - ); - }); - - (Module['_sqlite3__wasm_test_int64ptr'] = - function () { - return (Module[ - '_sqlite3__wasm_test_int64ptr' - ] = - Module['asm']['sqlite3__wasm_test_int64ptr']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_test_stack_overflow' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_stack_overflow' - ] = - Module['asm']['sqlite3__wasm_test_stack_overflow']).apply( - null, - arguments, - ); - }); - - (Module[ - '_sqlite3__wasm_test_str_hello' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_str_hello' - ] = - Module['asm']['sqlite3__wasm_test_str_hello']).apply(null, arguments); - }); - - (Module[ - '_sqlite3__wasm_SQLTester_strglob' - ] = function () { - return (Module[ - '_sqlite3__wasm_SQLTester_strglob' - ] = - Module['asm']['sqlite3__wasm_SQLTester_strglob']).apply( - null, - arguments, - ); - }); - - var _malloc = (Module['_malloc'] = function () { - return (_malloc = Module['_malloc'] = Module['asm']['malloc']).apply( - null, - arguments, - ); - }); - - (Module['_free'] = function () { - return (Module['_free'] = Module['asm']['free']).apply( - null, - arguments, - ); - }); - - (Module['_realloc'] = function () { - return (Module['_realloc'] = Module['asm']['realloc']).apply( - null, - arguments, - ); - }); - - var _emscripten_builtin_memalign = (Module['_emscripten_builtin_memalign'] = - function () { - return (_emscripten_builtin_memalign = Module[ - '_emscripten_builtin_memalign' - ] = - Module['asm']['emscripten_builtin_memalign']).apply(null, arguments); - }); - - (Module['stackSave'] = function () { - return (Module['stackSave'] = - Module['asm']['stackSave']).apply(null, arguments); - }); - - (Module['stackRestore'] = function () { - return (Module['stackRestore'] = - Module['asm']['stackRestore']).apply(null, arguments); - }); - - (Module['stackAlloc'] = function () { - return (Module['stackAlloc'] = - Module['asm']['stackAlloc']).apply(null, arguments); - }); - - Module['wasmMemory'] = wasmMemory; - - var calledRun; - - dependenciesFulfilled = function runCaller() { - if (!calledRun) run(); - if (!calledRun) dependenciesFulfilled = runCaller; - }; - - function run(args) { - - if (runDependencies > 0) { - return; - } - - preRun(); - - if (runDependencies > 0) { - return; - } - - function doRun() { - if (calledRun) return; - calledRun = true; - Module['calledRun'] = true; - - if (ABORT) return; - - initRuntime(); - - readyPromiseResolve(Module); - if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); - - postRun(); - } - - if (Module['setStatus']) { - Module['setStatus']('Running...'); - setTimeout(function () { - setTimeout(function () { - Module['setStatus'](''); - }, 1); - doRun(); - }, 1); - } else { - doRun(); - } - } - - if (Module['preInit']) { - if (typeof Module['preInit'] == 'function') - Module['preInit'] = [Module['preInit']]; - while (Module['preInit'].length > 0) { - Module['preInit'].pop()(); - } - } - - run(); - - if (!Module.postRun) Module.postRun = []; - Module.postRun.push(function (Module) { - globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( - apiConfig = globalThis.sqlite3ApiConfig || - sqlite3ApiBootstrap.defaultConfig, - ) { - if (sqlite3ApiBootstrap.sqlite3) { - (sqlite3ApiBootstrap.sqlite3.config || console).warn( - 'sqlite3ApiBootstrap() called multiple times.', - 'Config and external initializers are ignored on calls after the first.', - ); - return sqlite3ApiBootstrap.sqlite3; - } - const config = Object.assign( - Object.create(null), - { - exports: undefined, - memory: undefined, - bigIntEnabled: (() => { - if ('undefined' !== typeof Module) { - if (!!Module.HEAPU64) return true; - } - return !!globalThis.BigInt64Array; - })(), - debug: console.debug.bind(console), - warn: console.warn.bind(console), - error: console.error.bind(console), - log: console.log.bind(console), - wasmfsOpfsDir: '/opfs', - - useStdAlloc: false, - }, - apiConfig || {}, - ); - - Object.assign( - config, - { - allocExportName: config.useStdAlloc ? 'malloc' : 'sqlite3_malloc', - deallocExportName: config.useStdAlloc ? 'free' : 'sqlite3_free', - reallocExportName: config.useStdAlloc - ? 'realloc' - : 'sqlite3_realloc', - }, - config, - ); - - ['exports', 'memory', 'wasmfsOpfsDir'].forEach((k) => { - if ('function' === typeof config[k]) { - config[k] = config[k](); - } - }); - - delete globalThis.sqlite3ApiConfig; - delete sqlite3ApiBootstrap.defaultConfig; - - const capi = Object.create(null); - - const wasm = Object.create(null); - - const __rcStr = (rc) => { - return ( - (capi.sqlite3_js_rc_str && capi.sqlite3_js_rc_str(rc)) || - 'Unknown result code #' + rc - ); - }; - - const __isInt = (n) => 'number' === typeof n && n === (n | 0); - - class SQLite3Error extends Error { - constructor(...args) { - let rc; - if (args.length) { - if (__isInt(args[0])) { - rc = args[0]; - if (1 === args.length) { - super(__rcStr(args[0])); - } else { - const rcStr = __rcStr(rc); - if ('object' === typeof args[1]) { - super(rcStr, args[1]); - } else { - args[0] = rcStr + ':'; - super(args.join(' ')); - } - } - } else { - if (2 === args.length && 'object' === typeof args[1]) { - super(...args); - } else { - super(args.join(' ')); - } - } - } - this.resultCode = rc || capi.SQLITE_ERROR; - this.name = 'SQLite3Error'; - } - } - - SQLite3Error.toss = (...args) => { - throw new SQLite3Error(...args); - }; - const toss3 = SQLite3Error.toss; - - if (config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)) { - toss3( - "config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.", - ); - } - - const isInt32 = (n) => { - return ( - 'bigint' !== typeof n && - !!(n === (n | 0) && n <= 2147483647 && n >= -2147483648) - ); - }; - - const bigIntFits64 = function f(b) { - if (!f._max) { - f._max = BigInt('0x7fffffffffffffff'); - f._min = ~f._max; - } - return b >= f._min && b <= f._max; - }; - - const bigIntFits32 = (b) => b >= -0x7fffffffn - 1n && b <= 0x7fffffffn; - - const bigIntFitsDouble = function f(b) { - if (!f._min) { - f._min = Number.MIN_SAFE_INTEGER; - f._max = Number.MAX_SAFE_INTEGER; - } - return b >= f._min && b <= f._max; - }; - - const isTypedArray = (v) => { - return v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT) - ? v - : false; - }; - - const __SAB = - 'undefined' === typeof SharedArrayBuffer - ? function () {} - : SharedArrayBuffer; - - const isSharedTypedArray = (aTypedArray) => - aTypedArray.buffer instanceof __SAB; - - const typedArrayPart = (aTypedArray, begin, end) => { - return isSharedTypedArray(aTypedArray) - ? aTypedArray.slice(begin, end) - : aTypedArray.subarray(begin, end); - }; - - const isBindableTypedArray = (v) => { - return ( - v && - (v instanceof Uint8Array || - v instanceof Int8Array || - v instanceof ArrayBuffer) - ); - }; - - const isSQLableTypedArray = (v) => { - return ( - v && - (v instanceof Uint8Array || - v instanceof Int8Array || - v instanceof ArrayBuffer) - ); - }; - - const affirmBindableTypedArray = (v) => { - return ( - isBindableTypedArray(v) || - toss3('Value is not of a supported TypedArray type.') - ); - }; - - const utf8Decoder = new TextDecoder('utf-8'); - - const typedArrayToString = function (typedArray, begin, end) { - return utf8Decoder.decode(typedArrayPart(typedArray, begin, end)); - }; - - const flexibleString = function (v) { - if (isSQLableTypedArray(v)) { - return typedArrayToString( - v instanceof ArrayBuffer ? new Uint8Array(v) : v, - ); - } else if (Array.isArray(v)) return v.join(''); - else if (wasm.isPtr(v)) v = wasm.cstrToJs(v); - return v; - }; - - class WasmAllocError extends Error { - constructor(...args) { - if (2 === args.length && 'object' === typeof args[1]) { - super(...args); - } else if (args.length) { - super(args.join(' ')); - } else { - super('Allocation failed.'); - } - this.resultCode = capi.SQLITE_NOMEM; - this.name = 'WasmAllocError'; - } - } - - WasmAllocError.toss = (...args) => { - throw new WasmAllocError(...args); - }; - - Object.assign(capi, { - sqlite3_bind_blob: undefined, - - sqlite3_bind_text: undefined, - - sqlite3_create_function_v2: ( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xFunc, - xStep, - xFinal, - xDestroy, - ) => {}, - - sqlite3_create_function: ( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xFunc, - xStep, - xFinal, - ) => {}, - - sqlite3_create_window_function: ( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xStep, - xFinal, - xValue, - xInverse, - xDestroy, - ) => {}, - - sqlite3_prepare_v3: ( - dbPtr, - sql, - sqlByteLen, - prepFlags, - stmtPtrPtr, - strPtrPtr, - ) => {}, - - sqlite3_prepare_v2: ( - dbPtr, - sql, - sqlByteLen, - stmtPtrPtr, - strPtrPtr, - ) => {}, - - sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg) => {}, - - sqlite3_randomness: (n, outPtr) => {}, - }); - - const util = { - affirmBindableTypedArray, - flexibleString, - bigIntFits32, - bigIntFits64, - bigIntFitsDouble, - isBindableTypedArray, - isInt32, - isSQLableTypedArray, - isTypedArray, - typedArrayToString, - isUIThread: () => - globalThis.window === globalThis && !!globalThis.document, - - isSharedTypedArray, - toss: function (...args) { - throw new Error(args.join(' ')); - }, - toss3, - typedArrayPart, - - affirmDbHeader: function (bytes) { - if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); - const header = 'SQLite format 3'; - if (header.length > bytes.byteLength) { - toss3('Input does not contain an SQLite3 database header.'); - } - for (let i = 0; i < header.length; ++i) { - if (header.charCodeAt(i) !== bytes[i]) { - toss3('Input does not contain an SQLite3 database header.'); - } - } - }, - - affirmIsDb: function (bytes) { - if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); - const n = bytes.byteLength; - if (n < 512 || n % 512 !== 0) { - toss3('Byte array size', n, 'is invalid for an SQLite3 db.'); - } - util.affirmDbHeader(bytes); - }, - }; - - Object.assign(wasm, { - ptrSizeof: config.wasmPtrSizeof || 4, - - ptrIR: config.wasmPtrIR || 'i32', - - bigIntEnabled: !!config.bigIntEnabled, - - exports: - config.exports || - toss3('Missing API config.exports (WASM module exports).'), - - memory: - config.memory || - config.exports['memory'] || - toss3( - 'API config object requires a WebAssembly.Memory object', - 'in either config.exports.memory (exported)', - 'or config.memory (imported).', - ), - - alloc: undefined, - - realloc: undefined, - - dealloc: undefined, - }); - - wasm.allocFromTypedArray = function (srcTypedArray) { - if (srcTypedArray instanceof ArrayBuffer) { - srcTypedArray = new Uint8Array(srcTypedArray); - } - affirmBindableTypedArray(srcTypedArray); - const pRet = wasm.alloc(srcTypedArray.byteLength || 1); - wasm - .heapForSize(srcTypedArray.constructor) - .set(srcTypedArray.byteLength ? srcTypedArray : [0], pRet); - return pRet; - }; - - { - const keyAlloc = config.allocExportName, - keyDealloc = config.deallocExportName, - keyRealloc = config.reallocExportName; - for (const key of [keyAlloc, keyDealloc, keyRealloc]) { - const f = wasm.exports[key]; - if (!(f instanceof Function)) - toss3('Missing required exports[', key, '] function.'); - } - - wasm.alloc = function f(n) { - return ( - f.impl(n) || - WasmAllocError.toss('Failed to allocate', n, ' bytes.') - ); - }; - wasm.alloc.impl = wasm.exports[keyAlloc]; - wasm.realloc = function f(m, n) { - const m2 = f.impl(m, n); - return n - ? m2 || WasmAllocError.toss('Failed to reallocate', n, ' bytes.') - : 0; - }; - wasm.realloc.impl = wasm.exports[keyRealloc]; - wasm.dealloc = wasm.exports[keyDealloc]; - } - - wasm.compileOptionUsed = function f(optName) { - if (!arguments.length) { - if (f._result) return f._result; - else if (!f._opt) { - f._rx = /^([^=]+)=(.+)/; - f._rxInt = /^-?\d+$/; - f._opt = function (opt, rv) { - const m = f._rx.exec(opt); - rv[0] = m ? m[1] : opt; - rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true; - }; - } - const rc = {}, - ov = [0, 0]; - let i = 0, - k; - while ((k = capi.sqlite3_compileoption_get(i++))) { - f._opt(k, ov); - rc[ov[0]] = ov[1]; - } - return (f._result = rc); - } else if (Array.isArray(optName)) { - const rc = {}; - optName.forEach((v) => { - rc[v] = capi.sqlite3_compileoption_used(v); - }); - return rc; - } else if ('object' === typeof optName) { - Object.keys(optName).forEach((k) => { - optName[k] = capi.sqlite3_compileoption_used(k); - }); - return optName; - } - return 'string' === typeof optName - ? !!capi.sqlite3_compileoption_used(optName) - : false; - }; - - wasm.pstack = Object.assign(Object.create(null), { - restore: wasm.exports.sqlite3__wasm_pstack_restore, - - alloc: function (n) { - if ('string' === typeof n && !(n = wasm.sizeofIR(n))) { - WasmAllocError.toss( - 'Invalid value for pstack.alloc(', - arguments[0], - ')', - ); - } - return ( - wasm.exports.sqlite3__wasm_pstack_alloc(n) || - WasmAllocError.toss( - 'Could not allocate', - n, - 'bytes from the pstack.', - ) - ); - }, - - allocChunks: function (n, sz) { - if ('string' === typeof sz && !(sz = wasm.sizeofIR(sz))) { - WasmAllocError.toss( - 'Invalid size value for allocChunks(', - arguments[1], - ')', - ); - } - const mem = wasm.pstack.alloc(n * sz); - const rc = []; - let i = 0, - offset = 0; - for (; i < n; ++i, offset += sz) rc.push(mem + offset); - return rc; - }, - - allocPtr: (n = 1, safePtrSize = true) => { - return 1 === n - ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof) - : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof); - }, - - call: function (f) { - const stackPos = wasm.pstack.pointer; - try { - return f(sqlite3); - } finally { - wasm.pstack.restore(stackPos); - } - }, - }); - Object.defineProperties(wasm.pstack, { - pointer: { - configurable: false, - iterable: true, - writeable: false, - get: wasm.exports.sqlite3__wasm_pstack_ptr, - }, - - quota: { - configurable: false, - iterable: true, - writeable: false, - get: wasm.exports.sqlite3__wasm_pstack_quota, - }, - - remaining: { - configurable: false, - iterable: true, - writeable: false, - get: wasm.exports.sqlite3__wasm_pstack_remaining, - }, - }); - - capi.sqlite3_randomness = (...args) => { - if ( - 1 === args.length && - util.isTypedArray(args[0]) && - 1 === args[0].BYTES_PER_ELEMENT - ) { - const ta = args[0]; - if (0 === ta.byteLength) { - wasm.exports.sqlite3_randomness(0, 0); - return ta; - } - const stack = wasm.pstack.pointer; - try { - let n = ta.byteLength, - offset = 0; - const r = wasm.exports.sqlite3_randomness; - const heap = wasm.heap8u(); - const nAlloc = n < 512 ? n : 512; - const ptr = wasm.pstack.alloc(nAlloc); - do { - const j = n > nAlloc ? nAlloc : n; - r(j, ptr); - ta.set(typedArrayPart(heap, ptr, ptr + j), offset); - n -= j; - offset += j; - } while (n > 0); - } catch (e) { - console.error( - 'Highly unexpected (and ignored!) ' + - 'exception in sqlite3_randomness():', - e, - ); - } finally { - wasm.pstack.restore(stack); - } - return ta; - } - wasm.exports.sqlite3_randomness(...args); - }; - - let __wasmfsOpfsDir = undefined; - - capi.sqlite3_wasmfs_opfs_dir = function () { - if (undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir; - - const pdir = config.wasmfsOpfsDir; - if ( - !pdir || - !globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle - ) { - return (__wasmfsOpfsDir = ''); - } - try { - if ( - pdir && - 0 === - wasm.xCallWrapped( - 'sqlite3__wasm_init_wasmfs', - 'i32', - ['string'], - pdir, - ) - ) { - return (__wasmfsOpfsDir = pdir); - } else { - return (__wasmfsOpfsDir = ''); - } - } catch (e) { - return (__wasmfsOpfsDir = ''); - } - }; - - capi.sqlite3_wasmfs_filename_is_persistent = function (name) { - const p = capi.sqlite3_wasmfs_opfs_dir(); - return p && name ? name.startsWith(p + '/') : false; - }; - - capi.sqlite3_js_db_uses_vfs = function (pDb, vfsName, dbName = 0) { - try { - const pK = capi.sqlite3_vfs_find(vfsName); - if (!pK) return false; - else if (!pDb) { - return pK === capi.sqlite3_vfs_find(0) ? pK : false; - } else { - return pK === capi.sqlite3_js_db_vfs(pDb, dbName) ? pK : false; - } - } catch (e) { - return false; - } - }; - - capi.sqlite3_js_vfs_list = function () { - const rc = []; - let pVfs = capi.sqlite3_vfs_find(0); - while (pVfs) { - const oVfs = new capi.sqlite3_vfs(pVfs); - rc.push(wasm.cstrToJs(oVfs.$zName)); - pVfs = oVfs.$pNext; - oVfs.dispose(); - } - return rc; - }; - - capi.sqlite3_js_db_export = function (pDb, schema = 0) { - pDb = wasm.xWrap.testConvertArg('sqlite3*', pDb); - if (!pDb) toss3('Invalid sqlite3* argument.'); - if (!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.'); - const scope = wasm.scopedAllocPush(); - let pOut; - try { - const pSize = wasm.scopedAlloc(8 + wasm.ptrSizeof); - const ppOut = pSize + 8; - - const zSchema = schema - ? wasm.isPtr(schema) - ? schema - : wasm.scopedAllocCString('' + schema) - : 0; - let rc = wasm.exports.sqlite3__wasm_db_serialize( - pDb, - zSchema, - ppOut, - pSize, - 0, - ); - if (rc) { - toss3( - 'Database serialization failed with code', - sqlite3.capi.sqlite3_js_rc_str(rc), - ); - } - pOut = wasm.peekPtr(ppOut); - const nOut = wasm.peek(pSize, 'i64'); - rc = nOut - ? wasm.heap8u().slice(pOut, pOut + Number(nOut)) - : new Uint8Array(); - return rc; - } finally { - if (pOut) wasm.exports.sqlite3_free(pOut); - wasm.scopedAllocPop(scope); - } - }; - - capi.sqlite3_js_db_vfs = (dbPointer, dbName = 0) => - util.sqlite3__wasm_db_vfs(dbPointer, dbName); - - capi.sqlite3_js_aggregate_context = (pCtx, n) => { - return ( - capi.sqlite3_aggregate_context(pCtx, n) || - (n - ? WasmAllocError.toss( - 'Cannot allocate', - n, - 'bytes for sqlite3_aggregate_context()', - ) - : 0) - ); - }; - - capi.sqlite3_js_posix_create_file = function (filename, data, dataLen) { - let pData; - if (data && wasm.isPtr(data)) { - pData = data; - } else if ( - data instanceof ArrayBuffer || - data instanceof Uint8Array - ) { - pData = wasm.allocFromTypedArray(data); - if (arguments.length < 3 || !util.isInt32(dataLen) || dataLen < 0) { - dataLen = data.byteLength; - } - } else { - SQLite3Error.toss( - 'Invalid 2nd argument for sqlite3_js_posix_create_file().', - ); - } - try { - if (!util.isInt32(dataLen) || dataLen < 0) { - SQLite3Error.toss( - 'Invalid 3rd argument for sqlite3_js_posix_create_file().', - ); - } - const rc = util.sqlite3__wasm_posix_create_file( - filename, - pData, - dataLen, - ); - if (rc) - SQLite3Error.toss( - 'Creation of file failed with sqlite3 result code', - capi.sqlite3_js_rc_str(rc), - ); - } finally { - wasm.dealloc(pData); - } - }; - - capi.sqlite3_js_vfs_create_file = function ( - vfs, - filename, - data, - dataLen, - ) { - config.warn( - 'sqlite3_js_vfs_create_file() is deprecated and', - 'should be avoided because it can lead to C-level crashes.', - 'See its documentation for alternative options.', - ); - let pData; - if (data) { - if (wasm.isPtr(data)) { - pData = data; - } else if (data instanceof ArrayBuffer) { - data = new Uint8Array(data); - } - if (data instanceof Uint8Array) { - pData = wasm.allocFromTypedArray(data); - if ( - arguments.length < 4 || - !util.isInt32(dataLen) || - dataLen < 0 - ) { - dataLen = data.byteLength; - } - } else { - SQLite3Error.toss( - 'Invalid 3rd argument type for sqlite3_js_vfs_create_file().', - ); - } - } else { - pData = 0; - } - if (!util.isInt32(dataLen) || dataLen < 0) { - wasm.dealloc(pData); - SQLite3Error.toss( - 'Invalid 4th argument for sqlite3_js_vfs_create_file().', - ); - } - try { - const rc = util.sqlite3__wasm_vfs_create_file( - vfs, - filename, - pData, - dataLen, - ); - if (rc) - SQLite3Error.toss( - 'Creation of file failed with sqlite3 result code', - capi.sqlite3_js_rc_str(rc), - ); - } finally { - wasm.dealloc(pData); - } - }; - - capi.sqlite3_js_sql_to_string = (sql) => { - if ('string' === typeof sql) { - return sql; - } - const x = flexibleString(v); - return x === v ? undefined : x; - }; - - if (util.isUIThread()) { - const __kvvfsInfo = function (which) { - const rc = Object.create(null); - rc.prefix = 'kvvfs-' + which; - rc.stores = []; - if ('session' === which || '' === which) - rc.stores.push(globalThis.sessionStorage); - if ('local' === which || '' === which) - rc.stores.push(globalThis.localStorage); - return rc; - }; - - capi.sqlite3_js_kvvfs_clear = function (which = '') { - let rc = 0; - const kvinfo = __kvvfsInfo(which); - kvinfo.stores.forEach((s) => { - const toRm = []; - let i; - for (i = 0; i < s.length; ++i) { - const k = s.key(i); - if (k.startsWith(kvinfo.prefix)) toRm.push(k); - } - toRm.forEach((kk) => s.removeItem(kk)); - rc += toRm.length; - }); - return rc; - }; - - capi.sqlite3_js_kvvfs_size = function (which = '') { - let sz = 0; - const kvinfo = __kvvfsInfo(which); - kvinfo.stores.forEach((s) => { - let i; - for (i = 0; i < s.length; ++i) { - const k = s.key(i); - if (k.startsWith(kvinfo.prefix)) { - sz += k.length; - sz += s.getItem(k).length; - } - } - }); - return sz * 2; - }; - } - - capi.sqlite3_db_config = function (pDb, op, ...args) { - if (!this.s) { - this.s = wasm.xWrap('sqlite3__wasm_db_config_s', 'int', [ - 'sqlite3*', - 'int', - 'string:static', - ]); - this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int', [ - 'sqlite3*', - 'int', - '*', - 'int', - 'int', - ]); - this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip', 'int', [ - 'sqlite3*', - 'int', - 'int', - '*', - ]); - } - switch (op) { - case capi.SQLITE_DBCONFIG_ENABLE_FKEY: - case capi.SQLITE_DBCONFIG_ENABLE_TRIGGER: - case capi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: - case capi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: - case capi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: - case capi.SQLITE_DBCONFIG_ENABLE_QPSG: - case capi.SQLITE_DBCONFIG_TRIGGER_EQP: - case capi.SQLITE_DBCONFIG_RESET_DATABASE: - case capi.SQLITE_DBCONFIG_DEFENSIVE: - case capi.SQLITE_DBCONFIG_WRITABLE_SCHEMA: - case capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: - case capi.SQLITE_DBCONFIG_DQS_DML: - case capi.SQLITE_DBCONFIG_DQS_DDL: - case capi.SQLITE_DBCONFIG_ENABLE_VIEW: - case capi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: - case capi.SQLITE_DBCONFIG_TRUSTED_SCHEMA: - case capi.SQLITE_DBCONFIG_STMT_SCANSTATUS: - case capi.SQLITE_DBCONFIG_REVERSE_SCANORDER: - return this.ip(pDb, op, args[0], args[1] || 0); - case capi.SQLITE_DBCONFIG_LOOKASIDE: - return this.pii(pDb, op, args[0], args[1], args[2]); - case capi.SQLITE_DBCONFIG_MAINDBNAME: - return this.s(pDb, op, args[0]); - default: - return capi.SQLITE_MISUSE; - } - }.bind(Object.create(null)); - - capi.sqlite3_value_to_js = function ( - pVal, - throwIfCannotConvert = true, - ) { - let arg; - const valType = capi.sqlite3_value_type(pVal); - switch (valType) { - case capi.SQLITE_INTEGER: - if (wasm.bigIntEnabled) { - arg = capi.sqlite3_value_int64(pVal); - if (util.bigIntFitsDouble(arg)) arg = Number(arg); - } else arg = capi.sqlite3_value_double(pVal); - break; - case capi.SQLITE_FLOAT: - arg = capi.sqlite3_value_double(pVal); - break; - case capi.SQLITE_TEXT: - arg = capi.sqlite3_value_text(pVal); - break; - case capi.SQLITE_BLOB: { - const n = capi.sqlite3_value_bytes(pVal); - const pBlob = capi.sqlite3_value_blob(pVal); - if (n && !pBlob) - sqlite3.WasmAllocError.toss( - 'Cannot allocate memory for blob argument of', - n, - 'byte(s)', - ); - arg = n ? wasm.heap8u().slice(pBlob, pBlob + Number(n)) : null; - break; - } - case capi.SQLITE_NULL: - arg = null; - break; - default: - if (throwIfCannotConvert) { - toss3( - capi.SQLITE_MISMATCH, - 'Unhandled sqlite3_value_type():', - valType, - ); - } - arg = undefined; - } - return arg; - }; - - capi.sqlite3_values_to_js = function ( - argc, - pArgv, - throwIfCannotConvert = true, - ) { - let i; - const tgt = []; - for (i = 0; i < argc; ++i) { - tgt.push( - capi.sqlite3_value_to_js( - wasm.peekPtr(pArgv + wasm.ptrSizeof * i), - throwIfCannotConvert, - ), - ); - } - return tgt; - }; - - capi.sqlite3_result_error_js = function (pCtx, e) { - if (e instanceof WasmAllocError) { - capi.sqlite3_result_error_nomem(pCtx); - } else { - capi.sqlite3_result_error(pCtx, '' + e, -1); - } - }; - - capi.sqlite3_result_js = function (pCtx, val) { - if (val instanceof Error) { - capi.sqlite3_result_error_js(pCtx, val); - return; - } - try { - switch (typeof val) { - case 'undefined': - break; - case 'boolean': - capi.sqlite3_result_int(pCtx, val ? 1 : 0); - break; - case 'bigint': - if (util.bigIntFits32(val)) { - capi.sqlite3_result_int(pCtx, Number(val)); - } else if (util.bigIntFitsDouble(val)) { - capi.sqlite3_result_double(pCtx, Number(val)); - } else if (wasm.bigIntEnabled) { - if (util.bigIntFits64(val)) - capi.sqlite3_result_int64(pCtx, val); - else - toss3( - 'BigInt value', - val.toString(), - 'is too BigInt for int64.', - ); - } else { - toss3('BigInt value', val.toString(), 'is too BigInt.'); - } - break; - case 'number': { - let f; - if (util.isInt32(val)) { - f = capi.sqlite3_result_int; - } else if ( - wasm.bigIntEnabled && - Number.isInteger(val) && - util.bigIntFits64(BigInt(val)) - ) { - f = capi.sqlite3_result_int64; - } else { - f = capi.sqlite3_result_double; - } - f(pCtx, val); - break; - } - case 'string': { - const [p, n] = wasm.allocCString(val, true); - capi.sqlite3_result_text(pCtx, p, n, capi.SQLITE_WASM_DEALLOC); - break; - } - case 'object': - if (null === val) { - capi.sqlite3_result_null(pCtx); - break; - } else if (util.isBindableTypedArray(val)) { - const pBlob = wasm.allocFromTypedArray(val); - capi.sqlite3_result_blob( - pCtx, - pBlob, - val.byteLength, - capi.SQLITE_WASM_DEALLOC, - ); - break; - } - - default: - toss3( - "Don't not how to handle this UDF result value:", - typeof val, - val, - ); - } - } catch (e) { - capi.sqlite3_result_error_js(pCtx, e); - } - }; - - capi.sqlite3_column_js = function ( - pStmt, - iCol, - throwIfCannotConvert = true, - ) { - const v = capi.sqlite3_column_value(pStmt, iCol); - return 0 === v - ? undefined - : capi.sqlite3_value_to_js(v, throwIfCannotConvert); - }; - - const __newOldValue = function (pObj, iCol, impl) { - impl = capi[impl]; - if (!this.ptr) this.ptr = wasm.allocPtr(); - else wasm.pokePtr(this.ptr, 0); - const rc = impl(pObj, iCol, this.ptr); - if (rc) - return SQLite3Error.toss( - rc, - arguments[2] + '() failed with code ' + rc, - ); - const pv = wasm.peekPtr(this.ptr); - return pv ? capi.sqlite3_value_to_js(pv, true) : undefined; - }.bind(Object.create(null)); - - capi.sqlite3_preupdate_new_js = (pDb, iCol) => - __newOldValue(pDb, iCol, 'sqlite3_preupdate_new'); - - capi.sqlite3_preupdate_old_js = (pDb, iCol) => - __newOldValue(pDb, iCol, 'sqlite3_preupdate_old'); - - capi.sqlite3changeset_new_js = (pChangesetIter, iCol) => - __newOldValue(pChangesetIter, iCol, 'sqlite3changeset_new'); - - capi.sqlite3changeset_old_js = (pChangesetIter, iCol) => - __newOldValue(pChangesetIter, iCol, 'sqlite3changeset_old'); - - const sqlite3 = { - WasmAllocError: WasmAllocError, - SQLite3Error: SQLite3Error, - capi, - util, - wasm, - config, - - version: Object.create(null), - - client: undefined, - - asyncPostInit: async function ff() { - if (ff.isReady instanceof Promise) return ff.isReady; - let lia = sqlite3ApiBootstrap.initializersAsync; - delete sqlite3ApiBootstrap.initializersAsync; - const postInit = async () => { - if (!sqlite3.__isUnderTest) { - delete sqlite3.util; - - delete sqlite3.StructBinder; - } - return sqlite3; - }; - const catcher = (e) => { - config.error('an async sqlite3 initializer failed:', e); - throw e; - }; - if (!lia || !lia.length) { - return (ff.isReady = postInit().catch(catcher)); - } - lia = lia.map((f) => { - return f instanceof Function ? async (x) => f(sqlite3) : f; - }); - lia.push(postInit); - let p = Promise.resolve(sqlite3); - while (lia.length) p = p.then(lia.shift()); - return (ff.isReady = p.catch(catcher)); - }, - - scriptInfo: undefined, - }; - try { - sqlite3ApiBootstrap.initializers.forEach((f) => { - f(sqlite3); - }); - } catch (e) { - console.error('sqlite3 bootstrap initializer threw:', e); - throw e; - } - delete sqlite3ApiBootstrap.initializers; - sqlite3ApiBootstrap.sqlite3 = sqlite3; - return sqlite3; - }; - - globalThis.sqlite3ApiBootstrap.initializers = []; - - globalThis.sqlite3ApiBootstrap.initializersAsync = []; - - globalThis.sqlite3ApiBootstrap.defaultConfig = Object.create(null); - - globalThis.sqlite3ApiBootstrap.sqlite3 = undefined; - - globalThis.WhWasmUtilInstaller = function (target) { - if (undefined === target.bigIntEnabled) { - target.bigIntEnabled = !!globalThis['BigInt64Array']; - } - - const toss = (...args) => { - throw new Error(args.join(' ')); - }; - - if (!target.exports) { - Object.defineProperty(target, 'exports', { - enumerable: true, - configurable: true, - get: () => target.instance && target.instance.exports, - }); - } - - const ptrIR = target.pointerIR || 'i32'; - const ptrSizeof = (target.ptrSizeof = - 'i32' === ptrIR - ? 4 - : 'i64' === ptrIR - ? 8 - : toss('Unhandled ptrSizeof:', ptrIR)); - - const cache = Object.create(null); - - cache.heapSize = 0; - - cache.memory = null; - - cache.freeFuncIndexes = []; - - cache.scopedAlloc = []; - - cache.utf8Decoder = new TextDecoder(); - cache.utf8Encoder = new TextEncoder('utf-8'); - - target.sizeofIR = (n) => { - switch (n) { - case 'i8': - return 1; - case 'i16': - return 2; - case 'i32': - case 'f32': - case 'float': - return 4; - case 'i64': - case 'f64': - case 'double': - return 8; - case '*': - return ptrSizeof; - default: - return ('' + n).endsWith('*') ? ptrSizeof : undefined; - } - }; - - const heapWrappers = function () { - if (!cache.memory) { - cache.memory = - target.memory instanceof WebAssembly.Memory - ? target.memory - : target.exports.memory; - } else if (cache.heapSize === cache.memory.buffer.byteLength) { - return cache; - } - - const b = cache.memory.buffer; - cache.HEAP8 = new Int8Array(b); - cache.HEAP8U = new Uint8Array(b); - cache.HEAP16 = new Int16Array(b); - cache.HEAP16U = new Uint16Array(b); - cache.HEAP32 = new Int32Array(b); - cache.HEAP32U = new Uint32Array(b); - if (target.bigIntEnabled) { - cache.HEAP64 = new BigInt64Array(b); - cache.HEAP64U = new BigUint64Array(b); - } - cache.HEAP32F = new Float32Array(b); - cache.HEAP64F = new Float64Array(b); - cache.heapSize = b.byteLength; - return cache; - }; - - target.heap8 = () => heapWrappers().HEAP8; - - target.heap8u = () => heapWrappers().HEAP8U; - - target.heap16 = () => heapWrappers().HEAP16; - - target.heap16u = () => heapWrappers().HEAP16U; - - target.heap32 = () => heapWrappers().HEAP32; - - target.heap32u = () => heapWrappers().HEAP32U; - - target.heapForSize = function (n, unsigned = true) { - const c = - cache.memory && cache.heapSize === cache.memory.buffer.byteLength - ? cache - : heapWrappers(); - switch (n) { - case Int8Array: - return c.HEAP8; - case Uint8Array: - return c.HEAP8U; - case Int16Array: - return c.HEAP16; - case Uint16Array: - return c.HEAP16U; - case Int32Array: - return c.HEAP32; - case Uint32Array: - return c.HEAP32U; - case 8: - return unsigned ? c.HEAP8U : c.HEAP8; - case 16: - return unsigned ? c.HEAP16U : c.HEAP16; - case 32: - return unsigned ? c.HEAP32U : c.HEAP32; - case 64: - if (c.HEAP64) return unsigned ? c.HEAP64U : c.HEAP64; - break; - default: - if (target.bigIntEnabled) { - if (n === globalThis['BigUint64Array']) return c.HEAP64U; - else if (n === globalThis['BigInt64Array']) return c.HEAP64; - break; - } - } - toss( - 'Invalid heapForSize() size: expecting 8, 16, 32,', - 'or (if BigInt is enabled) 64.', - ); - }; - - target.functionTable = function () { - return target.exports.__indirect_function_table; - }; - - target.functionEntry = function (fptr) { - const ft = target.functionTable(); - return fptr < ft.length ? ft.get(fptr) : undefined; - }; - - target.jsFuncToWasm = function f(func, sig) { - if (!f._) { - f._ = { - sigTypes: Object.assign(Object.create(null), { - i: 'i32', - p: 'i32', - P: 'i32', - s: 'i32', - j: 'i64', - f: 'f32', - d: 'f64', - }), - - typeCodes: Object.assign(Object.create(null), { - f64: 0x7c, - f32: 0x7d, - i64: 0x7e, - i32: 0x7f, - }), - - uleb128Encode: function (tgt, method, n) { - if (n < 128) tgt[method](n); - else tgt[method](n % 128 | 128, n >> 7); - }, - - rxJSig: /^(\w)\((\w*)\)$/, - - sigParams: function (sig) { - const m = f._.rxJSig.exec(sig); - return m ? m[2] : sig.substr(1); - }, - - letterType: (x) => - f._.sigTypes[x] || toss('Invalid signature letter:', x), - - pushSigType: (dest, letter) => - dest.push(f._.typeCodes[f._.letterType(letter)]), - }; - } - if ('string' === typeof func) { - const x = sig; - sig = func; - func = x; - } - const sigParams = f._.sigParams(sig); - const wasmCode = [0x01, 0x60]; - f._.uleb128Encode(wasmCode, 'push', sigParams.length); - for (const x of sigParams) f._.pushSigType(wasmCode, x); - if ('v' === sig[0]) wasmCode.push(0); - else { - wasmCode.push(1); - f._.pushSigType(wasmCode, sig[0]); - } - f._.uleb128Encode(wasmCode, 'unshift', wasmCode.length); - wasmCode.unshift( - 0x00, - 0x61, - 0x73, - 0x6d, - 0x01, - 0x00, - 0x00, - 0x00, - 0x01, - ); - wasmCode.push( - 0x02, - 0x07, - - 0x01, - 0x01, - 0x65, - 0x01, - 0x66, - 0x00, - 0x00, - 0x07, - 0x05, - - 0x01, - 0x01, - 0x66, - 0x00, - 0x00, - ); - return new WebAssembly.Instance( - new WebAssembly.Module(new Uint8Array(wasmCode)), - { - e: { f: func }, - }, - ).exports['f']; - }; - - const __installFunction = function f(func, sig, scoped) { - if (scoped && !cache.scopedAlloc.length) { - toss('No scopedAllocPush() scope is active.'); - } - if ('string' === typeof func) { - const x = sig; - sig = func; - func = x; - } - if ('string' !== typeof sig || !(func instanceof Function)) { - toss( - 'Invalid arguments: expecting (function,signature) ' + - 'or (signature,function).', - ); - } - const ft = target.functionTable(); - const oldLen = ft.length; - let ptr; - while (cache.freeFuncIndexes.length) { - ptr = cache.freeFuncIndexes.pop(); - if (ft.get(ptr)) { - ptr = null; - continue; - } else { - break; - } - } - if (!ptr) { - ptr = oldLen; - ft.grow(1); - } - try { - ft.set(ptr, func); - if (scoped) { - cache.scopedAlloc[cache.scopedAlloc.length - 1].push(ptr); - } - return ptr; - } catch (e) { - if (!(e instanceof TypeError)) { - if (ptr === oldLen) cache.freeFuncIndexes.push(oldLen); - throw e; - } - } - - try { - const fptr = target.jsFuncToWasm(func, sig); - ft.set(ptr, fptr); - if (scoped) { - cache.scopedAlloc[cache.scopedAlloc.length - 1].push(ptr); - } - } catch (e) { - if (ptr === oldLen) cache.freeFuncIndexes.push(oldLen); - throw e; - } - return ptr; - }; - - target.installFunction = (func, sig) => - __installFunction(func, sig, false); - - target.scopedInstallFunction = (func, sig) => - __installFunction(func, sig, true); - - target.uninstallFunction = function (ptr) { - if (!ptr && 0 !== ptr) return undefined; - const fi = cache.freeFuncIndexes; - const ft = target.functionTable(); - fi.push(ptr); - const rc = ft.get(ptr); - ft.set(ptr, null); - return rc; - }; - - target.peek = function f(ptr, type = 'i8') { - if (type.endsWith('*')) type = ptrIR; - const c = - cache.memory && cache.heapSize === cache.memory.buffer.byteLength - ? cache - : heapWrappers(); - const list = Array.isArray(ptr) ? [] : undefined; - let rc; - do { - if (list) ptr = arguments[0].shift(); - switch (type) { - case 'i1': - case 'i8': - rc = c.HEAP8[ptr >> 0]; - break; - case 'i16': - rc = c.HEAP16[ptr >> 1]; - break; - case 'i32': - rc = c.HEAP32[ptr >> 2]; - break; - case 'float': - case 'f32': - rc = c.HEAP32F[ptr >> 2]; - break; - case 'double': - case 'f64': - rc = Number(c.HEAP64F[ptr >> 3]); - break; - case 'i64': - if (target.bigIntEnabled) { - rc = BigInt(c.HEAP64[ptr >> 3]); - break; - } - - default: - toss('Invalid type for peek():', type); - } - if (list) list.push(rc); - } while (list && arguments[0].length); - return list || rc; - }; - - target.poke = function (ptr, value, type = 'i8') { - if (type.endsWith('*')) type = ptrIR; - const c = - cache.memory && cache.heapSize === cache.memory.buffer.byteLength - ? cache - : heapWrappers(); - for (const p of Array.isArray(ptr) ? ptr : [ptr]) { - switch (type) { - case 'i1': - case 'i8': - c.HEAP8[p >> 0] = value; - continue; - case 'i16': - c.HEAP16[p >> 1] = value; - continue; - case 'i32': - c.HEAP32[p >> 2] = value; - continue; - case 'float': - case 'f32': - c.HEAP32F[p >> 2] = value; - continue; - case 'double': - case 'f64': - c.HEAP64F[p >> 3] = value; - continue; - case 'i64': - if (c.HEAP64) { - c.HEAP64[p >> 3] = BigInt(value); - continue; - } - - default: - toss('Invalid type for poke(): ' + type); - } - } - return this; - }; - - target.peekPtr = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, ptrIR); - - target.pokePtr = (ptr, value = 0) => target.poke(ptr, value, ptrIR); - - target.peek8 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'i8'); - - target.poke8 = (ptr, value) => target.poke(ptr, value, 'i8'); - - target.peek16 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'i16'); - - target.poke16 = (ptr, value) => target.poke(ptr, value, 'i16'); - - target.peek32 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'i32'); - - target.poke32 = (ptr, value) => target.poke(ptr, value, 'i32'); - - target.peek64 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'i64'); - - target.poke64 = (ptr, value) => target.poke(ptr, value, 'i64'); - - target.peek32f = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'f32'); - - target.poke32f = (ptr, value) => target.poke(ptr, value, 'f32'); - - target.peek64f = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'f64'); - - target.poke64f = (ptr, value) => target.poke(ptr, value, 'f64'); - - target.getMemValue = target.peek; - - target.getPtrValue = target.peekPtr; - - target.setMemValue = target.poke; - - target.setPtrValue = target.pokePtr; - - target.isPtr32 = (ptr) => - 'number' === typeof ptr && ptr === (ptr | 0) && ptr >= 0; - - target.isPtr = target.isPtr32; - - target.cstrlen = function (ptr) { - if (!ptr || !target.isPtr(ptr)) return null; - const h = heapWrappers().HEAP8U; - let pos = ptr; - for (; h[pos] !== 0; ++pos) {} - return pos - ptr; - }; - - const __SAB = - 'undefined' === typeof SharedArrayBuffer - ? function () {} - : SharedArrayBuffer; - const __utf8Decode = function (arrayBuffer, begin, end) { - return cache.utf8Decoder.decode( - arrayBuffer.buffer instanceof __SAB - ? arrayBuffer.slice(begin, end) - : arrayBuffer.subarray(begin, end), - ); - }; - - target.cstrToJs = function (ptr) { - const n = target.cstrlen(ptr); - return n - ? __utf8Decode(heapWrappers().HEAP8U, ptr, ptr + n) - : null === n - ? n - : ''; - }; - - target.jstrlen = function (str) { - if ('string' !== typeof str) return null; - const n = str.length; - let len = 0; - for (let i = 0; i < n; ++i) { - let u = str.charCodeAt(i); - if (u >= 0xd800 && u <= 0xdfff) { - u = - (0x10000 + ((u & 0x3ff) << 10)) | (str.charCodeAt(++i) & 0x3ff); - } - if (u <= 0x7f) ++len; - else if (u <= 0x7ff) len += 2; - else if (u <= 0xffff) len += 3; - else len += 4; - } - return len; - }; - - target.jstrcpy = function ( - jstr, - tgt, - offset = 0, - maxBytes = -1, - addNul = true, - ) { - if ( - !tgt || - (!(tgt instanceof Int8Array) && !(tgt instanceof Uint8Array)) - ) { - toss('jstrcpy() target must be an Int8Array or Uint8Array.'); - } - if (maxBytes < 0) maxBytes = tgt.length - offset; - if (!(maxBytes > 0) || !(offset >= 0)) return 0; - let i = 0, - max = jstr.length; - const begin = offset, - end = offset + maxBytes - (addNul ? 1 : 0); - for (; i < max && offset < end; ++i) { - let u = jstr.charCodeAt(i); - if (u >= 0xd800 && u <= 0xdfff) { - u = - (0x10000 + ((u & 0x3ff) << 10)) | - (jstr.charCodeAt(++i) & 0x3ff); - } - if (u <= 0x7f) { - if (offset >= end) break; - tgt[offset++] = u; - } else if (u <= 0x7ff) { - if (offset + 1 >= end) break; - tgt[offset++] = 0xc0 | (u >> 6); - tgt[offset++] = 0x80 | (u & 0x3f); - } else if (u <= 0xffff) { - if (offset + 2 >= end) break; - tgt[offset++] = 0xe0 | (u >> 12); - tgt[offset++] = 0x80 | ((u >> 6) & 0x3f); - tgt[offset++] = 0x80 | (u & 0x3f); - } else { - if (offset + 3 >= end) break; - tgt[offset++] = 0xf0 | (u >> 18); - tgt[offset++] = 0x80 | ((u >> 12) & 0x3f); - tgt[offset++] = 0x80 | ((u >> 6) & 0x3f); - tgt[offset++] = 0x80 | (u & 0x3f); - } - } - if (addNul) tgt[offset++] = 0; - return offset - begin; - }; - - target.cstrncpy = function (tgtPtr, srcPtr, n) { - if (!tgtPtr || !srcPtr) - toss('cstrncpy() does not accept NULL strings.'); - if (n < 0) n = target.cstrlen(strPtr) + 1; - else if (!(n > 0)) return 0; - const heap = target.heap8u(); - let i = 0, - ch; - for (; i < n && (ch = heap[srcPtr + i]); ++i) { - heap[tgtPtr + i] = ch; - } - if (i < n) heap[tgtPtr + i++] = 0; - return i; - }; - - target.jstrToUintArray = (str, addNul = false) => { - return cache.utf8Encoder.encode(addNul ? str + '\0' : str); - }; - - const __affirmAlloc = (obj, funcName) => { - if ( - !(obj.alloc instanceof Function) || - !(obj.dealloc instanceof Function) - ) { - toss( - 'Object is missing alloc() and/or dealloc() function(s)', - 'required by', - funcName + '().', - ); - } - }; - - const __allocCStr = function ( - jstr, - returnWithLength, - allocator, - funcName, - ) { - __affirmAlloc(target, funcName); - if ('string' !== typeof jstr) return null; - { - const u = cache.utf8Encoder.encode(jstr), - ptr = allocator(u.length + 1), - heap = heapWrappers().HEAP8U; - heap.set(u, ptr); - heap[ptr + u.length] = 0; - return returnWithLength ? [ptr, u.length] : ptr; - } - }; - - target.allocCString = (jstr, returnWithLength = false) => - __allocCStr(jstr, returnWithLength, target.alloc, 'allocCString()'); - - target.scopedAllocPush = function () { - __affirmAlloc(target, 'scopedAllocPush'); - const a = []; - cache.scopedAlloc.push(a); - return a; - }; - - target.scopedAllocPop = function (state) { - __affirmAlloc(target, 'scopedAllocPop'); - const n = arguments.length - ? cache.scopedAlloc.indexOf(state) - : cache.scopedAlloc.length - 1; - if (n < 0) toss('Invalid state object for scopedAllocPop().'); - if (0 === arguments.length) state = cache.scopedAlloc[n]; - cache.scopedAlloc.splice(n, 1); - for (let p; (p = state.pop()); ) { - if (target.functionEntry(p)) { - target.uninstallFunction(p); - } else target.dealloc(p); - } - }; - - target.scopedAlloc = function (n) { - if (!cache.scopedAlloc.length) { - toss('No scopedAllocPush() scope is active.'); - } - const p = target.alloc(n); - cache.scopedAlloc[cache.scopedAlloc.length - 1].push(p); - return p; - }; - - Object.defineProperty(target.scopedAlloc, 'level', { - configurable: false, - enumerable: false, - get: () => cache.scopedAlloc.length, - set: () => toss("The 'active' property is read-only."), - }); - - target.scopedAllocCString = (jstr, returnWithLength = false) => - __allocCStr( - jstr, - returnWithLength, - target.scopedAlloc, - 'scopedAllocCString()', - ); - - const __allocMainArgv = function (isScoped, list) { - const pList = target[isScoped ? 'scopedAlloc' : 'alloc']( - (list.length + 1) * target.ptrSizeof, - ); - let i = 0; - list.forEach((e) => { - target.pokePtr( - pList + target.ptrSizeof * i++, - target[isScoped ? 'scopedAllocCString' : 'allocCString']('' + e), - ); - }); - target.pokePtr(pList + target.ptrSizeof * i, 0); - return pList; - }; - - target.scopedAllocMainArgv = (list) => __allocMainArgv(true, list); - - target.allocMainArgv = (list) => __allocMainArgv(false, list); - - target.cArgvToJs = (argc, pArgv) => { - const list = []; - for (let i = 0; i < argc; ++i) { - const arg = target.peekPtr(pArgv + target.ptrSizeof * i); - list.push(arg ? target.cstrToJs(arg) : null); - } - return list; - }; - - target.scopedAllocCall = function (func) { - target.scopedAllocPush(); - try { - return func(); - } finally { - target.scopedAllocPop(); - } - }; - - const __allocPtr = function (howMany, safePtrSize, method) { - __affirmAlloc(target, method); - const pIr = safePtrSize ? 'i64' : ptrIR; - let m = target[method](howMany * (safePtrSize ? 8 : ptrSizeof)); - target.poke(m, 0, pIr); - if (1 === howMany) { - return m; - } - const a = [m]; - for (let i = 1; i < howMany; ++i) { - m += safePtrSize ? 8 : ptrSizeof; - a[i] = m; - target.poke(m, 0, pIr); - } - return a; - }; - - target.allocPtr = (howMany = 1, safePtrSize = true) => - __allocPtr(howMany, safePtrSize, 'alloc'); - - target.scopedAllocPtr = (howMany = 1, safePtrSize = true) => - __allocPtr(howMany, safePtrSize, 'scopedAlloc'); - - target.xGet = function (name) { - return ( - target.exports[name] || toss('Cannot find exported symbol:', name) - ); - }; - - const __argcMismatch = (f, n) => - toss(f + '() requires', n, 'argument(s).'); - - target.xCall = function (fname, ...args) { - const f = fname instanceof Function ? fname : target.xGet(fname); - if (!(f instanceof Function)) - toss('Exported symbol', fname, 'is not a function.'); - if (f.length !== args.length) - __argcMismatch(f === fname ? f.name : fname, f.length); - return 2 === arguments.length && Array.isArray(arguments[1]) - ? f.apply(null, arguments[1]) - : f.apply(null, args); - }; - - cache.xWrap = Object.create(null); - cache.xWrap.convert = Object.create(null); - - cache.xWrap.convert.arg = new Map(); - - cache.xWrap.convert.result = new Map(); - const xArg = cache.xWrap.convert.arg, - xResult = cache.xWrap.convert.result; - - if (target.bigIntEnabled) { - xArg.set('i64', (i) => BigInt(i)); - } - const __xArgPtr = - 'i32' === ptrIR ? (i) => i | 0 : (i) => BigInt(i) | BigInt(0); - xArg - .set('i32', __xArgPtr) - .set('i16', (i) => (i | 0) & 0xffff) - .set('i8', (i) => (i | 0) & 0xff) - .set('f32', (i) => Number(i).valueOf()) - .set('float', xArg.get('f32')) - .set('f64', xArg.get('f32')) - .set('double', xArg.get('f64')) - .set('int', xArg.get('i32')) - .set('null', (i) => i) - .set(null, xArg.get('null')) - .set('**', __xArgPtr) - .set('*', __xArgPtr); - xResult - .set('*', __xArgPtr) - .set('pointer', __xArgPtr) - .set('number', (v) => Number(v)) - .set('void', (v) => undefined) - .set('null', (v) => v) - .set(null, xResult.get('null')); - - { - const copyToResult = [ - 'i8', - 'i16', - 'i32', - 'int', - 'f32', - 'float', - 'f64', - 'double', - ]; - if (target.bigIntEnabled) copyToResult.push('i64'); - const adaptPtr = xArg.get(ptrIR); - for (const t of copyToResult) { - xArg.set(t + '*', adaptPtr); - xResult.set(t + '*', adaptPtr); - xResult.set(t, xArg.get(t) || toss('Missing arg converter:', t)); - } - } - - const __xArgString = function (v) { - if ('string' === typeof v) return target.scopedAllocCString(v); - return v ? __xArgPtr(v) : null; - }; - xArg - .set('string', __xArgString) - .set('utf8', __xArgString) - .set('pointer', __xArgString); - - xResult - .set('string', (i) => target.cstrToJs(i)) - .set('utf8', xResult.get('string')) - .set('string:dealloc', (i) => { - try { - return i ? target.cstrToJs(i) : null; - } finally { - target.dealloc(i); - } - }) - .set('utf8:dealloc', xResult.get('string:dealloc')) - .set('json', (i) => JSON.parse(target.cstrToJs(i))) - .set('json:dealloc', (i) => { - try { - return i ? JSON.parse(target.cstrToJs(i)) : null; - } finally { - target.dealloc(i); - } - }); - - const AbstractArgAdapter = class { - constructor(opt) { - this.name = opt.name || 'unnamed adapter'; - } - - convertArg(v, argv, argIndex) { - toss('AbstractArgAdapter must be subclassed.'); - } - }; - - xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter { - constructor(opt) { - super(opt); - if (xArg.FuncPtrAdapter.warnOnUse) { - console.warn( - 'xArg.FuncPtrAdapter is an internal-only API', - 'and is not intended to be invoked from', - 'client-level code. Invoked with:', - opt, - ); - } - this.name = opt.name || 'unnamed'; - this.signature = opt.signature; - if (opt.contextKey instanceof Function) { - this.contextKey = opt.contextKey; - if (!opt.bindScope) opt.bindScope = 'context'; - } - this.bindScope = - opt.bindScope || - toss( - 'FuncPtrAdapter options requires a bindScope (explicit or implied).', - ); - if (FuncPtrAdapter.bindScopes.indexOf(opt.bindScope) < 0) { - toss( - 'Invalid options.bindScope (' + - opt.bindMod + - ') for FuncPtrAdapter. ' + - 'Expecting one of: (' + - FuncPtrAdapter.bindScopes.join(', ') + - ')', - ); - } - this.isTransient = 'transient' === this.bindScope; - this.isContext = 'context' === this.bindScope; - this.isPermanent = 'permanent' === this.bindScope; - this.singleton = 'singleton' === this.bindScope ? [] : undefined; - - this.callProxy = - opt.callProxy instanceof Function ? opt.callProxy : undefined; - } - - contextKey(argv, argIndex) { - return this; - } - - contextMap(key) { - const cm = this.__cmap || (this.__cmap = new Map()); - let rc = cm.get(key); - if (undefined === rc) cm.set(key, (rc = [])); - return rc; - } - - convertArg(v, argv, argIndex) { - let pair = this.singleton; - if (!pair && this.isContext) { - pair = this.contextMap(this.contextKey(argv, argIndex)); - } - if (pair && pair[0] === v) return pair[1]; - if (v instanceof Function) { - if (this.callProxy) v = this.callProxy(v); - const fp = __installFunction(v, this.signature, this.isTransient); - if (FuncPtrAdapter.debugFuncInstall) { - FuncPtrAdapter.debugOut( - 'FuncPtrAdapter installed', - this, - this.contextKey(argv, argIndex), - '@' + fp, - v, - ); - } - if (pair) { - if (pair[1]) { - if (FuncPtrAdapter.debugFuncInstall) { - FuncPtrAdapter.debugOut( - 'FuncPtrAdapter uninstalling', - this, - this.contextKey(argv, argIndex), - '@' + pair[1], - v, - ); - } - try { - cache.scopedAlloc[cache.scopedAlloc.length - 1].push( - pair[1], - ); - } catch (e) {} - } - pair[0] = v; - pair[1] = fp; - } - return fp; - } else if (target.isPtr(v) || null === v || undefined === v) { - if (pair && pair[1] && pair[1] !== v) { - if (FuncPtrAdapter.debugFuncInstall) { - FuncPtrAdapter.debugOut( - 'FuncPtrAdapter uninstalling', - this, - this.contextKey(argv, argIndex), - '@' + pair[1], - v, - ); - } - try { - cache.scopedAlloc[cache.scopedAlloc.length - 1].push(pair[1]); - } catch (e) {} - pair[0] = pair[1] = v | 0; - } - return v || 0; - } else { - throw new TypeError( - 'Invalid FuncPtrAdapter argument type. ' + - 'Expecting a function pointer or a ' + - (this.name ? this.name + ' ' : '') + - 'function matching signature ' + - this.signature + - '.', - ); - } - } - }; - - xArg.FuncPtrAdapter.warnOnUse = false; - - xArg.FuncPtrAdapter.debugFuncInstall = false; - - xArg.FuncPtrAdapter.debugOut = console.debug.bind(console); - - xArg.FuncPtrAdapter.bindScopes = [ - 'transient', - 'context', - 'singleton', - 'permanent', - ]; - - const __xArgAdapterCheck = (t) => - xArg.get(t) || toss('Argument adapter not found:', t); - - const __xResultAdapterCheck = (t) => - xResult.get(t) || toss('Result adapter not found:', t); - - cache.xWrap.convertArg = (t, ...args) => __xArgAdapterCheck(t)(...args); - - cache.xWrap.convertArgNoCheck = (t, ...args) => xArg.get(t)(...args); - - cache.xWrap.convertResult = (t, v) => - null === t ? v : t ? __xResultAdapterCheck(t)(v) : undefined; - - cache.xWrap.convertResultNoCheck = (t, v) => - null === t ? v : t ? xResult.get(t)(v) : undefined; - - target.xWrap = function (fArg, resultType, ...argTypes) { - if (3 === arguments.length && Array.isArray(arguments[2])) { - argTypes = arguments[2]; - } - if (target.isPtr(fArg)) { - fArg = - target.functionEntry(fArg) || - toss('Function pointer not found in WASM function table.'); - } - const fIsFunc = fArg instanceof Function; - const xf = fIsFunc ? fArg : target.xGet(fArg); - if (fIsFunc) fArg = xf.name || 'unnamed function'; - if (argTypes.length !== xf.length) __argcMismatch(fArg, xf.length); - if (null === resultType && 0 === xf.length) { - return xf; - } - if (undefined !== resultType && null !== resultType) - __xResultAdapterCheck(resultType); - for (const t of argTypes) { - if (t instanceof AbstractArgAdapter) - xArg.set(t, (...args) => t.convertArg(...args)); - else __xArgAdapterCheck(t); - } - const cxw = cache.xWrap; - if (0 === xf.length) { - return (...args) => - args.length - ? __argcMismatch(fArg, xf.length) - : cxw.convertResult(resultType, xf.call(null)); - } - return function (...args) { - if (args.length !== xf.length) __argcMismatch(fArg, xf.length); - const scope = target.scopedAllocPush(); - try { - let i = 0; - for (; i < args.length; ++i) - args[i] = cxw.convertArgNoCheck(argTypes[i], args[i], args, i); - return cxw.convertResultNoCheck(resultType, xf.apply(null, args)); - } finally { - target.scopedAllocPop(scope); - } - }; - }; - - const __xAdapter = function ( - func, - argc, - typeName, - adapter, - modeName, - xcvPart, - ) { - if ('string' === typeof typeName) { - if (1 === argc) return xcvPart.get(typeName); - else if (2 === argc) { - if (!adapter) { - delete xcvPart.get(typeName); - return func; - } else if (!(adapter instanceof Function)) { - toss(modeName, 'requires a function argument.'); - } - xcvPart.set(typeName, adapter); - return func; - } - } - toss('Invalid arguments to', modeName); - }; - - target.xWrap.resultAdapter = function f(typeName, adapter) { - return __xAdapter( - f, - arguments.length, - typeName, - adapter, - 'resultAdapter()', - xResult, - ); - }; - - target.xWrap.argAdapter = function f(typeName, adapter) { - return __xAdapter( - f, - arguments.length, - typeName, - adapter, - 'argAdapter()', - xArg, - ); - }; - - target.xWrap.FuncPtrAdapter = xArg.FuncPtrAdapter; - - target.xCallWrapped = function (fArg, resultType, argTypes, ...args) { - if (Array.isArray(arguments[3])) args = arguments[3]; - return target - .xWrap(fArg, resultType, argTypes || []) - .apply(null, args || []); - }; - - target.xWrap.testConvertArg = cache.xWrap.convertArg; - - target.xWrap.testConvertResult = cache.xWrap.convertResult; - - return target; - }; - - globalThis.WhWasmUtilInstaller.yawl = function (config) { - const wfetch = () => fetch(config.uri, { credentials: 'same-origin' }); - const wui = this; - const finalThen = function (arg) { - if (config.wasmUtilTarget) { - const toss = (...args) => { - throw new Error(args.join(' ')); - }; - const tgt = config.wasmUtilTarget; - tgt.module = arg.module; - tgt.instance = arg.instance; - - if (!tgt.instance.exports.memory) { - tgt.memory = - (config.imports && - config.imports.env && - config.imports.env.memory) || - toss("Missing 'memory' object!"); - } - if (!tgt.alloc && arg.instance.exports.malloc) { - const exports = arg.instance.exports; - tgt.alloc = function (n) { - return ( - exports.malloc(n) || toss('Allocation of', n, 'bytes failed.') - ); - }; - tgt.dealloc = function (m) { - exports.free(m); - }; - } - wui(tgt); - } - if (config.onload) config.onload(arg, config); - return arg; - }; - const loadWasm = WebAssembly.instantiateStreaming - ? function loadWasmStreaming() { - return WebAssembly.instantiateStreaming( - wfetch(), - config.imports || {}, - ).then(finalThen); - } - : function loadWasmOldSchool() { - return wfetch() - .then((response) => response.arrayBuffer()) - .then((bytes) => - WebAssembly.instantiate(bytes, config.imports || {}), - ) - .then(finalThen); - }; - return loadWasm; - }.bind(globalThis.WhWasmUtilInstaller); - globalThis.Jaccwabyt = function StructBinderFactory(config) { - const toss = (...args) => { - throw new Error(args.join(' ')); - }; - - if ( - !(config.heap instanceof WebAssembly.Memory) && - !(config.heap instanceof Function) - ) { - toss( - 'config.heap must be WebAssembly.Memory instance or a function.', - ); - } - ['alloc', 'dealloc'].forEach(function (k) { - config[k] instanceof Function || - toss("Config option '" + k + "' must be a function."); - }); - const SBF = StructBinderFactory; - const heap = - config.heap instanceof Function - ? config.heap - : () => new Uint8Array(config.heap.buffer), - alloc = config.alloc, - dealloc = config.dealloc, - log = config.log || console.log.bind(console), - memberPrefix = config.memberPrefix || '', - memberSuffix = config.memberSuffix || '', - bigIntEnabled = - undefined === config.bigIntEnabled - ? !!globalThis['BigInt64Array'] - : !!config.bigIntEnabled, - BigInt = globalThis['BigInt'], - BigInt64Array = globalThis['BigInt64Array'], - ptrSizeof = config.ptrSizeof || 4, - ptrIR = config.ptrIR || 'i32'; - if (!SBF.debugFlags) { - SBF.__makeDebugFlags = function (deriveFrom = null) { - if (deriveFrom && deriveFrom.__flags) - deriveFrom = deriveFrom.__flags; - const f = function f(flags) { - if (0 === arguments.length) { - return f.__flags; - } - if (flags < 0) { - delete f.__flags.getter; - delete f.__flags.setter; - delete f.__flags.alloc; - delete f.__flags.dealloc; - } else { - f.__flags.getter = 0 !== (0x01 & flags); - f.__flags.setter = 0 !== (0x02 & flags); - f.__flags.alloc = 0 !== (0x04 & flags); - f.__flags.dealloc = 0 !== (0x08 & flags); - } - return f._flags; - }; - Object.defineProperty(f, '__flags', { - iterable: false, - writable: false, - value: Object.create(deriveFrom), - }); - if (!deriveFrom) f(0); - return f; - }; - SBF.debugFlags = SBF.__makeDebugFlags(); - } - - const isLittleEndian = (function () { - const buffer = new ArrayBuffer(2); - new DataView(buffer).setInt16(0, 256, true); - - return new Int16Array(buffer)[0] === 256; - })(); - - const isFuncSig = (s) => '(' === s[1]; - const isAutoPtrSig = (s) => 'P' === s; - const sigLetter = (s) => (isFuncSig(s) ? 'p' : s[0]); - - const sigIR = function (s) { - switch (sigLetter(s)) { - case 'c': - case 'C': - return 'i8'; - case 'i': - return 'i32'; - case 'p': - case 'P': - case 's': - return ptrIR; - case 'j': - return 'i64'; - case 'f': - return 'float'; - case 'd': - return 'double'; - } - toss('Unhandled signature IR:', s); - }; - - const affirmBigIntArray = BigInt64Array - ? () => true - : () => toss('BigInt64Array is not available.'); - - const sigDVGetter = function (s) { - switch (sigLetter(s)) { - case 'p': - case 'P': - case 's': { - switch (ptrSizeof) { - case 4: - return 'getInt32'; - case 8: - return affirmBigIntArray() && 'getBigInt64'; - } - break; - } - case 'i': - return 'getInt32'; - case 'c': - return 'getInt8'; - case 'C': - return 'getUint8'; - case 'j': - return affirmBigIntArray() && 'getBigInt64'; - case 'f': - return 'getFloat32'; - case 'd': - return 'getFloat64'; - } - toss('Unhandled DataView getter for signature:', s); - }; - - const sigDVSetter = function (s) { - switch (sigLetter(s)) { - case 'p': - case 'P': - case 's': { - switch (ptrSizeof) { - case 4: - return 'setInt32'; - case 8: - return affirmBigIntArray() && 'setBigInt64'; - } - break; - } - case 'i': - return 'setInt32'; - case 'c': - return 'setInt8'; - case 'C': - return 'setUint8'; - case 'j': - return affirmBigIntArray() && 'setBigInt64'; - case 'f': - return 'setFloat32'; - case 'd': - return 'setFloat64'; - } - toss('Unhandled DataView setter for signature:', s); - }; - - const sigDVSetWrapper = function (s) { - switch (sigLetter(s)) { - case 'i': - case 'f': - case 'c': - case 'C': - case 'd': - return Number; - case 'j': - return affirmBigIntArray() && BigInt; - case 'p': - case 'P': - case 's': - switch (ptrSizeof) { - case 4: - return Number; - case 8: - return affirmBigIntArray() && BigInt; - } - break; - } - toss('Unhandled DataView set wrapper for signature:', s); - }; - - const sPropName = (s, k) => s + '::' + k; - - const __propThrowOnSet = function (structName, propName) { - return () => toss(sPropName(structName, propName), 'is read-only.'); - }; - - const __instancePointerMap = new WeakMap(); - - const xPtrPropName = '(pointer-is-external)'; - - const __freeStruct = function (ctor, obj, m) { - if (!m) m = __instancePointerMap.get(obj); - if (m) { - __instancePointerMap.delete(obj); - if (Array.isArray(obj.ondispose)) { - let x; - while ((x = obj.ondispose.shift())) { - try { - if (x instanceof Function) x.call(obj); - else if (x instanceof StructType) x.dispose(); - else if ('number' === typeof x) dealloc(x); - } catch (e) { - console.warn( - 'ondispose() for', - ctor.structName, - '@', - m, - 'threw. NOT propagating it.', - e, - ); - } - } - } else if (obj.ondispose instanceof Function) { - try { - obj.ondispose(); - } catch (e) { - console.warn( - 'ondispose() for', - ctor.structName, - '@', - m, - 'threw. NOT propagating it.', - e, - ); - } - } - delete obj.ondispose; - if (ctor.debugFlags.__flags.dealloc) { - log( - 'debug.dealloc:', - obj[xPtrPropName] ? 'EXTERNAL' : '', - ctor.structName, - 'instance:', - ctor.structInfo.sizeof, - 'bytes @' + m, - ); - } - if (!obj[xPtrPropName]) dealloc(m); - } - }; - - const rop = (v) => { - return { - configurable: false, - writable: false, - iterable: false, - value: v, - }; - }; - - const __allocStruct = function (ctor, obj, m) { - let fill = !m; - if (m) Object.defineProperty(obj, xPtrPropName, rop(m)); - else { - m = alloc(ctor.structInfo.sizeof); - if (!m) toss('Allocation of', ctor.structName, 'structure failed.'); - } - try { - if (ctor.debugFlags.__flags.alloc) { - log( - 'debug.alloc:', - fill ? '' : 'EXTERNAL', - ctor.structName, - 'instance:', - ctor.structInfo.sizeof, - 'bytes @' + m, - ); - } - if (fill) heap().fill(0, m, m + ctor.structInfo.sizeof); - __instancePointerMap.set(obj, m); - } catch (e) { - __freeStruct(ctor, obj, m); - throw e; - } - }; - - const __memoryDump = function () { - const p = this.pointer; - return p - ? new Uint8Array(heap().slice(p, p + this.structInfo.sizeof)) - : null; - }; - - const __memberKey = (k) => memberPrefix + k + memberSuffix; - const __memberKeyProp = rop(__memberKey); - - const __lookupMember = function ( - structInfo, - memberName, - tossIfNotFound = true, - ) { - let m = structInfo.members[memberName]; - if (!m && (memberPrefix || memberSuffix)) { - for (const v of Object.values(structInfo.members)) { - if (v.key === memberName) { - m = v; - break; - } - } - if (!m && tossIfNotFound) { - toss( - sPropName(structInfo.name, memberName), - 'is not a mapped struct member.', - ); - } - } - return m; - }; - - const __memberSignature = function f( - obj, - memberName, - emscriptenFormat = false, - ) { - if (!f._) - f._ = (x) => - x.replace(/[^vipPsjrdcC]/g, '').replace(/[pPscC]/g, 'i'); - const m = __lookupMember(obj.structInfo, memberName, true); - return emscriptenFormat ? f._(m.signature) : m.signature; - }; - - const __ptrPropDescriptor = { - configurable: false, - enumerable: false, - get: function () { - return __instancePointerMap.get(this); - }, - set: () => toss("Cannot assign the 'pointer' property of a struct."), - }; - - const __structMemberKeys = rop(function () { - const a = []; - for (const k of Object.keys(this.structInfo.members)) { - a.push(this.memberKey(k)); - } - return a; - }); - - const __utf8Decoder = new TextDecoder('utf-8'); - const __utf8Encoder = new TextEncoder(); - - const __SAB = - 'undefined' === typeof SharedArrayBuffer - ? function () {} - : SharedArrayBuffer; - const __utf8Decode = function (arrayBuffer, begin, end) { - return __utf8Decoder.decode( - arrayBuffer.buffer instanceof __SAB - ? arrayBuffer.slice(begin, end) - : arrayBuffer.subarray(begin, end), - ); - }; - - const __memberIsString = function ( - obj, - memberName, - tossIfNotFound = false, - ) { - const m = __lookupMember(obj.structInfo, memberName, tossIfNotFound); - return m && 1 === m.signature.length && 's' === m.signature[0] - ? m - : false; - }; - - const __affirmCStringSignature = function (member) { - if ('s' === member.signature) return; - toss( - 'Invalid member type signature for C-string value:', - JSON.stringify(member), - ); - }; - - const __memberToJsString = function f(obj, memberName) { - const m = __lookupMember(obj.structInfo, memberName, true); - __affirmCStringSignature(m); - const addr = obj[m.key]; - - if (!addr) return null; - let pos = addr; - const mem = heap(); - for (; mem[pos] !== 0; ++pos) {} - - return addr === pos ? '' : __utf8Decode(mem, addr, pos); - }; - - const __addOnDispose = function (obj, ...v) { - if (obj.ondispose) { - if (!Array.isArray(obj.ondispose)) { - obj.ondispose = [obj.ondispose]; - } - } else { - obj.ondispose = []; - } - obj.ondispose.push(...v); - }; - - const __allocCString = function (str) { - const u = __utf8Encoder.encode(str); - const mem = alloc(u.length + 1); - if (!mem) toss('Allocation error while duplicating string:', str); - const h = heap(); - - h.set(u, mem); - h[mem + u.length] = 0; - - return mem; - }; - - const __setMemberCString = function (obj, memberName, str) { - const m = __lookupMember(obj.structInfo, memberName, true); - __affirmCStringSignature(m); - - const mem = __allocCString(str); - obj[m.key] = mem; - __addOnDispose(obj, mem); - return obj; - }; - - const StructType = function ctor(structName, structInfo) { - if (arguments[2] !== rop) { - toss( - 'Do not call the StructType constructor', - 'from client-level code.', - ); - } - Object.defineProperties(this, { - structName: rop(structName), - structInfo: rop(structInfo), - }); - }; - - StructType.prototype = Object.create(null, { - dispose: rop(function () { - __freeStruct(this.constructor, this); - }), - lookupMember: rop(function (memberName, tossIfNotFound = true) { - return __lookupMember(this.structInfo, memberName, tossIfNotFound); - }), - memberToJsString: rop(function (memberName) { - return __memberToJsString(this, memberName); - }), - memberIsString: rop(function (memberName, tossIfNotFound = true) { - return __memberIsString(this, memberName, tossIfNotFound); - }), - memberKey: __memberKeyProp, - memberKeys: __structMemberKeys, - memberSignature: rop(function (memberName, emscriptenFormat = false) { - return __memberSignature(this, memberName, emscriptenFormat); - }), - memoryDump: rop(__memoryDump), - pointer: __ptrPropDescriptor, - setMemberCString: rop(function (memberName, str) { - return __setMemberCString(this, memberName, str); - }), - }); - - Object.assign(StructType.prototype, { - addOnDispose: function (...v) { - __addOnDispose(this, ...v); - return this; - }, - }); - - Object.defineProperties(StructType, { - allocCString: rop(__allocCString), - isA: rop((v) => v instanceof StructType), - hasExternalPointer: rop( - (v) => v instanceof StructType && !!v[xPtrPropName], - ), - memberKey: __memberKeyProp, - }); - - const isNumericValue = (v) => - Number.isFinite(v) || v instanceof (BigInt || Number); - - const makeMemberWrapper = function f(ctor, name, descr) { - if (!f._) { - f._ = { getters: {}, setters: {}, sw: {} }; - const a = ['i', 'c', 'C', 'p', 'P', 's', 'f', 'd', 'v()']; - if (bigIntEnabled) a.push('j'); - a.forEach(function (v) { - f._.getters[v] = sigDVGetter(v); - f._.setters[v] = sigDVSetter(v); - f._.sw[v] = sigDVSetWrapper(v); - }); - const rxSig1 = /^[ipPsjfdcC]$/, - rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/; - f.sigCheck = function (obj, name, key, sig) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - toss(obj.structName, 'already has a property named', key + '.'); - } - rxSig1.test(sig) || - rxSig2.test(sig) || - toss( - 'Malformed signature for', - sPropName(obj.structName, name) + ':', - sig, - ); - }; - } - const key = ctor.memberKey(name); - f.sigCheck(ctor.prototype, name, key, descr.signature); - descr.key = key; - descr.name = name; - const sigGlyph = sigLetter(descr.signature); - const xPropName = sPropName(ctor.prototype.structName, key); - const dbg = ctor.prototype.debugFlags.__flags; - - const prop = Object.create(null); - prop.configurable = false; - prop.enumerable = false; - prop.get = function () { - if (dbg.getter) { - log( - 'debug.getter:', - f._.getters[sigGlyph], - 'for', - sigIR(sigGlyph), - xPropName, - '@', - this.pointer, - '+', - descr.offset, - 'sz', - descr.sizeof, - ); - } - let rc = new DataView( - heap().buffer, - this.pointer + descr.offset, - descr.sizeof, - )[f._.getters[sigGlyph]](0, isLittleEndian); - if (dbg.getter) log('debug.getter:', xPropName, 'result =', rc); - return rc; - }; - if (descr.readOnly) { - prop.set = __propThrowOnSet(ctor.prototype.structName, key); - } else { - prop.set = function (v) { - if (dbg.setter) { - log( - 'debug.setter:', - f._.setters[sigGlyph], - 'for', - sigIR(sigGlyph), - xPropName, - '@', - this.pointer, - '+', - descr.offset, - 'sz', - descr.sizeof, - v, - ); - } - if (!this.pointer) { - toss('Cannot set struct property on disposed instance.'); - } - if (null === v) v = 0; - else - while (!isNumericValue(v)) { - if ( - isAutoPtrSig(descr.signature) && - v instanceof StructType - ) { - v = v.pointer || 0; - if (dbg.setter) - log('debug.setter:', xPropName, 'resolved to', v); - break; - } - toss('Invalid value for pointer-type', xPropName + '.'); - } - new DataView( - heap().buffer, - this.pointer + descr.offset, - descr.sizeof, - )[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian); - }; - } - Object.defineProperty(ctor.prototype, key, prop); - }; - - const StructBinder = function StructBinder(structName, structInfo) { - if (1 === arguments.length) { - structInfo = structName; - structName = structInfo.name; - } else if (!structInfo.name) { - structInfo.name = structName; - } - if (!structName) toss('Struct name is required.'); - let lastMember = false; - Object.keys(structInfo.members).forEach((k) => { - const m = structInfo.members[k]; - if (!m.sizeof) toss(structName, 'member', k, 'is missing sizeof.'); - else if (m.sizeof === 1) { - m.signature === 'c' || - m.signature === 'C' || - toss( - 'Unexpected sizeof==1 member', - sPropName(structInfo.name, k), - 'with signature', - m.signature, - ); - } else { - if (0 !== m.sizeof % 4) { - console.warn( - 'Invalid struct member description =', - m, - 'from', - structInfo, - ); - toss( - structName, - 'member', - k, - 'sizeof is not aligned. sizeof=' + m.sizeof, - ); - } - if (0 !== m.offset % 4) { - console.warn( - 'Invalid struct member description =', - m, - 'from', - structInfo, - ); - toss( - structName, - 'member', - k, - 'offset is not aligned. offset=' + m.offset, - ); - } - } - if (!lastMember || lastMember.offset < m.offset) lastMember = m; - }); - if (!lastMember) toss('No member property descriptions found.'); - else if (structInfo.sizeof < lastMember.offset + lastMember.sizeof) { - toss( - 'Invalid struct config:', - structName, - 'max member offset (' + lastMember.offset + ') ', - 'extends past end of struct (sizeof=' + structInfo.sizeof + ').', - ); - } - const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags)); - - const StructCtor = function StructCtor(externalMemory) { - if (!(this instanceof StructCtor)) { - toss( - 'The', - structName, - "constructor may only be called via 'new'.", - ); - } else if (arguments.length) { - if ( - externalMemory !== (externalMemory | 0) || - externalMemory <= 0 - ) { - toss('Invalid pointer value for', structName, 'constructor.'); - } - __allocStruct(StructCtor, this, externalMemory); - } else { - __allocStruct(StructCtor, this); - } - }; - Object.defineProperties(StructCtor, { - debugFlags: debugFlags, - isA: rop((v) => v instanceof StructCtor), - memberKey: __memberKeyProp, - memberKeys: __structMemberKeys, - methodInfoForKey: rop(function (mKey) {}), - structInfo: rop(structInfo), - structName: rop(structName), - }); - StructCtor.prototype = new StructType(structName, structInfo, rop); - Object.defineProperties(StructCtor.prototype, { - debugFlags: debugFlags, - constructor: rop(StructCtor), - }); - Object.keys(structInfo.members).forEach((name) => - makeMemberWrapper(StructCtor, name, structInfo.members[name]), - ); - return StructCtor; - }; - StructBinder.StructType = StructType; - StructBinder.config = config; - StructBinder.allocCString = __allocCString; - if (!StructBinder.debugFlags) { - StructBinder.debugFlags = SBF.__makeDebugFlags(SBF.debugFlags); - } - return StructBinder; - }; - - globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { - const toss = (...args) => { - throw new Error(args.join(' ')); - }; - sqlite3.SQLite3Error.toss; - const capi = sqlite3.capi, - wasm = sqlite3.wasm, - util = sqlite3.util; - globalThis.WhWasmUtilInstaller(wasm); - delete globalThis.WhWasmUtilInstaller; - - wasm.bindingSignatures = [ - ['sqlite3_aggregate_context', 'void*', 'sqlite3_context*', 'int'], - - ['sqlite3_bind_double', 'int', 'sqlite3_stmt*', 'int', 'f64'], - ['sqlite3_bind_int', 'int', 'sqlite3_stmt*', 'int', 'int'], - ['sqlite3_bind_null', undefined, 'sqlite3_stmt*', 'int'], - ['sqlite3_bind_parameter_count', 'int', 'sqlite3_stmt*'], - ['sqlite3_bind_parameter_index', 'int', 'sqlite3_stmt*', 'string'], - [ - 'sqlite3_bind_pointer', - 'int', - 'sqlite3_stmt*', - 'int', - '*', - 'string:static', - '*', - ], - [ - 'sqlite3_busy_handler', - 'int', - [ - 'sqlite3*', - new wasm.xWrap.FuncPtrAdapter({ - signature: 'i(pi)', - contextKey: (argv, argIndex) => argv[0], - }), - '*', - ], - ], - ['sqlite3_busy_timeout', 'int', 'sqlite3*', 'int'], - - ['sqlite3_changes', 'int', 'sqlite3*'], - ['sqlite3_clear_bindings', 'int', 'sqlite3_stmt*'], - ['sqlite3_collation_needed', 'int', 'sqlite3*', '*', '*'], - ['sqlite3_column_blob', '*', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_bytes', 'int', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_count', 'int', 'sqlite3_stmt*'], - ['sqlite3_column_double', 'f64', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_int', 'int', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_name', 'string', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_text', 'string', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_type', 'int', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_value', 'sqlite3_value*', 'sqlite3_stmt*', 'int'], - [ - 'sqlite3_commit_hook', - 'void*', - [ - 'sqlite3*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_commit_hook', - signature: 'i(p)', - contextKey: (argv) => argv[0], - }), - '*', - ], - ], - ['sqlite3_compileoption_get', 'string', 'int'], - ['sqlite3_compileoption_used', 'int', 'string'], - ['sqlite3_complete', 'int', 'string:flexible'], - ['sqlite3_context_db_handle', 'sqlite3*', 'sqlite3_context*'], - - ['sqlite3_data_count', 'int', 'sqlite3_stmt*'], - ['sqlite3_db_filename', 'string', 'sqlite3*', 'string'], - ['sqlite3_db_handle', 'sqlite3*', 'sqlite3_stmt*'], - ['sqlite3_db_name', 'string', 'sqlite3*', 'int'], - ['sqlite3_db_status', 'int', 'sqlite3*', 'int', '*', '*', 'int'], - ['sqlite3_errcode', 'int', 'sqlite3*'], - ['sqlite3_errmsg', 'string', 'sqlite3*'], - ['sqlite3_error_offset', 'int', 'sqlite3*'], - ['sqlite3_errstr', 'string', 'int'], - [ - 'sqlite3_exec', - 'int', - [ - 'sqlite3*', - 'string:flexible', - new wasm.xWrap.FuncPtrAdapter({ - signature: 'i(pipp)', - bindScope: 'transient', - callProxy: (callback) => { - let aNames; - return (pVoid, nCols, pColVals, pColNames) => { - try { - const aVals = wasm.cArgvToJs(nCols, pColVals); - if (!aNames) aNames = wasm.cArgvToJs(nCols, pColNames); - return callback(aVals, aNames) | 0; - } catch (e) { - return e.resultCode || capi.SQLITE_ERROR; - } - }; - }, - }), - '*', - '**', - ], - ], - ['sqlite3_expanded_sql', 'string', 'sqlite3_stmt*'], - ['sqlite3_extended_errcode', 'int', 'sqlite3*'], - ['sqlite3_extended_result_codes', 'int', 'sqlite3*', 'int'], - ['sqlite3_file_control', 'int', 'sqlite3*', 'string', 'int', '*'], - ['sqlite3_finalize', 'int', 'sqlite3_stmt*'], - ['sqlite3_free', undefined, '*'], - ['sqlite3_get_autocommit', 'int', 'sqlite3*'], - ['sqlite3_get_auxdata', '*', 'sqlite3_context*', 'int'], - ['sqlite3_initialize', undefined], - - ['sqlite3_keyword_count', 'int'], - ['sqlite3_keyword_name', 'int', ['int', '**', '*']], - ['sqlite3_keyword_check', 'int', ['string', 'int']], - ['sqlite3_libversion', 'string'], - ['sqlite3_libversion_number', 'int'], - ['sqlite3_limit', 'int', ['sqlite3*', 'int', 'int']], - ['sqlite3_malloc', '*', 'int'], - ['sqlite3_open', 'int', 'string', '*'], - ['sqlite3_open_v2', 'int', 'string', '*', 'int', 'string'], - - [ - 'sqlite3_progress_handler', - undefined, - [ - 'sqlite3*', - 'int', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xProgressHandler', - signature: 'i(p)', - bindScope: 'context', - contextKey: (argv, argIndex) => argv[0], - }), - '*', - ], - ], - ['sqlite3_realloc', '*', '*', 'int'], - ['sqlite3_reset', 'int', 'sqlite3_stmt*'], - - [ - 'sqlite3_result_blob', - undefined, - 'sqlite3_context*', - '*', - 'int', - '*', - ], - ['sqlite3_result_double', undefined, 'sqlite3_context*', 'f64'], - [ - 'sqlite3_result_error', - undefined, - 'sqlite3_context*', - 'string', - 'int', - ], - ['sqlite3_result_error_code', undefined, 'sqlite3_context*', 'int'], - ['sqlite3_result_error_nomem', undefined, 'sqlite3_context*'], - ['sqlite3_result_error_toobig', undefined, 'sqlite3_context*'], - ['sqlite3_result_int', undefined, 'sqlite3_context*', 'int'], - ['sqlite3_result_null', undefined, 'sqlite3_context*'], - [ - 'sqlite3_result_pointer', - undefined, - 'sqlite3_context*', - '*', - 'string:static', - '*', - ], - ['sqlite3_result_subtype', undefined, 'sqlite3_value*', 'int'], - [ - 'sqlite3_result_text', - undefined, - 'sqlite3_context*', - 'string', - 'int', - '*', - ], - ['sqlite3_result_zeroblob', undefined, 'sqlite3_context*', 'int'], - [ - 'sqlite3_rollback_hook', - 'void*', - [ - 'sqlite3*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_rollback_hook', - signature: 'v(p)', - contextKey: (argv) => argv[0], - }), - '*', - ], - ], - [ - 'sqlite3_set_authorizer', - 'int', - [ - 'sqlite3*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_set_authorizer::xAuth', - signature: 'i(pi' + 'ssss)', - contextKey: (argv, argIndex) => argv[0], - callProxy: (callback) => { - return (pV, iCode, s0, s1, s2, s3) => { - try { - s0 = s0 && wasm.cstrToJs(s0); - s1 = s1 && wasm.cstrToJs(s1); - s2 = s2 && wasm.cstrToJs(s2); - s3 = s3 && wasm.cstrToJs(s3); - return callback(pV, iCode, s0, s1, s2, s3) || 0; - } catch (e) { - return e.resultCode || capi.SQLITE_ERROR; - } - }; - }, - }), - '*', - ], - ], - [ - 'sqlite3_set_auxdata', - undefined, - [ - 'sqlite3_context*', - 'int', - '*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xDestroyAuxData', - signature: 'v(*)', - contextKey: (argv, argIndex) => argv[0], - }), - ], - ], - ['sqlite3_shutdown', undefined], - ['sqlite3_sourceid', 'string'], - ['sqlite3_sql', 'string', 'sqlite3_stmt*'], - ['sqlite3_status', 'int', 'int', '*', '*', 'int'], - ['sqlite3_step', 'int', 'sqlite3_stmt*'], - ['sqlite3_stmt_isexplain', 'int', ['sqlite3_stmt*']], - ['sqlite3_stmt_readonly', 'int', ['sqlite3_stmt*']], - ['sqlite3_stmt_status', 'int', 'sqlite3_stmt*', 'int', 'int'], - ['sqlite3_strglob', 'int', 'string', 'string'], - ['sqlite3_stricmp', 'int', 'string', 'string'], - ['sqlite3_strlike', 'int', 'string', 'string', 'int'], - ['sqlite3_strnicmp', 'int', 'string', 'string', 'int'], - [ - 'sqlite3_table_column_metadata', - 'int', - 'sqlite3*', - 'string', - 'string', - 'string', - '**', - '**', - '*', - '*', - '*', - ], - ['sqlite3_total_changes', 'int', 'sqlite3*'], - [ - 'sqlite3_trace_v2', - 'int', - [ - 'sqlite3*', - 'int', - new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_trace_v2::callback', - signature: 'i(ippp)', - contextKey: (argv, argIndex) => argv[0], - }), - '*', - ], - ], - ['sqlite3_txn_state', 'int', ['sqlite3*', 'string']], - - ['sqlite3_uri_boolean', 'int', 'sqlite3_filename', 'string', 'int'], - ['sqlite3_uri_key', 'string', 'sqlite3_filename', 'int'], - ['sqlite3_uri_parameter', 'string', 'sqlite3_filename', 'string'], - ['sqlite3_user_data', 'void*', 'sqlite3_context*'], - ['sqlite3_value_blob', '*', 'sqlite3_value*'], - ['sqlite3_value_bytes', 'int', 'sqlite3_value*'], - ['sqlite3_value_double', 'f64', 'sqlite3_value*'], - ['sqlite3_value_dup', 'sqlite3_value*', 'sqlite3_value*'], - ['sqlite3_value_free', undefined, 'sqlite3_value*'], - ['sqlite3_value_frombind', 'int', 'sqlite3_value*'], - ['sqlite3_value_int', 'int', 'sqlite3_value*'], - ['sqlite3_value_nochange', 'int', 'sqlite3_value*'], - ['sqlite3_value_numeric_type', 'int', 'sqlite3_value*'], - ['sqlite3_value_pointer', '*', 'sqlite3_value*', 'string:static'], - ['sqlite3_value_subtype', 'int', 'sqlite3_value*'], - ['sqlite3_value_text', 'string', 'sqlite3_value*'], - ['sqlite3_value_type', 'int', 'sqlite3_value*'], - ['sqlite3_vfs_find', '*', 'string'], - ['sqlite3_vfs_register', 'int', 'sqlite3_vfs*', 'int'], - ['sqlite3_vfs_unregister', 'int', 'sqlite3_vfs*'], - ]; - - wasm.bindingSignatures.int64 = [ - ['sqlite3_bind_int64', 'int', ['sqlite3_stmt*', 'int', 'i64']], - ['sqlite3_changes64', 'i64', ['sqlite3*']], - ['sqlite3_column_int64', 'i64', ['sqlite3_stmt*', 'int']], - [ - 'sqlite3_create_module', - 'int', - ['sqlite3*', 'string', 'sqlite3_module*', '*'], - ], - [ - 'sqlite3_create_module_v2', - 'int', - ['sqlite3*', 'string', 'sqlite3_module*', '*', '*'], - ], - ['sqlite3_declare_vtab', 'int', ['sqlite3*', 'string:flexible']], - [ - 'sqlite3_deserialize', - 'int', - 'sqlite3*', - 'string', - '*', - 'i64', - 'i64', - 'int', - ], - ['sqlite3_drop_modules', 'int', ['sqlite3*', '**']], - ['sqlite3_last_insert_rowid', 'i64', ['sqlite3*']], - ['sqlite3_malloc64', '*', 'i64'], - ['sqlite3_msize', 'i64', '*'], - ['sqlite3_overload_function', 'int', ['sqlite3*', 'string', 'int']], - ['sqlite3_preupdate_blobwrite', 'int', 'sqlite3*'], - ['sqlite3_preupdate_count', 'int', 'sqlite3*'], - ['sqlite3_preupdate_depth', 'int', 'sqlite3*'], - [ - 'sqlite3_preupdate_hook', - '*', - [ - 'sqlite3*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_preupdate_hook', - signature: 'v(ppippjj)', - contextKey: (argv) => argv[0], - callProxy: (callback) => { - return (p, db, op, zDb, zTbl, iKey1, iKey2) => { - callback( - p, - db, - op, - wasm.cstrToJs(zDb), - wasm.cstrToJs(zTbl), - iKey1, - iKey2, - ); - }; - }, - }), - '*', - ], - ], - ['sqlite3_preupdate_new', 'int', ['sqlite3*', 'int', '**']], - ['sqlite3_preupdate_old', 'int', ['sqlite3*', 'int', '**']], - ['sqlite3_realloc64', '*', '*', 'i64'], - ['sqlite3_result_int64', undefined, '*', 'i64'], - ['sqlite3_result_zeroblob64', 'int', '*', 'i64'], - ['sqlite3_serialize', '*', 'sqlite3*', 'string', '*', 'int'], - ['sqlite3_set_last_insert_rowid', undefined, ['sqlite3*', 'i64']], - ['sqlite3_status64', 'int', 'int', '*', '*', 'int'], - ['sqlite3_total_changes64', 'i64', ['sqlite3*']], - [ - 'sqlite3_update_hook', - '*', - [ - 'sqlite3*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_update_hook', - signature: 'v(iippj)', - contextKey: (argv) => argv[0], - callProxy: (callback) => { - return (p, op, z0, z1, rowid) => { - callback( - p, - op, - wasm.cstrToJs(z0), - wasm.cstrToJs(z1), - rowid, - ); - }; - }, - }), - '*', - ], - ], - ['sqlite3_uri_int64', 'i64', ['sqlite3_filename', 'string', 'i64']], - ['sqlite3_value_int64', 'i64', 'sqlite3_value*'], - ['sqlite3_vtab_collation', 'string', 'sqlite3_index_info*', 'int'], - ['sqlite3_vtab_distinct', 'int', 'sqlite3_index_info*'], - ['sqlite3_vtab_in', 'int', 'sqlite3_index_info*', 'int', 'int'], - ['sqlite3_vtab_in_first', 'int', 'sqlite3_value*', '**'], - ['sqlite3_vtab_in_next', 'int', 'sqlite3_value*', '**'], - - ['sqlite3_vtab_nochange', 'int', 'sqlite3_context*'], - ['sqlite3_vtab_on_conflict', 'int', 'sqlite3*'], - ['sqlite3_vtab_rhs_value', 'int', 'sqlite3_index_info*', 'int', '**'], - ]; - - if (wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add) { - const __ipsProxy = { - signature: 'i(ps)', - callProxy: (callback) => { - return (p, s) => { - try { - return callback(p, wasm.cstrToJs(s)) | 0; - } catch (e) { - return e.resultCode || capi.SQLITE_ERROR; - } - }; - }, - }; - - wasm.bindingSignatures.int64.push( - ...[ - [ - 'sqlite3changegroup_add', - 'int', - ['sqlite3_changegroup*', 'int', 'void*'], - ], - [ - 'sqlite3changegroup_add_strm', - 'int', - [ - 'sqlite3_changegroup*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - ], - ], - [ - 'sqlite3changegroup_delete', - undefined, - ['sqlite3_changegroup*'], - ], - ['sqlite3changegroup_new', 'int', ['**']], - [ - 'sqlite3changegroup_output', - 'int', - ['sqlite3_changegroup*', 'int*', '**'], - ], - [ - 'sqlite3changegroup_output_strm', - 'int', - [ - 'sqlite3_changegroup*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppi)', - bindScope: 'transient', - }), - 'void*', - ], - ], - [ - 'sqlite3changeset_apply', - 'int', - [ - 'sqlite3*', - 'int', - 'void*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - bindScope: 'transient', - ...__ipsProxy, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xConflict', - signature: 'i(pip)', - bindScope: 'transient', - }), - 'void*', - ], - ], - [ - 'sqlite3changeset_apply_strm', - 'int', - [ - 'sqlite3*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - bindScope: 'transient', - ...__ipsProxy, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xConflict', - signature: 'i(pip)', - bindScope: 'transient', - }), - 'void*', - ], - ], - [ - 'sqlite3changeset_apply_v2', - 'int', - [ - 'sqlite3*', - 'int', - 'void*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - bindScope: 'transient', - ...__ipsProxy, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xConflict', - signature: 'i(pip)', - bindScope: 'transient', - }), - 'void*', - '**', - 'int*', - 'int', - ], - ], - [ - 'sqlite3changeset_apply_v2_strm', - 'int', - [ - 'sqlite3*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - bindScope: 'transient', - ...__ipsProxy, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xConflict', - signature: 'i(pip)', - bindScope: 'transient', - }), - 'void*', - '**', - 'int*', - 'int', - ], - ], - [ - 'sqlite3changeset_concat', - 'int', - ['int', 'void*', 'int', 'void*', 'int*', '**'], - ], - [ - 'sqlite3changeset_concat_strm', - 'int', - [ - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInputA', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInputB', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppi)', - bindScope: 'transient', - }), - 'void*', - ], - ], - [ - 'sqlite3changeset_conflict', - 'int', - ['sqlite3_changeset_iter*', 'int', '**'], - ], - ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']], - [ - 'sqlite3changeset_fk_conflicts', - 'int', - ['sqlite3_changeset_iter*', 'int*'], - ], - [ - 'sqlite3changeset_invert', - 'int', - ['int', 'void*', 'int*', '**'], - ], - [ - 'sqlite3changeset_invert_strm', - 'int', - [ - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppi)', - bindScope: 'transient', - }), - 'void*', - ], - ], - [ - 'sqlite3changeset_new', - 'int', - ['sqlite3_changeset_iter*', 'int', '**'], - ], - ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']], - [ - 'sqlite3changeset_old', - 'int', - ['sqlite3_changeset_iter*', 'int', '**'], - ], - [ - 'sqlite3changeset_op', - 'int', - ['sqlite3_changeset_iter*', '**', 'int*', 'int*', 'int*'], - ], - [ - 'sqlite3changeset_pk', - 'int', - ['sqlite3_changeset_iter*', '**', 'int*'], - ], - ['sqlite3changeset_start', 'int', ['**', 'int', '*']], - [ - 'sqlite3changeset_start_strm', - 'int', - [ - '**', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - ], - ], - ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']], - [ - 'sqlite3changeset_start_v2_strm', - 'int', - [ - '**', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - 'int', - ], - ], - ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']], - [ - 'sqlite3session_changeset', - 'int', - ['sqlite3_session*', 'int*', '**'], - ], - ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']], - [ - 'sqlite3session_changeset_strm', - 'int', - [ - 'sqlite3_session*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - ], - ], - ['sqlite3session_config', 'int', ['int', 'void*']], - ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']], - - [ - 'sqlite3session_diff', - 'int', - ['sqlite3_session*', 'string', 'string', '**'], - ], - ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']], - ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']], - ['sqlite3session_isempty', 'int', ['sqlite3_session*']], - ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']], - [ - 'sqlite3session_object_config', - 'int', - ['sqlite3_session*', 'int', 'void*'], - ], - [ - 'sqlite3session_patchset', - 'int', - ['sqlite3_session*', '*', '**'], - ], - [ - 'sqlite3session_patchset_strm', - 'int', - [ - 'sqlite3_session*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppp)', - bindScope: 'transient', - }), - 'void*', - ], - ], - [ - 'sqlite3session_table_filter', - undefined, - [ - 'sqlite3_session*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - ...__ipsProxy, - contextKey: (argv, argIndex) => argv[0], - }), - '*', - ], - ], - ], - ); - } - - wasm.bindingSignatures.wasmInternal = [ - ['sqlite3__wasm_db_reset', 'int', 'sqlite3*'], - ['sqlite3__wasm_db_vfs', 'sqlite3_vfs*', 'sqlite3*', 'string'], - [ - 'sqlite3__wasm_vfs_create_file', - 'int', - 'sqlite3_vfs*', - 'string', - '*', - 'int', - ], - ['sqlite3__wasm_posix_create_file', 'int', 'string', '*', 'int'], - ['sqlite3__wasm_vfs_unlink', 'int', 'sqlite3_vfs*', 'string'], - ['sqlite3__wasm_qfmt_token', 'string:dealloc', 'string', 'int'], - ]; - - sqlite3.StructBinder = globalThis.Jaccwabyt({ - heap: wasm.heap8u, - alloc: wasm.alloc, - dealloc: wasm.dealloc, - bigIntEnabled: wasm.bigIntEnabled, - memberPrefix: '$', - }); - delete globalThis.Jaccwabyt; - - { - const __xString = wasm.xWrap.argAdapter('string'); - wasm.xWrap.argAdapter('string:flexible', (v) => - __xString(util.flexibleString(v)), - ); - - wasm.xWrap.argAdapter( - 'string:static', - function (v) { - if (wasm.isPtr(v)) return v; - v = '' + v; - let rc = this[v]; - return rc || (this[v] = wasm.allocCString(v)); - }.bind(Object.create(null)), - ); - - const __xArgPtr = wasm.xWrap.argAdapter('*'); - const nilType = function () {}; - wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)( - 'sqlite3_context*', - __xArgPtr, - )('sqlite3_value*', __xArgPtr)('void*', __xArgPtr)( - 'sqlite3_changegroup*', - __xArgPtr, - )('sqlite3_changeset_iter*', __xArgPtr)( - 'sqlite3_session*', - __xArgPtr, - )('sqlite3_stmt*', (v) => - __xArgPtr( - v instanceof (sqlite3?.oo1?.Stmt || nilType) ? v.pointer : v, - ), - )('sqlite3*', (v) => - __xArgPtr( - v instanceof (sqlite3?.oo1?.DB || nilType) ? v.pointer : v, - ), - )('sqlite3_index_info*', (v) => - __xArgPtr( - v instanceof (capi.sqlite3_index_info || nilType) ? v.pointer : v, - ), - )('sqlite3_module*', (v) => - __xArgPtr( - v instanceof (capi.sqlite3_module || nilType) ? v.pointer : v, - ), - )('sqlite3_vfs*', (v) => { - if ('string' === typeof v) { - return ( - capi.sqlite3_vfs_find(v) || - sqlite3.SQLite3Error.toss( - capi.SQLITE_NOTFOUND, - 'Unknown sqlite3_vfs name:', - v, - ) - ); - } - return __xArgPtr( - v instanceof (capi.sqlite3_vfs || nilType) ? v.pointer : v, - ); - }); - - const __xRcPtr = wasm.xWrap.resultAdapter('*'); - wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)( - 'sqlite3_context*', - __xRcPtr, - )('sqlite3_stmt*', __xRcPtr)('sqlite3_value*', __xRcPtr)( - 'sqlite3_vfs*', - __xRcPtr, - )('void*', __xRcPtr); - - if (0 === wasm.exports.sqlite3_step.length) { - wasm.xWrap.doArgcCheck = false; - sqlite3.config.warn( - 'Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks.', - ); - } - for (const e of wasm.bindingSignatures) { - capi[e[0]] = wasm.xWrap.apply(null, e); - } - for (const e of wasm.bindingSignatures.wasmInternal) { - util[e[0]] = wasm.xWrap.apply(null, e); - } - - const fI64Disabled = function (fname) { - return () => - toss( - fname + '() is unavailable due to lack', - 'of BigInt support in this build.', - ); - }; - for (const e of wasm.bindingSignatures.int64) { - capi[e[0]] = wasm.bigIntEnabled - ? wasm.xWrap.apply(null, e) - : fI64Disabled(e[0]); - } - - delete wasm.bindingSignatures; - - if (wasm.exports.sqlite3__wasm_db_error) { - const __db_err = wasm.xWrap( - 'sqlite3__wasm_db_error', - 'int', - 'sqlite3*', - 'int', - 'string', - ); - - util.sqlite3__wasm_db_error = function (pDb, resultCode, message) { - if (resultCode instanceof sqlite3.WasmAllocError) { - resultCode = capi.SQLITE_NOMEM; - message = 0; - } else if (resultCode instanceof Error) { - message = message || '' + resultCode; - resultCode = resultCode.resultCode || capi.SQLITE_ERROR; - } - return pDb ? __db_err(pDb, resultCode, message) : resultCode; - }; - } else { - util.sqlite3__wasm_db_error = function (pDb, errCode, msg) { - console.warn( - 'sqlite3__wasm_db_error() is not exported.', - arguments, - ); - return errCode; - }; - } - } - - { - const cJson = wasm.xCall('sqlite3__wasm_enum_json'); - if (!cJson) { - toss( - "Maintenance required: increase sqlite3__wasm_enum_json()'s", - 'static buffer size!', - ); - } - - wasm.ctype = JSON.parse(wasm.cstrToJs(cJson)); - - const defineGroups = [ - 'access', - 'authorizer', - 'blobFinalizers', - 'changeset', - 'config', - 'dataTypes', - 'dbConfig', - 'dbStatus', - 'encodings', - 'fcntl', - 'flock', - 'ioCap', - 'limits', - 'openFlags', - 'prepareFlags', - 'resultCodes', - 'sqlite3Status', - 'stmtStatus', - 'syncFlags', - 'trace', - 'txnState', - 'udfFlags', - 'version', - ]; - if (wasm.bigIntEnabled) { - defineGroups.push('serialize', 'session', 'vtab'); - } - for (const t of defineGroups) { - for (const e of Object.entries(wasm.ctype[t])) { - capi[e[0]] = e[1]; - } - } - if (!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)) { - toss( - 'Internal error: cannot resolve exported function', - 'entry SQLITE_WASM_DEALLOC (==' + capi.SQLITE_WASM_DEALLOC + ').', - ); - } - const __rcMap = Object.create(null); - for (const t of ['resultCodes']) { - for (const e of Object.entries(wasm.ctype[t])) { - __rcMap[e[1]] = e[0]; - } - } - - capi.sqlite3_js_rc_str = (rc) => __rcMap[rc]; - - const notThese = Object.assign(Object.create(null), { - WasmTestStruct: true, - - sqlite3_kvvfs_methods: !util.isUIThread(), - - sqlite3_index_info: !wasm.bigIntEnabled, - sqlite3_index_constraint: !wasm.bigIntEnabled, - sqlite3_index_orderby: !wasm.bigIntEnabled, - sqlite3_index_constraint_usage: !wasm.bigIntEnabled, - }); - for (const s of wasm.ctype.structs) { - if (!notThese[s.name]) { - capi[s.name] = sqlite3.StructBinder(s); - } - } - if (capi.sqlite3_index_info) { - for (const k of [ - 'sqlite3_index_constraint', - 'sqlite3_index_orderby', - 'sqlite3_index_constraint_usage', - ]) { - capi.sqlite3_index_info[k] = capi[k]; - delete capi[k]; - } - capi.sqlite3_vtab_config = wasm.xWrap( - 'sqlite3__wasm_vtab_config', - 'int', - ['sqlite3*', 'int', 'int'], - ); - } - } - - const __dbArgcMismatch = (pDb, f, n) => { - return util.sqlite3__wasm_db_error( - pDb, - capi.SQLITE_MISUSE, - f + '() requires ' + n + ' argument' + (1 === n ? '' : 's') + '.', - ); - }; - - const __errEncoding = (pDb) => { - return util.sqlite3__wasm_db_error( - pDb, - capi.SQLITE_FORMAT, - 'SQLITE_UTF8 is the only supported encoding.', - ); - }; - - const __argPDb = (pDb) => wasm.xWrap.argAdapter('sqlite3*')(pDb); - const __argStr = (str) => (wasm.isPtr(str) ? wasm.cstrToJs(str) : str); - const __dbCleanupMap = function (pDb, mode) { - pDb = __argPDb(pDb); - let m = this.dbMap.get(pDb); - if (!mode) { - this.dbMap.delete(pDb); - return m; - } else if (!m && mode > 0) { - this.dbMap.set(pDb, (m = Object.create(null))); - } - return m; - }.bind( - Object.assign(Object.create(null), { - dbMap: new Map(), - }), - ); - - __dbCleanupMap.addCollation = function (pDb, name) { - const m = __dbCleanupMap(pDb, 1); - if (!m.collation) m.collation = new Set(); - m.collation.add(__argStr(name).toLowerCase()); - }; - - __dbCleanupMap._addUDF = function (pDb, name, arity, map) { - name = __argStr(name).toLowerCase(); - let u = map.get(name); - if (!u) map.set(name, (u = new Set())); - u.add(arity < 0 ? -1 : arity); - }; - - __dbCleanupMap.addFunction = function (pDb, name, arity) { - const m = __dbCleanupMap(pDb, 1); - if (!m.udf) m.udf = new Map(); - this._addUDF(pDb, name, arity, m.udf); - }; - - __dbCleanupMap.addWindowFunc = function (pDb, name, arity) { - const m = __dbCleanupMap(pDb, 1); - if (!m.wudf) m.wudf = new Map(); - this._addUDF(pDb, name, arity, m.wudf); - }; - - __dbCleanupMap.cleanup = function (pDb) { - pDb = __argPDb(pDb); - - const closeArgs = [pDb]; - for (const name of [ - 'sqlite3_busy_handler', - 'sqlite3_commit_hook', - 'sqlite3_preupdate_hook', - 'sqlite3_progress_handler', - 'sqlite3_rollback_hook', - 'sqlite3_set_authorizer', - 'sqlite3_trace_v2', - 'sqlite3_update_hook', - ]) { - const x = wasm.exports[name]; - closeArgs.length = x.length; - try { - capi[name](...closeArgs); - } catch (e) { - console.warn( - 'close-time call of', - name + '(', - closeArgs, - ') threw:', - e, - ); - } - } - const m = __dbCleanupMap(pDb, 0); - if (!m) return; - if (m.collation) { - for (const name of m.collation) { - try { - capi.sqlite3_create_collation_v2( - pDb, - name, - capi.SQLITE_UTF8, - 0, - 0, - 0, - ); - } catch (e) {} - } - delete m.collation; - } - let i; - for (i = 0; i < 2; ++i) { - const fmap = i ? m.wudf : m.udf; - if (!fmap) continue; - const func = i - ? capi.sqlite3_create_window_function - : capi.sqlite3_create_function_v2; - for (const e of fmap) { - const name = e[0], - arities = e[1]; - const fargs = [pDb, name, 0, capi.SQLITE_UTF8, 0, 0, 0, 0, 0]; - if (i) fargs.push(0); - for (const arity of arities) { - try { - fargs[2] = arity; - func.apply(null, fargs); - } catch (e) {} - } - arities.clear(); - } - fmap.clear(); - } - delete m.udf; - delete m.wudf; - }; - - { - const __sqlite3CloseV2 = wasm.xWrap( - 'sqlite3_close_v2', - 'int', - 'sqlite3*', - ); - capi.sqlite3_close_v2 = function (pDb) { - if (1 !== arguments.length) - return __dbArgcMismatch(pDb, 'sqlite3_close_v2', 1); - if (pDb) { - try { - __dbCleanupMap.cleanup(pDb); - } catch (e) {} - } - return __sqlite3CloseV2(pDb); - }; - } - - if (capi.sqlite3session_table_filter) { - const __sqlite3SessionDelete = wasm.xWrap( - 'sqlite3session_delete', - undefined, - ['sqlite3_session*'], - ); - capi.sqlite3session_delete = function (pSession) { - if (1 !== arguments.length) { - return __dbArgcMismatch(pDb, 'sqlite3session_delete', 1); - } else if (pSession) { - capi.sqlite3session_table_filter(pSession, 0, 0); - } - __sqlite3SessionDelete(pSession); - }; - } - - { - const contextKey = (argv, argIndex) => { - return ( - 'argv[' + - argIndex + - ']:' + - argv[0] + - ':' + - wasm.cstrToJs(argv[1]).toLowerCase() - ); - }; - const __sqlite3CreateCollationV2 = wasm.xWrap( - 'sqlite3_create_collation_v2', - 'int', - [ - 'sqlite3*', - 'string', - 'int', - '*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xCompare', - signature: 'i(pipip)', - contextKey, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xDestroy', - signature: 'v(p)', - contextKey, - }), - ], - ); - - capi.sqlite3_create_collation_v2 = function ( - pDb, - zName, - eTextRep, - pArg, - xCompare, - xDestroy, - ) { - if (6 !== arguments.length) - return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6); - else if (0 === (eTextRep & 0xf)) { - eTextRep |= capi.SQLITE_UTF8; - } else if (capi.SQLITE_UTF8 !== (eTextRep & 0xf)) { - return __errEncoding(pDb); - } - try { - const rc = __sqlite3CreateCollationV2( - pDb, - zName, - eTextRep, - pArg, - xCompare, - xDestroy, - ); - if (0 === rc && xCompare instanceof Function) { - __dbCleanupMap.addCollation(pDb, zName); - } - return rc; - } catch (e) { - return util.sqlite3__wasm_db_error(pDb, e); - } - }; - - capi.sqlite3_create_collation = ( - pDb, - zName, - eTextRep, - pArg, - xCompare, - ) => { - return 5 === arguments.length - ? capi.sqlite3_create_collation_v2( - pDb, - zName, - eTextRep, - pArg, - xCompare, - 0, - ) - : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5); - }; - } - - { - const contextKey = function (argv, argIndex) { - return ( - argv[0] + - ':' + - (argv[2] < 0 ? -1 : argv[2]) + - ':' + - argIndex + - ':' + - wasm.cstrToJs(argv[1]).toLowerCase() - ); - }; - - const __cfProxy = Object.assign(Object.create(null), { - xInverseAndStep: { - signature: 'v(pip)', - contextKey, - callProxy: (callback) => { - return (pCtx, argc, pArgv) => { - try { - callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)); - } catch (e) { - capi.sqlite3_result_error_js(pCtx, e); - } - }; - }, - }, - xFinalAndValue: { - signature: 'v(p)', - contextKey, - callProxy: (callback) => { - return (pCtx) => { - try { - capi.sqlite3_result_js(pCtx, callback(pCtx)); - } catch (e) { - capi.sqlite3_result_error_js(pCtx, e); - } - }; - }, - }, - xFunc: { - signature: 'v(pip)', - contextKey, - callProxy: (callback) => { - return (pCtx, argc, pArgv) => { - try { - capi.sqlite3_result_js( - pCtx, - callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)), - ); - } catch (e) { - capi.sqlite3_result_error_js(pCtx, e); - } - }; - }, - }, - xDestroy: { - signature: 'v(p)', - contextKey, - - callProxy: (callback) => { - return (pVoid) => { - try { - callback(pVoid); - } catch (e) { - console.error('UDF xDestroy method threw:', e); - } - }; - }, - }, - }); - - const __sqlite3CreateFunction = wasm.xWrap( - 'sqlite3_create_function_v2', - 'int', - [ - 'sqlite3*', - 'string', - 'int', - 'int', - '*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xFunc', - ...__cfProxy.xFunc, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xStep', - ...__cfProxy.xInverseAndStep, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xFinal', - ...__cfProxy.xFinalAndValue, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xDestroy', - ...__cfProxy.xDestroy, - }), - ], - ); - - const __sqlite3CreateWindowFunction = wasm.xWrap( - 'sqlite3_create_window_function', - 'int', - [ - 'sqlite3*', - 'string', - 'int', - 'int', - '*', - new wasm.xWrap.FuncPtrAdapter({ - name: 'xStep', - ...__cfProxy.xInverseAndStep, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xFinal', - ...__cfProxy.xFinalAndValue, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xValue', - ...__cfProxy.xFinalAndValue, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xInverse', - ...__cfProxy.xInverseAndStep, - }), - new wasm.xWrap.FuncPtrAdapter({ - name: 'xDestroy', - ...__cfProxy.xDestroy, - }), - ], - ); - - capi.sqlite3_create_function_v2 = function f( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xFunc, - xStep, - xFinal, - xDestroy, - ) { - if (f.length !== arguments.length) { - return __dbArgcMismatch( - pDb, - 'sqlite3_create_function_v2', - f.length, - ); - } else if (0 === (eTextRep & 0xf)) { - eTextRep |= capi.SQLITE_UTF8; - } else if (capi.SQLITE_UTF8 !== (eTextRep & 0xf)) { - return __errEncoding(pDb); - } - try { - const rc = __sqlite3CreateFunction( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xFunc, - xStep, - xFinal, - xDestroy, - ); - if ( - 0 === rc && - (xFunc instanceof Function || - xStep instanceof Function || - xFinal instanceof Function || - xDestroy instanceof Function) - ) { - __dbCleanupMap.addFunction(pDb, funcName, nArg); - } - return rc; - } catch (e) { - console.error('sqlite3_create_function_v2() setup threw:', e); - return util.sqlite3__wasm_db_error( - pDb, - e, - 'Creation of UDF threw: ' + e, - ); - } - }; - - capi.sqlite3_create_function = function f( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xFunc, - xStep, - xFinal, - ) { - return f.length === arguments.length - ? capi.sqlite3_create_function_v2( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xFunc, - xStep, - xFinal, - 0, - ) - : __dbArgcMismatch(pDb, 'sqlite3_create_function', f.length); - }; - - capi.sqlite3_create_window_function = function f( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xStep, - xFinal, - xValue, - xInverse, - xDestroy, - ) { - if (f.length !== arguments.length) { - return __dbArgcMismatch( - pDb, - 'sqlite3_create_window_function', - f.length, - ); - } else if (0 === (eTextRep & 0xf)) { - eTextRep |= capi.SQLITE_UTF8; - } else if (capi.SQLITE_UTF8 !== (eTextRep & 0xf)) { - return __errEncoding(pDb); - } - try { - const rc = __sqlite3CreateWindowFunction( - pDb, - funcName, - nArg, - eTextRep, - pApp, - xStep, - xFinal, - xValue, - xInverse, - xDestroy, - ); - if ( - 0 === rc && - (xStep instanceof Function || - xFinal instanceof Function || - xValue instanceof Function || - xInverse instanceof Function || - xDestroy instanceof Function) - ) { - __dbCleanupMap.addWindowFunc(pDb, funcName, nArg); - } - return rc; - } catch (e) { - console.error('sqlite3_create_window_function() setup threw:', e); - return util.sqlite3__wasm_db_error( - pDb, - e, - 'Creation of UDF threw: ' + e, - ); - } - }; - - capi.sqlite3_create_function_v2.udfSetResult = - capi.sqlite3_create_function.udfSetResult = - capi.sqlite3_create_window_function.udfSetResult = - capi.sqlite3_result_js; - - capi.sqlite3_create_function_v2.udfConvertArgs = - capi.sqlite3_create_function.udfConvertArgs = - capi.sqlite3_create_window_function.udfConvertArgs = - capi.sqlite3_values_to_js; - - capi.sqlite3_create_function_v2.udfSetError = - capi.sqlite3_create_function.udfSetError = - capi.sqlite3_create_window_function.udfSetError = - capi.sqlite3_result_error_js; - } - - { - const __flexiString = (v, n) => { - if ('string' === typeof v) { - n = -1; - } else if (util.isSQLableTypedArray(v)) { - n = v.byteLength; - v = util.typedArrayToString( - v instanceof ArrayBuffer ? new Uint8Array(v) : v, - ); - } else if (Array.isArray(v)) { - v = v.join(''); - n = -1; - } - return [v, n]; - }; - - const __prepare = { - basic: wasm.xWrap('sqlite3_prepare_v3', 'int', [ - 'sqlite3*', - 'string', - 'int', - 'int', - '**', - '**', - ]), - - full: wasm.xWrap('sqlite3_prepare_v3', 'int', [ - 'sqlite3*', - '*', - 'int', - 'int', - '**', - '**', - ]), - }; - - capi.sqlite3_prepare_v3 = function f( - pDb, - sql, - sqlLen, - prepFlags, - ppStmt, - pzTail, - ) { - if (f.length !== arguments.length) { - return __dbArgcMismatch(pDb, 'sqlite3_prepare_v3', f.length); - } - const [xSql, xSqlLen] = __flexiString(sql, sqlLen); - switch (typeof xSql) { - case 'string': - return __prepare.basic( - pDb, - xSql, - xSqlLen, - prepFlags, - ppStmt, - null, - ); - case 'number': - return __prepare.full( - pDb, - xSql, - xSqlLen, - prepFlags, - ppStmt, - pzTail, - ); - default: - return util.sqlite3__wasm_db_error( - pDb, - capi.SQLITE_MISUSE, - 'Invalid SQL argument type for sqlite3_prepare_v2/v3().', - ); - } - }; - - capi.sqlite3_prepare_v2 = function f( - pDb, - sql, - sqlLen, - ppStmt, - pzTail, - ) { - return f.length === arguments.length - ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) - : __dbArgcMismatch(pDb, 'sqlite3_prepare_v2', f.length); - }; - } - - { - const __bindText = wasm.xWrap('sqlite3_bind_text', 'int', [ - 'sqlite3_stmt*', - 'int', - 'string', - 'int', - '*', - ]); - const __bindBlob = wasm.xWrap('sqlite3_bind_blob', 'int', [ - 'sqlite3_stmt*', - 'int', - '*', - 'int', - '*', - ]); - - capi.sqlite3_bind_text = function f( - pStmt, - iCol, - text, - nText, - xDestroy, - ) { - if (f.length !== arguments.length) { - return __dbArgcMismatch( - capi.sqlite3_db_handle(pStmt), - 'sqlite3_bind_text', - f.length, - ); - } else if (wasm.isPtr(text) || null === text) { - return __bindText(pStmt, iCol, text, nText, xDestroy); - } else if (text instanceof ArrayBuffer) { - text = new Uint8Array(text); - } else if (Array.isArray(pMem)) { - text = pMem.join(''); - } - let p, n; - try { - if (util.isSQLableTypedArray(text)) { - p = wasm.allocFromTypedArray(text); - n = text.byteLength; - } else if ('string' === typeof text) { - [p, n] = wasm.allocCString(text); - } else { - return util.sqlite3__wasm_db_error( - capi.sqlite3_db_handle(pStmt), - capi.SQLITE_MISUSE, - 'Invalid 3rd argument type for sqlite3_bind_text().', - ); - } - return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); - } catch (e) { - wasm.dealloc(p); - return util.sqlite3__wasm_db_error( - capi.sqlite3_db_handle(pStmt), - e, - ); - } - }; - - capi.sqlite3_bind_blob = function f( - pStmt, - iCol, - pMem, - nMem, - xDestroy, - ) { - if (f.length !== arguments.length) { - return __dbArgcMismatch( - capi.sqlite3_db_handle(pStmt), - 'sqlite3_bind_blob', - f.length, - ); - } else if (wasm.isPtr(pMem) || null === pMem) { - return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy); - } else if (pMem instanceof ArrayBuffer) { - pMem = new Uint8Array(pMem); - } else if (Array.isArray(pMem)) { - pMem = pMem.join(''); - } - let p, n; - try { - if (util.isBindableTypedArray(pMem)) { - p = wasm.allocFromTypedArray(pMem); - n = nMem >= 0 ? nMem : pMem.byteLength; - } else if ('string' === typeof pMem) { - [p, n] = wasm.allocCString(pMem); - } else { - return util.sqlite3__wasm_db_error( - capi.sqlite3_db_handle(pStmt), - capi.SQLITE_MISUSE, - 'Invalid 3rd argument type for sqlite3_bind_blob().', - ); - } - return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); - } catch (e) { - wasm.dealloc(p); - return util.sqlite3__wasm_db_error( - capi.sqlite3_db_handle(pStmt), - e, - ); - } - }; - } - - { - capi.sqlite3_config = function (op, ...args) { - if (arguments.length < 2) return capi.SQLITE_MISUSE; - switch (op) { - case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN: - case capi.SQLITE_CONFIG_MEMSTATUS: - case capi.SQLITE_CONFIG_SMALL_MALLOC: - case capi.SQLITE_CONFIG_SORTERREF_SIZE: - case capi.SQLITE_CONFIG_STMTJRNL_SPILL: - case capi.SQLITE_CONFIG_URI: - return wasm.exports.sqlite3__wasm_config_i(op, args[0]); - case capi.SQLITE_CONFIG_LOOKASIDE: - return wasm.exports.sqlite3__wasm_config_ii( - op, - args[0], - args[1], - ); - case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: - return wasm.exports.sqlite3__wasm_config_j(op, args[0]); - case capi.SQLITE_CONFIG_GETMALLOC: - case capi.SQLITE_CONFIG_GETMUTEX: - case capi.SQLITE_CONFIG_GETPCACHE2: - case capi.SQLITE_CONFIG_GETPCACHE: - case capi.SQLITE_CONFIG_HEAP: - case capi.SQLITE_CONFIG_LOG: - case capi.SQLITE_CONFIG_MALLOC: - case capi.SQLITE_CONFIG_MMAP_SIZE: - case capi.SQLITE_CONFIG_MULTITHREAD: - case capi.SQLITE_CONFIG_MUTEX: - case capi.SQLITE_CONFIG_PAGECACHE: - case capi.SQLITE_CONFIG_PCACHE2: - case capi.SQLITE_CONFIG_PCACHE: - case capi.SQLITE_CONFIG_PCACHE_HDRSZ: - case capi.SQLITE_CONFIG_PMASZ: - case capi.SQLITE_CONFIG_SERIALIZED: - case capi.SQLITE_CONFIG_SINGLETHREAD: - case capi.SQLITE_CONFIG_SQLLOG: - case capi.SQLITE_CONFIG_WIN32_HEAPSIZE: - default: - return capi.SQLITE_NOTFOUND; - } - }; - } - - { - const __autoExtFptr = new Set(); - - capi.sqlite3_auto_extension = function (fPtr) { - if (fPtr instanceof Function) { - fPtr = wasm.installFunction('i(ppp)', fPtr); - } else if (1 !== arguments.length || !wasm.isPtr(fPtr)) { - return capi.SQLITE_MISUSE; - } - const rc = wasm.exports.sqlite3_auto_extension(fPtr); - if (fPtr !== arguments[0]) { - if (0 === rc) __autoExtFptr.add(fPtr); - else wasm.uninstallFunction(fPtr); - } - return rc; - }; - - capi.sqlite3_cancel_auto_extension = function (fPtr) { - if (!fPtr || 1 !== arguments.length || !wasm.isPtr(fPtr)) return 0; - return wasm.exports.sqlite3_cancel_auto_extension(fPtr); - }; - - capi.sqlite3_reset_auto_extension = function () { - wasm.exports.sqlite3_reset_auto_extension(); - for (const fp of __autoExtFptr) wasm.uninstallFunction(fp); - __autoExtFptr.clear(); - }; - } - - const pKvvfs = capi.sqlite3_vfs_find('kvvfs'); - if (pKvvfs) { - if (util.isUIThread()) { - const kvvfsMethods = new capi.sqlite3_kvvfs_methods( - wasm.exports.sqlite3__wasm_kvvfs_methods(), - ); - delete capi.sqlite3_kvvfs_methods; - - const kvvfsMakeKey = - wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack, - pstack = wasm.pstack; - - const kvvfsStorage = (zClass) => - 115 === wasm.peek(zClass) ? sessionStorage : localStorage; - - const kvvfsImpls = { - xRead: (zClass, zKey, zBuf, nBuf) => { - const stack = pstack.pointer, - astack = wasm.scopedAllocPush(); - try { - const zXKey = kvvfsMakeKey(zClass, zKey); - if (!zXKey) return -3; - const jKey = wasm.cstrToJs(zXKey); - const jV = kvvfsStorage(zClass).getItem(jKey); - if (!jV) return -1; - const nV = jV.length; - if (nBuf <= 0) return nV; - else if (1 === nBuf) { - wasm.poke(zBuf, 0); - return nV; - } - const zV = wasm.scopedAllocCString(jV); - if (nBuf > nV + 1) nBuf = nV + 1; - wasm.heap8u().copyWithin(zBuf, zV, zV + nBuf - 1); - wasm.poke(zBuf + nBuf - 1, 0); - return nBuf - 1; - } catch (e) { - console.error('kvstorageRead()', e); - return -2; - } finally { - pstack.restore(stack); - wasm.scopedAllocPop(astack); - } - }, - xWrite: (zClass, zKey, zData) => { - const stack = pstack.pointer; - try { - const zXKey = kvvfsMakeKey(zClass, zKey); - if (!zXKey) return 1; - const jKey = wasm.cstrToJs(zXKey); - kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData)); - return 0; - } catch (e) { - console.error('kvstorageWrite()', e); - return capi.SQLITE_IOERR; - } finally { - pstack.restore(stack); - } - }, - xDelete: (zClass, zKey) => { - const stack = pstack.pointer; - try { - const zXKey = kvvfsMakeKey(zClass, zKey); - if (!zXKey) return 1; - kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey)); - return 0; - } catch (e) { - console.error('kvstorageDelete()', e); - return capi.SQLITE_IOERR; - } finally { - pstack.restore(stack); - } - }, - }; - for (const k of Object.keys(kvvfsImpls)) { - kvvfsMethods[kvvfsMethods.memberKey(k)] = wasm.installFunction( - kvvfsMethods.memberSignature(k), - kvvfsImpls[k], - ); - } - } else { - capi.sqlite3_vfs_unregister(pKvvfs); - } - } - - wasm.xWrap.FuncPtrAdapter.warnOnUse = true; - - const StructBinder = sqlite3.StructBinder; - const installMethod = function callee( - tgt, - name, - func, - applyArgcCheck = callee.installMethodArgcCheck, - ) { - if (!(tgt instanceof StructBinder.StructType)) { - toss('Usage error: target object is-not-a StructType.'); - } else if (!(func instanceof Function) && !wasm.isPtr(func)) { - toss('Usage errror: expecting a Function or WASM pointer to one.'); - } - if (1 === arguments.length) { - return (n, f) => callee(tgt, n, f, applyArgcCheck); - } - if (!callee.argcProxy) { - callee.argcProxy = function (tgt, funcName, func, sig) { - return function (...args) { - if (func.length !== arguments.length) { - toss( - 'Argument mismatch for', - tgt.structInfo.name + - '::' + - funcName + - ': Native signature is:', - sig, - ); - } - return func.apply(this, args); - }; - }; - - callee.removeFuncList = function () { - if (this.ondispose.__removeFuncList) { - this.ondispose.__removeFuncList.forEach((v, ndx) => { - if ('number' === typeof v) { - try { - wasm.uninstallFunction(v); - } catch (e) {} - } - }); - delete this.ondispose.__removeFuncList; - } - }; - } - const sigN = tgt.memberSignature(name); - if (sigN.length < 2) { - toss( - 'Member', - name, - 'does not have a function pointer signature:', - sigN, - ); - } - const memKey = tgt.memberKey(name); - const fProxy = - applyArgcCheck && !wasm.isPtr(func) - ? callee.argcProxy(tgt, memKey, func, sigN) - : func; - if (wasm.isPtr(fProxy)) { - if (fProxy && !wasm.functionEntry(fProxy)) { - toss('Pointer', fProxy, 'is not a WASM function table entry.'); - } - tgt[memKey] = fProxy; - } else { - const pFunc = wasm.installFunction( - fProxy, - tgt.memberSignature(name, true), - ); - tgt[memKey] = pFunc; - if (!tgt.ondispose || !tgt.ondispose.__removeFuncList) { - tgt.addOnDispose( - 'ondispose.__removeFuncList handler', - callee.removeFuncList, - ); - tgt.ondispose.__removeFuncList = []; - } - tgt.ondispose.__removeFuncList.push(memKey, pFunc); - } - return (n, f) => callee(tgt, n, f, applyArgcCheck); - }; - installMethod.installMethodArgcCheck = false; - - const installMethods = function ( - structInstance, - methods, - applyArgcCheck = installMethod.installMethodArgcCheck, - ) { - const seen = new Map(); - for (const k of Object.keys(methods)) { - const m = methods[k]; - const prior = seen.get(m); - if (prior) { - const mkey = structInstance.memberKey(k); - structInstance[mkey] = - structInstance[structInstance.memberKey(prior)]; - } else { - installMethod(structInstance, k, m, applyArgcCheck); - seen.set(m, k); - } - } - return structInstance; - }; - - StructBinder.StructType.prototype.installMethod = function callee( - name, - func, - applyArgcCheck = installMethod.installMethodArgcCheck, - ) { - return arguments.length < 3 && name && 'object' === typeof name - ? installMethods(this, ...arguments) - : installMethod(this, ...arguments); - }; - - StructBinder.StructType.prototype.installMethods = function ( - methods, - applyArgcCheck = installMethod.installMethodArgcCheck, - ) { - return installMethods(this, methods, applyArgcCheck); - }; - }); - - globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { - sqlite3.version = { - libVersion: '3.46.1', - libVersionNumber: 3046001, - sourceId: - '2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33', - downloadVersion: 3460100, - }; - }); - - globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { - const toss3 = (...args) => { - throw new sqlite3.SQLite3Error(...args); - }; - - const capi = sqlite3.capi, - wasm = sqlite3.wasm, - util = sqlite3.util; - - const __ptrMap = new WeakMap(); - - const __stmtMap = new WeakMap(); - - const getOwnOption = (opts, p, dflt) => { - const d = Object.getOwnPropertyDescriptor(opts, p); - return d ? d.value : dflt; - }; - - const checkSqlite3Rc = function (dbPtr, sqliteResultCode) { - if (sqliteResultCode) { - if (dbPtr instanceof DB) dbPtr = dbPtr.pointer; - toss3( - sqliteResultCode, - 'sqlite3 result code', - sqliteResultCode + ':', - dbPtr - ? capi.sqlite3_errmsg(dbPtr) - : capi.sqlite3_errstr(sqliteResultCode), - ); - } - return arguments[0]; - }; - - const __dbTraceToConsole = wasm.installFunction( - 'i(ippp)', - function (t, c, p, x) { - if (capi.SQLITE_TRACE_STMT === t) { - console.log( - 'SQL TRACE #' + ++this.counter + ' via sqlite3@' + c + ':', - wasm.cstrToJs(x), - ); - } - }.bind({ counter: 0 }), - ); - - const __vfsPostOpenSql = Object.create(null); - - const dbCtorHelper = function ctor(...args) { - if (!ctor._name2vfs) { - ctor._name2vfs = Object.create(null); - const isWorkerThread = - 'function' === typeof importScripts - ? (n) => - toss3( - 'The VFS for', - n, - 'is only available in the main window thread.', - ) - : false; - ctor._name2vfs[':localStorage:'] = { - vfs: 'kvvfs', - filename: isWorkerThread || (() => 'local'), - }; - ctor._name2vfs[':sessionStorage:'] = { - vfs: 'kvvfs', - filename: isWorkerThread || (() => 'session'), - }; - } - const opt = ctor.normalizeArgs(...args); - let fn = opt.filename, - vfsName = opt.vfs, - flagsStr = opt.flags; - if ( - ('string' !== typeof fn && 'number' !== typeof fn) || - 'string' !== typeof flagsStr || - (vfsName && - 'string' !== typeof vfsName && - 'number' !== typeof vfsName) - ) { - sqlite3.config.error('Invalid DB ctor args', opt, arguments); - toss3('Invalid arguments for DB constructor.'); - } - let fnJs = 'number' === typeof fn ? wasm.cstrToJs(fn) : fn; - const vfsCheck = ctor._name2vfs[fnJs]; - if (vfsCheck) { - vfsName = vfsCheck.vfs; - fn = fnJs = vfsCheck.filename(fnJs); - } - let pDb, - oflags = 0; - if (flagsStr.indexOf('c') >= 0) { - oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; - } - if (flagsStr.indexOf('w') >= 0) oflags |= capi.SQLITE_OPEN_READWRITE; - if (0 === oflags) oflags |= capi.SQLITE_OPEN_READONLY; - oflags |= capi.SQLITE_OPEN_EXRESCODE; - const stack = wasm.pstack.pointer; - try { - const pPtr = wasm.pstack.allocPtr(); - let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0); - pDb = wasm.peekPtr(pPtr); - checkSqlite3Rc(pDb, rc); - capi.sqlite3_extended_result_codes(pDb, 1); - if (flagsStr.indexOf('t') >= 0) { - capi.sqlite3_trace_v2( - pDb, - capi.SQLITE_TRACE_STMT, - __dbTraceToConsole, - pDb, - ); - } - } catch (e) { - if (pDb) capi.sqlite3_close_v2(pDb); - throw e; - } finally { - wasm.pstack.restore(stack); - } - this.filename = fnJs; - __ptrMap.set(this, pDb); - __stmtMap.set(this, Object.create(null)); - try { - const pVfs = - capi.sqlite3_js_db_vfs(pDb) || - toss3('Internal error: cannot get VFS for new db handle.'); - const postInitSql = __vfsPostOpenSql[pVfs]; - if (postInitSql) { - if (postInitSql instanceof Function) { - postInitSql(this, sqlite3); - } else { - checkSqlite3Rc( - pDb, - capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0), - ); - } - } - } catch (e) { - this.close(); - throw e; - } - }; - - dbCtorHelper.setVfsPostOpenSql = function (pVfs, sql) { - __vfsPostOpenSql[pVfs] = sql; - }; - - dbCtorHelper.normalizeArgs = function ( - filename = ':memory:', - flags = 'c', - vfs = null, - ) { - const arg = {}; - if ( - 1 === arguments.length && - arguments[0] && - 'object' === typeof arguments[0] - ) { - Object.assign(arg, arguments[0]); - if (undefined === arg.flags) arg.flags = 'c'; - if (undefined === arg.vfs) arg.vfs = null; - if (undefined === arg.filename) arg.filename = ':memory:'; - } else { - arg.filename = filename; - arg.flags = flags; - arg.vfs = vfs; - } - return arg; - }; - - const DB = function (...args) { - dbCtorHelper.apply(this, args); - }; - DB.dbCtorHelper = dbCtorHelper; - - const BindTypes = { - null: 1, - number: 2, - string: 3, - boolean: 4, - blob: 5, - }; - BindTypes['undefined'] == BindTypes.null; - if (wasm.bigIntEnabled) { - BindTypes.bigint = BindTypes.number; - } - - const Stmt = function () { - if (BindTypes !== arguments[2]) { - toss3( - capi.SQLITE_MISUSE, - 'Do not call the Stmt constructor directly. Use DB.prepare().', - ); - } - this.db = arguments[0]; - __ptrMap.set(this, arguments[1]); - this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer); - }; - - const affirmDbOpen = function (db) { - if (!db.pointer) toss3('DB has been closed.'); - return db; - }; - - const affirmColIndex = function (stmt, ndx) { - if (ndx !== (ndx | 0) || ndx < 0 || ndx >= stmt.columnCount) { - toss3('Column index', ndx, 'is out of range.'); - } - return stmt; - }; - - const parseExecArgs = function (db, args) { - const out = Object.create(null); - out.opt = Object.create(null); - switch (args.length) { - case 1: - if ( - 'string' === typeof args[0] || - util.isSQLableTypedArray(args[0]) - ) { - out.sql = args[0]; - } else if (Array.isArray(args[0])) { - out.sql = args[0]; - } else if (args[0] && 'object' === typeof args[0]) { - out.opt = args[0]; - out.sql = out.opt.sql; - } - break; - case 2: - out.sql = args[0]; - out.opt = args[1]; - break; - default: - toss3('Invalid argument count for exec().'); - } - out.sql = util.flexibleString(out.sql); - if ('string' !== typeof out.sql) { - toss3('Missing SQL argument or unsupported SQL value type.'); - } - const opt = out.opt; - switch (opt.returnValue) { - case 'resultRows': - if (!opt.resultRows) opt.resultRows = []; - out.returnVal = () => opt.resultRows; - break; - case 'saveSql': - if (!opt.saveSql) opt.saveSql = []; - out.returnVal = () => opt.saveSql; - break; - case undefined: - case 'this': - out.returnVal = () => db; - break; - default: - toss3('Invalid returnValue value:', opt.returnValue); - } - if (!opt.callback && !opt.returnValue && undefined !== opt.rowMode) { - if (!opt.resultRows) opt.resultRows = []; - out.returnVal = () => opt.resultRows; - } - if (opt.callback || opt.resultRows) { - switch (undefined === opt.rowMode ? 'array' : opt.rowMode) { - case 'object': - out.cbArg = (stmt, cache) => { - if (!cache.columnNames) - cache.columnNames = stmt.getColumnNames([]); - - const row = stmt.get([]); - const rv = Object.create(null); - for (const i in cache.columnNames) - rv[cache.columnNames[i]] = row[i]; - return rv; - }; - break; - case 'array': - out.cbArg = (stmt) => stmt.get([]); - break; - case 'stmt': - if (Array.isArray(opt.resultRows)) { - toss3( - 'exec(): invalid rowMode for a resultRows array: must', - "be one of 'array', 'object',", - 'a result column number, or column name reference.', - ); - } - out.cbArg = (stmt) => stmt; - break; - default: - if (util.isInt32(opt.rowMode)) { - out.cbArg = (stmt) => stmt.get(opt.rowMode); - break; - } else if ( - 'string' === typeof opt.rowMode && - opt.rowMode.length > 1 && - '$' === opt.rowMode[0] - ) { - const $colName = opt.rowMode.substr(1); - out.cbArg = (stmt) => { - const rc = stmt.get(Object.create(null))[$colName]; - return undefined === rc - ? toss3( - capi.SQLITE_NOTFOUND, - 'exec(): unknown result column:', - $colName, - ) - : rc; - }; - break; - } - toss3('Invalid rowMode:', opt.rowMode); - } - } - return out; - }; - - const __selectFirstRow = (db, sql, bind, ...getArgs) => { - const stmt = db.prepare(sql); - try { - const rc = stmt.bind(bind).step() - ? stmt.get(...getArgs) - : undefined; - stmt.reset(); - return rc; - } finally { - stmt.finalize(); - } - }; - - const __selectAll = (db, sql, bind, rowMode) => - db.exec({ - sql, - bind, - rowMode, - returnValue: 'resultRows', - }); - - DB.checkRc = (db, resultCode) => checkSqlite3Rc(db, resultCode); - - DB.prototype = { - isOpen: function () { - return !!this.pointer; - }, - - affirmOpen: function () { - return affirmDbOpen(this); - }, - - close: function () { - if (this.pointer) { - if (this.onclose && this.onclose.before instanceof Function) { - try { - this.onclose.before(this); - } catch (e) {} - } - const pDb = this.pointer; - Object.keys(__stmtMap.get(this)).forEach((k, s) => { - if (s && s.pointer) { - try { - s.finalize(); - } catch (e) {} - } - }); - __ptrMap.delete(this); - __stmtMap.delete(this); - capi.sqlite3_close_v2(pDb); - if (this.onclose && this.onclose.after instanceof Function) { - try { - this.onclose.after(this); - } catch (e) {} - } - delete this.filename; - } - }, - - changes: function (total = false, sixtyFour = false) { - const p = affirmDbOpen(this).pointer; - if (total) { - return sixtyFour - ? capi.sqlite3_total_changes64(p) - : capi.sqlite3_total_changes(p); - } else { - return sixtyFour - ? capi.sqlite3_changes64(p) - : capi.sqlite3_changes(p); - } - }, - - dbFilename: function (dbName = 'main') { - return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName); - }, - - dbName: function (dbNumber = 0) { - return capi.sqlite3_db_name(affirmDbOpen(this).pointer, dbNumber); - }, - - dbVfsName: function (dbName = 0) { - let rc; - const pVfs = capi.sqlite3_js_db_vfs( - affirmDbOpen(this).pointer, - dbName, - ); - if (pVfs) { - const v = new capi.sqlite3_vfs(pVfs); - try { - rc = wasm.cstrToJs(v.$zName); - } finally { - v.dispose(); - } - } - return rc; - }, - - prepare: function (sql) { - affirmDbOpen(this); - const stack = wasm.pstack.pointer; - let ppStmt, pStmt; - try { - ppStmt = wasm.pstack.alloc(8); - DB.checkRc( - this, - capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null), - ); - pStmt = wasm.peekPtr(ppStmt); - } finally { - wasm.pstack.restore(stack); - } - if (!pStmt) toss3('Cannot prepare empty SQL.'); - const stmt = new Stmt(this, pStmt, BindTypes); - __stmtMap.get(this)[pStmt] = stmt; - return stmt; - }, - - exec: function () { - affirmDbOpen(this); - const arg = parseExecArgs(this, arguments); - if (!arg.sql) { - return toss3('exec() requires an SQL string.'); - } - const opt = arg.opt; - const callback = opt.callback; - const resultRows = Array.isArray(opt.resultRows) - ? opt.resultRows - : undefined; - let stmt; - let bind = opt.bind; - let evalFirstResult = !!( - arg.cbArg || - opt.columnNames || - resultRows - ); - const stack = wasm.scopedAllocPush(); - const saveSql = Array.isArray(opt.saveSql) - ? opt.saveSql - : undefined; - try { - const isTA = util.isSQLableTypedArray(arg.sql); - let sqlByteLen = isTA - ? arg.sql.byteLength - : wasm.jstrlen(arg.sql); - const ppStmt = wasm.scopedAlloc( - 2 * wasm.ptrSizeof + (sqlByteLen + 1), - ); - const pzTail = ppStmt + wasm.ptrSizeof; - let pSql = pzTail + wasm.ptrSizeof; - const pSqlEnd = pSql + sqlByteLen; - if (isTA) wasm.heap8().set(arg.sql, pSql); - else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false); - wasm.poke(pSql + sqlByteLen, 0); - while (pSql && wasm.peek(pSql, 'i8')) { - wasm.pokePtr([ppStmt, pzTail], 0); - DB.checkRc( - this, - capi.sqlite3_prepare_v3( - this.pointer, - pSql, - sqlByteLen, - 0, - ppStmt, - pzTail, - ), - ); - const pStmt = wasm.peekPtr(ppStmt); - pSql = wasm.peekPtr(pzTail); - sqlByteLen = pSqlEnd - pSql; - if (!pStmt) continue; - if (saveSql) saveSql.push(capi.sqlite3_sql(pStmt).trim()); - stmt = new Stmt(this, pStmt, BindTypes); - if (bind && stmt.parameterCount) { - stmt.bind(bind); - bind = null; - } - if (evalFirstResult && stmt.columnCount) { - let gotColNames = Array.isArray(opt.columnNames) ? 0 : 1; - evalFirstResult = false; - if (arg.cbArg || resultRows) { - const cbArgCache = Object.create(null); - for (; stmt.step(); stmt._lockedByExec = false) { - if (0 === gotColNames++) { - stmt.getColumnNames( - (cbArgCache.columnNames = opt.columnNames || []), - ); - } - stmt._lockedByExec = true; - const row = arg.cbArg(stmt, cbArgCache); - if (resultRows) resultRows.push(row); - if (callback && false === callback.call(opt, row, stmt)) { - break; - } - } - stmt._lockedByExec = false; - } - if (0 === gotColNames) { - stmt.getColumnNames(opt.columnNames); - } - } else { - stmt.step(); - } - stmt.reset().finalize(); - stmt = null; - } - } finally { - wasm.scopedAllocPop(stack); - if (stmt) { - delete stmt._lockedByExec; - stmt.finalize(); - } - } - return arg.returnVal(); - }, - - createFunction: function f(name, xFunc, opt) { - const isFunc = (f) => f instanceof Function; - switch (arguments.length) { - case 1: - opt = name; - name = opt.name; - xFunc = opt.xFunc || 0; - break; - case 2: - if (!isFunc(xFunc)) { - opt = xFunc; - xFunc = opt.xFunc || 0; - } - break; - } - if (!opt) opt = {}; - if ('string' !== typeof name) { - toss3('Invalid arguments: missing function name.'); - } - let xStep = opt.xStep || 0; - let xFinal = opt.xFinal || 0; - const xValue = opt.xValue || 0; - const xInverse = opt.xInverse || 0; - let isWindow = undefined; - if (isFunc(xFunc)) { - isWindow = false; - if (isFunc(xStep) || isFunc(xFinal)) { - toss3('Ambiguous arguments: scalar or aggregate?'); - } - xStep = xFinal = null; - } else if (isFunc(xStep)) { - if (!isFunc(xFinal)) { - toss3('Missing xFinal() callback for aggregate or window UDF.'); - } - xFunc = null; - } else if (isFunc(xFinal)) { - toss3('Missing xStep() callback for aggregate or window UDF.'); - } else { - toss3('Missing function-type properties.'); - } - if (false === isWindow) { - if (isFunc(xValue) || isFunc(xInverse)) { - toss3( - 'xValue and xInverse are not permitted for non-window UDFs.', - ); - } - } else if (isFunc(xValue)) { - if (!isFunc(xInverse)) { - toss3('xInverse must be provided if xValue is.'); - } - isWindow = true; - } else if (isFunc(xInverse)) { - toss3('xValue must be provided if xInverse is.'); - } - const pApp = opt.pApp; - if ( - undefined !== pApp && - null !== pApp && - ('number' !== typeof pApp || !util.isInt32(pApp)) - ) { - toss3( - 'Invalid value for pApp property. Must be a legal WASM pointer value.', - ); - } - const xDestroy = opt.xDestroy || 0; - if (xDestroy && !isFunc(xDestroy)) { - toss3('xDestroy property must be a function.'); - } - let fFlags = 0; - if (getOwnOption(opt, 'deterministic')) - fFlags |= capi.SQLITE_DETERMINISTIC; - if (getOwnOption(opt, 'directOnly')) - fFlags |= capi.SQLITE_DIRECTONLY; - if (getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS; - name = name.toLowerCase(); - const xArity = xFunc || xStep; - const arity = getOwnOption(opt, 'arity'); - const arityArg = - 'number' === typeof arity - ? arity - : xArity.length - ? xArity.length - 1 - : 0; - let rc; - if (isWindow) { - rc = capi.sqlite3_create_window_function( - this.pointer, - name, - arityArg, - capi.SQLITE_UTF8 | fFlags, - pApp || 0, - xStep, - xFinal, - xValue, - xInverse, - xDestroy, - ); - } else { - rc = capi.sqlite3_create_function_v2( - this.pointer, - name, - arityArg, - capi.SQLITE_UTF8 | fFlags, - pApp || 0, - xFunc, - xStep, - xFinal, - xDestroy, - ); - } - DB.checkRc(this, rc); - return this; - }, - - selectValue: function (sql, bind, asType) { - return __selectFirstRow(this, sql, bind, 0, asType); - }, - - selectValues: function (sql, bind, asType) { - const stmt = this.prepare(sql), - rc = []; - try { - stmt.bind(bind); - while (stmt.step()) rc.push(stmt.get(0, asType)); - stmt.reset(); - } finally { - stmt.finalize(); - } - return rc; - }, - - selectArray: function (sql, bind) { - return __selectFirstRow(this, sql, bind, []); - }, - - selectObject: function (sql, bind) { - return __selectFirstRow(this, sql, bind, {}); - }, - - selectArrays: function (sql, bind) { - return __selectAll(this, sql, bind, 'array'); - }, - - selectObjects: function (sql, bind) { - return __selectAll(this, sql, bind, 'object'); - }, - - openStatementCount: function () { - return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0; - }, - - transaction: function (callback) { - let opener = 'BEGIN'; - if (arguments.length > 1) { - if (/[^a-zA-Z]/.test(arguments[0])) { - toss3( - capi.SQLITE_MISUSE, - 'Invalid argument for BEGIN qualifier.', - ); - } - opener += ' ' + arguments[0]; - callback = arguments[1]; - } - affirmDbOpen(this).exec(opener); - try { - const rc = callback(this); - this.exec('COMMIT'); - return rc; - } catch (e) { - this.exec('ROLLBACK'); - throw e; - } - }, - - savepoint: function (callback) { - affirmDbOpen(this).exec('SAVEPOINT oo1'); - try { - const rc = callback(this); - this.exec('RELEASE oo1'); - return rc; - } catch (e) { - this.exec('ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1'); - throw e; - } - }, - - checkRc: function (resultCode) { - return checkSqlite3Rc(this, resultCode); - }, - }; - - const affirmStmtOpen = function (stmt) { - if (!stmt.pointer) toss3('Stmt has been closed.'); - return stmt; - }; - - const isSupportedBindType = function (v) { - let t = BindTypes[null === v || undefined === v ? 'null' : typeof v]; - switch (t) { - case BindTypes.boolean: - case BindTypes.null: - case BindTypes.number: - case BindTypes.string: - return t; - case BindTypes.bigint: - if (wasm.bigIntEnabled) return t; - - default: - return util.isBindableTypedArray(v) ? BindTypes.blob : undefined; - } - }; - - const affirmSupportedBindType = function (v) { - return ( - isSupportedBindType(v) || - toss3('Unsupported bind() argument type:', typeof v) - ); - }; - - const affirmParamIndex = function (stmt, key) { - const n = - 'number' === typeof key - ? key - : capi.sqlite3_bind_parameter_index(stmt.pointer, key); - if (0 === n || !util.isInt32(n)) { - toss3('Invalid bind() parameter name: ' + key); - } else if (n < 1 || n > stmt.parameterCount) - toss3('Bind index', key, 'is out of range.'); - return n; - }; - - const affirmNotLockedByExec = function (stmt, currentOpName) { - if (stmt._lockedByExec) { - toss3( - 'Operation is illegal when statement is locked:', - currentOpName, - ); - } - return stmt; - }; - - const bindOne = function f(stmt, ndx, bindType, val) { - affirmNotLockedByExec(affirmStmtOpen(stmt), 'bind()'); - if (!f._) { - f._tooBigInt = (v) => - toss3( - 'BigInt value is too big to store without precision loss:', - v, - ); - f._ = { - string: function (stmt, ndx, val, asBlob) { - const [pStr, n] = wasm.allocCString(val, true); - const f = asBlob - ? capi.sqlite3_bind_blob - : capi.sqlite3_bind_text; - return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_WASM_DEALLOC); - }, - }; - } - affirmSupportedBindType(val); - ndx = affirmParamIndex(stmt, ndx); - let rc = 0; - switch ( - null === val || undefined === val ? BindTypes.null : bindType - ) { - case BindTypes.null: - rc = capi.sqlite3_bind_null(stmt.pointer, ndx); - break; - case BindTypes.string: - rc = f._.string(stmt, ndx, val, false); - break; - case BindTypes.number: { - let m; - if (util.isInt32(val)) m = capi.sqlite3_bind_int; - else if ('bigint' === typeof val) { - if (!util.bigIntFits64(val)) { - f._tooBigInt(val); - } else if (wasm.bigIntEnabled) { - m = capi.sqlite3_bind_int64; - } else if (util.bigIntFitsDouble(val)) { - val = Number(val); - m = capi.sqlite3_bind_double; - } else { - f._tooBigInt(val); - } - } else { - val = Number(val); - if (wasm.bigIntEnabled && Number.isInteger(val)) { - m = capi.sqlite3_bind_int64; - } else { - m = capi.sqlite3_bind_double; - } - } - rc = m(stmt.pointer, ndx, val); - break; - } - case BindTypes.boolean: - rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0); - break; - case BindTypes.blob: { - if ('string' === typeof val) { - rc = f._.string(stmt, ndx, val, true); - break; - } else if (val instanceof ArrayBuffer) { - val = new Uint8Array(val); - } else if (!util.isBindableTypedArray(val)) { - toss3( - 'Binding a value as a blob requires', - 'that it be a string, Uint8Array, Int8Array, or ArrayBuffer.', - ); - } - const pBlob = wasm.alloc(val.byteLength || 1); - wasm.heap8().set(val.byteLength ? val : [0], pBlob); - rc = capi.sqlite3_bind_blob( - stmt.pointer, - ndx, - pBlob, - val.byteLength, - capi.SQLITE_WASM_DEALLOC, - ); - break; - } - default: - sqlite3.config.warn('Unsupported bind() argument type:', val); - toss3('Unsupported bind() argument type: ' + typeof val); - } - if (rc) DB.checkRc(stmt.db.pointer, rc); - stmt._mayGet = false; - return stmt; - }; - - Stmt.prototype = { - finalize: function () { - if (this.pointer) { - affirmNotLockedByExec(this, 'finalize()'); - const rc = capi.sqlite3_finalize(this.pointer); - delete __stmtMap.get(this.db)[this.pointer]; - __ptrMap.delete(this); - delete this._mayGet; - delete this.parameterCount; - delete this._lockedByExec; - delete this.db; - return rc; - } - }, - - clearBindings: function () { - affirmNotLockedByExec(affirmStmtOpen(this), 'clearBindings()'); - capi.sqlite3_clear_bindings(this.pointer); - this._mayGet = false; - return this; - }, - - reset: function (alsoClearBinds) { - affirmNotLockedByExec(this, 'reset()'); - if (alsoClearBinds) this.clearBindings(); - const rc = capi.sqlite3_reset(affirmStmtOpen(this).pointer); - this._mayGet = false; - checkSqlite3Rc(this.db, rc); - return this; - }, - - bind: function () { - affirmStmtOpen(this); - let ndx, arg; - switch (arguments.length) { - case 1: - ndx = 1; - arg = arguments[0]; - break; - case 2: - ndx = arguments[0]; - arg = arguments[1]; - break; - default: - toss3('Invalid bind() arguments.'); - } - if (undefined === arg) { - return this; - } else if (!this.parameterCount) { - toss3('This statement has no bindable parameters.'); - } - this._mayGet = false; - if (null === arg) { - return bindOne(this, ndx, BindTypes.null, arg); - } else if (Array.isArray(arg)) { - if (1 !== arguments.length) { - toss3( - 'When binding an array, an index argument is not permitted.', - ); - } - arg.forEach((v, i) => - bindOne(this, i + 1, affirmSupportedBindType(v), v), - ); - return this; - } else if (arg instanceof ArrayBuffer) { - arg = new Uint8Array(arg); - } - if ('object' === typeof arg && !util.isBindableTypedArray(arg)) { - if (1 !== arguments.length) { - toss3( - 'When binding an object, an index argument is not permitted.', - ); - } - Object.keys(arg).forEach((k) => - bindOne(this, k, affirmSupportedBindType(arg[k]), arg[k]), - ); - return this; - } else { - return bindOne(this, ndx, affirmSupportedBindType(arg), arg); - } - }, - - bindAsBlob: function (ndx, arg) { - affirmStmtOpen(this); - if (1 === arguments.length) { - arg = ndx; - ndx = 1; - } - const t = affirmSupportedBindType(arg); - if ( - BindTypes.string !== t && - BindTypes.blob !== t && - BindTypes.null !== t - ) { - toss3('Invalid value type for bindAsBlob()'); - } - return bindOne(this, ndx, BindTypes.blob, arg); - }, - - step: function () { - affirmNotLockedByExec(this, 'step()'); - const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer); - switch (rc) { - case capi.SQLITE_DONE: - return (this._mayGet = false); - case capi.SQLITE_ROW: - return (this._mayGet = true); - default: - this._mayGet = false; - sqlite3.config.warn( - 'sqlite3_step() rc=', - rc, - capi.sqlite3_js_rc_str(rc), - 'SQL =', - capi.sqlite3_sql(this.pointer), - ); - DB.checkRc(this.db.pointer, rc); - } - }, - - stepReset: function () { - this.step(); - return this.reset(); - }, - - stepFinalize: function () { - try { - const rc = this.step(); - this.reset(); - return rc; - } finally { - try { - this.finalize(); - } catch (e) {} - } - }, - - get: function (ndx, asType) { - if (!affirmStmtOpen(this)._mayGet) { - toss3('Stmt.step() has not (recently) returned true.'); - } - if (Array.isArray(ndx)) { - let i = 0; - const n = this.columnCount; - while (i < n) { - ndx[i] = this.get(i++); - } - return ndx; - } else if (ndx && 'object' === typeof ndx) { - let i = 0; - const n = this.columnCount; - while (i < n) { - ndx[capi.sqlite3_column_name(this.pointer, i)] = this.get(i++); - } - return ndx; - } - affirmColIndex(this, ndx); - switch ( - undefined === asType - ? capi.sqlite3_column_type(this.pointer, ndx) - : asType - ) { - case capi.SQLITE_NULL: - return null; - case capi.SQLITE_INTEGER: { - if (wasm.bigIntEnabled) { - const rc = capi.sqlite3_column_int64(this.pointer, ndx); - if ( - rc >= Number.MIN_SAFE_INTEGER && - rc <= Number.MAX_SAFE_INTEGER - ) { - return Number(rc).valueOf(); - } - return rc; - } else { - const rc = capi.sqlite3_column_double(this.pointer, ndx); - if ( - rc > Number.MAX_SAFE_INTEGER || - rc < Number.MIN_SAFE_INTEGER - ) { - toss3( - 'Integer is out of range for JS integer range: ' + rc, - ); - } - - return util.isInt32(rc) ? rc | 0 : rc; - } - } - case capi.SQLITE_FLOAT: - return capi.sqlite3_column_double(this.pointer, ndx); - case capi.SQLITE_TEXT: - return capi.sqlite3_column_text(this.pointer, ndx); - case capi.SQLITE_BLOB: { - const n = capi.sqlite3_column_bytes(this.pointer, ndx), - ptr = capi.sqlite3_column_blob(this.pointer, ndx), - rc = new Uint8Array(n); - - if (n) rc.set(wasm.heap8u().slice(ptr, ptr + n), 0); - - if (n && this.db._blobXfer instanceof Array) { - this.db._blobXfer.push(rc.buffer); - } - return rc; - } - default: - toss3( - "Don't know how to translate", - 'type of result column #' + ndx + '.', - ); - } - toss3('Not reached.'); - }, - - getInt: function (ndx) { - return this.get(ndx, capi.SQLITE_INTEGER); - }, - - getFloat: function (ndx) { - return this.get(ndx, capi.SQLITE_FLOAT); - }, - - getString: function (ndx) { - return this.get(ndx, capi.SQLITE_TEXT); - }, - - getBlob: function (ndx) { - return this.get(ndx, capi.SQLITE_BLOB); - }, - - getJSON: function (ndx) { - const s = this.get(ndx, capi.SQLITE_STRING); - return null === s ? s : JSON.parse(s); - }, - - getColumnName: function (ndx) { - return capi.sqlite3_column_name( - affirmColIndex(affirmStmtOpen(this), ndx).pointer, - ndx, - ); - }, - - getColumnNames: function (tgt = []) { - affirmColIndex(affirmStmtOpen(this), 0); - const n = this.columnCount; - for (let i = 0; i < n; ++i) { - tgt.push(capi.sqlite3_column_name(this.pointer, i)); - } - return tgt; - }, - - getParamIndex: function (name) { - return affirmStmtOpen(this).parameterCount - ? capi.sqlite3_bind_parameter_index(this.pointer, name) - : undefined; - }, - }; - - { - const prop = { - enumerable: true, - get: function () { - return __ptrMap.get(this); - }, - set: () => toss3('The pointer property is read-only.'), - }; - Object.defineProperty(Stmt.prototype, 'pointer', prop); - Object.defineProperty(DB.prototype, 'pointer', prop); - } - - Object.defineProperty(Stmt.prototype, 'columnCount', { - enumerable: false, - get: function () { - return capi.sqlite3_column_count(this.pointer); - }, - set: () => toss3('The columnCount property is read-only.'), - }); - - sqlite3.oo1 = { - DB, - Stmt, - }; - - if (util.isUIThread()) { - sqlite3.oo1.JsStorageDb = function (storageName = 'session') { - const opt = dbCtorHelper.normalizeArgs(...arguments); - storageName = opt.filename; - if ('session' !== storageName && 'local' !== storageName) { - toss3("JsStorageDb db name must be one of 'session' or 'local'."); - } - opt.vfs = 'kvvfs'; - dbCtorHelper.call(this, opt); - }; - const jdb = sqlite3.oo1.JsStorageDb; - jdb.prototype = Object.create(DB.prototype); - - jdb.clearStorage = capi.sqlite3_js_kvvfs_clear; - - jdb.prototype.clearStorage = function () { - return jdb.clearStorage(affirmDbOpen(this).filename); - }; - - jdb.storageSize = capi.sqlite3_js_kvvfs_size; - - jdb.prototype.storageSize = function () { - return jdb.storageSize(affirmDbOpen(this).filename); - }; - } - }); - - globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { - const util = sqlite3.util; - sqlite3.initWorker1API = function () { - const toss = (...args) => { - throw new Error(args.join(' ')); - }; - if (!(globalThis.WorkerGlobalScope instanceof Function)) { - toss('initWorker1API() must be run from a Worker thread.'); - } - const sqlite3 = this.sqlite3 || toss('Missing this.sqlite3 object.'); - const DB = sqlite3.oo1.DB; - - const getDbId = function (db) { - let id = wState.idMap.get(db); - if (id) return id; - id = 'db#' + ++wState.idSeq + '@' + db.pointer; - - wState.idMap.set(db, id); - return id; - }; - - const wState = { - dbList: [], - - idSeq: 0, - - idMap: new WeakMap(), - - xfer: [], - open: function (opt) { - const db = new DB(opt); - this.dbs[getDbId(db)] = db; - if (this.dbList.indexOf(db) < 0) this.dbList.push(db); - return db; - }, - close: function (db, alsoUnlink) { - if (db) { - delete this.dbs[getDbId(db)]; - const filename = db.filename; - const pVfs = util.sqlite3__wasm_db_vfs(db.pointer, 0); - db.close(); - const ddNdx = this.dbList.indexOf(db); - if (ddNdx >= 0) this.dbList.splice(ddNdx, 1); - if (alsoUnlink && filename && pVfs) { - util.sqlite3__wasm_vfs_unlink(pVfs, filename); - } - } - }, - - post: function (msg, xferList) { - if (xferList && xferList.length) { - globalThis.postMessage(msg, Array.from(xferList)); - xferList.length = 0; - } else { - globalThis.postMessage(msg); - } - }, - - dbs: Object.create(null), - - getDb: function (id, require = true) { - return ( - this.dbs[id] || - (require ? toss('Unknown (or closed) DB ID:', id) : undefined) - ); - }, - }; - - const affirmDbOpen = function (db = wState.dbList[0]) { - return db && db.pointer ? db : toss('DB is not opened.'); - }; - - const getMsgDb = function (msgData, affirmExists = true) { - const db = wState.getDb(msgData.dbId, false) || wState.dbList[0]; - return affirmExists ? affirmDbOpen(db) : db; - }; - - const getDefaultDbId = function () { - return wState.dbList[0] && getDbId(wState.dbList[0]); - }; - - const wMsgHandler = { - open: function (ev) { - const oargs = Object.create(null), - args = ev.args || Object.create(null); - if (args.simulateError) { - toss('Throwing because of simulateError flag.'); - } - const rc = Object.create(null); - oargs.vfs = args.vfs; - oargs.filename = args.filename || ''; - const db = wState.open(oargs); - rc.filename = db.filename; - rc.persistent = !!sqlite3.capi.sqlite3_js_db_uses_vfs( - db.pointer, - 'opfs', - ); - rc.dbId = getDbId(db); - rc.vfs = db.dbVfsName(); - return rc; - }, - - close: function (ev) { - const db = getMsgDb(ev, false); - const response = { - filename: db && db.filename, - }; - if (db) { - const doUnlink = - ev.args && 'object' === typeof ev.args - ? !!ev.args.unlink - : false; - wState.close(db, doUnlink); - } - return response; - }, - - exec: function (ev) { - const rc = - 'string' === typeof ev.args - ? { sql: ev.args } - : ev.args || Object.create(null); - if ('stmt' === rc.rowMode) { - toss( - "Invalid rowMode for 'exec': stmt mode", - 'does not work in the Worker API.', - ); - } else if (!rc.sql) { - toss("'exec' requires input SQL."); - } - const db = getMsgDb(ev); - if (rc.callback || Array.isArray(rc.resultRows)) { - db._blobXfer = wState.xfer; - } - const theCallback = rc.callback; - let rowNumber = 0; - const hadColNames = !!rc.columnNames; - if ('string' === typeof theCallback) { - if (!hadColNames) rc.columnNames = []; - - rc.callback = function (row, stmt) { - wState.post( - { - type: theCallback, - columnNames: rc.columnNames, - rowNumber: ++rowNumber, - row: row, - }, - wState.xfer, - ); - }; - } - try { - const changeCount = !!rc.countChanges - ? db.changes(true, 64 === rc.countChanges) - : undefined; - db.exec(rc); - if (undefined !== changeCount) { - rc.changeCount = - db.changes(true, 64 === rc.countChanges) - changeCount; - } - if (rc.callback instanceof Function) { - rc.callback = theCallback; - - wState.post({ - type: theCallback, - columnNames: rc.columnNames, - rowNumber: null, - row: undefined, - }); - } - } finally { - delete db._blobXfer; - if (rc.callback) rc.callback = theCallback; - } - return rc; - }, - - 'config-get': function () { - const rc = Object.create(null), - src = sqlite3.config; - ['bigIntEnabled'].forEach(function (k) { - if (Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k]; - }); - rc.version = sqlite3.version; - rc.vfsList = sqlite3.capi.sqlite3_js_vfs_list(); - rc.opfsEnabled = !!sqlite3.opfs; - return rc; - }, - - export: function (ev) { - const db = getMsgDb(ev); - const response = { - byteArray: sqlite3.capi.sqlite3_js_db_export(db.pointer), - filename: db.filename, - mimetype: 'application/x-sqlite3', - }; - wState.xfer.push(response.byteArray.buffer); - return response; - }, - - toss: function (ev) { - toss('Testing worker exception'); - }, - - 'opfs-tree': async function (ev) { - if (!sqlite3.opfs) toss('OPFS support is unavailable.'); - const response = await sqlite3.opfs.treeList(); - return response; - }, - }; - - globalThis.onmessage = async function (ev) { - ev = ev.data; - let result, - dbId = ev.dbId, - evType = ev.type; - const arrivalTime = performance.now(); - try { - if ( - wMsgHandler.hasOwnProperty(evType) && - wMsgHandler[evType] instanceof Function - ) { - result = await wMsgHandler[evType](ev); - } else { - toss('Unknown db worker message type:', ev.type); - } - } catch (err) { - evType = 'error'; - result = { - operation: ev.type, - message: err.message, - errorClass: err.name, - input: ev, - }; - if (err.stack) { - result.stack = - 'string' === typeof err.stack - ? err.stack.split(/\n\s*/) - : err.stack; - } - } - if (!dbId) { - dbId = result.dbId || getDefaultDbId(); - } - - wState.post( - { - type: evType, - dbId: dbId, - messageId: ev.messageId, - workerReceivedTime: arrivalTime, - workerRespondTime: performance.now(), - departureTime: ev.departureTime, - - result: result, - }, - wState.xfer, - ); - }; - globalThis.postMessage({ - type: 'sqlite3-api', - result: 'worker1-ready', - }); - }.bind({ sqlite3 }); - }); - globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { - const wasm = sqlite3.wasm, - capi = sqlite3.capi, - toss = sqlite3.util.toss3; - const vfs = Object.create(null); - sqlite3.vfs = vfs; - - capi.sqlite3_vfs.prototype.registerVfs = function (asDefault = false) { - if (!(this instanceof sqlite3.capi.sqlite3_vfs)) { - toss('Expecting a sqlite3_vfs-type argument.'); - } - const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0); - if (rc) { - toss('sqlite3_vfs_register(', this, ') failed with rc', rc); - } - if (this.pointer !== capi.sqlite3_vfs_find(this.$zName)) { - toss( - 'BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS', - this, - ); - } - return this; - }; - - vfs.installVfs = function (opt) { - let count = 0; - const propList = ['io', 'vfs']; - for (const key of propList) { - const o = opt[key]; - if (o) { - ++count; - o.struct.installMethods(o.methods, !!o.applyArgcCheck); - if ('vfs' === key) { - if (!o.struct.$zName && 'string' === typeof o.name) { - o.struct.addOnDispose( - (o.struct.$zName = wasm.allocCString(o.name)), - ); - } - o.struct.registerVfs(!!o.asDefault); - } - } - } - if (!count) - toss( - 'Misuse: installVfs() options object requires at least', - 'one of:', - propList, - ); - return this; - }; - }); - globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { - const wasm = sqlite3.wasm, - capi = sqlite3.capi, - toss = sqlite3.util.toss3; - const vtab = Object.create(null); - sqlite3.vtab = vtab; - - const sii = capi.sqlite3_index_info; - - sii.prototype.nthConstraint = function (n, asPtr = false) { - if (n < 0 || n >= this.$nConstraint) return false; - const ptr = - this.$aConstraint + - sii.sqlite3_index_constraint.structInfo.sizeof * n; - return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr); - }; - - sii.prototype.nthConstraintUsage = function (n, asPtr = false) { - if (n < 0 || n >= this.$nConstraint) return false; - const ptr = - this.$aConstraintUsage + - sii.sqlite3_index_constraint_usage.structInfo.sizeof * n; - return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr); - }; - - sii.prototype.nthOrderBy = function (n, asPtr = false) { - if (n < 0 || n >= this.$nOrderBy) return false; - const ptr = - this.$aOrderBy + sii.sqlite3_index_orderby.structInfo.sizeof * n; - return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr); - }; - - const __xWrapFactory = function (methodName, StructType) { - return function (ptr, removeMapping = false) { - if (0 === arguments.length) ptr = new StructType(); - if (ptr instanceof StructType) { - this.set(ptr.pointer, ptr); - return ptr; - } else if (!wasm.isPtr(ptr)) { - sqlite3.SQLite3Error.toss( - 'Invalid argument to', - methodName + '()', - ); - } - let rc = this.get(ptr); - if (removeMapping) this.delete(ptr); - return rc; - }.bind(new Map()); - }; - - const StructPtrMapper = function (name, StructType) { - const __xWrap = __xWrapFactory(name, StructType); - - return Object.assign(Object.create(null), { - StructType, - - create: (ppOut) => { - const rc = __xWrap(); - wasm.pokePtr(ppOut, rc.pointer); - return rc; - }, - - get: (pCObj) => __xWrap(pCObj), - - unget: (pCObj) => __xWrap(pCObj, true), - - dispose: (pCObj) => { - const o = __xWrap(pCObj, true); - if (o) o.dispose(); - }, - }); - }; - - vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab); - - vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor); - - vtab.xIndexInfo = (pIdxInfo) => new capi.sqlite3_index_info(pIdxInfo); - - vtab.xError = function f(methodName, err, defaultRc) { - if (f.errorReporter instanceof Function) { - try { - f.errorReporter( - 'sqlite3_module::' + methodName + '(): ' + err.message, - ); - } catch (e) {} - } - let rc; - if (err instanceof sqlite3.WasmAllocError) rc = capi.SQLITE_NOMEM; - else if (arguments.length > 2) rc = defaultRc; - else if (err instanceof sqlite3.SQLite3Error) rc = err.resultCode; - return rc || capi.SQLITE_ERROR; - }; - vtab.xError.errorReporter = console.error.bind(console) ; - - vtab.xRowid = (ppRowid64, value) => wasm.poke(ppRowid64, value, 'i64'); - - vtab.setupModule = function (opt) { - let createdMod = false; - const mod = - this instanceof capi.sqlite3_module - ? this - : opt.struct || (createdMod = new capi.sqlite3_module()); - try { - const methods = opt.methods || toss("Missing 'methods' object."); - for (const e of Object.entries({ - xConnect: 'xCreate', - xDisconnect: 'xDestroy', - })) { - const k = e[0], - v = e[1]; - if (true === methods[k]) methods[k] = methods[v]; - else if (true === methods[v]) methods[v] = methods[k]; - } - if (opt.catchExceptions) { - const fwrap = function (methodName, func) { - if (['xConnect', 'xCreate'].indexOf(methodName) >= 0) { - return function (pDb, pAux, argc, argv, ppVtab, pzErr) { - try { - return func(...arguments) || 0; - } catch (e) { - if (!(e instanceof sqlite3.WasmAllocError)) { - wasm.dealloc(wasm.peekPtr(pzErr)); - wasm.pokePtr(pzErr, wasm.allocCString(e.message)); - } - return vtab.xError(methodName, e); - } - }; - } else { - return function (...args) { - try { - return func(...args) || 0; - } catch (e) { - return vtab.xError(methodName, e); - } - }; - } - }; - const mnames = [ - 'xCreate', - 'xConnect', - 'xBestIndex', - 'xDisconnect', - 'xDestroy', - 'xOpen', - 'xClose', - 'xFilter', - 'xNext', - 'xEof', - 'xColumn', - 'xRowid', - 'xUpdate', - 'xBegin', - 'xSync', - 'xCommit', - 'xRollback', - 'xFindFunction', - 'xRename', - 'xSavepoint', - 'xRelease', - 'xRollbackTo', - 'xShadowName', - ]; - const remethods = Object.create(null); - for (const k of mnames) { - const m = methods[k]; - if (!(m instanceof Function)) continue; - else if ('xConnect' === k && methods.xCreate === m) { - remethods[k] = methods.xCreate; - } else if ('xCreate' === k && methods.xConnect === m) { - remethods[k] = methods.xConnect; - } else { - remethods[k] = fwrap(k, m); - } - } - mod.installMethods(remethods, false); - } else { - mod.installMethods(methods, !!opt.applyArgcCheck); - } - if (0 === mod.$iVersion) { - let v; - if ('number' === typeof opt.iVersion) v = opt.iVersion; - else if (mod.$xShadowName) v = 3; - else if (mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) - v = 2; - else v = 1; - mod.$iVersion = v; - } - } catch (e) { - if (createdMod) createdMod.dispose(); - throw e; - } - return mod; - }; - - capi.sqlite3_module.prototype.setupModule = function (opt) { - return vtab.setupModule.call(this, opt); - }; - }); - globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { - const installOpfsVfs = function callee(options) { - if (!globalThis.SharedArrayBuffer || !globalThis.Atomics) { - return Promise.reject( - new Error( - 'Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. ' + - 'The server must emit the COOP/COEP response headers to enable those. ' + - 'See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep', - ), - ); - } else if ('undefined' === typeof WorkerGlobalScope) { - return Promise.reject( - new Error( - 'The OPFS sqlite3_vfs cannot run in the main thread ' + - 'because it requires Atomics.wait().', - ), - ); - } else if ( - !globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory - ) { - return Promise.reject(new Error('Missing required OPFS APIs.')); - } - if (!options || 'object' !== typeof options) { - options = Object.create(null); - } - const urlParams = new URL(globalThis.location.href).searchParams; - if (urlParams.has('opfs-disable')) { - return Promise.resolve(sqlite3); - } - if (undefined === options.verbose) { - options.verbose = urlParams.has('opfs-verbose') - ? +urlParams.get('opfs-verbose') || 2 - : 1; - } - if (undefined === options.sanityChecks) { - options.sanityChecks = urlParams.has('opfs-sanity-check'); - } - if (undefined === options.proxyUri) { - options.proxyUri = callee.defaultProxyUri; - } - - if ('function' === typeof options.proxyUri) { - options.proxyUri = options.proxyUri(); - } - const thePromise = new Promise(function ( - promiseResolve_, - promiseReject_, - ) { - const loggers = [ - sqlite3.config.error, - sqlite3.config.warn, - sqlite3.config.log, - ]; - const logImpl = (level, ...args) => { - if (options.verbose > level) - loggers[level]('OPFS syncer:', ...args); - }; - const log = (...args) => logImpl(2, ...args); - const warn = (...args) => logImpl(1, ...args); - const error = (...args) => logImpl(0, ...args); - const toss = sqlite3.util.toss; - const capi = sqlite3.capi; - const util = sqlite3.util; - const wasm = sqlite3.wasm; - const sqlite3_vfs = capi.sqlite3_vfs; - const sqlite3_file = capi.sqlite3_file; - const sqlite3_io_methods = capi.sqlite3_io_methods; - - const opfsUtil = Object.create(null); - - const thisThreadHasOPFS = () => { - return ( - globalThis.FileSystemHandle && - globalThis.FileSystemDirectoryHandle && - globalThis.FileSystemFileHandle && - globalThis.FileSystemFileHandle.prototype - .createSyncAccessHandle && - navigator?.storage?.getDirectory - ); - }; - - opfsUtil.metrics = { - dump: function () { - let k, - n = 0, - t = 0, - w = 0; - for (k in state.opIds) { - const m = metrics[k]; - n += m.count; - t += m.time; - w += m.wait; - m.avgTime = m.count && m.time ? m.time / m.count : 0; - m.avgWait = m.count && m.wait ? m.wait / m.count : 0; - } - sqlite3.config.log( - globalThis.location.href, - 'metrics for', - globalThis.location.href, - ':', - metrics, - '\nTotal of', - n, - 'op(s) for', - t, - 'ms (incl. ' + w + ' ms of waiting on the async side)', - ); - sqlite3.config.log('Serialization metrics:', metrics.s11n); - W.postMessage({ type: 'opfs-async-metrics' }); - }, - reset: function () { - let k; - const r = (m) => (m.count = m.time = m.wait = 0); - for (k in state.opIds) { - r((metrics[k] = Object.create(null))); - } - let s = (metrics.s11n = Object.create(null)); - s = s.serialize = Object.create(null); - s.count = s.time = 0; - s = metrics.s11n.deserialize = Object.create(null); - s.count = s.time = 0; - }, - }; - const opfsIoMethods = new sqlite3_io_methods(); - const opfsVfs = new sqlite3_vfs().addOnDispose(() => - opfsIoMethods.dispose(), - ); - let promiseWasRejected = undefined; - const promiseReject = (err) => { - promiseWasRejected = true; - opfsVfs.dispose(); - return promiseReject_(err); - }; - const promiseResolve = () => { - promiseWasRejected = false; - return promiseResolve_(sqlite3); - }; - const W = new Worker( - new URL('sqlite3-opfs-async-proxy.js', import.meta.url), - ); - setTimeout(() => { - if (undefined === promiseWasRejected) { - promiseReject( - new Error( - 'Timeout while waiting for OPFS async proxy worker.', - ), - ); - } - }, 4000); - W._originalOnError = W.onerror; - W.onerror = function (err) { - error('Error initializing OPFS asyncer:', err); - promiseReject( - new Error( - 'Loading OPFS async Worker failed for unknown reasons.', - ), - ); - }; - const pDVfs = capi.sqlite3_vfs_find(null); - const dVfs = pDVfs ? new sqlite3_vfs(pDVfs) : null; - opfsIoMethods.$iVersion = 1; - opfsVfs.$iVersion = 2; - opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; - opfsVfs.$mxPathname = 1024; - opfsVfs.$zName = wasm.allocCString('opfs'); - - opfsVfs.$xDlOpen = - opfsVfs.$xDlError = - opfsVfs.$xDlSym = - opfsVfs.$xDlClose = - null; - opfsVfs.addOnDispose( - '$zName', - opfsVfs.$zName, - 'cleanup default VFS wrapper', - () => (dVfs ? dVfs.dispose() : null), - ); - - const state = Object.create(null); - state.verbose = options.verbose; - state.littleEndian = (() => { - const buffer = new ArrayBuffer(2); - new DataView(buffer).setInt16(0, 256, true); - - return new Int16Array(buffer)[0] === 256; - })(); - - state.asyncIdleWaitTime = 150; - - state.asyncS11nExceptions = 1; - - state.fileBufferSize = 1024 * 64; - state.sabS11nOffset = state.fileBufferSize; - - state.sabS11nSize = opfsVfs.$mxPathname * 2; - - state.sabIO = new SharedArrayBuffer( - state.fileBufferSize + state.sabS11nSize, - ); - state.opIds = Object.create(null); - const metrics = Object.create(null); - { - let i = 0; - - state.opIds.whichOp = i++; - - state.opIds.rc = i++; - - state.opIds.xAccess = i++; - state.opIds.xClose = i++; - state.opIds.xDelete = i++; - state.opIds.xDeleteNoWait = i++; - state.opIds.xFileSize = i++; - state.opIds.xLock = i++; - state.opIds.xOpen = i++; - state.opIds.xRead = i++; - state.opIds.xSleep = i++; - state.opIds.xSync = i++; - state.opIds.xTruncate = i++; - state.opIds.xUnlock = i++; - state.opIds.xWrite = i++; - state.opIds.mkdir = i++; - state.opIds['opfs-async-metrics'] = i++; - state.opIds['opfs-async-shutdown'] = i++; - - state.opIds.retry = i++; - state.sabOP = new SharedArrayBuffer(i * 4); - opfsUtil.metrics.reset(); - } - - state.sq3Codes = Object.create(null); - [ - 'SQLITE_ACCESS_EXISTS', - 'SQLITE_ACCESS_READWRITE', - 'SQLITE_BUSY', - 'SQLITE_CANTOPEN', - 'SQLITE_ERROR', - 'SQLITE_IOERR', - 'SQLITE_IOERR_ACCESS', - 'SQLITE_IOERR_CLOSE', - 'SQLITE_IOERR_DELETE', - 'SQLITE_IOERR_FSYNC', - 'SQLITE_IOERR_LOCK', - 'SQLITE_IOERR_READ', - 'SQLITE_IOERR_SHORT_READ', - 'SQLITE_IOERR_TRUNCATE', - 'SQLITE_IOERR_UNLOCK', - 'SQLITE_IOERR_WRITE', - 'SQLITE_LOCK_EXCLUSIVE', - 'SQLITE_LOCK_NONE', - 'SQLITE_LOCK_PENDING', - 'SQLITE_LOCK_RESERVED', - 'SQLITE_LOCK_SHARED', - 'SQLITE_LOCKED', - 'SQLITE_MISUSE', - 'SQLITE_NOTFOUND', - 'SQLITE_OPEN_CREATE', - 'SQLITE_OPEN_DELETEONCLOSE', - 'SQLITE_OPEN_MAIN_DB', - 'SQLITE_OPEN_READONLY', - ].forEach((k) => { - if (undefined === (state.sq3Codes[k] = capi[k])) { - toss('Maintenance required: not found:', k); - } - }); - state.opfsFlags = Object.assign(Object.create(null), { - OPFS_UNLOCK_ASAP: 0x01, - - OPFS_UNLINK_BEFORE_OPEN: 0x02, - - defaultUnlockAsap: false, - }); - - const opRun = (op, ...args) => { - const opNdx = state.opIds[op] || toss('Invalid op ID:', op); - state.s11n.serialize(...args); - Atomics.store(state.sabOPView, state.opIds.rc, -1); - Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); - Atomics.notify(state.sabOPView, state.opIds.whichOp); - const t = performance.now(); - while ( - 'not-equal' !== - Atomics.wait(state.sabOPView, state.opIds.rc, -1) - ) {} - - const rc = Atomics.load(state.sabOPView, state.opIds.rc); - metrics[op].wait += performance.now() - t; - if (rc && state.asyncS11nExceptions) { - const err = state.s11n.deserialize(); - if (err) error(op + '() async error:', ...err); - } - return rc; - }; - - opfsUtil.debug = { - asyncShutdown: () => { - warn( - 'Shutting down OPFS async listener. The OPFS VFS will no longer work.', - ); - opRun('opfs-async-shutdown'); - }, - asyncRestart: () => { - warn( - 'Attempting to restart OPFS VFS async listener. Might work, might not.', - ); - W.postMessage({ type: 'opfs-async-restart' }); - }, - }; - - const initS11n = () => { - if (state.s11n) return state.s11n; - const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder('utf-8'), - viewU8 = new Uint8Array( - state.sabIO, - state.sabS11nOffset, - state.sabS11nSize, - ), - viewDV = new DataView( - state.sabIO, - state.sabS11nOffset, - state.sabS11nSize, - ); - state.s11n = Object.create(null); - - const TypeIds = Object.create(null); - TypeIds.number = { - id: 1, - size: 8, - getter: 'getFloat64', - setter: 'setFloat64', - }; - TypeIds.bigint = { - id: 2, - size: 8, - getter: 'getBigInt64', - setter: 'setBigInt64', - }; - TypeIds.boolean = { - id: 3, - size: 4, - getter: 'getInt32', - setter: 'setInt32', - }; - TypeIds.string = { id: 4 }; - - const getTypeId = (v) => - TypeIds[typeof v] || - toss( - 'Maintenance required: this value type cannot be serialized.', - v, - ); - const getTypeIdById = (tid) => { - switch (tid) { - case TypeIds.number.id: - return TypeIds.number; - case TypeIds.bigint.id: - return TypeIds.bigint; - case TypeIds.boolean.id: - return TypeIds.boolean; - case TypeIds.string.id: - return TypeIds.string; - default: - toss('Invalid type ID:', tid); - } - }; - - state.s11n.deserialize = function (clear = false) { - ++metrics.s11n.deserialize.count; - const t = performance.now(); - const argc = viewU8[0]; - const rc = argc ? [] : null; - if (argc) { - const typeIds = []; - let offset = 1, - i, - n, - v; - for (i = 0; i < argc; ++i, ++offset) { - typeIds.push(getTypeIdById(viewU8[offset])); - } - for (i = 0; i < argc; ++i) { - const t = typeIds[i]; - if (t.getter) { - v = viewDV[t.getter](offset, state.littleEndian); - offset += t.size; - } else { - n = viewDV.getInt32(offset, state.littleEndian); - offset += 4; - v = textDecoder.decode(viewU8.slice(offset, offset + n)); - offset += n; - } - rc.push(v); - } - } - if (clear) viewU8[0] = 0; - - metrics.s11n.deserialize.time += performance.now() - t; - return rc; - }; - - state.s11n.serialize = function (...args) { - const t = performance.now(); - ++metrics.s11n.serialize.count; - if (args.length) { - const typeIds = []; - let i = 0, - offset = 1; - viewU8[0] = args.length & 0xff; - for (; i < args.length; ++i, ++offset) { - typeIds.push(getTypeId(args[i])); - viewU8[offset] = typeIds[i].id; - } - for (i = 0; i < args.length; ++i) { - const t = typeIds[i]; - if (t.setter) { - viewDV[t.setter](offset, args[i], state.littleEndian); - offset += t.size; - } else { - const s = textEncoder.encode(args[i]); - viewDV.setInt32(offset, s.byteLength, state.littleEndian); - offset += 4; - viewU8.set(s, offset); - offset += s.byteLength; - } - } - } else { - viewU8[0] = 0; - } - metrics.s11n.serialize.time += performance.now() - t; - }; - return state.s11n; - }; - - const randomFilename = function f(len = 16) { - if (!f._chars) { - f._chars = - 'abcdefghijklmnopqrstuvwxyz' + - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + - '012346789'; - f._n = f._chars.length; - } - const a = []; - let i = 0; - for (; i < len; ++i) { - const ndx = (Math.random() * (f._n * 64)) % f._n | 0; - a[i] = f._chars[ndx]; - } - return a.join(''); - }; - - const __openFiles = Object.create(null); - - const opTimer = Object.create(null); - opTimer.op = undefined; - opTimer.start = undefined; - const mTimeStart = (op) => { - opTimer.start = performance.now(); - opTimer.op = op; - ++metrics[op].count; - }; - const mTimeEnd = () => - (metrics[opTimer.op].time += performance.now() - opTimer.start); - - const ioSyncWrappers = { - xCheckReservedLock: function (pFile, pOut) { - { - wasm.poke(pOut, 0, 'i32'); - } - return 0; - }, - xClose: function (pFile) { - mTimeStart('xClose'); - let rc = 0; - const f = __openFiles[pFile]; - if (f) { - delete __openFiles[pFile]; - rc = opRun('xClose', pFile); - if (f.sq3File) f.sq3File.dispose(); - } - mTimeEnd(); - return rc; - }, - xDeviceCharacteristics: function (pFile) { - return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; - }, - xFileControl: function (pFile, opId, pArg) { - return capi.SQLITE_NOTFOUND; - }, - xFileSize: function (pFile, pSz64) { - mTimeStart('xFileSize'); - let rc = opRun('xFileSize', pFile); - if (0 == rc) { - try { - const sz = state.s11n.deserialize()[0]; - wasm.poke(pSz64, sz, 'i64'); - } catch (e) { - error('Unexpected error reading xFileSize() result:', e); - rc = state.sq3Codes.SQLITE_IOERR; - } - } - mTimeEnd(); - return rc; - }, - xLock: function (pFile, lockType) { - mTimeStart('xLock'); - const f = __openFiles[pFile]; - let rc = 0; - - if (!f.lockType) { - rc = opRun('xLock', pFile, lockType); - if (0 === rc) f.lockType = lockType; - } else { - f.lockType = lockType; - } - mTimeEnd(); - return rc; - }, - xRead: function (pFile, pDest, n, offset64) { - mTimeStart('xRead'); - const f = __openFiles[pFile]; - let rc; - try { - rc = opRun('xRead', pFile, n, Number(offset64)); - if (0 === rc || capi.SQLITE_IOERR_SHORT_READ === rc) { - wasm.heap8u().set(f.sabView.subarray(0, n), pDest); - } - } catch (e) { - error('xRead(', arguments, ') failed:', e, f); - rc = capi.SQLITE_IOERR_READ; - } - mTimeEnd(); - return rc; - }, - xSync: function (pFile, flags) { - mTimeStart('xSync'); - ++metrics.xSync.count; - const rc = opRun('xSync', pFile, flags); - mTimeEnd(); - return rc; - }, - xTruncate: function (pFile, sz64) { - mTimeStart('xTruncate'); - const rc = opRun('xTruncate', pFile, Number(sz64)); - mTimeEnd(); - return rc; - }, - xUnlock: function (pFile, lockType) { - mTimeStart('xUnlock'); - const f = __openFiles[pFile]; - let rc = 0; - if (capi.SQLITE_LOCK_NONE === lockType && f.lockType) { - rc = opRun('xUnlock', pFile, lockType); - } - if (0 === rc) f.lockType = lockType; - mTimeEnd(); - return rc; - }, - xWrite: function (pFile, pSrc, n, offset64) { - mTimeStart('xWrite'); - const f = __openFiles[pFile]; - let rc; - try { - f.sabView.set(wasm.heap8u().subarray(pSrc, pSrc + n)); - rc = opRun('xWrite', pFile, n, Number(offset64)); - } catch (e) { - error('xWrite(', arguments, ') failed:', e, f); - rc = capi.SQLITE_IOERR_WRITE; - } - mTimeEnd(); - return rc; - }, - }; - - const vfsSyncWrappers = { - xAccess: function (pVfs, zName, flags, pOut) { - mTimeStart('xAccess'); - const rc = opRun('xAccess', wasm.cstrToJs(zName)); - wasm.poke(pOut, rc ? 0 : 1, 'i32'); - mTimeEnd(); - return 0; - }, - xCurrentTime: function (pVfs, pOut) { - wasm.poke( - pOut, - 2440587.5 + new Date().getTime() / 86400000, - 'double', - ); - return 0; - }, - xCurrentTimeInt64: function (pVfs, pOut) { - wasm.poke( - pOut, - 2440587.5 * 86400000 + new Date().getTime(), - 'i64', - ); - return 0; - }, - xDelete: function (pVfs, zName, doSyncDir) { - mTimeStart('xDelete'); - const rc = opRun( - 'xDelete', - wasm.cstrToJs(zName), - doSyncDir, - false, - ); - mTimeEnd(); - return rc; - }, - xFullPathname: function (pVfs, zName, nOut, pOut) { - const i = wasm.cstrncpy(pOut, zName, nOut); - return i < nOut ? 0 : capi.SQLITE_CANTOPEN; - }, - xGetLastError: function (pVfs, nOut, pOut) { - warn('OPFS xGetLastError() has nothing sensible to return.'); - return 0; - }, - - xOpen: function f(pVfs, zName, pFile, flags, pOutFlags) { - mTimeStart('xOpen'); - let opfsFlags = 0; - if (0 === zName) { - zName = randomFilename(); - } else if (wasm.isPtr(zName)) { - if (capi.sqlite3_uri_boolean(zName, 'opfs-unlock-asap', 0)) { - opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP; - } - if ( - capi.sqlite3_uri_boolean(zName, 'delete-before-open', 0) - ) { - opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN; - } - zName = wasm.cstrToJs(zName); - } - const fh = Object.create(null); - fh.fid = pFile; - fh.filename = zName; - fh.sab = new SharedArrayBuffer(state.fileBufferSize); - fh.flags = flags; - const rc = opRun('xOpen', pFile, zName, flags, opfsFlags); - if (!rc) { - if (fh.readOnly) { - wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, 'i32'); - } - __openFiles[pFile] = fh; - fh.sabView = state.sabFileBufView; - fh.sq3File = new sqlite3_file(pFile); - fh.sq3File.$pMethods = opfsIoMethods.pointer; - fh.lockType = capi.SQLITE_LOCK_NONE; - } - mTimeEnd(); - return rc; - }, - }; - - if (dVfs) { - opfsVfs.$xRandomness = dVfs.$xRandomness; - opfsVfs.$xSleep = dVfs.$xSleep; - } - if (!opfsVfs.$xRandomness) { - vfsSyncWrappers.xRandomness = function (pVfs, nOut, pOut) { - const heap = wasm.heap8u(); - let i = 0; - for (; i < nOut; ++i) - heap[pOut + i] = (Math.random() * 255000) & 0xff; - return i; - }; - } - if (!opfsVfs.$xSleep) { - vfsSyncWrappers.xSleep = function (pVfs, ms) { - Atomics.wait(state.sabOPView, state.opIds.xSleep, 0, ms); - return 0; - }; - } - - opfsUtil.getResolvedPath = function (filename, splitIt) { - const p = new URL(filename, 'file://irrelevant').pathname; - return splitIt ? p.split('/').filter((v) => !!v) : p; - }; - - opfsUtil.getDirForFilename = async function f( - absFilename, - createDirs = false, - ) { - const path = opfsUtil.getResolvedPath(absFilename, true); - const filename = path.pop(); - let dh = opfsUtil.rootDirectory; - for (const dirName of path) { - if (dirName) { - dh = await dh.getDirectoryHandle(dirName, { - create: !!createDirs, - }); - } - } - return [dh, filename]; - }; - - opfsUtil.mkdir = async function (absDirName) { - try { - await opfsUtil.getDirForFilename( - absDirName + '/filepart', - true, - ); - return true; - } catch (e) { - return false; - } - }; - - opfsUtil.entryExists = async function (fsEntryName) { - try { - const [dh, fn] = await opfsUtil.getDirForFilename(fsEntryName); - await dh.getFileHandle(fn); - return true; - } catch (e) { - return false; - } - }; - - opfsUtil.randomFilename = randomFilename; - - opfsUtil.treeList = async function () { - const doDir = async function callee(dirHandle, tgt) { - tgt.name = dirHandle.name; - tgt.dirs = []; - tgt.files = []; - for await (const handle of dirHandle.values()) { - if ('directory' === handle.kind) { - const subDir = Object.create(null); - tgt.dirs.push(subDir); - await callee(handle, subDir); - } else { - tgt.files.push(handle.name); - } - } - }; - const root = Object.create(null); - await doDir(opfsUtil.rootDirectory, root); - return root; - }; - - opfsUtil.rmfr = async function () { - const dir = opfsUtil.rootDirectory, - opt = { recurse: true }; - for await (const handle of dir.values()) { - dir.removeEntry(handle.name, opt); - } - }; - - opfsUtil.unlink = async function ( - fsEntryName, - recursive = false, - throwOnError = false, - ) { - try { - const [hDir, filenamePart] = await opfsUtil.getDirForFilename( - fsEntryName, - false, - ); - await hDir.removeEntry(filenamePart, { recursive }); - return true; - } catch (e) { - if (throwOnError) { - throw new Error( - 'unlink(', - arguments[0], - ') failed: ' + e.message, - { - cause: e, - }, - ); - } - return false; - } - }; - - opfsUtil.traverse = async function (opt) { - const defaultOpt = { - recursive: true, - directory: opfsUtil.rootDirectory, - }; - if ('function' === typeof opt) { - opt = { callback: opt }; - } - opt = Object.assign(defaultOpt, opt || {}); - const doDir = async function callee(dirHandle, depth) { - for await (const handle of dirHandle.values()) { - if (false === opt.callback(handle, dirHandle, depth)) - return false; - else if (opt.recursive && 'directory' === handle.kind) { - if (false === (await callee(handle, depth + 1))) break; - } - } - }; - doDir(opt.directory, 0); - }; - - const importDbChunked = async function (filename, callback) { - const [hDir, fnamePart] = await opfsUtil.getDirForFilename( - filename, - true, - ); - const hFile = await hDir.getFileHandle(fnamePart, { - create: true, - }); - let sah = await hFile.createSyncAccessHandle(); - let nWrote = 0, - chunk, - checkedHeader = false; - try { - sah.truncate(0); - while (undefined !== (chunk = await callback())) { - if (chunk instanceof ArrayBuffer) - chunk = new Uint8Array(chunk); - if (0 === nWrote && chunk.byteLength >= 15) { - util.affirmDbHeader(chunk); - checkedHeader = true; - } - sah.write(chunk, { at: nWrote }); - nWrote += chunk.byteLength; - } - if (nWrote < 512 || 0 !== nWrote % 512) { - toss( - 'Input size', - nWrote, - 'is not correct for an SQLite database.', - ); - } - if (!checkedHeader) { - const header = new Uint8Array(20); - sah.read(header, { at: 0 }); - util.affirmDbHeader(header); - } - sah.write(new Uint8Array([1, 1]), { at: 18 }); - return nWrote; - } catch (e) { - await sah.close(); - sah = undefined; - await hDir.removeEntry(fnamePart).catch(() => {}); - throw e; - } finally { - if (sah) await sah.close(); - } - }; - - opfsUtil.importDb = async function (filename, bytes) { - if (bytes instanceof Function) { - return importDbChunked(filename, bytes); - } - if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); - util.affirmIsDb(bytes); - const n = bytes.byteLength; - const [hDir, fnamePart] = await opfsUtil.getDirForFilename( - filename, - true, - ); - let sah, - nWrote = 0; - try { - const hFile = await hDir.getFileHandle(fnamePart, { - create: true, - }); - sah = await hFile.createSyncAccessHandle(); - sah.truncate(0); - nWrote = sah.write(bytes, { at: 0 }); - if (nWrote != n) { - toss( - 'Expected to write ' + - n + - ' bytes but wrote ' + - nWrote + - '.', - ); - } - sah.write(new Uint8Array([1, 1]), { at: 18 }); - return nWrote; - } catch (e) { - if (sah) { - await sah.close(); - sah = undefined; - } - await hDir.removeEntry(fnamePart).catch(() => {}); - throw e; - } finally { - if (sah) await sah.close(); - } - }; - - if (sqlite3.oo1) { - const OpfsDb = function (...args) { - const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); - opt.vfs = opfsVfs.$zName; - sqlite3.oo1.DB.dbCtorHelper.call(this, opt); - }; - OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); - sqlite3.oo1.OpfsDb = OpfsDb; - OpfsDb.importDb = opfsUtil.importDb; - sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenSql( - opfsVfs.pointer, - function (oo1Db, sqlite3) { - sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); - sqlite3.capi.sqlite3_exec( - oo1Db, - [ - 'pragma journal_mode=DELETE;', - - 'pragma cache_size=-16384;', - ], - 0, - 0, - 0, - ); - }, - ); - } - - const sanityCheck = function () { - const scope = wasm.scopedAllocPush(); - const sq3File = new sqlite3_file(); - try { - const fid = sq3File.pointer; - const openFlags = - capi.SQLITE_OPEN_CREATE | - capi.SQLITE_OPEN_READWRITE | - capi.SQLITE_OPEN_MAIN_DB; - const pOut = wasm.scopedAlloc(8); - const dbFile = '/sanity/check/file' + randomFilename(8); - const zDbFile = wasm.scopedAllocCString(dbFile); - let rc; - state.s11n.serialize('This is ä string.'); - rc = state.s11n.deserialize(); - log('deserialize() says:', rc); - if ('This is ä string.' !== rc[0]) toss('String d13n error.'); - vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, 'i32'); - log('xAccess(', dbFile, ') exists ?=', rc); - rc = vfsSyncWrappers.xOpen( - opfsVfs.pointer, - zDbFile, - fid, - openFlags, - pOut, - ); - log( - 'open rc =', - rc, - 'state.sabOPView[xOpen] =', - state.sabOPView[state.opIds.xOpen], - ); - if (0 !== rc) { - error('open failed with code', rc); - return; - } - vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, 'i32'); - if (!rc) toss('xAccess() failed to detect file.'); - rc = ioSyncWrappers.xSync(sq3File.pointer, 0); - if (rc) toss('sync failed w/ rc', rc); - rc = ioSyncWrappers.xTruncate(sq3File.pointer, 1024); - if (rc) toss('truncate failed w/ rc', rc); - wasm.poke(pOut, 0, 'i64'); - rc = ioSyncWrappers.xFileSize(sq3File.pointer, pOut); - if (rc) toss('xFileSize failed w/ rc', rc); - log('xFileSize says:', wasm.peek(pOut, 'i64')); - rc = ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1); - if (rc) toss('xWrite() failed!'); - const readBuf = wasm.scopedAlloc(16); - rc = ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); - wasm.poke(readBuf + 6, 0); - let jRead = wasm.cstrToJs(readBuf); - log('xRead() got:', jRead); - if ('sanity' !== jRead) toss('Unexpected xRead() value.'); - if (vfsSyncWrappers.xSleep) { - log('xSleep()ing before close()ing...'); - vfsSyncWrappers.xSleep(opfsVfs.pointer, 2000); - log('waking up from xSleep()'); - } - rc = ioSyncWrappers.xClose(fid); - log('xClose rc =', rc, 'sabOPView =', state.sabOPView); - log('Deleting file:', dbFile); - vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234); - vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, 'i32'); - if (rc) - toss( - 'Expecting 0 from xAccess(', - dbFile, - ') after xDelete().', - ); - warn('End of OPFS sanity checks.'); - } finally { - sq3File.dispose(); - wasm.scopedAllocPop(scope); - } - }; - - W.onmessage = function ({ data }) { - switch (data.type) { - case 'opfs-unavailable': - promiseReject(new Error(data.payload.join(' '))); - break; - case 'opfs-async-loaded': - W.postMessage({ type: 'opfs-async-init', args: state }); - break; - case 'opfs-async-inited': { - if (true === promiseWasRejected) { - break; - } - try { - sqlite3.vfs.installVfs({ - io: { struct: opfsIoMethods, methods: ioSyncWrappers }, - vfs: { struct: opfsVfs, methods: vfsSyncWrappers }, - }); - state.sabOPView = new Int32Array(state.sabOP); - state.sabFileBufView = new Uint8Array( - state.sabIO, - 0, - state.fileBufferSize, - ); - state.sabS11nView = new Uint8Array( - state.sabIO, - state.sabS11nOffset, - state.sabS11nSize, - ); - initS11n(); - if (options.sanityChecks) { - warn( - 'Running sanity checks because of opfs-sanity-check URL arg...', - ); - sanityCheck(); - } - if (thisThreadHasOPFS()) { - navigator.storage - .getDirectory() - .then((d) => { - W.onerror = W._originalOnError; - delete W._originalOnError; - sqlite3.opfs = opfsUtil; - opfsUtil.rootDirectory = d; - log('End of OPFS sqlite3_vfs setup.', opfsVfs); - promiseResolve(); - }) - .catch(promiseReject); - } else { - promiseResolve(); - } - } catch (e) { - error(e); - promiseReject(e); - } - break; - } - default: { - const errMsg = - 'Unexpected message from the OPFS async worker: ' + - JSON.stringify(data); - error(errMsg); - promiseReject(new Error(errMsg)); - break; - } - } - }; - }); - return thePromise; - }; - installOpfsVfs.defaultProxyUri = 'sqlite3-opfs-async-proxy.js'; - globalThis.sqlite3ApiBootstrap.initializersAsync.push( - async (sqlite3) => { - try { - let proxyJs = installOpfsVfs.defaultProxyUri; - if (sqlite3.scriptInfo.sqlite3Dir) { - installOpfsVfs.defaultProxyUri = - sqlite3.scriptInfo.sqlite3Dir + proxyJs; - } - return installOpfsVfs().catch((e) => { - sqlite3.config.warn( - 'Ignoring inability to install OPFS sqlite3_vfs:', - e.message, - ); - }); - } catch (e) { - sqlite3.config.error('installOpfsVfs() exception:', e); - return Promise.reject(e); - } - }, - ); - }); - - globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { - const toss = sqlite3.util.toss; - const toss3 = sqlite3.util.toss3; - const initPromises = Object.create(null); - const capi = sqlite3.capi; - const util = sqlite3.util; - const wasm = sqlite3.wasm; - - const SECTOR_SIZE = 4096; - const HEADER_MAX_PATH_SIZE = 512; - const HEADER_FLAGS_SIZE = 4; - const HEADER_DIGEST_SIZE = 8; - const HEADER_CORPUS_SIZE = HEADER_MAX_PATH_SIZE + HEADER_FLAGS_SIZE; - const HEADER_OFFSET_FLAGS = HEADER_MAX_PATH_SIZE; - const HEADER_OFFSET_DIGEST = HEADER_CORPUS_SIZE; - const HEADER_OFFSET_DATA = SECTOR_SIZE; - - const PERSISTENT_FILE_TYPES = - capi.SQLITE_OPEN_MAIN_DB | - capi.SQLITE_OPEN_MAIN_JOURNAL | - capi.SQLITE_OPEN_SUPER_JOURNAL | - capi.SQLITE_OPEN_WAL; - - const OPAQUE_DIR_NAME = '.opaque'; - - const getRandomName = () => Math.random().toString(36).slice(2); - - const textDecoder = new TextDecoder(); - const textEncoder = new TextEncoder(); - - const optionDefaults = Object.assign(Object.create(null), { - name: 'opfs-sahpool', - directory: undefined, - initialCapacity: 6, - clearOnInit: false, - - verbosity: 2, - }); - - const loggers = [ - sqlite3.config.error, - sqlite3.config.warn, - sqlite3.config.log, - ]; - sqlite3.config.log; - const warn = sqlite3.config.warn; - sqlite3.config.error; - - const __mapVfsToPool = new Map(); - const getPoolForVfs = (pVfs) => __mapVfsToPool.get(pVfs); - const setPoolForVfs = (pVfs, pool) => { - if (pool) __mapVfsToPool.set(pVfs, pool); - else __mapVfsToPool.delete(pVfs); - }; - - const __mapSqlite3File = new Map(); - const getPoolForPFile = (pFile) => __mapSqlite3File.get(pFile); - const setPoolForPFile = (pFile, pool) => { - if (pool) __mapSqlite3File.set(pFile, pool); - else __mapSqlite3File.delete(pFile); - }; - - const ioMethods = { - xCheckReservedLock: function (pFile, pOut) { - const pool = getPoolForPFile(pFile); - pool.log('xCheckReservedLock'); - pool.storeErr(); - wasm.poke32(pOut, 1); - return 0; - }, - xClose: function (pFile) { - const pool = getPoolForPFile(pFile); - pool.storeErr(); - const file = pool.getOFileForS3File(pFile); - if (file) { - try { - pool.log(`xClose ${file.path}`); - pool.mapS3FileToOFile(pFile, false); - file.sah.flush(); - if (file.flags & capi.SQLITE_OPEN_DELETEONCLOSE) { - pool.deletePath(file.path); - } - } catch (e) { - return pool.storeErr(e, capi.SQLITE_IOERR); - } - } - return 0; - }, - xDeviceCharacteristics: function (pFile) { - return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; - }, - xFileControl: function (pFile, opId, pArg) { - return capi.SQLITE_NOTFOUND; - }, - xFileSize: function (pFile, pSz64) { - const pool = getPoolForPFile(pFile); - pool.log(`xFileSize`); - const file = pool.getOFileForS3File(pFile); - const size = file.sah.getSize() - HEADER_OFFSET_DATA; - - wasm.poke64(pSz64, BigInt(size)); - return 0; - }, - xLock: function (pFile, lockType) { - const pool = getPoolForPFile(pFile); - pool.log(`xLock ${lockType}`); - pool.storeErr(); - const file = pool.getOFileForS3File(pFile); - file.lockType = lockType; - return 0; - }, - xRead: function (pFile, pDest, n, offset64) { - const pool = getPoolForPFile(pFile); - pool.storeErr(); - const file = pool.getOFileForS3File(pFile); - pool.log(`xRead ${file.path} ${n} @ ${offset64}`); - try { - const nRead = file.sah.read( - wasm.heap8u().subarray(pDest, pDest + n), - { at: HEADER_OFFSET_DATA + Number(offset64) }, - ); - if (nRead < n) { - wasm.heap8u().fill(0, pDest + nRead, pDest + n); - return capi.SQLITE_IOERR_SHORT_READ; - } - return 0; - } catch (e) { - return pool.storeErr(e, capi.SQLITE_IOERR); - } - }, - xSectorSize: function (pFile) { - return SECTOR_SIZE; - }, - xSync: function (pFile, flags) { - const pool = getPoolForPFile(pFile); - pool.log(`xSync ${flags}`); - pool.storeErr(); - const file = pool.getOFileForS3File(pFile); - - try { - file.sah.flush(); - return 0; - } catch (e) { - return pool.storeErr(e, capi.SQLITE_IOERR); - } - }, - xTruncate: function (pFile, sz64) { - const pool = getPoolForPFile(pFile); - pool.log(`xTruncate ${sz64}`); - pool.storeErr(); - const file = pool.getOFileForS3File(pFile); - - try { - file.sah.truncate(HEADER_OFFSET_DATA + Number(sz64)); - return 0; - } catch (e) { - return pool.storeErr(e, capi.SQLITE_IOERR); - } - }, - xUnlock: function (pFile, lockType) { - const pool = getPoolForPFile(pFile); - pool.log('xUnlock'); - const file = pool.getOFileForS3File(pFile); - file.lockType = lockType; - return 0; - }, - xWrite: function (pFile, pSrc, n, offset64) { - const pool = getPoolForPFile(pFile); - pool.storeErr(); - const file = pool.getOFileForS3File(pFile); - pool.log(`xWrite ${file.path} ${n} ${offset64}`); - try { - const nBytes = file.sah.write( - wasm.heap8u().subarray(pSrc, pSrc + n), - { at: HEADER_OFFSET_DATA + Number(offset64) }, - ); - return n === nBytes ? 0 : toss('Unknown write() failure.'); - } catch (e) { - return pool.storeErr(e, capi.SQLITE_IOERR); - } - }, - }; - - const opfsIoMethods = new capi.sqlite3_io_methods(); - opfsIoMethods.$iVersion = 1; - sqlite3.vfs.installVfs({ - io: { struct: opfsIoMethods, methods: ioMethods }, - }); - - const vfsMethods = { - xAccess: function (pVfs, zName, flags, pOut) { - const pool = getPoolForVfs(pVfs); - pool.storeErr(); - try { - const name = pool.getPath(zName); - wasm.poke32(pOut, pool.hasFilename(name) ? 1 : 0); - } catch (e) { - wasm.poke32(pOut, 0); - } - return 0; - }, - xCurrentTime: function (pVfs, pOut) { - wasm.poke( - pOut, - 2440587.5 + new Date().getTime() / 86400000, - 'double', - ); - return 0; - }, - xCurrentTimeInt64: function (pVfs, pOut) { - wasm.poke(pOut, 2440587.5 * 86400000 + new Date().getTime(), 'i64'); - return 0; - }, - xDelete: function (pVfs, zName, doSyncDir) { - const pool = getPoolForVfs(pVfs); - pool.log(`xDelete ${wasm.cstrToJs(zName)}`); - pool.storeErr(); - try { - pool.deletePath(pool.getPath(zName)); - return 0; - } catch (e) { - pool.storeErr(e); - return capi.SQLITE_IOERR_DELETE; - } - }, - xFullPathname: function (pVfs, zName, nOut, pOut) { - const i = wasm.cstrncpy(pOut, zName, nOut); - return i < nOut ? 0 : capi.SQLITE_CANTOPEN; - }, - xGetLastError: function (pVfs, nOut, pOut) { - const pool = getPoolForVfs(pVfs); - const e = pool.popErr(); - pool.log(`xGetLastError ${nOut} e =`, e); - if (e) { - const scope = wasm.scopedAllocPush(); - try { - const [cMsg, n] = wasm.scopedAllocCString(e.message, true); - wasm.cstrncpy(pOut, cMsg, nOut); - if (n > nOut) wasm.poke8(pOut + nOut - 1, 0); - } catch (e) { - return capi.SQLITE_NOMEM; - } finally { - wasm.scopedAllocPop(scope); - } - } - return e ? e.sqlite3Rc || capi.SQLITE_IOERR : 0; - }, - - xOpen: function f(pVfs, zName, pFile, flags, pOutFlags) { - const pool = getPoolForVfs(pVfs); - try { - pool.log(`xOpen ${wasm.cstrToJs(zName)} ${flags}`); - - const path = - zName && wasm.peek8(zName) - ? pool.getPath(zName) - : getRandomName(); - let sah = pool.getSAHForPath(path); - if (!sah && flags & capi.SQLITE_OPEN_CREATE) { - if (pool.getFileCount() < pool.getCapacity()) { - sah = pool.nextAvailableSAH(); - pool.setAssociatedPath(sah, path, flags); - } else { - toss('SAH pool is full. Cannot create file', path); - } - } - if (!sah) { - toss('file not found:', path); - } - - const file = { path, flags, sah }; - pool.mapS3FileToOFile(pFile, file); - file.lockType = capi.SQLITE_LOCK_NONE; - const sq3File = new capi.sqlite3_file(pFile); - sq3File.$pMethods = opfsIoMethods.pointer; - sq3File.dispose(); - wasm.poke32(pOutFlags, flags); - return 0; - } catch (e) { - pool.storeErr(e); - return capi.SQLITE_CANTOPEN; - } - }, - }; - - const createOpfsVfs = function (vfsName) { - if (sqlite3.capi.sqlite3_vfs_find(vfsName)) { - toss3('VFS name is already registered:', vfsName); - } - const opfsVfs = new capi.sqlite3_vfs(); - - const pDVfs = capi.sqlite3_vfs_find(null); - const dVfs = pDVfs ? new capi.sqlite3_vfs(pDVfs) : null; - opfsVfs.$iVersion = 2; - opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; - opfsVfs.$mxPathname = HEADER_MAX_PATH_SIZE; - opfsVfs.addOnDispose( - (opfsVfs.$zName = wasm.allocCString(vfsName)), - () => setPoolForVfs(opfsVfs.pointer, 0), - ); - - if (dVfs) { - opfsVfs.$xRandomness = dVfs.$xRandomness; - opfsVfs.$xSleep = dVfs.$xSleep; - dVfs.dispose(); - } - if (!opfsVfs.$xRandomness && !vfsMethods.xRandomness) { - vfsMethods.xRandomness = function (pVfs, nOut, pOut) { - const heap = wasm.heap8u(); - let i = 0; - for (; i < nOut; ++i) - heap[pOut + i] = (Math.random() * 255000) & 0xff; - return i; - }; - } - if (!opfsVfs.$xSleep && !vfsMethods.xSleep) { - vfsMethods.xSleep = (pVfs, ms) => 0; - } - sqlite3.vfs.installVfs({ - vfs: { struct: opfsVfs, methods: vfsMethods }, - }); - return opfsVfs; - }; - - class OpfsSAHPool { - vfsDir; - - #dhVfsRoot; - - #dhOpaque; - - #dhVfsParent; - - #mapSAHToName = new Map(); - - #mapFilenameToSAH = new Map(); - - #availableSAH = new Set(); - - #mapS3FileToOFile_ = new Map(); - - #apBody = new Uint8Array(HEADER_CORPUS_SIZE); - - #dvBody; - - #cVfs; - - #verbosity; - - constructor(options = Object.create(null)) { - this.#verbosity = options.verbosity ?? optionDefaults.verbosity; - this.vfsName = options.name || optionDefaults.name; - this.#cVfs = createOpfsVfs(this.vfsName); - setPoolForVfs(this.#cVfs.pointer, this); - this.vfsDir = options.directory || '.' + this.vfsName; - this.#dvBody = new DataView( - this.#apBody.buffer, - this.#apBody.byteOffset, - ); - this.isReady = this.reset( - !!(options.clearOnInit ?? optionDefaults.clearOnInit), - ).then(() => { - if (this.$error) throw this.$error; - return this.getCapacity() - ? Promise.resolve(undefined) - : this.addCapacity( - options.initialCapacity || optionDefaults.initialCapacity, - ); - }); - } - - #logImpl(level, ...args) { - if (this.#verbosity > level) - loggers[level](this.vfsName + ':', ...args); - } - log(...args) { - this.#logImpl(2, ...args); - } - warn(...args) { - this.#logImpl(1, ...args); - } - error(...args) { - this.#logImpl(0, ...args); - } - - getVfs() { - return this.#cVfs; - } - - getCapacity() { - return this.#mapSAHToName.size; - } - - getFileCount() { - return this.#mapFilenameToSAH.size; - } - - getFileNames() { - const rc = []; - const iter = this.#mapFilenameToSAH.keys(); - for (const n of iter) rc.push(n); - return rc; - } - - async addCapacity(n) { - for (let i = 0; i < n; ++i) { - const name = getRandomName(); - const h = await this.#dhOpaque.getFileHandle(name, { - create: true, - }); - const ah = await h.createSyncAccessHandle(); - this.#mapSAHToName.set(ah, name); - this.setAssociatedPath(ah, '', 0); - } - return this.getCapacity(); - } - - async reduceCapacity(n) { - let nRm = 0; - for (const ah of Array.from(this.#availableSAH)) { - if (nRm === n || this.getFileCount() === this.getCapacity()) { - break; - } - const name = this.#mapSAHToName.get(ah); - - ah.close(); - await this.#dhOpaque.removeEntry(name); - this.#mapSAHToName.delete(ah); - this.#availableSAH.delete(ah); - ++nRm; - } - return nRm; - } - - releaseAccessHandles() { - for (const ah of this.#mapSAHToName.keys()) ah.close(); - this.#mapSAHToName.clear(); - this.#mapFilenameToSAH.clear(); - this.#availableSAH.clear(); - } - - async acquireAccessHandles(clearFiles) { - const files = []; - for await (const [name, h] of this.#dhOpaque) { - if ('file' === h.kind) { - files.push([name, h]); - } - } - return Promise.all( - files.map(async ([name, h]) => { - try { - const ah = await h.createSyncAccessHandle(); - this.#mapSAHToName.set(ah, name); - if (clearFiles) { - ah.truncate(HEADER_OFFSET_DATA); - this.setAssociatedPath(ah, '', 0); - } else { - const path = this.getAssociatedPath(ah); - if (path) { - this.#mapFilenameToSAH.set(path, ah); - } else { - this.#availableSAH.add(ah); - } - } - } catch (e) { - this.storeErr(e); - this.releaseAccessHandles(); - throw e; - } - }), - ); - } - - getAssociatedPath(sah) { - sah.read(this.#apBody, { at: 0 }); - - const flags = this.#dvBody.getUint32(HEADER_OFFSET_FLAGS); - if ( - this.#apBody[0] && - (flags & capi.SQLITE_OPEN_DELETEONCLOSE || - (flags & PERSISTENT_FILE_TYPES) === 0) - ) { - warn( - `Removing file with unexpected flags ${flags.toString(16)}`, - this.#apBody, - ); - this.setAssociatedPath(sah, '', 0); - return ''; - } - - const fileDigest = new Uint32Array(HEADER_DIGEST_SIZE / 4); - sah.read(fileDigest, { at: HEADER_OFFSET_DIGEST }); - const compDigest = this.computeDigest(this.#apBody); - if (fileDigest.every((v, i) => v === compDigest[i])) { - const pathBytes = this.#apBody.findIndex((v) => 0 === v); - if (0 === pathBytes) { - sah.truncate(HEADER_OFFSET_DATA); - } - return pathBytes - ? textDecoder.decode(this.#apBody.subarray(0, pathBytes)) - : ''; - } else { - warn('Disassociating file with bad digest.'); - this.setAssociatedPath(sah, '', 0); - return ''; - } - } - - setAssociatedPath(sah, path, flags) { - const enc = textEncoder.encodeInto(path, this.#apBody); - if (HEADER_MAX_PATH_SIZE <= enc.written + 1) { - toss('Path too long:', path); - } - this.#apBody.fill(0, enc.written, HEADER_MAX_PATH_SIZE); - this.#dvBody.setUint32(HEADER_OFFSET_FLAGS, flags); - - const digest = this.computeDigest(this.#apBody); - sah.write(this.#apBody, { at: 0 }); - sah.write(digest, { at: HEADER_OFFSET_DIGEST }); - sah.flush(); - - if (path) { - this.#mapFilenameToSAH.set(path, sah); - this.#availableSAH.delete(sah); - } else { - sah.truncate(HEADER_OFFSET_DATA); - this.#availableSAH.add(sah); - } - } - - computeDigest(byteArray) { - let h1 = 0xdeadbeef; - let h2 = 0x41c6ce57; - for (const v of byteArray) { - h1 = 31 * h1 + v * 307; - h2 = 31 * h2 + v * 307; - } - return new Uint32Array([h1 >>> 0, h2 >>> 0]); - } - - async reset(clearFiles) { - await this.isReady; - let h = await navigator.storage.getDirectory(); - let prev; - for (const d of this.vfsDir.split('/')) { - if (d) { - prev = h; - h = await h.getDirectoryHandle(d, { create: true }); - } - } - this.#dhVfsRoot = h; - this.#dhVfsParent = prev; - this.#dhOpaque = await this.#dhVfsRoot.getDirectoryHandle( - OPAQUE_DIR_NAME, - { create: true }, - ); - this.releaseAccessHandles(); - return this.acquireAccessHandles(clearFiles); - } - - getPath(arg) { - if (wasm.isPtr(arg)) arg = wasm.cstrToJs(arg); - return ( - arg instanceof URL ? arg : new URL(arg, 'file://localhost/') - ).pathname; - } - - deletePath(path) { - const sah = this.#mapFilenameToSAH.get(path); - if (sah) { - this.#mapFilenameToSAH.delete(path); - this.setAssociatedPath(sah, '', 0); - } - return !!sah; - } - - storeErr(e, code) { - if (e) { - e.sqlite3Rc = code || capi.SQLITE_IOERR; - this.error(e); - } - this.$error = e; - return code; - } - - popErr() { - const rc = this.$error; - this.$error = undefined; - return rc; - } - - nextAvailableSAH() { - const [rc] = this.#availableSAH.keys(); - return rc; - } - - getOFileForS3File(pFile) { - return this.#mapS3FileToOFile_.get(pFile); - } - - mapS3FileToOFile(pFile, file) { - if (file) { - this.#mapS3FileToOFile_.set(pFile, file); - setPoolForPFile(pFile, this); - } else { - this.#mapS3FileToOFile_.delete(pFile); - setPoolForPFile(pFile, false); - } - } - - hasFilename(name) { - return this.#mapFilenameToSAH.has(name); - } - - getSAHForPath(path) { - return this.#mapFilenameToSAH.get(path); - } - - async removeVfs() { - if (!this.#cVfs.pointer || !this.#dhOpaque) return false; - capi.sqlite3_vfs_unregister(this.#cVfs.pointer); - this.#cVfs.dispose(); - try { - this.releaseAccessHandles(); - await this.#dhVfsRoot.removeEntry(OPAQUE_DIR_NAME, { - recursive: true, - }); - this.#dhOpaque = undefined; - await this.#dhVfsParent.removeEntry(this.#dhVfsRoot.name, { - recursive: true, - }); - this.#dhVfsRoot = this.#dhVfsParent = undefined; - } catch (e) { - sqlite3.config.error(this.vfsName, 'removeVfs() failed:', e); - } - return true; - } - - exportFile(name) { - const sah = - this.#mapFilenameToSAH.get(name) || toss('File not found:', name); - const n = sah.getSize() - HEADER_OFFSET_DATA; - const b = new Uint8Array(n > 0 ? n : 0); - if (n > 0) { - const nRead = sah.read(b, { at: HEADER_OFFSET_DATA }); - if (nRead != n) { - toss( - 'Expected to read ' + n + ' bytes but read ' + nRead + '.', - ); - } - } - return b; - } - - async importDbChunked(name, callback) { - const sah = - this.#mapFilenameToSAH.get(name) || - this.nextAvailableSAH() || - toss('No available handles to import to.'); - sah.truncate(0); - let nWrote = 0, - chunk, - checkedHeader = false; - try { - while (undefined !== (chunk = await callback())) { - if (chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk); - if (0 === nWrote && chunk.byteLength >= 15) { - util.affirmDbHeader(chunk); - checkedHeader = true; - } - sah.write(chunk, { at: HEADER_OFFSET_DATA + nWrote }); - nWrote += chunk.byteLength; - } - if (nWrote < 512 || 0 !== nWrote % 512) { - toss( - 'Input size', - nWrote, - 'is not correct for an SQLite database.', - ); - } - if (!checkedHeader) { - const header = new Uint8Array(20); - sah.read(header, { at: 0 }); - util.affirmDbHeader(header); - } - sah.write(new Uint8Array([1, 1]), { - at: HEADER_OFFSET_DATA + 18, - }); - } catch (e) { - this.setAssociatedPath(sah, '', 0); - throw e; - } - this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB); - return nWrote; - } - - importDb(name, bytes) { - if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); - else if (bytes instanceof Function) - return this.importDbChunked(name, bytes); - const sah = - this.#mapFilenameToSAH.get(name) || - this.nextAvailableSAH() || - toss('No available handles to import to.'); - const n = bytes.byteLength; - if (n < 512 || n % 512 != 0) { - toss('Byte array size is invalid for an SQLite db.'); - } - const header = 'SQLite format 3'; - for (let i = 0; i < header.length; ++i) { - if (header.charCodeAt(i) !== bytes[i]) { - toss('Input does not contain an SQLite database header.'); - } - } - const nWrote = sah.write(bytes, { at: HEADER_OFFSET_DATA }); - if (nWrote != n) { - this.setAssociatedPath(sah, '', 0); - toss( - 'Expected to write ' + n + ' bytes but wrote ' + nWrote + '.', - ); - } else { - sah.write(new Uint8Array([1, 1]), { - at: HEADER_OFFSET_DATA + 18, - }); - this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB); - } - return nWrote; - } - } - - class OpfsSAHPoolUtil { - #p; - - constructor(sahPool) { - this.#p = sahPool; - this.vfsName = sahPool.vfsName; - } - - async addCapacity(n) { - return this.#p.addCapacity(n); - } - - async reduceCapacity(n) { - return this.#p.reduceCapacity(n); - } - - getCapacity() { - return this.#p.getCapacity(this.#p); - } - - getFileCount() { - return this.#p.getFileCount(); - } - getFileNames() { - return this.#p.getFileNames(); - } - - async reserveMinimumCapacity(min) { - const c = this.#p.getCapacity(); - return c < min ? this.#p.addCapacity(min - c) : c; - } - - exportFile(name) { - return this.#p.exportFile(name); - } - - importDb(name, bytes) { - return this.#p.importDb(name, bytes); - } - - async wipeFiles() { - return this.#p.reset(true); - } - - unlink(filename) { - return this.#p.deletePath(filename); - } - - async removeVfs() { - return this.#p.removeVfs(); - } - } - - const apiVersionCheck = async () => { - const dh = await navigator.storage.getDirectory(); - const fn = '.opfs-sahpool-sync-check-' + getRandomName(); - const fh = await dh.getFileHandle(fn, { create: true }); - const ah = await fh.createSyncAccessHandle(); - const close = ah.close(); - await close; - await dh.removeEntry(fn); - if (close?.then) { - toss( - 'The local OPFS API is too old for opfs-sahpool:', - 'it has an async FileSystemSyncAccessHandle.close() method.', - ); - } - return true; - }; - - sqlite3.installOpfsSAHPoolVfs = async function ( - options = Object.create(null), - ) { - const vfsName = options.name || optionDefaults.name; - if (initPromises[vfsName]) { - return initPromises[vfsName]; - } - if ( - !globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory - ) { - return (initPromises[vfsName] = Promise.reject( - new Error('Missing required OPFS APIs.'), - )); - } - - return (initPromises[vfsName] = apiVersionCheck() - .then(async function () { - if (options.$testThrowInInit) { - throw options.$testThrowInInit; - } - const thePool = new OpfsSAHPool(options); - return thePool.isReady - .then(async () => { - const poolUtil = new OpfsSAHPoolUtil(thePool); - if (sqlite3.oo1) { - const oo1 = sqlite3.oo1; - const theVfs = thePool.getVfs(); - const OpfsSAHPoolDb = function (...args) { - const opt = oo1.DB.dbCtorHelper.normalizeArgs(...args); - opt.vfs = theVfs.$zName; - oo1.DB.dbCtorHelper.call(this, opt); - }; - OpfsSAHPoolDb.prototype = Object.create(oo1.DB.prototype); - - poolUtil.OpfsSAHPoolDb = OpfsSAHPoolDb; - oo1.DB.dbCtorHelper.setVfsPostOpenSql( - theVfs.pointer, - function (oo1Db, sqlite3) { - sqlite3.capi.sqlite3_exec( - oo1Db, - [ - 'pragma journal_mode=DELETE;', - 'pragma cache_size=-16384;', - ], - 0, - 0, - 0, - ); - }, - ); - } - thePool.log('VFS initialized.'); - return poolUtil; - }) - .catch(async (e) => { - await thePool.removeVfs().catch(() => {}); - throw e; - }); - }) - .catch((err) => { - return (initPromises[vfsName] = Promise.reject(err)); - })); - }; - }); - if ('undefined' !== typeof Module) { - const SABC = Object.assign( - Object.create(null), - { - exports: - 'undefined' === typeof wasmExports ? Module['asm'] : wasmExports, - memory: Module.wasmMemory, - }, - globalThis.sqlite3ApiConfig || {}, - ); - - globalThis.sqlite3ApiConfig = SABC; - let sqlite3; - try { - sqlite3 = globalThis.sqlite3ApiBootstrap(); - } catch (e) { - console.error('sqlite3ApiBootstrap() error:', e); - throw e; - } finally { - delete globalThis.sqlite3ApiBootstrap; - delete globalThis.sqlite3ApiConfig; - } - - Module.sqlite3 = sqlite3; - } else { - console.warn( - 'This is not running in an Emscripten module context, so', - 'globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack', - 'of config info for the WASM environment.', - 'It must be called manually.', - ); - } - }); - - return sqlite3InitModule.ready; - }; -})(); - -const toExportForESM = (function () { - const originalInit = sqlite3InitModule; - if (!originalInit) { - throw new Error( - 'Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build.', - ); - } - - const initModuleState = (globalThis.sqlite3InitModuleState = Object.assign( - Object.create(null), - { - moduleScript: globalThis?.document?.currentScript, - isWorker: 'undefined' !== typeof WorkerGlobalScope, - location: globalThis.location, - urlParams: globalThis?.location?.href - ? new URL(globalThis.location.href).searchParams - : new URLSearchParams(), - }, - )); - initModuleState.debugModule = initModuleState.urlParams.has( - 'sqlite3.debugModule', - ) - ? (...args) => console.warn('sqlite3.debugModule:', ...args) - : () => {}; - - if (initModuleState.urlParams.has('sqlite3.dir')) { - initModuleState.sqlite3Dir = - initModuleState.urlParams.get('sqlite3.dir') + '/'; - } else if (initModuleState.moduleScript) { - const li = initModuleState.moduleScript.src.split('/'); - li.pop(); - initModuleState.sqlite3Dir = li.join('/') + '/'; - } - - globalThis.sqlite3InitModule = function ff(...args) { - return originalInit(...args) - .then((EmscriptenModule) => { - const s = EmscriptenModule.sqlite3; - s.scriptInfo = initModuleState; - - if (ff.__isUnderTest) s.__isUnderTest = true; - const f = s.asyncPostInit; - delete s.asyncPostInit; - return f(); - }) - .catch((e) => { - console.error('Exception loading sqlite3 module:', e); - throw e; - }); - }; - globalThis.sqlite3InitModule.ready = originalInit.ready; - - if (globalThis.sqlite3InitModuleState.moduleScript) { - const sim = globalThis.sqlite3InitModuleState; - let src = sim.moduleScript.src.split('/'); - src.pop(); - sim.scriptDir = src.join('/') + '/'; - } - initModuleState.debugModule('sqlite3InitModuleState =', initModuleState); - return globalThis.sqlite3InitModule; -})(); -sqlite3InitModule = toExportForESM; -var sqlite3InitModule$1 = sqlite3InitModule; - -/* - 2022-08-24 - - The author disclaims copyright to this source code. In place of a - legal notice, here is a blessing: - - * May you do good and not evil. - * May you find forgiveness for yourself and forgive others. - * May you share freely, never taking more than you give. - - *********************************************************************** - - This file implements a Promise-based proxy for the sqlite3 Worker - API #1. It is intended to be included either from the main thread or - a Worker, but only if (A) the environment supports nested Workers - and (B) it's _not_ a Worker which loads the sqlite3 WASM/JS - module. This file's features will load that module and provide a - slightly simpler client-side interface than the slightly-lower-level - Worker API does. - - This script necessarily exposes one global symbol, but clients may - freely `delete` that symbol after calling it. -*/ - -globalThis.sqlite3Worker1Promiser = function callee( - config = callee.defaultConfig, -) { - if (1 === arguments.length && 'function' === typeof arguments[0]) { - const f = config; - config = Object.assign(Object.create(null), callee.defaultConfig); - config.onready = f; - } else { - config = Object.assign(Object.create(null), callee.defaultConfig, config); - } - const handlerMap = Object.create(null); - const noop = function () {}; - const err = config.onerror || noop; - const debug = config.debug || noop; - const idTypeMap = config.generateMessageId ? undefined : Object.create(null); - const genMsgId = - config.generateMessageId || - function (msg) { - return ( - msg.type + '#' + (idTypeMap[msg.type] = (idTypeMap[msg.type] || 0) + 1) - ); - }; - const toss = (...args) => { - throw new Error(args.join(' ')); - }; - if (!config.worker) config.worker = callee.defaultConfig.worker; - if ('function' === typeof config.worker) config.worker = config.worker(); - let dbId; - let promiserFunc; - config.worker.onmessage = function (ev) { - ev = ev.data; - debug('worker1.onmessage', ev); - let msgHandler = handlerMap[ev.messageId]; - if (!msgHandler) { - if (ev && 'sqlite3-api' === ev.type && 'worker1-ready' === ev.result) { - if (config.onready) config.onready(promiserFunc); - return; - } - msgHandler = handlerMap[ev.type]; - if (msgHandler && msgHandler.onrow) { - msgHandler.onrow(ev); - return; - } - if (config.onunhandled) config.onunhandled(arguments[0]); - else err('sqlite3Worker1Promiser() unhandled worker message:', ev); - return; - } - delete handlerMap[ev.messageId]; - switch (ev.type) { - case 'error': - msgHandler.reject(ev); - return; - case 'open': - if (!dbId) dbId = ev.dbId; - break; - case 'close': - if (ev.dbId === dbId) dbId = undefined; - break; - } - try { - msgHandler.resolve(ev); - } catch (e) { - msgHandler.reject(e); - } - }; - return (promiserFunc = function () { - let msg; - if (1 === arguments.length) { - msg = arguments[0]; - } else if (2 === arguments.length) { - msg = Object.create(null); - msg.type = arguments[0]; - msg.args = arguments[1]; - msg.dbId = msg.args.dbId; - } else { - toss('Invalid arguments for sqlite3Worker1Promiser()-created factory.'); - } - if (!msg.dbId && msg.type !== 'open') msg.dbId = dbId; - msg.messageId = genMsgId(msg); - msg.departureTime = performance.now(); - const proxy = Object.create(null); - proxy.message = msg; - let rowCallbackId; - if ('exec' === msg.type && msg.args) { - if ('function' === typeof msg.args.callback) { - rowCallbackId = msg.messageId + ':row'; - proxy.onrow = msg.args.callback; - msg.args.callback = rowCallbackId; - handlerMap[rowCallbackId] = proxy; - } else if ('string' === typeof msg.args.callback) { - toss( - 'exec callback may not be a string when using the Promise interface.', - ); - } - } - - let p = new Promise(function (resolve, reject) { - proxy.resolve = resolve; - proxy.reject = reject; - handlerMap[msg.messageId] = proxy; - debug( - 'Posting', - msg.type, - 'message to Worker dbId=' + (dbId || 'default') + ':', - msg, - ); - config.worker.postMessage(msg); - }); - if (rowCallbackId) p = p.finally(() => delete handlerMap[rowCallbackId]); - return p; - }); -}; - -globalThis.sqlite3Worker1Promiser.defaultConfig = { - worker: function () { - return new Worker( - new URL('sqlite3-worker1-bundler-friendly.mjs', import.meta.url), - { - type: 'module', - }, - ); - }, - onerror: (...args) => console.error('worker1 promiser error', ...args), -}; - -sqlite3Worker1Promiser.v2 = function (config) { - let oldFunc; - if ('function' == typeof config) { - oldFunc = config; - config = {}; - } else if ('function' === typeof config?.onready) { - oldFunc = config.onready; - delete config.onready; - } - const promiseProxy = Object.create(null); - config = Object.assign(config || Object.create(null), { - onready: async function (func) { - try { - if (oldFunc) await oldFunc(func); - promiseProxy.resolve(func); - } catch (e) { - promiseProxy.reject(e); - } - }, - }); - const p = new Promise(function (resolve, reject) { - promiseProxy.resolve = resolve; - promiseProxy.reject = reject; - }); - try { - this.original(config); - } catch (e) { - promiseProxy.reject(e); - } - return p; -}.bind({ - original: sqlite3Worker1Promiser, -}); - -sqlite3Worker1Promiser.v2; - -const log = console.log; -const err_log = console.error; - -class SQLiteError extends Error { - constructor(message, code) { - super(message); - this.code = code; - } -} - -class SQLite { - #module; - #sqlite3; - constructor(sqlite3) { - if (typeof sqlite3 === "undefined") { - throw new Error( - "`sqliteObject` must be defined before calling constructor", - ); - } - this.sqlite3 = sqlite3; - } - - static async init_module(opts) { - return await sqlite3InitModule$1({ - print: log, - printErr: err_log, - ...opts, - }); - } - - version() { - return this.sqlite3.version; - } - - filename(db, name) { - return this.sqlite3.capi.sqlite3_db_filename(db, name); - } - - extended_errcode(connection) { - return this.sqlite3.capi.sqlite3_extended_errcode(connection); - } - - errstr(code) { - return this.sqlite3.capi.sqlite3_errstr(code); - } - - errmsg(connection) { - return this.sqlite3.capi.sqlite3_errmsg(connection); - } - - result_js(context, value) { - return this.sqlite3.capi.sqlite3_result_js(context, value); - } - - result_text(context, value) { - return this.sqlite3.capi.sqlite3_result_text(context, value); - } - - result_int(context, value) { - return this.sqlite3.capi.sqlite3_result_int(context, value); - } - - result_int64(context, value) { - return this.sqlite3.capi.sqlite3_result_int64(context, value); - } - - result_double(context, value) { - return this.sqlite3.capi.sqlite3_result_double(context, value); - } - - result_blob(context, value) { - return this.sqlite3.capi.sqlite3_result_blob(context, value); - } - - result_null(context) { - return this.sqlite3.capi.sqlite3_result_null(context); - } - - bind_blob(stmt, i, value, len, flags) { - return this.sqlite3.capi.sqlite3_bind_blob(stmt, i, value, len, flags); - } - - bind_text(stmt, i, value, len, flags) { - return this.sqlite3.capi.sqlite3_bind_text(stmt, i, value, len, flags); - } - - bind_double(stmt, i, value) { - return this.sqlite3.capi.sqlite3_bind_double(stmt, i, value); - } - - bind_int(stmt, i, value) { - return this.sqlite3.capi.sqlite3_bind_int(stmt, i, value); - } - - bind_int64(stmt, i, value) { - return this.sqlite3.capi.sqlite3_bind_int64(stmt, i, value); - } - - bind_null(stmt, i) { - this.sqlite3.capi.sqlite3_bind_null(stmt, i); - /// There's no way bind_null can fail. - return this.sqlite3.capi.SQLITE_OK; - } - - bind_parameter_count(stmt) { - return this.sqlite3.capi.sqlite3_bind_parameter_count(stmt); - } - - bind_parameter_name(stmt, i) { - return this.sqlite3.capi.sqlite3_bind_paramater_name(stmt, it); - } - - value_dup(pValue) { - return this.sqlite3.capi.sqlite3_value_dup(pValue); - } - - value_blob(pValue) { - return this.sqlite3.capi.sqlite3_value_blob(pValue); - } - - value_bytes(pValue) { - return this.sqlite3.capi.sqlite3_value_bytes(pValue); - } - - value_double(pValue) { - return this.sqlite3.capi.sqlite3_value_double(pValue); - } - - value_int(pValue) { - return this.sqlite3.capi.sqlite3_value_int(pValue); - } - - value_int64(pValue) { - return this.sqlite3.capi.sqlite3_value_int64(pValue); - } - - value_text(pValue) { - return this.sqlite3.capi.sqlite3_value_text(pValue); - } - - value_type(pValue) { - return this.sqlite3.capi.sqlite3_value_type(pValue); - } - - open(database_url, iflags) { - try { - return new this.sqlite3.oo1.OpfsDb(database_url); - } catch (error) { - console.log("OPFS open error", error); - throw error; - } - } - - exec(db, query) { - try { - return db.exec(query, { - callback: (row) => {}, - }); - } catch (error) { - throw error; - } - } - - finalize(stmt) { - return this.sqlite3.capi.sqlite3_finalize(stmt); - } - - changes(db) { - return this.sqlite3.capi.sqlite3_changes(db); - } - - clear_bindings(stmt) { - return this.sqlite3.capi.sqlite3_clear_bindings(stmt); - } - - reset(stmt) { - return this.sqlite3.capi.sqlite3_reset(stmt); - } - - close(db) { - return this.sqlite3.capi.sqlite3_close_v2(db.pointer); - } - - db_handle(stmt) { - return this.sqlite3.capi.sqlite3_db_handle(stmt); - } - - prepare_v3(db, sql, nByte, prepFlags, ppStmt, pzTail) { - return this.sqlite3.capi.sqlite3_prepare_v3( - db.pointer, - sql, - nByte, - prepFlags, - ppStmt, - pzTail, - ); - } - - step(stmt) { - return this.sqlite3.capi.sqlite3_step(stmt); - } - - column_value(stmt, i) { - return this.sqlite3.capi.sqlite3_column_value(stmt, i); - } - - column_name(stmt, idx) { - return this.sqlite3.capi.sqlite3_column_name(stmt, idx); - } - - column_count(stmt) { - return this.sqlite3.capi.sqlite3_column_count(stmt); - } - - create_function( - database, - functionName, - nArg, - textRep, - pApp, - xFunc, - xStep, - xFinal, - ) { - try { - this.sqlite3.capi.sqlite3_create_function( - database, - functionName, - nArg, - textRep, - pApp, // pApp is ignored - xFunc, - xStep, - xFinal, - ); - console.log("create function"); - } catch (error) { - console.log("create function err"); - throw error; - } - } - - //TODO: At some point need a way to register functions from rust - //but for now this is fine. - register_diesel_sql_functions(database) { - try { - this.sqlite3.capi.sqlite3_create_function( - database, - "diesel_manage_updated_at", - 1, - this.sqlite3.capi.SQLITE_UTF8, - 0, - async (context, values) => { - const table_name = this.sqlite3.value_text(values[0]); - - database.exec( - context, - `CREATE TRIGGER __diesel_manage_updated_at_${table_name} - AFTER UPDATE ON ${table_name} - FOR EACH ROW WHEN - old.updated_at IS NULL AND - new.updated_at IS NULL OR - old.updated_at == new.updated_at - BEGIN - UPDATE ${table_name} - SET updated_at = CURRENT_TIMESTAMP - WHERE ROWID = new.ROWID; - END`, - (row) => { - log(`------------------------------------`); - log(`Created trigger for ${table_name}`); - log(row); - log(`------------------------------------`); - }, - ); - }, - ); - } catch (error) { - console.log("error creating diesel trigger"); - throw error; - } - } - - value_free(value) { - return this.sqlite3.capi.sqlite3_value_free(value); - } - - sqlite3_serialize(database, z_schema, p_size, m_flags) { - try { - return this.sqlite3.capi.sqlite3_serialize( - database, - z_schema, - p_size, - m_flags, - ); - } catch (error) { - console.log("error serializing"); - throw error; - } - } - - sqlite3_deserialize( - database, - z_schema, - p_data, - sz_database, - sz_buffer, - m_flags, - ) { - try { - return this.sqlite3.capi.sqlite3_deserialize( - database, - z_schema, - p_data, - sz_database, - sz_buffer, - m_flags, - ); - } catch (error) { - console.log("error deserializing"); - throw error; - } - } - - sqlite3_free(_database, arg1) { - return this.sqlite3.capi.sqlite3_free(arg1); - } -} - -export { SQLite, SQLiteError }; diff --git a/diesel-wasm-sqlite/src/lib.rs b/diesel-wasm-sqlite/src/lib.rs deleted file mode 100755 index 0707acaa1..000000000 --- a/diesel-wasm-sqlite/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Module for an SQLite backend accesible from the web. -pub mod backend; -pub mod connection; -pub mod ffi; -pub mod query_builder; -pub mod sqlite_fixes; -pub mod sqlite_types; - -#[global_allocator] -static ALLOCATOR: talc::TalckWasm = unsafe { talc::TalckWasm::new_global() }; - -#[cfg(any(feature = "unsafe-debug-query", test))] -pub use query_builder::insert_with_default_sqlite::unsafe_debug_query::DebugQueryWrapper; - -#[cfg(not(target_arch = "wasm32"))] -compile_error!("This crate only suports the `wasm32-unknown-unknown` target"); - -use wasm_bindgen::JsValue; - -pub use backend::{SqliteType, WasmSqlite}; -pub(crate) use ffi::get_sqlite_unchecked; -pub use ffi::init_sqlite; -pub use sqlite_fixes::dsl; - -#[derive(thiserror::Error, Debug)] -pub enum WasmSqliteError { - #[error("JS Bridge Error {0:?}")] - Js(JsValue), - #[error(transparent)] - Diesel(#[from] diesel::result::Error), - #[error(transparent)] - Bindgen(#[from] serde_wasm_bindgen::Error), -} - -impl From for diesel::result::Error { - fn from(value: WasmSqliteError) -> diesel::result::Error { - tracing::error!("NOT IMPLEMENTED, {:?}", value); - diesel::result::Error::NotFound - } -} - -impl From for diesel::result::ConnectionError { - fn from(value: WasmSqliteError) -> diesel::result::ConnectionError { - tracing::error!("{:?}", value); - diesel::result::ConnectionError::BadConnection("Not implemented".to_string()) - } -} - -impl From for WasmSqliteError { - fn from(err: JsValue) -> WasmSqliteError { - WasmSqliteError::Js(err) - } -} diff --git a/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs b/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs deleted file mode 100644 index bc5a11f8d..000000000 --- a/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs +++ /dev/null @@ -1,567 +0,0 @@ -use crate::{WasmSqlite, dsl::ExecuteDsl}; -use diesel::connection::Connection; -use diesel::insertable::InsertValues; -use diesel::insertable::{CanInsertInSingleQuery, ColumnInsertValue, DefaultableColumnInsertValue}; -// use diesel::prelude::RunQueryDsl; -use diesel::query_builder::QueryFragment; -use diesel::query_builder::{AstPass, QueryId, ValuesClause}; -use diesel::query_builder::{BatchInsert, InsertStatement}; -// use diesel::query_dsl::load_dsl::ExecuteDsl; -use diesel::{QueryResult, QuerySource, Table}; - -#[cfg(any(feature = "unsafe-debug-query", test))] -pub mod unsafe_debug_query { - use super::*; - use diesel::backend::Backend; - use diesel::{debug_query, query_builder::DebugQuery}; - use std::fmt::{self, Debug, Display}; - - pub trait DebugQueryHelper { - fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; - fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; - } - - // FIXME: Here to temporarily workaround private fields of `DebugQuery`. - // this should never go in prod - // this is cause `DebugQuery` is private - #[repr(transparent)] - struct DebugQueryUnsafe<'a, T: 'a, DB> { - pub(crate) query: &'a T, - _marker: std::marker::PhantomData, - } - - impl<'a, T, V, QId, Op, Ret, const STATIC_QUERY_ID: bool> DebugQueryHelper - for DebugQuery< - 'a, - InsertStatement< - T, - BatchInsert>, T, QId, STATIC_QUERY_ID>, - Op, - Ret, - >, - WasmSqlite, - > - where - V: QueryFragment, - T: Copy + QuerySource, - Op: Copy, - Ret: Copy, - for<'b> InsertStatement, Op, Ret>: QueryFragment, - { - fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let query = unsafe { - std::mem::transmute::< - &DebugQuery< - 'a, - InsertStatement< - T, - BatchInsert>, T, QId, STATIC_QUERY_ID>, - Op, - Ret, - >, - WasmSqlite, - >, - &DebugQueryUnsafe< - 'a, - InsertStatement< - T, - BatchInsert>, T, QId, STATIC_QUERY_ID>, - Op, - Ret, - >, - WasmSqlite, - >, - >(self) - }; - let query = query.query; - let mut statements = vec![String::from("BEGIN")]; - for record in query.records.values.iter() { - let stmt = - InsertStatement::new(query.target, record, query.operator, query.returning); - statements.push(debug_query(&stmt).to_string()); - } - statements.push("COMMIT".into()); - f.debug_struct("Query") - .field("sql", &statements) - .field("binds", &[] as &[i32; 0]) - .finish() - } - - fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let query = unsafe { - std::mem::transmute::< - &DebugQuery< - 'a, - InsertStatement< - T, - BatchInsert>, T, QId, STATIC_QUERY_ID>, - Op, - Ret, - >, - WasmSqlite, - >, - &DebugQueryUnsafe< - 'a, - InsertStatement< - T, - BatchInsert>, T, QId, STATIC_QUERY_ID>, - Op, - Ret, - >, - WasmSqlite, - >, - >(self) - }; - let query = query.query; - writeln!(f, "BEGIN;")?; - for record in query.records.values.iter() { - let stmt = - InsertStatement::new(query.target, record, query.operator, query.returning); - writeln!(f, "{}", debug_query(&stmt))?; - } - writeln!(f, "COMMIT;")?; - Ok(()) - } - } - - #[allow(unsafe_code)] // cast to transparent wrapper type - impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> DebugQueryHelper - for DebugQuery< - 'a, - InsertStatement, Op>, - WasmSqlite, - > - where - T: Copy + QuerySource, - Op: Copy, - DebugQuery< - 'a, - InsertStatement, Op>, - WasmSqlite, - >: Debug + Display, - { - fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let value = unsafe { - // This cast is safe as `SqliteBatchInsertWrapper` is #[repr(transparent)] - &*(self as *const DebugQuery< - 'a, - InsertStatement, Op>, - WasmSqlite, - > - as *const DebugQuery< - 'a, - InsertStatement< - T, - SqliteBatchInsertWrapper, - Op, - >, - WasmSqlite, - >) - }; - <_ as Debug>::fmt(value, f) - } - fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let value = unsafe { - // This cast is safe as `SqliteBatchInsertWrapper` is #[repr(transparent)] - &*(self as *const DebugQuery< - 'a, - InsertStatement, Op>, - WasmSqlite, - > - as *const DebugQuery< - 'a, - InsertStatement< - T, - SqliteBatchInsertWrapper, - Op, - >, - WasmSqlite, - >) - }; - <_ as Display>::fmt(value, f) - } - } - - pub struct DebugQueryWrapper<'a, T: 'a, DB>(DebugQuery<'a, T, DB>); - - impl<'a, T, DB> DebugQueryWrapper<'a, T, DB> { - pub fn new(query: &'a T) -> Self { - DebugQueryWrapper(diesel::debug_query(query)) - } - } - - impl<'a, T, DB> Display for DebugQueryWrapper<'a, T, DB> - where - DB: Backend + Default, - DB::QueryBuilder: Default, - T: QueryFragment, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - std::fmt::Display::fmt(&self.0, f) - } - } - - impl<'a, T, DB> Debug for DebugQueryWrapper<'a, T, DB> - where - DB: Backend + Default, - DB::QueryBuilder: Default, - T: QueryFragment, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - std::fmt::Debug::fmt(&self.0, f) - } - } - - impl<'a, T, V, QId, Op, Ret, const STATIC_QUERY_ID: bool> DebugQueryHelper - for DebugQueryWrapper< - 'a, - InsertStatement< - T, - BatchInsert>, T, QId, STATIC_QUERY_ID>, - Op, - Ret, - >, - WasmSqlite, - > - where - V: QueryFragment, - T: Copy + QuerySource, - Op: Copy, - Ret: Copy, - for<'b> InsertStatement, Op, Ret>: QueryFragment, - { - fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - DebugQueryHelper::fmt_debug(&self.0, f) - } - - fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - DebugQueryHelper::fmt_display(&self.0, f) - } - } - - impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> DebugQueryHelper - for DebugQueryWrapper< - 'a, - InsertStatement, Op>, - WasmSqlite, - > - where - T: Copy + QuerySource, - Op: Copy, - DebugQuery< - 'a, - InsertStatement, Op>, - WasmSqlite, - >: Debug + Display, - { - fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - DebugQueryHelper::fmt_debug(&self.0, f) - } - - fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - DebugQueryHelper::fmt_display(&self.0, f) - } - } - - impl<'a, T, V, QId, Op, O, const STATIC_QUERY_ID: bool> Display - for DebugQueryWrapper< - 'a, - InsertStatement>, T, QId, STATIC_QUERY_ID>, Op>, - WasmSqlite, - > - where - T: QuerySource, - V: ContainsDefaultableValue, - Self: DebugQueryHelper, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.fmt_display(f) - } - } - - impl<'a, T, V, QId, Op, O, const STATIC_QUERY_ID: bool> Debug - for DebugQueryWrapper< - 'a, - InsertStatement>, T, QId, STATIC_QUERY_ID>, Op>, - WasmSqlite, - > - where - T: QuerySource, - V: ContainsDefaultableValue, - Self: DebugQueryHelper, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.fmt_debug(f) - } - } -} - -#[allow(missing_debug_implementations, missing_copy_implementations)] -pub struct Yes; - -impl Default for Yes { - fn default() -> Self { - Yes - } -} - -#[allow(missing_debug_implementations, missing_copy_implementations)] -pub struct No; - -impl Default for No { - fn default() -> Self { - No - } -} - -pub trait Any { - type Out: Any + Any; -} - -impl Any for No { - type Out = No; -} - -impl Any for No { - type Out = Yes; -} - -impl Any for Yes { - type Out = Yes; -} - -impl Any for Yes { - type Out = Yes; -} - -pub trait ContainsDefaultableValue { - type Out: Any + Any; -} - -impl ContainsDefaultableValue for ColumnInsertValue { - type Out = No; -} - -impl ContainsDefaultableValue for DefaultableColumnInsertValue { - type Out = Yes; -} - -impl ContainsDefaultableValue for [I; SIZE] -where - I: ContainsDefaultableValue, -{ - type Out = I::Out; -} - -impl ContainsDefaultableValue for ValuesClause -where - I: ContainsDefaultableValue, -{ - type Out = I::Out; -} - -impl<'a, T> ContainsDefaultableValue for &'a T -where - T: ContainsDefaultableValue, -{ - type Out = T::Out; -} - -impl ExecuteDsl - for InsertStatement>, T, QId, STATIC_QUERY_ID>, Op> -where - T: QuerySource, - C: Connection, - V: ContainsDefaultableValue, - O: Default, - (O, Self): ExecuteDsl, -{ - fn execute(query: Self, conn: &mut C) -> QueryResult { - <(O, Self) as ExecuteDsl>::execute( - (O::default(), query), - conn, - ) - } -} - -impl ExecuteDsl - for ( - Yes, - InsertStatement>, T, QId, STATIC_QUERY_ID>, Op>, - ) -where - T: Table + Copy + QueryId + 'static, - C: Connection, - T::FromClause: QueryFragment, - Op: Copy + QueryId + QueryFragment, - V: InsertValues + CanInsertInSingleQuery + QueryId, -{ - fn execute((Yes, query): Self, conn: &mut C) -> QueryResult { - conn.transaction(|conn| { - let mut result = 0; - for record in &query.records.values { - let stmt = - InsertStatement::new(query.target, record, query.operator, query.returning); - result += ExecuteDsl::::execute(stmt, conn)?; - } - Ok(result) - }) - } -} - -#[allow(missing_debug_implementations, missing_copy_implementations)] -#[repr(transparent)] -pub struct SqliteBatchInsertWrapper( - BatchInsert, -); - -impl QueryFragment - for SqliteBatchInsertWrapper>, Tab, QId, STATIC_QUERY_ID> -where - ValuesClause: QueryFragment, - V: QueryFragment, -{ - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - if !STATIC_QUERY_ID { - out.unsafe_to_cache_prepared(); - } - - let mut values = self.0.values.iter(); - if let Some(value) = values.next() { - value.walk_ast(out.reborrow())?; - } - for value in values { - out.push_sql(", ("); - value.values.walk_ast(out.reborrow())?; - out.push_sql(")"); - } - Ok(()) - } -} - -#[allow(missing_copy_implementations, missing_debug_implementations)] -#[repr(transparent)] -pub struct SqliteCanInsertInSingleQueryHelper(T); - -impl CanInsertInSingleQuery - for SqliteBatchInsertWrapper>, T, QId, STATIC_QUERY_ID> -where - // We constrain that here on an internal helper type - // to make sure that this does not accidentally leak - // so that none does really implement normal batch - // insert for inserts with default values here - SqliteCanInsertInSingleQueryHelper: CanInsertInSingleQuery, -{ - fn rows_to_insert(&self) -> Option { - Some(self.0.values.len()) - } -} - -impl CanInsertInSingleQuery for SqliteCanInsertInSingleQueryHelper -where - T: CanInsertInSingleQuery, -{ - fn rows_to_insert(&self) -> Option { - self.0.rows_to_insert() - } -} - -impl QueryId - for SqliteBatchInsertWrapper -where - BatchInsert: QueryId, -{ - type QueryId = as QueryId>::QueryId; - - const HAS_STATIC_QUERY_ID: bool = - as QueryId>::HAS_STATIC_QUERY_ID; -} - -impl ExecuteDsl - for ( - No, - InsertStatement, Op>, - ) -where - T: Table + QueryId + 'static, - T::FromClause: QueryFragment, - C: Connection, - Op: QueryFragment + QueryId, - SqliteBatchInsertWrapper: - QueryFragment + QueryId + CanInsertInSingleQuery, -{ - fn execute((No, query): Self, conn: &mut C) -> QueryResult { - let query = InsertStatement::new( - query.target, - SqliteBatchInsertWrapper(query.records), - query.operator, - query.returning, - ); - ExecuteDsl::::execute(query, conn) - } -} - -macro_rules! tuple_impls { - ($( - $Tuple:tt { - $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+ - } - )+) => { - $( - impl_contains_defaultable_value!($($T,)*); - )* - } - } - -macro_rules! impl_contains_defaultable_value { - ( - @build - start_ts = [$($ST: ident,)*], - ts = [$T1: ident,], - bounds = [$($bounds: tt)*], - out = [$($out: tt)*], - )=> { - impl<$($ST,)*> ContainsDefaultableValue for ($($ST,)*) - where - $($ST: ContainsDefaultableValue,)* - $($bounds)* - $T1::Out: Any<$($out)*>, - { - type Out = <$T1::Out as Any<$($out)*>>::Out; - } - - }; - ( - @build - start_ts = [$($ST: ident,)*], - ts = [$T1: ident, $($T: ident,)+], - bounds = [$($bounds: tt)*], - out = [$($out: tt)*], - )=> { - impl_contains_defaultable_value! { - @build - start_ts = [$($ST,)*], - ts = [$($T,)*], - bounds = [$($bounds)* $T1::Out: Any<$($out)*>,], - out = [<$T1::Out as Any<$($out)*>>::Out], - } - }; - ($T1: ident, $($T: ident,)+) => { - impl_contains_defaultable_value! { - @build - start_ts = [$T1, $($T,)*], - ts = [$($T,)*], - bounds = [], - out = [$T1::Out], - } - }; - ($T1: ident,) => { - impl<$T1> ContainsDefaultableValue for ($T1,) - where $T1: ContainsDefaultableValue, - { - type Out = <$T1 as ContainsDefaultableValue>::Out; - } - } -} - -diesel_derives::__diesel_for_each_tuple!(tuple_impls); diff --git a/diesel-wasm-sqlite/src/query_builder/limit_offset.rs b/diesel-wasm-sqlite/src/query_builder/limit_offset.rs deleted file mode 100644 index 65740b9fd..000000000 --- a/diesel-wasm-sqlite/src/query_builder/limit_offset.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::WasmSqlite; -use diesel::query_builder::{AstPass, IntoBoxedClause, QueryFragment}; -use diesel::query_builder::{BoxedLimitOffsetClause, LimitOffsetClause}; -use diesel::query_builder::{LimitClause, NoLimitClause}; -use diesel::query_builder::{NoOffsetClause, OffsetClause}; -use diesel::result::QueryResult; - -impl QueryFragment for LimitOffsetClause { - fn walk_ast<'b>(&'b self, _out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - Ok(()) - } -} - -impl QueryFragment for LimitOffsetClause, NoOffsetClause> -where - LimitClause: QueryFragment, -{ - fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - self.limit_clause.walk_ast(out)?; - Ok(()) - } -} - -impl QueryFragment for LimitOffsetClause> -where - OffsetClause: QueryFragment, -{ - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - // Sqlite requires a limit clause in front of any offset clause - // using `LIMIT -1` is the same as not having any limit clause - // https://sqlite.org/lang_select.html - out.push_sql(" LIMIT -1 "); - self.offset_clause.walk_ast(out)?; - Ok(()) - } -} - -impl QueryFragment for LimitOffsetClause, OffsetClause> -where - LimitClause: QueryFragment, - OffsetClause: QueryFragment, -{ - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - self.limit_clause.walk_ast(out.reborrow())?; - self.offset_clause.walk_ast(out.reborrow())?; - Ok(()) - } -} - -impl<'a> QueryFragment for BoxedLimitOffsetClause<'a, WasmSqlite> { - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - match (self.limit.as_ref(), self.offset.as_ref()) { - (Some(limit), Some(offset)) => { - limit.walk_ast(out.reborrow())?; - offset.walk_ast(out.reborrow())?; - } - (Some(limit), None) => { - limit.walk_ast(out.reborrow())?; - } - (None, Some(offset)) => { - // See the `QueryFragment` implementation for `LimitOffsetClause` for details. - out.push_sql(" LIMIT -1 "); - offset.walk_ast(out.reborrow())?; - } - (None, None) => {} - } - Ok(()) - } -} - -// Have explicit impls here because we need to set `Some`/`None` for the clauses -// correspondingly, otherwise we cannot match on it in the `QueryFragment` impl -// above -impl<'a> IntoBoxedClause<'a, WasmSqlite> for LimitOffsetClause { - type BoxedClause = BoxedLimitOffsetClause<'a, WasmSqlite>; - - fn into_boxed(self) -> Self::BoxedClause { - BoxedLimitOffsetClause { - limit: None, - offset: None, - } - } -} - -impl<'a, L> IntoBoxedClause<'a, WasmSqlite> for LimitOffsetClause, NoOffsetClause> -where - L: QueryFragment + Send + 'a, -{ - type BoxedClause = BoxedLimitOffsetClause<'a, WasmSqlite>; - - fn into_boxed(self) -> Self::BoxedClause { - BoxedLimitOffsetClause { - limit: Some(Box::new(self.limit_clause)), - offset: None, - } - } -} - -impl<'a, O> IntoBoxedClause<'a, WasmSqlite> for LimitOffsetClause> -where - O: QueryFragment + Send + 'a, -{ - type BoxedClause = BoxedLimitOffsetClause<'a, WasmSqlite>; - - fn into_boxed(self) -> Self::BoxedClause { - BoxedLimitOffsetClause { - limit: None, - offset: Some(Box::new(self.offset_clause)), - } - } -} - -impl<'a, L, O> IntoBoxedClause<'a, WasmSqlite> - for LimitOffsetClause, OffsetClause> -where - L: QueryFragment + Send + 'a, - O: QueryFragment + Send + 'a, -{ - type BoxedClause = BoxedLimitOffsetClause<'a, WasmSqlite>; - - fn into_boxed(self) -> Self::BoxedClause { - BoxedLimitOffsetClause { - limit: Some(Box::new(self.limit_clause)), - offset: Some(Box::new(self.offset_clause)), - } - } -} diff --git a/diesel-wasm-sqlite/src/query_builder/mod.rs b/diesel-wasm-sqlite/src/query_builder/mod.rs deleted file mode 100644 index 4d573a758..000000000 --- a/diesel-wasm-sqlite/src/query_builder/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! The SQLite query builder - -use super::backend::WasmSqlite; -use diesel::query_builder::QueryBuilder; -use diesel::result::QueryResult; - -pub(super) mod insert_with_default_sqlite; -mod limit_offset; -// mod query_fragment_impls; -mod returning; - -/// Constructs SQL queries for use with the SQLite backend -#[allow(missing_debug_implementations)] -#[derive(Default)] -pub struct SqliteQueryBuilder { - sql: String, -} - -impl SqliteQueryBuilder { - /// Construct a new query builder with an empty query - pub fn new() -> Self { - SqliteQueryBuilder::default() - } -} - -impl QueryBuilder for SqliteQueryBuilder { - fn push_sql(&mut self, sql: &str) { - self.sql.push_str(sql); - } - - fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> { - self.push_sql("`"); - self.push_sql(&identifier.replace('`', "``")); - self.push_sql("`"); - Ok(()) - } - - fn push_bind_param(&mut self) { - self.push_sql("?"); - } - - fn finish(self) -> String { - self.sql - } -} diff --git a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs deleted file mode 100644 index 129c0bf2c..000000000 --- a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::WasmSqlite; -use diesel::query_builder::into_conflict_clause::OnConflictSelectWrapper; -use diesel::query_builder::where_clause::BoxedWhereClause; -use diesel::query_builder::where_clause::WhereClause; -use diesel::query_builder::AstPass; -use diesel::query_builder::BoxedSelectStatement; -use diesel::query_builder::QueryFragment; -use diesel::query_builder::SelectStatement; -use diesel::result::QueryResult; -use diesel::QueryId; - -// The corresponding impl for`NoWhereClause` is missing because of -// https://www.sqlite.org/lang_UPSERT.html (Parsing Ambiguity) -impl QueryFragment - for OnConflictSelectWrapper, O, LOf, G, H, LC>> -where - SelectStatement, O, LOf, G, H, LC>: QueryFragment, -{ - fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - self.0.walk_ast(out) - } -} - -impl<'a, ST, QS, GB> QueryFragment - for OnConflictSelectWrapper> -where - BoxedSelectStatement<'a, ST, QS, WasmSqlite, GB>: QueryFragment, - QS: QueryFragment, -{ - fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - // https://www.sqlite.org/lang_UPSERT.html (Parsing Ambiguity) - self.0.build_query(pass, |where_clause, mut pass| { - match where_clause { - BoxedWhereClause::None => pass.push_sql(" WHERE 1=1 "), - w => w.walk_ast(pass.reborrow())?, - } - Ok(()) - }) - } -} diff --git a/diesel-wasm-sqlite/src/query_builder/returning.rs b/diesel-wasm-sqlite/src/query_builder/returning.rs deleted file mode 100644 index edc466034..000000000 --- a/diesel-wasm-sqlite/src/query_builder/returning.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::backend::{SqliteReturningClause, WasmSqlite}; -use diesel::query_builder::ReturningClause; -use diesel::query_builder::{AstPass, QueryFragment}; -use diesel::result::QueryResult; - -impl QueryFragment for ReturningClause -where - Expr: QueryFragment, -{ - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - out.skip_from(true); - out.push_sql(" RETURNING "); - self.0.walk_ast(out.reborrow())?; - Ok(()) - } -} diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs deleted file mode 100644 index 79402396c..000000000 --- a/diesel-wasm-sqlite/src/sqlite_fixes.rs +++ /dev/null @@ -1,290 +0,0 @@ -use crate::{connection::WasmSqliteConnection, WasmSqlite}; -use diesel::{ - associations::HasTable, - dsl::{Find, Update}, - expression::{is_aggregate, MixedAggregates, ValidGrouping}, - insertable::{ColumnInsertValue, DefaultableColumnInsertValue, InsertValues}, - prelude::{AsChangeset, Identifiable}, - query_builder::{ - AstPass, InsertOrIgnore, IntoUpdateTarget, NoFromClause, QueryFragment, Replace, - }, - query_dsl::{ - methods::{ExecuteDsl, FindDsl, LoadQuery}, - UpdateAndFetchResults, - }, - AppearsOnTable, Column, Expression, QueryResult, RunQueryDsl, Table, -}; - -/// We re-define Dsl traits to make `insert_with_default_sqlite.rs` generic over all `Connection` -/// implementations with `WasmSqlite` backend`. This works around Rusts orphan rules. -pub mod dsl { - use diesel::{ - backend::Backend, - dsl::Limit, - query_builder::{QueryFragment, QueryId}, - query_dsl::methods::{LimitDsl, LoadQuery}, - Connection, QueryResult, - }; - - pub trait ExecuteDsl< - Conn: Connection, - DB: Backend = ::Backend, - >: Sized - { - fn execute(query: Self, conn: &mut Conn) -> QueryResult; - } - - impl ExecuteDsl for T - where - Conn: Connection, - DB: Backend, - T: QueryFragment + QueryId, - { - fn execute(query: T, conn: &mut Conn) -> QueryResult { - conn.execute_returning_count(&query) - } - } - - pub trait RunQueryDsl: Sized + diesel::query_dsl::RunQueryDsl { - fn execute(self, conn: &mut Conn) -> QueryResult - where - Conn: Connection, - Self: ExecuteDsl, - { - ExecuteDsl::execute(self, conn) - } - - fn load<'query, U>(self, conn: &mut Conn) -> QueryResult> - where - Self: LoadQuery<'query, Conn, U>, - { - >::load(self, conn) - } - fn load_iter<'conn, 'query: 'conn, U, B>( - self, - conn: &'conn mut Conn, - ) -> QueryResult> - where - U: 'conn, - Self: LoadQuery<'query, Conn, U, B> + 'conn, - { - >::load_iter(self, conn) - } - fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult - where - Self: LoadQuery<'query, Conn, U>, - { - >::get_result(self, conn) - } - fn get_results<'query, U>(self, conn: &mut Conn) -> QueryResult> - where - Self: LoadQuery<'query, Conn, U>, - { - >::get_results(self, conn) - } - fn first<'query, U>(self, conn: &mut Conn) -> QueryResult - where - Self: LimitDsl, - Limit: LoadQuery<'query, Conn, U>, - { - >::first(self, conn) - } - } - - impl RunQueryDsl for T where T: diesel::query_dsl::RunQueryDsl {} -} - -impl InsertValues - for DefaultableColumnInsertValue> -where - Col: Column, - Expr: Expression + AppearsOnTable, - Self: QueryFragment, -{ - fn column_names(&self, mut out: AstPass<'_, '_, WasmSqlite>) -> QueryResult<()> { - if let Self::Expression(..) = *self { - out.push_identifier(Col::NAME)?; - } - Ok(()) - } -} - -impl - QueryFragment< - WasmSqlite, - diesel::backend::sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword, - > for DefaultableColumnInsertValue> -where - Expr: QueryFragment, -{ - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - if let Self::Expression(ref inner) = *self { - inner.walk_ast(out.reborrow())?; - } - Ok(()) - } -} - -impl QueryFragment for InsertOrIgnore { - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - out.push_sql("INSERT OR IGNORE"); - Ok(()) - } -} - -impl QueryFragment for Replace { - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - out.push_sql("REPLACE"); - Ok(()) - } -} - -impl<'b, Changes, Output> UpdateAndFetchResults for WasmSqliteConnection -where - Changes: Copy + Identifiable, - Changes: AsChangeset::Table> + IntoUpdateTarget, - Changes::Table: FindDsl, - Update: ExecuteDsl, - Find: LoadQuery<'b, WasmSqliteConnection, Output>, - ::AllColumns: ValidGrouping<()>, - <::AllColumns as ValidGrouping<()>>::IsAggregate: - MixedAggregates, -{ - fn update_and_fetch(&mut self, changeset: Changes) -> QueryResult { - diesel::update(changeset).set(changeset).execute(self)?; - Changes::table().find(changeset.id()).get_result(self) - } -} - -mod parenthesis_wrapper { - use super::*; - - use crate::WasmSqlite; - // use diesel::query_builder::combination_clause::SupportsCombinationClause; - use diesel::query_builder::{ - All, AstPass, Distinct, Except, Intersect, ParenthesisWrapper, QueryFragment, - SupportsCombinationClause, Union, - }; - - impl> QueryFragment for ParenthesisWrapper { - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - // SQLite does not support parenthesis around this clause - // we can emulate this by construct a fake outer - // SELECT * FROM (inner_query) statement - out.push_sql("SELECT * FROM ("); - self.inner.walk_ast(out.reborrow())?; - out.push_sql(")"); - Ok(()) - } - } - - impl SupportsCombinationClause for WasmSqlite {} - impl SupportsCombinationClause for WasmSqlite {} - impl SupportsCombinationClause for WasmSqlite {} - impl SupportsCombinationClause for WasmSqlite {} -} - -// Anything commented here are implementation present in diesel -// but not possible because parts of it exist as private types in diesel. - -/* -impl AsExpression for now { - type Expression = Coerce; - - fn as_expression(self) -> Self::Expression { - Coerce::new(self) - } -} - -impl AsExpression> for now { - type Expression = Coerce>; - - fn as_expression(self) -> Self::Expression { - Coerce::new(self) - } -} -*/ - -/* -use diesel::dsl; -use diesel::expression::grouped::Grouped; -use diesel::expression::AsExpression; -use diesel::operators::*; -use diesel::sql_types::SqlType; - -/// Sqlite specific methods which are present on all expressions. -pub trait SqliteExpressionMethods: Expression + Sized { - /// Creates a Sqlite `IS` expression. - /// - /// The `IS` operator work like = except when one or both of the operands are NULL. - /// In this case, if both operands are NULL, then the `IS` operator evaluates to true. - /// If one operand is NULL and the other is not, then the `IS` operator evaluates to false. - /// It is not possible for an `IS` expression to evaluate to NULL. - /// - /// # Example - /// - /// ```rust - /// # include!("../../doctest_setup.rs"); - /// # - /// # fn main() { - /// # run_test().unwrap(); - /// # } - /// # - /// # fn run_test() -> QueryResult<()> { - /// # use schema::animals::dsl::*; - /// # let connection = &mut establish_connection(); - /// let jack_is_a_dog = animals - /// .select(name) - /// .filter(species.is("dog")) - /// .get_results::>(connection)?; - /// assert_eq!(vec![Some("Jack".to_string())], jack_is_a_dog); - /// # Ok(()) - /// # } - /// ``` - fn is(self, other: T) -> dsl::Is - where - Self::SqlType: SqlType, - T: AsExpression, - { - Grouped(Is::new(self, other.as_expression())) - } - - /// Creates a Sqlite `IS NOT` expression. - /// - /// The `IS NOT` operator work like != except when one or both of the operands are NULL. - /// In this case, if both operands are NULL, then the `IS NOT` operator evaluates to false. - /// If one operand is NULL and the other is not, then the `IS NOT` operator is true. - /// It is not possible for an `IS NOT` expression to evaluate to NULL. - /// - /// # Example - /// - /// ```rust - /// # include!("../../doctest_setup.rs"); - /// # - /// # fn main() { - /// # run_test().unwrap(); - /// # } - /// # - /// # fn run_test() -> QueryResult<()> { - /// # use schema::animals::dsl::*; - /// # let connection = &mut establish_connection(); - /// let jack_is_not_a_spider = animals - /// .select(name) - /// .filter(species.is_not("spider")) - /// .get_results::>(connection)?; - /// assert_eq!(vec![Some("Jack".to_string())], jack_is_not_a_spider); - /// # Ok(()) - /// # } - /// ``` - #[allow(clippy::wrong_self_convention)] // This is named after the sql operator - fn is_not(self, other: T) -> dsl::IsNot - where - Self::SqlType: SqlType, - T: AsExpression, - { - Grouped(IsNot::new(self, other.as_expression())) - } -} - -impl SqliteExpressionMethods for T {} -*/ diff --git a/diesel-wasm-sqlite/src/sqlite_types.rs b/diesel-wasm-sqlite/src/sqlite_types.rs deleted file mode 100644 index 2b4a9d2f1..000000000 --- a/diesel-wasm-sqlite/src/sqlite_types.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::backend::{SqliteType, WasmSqlite}; -use diesel::sql_types::*; - -pub mod to_sql; - -//TODO These Database Types are defined in the wasm file and should be imported. -// this is easier for now because of quirks with converting from JsValue to integer within extern -// "C" declaration. -macro_rules! impl_has_sql_type { - ($type:ty, $sql_type:expr) => { - impl HasSqlType<$type> for WasmSqlite { - fn metadata(_: &mut ()) -> SqliteType { - $sql_type - } - } - }; -} - -impl_has_sql_type!(Bool, SqliteType::Integer); -impl_has_sql_type!(SmallInt, SqliteType::SmallInt); -impl_has_sql_type!(Integer, SqliteType::Integer); -impl_has_sql_type!(BigInt, SqliteType::Long); -impl_has_sql_type!(Float, SqliteType::Float); -impl_has_sql_type!(Double, SqliteType::Double); -impl_has_sql_type!(Numeric, SqliteType::Double); -impl_has_sql_type!(Text, SqliteType::Text); -impl_has_sql_type!(Binary, SqliteType::Binary); -impl_has_sql_type!(Date, SqliteType::Text); -impl_has_sql_type!(Time, SqliteType::Text); -impl_has_sql_type!(Timestamp, SqliteType::Text); diff --git a/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs b/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs deleted file mode 100644 index 74e34bcc3..000000000 --- a/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs +++ /dev/null @@ -1,194 +0,0 @@ -// mod date_and_time; -// mod numeric; - -//TODO: CODE CAN BE SHARED (pretty muhch exactly the same) -use crate::connection::SqliteValue; -use crate::WasmSqlite; -use diesel::deserialize::{self, FromSql}; -use diesel::query_builder::QueryId; -use diesel::serialize::{self, IsNull, Output, ToSql}; -use diesel::sql_types; -use diesel::sql_types::SqlType; - -/// The returned pointer is *only* valid for the lifetime to the argument of -/// `from_sql`. This impl is intended for uses where you want to write a new -/// impl in terms of `String`, but don't want to allocate. -/// -/// FIXME: -/// We have to return a -/// raw pointer instead of a reference with a lifetime due to the structure of -/// `FromSql` because we allocate a string in `read_text` (since SQLite memory is not shared with -/// us). So this function would -/// produce a dangling pointer. -/* -// Not posible until we share mem with sqlite. There's no -// way to avoid an allocation into our host memory until then. - -impl FromSql for *const str { - fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { - tracing::debug!("IN FROM SQL"); - let text = value.read_text(); - let text = text.as_str(); - Ok(text as *const _) - } -} -*/ - -impl FromSql for String { - fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { - Ok(value.read_text()) - } -} - -/* Not Possible until we share mem with SQLite -impl Queryable for *const str { - type Row = Self; - - fn build(row: Self::Row) -> deserialize::Result { - Ok(row) - } -} -*/ - -impl FromSql for Vec { - fn from_sql(bytes: SqliteValue<'_, '_, '_>) -> deserialize::Result { - Ok(bytes.read_blob()) - } -} - -/// The returned pointer is *only* valid for the lifetime to the argument of -/// `from_sql`. This impl is intended for uses where you want to write a new -/// impl in terms of `Vec`, but don't want to allocate. We have to return a -/// raw pointer instead of a reference with a lifetime due to the structure of -/// `FromSql` -/* Not possible until we share mem with SQLite -impl FromSql for *const [u8] { - fn from_sql(bytes: SqliteValue<'_, '_, '_>) -> deserialize::Result { - let bytes = bytes.read_blob(); - let bytes = bytes.as_slice(); - Ok(bytes as *const _) - } -} - -impl Queryable for *const [u8] { - type Row = Self; - - fn build(row: Self::Row) -> deserialize::Result { - Ok(row) - } -} -*/ - -impl FromSql for i16 { - fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { - Ok(value.read_integer() as i16) - } -} - -impl FromSql for i32 { - fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { - Ok(value.read_integer()) - } -} - -impl FromSql for bool { - fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { - Ok(value.read_integer() != 0) - } -} - -impl FromSql for i64 { - fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { - Ok(value.read_long()) - } -} - -impl FromSql for f32 { - fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { - Ok(value.read_double() as f32) - } -} - -impl FromSql for f64 { - fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { - Ok(value.read_double()) - } -} - -impl ToSql for bool { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { - let int_value = if *self { &1 } else { &0 }; - >::to_sql(int_value, out) - } -} - -impl ToSql for str { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { - out.set_value(self); - Ok(IsNull::No) - } -} - -impl ToSql for [u8] { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { - out.set_value(self); - Ok(IsNull::No) - } -} - -impl ToSql for i16 { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { - out.set_value(*self as i32); - Ok(IsNull::No) - } -} - -impl ToSql for i32 { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { - out.set_value(*self); - Ok(IsNull::No) - } -} - -impl ToSql for i64 { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { - out.set_value(*self); - Ok(IsNull::No) - } -} - -impl ToSql for f32 { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { - out.set_value(*self as f64); - Ok(IsNull::No) - } -} - -impl ToSql for f64 { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, WasmSqlite>) -> serialize::Result { - out.set_value(*self); - Ok(IsNull::No) - } -} - -/// The SQLite timestamp with time zone type -/// -/// ### [`ToSql`] impls -/// -/// - [`chrono::NaiveDateTime`] with `feature = "chrono"` -/// - [`chrono::DateTime`] with `feature = "chrono"` -/// - [`time::PrimitiveDateTime`] with `feature = "time"` -/// - [`time::OffsetDateTime`] with `feature = "time"` -/// -/// ### [`FromSql`] impls -/// -/// - [`chrono::NaiveDateTime`] with `feature = "chrono"` -/// - [`chrono::DateTime`] with `feature = "chrono"` -/// - [`time::PrimitiveDateTime`] with `feature = "time"` -/// - [`time::OffsetDateTime`] with `feature = "time"` -/// -/// [`ToSql`]: crate::serialize::ToSql -/// [`FromSql`]: crate::deserialize::FromSql -#[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[diesel(sqlite_type(name = "Text"))] -pub struct Timestamptz; diff --git a/diesel-wasm-sqlite/src/utils.rs b/diesel-wasm-sqlite/src/utils.rs deleted file mode 100644 index 8b1378917..000000000 --- a/diesel-wasm-sqlite/src/utils.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/diesel-wasm-sqlite/tests/common/mod.rs b/diesel-wasm-sqlite/tests/common/mod.rs deleted file mode 100644 index 26d309276..000000000 --- a/diesel-wasm-sqlite/tests/common/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Common utilities/imports amongst WebAssembly tests -use prelude::*; - -use tokio::sync::OnceCell; -use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; - -static INIT: OnceCell<()> = OnceCell::const_new(); - -pub async fn init() { - INIT.get_or_init(|| async { - console::log_1(&"INIT".into()); - tracing_wasm::set_as_global_default(); - console_error_panic_hook::set_once(); - diesel_wasm_sqlite::init_sqlite().await; - }) - .await; -} - -pub async fn connection() -> WasmSqliteConnection { - diesel_wasm_sqlite::init_sqlite().await; - WasmSqliteConnection::establish(":memory:").unwrap() -} - -// re-exports used in tests -#[allow(unused)] -pub mod prelude { - pub(crate) use super::init; - pub(crate) use diesel::{ - connection::{Connection, LoadConnection}, - debug_query, - deserialize::{self, FromSql, FromSqlRow}, - insert_into, - prelude::*, - sql_types::{Integer, Nullable, Text}, - }; - pub(crate) use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; - pub(crate) use diesel_wasm_sqlite::{ - connection::WasmSqliteConnection, WasmSqlite, - }; - pub(crate) use serde::Deserialize; - pub(crate) use wasm_bindgen_test::*; - pub(crate) use web_sys::console; - #[cfg(feature = "unsafe-debug-query")] - pub(crate) use diesel_wasm_sqlite::DebugQueryWrapper; -} diff --git a/diesel-wasm-sqlite/tests/dedicated_web_worker.rs b/diesel-wasm-sqlite/tests/dedicated_web_worker.rs deleted file mode 100755 index 7c904c52a..000000000 --- a/diesel-wasm-sqlite/tests/dedicated_web_worker.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Integration Test Organization in rust is little bit non-standard comapred to normal -//! organization in a library/binary. -//! In order to avoid being compiled as a test, common functions must be defined in -//! `common/mod.rs` -//! -//! Tests are separated into separate files in the module `test`. -#![recursion_limit = "256"] -#![cfg(target_arch = "wasm32")] - -wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - -mod common; - -mod test { - mod row; - mod web; -} diff --git a/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/down.sql b/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/down.sql deleted file mode 100644 index a865c73a8..000000000 --- a/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE books diff --git a/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql b/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql deleted file mode 100644 index dc1583510..000000000 --- a/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE books ( - id INTEGER PRIMARY KEY NOT NULL, - title TEXT NOT NULL, - author TEXT -) diff --git a/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql deleted file mode 100644 index d9a93fe9a..000000000 --- a/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` diff --git a/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql deleted file mode 100644 index 6a2721ecb..000000000 --- a/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TABLE test_table( - -- The inbox_id the update refers to - "id" text NOT NULL, - -- The sequence_id of the update - "id2" bigint NOT NULL, - -- Based on the timestamp given by the server - "timestamp_ns" bigint NOT NULL, - -- Random ID generated by group creator - "payload" BLOB NOT NULL, - -- Compound primary key of the `inbox_id` and `sequence_id` - PRIMARY KEY (id, id2) -); - - -CREATE INDEX idx_test_table_id_id2_asc ON test_table(id, id2 ASC); diff --git a/diesel-wasm-sqlite/tests/test/row.rs b/diesel-wasm-sqlite/tests/test/row.rs deleted file mode 100644 index 588c02e68..000000000 --- a/diesel-wasm-sqlite/tests/test/row.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::common::{connection, prelude::*}; -use diesel_wasm_sqlite::dsl::RunQueryDsl; - -// test copied from diesel -#[wasm_bindgen_test] -async fn fun_with_row_iters() { - diesel_wasm_sqlite::init_sqlite().await; - - diesel::table! { - #[allow(unused_parens)] - users(id) { - id -> Integer, - name -> Text, - } - } - - use diesel::connection::LoadConnection; - use diesel::deserialize::{FromSql, FromSqlRow}; - use diesel::row::{Field, Row}; - use diesel::sql_types; - - let conn: &mut WasmSqliteConnection = &mut connection().await; - - diesel::sql_query("CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);") - .execute(conn) - .unwrap(); - - diesel::insert_into(users::table) - .values(vec![ - (users::id.eq(1), users::name.eq("Sean")), - (users::id.eq(2), users::name.eq("Tess")), - ]) - .execute(conn) - .unwrap(); - - let query = users::table.select((users::id, users::name)); - - let expected = vec![(1, String::from("Sean")), (2, String::from("Tess"))]; - let row_iter = conn.load(query).unwrap(); - for (row, expected) in row_iter.zip(&expected) { - let row = row.expect("Unwrap failed"); - - let deserialized = <(i32, String) as FromSqlRow< - (sql_types::Integer, sql_types::Text), - _, - >>::build_from_row(&row) - .unwrap(); - - assert_eq!(&deserialized, expected); - } - - { - let collected_rows = conn.load(query).unwrap().collect::>(); - - for (row, expected) in collected_rows.iter().zip(&expected) { - let deserialized = row - .as_ref() - .map(|row| { - <(i32, String) as FromSqlRow< - (sql_types::Integer, sql_types::Text), - _, - >>::build_from_row(row).unwrap() - }) - .unwrap(); - - assert_eq!(&deserialized, expected); - } - } - - let mut row_iter = conn.load(query).unwrap(); - - let first_row = row_iter.next().unwrap().unwrap(); - let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); - let first_values = (first_fields.0.value(), first_fields.1.value()); - - assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(first_values); - assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(first_fields); - - let second_row = row_iter.next().unwrap().unwrap(); - let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap()); - let second_values = (second_fields.0.value(), second_fields.1.value()); - - assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(second_values); - assert!(row_iter.next().unwrap().is_err()); - std::mem::drop(second_fields); - - assert!(row_iter.next().is_none()); - - let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); - let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap()); - - let first_values = (first_fields.0.value(), first_fields.1.value()); - let second_values = (second_fields.0.value(), second_fields.1.value()); - - assert_eq!( - >::from_nullable_sql(first_values.0) - .unwrap(), - expected[0].0 - ); - assert_eq!( - >::from_nullable_sql(first_values.1) - .unwrap(), - expected[0].1 - ); - - assert_eq!( - >::from_nullable_sql(second_values.0) - .unwrap(), - expected[1].0 - ); - assert_eq!( - >::from_nullable_sql(second_values.1) - .unwrap(), - expected[1].1 - ); - - let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap()); - let first_values = (first_fields.0.value(), first_fields.1.value()); - - assert_eq!( - >::from_nullable_sql(first_values.0) - .unwrap(), - expected[0].0 - ); - assert_eq!( - >::from_nullable_sql(first_values.1) - .unwrap(), - expected[0].1 - ); -} diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs deleted file mode 100755 index b59fab616..000000000 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ /dev/null @@ -1,332 +0,0 @@ -//! General tests for migrations/diesel ORM/persistant databases -use crate::common::prelude::*; -use diesel_wasm_sqlite::dsl::RunQueryDsl; - -pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/migrations/"); - -mod schema { - diesel::table! { - books { - id -> Integer, - title -> Text, - author -> Nullable, - // published_year -> Timestamp, - } - } - - diesel::table! { - test_table (id, id2) { - id -> Text, - id2 -> BigInt, - timestamp_ns -> BigInt, - payload -> Binary, - } - } -} - -use schema::{books, test_table}; - -#[derive(Deserialize, Insertable, Debug, PartialEq, Clone)] -#[diesel(table_name = books)] -pub struct BookForm { - title: String, - author: Option, - // published_year: NaiveDateTime, -} - -#[derive(Queryable, QueryableByName, Selectable, PartialEq, Debug)] -#[diesel(table_name = books, check_for_backend(diesel_wasm_sqlite::WasmSqlite))] -pub struct StoredBook { - #[diesel(sql_type = Integer)] - id: i32, - #[diesel(sql_type = Text)] - title: String, - #[diesel(sql_type = Nullable)] - author: Option, - // published_year: NaiveDateTime, -} - -async fn establish_connection() -> WasmSqliteConnection { - diesel_wasm_sqlite::init_sqlite().await; - - let rng: u16 = rand::random(); - let result = WasmSqliteConnection::establish(&format!("test-{}", rng)); - let mut conn = result.unwrap(); - tracing::info!("running migrations..."); - conn.run_pending_migrations(MIGRATIONS).unwrap(); - conn -} - -fn insert_books(conn: &mut WasmSqliteConnection, new_books: Vec) -> QueryResult { - use schema::books::dsl::*; - let query = insert_into(books).values(new_books); - // let sql = DebugQueryWrapper::<_, WasmSqlite>::new(&query).to_string(); - // tracing::info!("QUERY = {}", sql); - let rows_changed = query.execute(conn)?; - Ok(rows_changed) -} - -/* -#[wasm_bindgen_test] -fn examine_sql_from_insert_default_values() { - use schema::books::dsl::*; - - let query = insert_into(books).default_values(); - let sql = "INSERT INTO `books` DEFAULT VALUES -- binds: []"; - assert_eq!(sql, debug_query::(&query).to_string()); - console::log_1(&debug_query::(&query).to_string().into()); -} -*/ - -#[wasm_bindgen_test] -async fn test_orm_insert() { - init().await; - let mut conn = establish_connection().await; - let new_books = vec![ - BookForm { - title: "Game of Thrones".into(), - author: Some("George R.R".into()), - // published_year: NaiveDate::from_ymd_opt(2015, 5, 3).unwrap(), - }, - BookForm { - title: "The Hobbit".into(), - author: Some("J.R.R. Tolkien".into()), - // published_year: NaiveDate::from_ymd_opt(1937, 9, 21).unwrap(), - }, - BookForm { - title: "To Kill a Mockingbird".into(), - author: Some("Harper Lee".into()), - // published_year: NaiveDate::from_ymd_opt(1960, 7, 11).unwrap(), - }, - BookForm { - title: "1984".into(), - author: Some("George Orwell".into()), - // published_year: NaiveDate::from_ymd_opt(1949, 6, 8).unwrap(), - }, - BookForm { - title: "Pride and Prejudice".into(), - author: Some("Jane Austen".into()), - // published_year: NaiveDate::from_ymd_opt(1813, 1, 28).unwrap(), - }, - BookForm { - title: "Moby-Dick".into(), - author: Some("Herman Melville".into()), - // published_year: NaiveDate::from_ymd_opt(1851, 10, 18).unwrap(), - }, - ]; - let rows_changed = insert_books(&mut conn, new_books).unwrap(); - assert_eq!(rows_changed, 6); - tracing::info!("{} rows changed", rows_changed); - console::log_1(&"Showing Users".into()); - let title = schema::books::table - .select(schema::books::title) - .filter(schema::books::id.eq(2)) - .first::(&mut conn) - .unwrap(); - assert_eq!(title, "The Hobbit"); - - let author = schema::books::table - .select(schema::books::author) - .filter(schema::books::id.eq(1)) - .first::>(&mut conn) - .unwrap(); - assert_eq!(author, Some("George R.R".into())); - - let id = schema::books::table - .select(schema::books::id) - .filter(schema::books::id.eq(1)) - .first::(&mut conn) - .unwrap(); - assert_eq!(id, 1); - - let loaded_books = schema::books::dsl::books - .select(StoredBook::as_select()) - .limit(5) - .load(&mut conn); - assert_eq!( - loaded_books.unwrap(), - vec![ - StoredBook { - id: 1, - title: "Game of Thrones".into(), - author: Some("George R.R".into()), - }, - StoredBook { - id: 2, - title: "The Hobbit".into(), - author: Some("J.R.R. Tolkien".into()), - }, - StoredBook { - id: 3, - title: "To Kill a Mockingbird".into(), - author: Some("Harper Lee".into()), - }, - StoredBook { - id: 4, - title: "1984".into(), - author: Some("George Orwell".into()), - }, - StoredBook { - id: 5, - title: "Pride and Prejudice".into(), - author: Some("Jane Austen".into()), - }, - ] - ) -} - -/// StoredIdentityUpdate holds a serialized IdentityUpdate record -#[derive(Insertable, Identifiable, Queryable, Selectable, Debug, Clone, PartialEq, Eq)] -#[diesel(table_name = test_table)] -#[diesel(primary_key(id, id2))] -pub struct Item { - pub id: String, - pub id2: i64, - pub timestamp_ns: i64, - pub payload: Vec, -} - -fn insert_or_ignore(updates: &[Item], conn: &mut WasmSqliteConnection) { - use schema::test_table::dsl::*; - - diesel::insert_or_ignore_into(test_table) - .values(updates) - .execute(conn) - .unwrap(); -} - -#[wasm_bindgen_test] -async fn can_insert_or_ignore() { - init().await; - let mut conn = establish_connection().await; - let updates = vec![ - Item { - id: "test".into(), - id2: 13, - timestamp_ns: 1231232, - payload: b"testing 1".to_vec(), - }, - Item { - id: "test2".into(), - id2: 14, - timestamp_ns: 1201222, - payload: b"testing 2".to_vec(), - }, - ]; - insert_or_ignore(&updates, &mut conn); -} - -#[wasm_bindgen_test] -async fn can_retrieve_blob() { - init().await; - let mut conn = establish_connection().await; - let updates = vec![ - Item { - id: "test".into(), - id2: 13, - timestamp_ns: 1231232, - payload: b"testing 1".to_vec(), - }, - Item { - id: "test2".into(), - id2: 14, - timestamp_ns: 1201222, - payload: b"testing 2".to_vec(), - }, - ]; - insert_or_ignore(&updates, &mut conn); - - let res = schema::test_table::dsl::test_table - .select(Item::as_select()) - .load(&mut conn) - .unwrap(); - - assert_eq!(res[0].payload, b"testing 1"); - assert_eq!(res[1].payload, b"testing 2"); - -} - -#[wasm_bindgen_test] -async fn serializing() { - init().await; - let mut conn = establish_connection().await; - let new_books = vec![BookForm { - title: "Game of Thrones".into(), - author: Some("George R.R".into()), - }]; - let rows_changed = insert_books(&mut conn, new_books).unwrap(); - assert_eq!(rows_changed, 1); - - let serialized = conn.serialize(); - - let loaded_books = schema::books::dsl::books - .select(StoredBook::as_select()) - .load(&mut conn); - assert_eq!(loaded_books.unwrap().len(), 1); - - // delete all the books - diesel::delete(schema::books::table) - .execute(&mut conn) - .unwrap(); - - let loaded_books = schema::books::dsl::books - .select(StoredBook::as_select()) - .load(&mut conn); - assert_eq!(loaded_books.unwrap().len(), 0); - - let result = conn.deserialize(&serialized.data); - assert_eq!(result, 0); - - let loaded_books = schema::books::dsl::books - .select(StoredBook::as_select()) - .load(&mut conn); - assert_eq!( - loaded_books.unwrap(), - vec![StoredBook { - id: 1, - title: "Game of Thrones".into(), - author: Some("George R.R".into()), - },] - ); -} - -#[wasm_bindgen_test] -async fn can_find() { - use schema::{books::dsl, self}; - - init().await; - let mut conn = establish_connection().await; - let new_books = vec![ - BookForm { - title: "Game of Thrones".into(), - author: Some("George R.R".into()), - }, - BookForm { - title: "1984".into(), - author: Some("George Orwell".into()), - } - ]; - - let changed = insert_books(&mut conn, new_books).unwrap(); - tracing::info!("{changed} rows changed"); - - let res: Option = dsl::books.find(1).first(&mut conn).optional().unwrap(); - tracing::debug!("res: {:?}", res); - tracing::debug!("FIND RES: {:?}", res); - - let res: Vec = diesel::sql_query("SELECT * FROM books where (id = 1)") - .load::(&mut conn).unwrap(); - tracing::debug!("SQL_QUERY RES: {:?}", res); -/* - assert_eq!(res, vec![ - StoredBook { id: 0, title: "Game of Thrones".into(), author: Some("George R.R".into()) } - ]); -*/ - let stored_books = schema::books::dsl::books - .select(StoredBook::as_select()) - .load(&mut conn); - tracing::debug!("Books: {:?}", stored_books); - - let first: Option = dsl::books.first(&mut conn).optional().unwrap(); - tracing::debug!("FIRST BOOK {:?}", first) -} diff --git a/diesel-wasm-sqlite/yarn.lock b/diesel-wasm-sqlite/yarn.lock deleted file mode 100644 index 89fcaa79a..000000000 --- a/diesel-wasm-sqlite/yarn.lock +++ /dev/null @@ -1,1600 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 8 - cacheKey: 10 - -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" - dependencies: - string-width: "npm:^5.1.2" - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: "npm:^7.0.1" - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: "npm:^8.1.0" - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 10/e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 - languageName: node - linkType: hard - -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": "npm:2.0.5" - run-parallel: "npm:^1.1.9" - checksum: 10/6ab2a9b8a1d67b067922c36f259e3b3dfd6b97b219c540877a4944549a4d49ea5ceba5663905ab5289682f1f3c15ff441d02f0447f620a42e1cb5e1937174d4b - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 10/012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": "npm:2.1.5" - fastq: "npm:^1.6.0" - checksum: 10/40033e33e96e97d77fba5a238e4bba4487b8284678906a9f616b5579ddaf868a18874c0054a75402c9fbaaa033a25ceae093af58c9c30278e35c23c9479e79b0 - languageName: node - linkType: hard - -"@npmcli/agent@npm:^2.0.0": - version: 2.2.2 - resolution: "@npmcli/agent@npm:2.2.2" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^10.0.1" - socks-proxy-agent: "npm:^8.0.3" - checksum: 10/96fc0036b101bae5032dc2a4cd832efb815ce9b33f9ee2f29909ee49d96a0026b3565f73c507a69eb8603f5cb32e0ae45a70cab1e2655990a4e06ae99f7f572a - languageName: node - linkType: hard - -"@npmcli/fs@npm:^3.1.0": - version: 3.1.1 - resolution: "@npmcli/fs@npm:3.1.1" - dependencies: - semver: "npm:^7.3.5" - checksum: 10/1e0e04087049b24b38bc0b30d87a9388ee3ca1d3fdfc347c2f77d84fcfe6a51f250bc57ba2c1f614d7e4285c6c62bf8c769bc19aa0949ea39e5b043ee023b0bd - languageName: node - linkType: hard - -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 10/115e8ceeec6bc69dff2048b35c0ab4f8bbee12d8bb6c1f4af758604586d802b6e669dcb02dda61d078de42c2b4ddce41b3d9e726d7daa6b4b850f4adbf7333ff - languageName: node - linkType: hard - -"@rollup/plugin-node-resolve@npm:^15.2.3": - version: 15.2.3 - resolution: "@rollup/plugin-node-resolve@npm:15.2.3" - dependencies: - "@rollup/pluginutils": "npm:^5.0.1" - "@types/resolve": "npm:1.20.2" - deepmerge: "npm:^4.2.2" - is-builtin-module: "npm:^3.2.1" - is-module: "npm:^1.0.0" - resolve: "npm:^1.22.1" - peerDependencies: - rollup: ^2.78.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - checksum: 10/d36a6792fbe9d8673d3a7c7dc88920be669ac54fba02ac0093d3c00fc9463fce2e87da1906a2651016742709c3d202b367fb49a62acd0d98f18409343f27b8b4 - languageName: node - linkType: hard - -"@rollup/pluginutils@npm:^5.0.1": - version: 5.1.0 - resolution: "@rollup/pluginutils@npm:5.1.0" - dependencies: - "@types/estree": "npm:^1.0.0" - estree-walker: "npm:^2.0.2" - picomatch: "npm:^2.3.1" - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - checksum: 10/abb15eaec5b36f159ec351b48578401bedcefdfa371d24a914cfdbb1e27d0ebfbf895299ec18ccc343d247e71f2502cba21202bc1362d7ef27d5ded699e5c2b2 - languageName: node - linkType: hard - -"@rollup/rollup-android-arm-eabi@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.21.0" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@rollup/rollup-android-arm64@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-android-arm64@npm:4.21.0" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-darwin-arm64@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.21.0" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-darwin-x64@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.21.0" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm-gnueabihf@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.21.0" - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm-musleabihf@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.21.0" - conditions: os=linux & cpu=arm & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm64-gnu@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.21.0" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm64-musl@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.21.0" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.0" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-riscv64-gnu@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.21.0" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-s390x-gnu@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.21.0" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-x64-gnu@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.21.0" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-x64-musl@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.21.0" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-win32-arm64-msvc@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.21.0" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-win32-ia32-msvc@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.21.0" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@rollup/rollup-win32-x64-msvc@npm:4.21.0": - version: 4.21.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.21.0" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@sqlite.org/sqlite-wasm@npm:latest": - version: 3.46.1-build1 - resolution: "@sqlite.org/sqlite-wasm@npm:3.46.1-build1" - bin: - sqlite-wasm: bin/index.js - checksum: 10/cbb6dda0570a73f6614e53a8d46714fbe4e2a935d6668fd19e6dcba23569b4e07b90bc598fddc03a45677a1b35be9415517871c274da78c0ad22f8efe2e6bf14 - languageName: node - linkType: hard - -"@types/estree@npm:1.0.5, @types/estree@npm:^1.0.0": - version: 1.0.5 - resolution: "@types/estree@npm:1.0.5" - checksum: 10/7de6d928dd4010b0e20c6919e1a6c27b61f8d4567befa89252055fad503d587ecb9a1e3eab1b1901f923964d7019796db810b7fd6430acb26c32866d126fd408 - languageName: node - linkType: hard - -"@types/fs-extra@npm:^8.0.1": - version: 8.1.5 - resolution: "@types/fs-extra@npm:8.1.5" - dependencies: - "@types/node": "npm:*" - checksum: 10/565d9e55cd05064b3ab272b8748ed512b8fa5cddc23fd32b0d5f147f9ea3a45981577c4478b5060cae7b3d914c508bd2ea97eb84d9c1fa6f967982c892e4ab26 - languageName: node - linkType: hard - -"@types/glob@npm:^7.1.1": - version: 7.2.0 - resolution: "@types/glob@npm:7.2.0" - dependencies: - "@types/minimatch": "npm:*" - "@types/node": "npm:*" - checksum: 10/6ae717fedfdfdad25f3d5a568323926c64f52ef35897bcac8aca8e19bc50c0bd84630bbd063e5d52078b2137d8e7d3c26eabebd1a2f03ff350fff8a91e79fc19 - languageName: node - linkType: hard - -"@types/minimatch@npm:*": - version: 5.1.2 - resolution: "@types/minimatch@npm:5.1.2" - checksum: 10/94db5060d20df2b80d77b74dd384df3115f01889b5b6c40fa2dfa27cfc03a68fb0ff7c1f2a0366070263eb2e9d6bfd8c87111d4bc3ae93c3f291297c1bf56c85 - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 22.4.1 - resolution: "@types/node@npm:22.4.1" - dependencies: - undici-types: "npm:~6.19.2" - checksum: 10/cce9221aea24688bccc3d7c25afd26d95c1bdab73a32ee5c43bb456e070116abf6ba537a9ff19c728bc06fe054e69a2c7ec8e5d818e34a3bf9567eae2cb20059 - languageName: node - linkType: hard - -"@types/resolve@npm:1.20.2": - version: 1.20.2 - resolution: "@types/resolve@npm:1.20.2" - checksum: 10/1bff0d3875e7e1557b6c030c465beca9bf3b1173ebc6937cac547654b0af3bb3ff0f16470e9c4d7c5dc308ad9ac8627c38dbff24ef698b66673ff5bd4ead7f7e - languageName: node - linkType: hard - -"abbrev@npm:^2.0.0": - version: 2.0.0 - resolution: "abbrev@npm:2.0.0" - checksum: 10/ca0a54e35bea4ece0ecb68a47b312e1a9a6f772408d5bcb9051230aaa94b0460671c5b5c9cb3240eb5b7bc94c52476550eb221f65a0bbd0145bdc9f3113a6707 - languageName: node - linkType: hard - -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": - version: 7.1.1 - resolution: "agent-base@npm:7.1.1" - dependencies: - debug: "npm:^4.3.4" - checksum: 10/c478fec8f79953f118704d007a38f2a185458853f5c45579b9669372bd0e12602e88dc2ad0233077831504f7cd6fcc8251c383375bba5eaaf563b102938bda26 - languageName: node - linkType: hard - -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: - clean-stack: "npm:^2.0.0" - indent-string: "npm:^4.0.0" - checksum: 10/1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 10/2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b - languageName: node - linkType: hard - -"ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 10/1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 - 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: 10/b4494dfbfc7e4591b4711a396bd27e540f8153914123dccb4cdbbcb514015ada63a3809f362b9d8d4f6b17a706f1d7bea3c6f974b15fa5ae76b5b502070889ff - languageName: node - linkType: hard - -"ansi-styles@npm:^6.1.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: 10/70fdf883b704d17a5dfc9cde206e698c16bcd74e7f196ab821511651aee4f9f76c9514bdfa6ca3a27b5e49138b89cb222a28caf3afe4567570139577f991df32 - languageName: node - linkType: hard - -"array-union@npm:^2.1.0": - version: 2.1.0 - resolution: "array-union@npm:2.1.0" - checksum: 10/5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10/9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" - dependencies: - balanced-match: "npm:^1.0.0" - checksum: 10/a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 - languageName: node - linkType: hard - -"braces@npm:^3.0.3": - version: 3.0.3 - resolution: "braces@npm:3.0.3" - dependencies: - fill-range: "npm:^7.1.1" - checksum: 10/fad11a0d4697a27162840b02b1fad249c1683cbc510cd5bf1a471f2f8085c046d41094308c577a50a03a579dd99d5a6b3724c4b5e8b14df2c4443844cfcda2c6 - languageName: node - linkType: hard - -"builtin-modules@npm:^3.3.0": - version: 3.3.0 - resolution: "builtin-modules@npm:3.3.0" - checksum: 10/62e063ab40c0c1efccbfa9ffa31873e4f9d57408cb396a2649981a0ecbce56aabc93c28feaccbc5658c95aab2703ad1d11980e62ec2e5e72637404e1eb60f39e - languageName: node - linkType: hard - -"cacache@npm:^18.0.0": - version: 18.0.4 - resolution: "cacache@npm:18.0.4" - dependencies: - "@npmcli/fs": "npm:^3.1.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^10.2.2" - lru-cache: "npm:^10.0.1" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^4.0.0" - ssri: "npm:^10.0.0" - tar: "npm:^6.1.11" - unique-filename: "npm:^3.0.0" - checksum: 10/ca2f7b2d3003f84d362da9580b5561058ccaecd46cba661cbcff0375c90734b610520d46b472a339fd032d91597ad6ed12dde8af81571197f3c9772b5d35b104 - languageName: node - linkType: hard - -"chownr@npm:^2.0.0": - version: 2.0.0 - resolution: "chownr@npm:2.0.0" - checksum: 10/c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f - languageName: node - linkType: hard - -"clean-stack@npm:^2.0.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 10/2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 - 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: 10/fa00c91b4332b294de06b443923246bccebe9fab1b253f7fe1772d37b06a2269b4039a85e309abe1fe11b267b11c08d1d0473fda3badd6167f57313af2887a64 - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: 10/b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - -"colorette@npm:^1.1.0": - version: 1.4.0 - resolution: "colorette@npm:1.4.0" - checksum: 10/c8d6c8c3ef5a99acfc3dd9a68f48019f1479ec347551387e4a1762e40f69e98ce19d4dc321ffb4919d1f28a7bdc90c39d4e9a901f4c474fd2124ad93a00c0454 - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10/9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.0": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10/e1a13869d2f57d974de0d9ef7acbf69dc6937db20b918525a01dacb5032129bd552d290d886d981e99f1b624cb03657084cc87bd40f115c07ecf376821c729ce - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.3.4": - version: 4.3.6 - resolution: "debug@npm:4.3.6" - dependencies: - ms: "npm:2.1.2" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10/d3adb9af7d57a9e809a68f404490cf776122acca16e6359a2702c0f462e510e91f9765c07f707b8ab0d91e03bad57328f3256f5082631cefb5393d0394d50fb7 - languageName: node - linkType: hard - -"deepmerge@npm:^4.2.2": - version: 4.3.1 - resolution: "deepmerge@npm:4.3.1" - checksum: 10/058d9e1b0ff1a154468bf3837aea436abcfea1ba1d165ddaaf48ca93765fdd01a30d33c36173da8fbbed951dd0a267602bc782fe288b0fc4b7e1e7091afc4529 - languageName: node - linkType: hard - -"diesel-wasm-sqlite@workspace:.": - version: 0.0.0-use.local - resolution: "diesel-wasm-sqlite@workspace:." - dependencies: - "@rollup/plugin-node-resolve": "npm:^15.2.3" - "@sqlite.org/sqlite-wasm": "npm:latest" - rollup: "npm:^4.19.0" - rollup-plugin-copy: "npm:^3.5.0" - languageName: unknown - linkType: soft - -"dir-glob@npm:^3.0.1": - version: 3.0.1 - resolution: "dir-glob@npm:3.0.1" - dependencies: - path-type: "npm:^4.0.0" - checksum: 10/fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 - languageName: node - linkType: hard - -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 10/9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: 10/c72d67a6821be15ec11997877c437491c313d924306b8da5d87d2a2bcc2cec9903cb5b04ee1a088460501d8e5b44f10df82fdc93c444101a7610b80c8b6938e1 - languageName: node - linkType: hard - -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 10/915acf859cea7131dac1b2b5c9c8e35c4849e325a1d114c30adb8cd615970f6dca0e27f64f3a4949d7d6ed86ecd79a1c5c63f02e697513cddd7b5835c90948b8 - languageName: node - linkType: hard - -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: "npm:^0.6.2" - checksum: 10/bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 10/65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e - languageName: node - linkType: hard - -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 10/1d20d825cdcce8d811bfbe86340f4755c02655a7feb2f13f8c880566d9d72a3f6c92c192a6867632e490d6da67b678271f46e01044996a6443e870331100dfdd - languageName: node - linkType: hard - -"estree-walker@npm:^2.0.2": - version: 2.0.2 - resolution: "estree-walker@npm:2.0.2" - checksum: 10/b02109c5d46bc2ed47de4990eef770f7457b1159a229f0999a09224d2b85ffeed2d7679cffcff90aeb4448e94b0168feb5265b209cdec29aad50a3d6e93d21e2 - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.1 - resolution: "exponential-backoff@npm:3.1.1" - checksum: 10/2d9bbb6473de7051f96790d5f9a678f32e60ed0aa70741dc7fdc96fec8d631124ec3374ac144387604f05afff9500f31a1d45bd9eee4cdc2e4f9ad2d9b9d5dbd - languageName: node - linkType: hard - -"fast-glob@npm:^3.0.3": - version: 3.3.2 - resolution: "fast-glob@npm:3.3.2" - dependencies: - "@nodelib/fs.stat": "npm:^2.0.2" - "@nodelib/fs.walk": "npm:^1.2.3" - glob-parent: "npm:^5.1.2" - merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.4" - checksum: 10/222512e9315a0efca1276af9adb2127f02105d7288fa746145bf45e2716383fb79eb983c89601a72a399a56b7c18d38ce70457c5466218c5f13fad957cee16df - languageName: node - linkType: hard - -"fastq@npm:^1.6.0": - version: 1.17.1 - resolution: "fastq@npm:1.17.1" - dependencies: - reusify: "npm:^1.0.4" - checksum: 10/a443180068b527dd7b3a63dc7f2a47ceca2f3e97b9c00a1efe5538757e6cc4056a3526df94308075d7727561baf09ebaa5b67da8dcbddb913a021c5ae69d1f69 - languageName: node - linkType: hard - -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10/a7095cb39e5bc32fada2aa7c7249d3f6b01bd1ce461a61b0adabacccabd9198500c6fb1f68a7c851a657e273fce2233ba869638897f3d7ed2e87a2d89b4436ea - languageName: node - linkType: hard - -"foreground-child@npm:^3.1.0": - version: 3.3.0 - resolution: "foreground-child@npm:3.3.0" - dependencies: - cross-spawn: "npm:^7.0.0" - signal-exit: "npm:^4.0.1" - checksum: 10/e3a60480f3a09b12273ce2c5fcb9514d98dd0e528f58656a1b04680225f918d60a2f81f6a368f2f3b937fcee9cfc0cbf16f1ad9a0bc6a3a6e103a84c9a90087e - languageName: node - linkType: hard - -"fs-extra@npm:^8.1.0": - version: 8.1.0 - resolution: "fs-extra@npm:8.1.0" - dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^4.0.0" - universalify: "npm:^0.1.0" - checksum: 10/6fb12449f5349be724a138b4a7b45fe6a317d2972054517f5971959c26fbd17c0e145731a11c7324460262baa33e0a799b183ceace98f7a372c95fbb6f20f5de - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0": - version: 2.1.0 - resolution: "fs-minipass@npm:2.1.0" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/03191781e94bc9a54bd376d3146f90fe8e082627c502185dbf7b9b3032f66b0b142c1115f3b2cc5936575fc1b44845ce903dd4c21bec2a8d69f3bd56f9cee9ec - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/af143246cf6884fe26fa281621d45cfe111d34b30535a475bfa38dafe343dadb466c047a924ffc7d6b7b18265df4110224ce3803806dbb07173bf2087b648d7f - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 10/e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96 - languageName: node - linkType: hard - -"fsevents@npm:~2.3.2": - version: 2.3.3 - resolution: "fsevents@npm:2.3.3" - dependencies: - node-gyp: "npm:latest" - checksum: 10/4c1ade961ded57cdbfbb5cac5106ec17bc8bccd62e16343c569a0ceeca83b9dfef87550b4dc5cbb89642da412b20c5071f304c8c464b80415446e8e155a038c0 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": - version: 2.3.3 - resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" - dependencies: - node-gyp: "npm:latest" - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10/185e20d20f10c8d661d59aac0f3b63b31132d492e1b11fcc2a93cb2c47257ebaee7407c38513efd2b35cafdf972d9beb2ea4593c1e0f3bf8f2744836928d7454 - languageName: node - linkType: hard - -"glob-parent@npm:^5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10/32cd106ce8c0d83731966d31517adb766d02c3812de49c30cfe0675c7c0ae6630c11214c54a5ae67aca882cf738d27fd7768f21aa19118b9245950554be07247 - languageName: node - linkType: hard - -"glob@npm:^10.2.2, glob@npm:^10.3.10": - version: 10.4.5 - resolution: "glob@npm:10.4.5" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^3.1.2" - minimatch: "npm:^9.0.4" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^1.11.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10/698dfe11828b7efd0514cd11e573eaed26b2dff611f0400907281ce3eab0c1e56143ef9b35adc7c77ecc71fba74717b510c7c223d34ca8a98ec81777b293d4ac - languageName: node - linkType: hard - -"glob@npm:^7.1.3": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.1.1" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10/59452a9202c81d4508a43b8af7082ca5c76452b9fcc4a9ab17655822e6ce9b21d4f8fbadabe4fe3faef448294cec249af305e2cd824b7e9aaf689240e5e96a7b - languageName: node - linkType: hard - -"globby@npm:10.0.1": - version: 10.0.1 - resolution: "globby@npm:10.0.1" - dependencies: - "@types/glob": "npm:^7.1.1" - array-union: "npm:^2.1.0" - dir-glob: "npm:^3.0.1" - fast-glob: "npm:^3.0.3" - glob: "npm:^7.1.3" - ignore: "npm:^5.1.1" - merge2: "npm:^1.2.3" - slash: "npm:^3.0.0" - checksum: 10/ea724a820d7d4eafc5aa3882d667a7ef3505b3018652b2658185d58752f122b75d3370086e4d4a7b1bbcdf8c2e700e5709a48db189a930df37005e1b3c86c256 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 - languageName: node - linkType: hard - -"hasown@npm:^2.0.2": - version: 2.0.2 - resolution: "hasown@npm:2.0.2" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10/7898a9c1788b2862cf0f9c345a6bec77ba4a0c0983c7f19d610c382343d4f98fa260686b225dfb1f88393a66679d2ec58ee310c1d6868c081eda7918f32cc70a - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 10/362d5ed66b12ceb9c0a328fb31200b590ab1b02f4a254a697dc796850cc4385603e75f53ec59f768b2dad3bfa1464bd229f7de278d2899a0e3beffc634b6683f - languageName: node - linkType: hard - -"http-proxy-agent@npm:^7.0.0": - version: 7.0.2 - resolution: "http-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10/d062acfa0cb82beeb558f1043c6ba770ea892b5fb7b28654dbc70ea2aeea55226dd34c02a294f6c1ca179a5aa483c4ea641846821b182edbd9cc5d89b54c6848 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": - version: 7.0.5 - resolution: "https-proxy-agent@npm:7.0.5" - dependencies: - agent-base: "npm:^7.0.2" - debug: "npm:4" - checksum: 10/6679d46159ab3f9a5509ee80c3a3fc83fba3a920a5e18d32176c3327852c3c00ad640c0c4210a8fd70ea3c4a6d3a1b375bf01942516e7df80e2646bdc77658ab - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f - languageName: node - linkType: hard - -"ignore@npm:^5.1.1": - version: 5.3.2 - resolution: "ignore@npm:5.3.2" - checksum: 10/cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98 - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10/2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 10/cd3f5cbc9ca2d624c6a1f53f12e6b341659aba0e2d3254ae2b4464aaea8b4294cdb09616abbc59458f980531f2429784ed6a420d48d245bcad0811980c9efae9 - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 - languageName: node - linkType: hard - -"inherits@npm:2": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 - languageName: node - linkType: hard - -"ip-address@npm:^9.0.5": - version: 9.0.5 - resolution: "ip-address@npm:9.0.5" - dependencies: - jsbn: "npm:1.1.0" - sprintf-js: "npm:^1.1.3" - checksum: 10/1ed81e06721af012306329b31f532b5e24e00cb537be18ddc905a84f19fe8f83a09a1699862bf3a1ec4b9dea93c55a3fa5faf8b5ea380431469df540f38b092c - languageName: node - linkType: hard - -"is-builtin-module@npm:^3.2.1": - version: 3.2.1 - resolution: "is-builtin-module@npm:3.2.1" - dependencies: - builtin-modules: "npm:^3.3.0" - checksum: 10/e8f0ffc19a98240bda9c7ada84d846486365af88d14616e737d280d378695c8c448a621dcafc8332dbf0fcd0a17b0763b845400709963fa9151ddffece90ae88 - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0": - version: 2.15.0 - resolution: "is-core-module@npm:2.15.0" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10/70e962543e5d3a97c07cb29144a86792d545a21f28e67da5401d85878a0193d46fbab8d97bc3ca680e2778705dca66e7b6ca840c493497a27ca0e8c5f3ac3d1d - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10/df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 10/44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - -"is-glob@npm:^4.0.1": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10/3ed74f2b0cdf4f401f38edb0442ddfde3092d79d7d35c9919c86641efdbcbb32e45aa3c0f70ce5eecc946896cd5a0f26e4188b9f2b881876f7cb6c505b82da11 - languageName: node - linkType: hard - -"is-lambda@npm:^1.0.1": - version: 1.0.1 - resolution: "is-lambda@npm:1.0.1" - checksum: 10/93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 - languageName: node - linkType: hard - -"is-module@npm:^1.0.0": - version: 1.0.0 - resolution: "is-module@npm:1.0.0" - checksum: 10/8cd5390730c7976fb4e8546dd0b38865ee6f7bacfa08dfbb2cc07219606755f0b01709d9361e01f13009bbbd8099fa2927a8ed665118a6105d66e40f1b838c3f - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10/6a6c3383f68afa1e05b286af866017c78f1226d43ac8cb064e115ff9ed85eb33f5c4f7216c96a71e4dfea289ef52c5da3aef5bbfade8ffe47a0465d70c0c8e86 - languageName: node - linkType: hard - -"is-plain-object@npm:^3.0.0": - version: 3.0.1 - resolution: "is-plain-object@npm:3.0.1" - checksum: 10/d13fe75db350d4ac669595cdfe0242ae87fcecddf2bca858d2dd443a6ed6eb1f69951fac8c2fa85b16106c6b0d7738fea86c2aca2ecee7fd61de15c1574f2cc5 - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10/7c9f715c03aff08f35e98b1fadae1b9267b38f0615d501824f9743f3aab99ef10e303ce7db3f186763a0b70a19de5791ebfc854ff884d5a8c4d92211f642ec92 - languageName: node - linkType: hard - -"isexe@npm:^3.1.1": - version: 3.1.1 - resolution: "isexe@npm:3.1.1" - checksum: 10/7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e - languageName: node - linkType: hard - -"jackspeak@npm:^3.1.2": - version: 3.4.3 - resolution: "jackspeak@npm:3.4.3" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10/96f8786eaab98e4bf5b2a5d6d9588ea46c4d06bbc4f2eb861fdd7b6b182b16f71d8a70e79820f335d52653b16d4843b29dd9cdcf38ae80406756db9199497cf3 - languageName: node - linkType: hard - -"jsbn@npm:1.1.0": - version: 1.1.0 - resolution: "jsbn@npm:1.1.0" - checksum: 10/bebe7ae829bbd586ce8cbe83501dd8cb8c282c8902a8aeeed0a073a89dc37e8103b1244f3c6acd60278bcbfe12d93a3f83c9ac396868a3b3bbc3c5e5e3b648ef - languageName: node - linkType: hard - -"jsonfile@npm:^4.0.0": - version: 4.0.0 - resolution: "jsonfile@npm:4.0.0" - dependencies: - graceful-fs: "npm:^4.1.6" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10/17796f0ab1be8479827d3683433f97ebe0a1c6932c3360fa40348eac36904d69269aab26f8b16da311882d94b42e9208e8b28e490bf926364f3ac9bff134c226 - languageName: node - linkType: hard - -"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": - version: 10.4.3 - resolution: "lru-cache@npm:10.4.3" - checksum: 10/e6e90267360476720fa8e83cc168aa2bf0311f3f2eea20a6ba78b90a885ae72071d9db132f40fda4129c803e7dcec3a6b6a6fbb44ca90b081630b810b5d6a41a - languageName: node - linkType: hard - -"make-fetch-happen@npm:^13.0.0": - version: 13.0.1 - resolution: "make-fetch-happen@npm:13.0.1" - dependencies: - "@npmcli/agent": "npm:^2.0.0" - cacache: "npm:^18.0.0" - http-cache-semantics: "npm:^4.1.1" - is-lambda: "npm:^1.0.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^3.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^0.6.3" - proc-log: "npm:^4.2.0" - promise-retry: "npm:^2.0.1" - ssri: "npm:^10.0.0" - checksum: 10/11bae5ad6ac59b654dbd854f30782f9de052186c429dfce308eda42374528185a100ee40ac9ffdc36a2b6c821ecaba43913e4730a12f06f15e895ea9cb23fa59 - languageName: node - linkType: hard - -"merge2@npm:^1.2.3, merge2@npm:^1.3.0": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 10/7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 - languageName: node - linkType: hard - -"micromatch@npm:^4.0.4": - version: 4.0.7 - resolution: "micromatch@npm:4.0.7" - dependencies: - braces: "npm:^3.0.3" - picomatch: "npm:^2.3.1" - checksum: 10/a11ed1cb67dcbbe9a5fc02c4062cf8bb0157d73bf86956003af8dcfdf9b287f9e15ec0f6d6925ff6b8b5b496202335e497b01de4d95ef6cf06411bc5e5c474a0 - languageName: node - linkType: hard - -"minimatch@npm:^3.1.1": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10/e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 - languageName: node - linkType: hard - -"minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348 - languageName: node - linkType: hard - -"minipass-collect@npm:^2.0.1": - version: 2.0.1 - resolution: "minipass-collect@npm:2.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 - languageName: node - linkType: hard - -"minipass-fetch@npm:^3.0.0": - version: 3.0.5 - resolution: "minipass-fetch@npm:3.0.5" - dependencies: - encoding: "npm:^0.1.13" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^1.0.3" - minizlib: "npm:^2.1.2" - dependenciesMeta: - encoding: - optional: true - checksum: 10/c669948bec1373313aaa8f104b962a3ced9f45c49b26366a4b0ae27ccdfa9c5740d72c8a84d3f8623d7a61c5fc7afdfda44789008c078f61a62441142efc4a97 - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/40982d8d836a52b0f37049a0a7e5d0f089637298e6d9b45df9c115d4f0520682a78258905e5c8b180fb41b593b0a82cc1361d2c74b45f7ada66334f84d1ecfdd - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10/a5c6ef069f70d9a524d3428af39f2b117ff8cd84172e19b754e7264a33df460873e6eb3d6e55758531580970de50ae950c496256bb4ad3691a2974cddff189f0 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass@npm:5.0.0" - checksum: 10/61682162d29f45d3152b78b08bab7fb32ca10899bc5991ffe98afc18c9e9543bd1e3be94f8b8373ba6262497db63607079dc242ea62e43e7b2270837b7347c93 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": - version: 7.1.2 - resolution: "minipass@npm:7.1.2" - checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 - languageName: node - linkType: hard - -"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": - version: 2.1.2 - resolution: "minizlib@npm:2.1.2" - dependencies: - minipass: "npm:^3.0.0" - yallist: "npm:^4.0.0" - checksum: 10/ae0f45436fb51344dcb87938446a32fbebb540d0e191d63b35e1c773d47512e17307bf54aa88326cc6d176594d00e4423563a091f7266c2f9a6872cdc1e234d1 - languageName: node - linkType: hard - -"mkdirp@npm:^1.0.3": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: 10/d71b8dcd4b5af2fe13ecf3bd24070263489404fe216488c5ba7e38ece1f54daf219e72a833a3a2dc404331e870e9f44963a33399589490956bff003a3404d3b2 - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 10/673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f - languageName: node - linkType: hard - -"negotiator@npm:^0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: 10/2723fb822a17ad55c93a588a4bc44d53b22855bf4be5499916ca0cab1e7165409d0b288ba2577d7b029f10ce18cf2ed8e703e5af31c984e1e2304277ef979837 - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 10.2.0 - resolution: "node-gyp@npm:10.2.0" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - glob: "npm:^10.3.10" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^13.0.0" - nopt: "npm:^7.0.0" - proc-log: "npm:^4.1.0" - semver: "npm:^7.3.5" - tar: "npm:^6.2.1" - which: "npm:^4.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10/41773093b1275751dec942b985982fd4e7a69b88cae719b868babcef3880ee6168aaec8dcaa8cd0b9fa7c84873e36cc549c6cac6a124ee65ba4ce1f1cc108cfe - languageName: node - linkType: hard - -"nopt@npm:^7.0.0": - version: 7.2.1 - resolution: "nopt@npm:7.2.1" - dependencies: - abbrev: "npm:^2.0.0" - bin: - nopt: bin/nopt.js - checksum: 10/95a1f6dec8a81cd18cdc2fed93e6f0b4e02cf6bdb4501c848752c6e34f9883d9942f036a5e3b21a699047d8a448562d891e67492df68ec9c373e6198133337ae - languageName: node - linkType: hard - -"once@npm:^1.3.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: "npm:1" - checksum: 10/cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: "npm:^3.0.0" - checksum: 10/7ba4a2b1e24c05e1fc14bbaea0fc6d85cf005ae7e9c9425d4575550f37e2e584b1af97bcde78eacd7559208f20995988d52881334db16cf77bc1bcf68e48ed7c - languageName: node - linkType: hard - -"package-json-from-dist@npm:^1.0.0": - version: 1.0.0 - resolution: "package-json-from-dist@npm:1.0.0" - checksum: 10/ac706ec856a5a03f5261e4e48fa974f24feb044d51f84f8332e2af0af04fbdbdd5bbbfb9cbbe354190409bc8307c83a9e38c6672c3c8855f709afb0006a009ea - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 10/060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 - languageName: node - linkType: hard - -"path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 10/55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 - languageName: node - linkType: hard - -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 10/49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a - languageName: node - linkType: hard - -"path-scurry@npm:^1.11.1": - version: 1.11.1 - resolution: "path-scurry@npm:1.11.1" - dependencies: - lru-cache: "npm:^10.2.0" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10/5e8845c159261adda6f09814d7725683257fcc85a18f329880ab4d7cc1d12830967eae5d5894e453f341710d5484b8fdbbd4d75181b4d6e1eb2f4dc7aeadc434 - languageName: node - linkType: hard - -"path-type@npm:^4.0.0": - version: 4.0.0 - resolution: "path-type@npm:4.0.0" - checksum: 10/5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 - languageName: node - linkType: hard - -"picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc - languageName: node - linkType: hard - -"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": - version: 4.2.0 - resolution: "proc-log@npm:4.2.0" - checksum: 10/4e1394491b717f6c1ade15c570ecd4c2b681698474d3ae2d303c1e4b6ab9455bd5a81566211e82890d5a5ae9859718cc6954d5150bb18b09b72ecb297beae90a - languageName: node - linkType: hard - -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: "npm:^2.0.2" - retry: "npm:^0.12.0" - checksum: 10/96e1a82453c6c96eef53a37a1d6134c9f2482f94068f98a59145d0986ca4e497bf110a410adf73857e588165eab3899f0ebcf7b3890c1b3ce802abc0d65967d4 - languageName: node - linkType: hard - -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: 10/72900df0616e473e824202113c3df6abae59150dfb73ed13273503127235320e9c8ca4aaaaccfd58cf417c6ca92a6e68ee9a5c3182886ae949a768639b388a7b - languageName: node - linkType: hard - -"resolve@npm:^1.22.1": - version: 1.22.8 - resolution: "resolve@npm:1.22.8" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/c473506ee01eb45cbcfefb68652ae5759e092e6b0fb64547feadf9736a6394f258fbc6f88e00c5ca36d5477fbb65388b272432a3600fa223062e54333c156753 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.22.1#optional!builtin": - version: 1.22.8 - resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/f345cd37f56a2c0275e3fe062517c650bb673815d885e7507566df589375d165bbbf4bdb6aa95600a9bc55f4744b81f452b5a63f95b9f10a72787dba3c90890a - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 - languageName: node - linkType: hard - -"reusify@npm:^1.0.4": - version: 1.0.4 - resolution: "reusify@npm:1.0.4" - checksum: 10/14222c9e1d3f9ae01480c50d96057228a8524706db79cdeb5a2ce5bb7070dd9f409a6f84a02cbef8cdc80d39aef86f2dd03d155188a1300c599b05437dcd2ffb - languageName: node - linkType: hard - -"rollup-plugin-copy@npm:^3.5.0": - version: 3.5.0 - resolution: "rollup-plugin-copy@npm:3.5.0" - dependencies: - "@types/fs-extra": "npm:^8.0.1" - colorette: "npm:^1.1.0" - fs-extra: "npm:^8.1.0" - globby: "npm:10.0.1" - is-plain-object: "npm:^3.0.0" - checksum: 10/706ba6bd2052b95d1037f12963ff4b50749730f18aefad10544f9574aff7c035c88c5dd9ae1f0c0408cf09862e595a0ea4d68e13c2717addaea2bda3ade0d0e0 - languageName: node - linkType: hard - -"rollup@npm:^4.19.0": - version: 4.21.0 - resolution: "rollup@npm:4.21.0" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.21.0" - "@rollup/rollup-android-arm64": "npm:4.21.0" - "@rollup/rollup-darwin-arm64": "npm:4.21.0" - "@rollup/rollup-darwin-x64": "npm:4.21.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.21.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.21.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.21.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.21.0" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.21.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.21.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.21.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.21.0" - "@rollup/rollup-linux-x64-musl": "npm:4.21.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.21.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.21.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.21.0" - "@types/estree": "npm:1.0.5" - fsevents: "npm:~2.3.2" - dependenciesMeta: - "@rollup/rollup-android-arm-eabi": - optional: true - "@rollup/rollup-android-arm64": - optional: true - "@rollup/rollup-darwin-arm64": - optional: true - "@rollup/rollup-darwin-x64": - optional: true - "@rollup/rollup-linux-arm-gnueabihf": - optional: true - "@rollup/rollup-linux-arm-musleabihf": - optional: true - "@rollup/rollup-linux-arm64-gnu": - optional: true - "@rollup/rollup-linux-arm64-musl": - optional: true - "@rollup/rollup-linux-powerpc64le-gnu": - optional: true - "@rollup/rollup-linux-riscv64-gnu": - optional: true - "@rollup/rollup-linux-s390x-gnu": - optional: true - "@rollup/rollup-linux-x64-gnu": - optional: true - "@rollup/rollup-linux-x64-musl": - optional: true - "@rollup/rollup-win32-arm64-msvc": - optional: true - "@rollup/rollup-win32-ia32-msvc": - optional: true - "@rollup/rollup-win32-x64-msvc": - optional: true - fsevents: - optional: true - bin: - rollup: dist/bin/rollup - checksum: 10/27ac47d5049719249d2a44982e31f01423158a3625cabff2f2362219aee64bdc14c32572b669169c22c324c3a965044ce8f06e27eee00fd8802861cd13697f87 - languageName: node - linkType: hard - -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: "npm:^1.2.2" - checksum: 10/cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: 10/7eaf7a0cf37cc27b42fb3ef6a9b1df6e93a1c6d98c6c6702b02fe262d5fcbd89db63320793b99b21cb5348097d0a53de81bd5f4e8b86e20cc9412e3f1cfb4e83 - languageName: node - linkType: hard - -"semver@npm:^7.3.5": - version: 7.6.3 - resolution: "semver@npm:7.6.3" - bin: - semver: bin/semver.js - checksum: 10/36b1fbe1a2b6f873559cd57b238f1094a053dbfd997ceeb8757d79d1d2089c56d1321b9f1069ce263dc64cfa922fa1d2ad566b39426fe1ac6c723c1487589e10 - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10/6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10/1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 - languageName: node - linkType: hard - -"signal-exit@npm:^4.0.1": - version: 4.1.0 - resolution: "signal-exit@npm:4.1.0" - checksum: 10/c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f - languageName: node - linkType: hard - -"slash@npm:^3.0.0": - version: 3.0.0 - resolution: "slash@npm:3.0.0" - checksum: 10/94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: 10/927484aa0b1640fd9473cee3e0a0bcad6fce93fd7bbc18bac9ad0c33686f5d2e2c422fba24b5899c184524af01e11dd2bd051c2bf2b07e47aff8ca72cbfc60d2 - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^8.0.3": - version: 8.0.4 - resolution: "socks-proxy-agent@npm:8.0.4" - dependencies: - agent-base: "npm:^7.1.1" - debug: "npm:^4.3.4" - socks: "npm:^2.8.3" - checksum: 10/c8e7c2b398338b49a0a0f4d2bae5c0602aeeca6b478b99415927b6c5db349ca258448f2c87c6958ebf83eea17d42cbc5d1af0bfecb276cac10b9658b0f07f7d7 - languageName: node - linkType: hard - -"socks@npm:^2.8.3": - version: 2.8.3 - resolution: "socks@npm:2.8.3" - dependencies: - ip-address: "npm:^9.0.5" - smart-buffer: "npm:^4.2.0" - checksum: 10/ffcb622c22481dfcd7589aae71fbfd71ca34334064d181df64bf8b7feaeee19706aba4cffd1de35cc7bbaeeaa0af96be2d7f40fcbc7bc0ab69533a7ae9ffc4fb - languageName: node - linkType: hard - -"sprintf-js@npm:^1.1.3": - version: 1.1.3 - resolution: "sprintf-js@npm:1.1.3" - checksum: 10/e7587128c423f7e43cc625fe2f87e6affdf5ca51c1cc468e910d8aaca46bb44a7fbcfa552f787b1d3987f7043aeb4527d1b99559e6621e01b42b3f45e5a24cbb - languageName: node - linkType: hard - -"ssri@npm:^10.0.0": - version: 10.0.6 - resolution: "ssri@npm:10.0.6" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/f92c1b3cc9bfd0a925417412d07d999935917bc87049f43ebec41074661d64cf720315661844106a77da9f8204b6d55ae29f9514e673083cae39464343af2a8b - languageName: node - linkType: hard - -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: "npm:^8.0.0" - is-fullwidth-code-point: "npm:^3.0.0" - strip-ansi: "npm:^6.0.1" - checksum: 10/e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb - languageName: node - linkType: hard - -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: "npm:^0.2.0" - emoji-regex: "npm:^9.2.2" - strip-ansi: "npm:^7.0.1" - checksum: 10/7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 - 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" - dependencies: - ansi-regex: "npm:^5.0.1" - checksum: 10/ae3b5436d34fadeb6096367626ce987057713c566e1e7768818797e00ac5d62023d0f198c4e681eae9e20701721980b26a64a8f5b91238869592a9c6800719a2 - languageName: node - linkType: hard - -"strip-ansi@npm:^7.0.1": - version: 7.1.0 - resolution: "strip-ansi@npm:7.1.0" - dependencies: - ansi-regex: "npm:^6.0.1" - checksum: 10/475f53e9c44375d6e72807284024ac5d668ee1d06010740dec0b9744f2ddf47de8d7151f80e5f6190fc8f384e802fdf9504b76a7e9020c9faee7103623338be2 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 10/a9dc19ae2220c952bd2231d08ddeecb1b0328b61e72071ff4000c8384e145cc07c1c0bdb3b5a1cb06e186a7b2790f1dee793418b332f6ddf320de25d9125be7e - languageName: node - linkType: hard - -"tar@npm:^6.1.11, tar@npm:^6.2.1": - version: 6.2.1 - resolution: "tar@npm:6.2.1" - dependencies: - chownr: "npm:^2.0.0" - fs-minipass: "npm:^2.0.0" - minipass: "npm:^5.0.0" - minizlib: "npm:^2.1.1" - mkdirp: "npm:^1.0.3" - yallist: "npm:^4.0.0" - checksum: 10/bfbfbb2861888077fc1130b84029cdc2721efb93d1d1fb80f22a7ac3a98ec6f8972f29e564103bbebf5e97be67ebc356d37fa48dbc4960600a1eb7230fbd1ea0 - languageName: node - linkType: hard - -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a - languageName: node - linkType: hard - -"undici-types@npm:~6.19.2": - version: 6.19.8 - resolution: "undici-types@npm:6.19.8" - checksum: 10/cf0b48ed4fc99baf56584afa91aaffa5010c268b8842f62e02f752df209e3dea138b372a60a963b3b2576ed932f32329ce7ddb9cb5f27a6c83040d8cd74b7a70 - languageName: node - linkType: hard - -"unique-filename@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-filename@npm:3.0.0" - dependencies: - unique-slug: "npm:^4.0.0" - checksum: 10/8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df - languageName: node - linkType: hard - -"unique-slug@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-slug@npm:4.0.0" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10/40912a8963fc02fb8b600cf50197df4a275c602c60de4cac4f75879d3c48558cfac48de08a25cc10df8112161f7180b3bbb4d662aadb711568602f9eddee54f0 - languageName: node - linkType: hard - -"universalify@npm:^0.1.0": - version: 0.1.2 - resolution: "universalify@npm:0.1.2" - checksum: 10/40cdc60f6e61070fe658ca36016a8f4ec216b29bf04a55dce14e3710cc84c7448538ef4dad3728d0bfe29975ccd7bfb5f414c45e7b78883567fb31b246f02dff - languageName: node - linkType: hard - -"which@npm:^2.0.1": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: "npm:^2.0.0" - bin: - node-which: ./bin/node-which - checksum: 10/4782f8a1d6b8fc12c65e968fea49f59752bf6302dc43036c3bf87da718a80710f61a062516e9764c70008b487929a73546125570acea95c5b5dcc8ac3052c70f - languageName: node - linkType: hard - -"which@npm:^4.0.0": - version: 4.0.0 - resolution: "which@npm:4.0.0" - dependencies: - isexe: "npm:^3.1.1" - bin: - node-which: bin/which.js - checksum: 10/f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651 - languageName: node - linkType: hard - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: "npm:^4.0.0" - string-width: "npm:^4.1.0" - strip-ansi: "npm:^6.0.0" - checksum: 10/cebdaeca3a6880da410f75209e68cd05428580de5ad24535f22696d7d9cab134d1f8498599f344c3cf0fb37c1715807a183778d8c648d6cc0cb5ff2bb4236540 - languageName: node - linkType: hard - -"wrap-ansi@npm:^8.1.0": - version: 8.1.0 - resolution: "wrap-ansi@npm:8.1.0" - dependencies: - ansi-styles: "npm:^6.1.0" - string-width: "npm:^5.0.1" - strip-ansi: "npm:^7.0.1" - checksum: 10/7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf - languageName: node - linkType: hard - -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 10/159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 10/4cb02b42b8a93b5cf50caf5d8e9beb409400a8a4d85e83bb0685c1457e9ac0b7a00819e9f5991ac25ffabb56a78e2f017c1acc010b3a1babfe6de690ba531abd - languageName: node - linkType: hard From 34770d43afd79cbeb3a6693560b88c007603286b Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 15:19:26 -0400 Subject: [PATCH 46/97] remove wasm-backend workflow --- .github/workflows/test-wasm.yml | 53 --------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 .github/workflows/test-wasm.yml diff --git a/.github/workflows/test-wasm.yml b/.github/workflows/test-wasm.yml deleted file mode 100644 index b60d7d721..000000000 --- a/.github/workflows/test-wasm.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Test Diesel WASM Backend -on: - push: - branches: - - main - pull_request: - # only run tests when related changes are made - paths: - - ".github/workflows/test-wasm.yml" - - "dev/**" - - "diesel-wasm-sqlite/**" - - "Cargo.toml" - - "Cargo.lock" - - "rust-toolchain" -jobs: - test: - name: Test - # running with macos since it contains the safari driver - runs-on: warp-macos-13-arm64-6x - steps: - - name: Checkout - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - run: brew install --cask firefox - - name: Update rust toolchains - run: rustup update - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - - name: Setup node and yarn - uses: actions/setup-node@v4 - with: - node-version-file: ".node-version" - cache-dependency-path: "diesel-wasm-sqlite/yarn.lock" - cache: "yarn" - env: - SKIP_YARN_COREPACK_CHECK: "1" - - name: Enable corepack - run: corepack enable - - name: Run Yarn install - uses: borales/actions-yarn@v5 - with: - cmd: --cwd diesel-wasm-sqlite/ install - - name: Cache - uses: Swatinem/rust-cache@v2 - with: - workspaces: | - . - - run: wasm-pack test --headless --safari --features unsafe-debug-query - working-directory: diesel-wasm-sqlite - - run: wasm-pack test --headless --chrome --features unsafe-debug-query - working-directory: diesel-wasm-sqlite - - run: wasm-pack test --headless --firefox --features unsafe-debug-query - working-directory: diesel-wasm-sqlite From 6c720461ff855fca1254637e28be1ad5303caee8 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 17:24:41 -0400 Subject: [PATCH 47/97] remove unused dependencies, bring ffi crates into workspace --- Cargo.lock | 481 ++- Cargo.toml | 11 +- bindings_ffi/Cargo.lock | 6104 ----------------------------- bindings_ffi/Cargo.toml | 11 +- bindings_node/Cargo.lock | 5539 -------------------------- bindings_node/Cargo.toml | 13 +- bindings_wasm/Cargo.toml | 5 +- mls_validation_service/Cargo.toml | 3 - xmtp_api_grpc/Cargo.toml | 1 - xmtp_api_http/Cargo.toml | 1 - xmtp_id/Cargo.toml | 1 - xmtp_mls/Cargo.toml | 4 +- xmtp_proto/Cargo.toml | 4 +- xmtp_v2/Cargo.toml | 3 +- 14 files changed, 482 insertions(+), 11699 deletions(-) delete mode 100644 bindings_ffi/Cargo.lock delete mode 100644 bindings_node/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index 94fee6eaa..aa498fa33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,6 +177,47 @@ dependencies = [ "term", ] +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.72", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + [[package]] name = "assert-json-diff" version = "2.0.2" @@ -187,6 +228,19 @@ dependencies = [ "serde_json", ] +[[package]] +name = "async-compat" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bab94bde396a3f7b4962e396fdad640e241ed797d4d8d77fc8c237d14c58fc0" +dependencies = [ + "futures-core", + "futures-io", + "once_cell", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -352,6 +406,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bech32" version = "0.9.1" @@ -367,12 +430,29 @@ dependencies = [ "serde", ] +[[package]] +name = "bindings_node" +version = "0.0.1" +dependencies = [ + "hex", + "napi", + "napi-build", + "napi-derive", + "prost", + "tokio", + "tracing", + "xmtp_api_grpc", + "xmtp_cryptography", + "xmtp_id", + "xmtp_mls", + "xmtp_proto", +] + [[package]] name = "bindings_wasm" version = "0.0.1" dependencies = [ "js-sys", - "serde", "serde-wasm-bindgen", "wasm-bindgen", "wasm-bindgen-futures", @@ -381,7 +461,6 @@ dependencies = [ "xmtp_cryptography", "xmtp_id", "xmtp_mls", - "xmtp_proto", ] [[package]] @@ -517,6 +596,20 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cargo_metadata" version = "0.18.1" @@ -785,6 +878,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1562,7 +1664,7 @@ dependencies = [ "serde", "serde_json", "syn 2.0.72", - "toml", + "toml 0.8.19", "walkdir", ] @@ -1590,7 +1692,7 @@ checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" dependencies = [ "arrayvec", "bytes", - "cargo_metadata", + "cargo_metadata 0.18.1", "chrono", "const-hex", "elliptic-curve 0.13.8", @@ -1881,6 +1983,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + [[package]] name = "fs2" version = "0.4.3" @@ -2085,6 +2196,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "group" version = "0.12.1" @@ -2824,6 +2946,16 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + [[package]] name = "libm" version = "0.2.8" @@ -2963,7 +3095,7 @@ version = "2.2.0" source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ "serde", - "toml", + "toml 0.8.19", ] [[package]] @@ -2992,6 +3124,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -3026,10 +3164,7 @@ dependencies = [ "openmls", "openmls_basic_credential", "openmls_rust_crypto", - "openmls_traits", - "prost", "rand", - "serde", "sha2 0.10.8", "thiserror", "tokio", @@ -3116,6 +3251,64 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "napi" +version = "2.16.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53575dfa17f208dd1ce3a2da2da4659aae393b256a472f2738a8586a6c4107fd" +dependencies = [ + "bitflags 2.6.0", + "ctor", + "napi-derive", + "napi-sys", + "once_cell", + "tokio", +] + +[[package]] +name = "napi-build" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" + +[[package]] +name = "napi-derive" +version = "2.16.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17435f7a00bfdab20b0c27d9c56f58f6499e418252253081bfff448099da31d1" +dependencies = [ + "cfg-if", + "convert_case", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "napi-derive-backend" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "967c485e00f0bf3b1bdbe510a38a4606919cf1d34d9a37ad41f25a81aa077abe" +dependencies = [ + "convert_case", + "once_cell", + "proc-macro2", + "quote", + "regex", + "semver", + "syn 2.0.72", +] + +[[package]] +name = "napi-sys" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" +dependencies = [ + "libloading", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -3139,6 +3332,16 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -3545,6 +3748,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "path-slash" version = "0.2.1" @@ -3763,6 +3972,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "plotters" version = "0.3.6" @@ -4555,6 +4770,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "scrypt" version = "0.10.0" @@ -4834,6 +5069,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "socket2" version = "0.5.7" @@ -5141,6 +5382,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "smawk", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -5161,6 +5411,16 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "thread-id" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -5341,6 +5601,19 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + [[package]] name = "tokio-tungstenite" version = "0.20.1" @@ -5381,6 +5654,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" @@ -5702,6 +5984,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.1.13" @@ -5714,6 +6002,139 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "uniffi" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2db87def739fe4183947f8419d572d1849a4a09355eba4e988a2105cfd0ac6a7" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata 0.15.4", + "clap", + "uniffi_bindgen", + "uniffi_build", + "uniffi_core", + "uniffi_macros", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a112599c9556d1581e4a3d72019a74c2c3e122cc27f4af12577a429c4d5e614" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata 0.15.4", + "fs-err", + "glob", + "goblin", + "heck", + "once_cell", + "paste", + "serde", + "textwrap", + "toml 0.5.11", + "uniffi_meta", + "uniffi_testing", + "uniffi_udl", +] + +[[package]] +name = "uniffi_build" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b12684401d2a8508ca9c72a95bbc45906417e42fc80942abaf033bbf01aa33" +dependencies = [ + "anyhow", + "camino", + "uniffi_bindgen", +] + +[[package]] +name = "uniffi_checksum_derive" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22dbe67c1c957ac6e7611bdf605a6218aa86b0eebeb8be58b70ae85ad7d73dc" +dependencies = [ + "quote", + "syn 2.0.72", +] + +[[package]] +name = "uniffi_core" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a0c35aaad30e3a9e6d4fe34e358d64dbc92ee09045b48591b05fc9f12e0905b" +dependencies = [ + "anyhow", + "async-compat", + "bytes", + "camino", + "log", + "once_cell", + "paste", + "static_assertions", +] + +[[package]] +name = "uniffi_macros" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db66474c5c61b0f7afc3b4995fecf9b72b340daa5ca0ef3da7778d75eb5482ea" +dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn 2.0.72", + "toml 0.5.11", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d898893f102e0e39b8bcb7e3d2188f4156ba280db32db9e8af1f122d057e9526" +dependencies = [ + "anyhow", + "bytes", + "siphasher", + "uniffi_checksum_derive", +] + +[[package]] +name = "uniffi_testing" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6aa4f0cf9d12172d84fc00a35a6c1f3522b526daad05ae739f709f6941b9b6" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata 0.15.4", + "fs-err", + "once_cell", +] + +[[package]] +name = "uniffi_udl" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b044e9c519e0bb51e516ab6f6d8f4f4dcf900ce30d5ad07c03f924e2824f28e" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "uniffi_testing", + "weedle2", +] + [[package]] name = "universal-hash" version = "0.5.1" @@ -5776,6 +6197,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", + "rand", ] [[package]] @@ -6032,6 +6454,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weedle2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +dependencies = [ + "nom", +] + [[package]] name = "winapi" version = "0.3.9" @@ -6307,7 +6738,6 @@ dependencies = [ "futures", "hex", "prost", - "serde", "tokio", "tonic", "tracing", @@ -6322,7 +6752,6 @@ version = "0.0.1" dependencies = [ "async-stream", "futures", - "hyper 1.4.1", "reqwest 0.12.5", "serde", "serde_json", @@ -6384,7 +6813,6 @@ version = "0.0.1" dependencies = [ "async-trait", "chrono", - "ed25519", "ed25519-dalek", "ethers", "futures", @@ -6454,10 +6882,9 @@ dependencies = [ "tls_codec", "tokio", "tokio-stream", - "toml", + "toml 0.8.19", "tracing", "tracing-flame", - "tracing-log", "tracing-subscriber", "tracing-wasm", "trait-variant", @@ -6470,7 +6897,6 @@ dependencies = [ "xmtp_cryptography", "xmtp_id", "xmtp_proto", - "xmtp_v2", ] [[package]] @@ -6482,7 +6908,6 @@ dependencies = [ "pbjson", "pbjson-types", "prost", - "prost-types", "serde", "tonic", "trait-variant", @@ -6507,16 +6932,38 @@ dependencies = [ "aes-gcm", "ecdsa 0.15.1", "generic-array", - "getrandom", "hex", "hkdf", "k256 0.12.0", "rand", - "rand_chacha", "sha2 0.10.8", "sha3", ] +[[package]] +name = "xmtpv3" +version = "0.0.1" +dependencies = [ + "ethers", + "futures", + "log", + "parking_lot 0.12.3", + "rand", + "thiserror", + "thread-id", + "tokio", + "tokio-test", + "uniffi", + "uuid 1.10.0", + "xmtp_api_grpc", + "xmtp_cryptography", + "xmtp_id", + "xmtp_mls", + "xmtp_proto", + "xmtp_user_preferences", + "xmtp_v2", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 0362ec3a3..f38a6b981 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,13 +11,9 @@ members = [ "xmtp_v2", "xmtp_mls", "xmtp_id", - "bindings_wasm" -] - -exclude = [ - "bindings_ffi", + "bindings_wasm", "bindings_node", - "diesel-wasm-sqlite" + "bindings_ffi" ] # Make the feature resolver explicit. @@ -60,11 +56,12 @@ thiserror = "1.0" tls_codec = "0.4.1" tokio = { version = "1.35.1", default-features = false } tonic = "^0.12" -tracing = { version = "0.1", features = ["log"] } +tracing = { version = "0.1", features = ["log", "release_max_level_debug"] } tracing-subscriber = "0.3" diesel = { version = "2.2", default-features = false } diesel-wasm-sqlite = "0.0.1" diesel_migrations = { version = "2.2", default-features = false } +parking_lot = "0.12.3" wasm-bindgen-test = "0.3.42" wasm-bindgen-futures = "0.4" wasm-bindgen = "=0.2.92" diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock deleted file mode 100644 index 49d17ce08..000000000 --- a/bindings_ffi/Cargo.lock +++ /dev/null @@ -1,6104 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anstream" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "askama" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" -dependencies = [ - "askama_derive", - "askama_escape", -] - -[[package]] -name = "askama_derive" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" -dependencies = [ - "askama_parser", - "basic-toml", - "mime", - "mime_guess", - "proc-macro2", - "quote", - "serde", - "syn 2.0.48", -] - -[[package]] -name = "askama_escape" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" - -[[package]] -name = "askama_parser" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" -dependencies = [ - "nom", -] - -[[package]] -name = "async-compat" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f68a707c1feb095d8c07f8a65b9f506b117d30af431cab89374357de7c11461b" -dependencies = [ - "futures-core", - "futures-io", - "once_cell", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "async-trait" -version = "0.1.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "auto_impl" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "axum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 1.0.1", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 0.1.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "basic-toml" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5" -dependencies = [ - "serde", -] - -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bs58" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" -dependencies = [ - "sha2", - "tinyvec", -] - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -dependencies = [ - "serde", -] - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "jobserver", - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.0", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "clap" -version = "4.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim 0.10.0", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "coins-bip32" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" -dependencies = [ - "bs58", - "coins-core", - "digest", - "hmac", - "k256 0.13.3", - "serde", - "sha2", - "thiserror", -] - -[[package]] -name = "coins-bip39" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" -dependencies = [ - "bitvec", - "coins-bip32", - "hmac", - "once_cell", - "pbkdf2 0.12.2", - "rand", - "sha2", - "thiserror", -] - -[[package]] -name = "coins-core" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" -dependencies = [ - "base64 0.21.7", - "bech32", - "bs58", - "digest", - "generic-array", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2", - "sha3", - "thiserror", -] - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "const-hex" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" -dependencies = [ - "cfg-if", - "cpufeatures", - "hex", - "proptest", - "serde", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "platforms", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "darling" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.11.1", - "syn 2.0.48", -] - -[[package]] -name = "darling_macro" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "data-encoding" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "der" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "diesel" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" -dependencies = [ - "diesel_derives", - "libsqlite3-sys", - "r2d2", - "time", -] - -[[package]] -name = "diesel-wasm-sqlite" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "174378a6e27ada82d3faaac17ec226044f2b2590554bcb549622d3d2317f9909" -dependencies = [ - "diesel", - "diesel_derives", - "js-sys", - "serde", - "serde-wasm-bindgen", - "talc", - "thiserror", - "tokio", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", -] - -[[package]] -name = "diesel_derives" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6fdd83d5947068817016e939596d246e5367279453f2a3433287894f2f2996" -dependencies = [ - "diesel_table_macro_syntax", - "dsl_auto_type", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "diesel_migrations" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6" -dependencies = [ - "diesel", - "migrations_internals", - "migrations_macros", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" -dependencies = [ - "syn 2.0.48", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dsl_auto_type" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab32c18ea6760d951659768a3e35ea72fc1ba0916d665a88dfe048b2a41e543f" -dependencies = [ - "darling", - "either", - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" - -[[package]] -name = "ecdsa" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12844141594ad74185a926d030f3b605f6a903b4e3fec351f3ea338ac5b7637e" -dependencies = [ - "der 0.6.1", - "elliptic-curve 0.12.3", - "rfc6979 0.3.1", - "signature", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der 0.7.8", - "digest", - "elliptic-curve 0.13.8", - "rfc6979 0.4.0", - "signature", - "spki 0.7.3", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8 0.10.2", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", - "serde", - "sha2", - "signature", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct 0.1.1", - "crypto-bigint 0.4.9", - "der 0.6.1", - "digest", - "ff 0.12.1", - "generic-array", - "group 0.12.1", - "hkdf", - "pkcs8 0.9.0", - "rand_core", - "sec1 0.3.0", - "subtle", - "zeroize", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.5", - "digest", - "ff 0.13.0", - "generic-array", - "group 0.13.0", - "hkdf", - "pem-rfc7468", - "pkcs8 0.10.2", - "rand_core", - "sec1 0.7.3", - "subtle", - "zeroize", -] - -[[package]] -name = "ena" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" -dependencies = [ - "log", -] - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enr" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b" -dependencies = [ - "base64 0.21.7", - "bytes", - "hex", - "k256 0.13.3", - "log", - "rand", - "rlp", - "serde", - "sha3", - "zeroize", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "eth-keystore" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" -dependencies = [ - "aes", - "ctr", - "digest", - "hex", - "hmac", - "pbkdf2 0.11.0", - "rand", - "scrypt", - "serde", - "serde_json", - "sha2", - "sha3", - "thiserror", - "uuid 0.8.2", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c7cd562832e2ff584fa844cd2f6e5d4f35bbe11b28c7c9b8df957b2e1d0c701" -dependencies = [ - "ethers-addressbook", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-middleware", - "ethers-providers", - "ethers-signers", - "ethers-solc", -] - -[[package]] -name = "ethers-addressbook" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35dc9a249c066d17e8947ff52a4116406163cf92c7f0763cb8c001760b26403f" -dependencies = [ - "ethers-core", - "once_cell", - "serde", - "serde_json", -] - -[[package]] -name = "ethers-contract" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43304317c7f776876e47f2f637859f6d0701c1ec7930a150f169d5fbe7d76f5a" -dependencies = [ - "const-hex", - "ethers-contract-abigen", - "ethers-contract-derive", - "ethers-core", - "ethers-providers", - "futures-util", - "once_cell", - "pin-project", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "ethers-contract-abigen" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f96502317bf34f6d71a3e3d270defaa9485d754d789e15a8e04a84161c95eb" -dependencies = [ - "Inflector", - "const-hex", - "dunce", - "ethers-core", - "ethers-etherscan", - "eyre", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "reqwest 0.11.23", - "serde", - "serde_json", - "syn 2.0.48", - "toml 0.8.8", - "walkdir", -] - -[[package]] -name = "ethers-contract-derive" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "452ff6b0a64507ce8d67ffd48b1da3b42f03680dcf5382244e9c93822cbbf5de" -dependencies = [ - "Inflector", - "const-hex", - "ethers-contract-abigen", - "ethers-core", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.48", -] - -[[package]] -name = "ethers-core" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab3cef6cc1c9fd7f787043c81ad3052eff2b96a3878ef1526aa446311bdbfc9" -dependencies = [ - "arrayvec", - "bytes", - "cargo_metadata 0.18.1", - "chrono", - "const-hex", - "elliptic-curve 0.13.8", - "ethabi", - "generic-array", - "k256 0.13.3", - "num_enum", - "once_cell", - "open-fastrlp", - "rand", - "rlp", - "serde", - "serde_json", - "strum", - "syn 2.0.48", - "tempfile", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ethers-etherscan" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d45b981f5fa769e1d0343ebc2a44cfa88c9bc312eb681b676318b40cef6fb1" -dependencies = [ - "chrono", - "ethers-core", - "reqwest 0.11.23", - "semver", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "ethers-middleware" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145211f34342487ef83a597c1e69f0d3e01512217a7c72cc8a25931854c7dca0" -dependencies = [ - "async-trait", - "auto_impl", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", - "futures-channel", - "futures-locks", - "futures-util", - "instant", - "reqwest 0.11.23", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-futures", - "url", -] - -[[package]] -name = "ethers-providers" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb6b15393996e3b8a78ef1332d6483c11d839042c17be58decc92fa8b1c3508a" -dependencies = [ - "async-trait", - "auto_impl", - "base64 0.21.7", - "bytes", - "const-hex", - "enr", - "ethers-core", - "futures-core", - "futures-timer", - "futures-util", - "hashers", - "http 0.2.11", - "instant", - "jsonwebtoken", - "once_cell", - "pin-project", - "reqwest 0.11.23", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-tungstenite", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "ws_stream_wasm", -] - -[[package]] -name = "ethers-signers" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b125a103b56aef008af5d5fb48191984aa326b50bfd2557d231dc499833de3" -dependencies = [ - "async-trait", - "coins-bip32", - "coins-bip39", - "const-hex", - "elliptic-curve 0.13.8", - "eth-keystore", - "ethers-core", - "rand", - "sha2", - "thiserror", - "tracing", -] - -[[package]] -name = "ethers-solc" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d21df08582e0a43005018a858cc9b465c5fff9cf4056651be64f844e57d1f55f" -dependencies = [ - "cfg-if", - "const-hex", - "dirs", - "dunce", - "ethers-core", - "glob", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver", - "serde", - "serde_json", - "solang-parser", - "svm-rs", - "thiserror", - "tiny-keccak", - "tokio", - "tracing", - "walkdir", - "yansi", -] - -[[package]] -name = "eyre" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fluvio-wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b768c170dc045fa587a8f948c91f9bcfb87f774930477c6215addf54317f137f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs-err" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" -dependencies = [ - "autocfg", -] - -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-locks" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" -dependencies = [ - "futures-channel", - "futures-task", -] - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-timer" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" -dependencies = [ - "gloo-timers 0.2.6", - "send_wrapper 0.4.0", -] - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "goblin" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" -dependencies = [ - "log", - "plain", - "scroll", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff 0.12.1", - "rand_core", - "subtle", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff 0.13.0", - "rand_core", - "subtle", -] - -[[package]] -name = "h2" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.11", - "indexmap 2.1.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.1.0", - "indexmap 2.1.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "hashers" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "hpke-rs" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11bd4ee27b79fa1820e72ef8489cc729c87299ec3f7f52b8fc8dcb87cb2d485" -dependencies = [ - "hpke-rs-crypto", - "log", - "serde", - "tls_codec", - "zeroize", -] - -[[package]] -name = "hpke-rs-crypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3f1ae0a26c18d6469a70db1217136056261c4a244b09a755bc60bd4e055b67" -dependencies = [ - "rand_core", -] - -[[package]] -name = "hpke-rs-rust-crypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08d4500baf0aced746723d3515d08212bdb9d941df6d1aca3d46d1619b2a1cf" -dependencies = [ - "aes-gcm", - "chacha20poly1305", - "hkdf", - "hpke-rs-crypto", - "p256", - "p384", - "rand_chacha", - "rand_core", - "sha2", - "x25519-dalek", -] - -[[package]] -name = "http" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.11", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http 1.1.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" -dependencies = [ - "bytes", - "futures-core", - "http 1.1.0", - "http-body 1.0.0", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.24", - "http 0.2.11", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.11", - "hyper 0.14.28", - "rustls 0.21.10", - "tokio", - "tokio-rustls 0.24.1", -] - -[[package]] -name = "hyper-timeout" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" -dependencies = [ - "hyper 1.3.1", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.3.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", - "pin-project-lite", - "socket2", - "tokio", - "tower", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "is-terminal" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "jobserver" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" -dependencies = [ - "base64 0.21.7", - "pem", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "k256" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a55e0ff3b72c262bcf041d9e97f1b84492b68f1c1a384de2323d3dc9403397" -dependencies = [ - "cfg-if", - "ecdsa 0.15.1", - "elliptic-curve 0.12.3", - "once_cell", - "sha2", - "signature", -] - -[[package]] -name = "k256" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" -dependencies = [ - "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "once_cell", - "sha2", - "signature", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" -dependencies = [ - "ascii-canvas", - "bit-set", - "diff", - "ena", - "is-terminal", - "itertools 0.10.5", - "lalrpop-util", - "petgraph", - "regex", - "regex-syntax 0.7.5", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "libredox" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" -dependencies = [ - "bitflags 2.4.2", - "libc", - "redox_syscall 0.4.1", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4588d65215825ee71ebff9e1c9982067833b1355d7546845ffdb3165cbd7456" -dependencies = [ - "cc", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "migrations_internals" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff" -dependencies = [ - "serde", - "toml 0.8.8", -] - -[[package]] -name = "migrations_macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" -dependencies = [ - "hermit-abi", - "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" -dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "openmls" -version = "0.6.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "backtrace", - "fluvio-wasm-timer", - "getrandom", - "itertools 0.10.5", - "log", - "once_cell", - "openmls_basic_credential", - "openmls_memory_storage", - "openmls_rust_crypto", - "openmls_test", - "openmls_traits", - "rand", - "rayon", - "serde", - "serde_json", - "thiserror", - "tls_codec", - "wasm-bindgen-test", -] - -[[package]] -name = "openmls_basic_credential" -version = "0.3.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "ed25519-dalek", - "openmls_traits", - "p256", - "rand", - "serde", - "tls_codec", -] - -[[package]] -name = "openmls_memory_storage" -version = "0.3.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "hex", - "log", - "openmls_traits", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "openmls_rust_crypto" -version = "0.3.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "aes-gcm", - "chacha20poly1305", - "ed25519-dalek", - "hkdf", - "hmac", - "hpke-rs", - "hpke-rs-crypto", - "hpke-rs-rust-crypto", - "openmls_memory_storage", - "openmls_traits", - "p256", - "rand", - "rand_chacha", - "serde", - "sha2", - "thiserror", - "tls_codec", -] - -[[package]] -name = "openmls_test" -version = "0.1.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "ansi_term", - "openmls_rust_crypto", - "openmls_traits", - "proc-macro2", - "quote", - "rstest", - "rstest_reuse", - "syn 2.0.48", -] - -[[package]] -name = "openmls_traits" -version = "0.3.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "serde", - "tls_codec", -] - -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.3.0+3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba8804a1c5765b18c4b3f907e6897ebabeedebc9830e1a0046c4a4cf44663e1" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "primeorder", - "sha2", -] - -[[package]] -name = "p384" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" -dependencies = [ - "elliptic-curve 0.13.8", - "primeorder", -] - -[[package]] -name = "parity-scale-codec" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" -dependencies = [ - "proc-macro-crate 2.0.0", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -[[package]] -name = "path-slash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" - -[[package]] -name = "pbjson" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" -dependencies = [ - "base64 0.21.7", - "serde", -] - -[[package]] -name = "pbjson-build" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" -dependencies = [ - "heck 0.5.0", - "itertools 0.13.0", - "prost", - "prost-types", -] - -[[package]] -name = "pbjson-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" -dependencies = [ - "bytes", - "chrono", - "pbjson", - "pbjson-build", - "prost", - "prost-build", - "serde", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap 2.1.0", -] - -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der 0.6.1", - "spki 0.6.0", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der 0.7.8", - "spki 0.7.3", -] - -[[package]] -name = "pkg-config" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" - -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - -[[package]] -name = "platforms" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" -dependencies = [ - "proc-macro2", - "syn 2.0.48", -] - -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve 0.13.8", -] - -[[package]] -name = "primitive-types" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - -[[package]] -name = "proc-macro-crate" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" -dependencies = [ - "toml_edit 0.21.0", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proptest" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" -dependencies = [ - "bitflags 2.4.2", - "lazy_static", - "num-traits", - "rand", - "rand_chacha", - "rand_xorshift", - "regex-syntax 0.8.2", - "unarray", -] - -[[package]] -name = "prost" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" -dependencies = [ - "bytes", - "heck 0.5.0", - "itertools 0.13.0", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.48", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" -dependencies = [ - "anyhow", - "itertools 0.13.0", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "prost-types" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot 0.12.3", - "scheduled-thread-pool", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rayon" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_users" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.4", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "reqwest" -version = "0.11.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.24", - "http 0.2.11", - "http-body 0.4.6", - "hyper 0.14.28", - "hyper-rustls", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.10", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "system-configuration", - "tokio", - "tokio-rustls 0.24.1", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.25.3", - "winreg 0.50.0", -] - -[[package]] -name = "reqwest" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "hyper 1.3.1", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 2.1.0", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "winreg 0.52.0", -] - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac", - "zeroize", -] - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rlp-derive", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rstest" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962" -dependencies = [ - "futures", - "futures-timer", - "rstest_macros", - "rustc_version", -] - -[[package]] -name = "rstest_macros" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", - "unicode-ident", -] - -[[package]] -name = "rstest_reuse" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f80dcc84beab3a327bbe161f77db25f336a1452428176787c8c79ac79d7073" -dependencies = [ - "quote", - "rand", - "rustc_version", - "syn 1.0.109", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" -dependencies = [ - "bitflags 2.4.2", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" -dependencies = [ - "log", - "ring 0.17.8", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebbbdb961df0ad3f2652da8f3fdc4b36122f568f968f45ad3316f26c025c677b" -dependencies = [ - "log", - "once_cell", - "ring 0.17.8", - "rustls-pki-types", - "rustls-webpki 0.102.2", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe", - "rustls-pemfile 2.1.0", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-pemfile" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c333bb734fcdedcea57de1602543590f545f127dc8b533324318fd492c5c70b" -dependencies = [ - "base64 0.21.7", - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "rustls-webpki" -version = "0.102.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" -dependencies = [ - "ring 0.17.8", - "rustls-pki-types", - "untrusted 0.9.0", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scale-info" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot 0.12.3", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scroll" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "scrypt" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" -dependencies = [ - "hmac", - "pbkdf2 0.11.0", - "salsa20", - "sha2", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array", - "pkcs8 0.9.0", - "subtle", - "zeroize", -] - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct 0.2.0", - "der 0.7.8", - "generic-array", - "pkcs8 0.10.2", - "subtle", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" -dependencies = [ - "serde", -] - -[[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - -[[package]] -name = "serde" -version = "1.0.195" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.195" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "serde_json" -version = "1.0.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "solang-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" -dependencies = [ - "itertools 0.11.0", - "lalrpop", - "lalrpop-util", - "phf", - "thiserror", - "unicode-xid", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der 0.7.8", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot 0.12.3", - "phf_shared 0.10.0", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.48", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "svm-rs" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20689c7d03b6461b502d0b95d6c24874c7d24dea2688af80486a130a06af3b07" -dependencies = [ - "dirs", - "fs2", - "hex", - "once_cell", - "reqwest 0.11.23", - "semver", - "serde", - "serde_json", - "sha2", - "thiserror", - "url", - "zip", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "talc" -version = "4.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" -dependencies = [ - "lock_api", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall 0.4.1", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" -dependencies = [ - "smawk", -] - -[[package]] -name = "thiserror" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "thread-id" -version = "4.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tls_codec" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a" -dependencies = [ - "serde", - "tls_codec_derive", - "zeroize", -] - -[[package]] -name = "tls_codec_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "tokio" -version = "1.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "parking_lot 0.12.3", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.10", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" -dependencies = [ - "rustls 0.23.7", - "rustls-pki-types", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-test" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" -dependencies = [ - "async-stream", - "bytes", - "futures-core", - "tokio", - "tokio-stream", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls 0.21.10", - "tokio", - "tokio-rustls 0.24.1", - "tungstenite", - "webpki-roots 0.25.3", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.21.0", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.1.0", - "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.1.0", - "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" -dependencies = [ - "indexmap 2.1.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tonic" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.22.1", - "bytes", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "hyper 1.3.1", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost", - "rustls-native-certs", - "rustls-pemfile 2.1.0", - "socket2", - "tokio", - "tokio-rustls 0.26.0", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", - "webpki-roots 0.26.1", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 0.2.11", - "httparse", - "log", - "rand", - "rustls 0.21.10", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unarray" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "uniffi" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31bff6daf87277a9014bcdefbc2842b0553392919d1096843c5aad899ca4588" -dependencies = [ - "anyhow", - "camino", - "clap", - "uniffi_bindgen", - "uniffi_build", - "uniffi_core", - "uniffi_macros", -] - -[[package]] -name = "uniffi_bindgen" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96061d7e01b185aa405f7c9b134741ab3e50cc6796a47d6fd8ab9a5364b5feed" -dependencies = [ - "anyhow", - "askama", - "camino", - "cargo_metadata 0.15.4", - "fs-err", - "glob", - "goblin", - "heck 0.5.0", - "once_cell", - "paste", - "serde", - "textwrap", - "toml 0.5.11", - "uniffi_meta", - "uniffi_testing", - "uniffi_udl", -] - -[[package]] -name = "uniffi_build" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6b86f9b221046af0c533eafe09ece04e2f1ded04ccdc9bba0ec09aec1c52bd" -dependencies = [ - "anyhow", - "camino", - "uniffi_bindgen", -] - -[[package]] -name = "uniffi_checksum_derive" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fcfa22f55829d3aaa7acfb1c5150224188fe0f27c59a8a3eddcaa24d1ffbe58" -dependencies = [ - "quote", - "syn 2.0.48", -] - -[[package]] -name = "uniffi_core" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3210d57d6ab6065ab47a2898dacdb7c606fd6a4156196831fa3bf82e34ac58a6" -dependencies = [ - "anyhow", - "async-compat", - "bytes", - "camino", - "log", - "once_cell", - "paste", - "static_assertions", -] - -[[package]] -name = "uniffi_macros" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58691741080935437dc862122e68d7414432a11824ac1137868de46181a0bd2" -dependencies = [ - "bincode", - "camino", - "fs-err", - "once_cell", - "proc-macro2", - "quote", - "serde", - "syn 2.0.48", - "toml 0.5.11", - "uniffi_meta", -] - -[[package]] -name = "uniffi_meta" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7663eacdbd9fbf4a88907ddcfe2e6fa85838eb6dc2418a7d91eebb3786f8e20b" -dependencies = [ - "anyhow", - "bytes", - "siphasher", - "uniffi_checksum_derive", -] - -[[package]] -name = "uniffi_testing" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f922465f7566f25f8fe766920205fdfa9a3fcdc209c6bfb7557f0b5bf45b04dd" -dependencies = [ - "anyhow", - "camino", - "cargo_metadata 0.15.4", - "fs-err", - "once_cell", -] - -[[package]] -name = "uniffi_udl" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef408229a3a407fafa4c36dc4f6ece78a6fb258ab28d2b64bddd49c8cb680f6" -dependencies = [ - "anyhow", - "textwrap", - "uniffi_meta", - "uniffi_testing", - "weedle2", -] - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "uuid" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" -dependencies = [ - "getrandom", - "rand", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.48", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" - -[[package]] -name = "wasm-bindgen-test" -version = "0.3.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139bd73305d50e1c1c4333210c0db43d989395b64a237bd35c10ef3832a7f70c" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70072aebfe5da66d2716002c729a14e4aec4da0e23cc2ea66323dac541c93928" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "wasm-streams" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" - -[[package]] -name = "webpki-roots" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "weedle2" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" -dependencies = [ - "nom", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "ws_stream_wasm" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version", - "send_wrapper 0.6.0", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "x25519-dalek" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" -dependencies = [ - "curve25519-dalek", - "rand_core", - "serde", - "zeroize", -] - -[[package]] -name = "xmtp_api_grpc" -version = "0.0.1" -dependencies = [ - "async-stream", - "base64 0.22.1", - "futures", - "hex", - "prost", - "serde", - "tokio", - "tonic", - "tracing", - "xmtp_proto", - "xmtp_v2", -] - -[[package]] -name = "xmtp_cryptography" -version = "0.0.1" -dependencies = [ - "curve25519-dalek", - "ecdsa 0.16.9", - "ethers", - "getrandom", - "hex", - "k256 0.13.3", - "rand", - "rand_chacha", - "rustc-hex", - "serde", - "sha2", - "sha3", - "thiserror", - "tracing", -] - -[[package]] -name = "xmtp_id" -version = "0.0.1" -dependencies = [ - "async-trait", - "chrono", - "ed25519", - "ed25519-dalek", - "ethers", - "futures", - "getrandom", - "hex", - "openmls", - "openmls_traits", - "prost", - "rand", - "regex", - "rustc-hex", - "serde", - "sha2", - "thiserror", - "tokio", - "tracing", - "url", - "wasm-timer", - "xmtp_cryptography", - "xmtp_proto", -] - -[[package]] -name = "xmtp_mls" -version = "0.1.0" -dependencies = [ - "aes-gcm", - "async-stream", - "async-trait", - "bincode", - "chrono", - "diesel", - "diesel-wasm-sqlite", - "diesel_migrations", - "dyn-clone", - "ed25519-dalek", - "futures", - "getrandom", - "gloo-timers 0.3.0", - "hex", - "libsqlite3-sys", - "openmls", - "openmls_basic_credential", - "openmls_rust_crypto", - "openmls_traits", - "parking_lot 0.12.3", - "prost", - "rand", - "reqwest 0.12.4", - "serde", - "serde_json", - "sha2", - "thiserror", - "tls_codec", - "tokio", - "tokio-stream", - "tracing", - "tracing-subscriber", - "trait-variant", - "wasm-bindgen-futures", - "wasm-timer", - "web-sys", - "xmtp_api_grpc", - "xmtp_cryptography", - "xmtp_id", - "xmtp_proto", - "xmtp_v2", -] - -[[package]] -name = "xmtp_proto" -version = "0.0.1" -dependencies = [ - "futures", - "openmls", - "pbjson", - "pbjson-types", - "prost", - "prost-types", - "serde", - "tonic", - "trait-variant", -] - -[[package]] -name = "xmtp_user_preferences" -version = "0.0.1" -dependencies = [ - "base64 0.22.1", - "prost", - "xmtp_proto", - "xmtp_v2", -] - -[[package]] -name = "xmtp_v2" -version = "0.0.1" -dependencies = [ - "aes-gcm", - "ecdsa 0.15.1", - "generic-array", - "getrandom", - "hex", - "hkdf", - "k256 0.12.0", - "rand", - "rand_chacha", - "sha2", - "sha3", -] - -[[package]] -name = "xmtpv3" -version = "0.0.1" -dependencies = [ - "ethers", - "futures", - "log", - "parking_lot 0.12.3", - "rand", - "tempfile", - "thiserror", - "thread-id", - "tokio", - "tokio-test", - "uniffi", - "uuid 1.9.1", - "xmtp_api_grpc", - "xmtp_cryptography", - "xmtp_id", - "xmtp_mls", - "xmtp_proto", - "xmtp_user_preferences", - "xmtp_v2", -] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" -dependencies = [ - "cc", - "pkg-config", -] - -[[patch.unused]] -name = "openssl-sys" -version = "0.9.92" -source = "git+https://github.com/xmtp/rust-openssl.git?branch=clone-v0.9.92#00dacb9318930fbdd845cd4b36281e44c8d0c30f" diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index 8c190fea2..6a5786dbc 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -1,18 +1,18 @@ [package] edition = "2021" name = "xmtpv3" -version = "0.0.1" +version.workspace = true [lib] crate-type = ["lib", "cdylib", "staticlib"] [dependencies] -futures = "0.3.28" +futures.workspace = true log = { version = "0.4", features = ["std"] } -parking_lot = "0.12.3" -thiserror = "1.0" +parking_lot.workspace = true +thiserror.workspace = true thread-id = "4.2.1" -tokio = { version = "1.28.1", features = ["macros"] } +tokio = { workspace = true, features = ["macros"] } uniffi = { version = "0.28.0", features = ["tokio", "cli"] } xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_cryptography = { path = "../xmtp_cryptography" } @@ -41,7 +41,6 @@ path = "src/bin.rs" [dev-dependencies] ethers = "2.0.13" rand = "0.8.5" -tempfile = "3.5.0" tokio = { version = "1.28.1", features = ["full"] } tokio-test = "0.4" uniffi = { version = "0.28.0", features = ["bindgen-tests"] } diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock deleted file mode 100644 index 9c9fd7239..000000000 --- a/bindings_node/Cargo.lock +++ /dev/null @@ -1,5539 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anyhow" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "async-trait" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "auto_impl" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "axum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 1.0.1", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 0.1.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bindings_node" -version = "0.0.1" -dependencies = [ - "futures", - "hex", - "napi", - "napi-build", - "napi-derive", - "prost", - "rand", - "tokio", - "tonic", - "tracing", - "xmtp_api_grpc", - "xmtp_cryptography", - "xmtp_id", - "xmtp_mls", - "xmtp_proto", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "sha2", - "tinyvec", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -dependencies = [ - "serde", -] - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "camino" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.0.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" -dependencies = [ - "jobserver", - "libc", - "once_cell", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.5", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "coins-bip32" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" -dependencies = [ - "bs58", - "coins-core", - "digest", - "hmac", - "k256 0.13.3", - "serde", - "sha2", - "thiserror", -] - -[[package]] -name = "coins-bip39" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" -dependencies = [ - "bitvec", - "coins-bip32", - "hmac", - "once_cell", - "pbkdf2 0.12.2", - "rand", - "sha2", - "thiserror", -] - -[[package]] -name = "coins-core" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" -dependencies = [ - "base64 0.21.7", - "bech32", - "bs58", - "digest", - "generic-array", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2", - "sha3", - "thiserror", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "const-hex" -version = "1.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ff96486ccc291d36a958107caf2c0af8c78c0af7d31ae2f35ce055130de1a6" -dependencies = [ - "cfg-if", - "cpufeatures", - "hex", - "proptest", - "serde", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "ctor" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" -dependencies = [ - "quote", - "syn 2.0.64", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "platforms", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "darling" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.64", -] - -[[package]] -name = "darling_macro" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "diesel" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" -dependencies = [ - "diesel_derives", - "libsqlite3-sys", - "r2d2", - "time", -] - -[[package]] -name = "diesel-wasm-sqlite" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "174378a6e27ada82d3faaac17ec226044f2b2590554bcb549622d3d2317f9909" -dependencies = [ - "diesel", - "diesel_derives", - "js-sys", - "serde", - "serde-wasm-bindgen", - "talc", - "thiserror", - "tokio", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", -] - -[[package]] -name = "diesel_derives" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6fdd83d5947068817016e939596d246e5367279453f2a3433287894f2f2996" -dependencies = [ - "diesel_table_macro_syntax", - "dsl_auto_type", - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "diesel_migrations" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6" -dependencies = [ - "diesel", - "migrations_internals", - "migrations_macros", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" -dependencies = [ - "syn 2.0.64", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dsl_auto_type" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab32c18ea6760d951659768a3e35ea72fc1ba0916d665a88dfe048b2a41e543f" -dependencies = [ - "darling", - "either", - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" - -[[package]] -name = "ecdsa" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12844141594ad74185a926d030f3b605f6a903b4e3fec351f3ea338ac5b7637e" -dependencies = [ - "der 0.6.1", - "elliptic-curve 0.12.3", - "rfc6979 0.3.1", - "signature", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der 0.7.9", - "digest", - "elliptic-curve 0.13.8", - "rfc6979 0.4.0", - "signature", - "spki 0.7.3", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8 0.10.2", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", - "serde", - "sha2", - "signature", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct 0.1.1", - "crypto-bigint 0.4.9", - "der 0.6.1", - "digest", - "ff 0.12.1", - "generic-array", - "group 0.12.1", - "hkdf", - "pkcs8 0.9.0", - "rand_core", - "sec1 0.3.0", - "subtle", - "zeroize", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.5", - "digest", - "ff 0.13.0", - "generic-array", - "group 0.13.0", - "hkdf", - "pem-rfc7468", - "pkcs8 0.10.2", - "rand_core", - "sec1 0.7.3", - "subtle", - "zeroize", -] - -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enr" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" -dependencies = [ - "base64 0.21.7", - "bytes", - "hex", - "k256 0.13.3", - "log", - "rand", - "rlp", - "serde", - "sha3", - "zeroize", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "eth-keystore" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" -dependencies = [ - "aes", - "ctr", - "digest", - "hex", - "hmac", - "pbkdf2 0.11.0", - "rand", - "scrypt", - "serde", - "serde_json", - "sha2", - "sha3", - "thiserror", - "uuid", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" -dependencies = [ - "ethers-addressbook", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-middleware", - "ethers-providers", - "ethers-signers", - "ethers-solc", -] - -[[package]] -name = "ethers-addressbook" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" -dependencies = [ - "ethers-core", - "once_cell", - "serde", - "serde_json", -] - -[[package]] -name = "ethers-contract" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" -dependencies = [ - "const-hex", - "ethers-contract-abigen", - "ethers-contract-derive", - "ethers-core", - "ethers-providers", - "futures-util", - "once_cell", - "pin-project", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "ethers-contract-abigen" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" -dependencies = [ - "Inflector", - "const-hex", - "dunce", - "ethers-core", - "ethers-etherscan", - "eyre", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "reqwest 0.11.27", - "serde", - "serde_json", - "syn 2.0.64", - "toml", - "walkdir", -] - -[[package]] -name = "ethers-contract-derive" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" -dependencies = [ - "Inflector", - "const-hex", - "ethers-contract-abigen", - "ethers-core", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.64", -] - -[[package]] -name = "ethers-core" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" -dependencies = [ - "arrayvec", - "bytes", - "cargo_metadata", - "chrono", - "const-hex", - "elliptic-curve 0.13.8", - "ethabi", - "generic-array", - "k256 0.13.3", - "num_enum", - "once_cell", - "open-fastrlp", - "rand", - "rlp", - "serde", - "serde_json", - "strum", - "syn 2.0.64", - "tempfile", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ethers-etherscan" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" -dependencies = [ - "chrono", - "ethers-core", - "reqwest 0.11.27", - "semver", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "ethers-middleware" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" -dependencies = [ - "async-trait", - "auto_impl", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", - "futures-channel", - "futures-locks", - "futures-util", - "instant", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-futures", - "url", -] - -[[package]] -name = "ethers-providers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" -dependencies = [ - "async-trait", - "auto_impl", - "base64 0.21.7", - "bytes", - "const-hex", - "enr", - "ethers-core", - "futures-core", - "futures-timer", - "futures-util", - "hashers", - "http 0.2.12", - "instant", - "jsonwebtoken", - "once_cell", - "pin-project", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-tungstenite", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "ws_stream_wasm", -] - -[[package]] -name = "ethers-signers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" -dependencies = [ - "async-trait", - "coins-bip32", - "coins-bip39", - "const-hex", - "elliptic-curve 0.13.8", - "eth-keystore", - "ethers-core", - "rand", - "sha2", - "thiserror", - "tracing", -] - -[[package]] -name = "ethers-solc" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66244a771d9163282646dbeffe0e6eca4dda4146b6498644e678ac6089b11edd" -dependencies = [ - "cfg-if", - "const-hex", - "dirs", - "dunce", - "ethers-core", - "glob", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver", - "serde", - "serde_json", - "solang-parser", - "svm-rs", - "thiserror", - "tiny-keccak", - "tokio", - "tracing", - "walkdir", - "yansi", -] - -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fluvio-wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b768c170dc045fa587a8f948c91f9bcfb87f774930477c6215addf54317f137f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-locks" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" -dependencies = [ - "futures-channel", - "futures-task", -] - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" -dependencies = [ - "gloo-timers 0.2.6", - "send_wrapper 0.4.0", -] - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff 0.12.1", - "rand_core", - "subtle", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff 0.13.0", - "rand_core", - "subtle", -] - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.1.0", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashers" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "hpke-rs" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11bd4ee27b79fa1820e72ef8489cc729c87299ec3f7f52b8fc8dcb87cb2d485" -dependencies = [ - "hpke-rs-crypto", - "log", - "serde", - "tls_codec", - "zeroize", -] - -[[package]] -name = "hpke-rs-crypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3f1ae0a26c18d6469a70db1217136056261c4a244b09a755bc60bd4e055b67" -dependencies = [ - "rand_core", -] - -[[package]] -name = "hpke-rs-rust-crypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08d4500baf0aced746723d3515d08212bdb9d941df6d1aca3d46d1619b2a1cf" -dependencies = [ - "aes-gcm", - "chacha20poly1305", - "hkdf", - "hpke-rs-crypto", - "p256", - "p384", - "rand_chacha", - "rand_core", - "sha2", - "x25519-dalek", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http 1.1.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" -dependencies = [ - "bytes", - "futures-core", - "http 1.1.0", - "http-body 1.0.0", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.28", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - -[[package]] -name = "hyper-timeout" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" -dependencies = [ - "hyper 1.3.1", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.3.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", - "pin-project-lite", - "socket2", - "tokio", - "tower", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown 0.14.5", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jobserver" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" -dependencies = [ - "base64 0.21.7", - "pem", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "k256" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a55e0ff3b72c262bcf041d9e97f1b84492b68f1c1a384de2323d3dc9403397" -dependencies = [ - "cfg-if", - "ecdsa 0.15.1", - "elliptic-curve 0.12.3", - "once_cell", - "sha2", - "signature", -] - -[[package]] -name = "k256" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" -dependencies = [ - "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "once_cell", - "sha2", - "signature", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libloading" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if", - "windows-targets 0.52.5", -] - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.5.0", - "libc", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4588d65215825ee71ebff9e1c9982067833b1355d7546845ffdb3165cbd7456" -dependencies = [ - "cc", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "migrations_internals" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff" -dependencies = [ - "serde", - "toml", -] - -[[package]] -name = "migrations_macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" -dependencies = [ - "hermit-abi", - "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - -[[package]] -name = "napi" -version = "2.16.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc300228808a0e6aea5a58115c82889240bcf8dab16fc25ad675b33e454b368" -dependencies = [ - "bitflags 2.5.0", - "ctor", - "napi-derive", - "napi-sys", - "once_cell", - "tokio", -] - -[[package]] -name = "napi-build" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" - -[[package]] -name = "napi-derive" -version = "2.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb613535cde46cff231e53cd819c1694a32d48946bc2dda6b41174ace52ac08" -dependencies = [ - "cfg-if", - "convert_case", - "napi-derive-backend", - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "napi-derive-backend" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da041b19246ab4240998774e987fd9a7d92cc7406b91b5eddb6691e81feac044" -dependencies = [ - "convert_case", - "once_cell", - "proc-macro2", - "quote", - "regex", - "semver", - "syn 2.0.64", -] - -[[package]] -name = "napi-sys" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" -dependencies = [ - "libloading", -] - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "num-bigint" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "openmls" -version = "0.6.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "backtrace", - "fluvio-wasm-timer", - "getrandom", - "itertools 0.10.5", - "log", - "once_cell", - "openmls_basic_credential", - "openmls_memory_storage", - "openmls_rust_crypto", - "openmls_test", - "openmls_traits", - "rand", - "rayon", - "serde", - "serde_json", - "thiserror", - "tls_codec", - "wasm-bindgen-test", -] - -[[package]] -name = "openmls_basic_credential" -version = "0.3.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "ed25519-dalek", - "openmls_traits", - "p256", - "rand", - "serde", - "tls_codec", -] - -[[package]] -name = "openmls_memory_storage" -version = "0.3.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "hex", - "log", - "openmls_traits", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "openmls_rust_crypto" -version = "0.3.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "aes-gcm", - "chacha20poly1305", - "ed25519-dalek", - "hkdf", - "hmac", - "hpke-rs", - "hpke-rs-crypto", - "hpke-rs-rust-crypto", - "openmls_memory_storage", - "openmls_traits", - "p256", - "rand", - "rand_chacha", - "serde", - "sha2", - "thiserror", - "tls_codec", -] - -[[package]] -name = "openmls_test" -version = "0.1.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "ansi_term", - "openmls_rust_crypto", - "openmls_traits", - "proc-macro2", - "quote", - "rstest", - "rstest_reuse", - "syn 2.0.64", -] - -[[package]] -name = "openmls_traits" -version = "0.3.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "serde", - "tls_codec", -] - -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.2.3+3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "primeorder", - "sha2", -] - -[[package]] -name = "p384" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" -dependencies = [ - "elliptic-curve 0.13.8", - "primeorder", -] - -[[package]] -name = "parity-scale-codec" -version = "3.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.1", - "smallvec", - "windows-targets 0.52.5", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "path-slash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" - -[[package]] -name = "pbjson" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" -dependencies = [ - "base64 0.21.7", - "serde", -] - -[[package]] -name = "pbjson-build" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" -dependencies = [ - "heck 0.5.0", - "itertools 0.13.0", - "prost", - "prost-types", -] - -[[package]] -name = "pbjson-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" -dependencies = [ - "bytes", - "chrono", - "pbjson", - "pbjson-build", - "prost", - "prost-build", - "serde", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.2.6", -] - -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der 0.6.1", - "spki 0.6.0", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der 0.7.9", - "spki 0.7.3", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "platforms" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" -dependencies = [ - "proc-macro2", - "syn 2.0.64", -] - -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve 0.13.8", -] - -[[package]] -name = "primitive-types" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" -dependencies = [ - "toml_edit 0.21.1", -] - -[[package]] -name = "proc-macro2" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proptest" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" -dependencies = [ - "bitflags 2.5.0", - "lazy_static", - "num-traits", - "rand", - "rand_chacha", - "rand_xorshift", - "regex-syntax", - "unarray", -] - -[[package]] -name = "prost" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" -dependencies = [ - "bytes", - "heck 0.5.0", - "itertools 0.13.0", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.64", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" -dependencies = [ - "anyhow", - "itertools 0.13.0", - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "prost-types" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot 0.12.3", - "scheduled-thread-pool", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags 2.5.0", -] - -[[package]] -name = "redox_users" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.28", - "hyper-rustls", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", - "tokio", - "tokio-rustls 0.24.1", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.25.4", - "winreg 0.50.0", -] - -[[package]] -name = "reqwest" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "hyper 1.3.1", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 2.1.2", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "winreg 0.52.0", -] - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac", - "zeroize", -] - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rlp-derive", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rstest" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962" -dependencies = [ - "futures", - "futures-timer", - "rstest_macros", - "rustc_version", -] - -[[package]] -name = "rstest_macros" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", - "unicode-ident", -] - -[[package]] -name = "rstest_reuse" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f80dcc84beab3a327bbe161f77db25f336a1452428176787c8c79ac79d7073" -dependencies = [ - "quote", - "rand", - "rustc_version", - "syn 1.0.109", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring 0.17.8", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" -dependencies = [ - "log", - "once_cell", - "ring 0.17.8", - "rustls-pki-types", - "rustls-webpki 0.102.7", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe", - "rustls-pemfile 2.1.2", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-pemfile" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" -dependencies = [ - "base64 0.22.1", - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "rustls-webpki" -version = "0.102.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" -dependencies = [ - "ring 0.17.8", - "rustls-pki-types", - "untrusted 0.9.0", -] - -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scale-info" -version = "2.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot 0.12.3", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scrypt" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" -dependencies = [ - "hmac", - "pbkdf2 0.11.0", - "salsa20", - "sha2", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array", - "pkcs8 0.9.0", - "subtle", - "zeroize", -] - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct 0.2.0", - "der 0.7.9", - "generic-array", - "pkcs8 0.10.2", - "subtle", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" -dependencies = [ - "bitflags 2.5.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] - -[[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - -[[package]] -name = "serde" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "serde_json" -version = "1.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "signature" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "solang-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" -dependencies = [ - "itertools 0.11.0", - "lalrpop", - "lalrpop-util", - "phf", - "thiserror", - "unicode-xid", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der 0.7.9", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot 0.12.3", - "phf_shared 0.10.0", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.64", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "svm-rs" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11297baafe5fa0c99d5722458eac6a5e25c01eb1b8e5cd137f54079093daa7a4" -dependencies = [ - "dirs", - "fs2", - "hex", - "once_cell", - "reqwest 0.11.27", - "semver", - "serde", - "serde_json", - "sha2", - "thiserror", - "url", - "zip", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "talc" -version = "4.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" -dependencies = [ - "lock_api", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tls_codec" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a" -dependencies = [ - "serde", - "tls_codec_derive", - "zeroize", -] - -[[package]] -name = "tls_codec_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "tokio" -version = "1.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "tokio-macros", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" -dependencies = [ - "rustls 0.23.12", - "rustls-pki-types", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", - "tungstenite", - "webpki-roots 0.25.4", -] - -[[package]] -name = "tokio-util" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.13", -] - -[[package]] -name = "toml_datetime" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" -dependencies = [ - "indexmap 2.2.6", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.6.8", -] - -[[package]] -name = "tonic" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.22.1", - "bytes", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "hyper 1.3.1", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost", - "rustls-native-certs", - "rustls-pemfile 2.1.2", - "socket2", - "tokio", - "tokio-rustls 0.26.0", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", - "webpki-roots 0.26.1", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 0.2.12", - "httparse", - "log", - "rand", - "rustls 0.21.12", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unarray" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.64", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "wasm-bindgen-test" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "wasm-streams" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "webpki-roots" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "ws_stream_wasm" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version", - "send_wrapper 0.6.0", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "x25519-dalek" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" -dependencies = [ - "curve25519-dalek", - "rand_core", - "serde", - "zeroize", -] - -[[package]] -name = "xmtp_api_grpc" -version = "0.0.1" -dependencies = [ - "async-stream", - "base64 0.22.1", - "futures", - "hex", - "prost", - "serde", - "tokio", - "tonic", - "tracing", - "xmtp_proto", - "xmtp_v2", -] - -[[package]] -name = "xmtp_cryptography" -version = "0.0.1" -dependencies = [ - "curve25519-dalek", - "ecdsa 0.16.9", - "ethers", - "getrandom", - "hex", - "k256 0.13.3", - "rand", - "rand_chacha", - "rustc-hex", - "serde", - "sha2", - "sha3", - "thiserror", - "tracing", -] - -[[package]] -name = "xmtp_id" -version = "0.0.1" -dependencies = [ - "async-trait", - "chrono", - "ed25519", - "ed25519-dalek", - "ethers", - "futures", - "getrandom", - "hex", - "openmls", - "openmls_traits", - "prost", - "rand", - "regex", - "rustc-hex", - "serde", - "sha2", - "thiserror", - "tokio", - "tracing", - "url", - "wasm-timer", - "xmtp_cryptography", - "xmtp_proto", -] - -[[package]] -name = "xmtp_mls" -version = "0.1.0" -dependencies = [ - "aes-gcm", - "async-stream", - "async-trait", - "bincode", - "chrono", - "diesel", - "diesel-wasm-sqlite", - "diesel_migrations", - "dyn-clone", - "ed25519-dalek", - "futures", - "getrandom", - "gloo-timers 0.3.0", - "hex", - "libsqlite3-sys", - "openmls", - "openmls_basic_credential", - "openmls_rust_crypto", - "openmls_traits", - "parking_lot 0.12.3", - "prost", - "rand", - "reqwest 0.12.4", - "serde", - "serde_json", - "sha2", - "thiserror", - "tls_codec", - "tokio", - "tokio-stream", - "tracing", - "trait-variant", - "wasm-bindgen-futures", - "wasm-timer", - "web-sys", - "xmtp_cryptography", - "xmtp_id", - "xmtp_proto", - "xmtp_v2", -] - -[[package]] -name = "xmtp_proto" -version = "0.0.1" -dependencies = [ - "futures", - "openmls", - "pbjson", - "pbjson-types", - "prost", - "prost-types", - "serde", - "tonic", - "trait-variant", -] - -[[package]] -name = "xmtp_v2" -version = "0.0.1" -dependencies = [ - "aes-gcm", - "ecdsa 0.15.1", - "generic-array", - "getrandom", - "hex", - "hkdf", - "k256 0.12.0", - "rand", - "rand_chacha", - "sha2", - "sha3", -] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml index 25a06eb39..695a9b0f7 100644 --- a/bindings_node/Cargo.toml +++ b/bindings_node/Cargo.toml @@ -1,26 +1,23 @@ [package] edition = "2021" name = "bindings_node" -version = "0.0.1" +version.workspace = true [lib] crate-type = ["cdylib"] [dependencies] # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix -futures = "0.3.30" -hex = "0.4.3" -tracing = { version = "0.1", features = ["release_max_level_debug"] } +hex.workspace = true +tracing.workspace = true napi = { version = "2.12.2", default-features = false, features = [ "napi4", "napi6", "async", ] } napi-derive = "2.12.2" -prost = "^0.13" -rand = "0.8.5" -tokio = { version = "1.35.1", features = ["macros", "rt-multi-thread", "time"] } -tonic = { version = "^0.12", features = ["tls"] } +prost.workspace = true +tokio = { workspace = true, features = ["full"]} xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 2eb5586eb..9346fe1b0 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -1,7 +1,6 @@ [package] edition = "2021" name = "bindings_wasm" -resolver = "2" version.workspace = true [lib] @@ -9,7 +8,6 @@ crate-type = ["cdylib", "rlib"] [dependencies] js-sys.workspace = true -serde = { workspace = true, features = ["derive"] } serde-wasm-bindgen = "0.6.5" wasm-bindgen.workspace = true wasm-bindgen-futures.workspace = true @@ -17,10 +15,9 @@ xmtp_api_http = { path = "../xmtp_api_http" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } xmtp_mls = { path = "../xmtp_mls", features = ["message-history"] } -xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } [dev-dependencies] -wasm-bindgen-test = "0.3.42" +wasm-bindgen-test.workspace = true [profile.release] opt-level = "s" diff --git a/mls_validation_service/Cargo.toml b/mls_validation_service/Cargo.toml index 2c46aed6a..11d5cf2bd 100644 --- a/mls_validation_service/Cargo.toml +++ b/mls_validation_service/Cargo.toml @@ -14,9 +14,6 @@ futures = { workspace = true } hex = { workspace = true } openmls = { workspace = true } openmls_rust_crypto = { workspace = true } -openmls_traits = { workspace = true } -prost = { workspace = true, features = ["prost-derive"] } -serde = { workspace = true } thiserror.workspace = true tokio = { workspace = true, features = ["full"] } tonic = { workspace = true } diff --git a/xmtp_api_grpc/Cargo.toml b/xmtp_api_grpc/Cargo.toml index f0d6b8bac..017de33b1 100644 --- a/xmtp_api_grpc/Cargo.toml +++ b/xmtp_api_grpc/Cargo.toml @@ -9,7 +9,6 @@ base64 = "0.22" futures.workspace = true hex.workspace = true prost = { workspace = true, features = ["prost-derive"] } -serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } tonic = { workspace = true, features = [ "tls", diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml index 0e5097157..66a6b2723 100644 --- a/xmtp_api_http/Cargo.toml +++ b/xmtp_api_http/Cargo.toml @@ -11,7 +11,6 @@ async-stream.workspace = true futures = { workspace = true } tracing.workspace = true reqwest = { version = "0.12.5", features = ["json", "stream"] } -hyper = "1.4" serde = { workspace = true } serde_json = { workspace = true } thiserror = "1.0" diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index 5136e95d7..e66a42fce 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -8,7 +8,6 @@ url = "2.5.2" async-trait.workspace = true chrono.workspace = true ed25519-dalek = { workspace = true, features = ["digest"] } -ed25519.workspace = true ethers.workspace = true futures.workspace = true hex.workspace = true diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 84ae50c69..7b68543ad 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -17,7 +17,7 @@ http-api = ["xmtp_api_http"] message-history = [] [dependencies] -parking_lot = "0.12.3" +parking_lot.workspace = true async-stream.workspace = true trait-variant.workspace = true bincode = "1.3.3" @@ -46,7 +46,6 @@ wasm-timer.workspace = true xmtp_cryptography = { workspace = true } xmtp_id = { path = "../xmtp_id" } xmtp_proto = { workspace = true, features = ["proto_full", "convert"] } -xmtp_v2 = { path = "../xmtp_v2" } # Optional/Features toml = { version = "0.8.4", optional = true } @@ -105,7 +104,6 @@ tracing-subscriber.workspace = true tempfile = "3.5.0" mockito = "1.4.0" ctor.workspace = true -tracing-log = "0.2.0" [target.'cfg(target_arch = "wasm32")'.dev-dependencies] xmtp_api_http = { path = "../xmtp_api_http" } diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index b97283759..46beaae5e 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -8,8 +8,6 @@ futures = { workspace = true } pbjson-types.workspace = true pbjson.workspace = true prost = { workspace = true, features = ["prost-derive"] } -# Only necessary if using Protobuf well-known types: -prost-types = { workspace = true } serde = { workspace = true } openmls = { workspace = true, optional = true } trait-variant = "0.1.2" @@ -37,4 +35,4 @@ proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations "xmtp-mls-message_contents" = [] "xmtp-mls_validation-v1" = ["xmtp-identity-associations"] "xmtp-xmtpv4" = ["xmtp-identity-associations","xmtp-mls-api-v1"] -## @@protoc_insertion_point(features) +## @@protoc_insertion_point(features) \ No newline at end of file diff --git a/xmtp_v2/Cargo.toml b/xmtp_v2/Cargo.toml index f4fd6db74..20573e1e0 100644 --- a/xmtp_v2/Cargo.toml +++ b/xmtp_v2/Cargo.toml @@ -8,12 +8,11 @@ version.workspace = true aes-gcm = "0.10.1" ecdsa = "0.15.1" generic-array = "0.14.6" -getrandom = { workspace = true, features = ["js"] } +# getrandom = { workspace = true, features = ["js"] } hex = { workspace = true } hkdf = "0.12.3" k256 = { version = "0.12.0", features = ["ecdh"] } rand = { workspace = true } -rand_chacha = "0.3.1" sha2 = "0.10.6" sha3 = "0.10.6" From 7a9631d2e4ffc2f94ad58168c10270fd810138a2 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 18:36:04 -0400 Subject: [PATCH 48/97] try to correctly pin openssl-sys to 0.9.92 --- Cargo.lock | 752 ++++++++++++++++++++------------------- Cargo.toml | 27 +- bindings_ffi/Cargo.toml | 17 - bindings_node/Cargo.toml | 4 - bindings_wasm/Cargo.toml | 3 - xmtp_mls/Cargo.toml | 4 +- 6 files changed, 414 insertions(+), 393 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa498fa33..15e1addc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,18 +14,18 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -152,21 +152,21 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii-canvas" @@ -200,7 +200,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -243,9 +243,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -254,24 +254,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -299,20 +299,20 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -330,16 +330,16 @@ dependencies = [ "rustversion", "serde", "sync_wrapper 1.0.1", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -350,24 +350,24 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", ] [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -550,9 +550,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" dependencies = [ "serde", ] @@ -580,9 +580,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -632,12 +632,13 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.8" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -724,9 +725,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.14" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c937d4061031a6d0c8da4b9a4f98a172fc2976dfb1c19213a9cf7d0d3c837e36" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" dependencies = [ "clap_builder", "clap_derive", @@ -734,9 +735,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.14" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85379ba512b21a328adf887e85f7742d12e96eb31f3ef077df4ffc26b506ffed" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", @@ -746,14 +747,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -772,7 +773,7 @@ dependencies = [ "coins-core", "digest 0.10.7", "hmac 0.12.1", - "k256 0.13.3", + "k256 0.13.4", "serde", "sha2 0.10.8", "thiserror", @@ -855,9 +856,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" dependencies = [ "cfg-if", "cpufeatures", @@ -899,15 +900,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -1042,7 +1043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1078,7 +1079,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1102,7 +1103,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1113,7 +1114,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1160,7 +1161,7 @@ checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1168,7 +1169,7 @@ name = "diesel" version = "2.2.0" source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ - "diesel_derives 2.2.0", + "diesel_derives", "downcast-rs", "libsqlite3-sys", "r2d2", @@ -1178,10 +1179,10 @@ dependencies = [ [[package]] name = "diesel-wasm-sqlite" version = "0.0.1" -source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#b8bca417559da55258fccdb771b3190d8577fb5a" +source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#c1c4da6abed5dc65f47a1cf99e3d9cdf600c320b" dependencies = [ "diesel", - "diesel_derives 2.2.2", + "diesel_derives", "js-sys", "serde", "serde-wasm-bindgen", @@ -1198,24 +1199,11 @@ name = "diesel_derives" version = "2.2.0" source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ - "diesel_table_macro_syntax 0.2.0 (git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub)", - "dsl_auto_type 0.1.0", - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "diesel_derives" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" -dependencies = [ - "diesel_table_macro_syntax 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dsl_auto_type 0.1.2", + "diesel_table_macro_syntax", + "dsl_auto_type", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1228,21 +1216,12 @@ dependencies = [ "migrations_macros", ] -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" -dependencies = [ - "syn 2.0.72", -] - [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1330,21 +1309,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.72", -] - -[[package]] -name = "dsl_auto_type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" -dependencies = [ - "darling", - "either", - "heck", - "proc-macro2", - "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1492,7 +1457,7 @@ dependencies = [ "base64 0.21.7", "bytes", "hex", - "k256 0.13.3", + "k256 0.13.4", "log", "rand", "rlp", @@ -1663,7 +1628,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.72", + "syn 2.0.79", "toml 0.8.19", "walkdir", ] @@ -1681,7 +1646,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -1698,7 +1663,7 @@ dependencies = [ "elliptic-curve 0.13.8", "ethabi", "generic-array", - "k256 0.13.3", + "k256 0.13.4", "num_enum", "once_cell", "open-fastrlp", @@ -1707,7 +1672,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.72", + "syn 2.0.79", "tempfile", "thiserror", "tiny-keccak", @@ -1858,9 +1823,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "femme" @@ -1924,9 +1889,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide", @@ -2074,7 +2039,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -2162,9 +2127,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "glob" @@ -2241,7 +2206,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.3.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2250,9 +2215,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -2260,7 +2225,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.3.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2285,9 +2250,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "hashers" @@ -2334,6 +2299,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -2489,9 +2460,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2532,7 +2503,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -2560,15 +2531,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -2606,9 +2577,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", @@ -2619,16 +2590,15 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2719,12 +2689,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.3.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -2763,17 +2733,17 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi", + "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] @@ -2874,9 +2844,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa 0.16.9", @@ -2917,7 +2887,7 @@ dependencies = [ "lalrpop-util", "petgraph", "regex", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "string_cache", "term", "tiny-keccak", @@ -2931,7 +2901,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.7", + "regex-automata 0.4.8", ] [[package]] @@ -2942,9 +2912,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libloading" @@ -3132,20 +3102,20 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -3200,7 +3170,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -3247,9 +3217,9 @@ dependencies = [ [[package]] name = "multimap" -version = "0.8.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "napi" @@ -3282,7 +3252,7 @@ dependencies = [ "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -3297,7 +3267,7 @@ dependencies = [ "quote", "regex", "semver", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -3393,7 +3363,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -3415,7 +3385,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -3426,18 +3396,21 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +dependencies = [ + "portable-atomic", +] [[package]] name = "oorandom" @@ -3563,7 +3536,7 @@ dependencies = [ "quote", "rstest", "rstest_reuse", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -3577,9 +3550,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -3598,7 +3571,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -3609,18 +3582,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.3.1+3.3.1" +version = "111.28.2+1.1.1w" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" +checksum = "bb1830e20a48a975ca898ca8c1d036a36c3c6c5cb7dabc1c216706587857920f" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" dependencies = [ "cc", "libc", @@ -3732,7 +3705,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.7", "smallvec", "windows-targets 0.52.6", ] @@ -3850,7 +3823,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.3.0", + "indexmap 2.6.0", ] [[package]] @@ -3893,7 +3866,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -3931,7 +3904,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -3968,9 +3941,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plain" @@ -3980,9 +3953,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -3993,15 +3966,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -4031,9 +4004,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powerfmt" @@ -4084,12 +4057,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -4117,11 +4090,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] @@ -4145,15 +4118,15 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "unarray", ] [[package]] name = "prost" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", "prost-derive", @@ -4161,9 +4134,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", "heck", @@ -4176,37 +4149,37 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.72", + "syn 2.0.79", "tempfile", ] [[package]] name = "prost-derive" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] name = "prost-types" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" dependencies = [ "prost", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -4298,18 +4271,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -4318,14 +4291,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -4339,13 +4312,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4356,9 +4329,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -4389,7 +4362,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration", + "system-configuration 0.5.1", "tokio", "tokio-rustls 0.24.1", "tower-service", @@ -4398,26 +4371,26 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots 0.25.4", - "winreg 0.50.0", + "winreg", ] [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls 0.27.3", "hyper-tls", "hyper-util", "ipnet", @@ -4428,12 +4401,12 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.1", - "system-configuration", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-util", @@ -4443,7 +4416,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg 0.52.0", + "windows-registry", ] [[package]] @@ -4580,18 +4553,18 @@ checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -4614,27 +4587,27 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "log", "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -4651,19 +4624,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-webpki" @@ -4677,9 +4649,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -4742,11 +4714,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4787,7 +4759,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -4855,9 +4827,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -4886,9 +4858,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.205" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -4906,13 +4878,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.205" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -4926,9 +4898,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -4938,9 +4910,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -5011,6 +4983,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -5175,7 +5153,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -5186,15 +5164,15 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sval" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53eb957fbc79a55306d5d25d87daf3627bc3800681491cda0709eef36c748bfe" +checksum = "eaf38d1fa2ce984086ea42fb856a9f374d94680a4f796831a7fc868d7f2af1b9" [[package]] name = "sval_buffer" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96e860aef60e9cbf37888d4953a13445abf523c534640d1f6174d310917c410d" +checksum = "81682ff859964ca1d7cf3d3d0f9ec7204ea04c2c32acb8cc2cf68ecbd3127354" dependencies = [ "sval", "sval_ref", @@ -5202,18 +5180,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3f2b07929a1127d204ed7cb3905049381708245727680e9139dac317ed556f" +checksum = "2a213b93bb4c6f4c9f9b17f2e740e077fd18746bbf7c80c72bbadcac68fa7ee4" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e188677497de274a1367c4bda15bd2296de4070d91729aac8f0a09c1abf64d" +checksum = "6902c6d3fb52c89206fe0dc93546c0123f7d48b5997fd14e61c9e64ff0b63275" dependencies = [ "itoa", "ryu", @@ -5222,9 +5200,9 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f456c07dae652744781f2245d5e3b78e6a9ebad70790ac11eb15dbdbce5282" +checksum = "11a28041ea78cdc394b930ae6b897d36246dc240a29a6edf82d76562487fb0b4" dependencies = [ "itoa", "ryu", @@ -5233,9 +5211,9 @@ dependencies = [ [[package]] name = "sval_nested" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886feb24709f0476baaebbf9ac10671a50163caa7e439d7a7beb7f6d81d0a6fb" +checksum = "850346e4b0742a7f2fd2697d703ff80084d0b658f0f2e336d71b8a06abf9b68e" dependencies = [ "sval", "sval_buffer", @@ -5244,18 +5222,18 @@ dependencies = [ [[package]] name = "sval_ref" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2e7fc517d778f44f8cb64140afa36010999565528d48985f55e64d45f369ce" +checksum = "824afd97a8919f28a35b0fdea979845cc2ae461a8a3aaa129455cb89c88bb77a" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79bf66549a997ff35cd2114a27ac4b0c2843280f2cfa84b240d169ecaa0add46" +checksum = "8ada7520dd719ed672c786c7db7de4f5230f4d504b0821bd8305cd30ca442315" dependencies = [ "serde", "sval", @@ -5295,9 +5273,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -5315,6 +5293,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "system-configuration" @@ -5324,7 +5305,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys 0.6.0", ] [[package]] @@ -5337,6 +5329,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "talc" version = "4.4.1" @@ -5354,9 +5356,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -5393,22 +5395,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -5525,14 +5527,14 @@ checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] name = "tokio" -version = "1.39.2" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -5555,7 +5557,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -5584,16 +5586,16 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -5643,9 +5645,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -5672,7 +5674,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit", ] [[package]] @@ -5686,40 +5688,29 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.3.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap 2.3.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow", ] [[package]] name = "tonic" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", "axum", "base64 0.22.1", "bytes", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "http-body-util", @@ -5730,16 +5721,16 @@ dependencies = [ "pin-project", "prost", "rustls-native-certs", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "socket2", "tokio", "tokio-rustls 0.26.0", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] @@ -5762,17 +5753,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -5794,7 +5799,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -5876,7 +5881,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -5926,9 +5931,9 @@ dependencies = [ [[package]] name = "typeid" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" [[package]] name = "typenum" @@ -5965,21 +5970,21 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -5992,15 +5997,15 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "uniffi" @@ -6060,7 +6065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a22dbe67c1c957ac6e7611bdf605a6218aa86b0eebeb8be58b70ae85ad7d73dc" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -6092,7 +6097,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.72", + "syn 2.0.79", "toml 0.5.11", "uniffi_meta", ] @@ -6331,7 +6336,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -6365,7 +6370,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6398,14 +6403,14 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -6447,9 +6452,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -6503,6 +6508,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6653,18 +6688,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -6679,16 +6705,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "ws_stream_wasm" version = "0.7.4" @@ -6752,7 +6768,7 @@ version = "0.0.1" dependencies = [ "async-stream", "futures", - "reqwest 0.12.5", + "reqwest 0.12.8", "serde", "serde_json", "thiserror", @@ -6795,7 +6811,7 @@ dependencies = [ "ethers", "getrandom", "hex", - "k256 0.13.3", + "k256 0.13.4", "rand", "rand_chacha", "rustc-hex", @@ -6870,10 +6886,12 @@ dependencies = [ "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", + "openssl", + "openssl-sys", "parking_lot 0.12.3", "prost", "rand", - "reqwest 0.12.5", + "reqwest 0.12.8", "serde", "serde_json", "sha2 0.10.8", @@ -6988,7 +7006,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] @@ -7008,7 +7026,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f38a6b981..ce8e1106e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,11 @@ wasm-bindgen = "=0.2.92" gloo-timers = "0.3" web-sys = "0.3" js-sys = "0.3" +# NOTE: A regression in openssl-sys exists where libatomic is dynamically linked +# for i686-linux-android targets. https://github.com/sfackler/rust-openssl/issues/2163 +openssl-sys = "=0.9.92" +openssl = "=0.10.57" +libsqlite3-sys = { version = "0.29", features = ["bundled-sqlcipher-vendored-openssl" ] } # Internal Crate Dependencies xmtp_cryptography = { path = "xmtp_cryptography" } @@ -75,8 +80,29 @@ xmtp_id = { path = "xmtp_id" } xmtp_mls = { path = "xmtp_mls" } xmtp_proto = { path = "xmtp_proto" } +[profile.dev] +incremental = true + +[profile.test] +incremental = true + [profile.release] opt-level = "s" +panic = 'abort' +lto = true + +[profile.release.package.bindings_node] +strip = "symbols" + +# NOTE: The release profile reduces bundle size from 230M to 41M - may have performance impliciations +# https://stackoverflow.com/a/54842093 +[profile.release.package.xmtpv3] +codegen-units = 1 # Reduce number of codegen units to increase optimizations +opt-level = 'z' # Optimize for size +strip = true # Strip symbols from binary* + +[profile.release.package.bindings_wasm] +opt-level = "s" # patch needed until some items # are made public for third-party dependencies: https://github.com/diesel-rs/diesel/pull/4236 @@ -86,4 +112,3 @@ diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-repla diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } diesel-wasm-sqlite = { git = "https://github.com/xmtp/diesel-wasm-sqlite", branch = "main" } - diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index 6a5786dbc..aefb3e62c 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -22,14 +22,6 @@ xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } xmtp_user_preferences = { path = "../xmtp_user_preferences" } xmtp_v2 = { path = "../xmtp_v2" } -# NOTE: A regression in openssl-sys exists where libatomic is dynamically linked -# for i686-linux-android targets. https://github.com/sfackler/rust-openssl/issues/2163 -# -# This is fixed in the openssl-sys fork at -# https://github.com/xmtp/rust-openssl on the branch clone-v0.9.92, which is pinned -# to that version. Once this is addressed upstream we can remove the patch. -[patch.crates-io] -openssl-sys = { git = "https://github.com/xmtp/rust-openssl.git", branch = "clone-v0.9.92" } [build-dependencies] uniffi = { version = "0.28.0", features = ["build"] } @@ -46,12 +38,3 @@ tokio-test = "0.4" uniffi = { version = "0.28.0", features = ["bindgen-tests"] } uuid = { version = "1.9", features = ["v4", "fast-rng"] } xmtp_mls = { path = "../xmtp_mls", features = ["test-utils"] } - -# NOTE: The release profile reduces bundle size from 230M to 41M - may have performance impliciations -# https://stackoverflow.com/a/54842093 -[profile.release] -codegen-units = 1 # Reduce number of codegen units to increase optimizations -lto = true # Enable link-time optimization -opt-level = 'z' # Optimize for size -panic = 'abort' # Abort on panic -strip = true # Strip symbols from binary* diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml index 695a9b0f7..cb3617eaa 100644 --- a/bindings_node/Cargo.toml +++ b/bindings_node/Cargo.toml @@ -27,9 +27,5 @@ xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } [build-dependencies] napi-build = "2.0.1" -[profile.release] -lto = true -strip = "symbols" - [package.metadata.cross.build.env] volumes = ["__LIB12_DEP=../"] diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 9346fe1b0..31ef2be4f 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -19,9 +19,6 @@ xmtp_mls = { path = "../xmtp_mls", features = ["message-history"] } [dev-dependencies] wasm-bindgen-test.workspace = true -[profile.release] -opt-level = "s" - [build] target = "wasm32-unknown-unknown" diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 7b68543ad..6f471f52f 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -63,7 +63,9 @@ criterion = { version = "0.5", features = ["html_reports", "async_tokio"], optio [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # Native Dependencies -libsqlite3-sys = { version = "0.29.0", features = ["bundled-sqlcipher-vendored-openssl" ] } +libsqlite3-sys = { workspace = true } +openssl-sys.workspace = true +openssl.workspace = true diesel = { workspace = true, features = [ "r2d2", "returning_clauses_for_sqlite_3_35", From a6d5f416b1960e8cbb43436dfadeb77061b28812 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 18:43:03 -0400 Subject: [PATCH 49/97] exclude crates from workspace tests tests --- .github/workflows/test-http-api.yml | 2 +- .github/workflows/test-workspace.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-http-api.yml b/.github/workflows/test-http-api.yml index 22cf3e268..9ff158a65 100644 --- a/.github/workflows/test-http-api.yml +++ b/.github/workflows/test-http-api.yml @@ -41,4 +41,4 @@ jobs: - name: Install nextest uses: taiki-e/install-action@nextest - name: Run cargo nextest on main workspace - run: cargo nextest run --workspace --exclude xmtp_api_grpc --features http-api --test-threads 2 + run: cargo nextest run --workspace --exclude xmtp_api_grpc,xmtpv3,bindings_node --features http-api --test-threads 2 diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index 7c006d02f..d45b453d1 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -41,4 +41,4 @@ jobs: - name: Install nextest uses: taiki-e/install-action@nextest - name: Run cargo nextest on main workspace - run: cargo nextest run --test-threads 2 + run: cargo nextest run --test-threads 2 --exclude xmtpv3,bindings_node From dc1234f0db8dd782528a19e29c2ddb9de5551bd2 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 18:50:34 -0400 Subject: [PATCH 50/97] fix workflows --- .github/workflows/test-http-api.yml | 2 +- .github/workflows/test-workspace.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-http-api.yml b/.github/workflows/test-http-api.yml index 9ff158a65..6bdb3d80e 100644 --- a/.github/workflows/test-http-api.yml +++ b/.github/workflows/test-http-api.yml @@ -41,4 +41,4 @@ jobs: - name: Install nextest uses: taiki-e/install-action@nextest - name: Run cargo nextest on main workspace - run: cargo nextest run --workspace --exclude xmtp_api_grpc,xmtpv3,bindings_node --features http-api --test-threads 2 + run: cargo nextest run --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --features http-api --test-threads 2 diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index d45b453d1..9f2f2574c 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -41,4 +41,4 @@ jobs: - name: Install nextest uses: taiki-e/install-action@nextest - name: Run cargo nextest on main workspace - run: cargo nextest run --test-threads 2 --exclude xmtpv3,bindings_node + run: cargo nextest run --workspace --test-threads 2 --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm From 3ea09351d2494009fe5d8c8a344830473375d3e5 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 19:21:06 -0400 Subject: [PATCH 51/97] enable incremental compilation for validation service in CI --- .github/workflows/test-workspace.yml | 4 +++- dev/build_validation_service_local | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index 9f2f2574c..3343dfee6 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -37,7 +37,9 @@ jobs: workspaces: | . - name: Start Docker containers - run: dev/up + run: | + dev/build_validation_service_local + dev/docker/up - name: Install nextest uses: taiki-e/install-action@nextest - name: Run cargo nextest on main workspace diff --git a/dev/build_validation_service_local b/dev/build_validation_service_local index 95c18f581..f54dda1ac 100755 --- a/dev/build_validation_service_local +++ b/dev/build_validation_service_local @@ -10,7 +10,7 @@ fi rustup target add x86_64-unknown-linux-gnu export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc -cargo build --release --package mls_validation_service --target x86_64-unknown-linux-gnu +CARGO_INCREMENTAL=1 cargo build --release --package mls_validation_service --target x86_64-unknown-linux-gnu mkdir -p .cache cp -f ./target/x86_64-unknown-linux-gnu/release/mls-validation-service ./.cache/mls-validation-service -docker build --platform=linux/amd64 -t xmtp/mls-validation-service:latest -f ./dev/validation_service/local.Dockerfile . \ No newline at end of file +docker build --platform=linux/amd64 -t xmtp/mls-validation-service:latest -f ./dev/validation_service/local.Dockerfile . From de1e2149809d0d7f305499878605f7013c72d6f8 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 19:40:01 -0400 Subject: [PATCH 52/97] try incremenental --- .github/workflows/test-workspace.yml | 1 + dev/build_validation_service_local | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index 3343dfee6..4eda06be7 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -20,6 +20,7 @@ on: - "rust-toolchain" env: CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 1 jobs: test: name: Test diff --git a/dev/build_validation_service_local b/dev/build_validation_service_local index f54dda1ac..8f67e3402 100755 --- a/dev/build_validation_service_local +++ b/dev/build_validation_service_local @@ -10,7 +10,7 @@ fi rustup target add x86_64-unknown-linux-gnu export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc -CARGO_INCREMENTAL=1 cargo build --release --package mls_validation_service --target x86_64-unknown-linux-gnu +CARGO_INCREMENTAL=1 cargo build --package mls_validation_service --target x86_64-unknown-linux-gnu mkdir -p .cache cp -f ./target/x86_64-unknown-linux-gnu/release/mls-validation-service ./.cache/mls-validation-service docker build --platform=linux/amd64 -t xmtp/mls-validation-service:latest -f ./dev/validation_service/local.Dockerfile . From 11e0166d25678b1d79827592a68bd5494887a187 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 19:44:46 -0400 Subject: [PATCH 53/97] incremental --- .github/workflows/test-workspace.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index 4eda06be7..2caf8cd3b 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -34,6 +34,8 @@ jobs: uses: foundry-rs/foundry-toolchain@v1 - name: Cache uses: Swatinem/rust-cache@v2 + env: + CARGO_INCREMENTAL: 1 with: workspaces: | . From ed66e03b8435de101cae97254d64ed6f05797e7d Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 19:46:11 -0400 Subject: [PATCH 54/97] ci --- dev/build_validation_service_local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/build_validation_service_local b/dev/build_validation_service_local index 8f67e3402..f54dda1ac 100755 --- a/dev/build_validation_service_local +++ b/dev/build_validation_service_local @@ -10,7 +10,7 @@ fi rustup target add x86_64-unknown-linux-gnu export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc -CARGO_INCREMENTAL=1 cargo build --package mls_validation_service --target x86_64-unknown-linux-gnu +CARGO_INCREMENTAL=1 cargo build --release --package mls_validation_service --target x86_64-unknown-linux-gnu mkdir -p .cache cp -f ./target/x86_64-unknown-linux-gnu/release/mls-validation-service ./.cache/mls-validation-service docker build --platform=linux/amd64 -t xmtp/mls-validation-service:latest -f ./dev/validation_service/local.Dockerfile . From 843dab5c3685fdc53f429e3ec1f86a82b9d3c565 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 11:56:42 -0400 Subject: [PATCH 55/97] fix incremental +_ profiles --- .github/workflows/test-workspace.yml | 3 --- Cargo.toml | 11 ++++++----- dev/build_validation_service_local | 2 +- xmtp_mls/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index 2caf8cd3b..3343dfee6 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -20,7 +20,6 @@ on: - "rust-toolchain" env: CARGO_TERM_COLOR: always - CARGO_INCREMENTAL: 1 jobs: test: name: Test @@ -34,8 +33,6 @@ jobs: uses: foundry-rs/foundry-toolchain@v1 - name: Cache uses: Swatinem/rust-cache@v2 - env: - CARGO_INCREMENTAL: 1 with: workspaces: | . diff --git a/Cargo.toml b/Cargo.toml index ce8e1106e..61590654d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,12 +81,12 @@ xmtp_mls = { path = "xmtp_mls" } xmtp_proto = { path = "xmtp_proto" } [profile.dev] -incremental = true - -[profile.test] -incremental = true +# Disabling debug info speeds up builds a bunch, +# and we don't rely on it for debugging that much. +debug = 0 [profile.release] +incremental = true opt-level = "s" panic = 'abort' lto = true @@ -98,10 +98,11 @@ strip = "symbols" # https://stackoverflow.com/a/54842093 [profile.release.package.xmtpv3] codegen-units = 1 # Reduce number of codegen units to increase optimizations -opt-level = 'z' # Optimize for size +opt-level = 'z' # Optimize for size + loop vectorization strip = true # Strip symbols from binary* [profile.release.package.bindings_wasm] +# optimize for binary size opt-level = "s" # patch needed until some items diff --git a/dev/build_validation_service_local b/dev/build_validation_service_local index f54dda1ac..d3f05ae58 100755 --- a/dev/build_validation_service_local +++ b/dev/build_validation_service_local @@ -10,7 +10,7 @@ fi rustup target add x86_64-unknown-linux-gnu export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc -CARGO_INCREMENTAL=1 cargo build --release --package mls_validation_service --target x86_64-unknown-linux-gnu +cargo build --release --package mls_validation_service --target x86_64-unknown-linux-gnu mkdir -p .cache cp -f ./target/x86_64-unknown-linux-gnu/release/mls-validation-service ./.cache/mls-validation-service docker build --platform=linux/amd64 -t xmtp/mls-validation-service:latest -f ./dev/validation_service/local.Dockerfile . diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 6f471f52f..1cb6c6b15 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -91,8 +91,8 @@ tokio = { workspace = true, features = ["macros", "rt"] } openmls = { workspace = true, features = ["test-utils", "js"] } gloo-timers = { workspace = true, features = ["futures"] } wasm-bindgen-futures.workspace = true - web-sys.workspace = true + [dev-dependencies] ethers.workspace = true mockall = "0.13.0" From 98a41ad54c88b1ff85cdac8825d82c45838c96c4 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 14:45:40 -0400 Subject: [PATCH 56/97] dependency cleaning / profile optimization --- Cargo.lock | 71 +++++++++---------------------- Cargo.toml | 19 +++++++-- bindings_ffi/Cargo.toml | 11 +++-- bindings_node/Cargo.toml | 8 +--- bindings_wasm/Cargo.toml | 3 -- mls_validation_service/Cargo.toml | 2 +- xmtp_api_grpc/Cargo.toml | 7 ++- xmtp_id/Cargo.toml | 4 +- xmtp_mls/Cargo.toml | 13 +++--- xmtp_mls/src/subscriptions.rs | 3 +- xmtp_mls/src/utils/bench.rs | 4 +- xmtp_user_preferences/Cargo.toml | 4 +- 12 files changed, 61 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15e1addc6..309ff4faf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2559,6 +2559,19 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.30", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -3312,16 +3325,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -3608,12 +3611,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "p256" version = "0.13.2" @@ -4349,10 +4346,12 @@ dependencies = [ "http-body 0.4.6", "hyper 0.14.30", "hyper-rustls 0.24.2", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -4364,6 +4363,7 @@ dependencies = [ "sync_wrapper 0.1.2", "system-configuration 0.5.1", "tokio", + "tokio-native-tls", "tokio-rustls 0.24.1", "tower-service", "url", @@ -4391,7 +4391,7 @@ dependencies = [ "http-body-util", "hyper 1.4.1", "hyper-rustls 0.27.3", - "hyper-tls", + "hyper-tls 0.6.0", "hyper-util", "ipnet", "js-sys", @@ -5603,19 +5603,6 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "tokio-test" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" -dependencies = [ - "async-stream", - "bytes", - "futures-core", - "tokio", - "tokio-stream", -] - [[package]] name = "tokio-tungstenite" version = "0.20.1" @@ -5624,8 +5611,10 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", + "native-tls", "rustls 0.21.12", "tokio", + "tokio-native-tls", "tokio-rustls 0.24.1", "tungstenite 0.20.1", "webpki-roots 0.25.4", @@ -5809,7 +5798,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", - "valuable", ] [[package]] @@ -5833,17 +5821,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -5851,7 +5828,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", - "nu-ansi-term", "once_cell", "regex", "sharded-slab", @@ -5859,7 +5835,6 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log", ] [[package]] @@ -5902,6 +5877,7 @@ dependencies = [ "http 0.2.12", "httparse", "log", + "native-tls", "rand", "rustls 0.21.12", "sha1", @@ -6205,12 +6181,6 @@ dependencies = [ "rand", ] -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "value-bag" version = "1.9.0" @@ -6970,7 +6940,6 @@ dependencies = [ "thiserror", "thread-id", "tokio", - "tokio-test", "uniffi", "uuid 1.10.0", "xmtp_api_grpc", diff --git a/Cargo.toml b/Cargo.toml index 61590654d..d20335d5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ wasm-timer = "0.2" ctor = "0.2" ed25519 = "2.2.3" ed25519-dalek = "2.1.1" -ethers = "2.0.11" +ethers = { version = "2.0", default-features = false } futures = "0.3.30" futures-core = "0.3.30" getrandom = { version = "0.2", default-features = false } @@ -47,17 +47,19 @@ pbjson-types = "0.7.0" prost = "^0.13" prost-types = "^0.13" rand = "0.8.5" +uuid = "1.10" +base64 = "0.22" regex = "1.10.4" rustc-hex = "2.1.0" -serde = "1.0" -serde_json = "1.0" +serde = { version = "1.0", default-features = false } +serde_json = { version = "1.0", default-features = false } sha2 = "0.10.8" thiserror = "1.0" tls_codec = "0.4.1" tokio = { version = "1.35.1", default-features = false } tonic = "^0.12" tracing = { version = "0.1", features = ["log", "release_max_level_debug"] } -tracing-subscriber = "0.3" +tracing-subscriber = { version = "0.3", default-features = false } diesel = { version = "2.2", default-features = false } diesel-wasm-sqlite = "0.0.1" diesel_migrations = { version = "2.2", default-features = false } @@ -85,10 +87,18 @@ xmtp_proto = { path = "xmtp_proto" } # and we don't rely on it for debugging that much. debug = 0 +# Setting opt-level to 3 for proc macros/build scripts +# speeds up buildtime +[profile.dev.build-override] +opt-level = 3 + [profile.release] incremental = true opt-level = "s" panic = 'abort' + +[profile.release-wasm] +inherits = "release" lto = true [profile.release.package.bindings_node] @@ -102,6 +112,7 @@ opt-level = 'z' # Optimize for size + loop vectorization strip = true # Strip symbols from binary* [profile.release.package.bindings_wasm] +inherits = "release-wasm" # optimize for binary size opt-level = "s" diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index aefb3e62c..5797871ac 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -13,7 +13,7 @@ parking_lot.workspace = true thiserror.workspace = true thread-id = "4.2.1" tokio = { workspace = true, features = ["macros"] } -uniffi = { version = "0.28.0", features = ["tokio", "cli"] } +uniffi = { version = "0.28.0", default-features = false, features = ["tokio", "cli"] } xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } @@ -31,10 +31,9 @@ name = "ffi-uniffi-bindgen" path = "src/bin.rs" [dev-dependencies] -ethers = "2.0.13" -rand = "0.8.5" -tokio = { version = "1.28.1", features = ["full"] } -tokio-test = "0.4" +ethers = { workspace = true, features = ["openssl"] } +rand.workspace = true +tokio = { workspace = true, features = ["rt-multi-thread"] } uniffi = { version = "0.28.0", features = ["bindgen-tests"] } -uuid = { version = "1.9", features = ["v4", "fast-rng"] } +uuid = { workspace = true, features = ["v4", "fast-rng"] } xmtp_mls = { path = "../xmtp_mls", features = ["test-utils"] } diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml index cb3617eaa..39f6781d0 100644 --- a/bindings_node/Cargo.toml +++ b/bindings_node/Cargo.toml @@ -10,14 +10,10 @@ crate-type = ["cdylib"] # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix hex.workspace = true tracing.workspace = true -napi = { version = "2.12.2", default-features = false, features = [ - "napi4", - "napi6", - "async", -] } +napi = { version = "2.12.2", default-features = false, features = ["napi6", "async"] } napi-derive = "2.12.2" prost.workspace = true -tokio = { workspace = true, features = ["full"]} +tokio = { workspace = true, features = ["sync"]} xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 31ef2be4f..746b79103 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -19,6 +19,3 @@ xmtp_mls = { path = "../xmtp_mls", features = ["message-history"] } [dev-dependencies] wasm-bindgen-test.workspace = true -[build] -target = "wasm32-unknown-unknown" - diff --git a/mls_validation_service/Cargo.toml b/mls_validation_service/Cargo.toml index 11d5cf2bd..26e2fa3f9 100644 --- a/mls_validation_service/Cargo.toml +++ b/mls_validation_service/Cargo.toml @@ -15,7 +15,7 @@ hex = { workspace = true } openmls = { workspace = true } openmls_rust_crypto = { workspace = true } thiserror.workspace = true -tokio = { workspace = true, features = ["full"] } +tokio = { workspace = true, features = ["rt-multi-thread", "signal"] } tonic = { workspace = true } warp = "0.3.6" xmtp_id.workspace = true diff --git a/xmtp_api_grpc/Cargo.toml b/xmtp_api_grpc/Cargo.toml index 017de33b1..279e1ff2c 100644 --- a/xmtp_api_grpc/Cargo.toml +++ b/xmtp_api_grpc/Cargo.toml @@ -5,13 +5,12 @@ version.workspace = true [dependencies] async-stream.workspace = true -base64 = "0.22" +base64.workspace = true futures.workspace = true hex.workspace = true prost = { workspace = true, features = ["prost-derive"] } -tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } +tokio = { workspace = true, features = ["macros", "time"] } tonic = { workspace = true, features = [ - "tls", "tls-native-roots", "tls-webpki-roots", ] } @@ -20,4 +19,4 @@ xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } xmtp_v2 = { path = "../xmtp_v2" } [dev-dependencies] -uuid = { version = "1.3.1", features = ["v4"] } +uuid = { workspace = true, features = ["v4"] } diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index e66a42fce..0b803a41d 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -8,7 +8,6 @@ url = "2.5.2" async-trait.workspace = true chrono.workspace = true ed25519-dalek = { workspace = true, features = ["digest"] } -ethers.workspace = true futures.workspace = true hex.workspace = true tracing.workspace = true @@ -28,12 +27,13 @@ wasm-timer.workspace = true [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2", features = ["js"] } openmls = { workspace = true, features = ["js"] } +ethers = { workspace = true, features = ["rustls"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] openmls.workspace = true +ethers = { workspace = true, features = ["openssl"] } [dev-dependencies] -ed25519-dalek = { workspace = true, features = ["digest"] } xmtp_v2 = { path = "../xmtp_v2" } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 1cb6c6b15..e7123cad7 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -14,7 +14,7 @@ test-utils = ["dep:xmtp_api_grpc", "xmtp_id/test-utils", "tracing-subscriber"] bench = ["test-utils", "indicatif", "tracing-subscriber", "anyhow", "tracing-flame", "once_cell", "dep:xmtp_api_grpc", "criterion"] update-schema = ["toml"] http-api = ["xmtp_api_http"] -message-history = [] +message-history = ["dep:reqwest"] [dependencies] parking_lot.workspace = true @@ -35,22 +35,22 @@ rand = { workspace = true } serde = { workspace = true } serde_json.workspace = true thiserror = { workspace = true } -tokio-stream = { version = "0.1", features = ["sync"] } +tokio-stream = { version = "0.1", default-features = false, features = ["sync"] } async-trait.workspace = true futures.workspace = true -reqwest = { version = "0.12.4", features = ["stream"] } dyn-clone = "1" wasm-timer.workspace = true # XMTP/Local xmtp_cryptography = { workspace = true } xmtp_id = { path = "../xmtp_id" } -xmtp_proto = { workspace = true, features = ["proto_full", "convert"] } +xmtp_proto = { workspace = true, features = ["convert"] } # Optional/Features toml = { version = "0.8.4", optional = true } # for tests outside of the wasm environment xmtp_api_http = { path = "../xmtp_api_http", optional = true } +reqwest = { version = "0.12.4", features = ["stream"], optional = true } # Test/Bench Utils tracing-subscriber = { workspace = true, features = ["env-filter"], optional = true } @@ -87,20 +87,20 @@ diesel = { workspace = true, features = [ diesel_migrations.workspace = true getrandom = { workspace = true, features = ["js"] } chrono = { workspace = true, features = ["wasmbind"] } -tokio = { workspace = true, features = ["macros", "rt"] } +tokio = { workspace = true, features = ["macros", "rt", "time"] } openmls = { workspace = true, features = ["test-utils", "js"] } gloo-timers = { workspace = true, features = ["futures"] } wasm-bindgen-futures.workspace = true web-sys.workspace = true [dev-dependencies] -ethers.workspace = true mockall = "0.13.0" xmtp_id = { path = "../xmtp_id", features = ["test-utils"] } anyhow.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +ethers = { workspace = true, features = ["openssl"] } xmtp_api_grpc = { path = "../xmtp_api_grpc" } tracing-subscriber.workspace = true tempfile = "3.5.0" @@ -108,6 +108,7 @@ mockito = "1.4.0" ctor.workspace = true [target.'cfg(target_arch = "wasm32")'.dev-dependencies] +ethers = { workspace = true, features = ["rustls"] } xmtp_api_http = { path = "../xmtp_api_http" } tracing-wasm = { version = "0.2" } diesel-wasm-sqlite = { workspace = true, features = ["unsafe-debug-query", "r2d2"] } diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 33a7056ba..794a01186 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -816,7 +816,8 @@ pub(crate) mod tests { closer.end(); } - #[tokio::test(flavor = "multi_thread")] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] async fn test_dm_streaming() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); diff --git a/xmtp_mls/src/utils/bench.rs b/xmtp_mls/src/utils/bench.rs index 99f833cae..5d89e405d 100644 --- a/xmtp_mls/src/utils/bench.rs +++ b/xmtp_mls/src/utils/bench.rs @@ -181,7 +181,7 @@ pub async fn create_identities_if_dont_exist( ) -> Vec { match load_identities(is_dev_network) { Ok(identities) => { - tracing::info!( + log::info!( "Found generated identities at {}, checking for existence on backend...", file_path(is_dev_network) ); @@ -195,7 +195,7 @@ pub async fn create_identities_if_dont_exist( _ => (), } - tracing::info!( + log::info!( "Could not find any identitites to load, creating new identitites \n Beware, this fills $TMPDIR with ~10GBs of identities" ); diff --git a/xmtp_user_preferences/Cargo.toml b/xmtp_user_preferences/Cargo.toml index 7f7ba0f27..1af51954e 100644 --- a/xmtp_user_preferences/Cargo.toml +++ b/xmtp_user_preferences/Cargo.toml @@ -4,7 +4,7 @@ name = "xmtp_user_preferences" version.workspace = true [dependencies] -base64 = "0.22.1" +base64.workspace = true # Need to include this as a dep or compile will fail because of a version mismatch prost = { workspace = true, features = ["prost-derive"] } xmtp_proto = { path = "../xmtp_proto", features = ["xmtp-message_contents"] } @@ -15,4 +15,4 @@ libsecp256k1 = { version = "0.7.1", default-features = false, features = [ "hmac", "static-context", ] } -rand = "0.8.5" +rand.workspace = true From ab48d3531b7cbb1807253d68cb6b7e9d4541f30d Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 15:38:46 -0400 Subject: [PATCH 57/97] add some documentation --- Cargo.toml | 5 +++-- xmtp_mls/src/storage/encrypted_store/consent_record.rs | 5 ++++- xmtp_mls/src/storage/encrypted_store/mod.rs | 10 ++++++++++ xmtp_mls/src/storage/encrypted_store/native.rs | 1 + 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index db6dc3c54..9ce93111e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,7 +98,7 @@ incremental = true opt-level = "s" panic = 'abort' -[profile.release-wasm] +[profile.release-with-lto] inherits = "release" lto = true @@ -108,12 +108,13 @@ strip = "symbols" # NOTE: The release profile reduces bundle size from 230M to 41M - may have performance impliciations # https://stackoverflow.com/a/54842093 [profile.release.package.xmtpv3] +inherits = "release-with-lto" codegen-units = 1 # Reduce number of codegen units to increase optimizations opt-level = 'z' # Optimize for size + loop vectorization strip = true # Strip symbols from binary* [profile.release.package.bindings_wasm] -inherits = "release-wasm" +inherits = "release-with-lto" # optimize for binary size opt-level = "s" diff --git a/xmtp_mls/src/storage/encrypted_store/consent_record.rs b/xmtp_mls/src/storage/encrypted_store/consent_record.rs index 02705e1fc..eed989729 100644 --- a/xmtp_mls/src/storage/encrypted_store/consent_record.rs +++ b/xmtp_mls/src/storage/encrypted_store/consent_record.rs @@ -157,6 +157,8 @@ where #[cfg(test)] mod tests { use crate::storage::encrypted_store::tests::with_connection; + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); use super::*; @@ -172,7 +174,8 @@ mod tests { } } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn insert_and_read() { with_connection(|conn| { let inbox_id = "inbox_1"; diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 9567579c2..9fcf7a25a 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -92,6 +92,7 @@ pub trait XmtpDb { + Send; type TransactionManager: diesel::connection::TransactionManager; + /// Validate a connection is as expected fn validate(&self, _opts: &StorageOption) -> Result<(), StorageError> { Ok(()) } @@ -99,8 +100,10 @@ pub trait XmtpDb { /// Returns the Connection implementation for this Database fn conn(&self) -> Result, StorageError>; + /// Reconnect to the database fn reconnect(&self) -> Result<(), StorageError>; + /// Release connection to the database, closing it fn release_connection(&self) -> Result<(), StorageError>; } @@ -109,10 +112,12 @@ pub type EncryptedMessageStore = self::private::EncryptedMessageStore Result { Self::new_database(opts, Some(enc_key)) } + /// Create a new, unencrypted database pub async fn new_unencrypted(opts: StorageOption) -> Result { Self::new_database(opts, None) } @@ -155,6 +160,8 @@ impl EncryptedMessageStore { } } + +/// Shared Code between WebAssembly and Native using the `XmtpDb` trait #[doc(hidden)] pub mod private { use super::*; @@ -189,6 +196,7 @@ pub mod private { Ok::<_, StorageError>(()) } + /// Pulls a new connection from the store pub fn conn( &self, ) -> Result::Connection>, StorageError> { @@ -312,10 +320,12 @@ pub mod private { } } + /// Release connection to the database, closing it pub fn release_connection(&self) -> Result<(), StorageError> { self.db.release_connection() } + /// Reconnect to the database pub fn reconnect(&self) -> Result<(), StorageError> { self.db.reconnect() } diff --git a/xmtp_mls/src/storage/encrypted_store/native.rs b/xmtp_mls/src/storage/encrypted_store/native.rs index 7f442371f..4d4b36421 100644 --- a/xmtp_mls/src/storage/encrypted_store/native.rs +++ b/xmtp_mls/src/storage/encrypted_store/native.rs @@ -1,3 +1,4 @@ +/// Native SQLite connection using SqlCipher use crate::storage::encrypted_store::DbConnectionPrivate; use crate::storage::StorageError; pub use diesel::sqlite::SqliteConnection; From bea4c5b7372c0567dee6cca5867660ca8580bc83 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 15:43:37 -0400 Subject: [PATCH 58/97] remove doc hidden --- xmtp_mls/src/storage/encrypted_store/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 9fcf7a25a..5aad4fc5f 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -162,7 +162,6 @@ impl EncryptedMessageStore { /// Shared Code between WebAssembly and Native using the `XmtpDb` trait -#[doc(hidden)] pub mod private { use super::*; use diesel::connection::SimpleConnection; From c618349433f6e6f7cdd53a79cdeb0f1e87467d76 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 17:16:56 -0400 Subject: [PATCH 59/97] add CI workflow for wasm --- .github/workflows/test-webassembly.yml | 48 +++++++++++++++++++++ xmtp_id/Cargo.toml | 1 + xmtp_id/src/associations/test_utils.rs | 1 + xmtp_id/src/lib.rs | 3 +- xmtp_mls/src/storage/encrypted_store/mod.rs | 1 - 5 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/test-webassembly.yml diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml new file mode 100644 index 000000000..b06699c42 --- /dev/null +++ b/.github/workflows/test-webassembly.yml @@ -0,0 +1,48 @@ +name: Test Workspace with WebAssembly +on: + push: + branches: + - main + pull_request: + # only run tests when related changes are made + paths: + - ".github/workflows/test-webassembly.yml" + - "xmtp_mls/src/**" + - "xmtp_id/src/**" + - "xmtp_api_http/src/**" + - "Cargo.toml" + - "Cargo.lock" + - "rust-toolchain" +jobs: + test: + name: Test + # running with macos since it contains the safari driver + runs-on: warp-ubuntu-latest-x64-16x + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - name: Update rust toolchains + run: rustup update + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: Cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + . + - name: test `xmtp_mls` + run: | + wasm-pack test --chrome --release -- --manifest-path ./xmtp_mls/Cargo.toml -- \ + --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ + --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ + --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ + --skip xmtp_mls::storage::encrypted_store::group::tests::test_find_groups \ + --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated + working-directory: ./ + - name: test `xmtp_id` + run: wasm-pack test --headless --chrome -- --manifest-path ./xmtp_id/Cargo.toml + working-directory: ./ + - name: test `xmtp_api_http` + run: wasm-pack test --headless --chrome -- --manifest-path ./xmtp_api_http/Cargo.toml + working-directory: ./ diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index d65bffc6f..b75b45609 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -37,6 +37,7 @@ ethers = { workspace = true, features = ["openssl"] } [dev-dependencies] xmtp_v2 = { path = "../xmtp_v2" } +ed25519-dalek = { workspace = true, features = ["digest", "rand_core"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test.workspace = true diff --git a/xmtp_id/src/associations/test_utils.rs b/xmtp_id/src/associations/test_utils.rs index c7fbdd4c2..2b8418db7 100644 --- a/xmtp_id/src/associations/test_utils.rs +++ b/xmtp_id/src/associations/test_utils.rs @@ -1,3 +1,4 @@ +#![allow(clippy::unwrap_used)] use super::{ builder::SignatureRequest, unsigned_actions::UnsignedCreateInbox, diff --git a/xmtp_id/src/lib.rs b/xmtp_id/src/lib.rs index 1156897fa..7c2955a38 100644 --- a/xmtp_id/src/lib.rs +++ b/xmtp_id/src/lib.rs @@ -1,3 +1,4 @@ +#[warn(clippy::unwrap_used)] pub mod associations; pub mod constants; pub mod scw_verifier; @@ -60,7 +61,6 @@ impl InboxOwner for LocalWallet { #[cfg(test)] mod tests { - use super::*; use ethers::contract::abigen; #[cfg(target_arch = "wasm32")] @@ -81,6 +81,7 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] #[cfg(not(target_arch = "wasm32"))] async fn test_is_smart_contract() { + use super::*; use scw_verifier::tests::with_smart_contracts; with_smart_contracts(|anvil, _provider, _client, smart_contracts| async move { diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 5aad4fc5f..5bff8d609 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -160,7 +160,6 @@ impl EncryptedMessageStore { } } - /// Shared Code between WebAssembly and Native using the `XmtpDb` trait pub mod private { use super::*; From 0fd55156d72af769db6f4591f1d3fc557a8d1a34 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 17:19:28 -0400 Subject: [PATCH 60/97] fix ci path --- .github/workflows/test-webassembly.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index b06699c42..c1282aa1f 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -33,16 +33,16 @@ jobs: . - name: test `xmtp_mls` run: | - wasm-pack test --chrome --release -- --manifest-path ./xmtp_mls/Cargo.toml -- \ + wasm-pack test --chrome --release -- --manifest-path ./Cargo.toml -- \ --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ --skip xmtp_mls::storage::encrypted_store::group::tests::test_find_groups \ --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated - working-directory: ./ + working-directory: ./xmtp_mls - name: test `xmtp_id` - run: wasm-pack test --headless --chrome -- --manifest-path ./xmtp_id/Cargo.toml - working-directory: ./ + run: wasm-pack test --headless --chrome -- --manifest-path ./Cargo.toml + working-directory: ./xmtp_id - name: test `xmtp_api_http` - run: wasm-pack test --headless --chrome -- --manifest-path ./xmtp_api_http/Cargo.toml - working-directory: ./ + run: wasm-pack test --headless --chrome -- --manifest-path ./Cargo.toml + working-directory: ./xmtp_api_http From 4d507020b61aa01fad8663f0a1fc6e23f31c6d87 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 17:22:09 -0400 Subject: [PATCH 61/97] headless --- .github/workflows/test-webassembly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index c1282aa1f..f0653a253 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -33,7 +33,7 @@ jobs: . - name: test `xmtp_mls` run: | - wasm-pack test --chrome --release -- --manifest-path ./Cargo.toml -- \ + wasm-pack test --chrome --headless --release -- --manifest-path ./Cargo.toml -- \ --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ From 0131ebef3f738f84dd8e025b57735eae3b71174f Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 17:26:23 -0400 Subject: [PATCH 62/97] docker containers --- .github/workflows/test-webassembly.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index f0653a253..bf8c120b2 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -31,6 +31,10 @@ jobs: with: workspaces: | . + - name: Start Docker containers + run: | + dev/build_validation_service_local + dev/docker/up - name: test `xmtp_mls` run: | wasm-pack test --chrome --headless --release -- --manifest-path ./Cargo.toml -- \ From a6a37c3b7f342443e7a777288545fc31a7a5af98 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 3 Oct 2024 20:12:33 -0400 Subject: [PATCH 63/97] enable wasm module for wasm32 --- xmtp_mls/src/utils/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index 5d4ac8bf7..b6d5728a7 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -43,7 +43,7 @@ pub mod id { } } -#[cfg(all(target_arch = "wasm32", test))] +#[cfg(any(target_arch = "wasm32", all(test, target_arch = "wasm32")))] pub mod wasm { use tokio::sync::OnceCell; static INIT: OnceCell<()> = OnceCell::const_new(); From e336e6464d9ee4dadfd7c183924733288840a7b9 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 4 Oct 2024 09:51:58 -0400 Subject: [PATCH 64/97] wasm init for test-utils feature --- xmtp_mls/Cargo.toml | 7 ++++--- xmtp_mls/src/utils/mod.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 363cff75c..ee2a48884 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -10,10 +10,10 @@ targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown", "aarch64-apple- [features] default = [] -test-utils = ["dep:xmtp_api_grpc", "xmtp_id/test-utils", "tracing-subscriber"] +test-utils = ["dep:xmtp_api_grpc", "xmtp_id/test-utils", "tracing-subscriber", "dep:xmtp_api_http", "dep:tracing-wasm", "dep:console_error_panic_hook"] bench = ["test-utils", "indicatif", "tracing-subscriber", "anyhow", "tracing-flame", "once_cell", "dep:xmtp_api_grpc", "criterion"] update-schema = ["toml"] -http-api = ["xmtp_api_http"] +http-api = ["dep:xmtp_api_http"] message-history = ["dep:reqwest"] [dependencies] @@ -48,9 +48,10 @@ xmtp_proto = { workspace = true, features = ["convert"] } # Optional/Features toml = { version = "0.8.4", optional = true } -# for tests outside of the wasm environment +tracing-wasm = { version = "0.2", optional = true } xmtp_api_http = { path = "../xmtp_api_http", optional = true } reqwest = { version = "0.12.4", features = ["stream"], optional = true } +console_error_panic_hook = { version = "0.1", optional = true } # Test/Bench Utils tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "ansi"], optional = true } diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index b6d5728a7..550b3be70 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -43,7 +43,7 @@ pub mod id { } } -#[cfg(any(target_arch = "wasm32", all(test, target_arch = "wasm32")))] +#[cfg(any(all(target_arch = "wasm32", feature = "test-utils"), all(test, target_arch = "wasm32")))] pub mod wasm { use tokio::sync::OnceCell; static INIT: OnceCell<()> = OnceCell::const_new(); From 00d1bca5cf2a300403992becbdc5b8c9d0716a53 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 4 Oct 2024 17:25:31 -0400 Subject: [PATCH 65/97] CI --- .cargo/config.toml | 2 + .github/workflows/test-webassembly.yml | 51 ++++++++---- Cargo.lock | 78 +++++++++++-------- Cargo.toml | 2 +- dev/test-wasm | 4 + xmtp_api_http/Cargo.toml | 2 - xmtp_api_http/src/lib.rs | 2 +- xmtp_api_http/src/util.rs | 2 +- xmtp_id/src/associations/unverified.rs | 6 +- .../src/associations/verified_signature.rs | 9 ++- xmtp_mls/src/api/mls.rs | 2 + xmtp_mls/src/client.rs | 1 + xmtp_mls/src/groups/validated_commit.rs | 1 - xmtp_mls/src/identity_updates.rs | 2 + .../encrypted_store/key_package_history.rs | 2 + xmtp_mls/src/utils/mod.rs | 10 ++- xmtp_mls/src/utils/test/mod.rs | 1 + 17 files changed, 118 insertions(+), 59 deletions(-) create mode 100644 .cargo/config.toml create mode 100755 dev/test-wasm diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000..4ec2f3b86 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.wasm32-unknown-unknown] +runner = 'wasm-bindgen-test-runner' diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index bf8c120b2..6582cd51a 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -13,19 +13,20 @@ on: - "Cargo.toml" - "Cargo.lock" - "rust-toolchain" +env: + CARGO_TERM_COLOR: always + WASM_BINDGEN_TEST_TIMEOUT: 120 + WASM_BINDGEN_TEST_ONLY_WEB: 1 jobs: test: name: Test # running with macos since it contains the safari driver - runs-on: warp-ubuntu-latest-x64-16x + runs-on: warp-macos-14-arm64-6x steps: - name: Checkout uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - name: Update rust toolchains - run: rustup update - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: Install wasm-bindgen-test-runner + run: cargo install wasm-bindgen-cli - name: Cache uses: Swatinem/rust-cache@v2 with: @@ -35,18 +36,38 @@ jobs: run: | dev/build_validation_service_local dev/docker/up - - name: test `xmtp_mls` + - name: Build WebAssembly Packages + run: cargo build --tests --release --target wasm32-unknown-unknown -p xmtp_id -p xmtp_mls -p xmtp_api_http --tests + - name: test with chrome run: | - wasm-pack test --chrome --headless --release -- --manifest-path ./Cargo.toml -- \ + cargo test --release -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ --skip xmtp_mls::storage::encrypted_store::group::tests::test_find_groups \ --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated - working-directory: ./xmtp_mls - - name: test `xmtp_id` - run: wasm-pack test --headless --chrome -- --manifest-path ./Cargo.toml - working-directory: ./xmtp_id - - name: test `xmtp_api_http` - run: wasm-pack test --headless --chrome -- --manifest-path ./Cargo.toml - working-directory: ./xmtp_api_http + working-directory: ./ + env: + CHROMEDRIVER: "$CHROMEWEBDRIVER" + - name: test with firefox + run: | + cargo test --release -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ + --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ + --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ + --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ + --skip xmtp_mls::storage::encrypted_store::group::tests::test_find_groups \ + --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated + working-directory: ./ + env: + GECKODRIVER: "$GECKOWEBDRIVER" + - name: test with safari + run: | + cargo test --release -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ + --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ + --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ + --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ + --skip xmtp_mls::storage::encrypted_store::group::tests::test_find_groups \ + --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated + working-directory: ./ + env: + SAFARIWEBDRIVER: "$SAFARIWEBDRIVER" diff --git a/Cargo.lock b/Cargo.lock index 26e6ff748..3f3816f8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -1179,7 +1179,7 @@ dependencies = [ [[package]] name = "diesel-wasm-sqlite" version = "0.0.1" -source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#c1c4da6abed5dc65f47a1cf99e3d9cdf600c320b" +source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#8f086680b6b14bf82e1c86d51ecbac8062d19182" dependencies = [ "diesel", "diesel_derives", @@ -2127,9 +2127,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -2539,7 +2539,7 @@ dependencies = [ "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls 0.23.13", + "rustls 0.23.14", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -2746,9 +2746,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is-terminal" @@ -2820,9 +2820,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -3107,6 +3107,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "minicov" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3410,9 +3420,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] @@ -4604,9 +4614,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "log", "once_cell", @@ -5603,7 +5613,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.13", + "rustls 0.23.14", "rustls-pki-types", "tokio", ] @@ -6303,11 +6313,12 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "serde", "serde_json", "wasm-bindgen-macro", @@ -6315,9 +6326,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -6330,9 +6341,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -6342,9 +6353,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6352,9 +6363,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -6365,18 +6376,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-bindgen-test" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" +checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" dependencies = [ "console_error_panic_hook", "js-sys", + "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -6385,9 +6397,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" +checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", @@ -6424,9 +6436,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 9ce93111e..da62a99a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ diesel_migrations = { version = "2.2", default-features = false } parking_lot = "0.12.3" wasm-bindgen-test = "0.3.42" wasm-bindgen-futures = "0.4" -wasm-bindgen = "=0.2.92" +wasm-bindgen = "=0.2.93" gloo-timers = "0.3" web-sys = "0.3" js-sys = "0.3" diff --git a/dev/test-wasm b/dev/test-wasm new file mode 100755 index 000000000..860b8a0a2 --- /dev/null +++ b/dev/test-wasm @@ -0,0 +1,4 @@ +#!/bin/bash +set -eou pipefail + +WASM_BINDGEN_TEST_ONLY_WEB=1 WASM_BINDGEN_TEST_TIMEOUT=120 CHROMEDRIVER="chromedriver" cargo test --target wasm32-unknown-unknown --release -p xmtp_mls -p xmtp_id -p xmtp_api_http -- --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error --skip xmtp_mls::storage::encrypted_store::group::tests::test_find_groups --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml index 66a6b2723..bd8540ba8 100644 --- a/xmtp_api_http/Cargo.toml +++ b/xmtp_api_http/Cargo.toml @@ -23,5 +23,3 @@ tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] tokio = { workspace = true, features = ["macros", "time"] } wasm-bindgen-test.workspace = true - - diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index 2aca0c736..323a7defa 100755 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -334,7 +334,7 @@ impl XmtpIdentityClient for XmtpHttpApiClient { // tests #[cfg(test)] -mod tests { +pub mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); use xmtp_proto::xmtp::mls::api::v1::KeyPackageUpload; diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index f2ce9be1c..2e8b4e761 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -117,7 +117,7 @@ pub fn create_grpc_stream_inner< } #[cfg(test)] -pub(crate) mod tests { +pub mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); diff --git a/xmtp_id/src/associations/unverified.rs b/xmtp_id/src/associations/unverified.rs index b9120758c..ebf2fbccb 100644 --- a/xmtp_id/src/associations/unverified.rs +++ b/xmtp_id/src/associations/unverified.rs @@ -376,6 +376,9 @@ impl UnverifiedLegacyDelegatedSignature { #[cfg(test)] mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::associations::{ generate_inbox_id, test_utils::rand_string, unsigned_actions::UnsignedCreateInbox, }; @@ -385,7 +388,8 @@ mod tests { UnverifiedRecoverableEcdsaSignature, UnverifiedSignature, }; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn create_identity_update() { let account_address = rand_string(); let nonce = 1; diff --git a/xmtp_id/src/associations/verified_signature.rs b/xmtp_id/src/associations/verified_signature.rs index e30f07ad4..b08209687 100644 --- a/xmtp_id/src/associations/verified_signature.rs +++ b/xmtp_id/src/associations/verified_signature.rs @@ -150,6 +150,9 @@ impl VerifiedSignature { #[cfg(test)] mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; use crate::{ associations::{ @@ -238,7 +241,8 @@ mod tests { .expect_err("should fail with incorrect verifying key"); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn validate_good_key_round_trip() { let proto_bytes = vec![ 10, 79, 8, 192, 195, 165, 174, 203, 153, 231, 213, 23, 26, 67, 10, 65, 4, 216, 84, 174, @@ -261,7 +265,8 @@ mod tests { assert_eq!(validated_key.account_address(), account_address); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn validate_malformed_key() { let proto_bytes = vec![ 10, 79, 8, 192, 195, 165, 174, 203, 153, 231, 213, 23, 26, 67, 10, 65, 4, 216, 84, 174, diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index d321197eb..22d453477 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -305,6 +305,7 @@ pub mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] async fn test_upload_key_package() { + tracing::debug!("test_upload_key_package"); let mut mock_api = MockApiClient::new(); let key_package = vec![1, 2, 3]; // key_package gets moved below but needs to be used for assertions later @@ -327,6 +328,7 @@ pub mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_fetch_key_packages() { + tracing::debug!("test_fetch_key_packages"); let mut mock_api = MockApiClient::new(); let installation_keys: Vec> = vec![vec![1, 2, 3], vec![4, 5, 6]]; mock_api.expect_fetch_key_packages().returning(move |_| { diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 1082efb3c..58bc98415 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -957,6 +957,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_mls_error() { + tracing::debug!("Test MLS Error"); let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let result = client .api_client diff --git a/xmtp_mls/src/groups/validated_commit.rs b/xmtp_mls/src/groups/validated_commit.rs index c259fd3f2..1155e335e 100644 --- a/xmtp_mls/src/groups/validated_commit.rs +++ b/xmtp_mls/src/groups/validated_commit.rs @@ -481,7 +481,6 @@ async fn extract_expected_diff<'diff, ApiClient: XmtpApi>( .map(|inbox_id| build_inbox(inbox_id, immutable_metadata, mutable_metadata)) .collect::>(); - tracing::debug!("\n\n------------------------GETTING INSTALLATION DIFF ------------------------------------\n\n"); let expected_installation_diff = client .get_installation_diff( conn, diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index b0695dcaa..b7a6549ac 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -500,6 +500,8 @@ async fn verify_updates( #[cfg(test)] pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::{ associations::{ diff --git a/xmtp_mls/src/storage/encrypted_store/key_package_history.rs b/xmtp_mls/src/storage/encrypted_store/key_package_history.rs index 4249aca35..7947abb0a 100644 --- a/xmtp_mls/src/storage/encrypted_store/key_package_history.rs +++ b/xmtp_mls/src/storage/encrypted_store/key_package_history.rs @@ -79,6 +79,8 @@ impl DbConnection { #[cfg(test)] mod tests { use crate::{storage::encrypted_store::tests::with_connection, utils::test::rand_vec}; + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index 550b3be70..19872e390 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -43,7 +43,10 @@ pub mod id { } } -#[cfg(any(all(target_arch = "wasm32", feature = "test-utils"), all(test, target_arch = "wasm32")))] +#[cfg(any( + all(target_arch = "wasm32", feature = "test-utils"), + all(test, target_arch = "wasm32") +))] pub mod wasm { use tokio::sync::OnceCell; static INIT: OnceCell<()> = OnceCell::const_new(); @@ -55,7 +58,10 @@ pub mod wasm { INIT.get_or_init(|| async { console::log_1(&"INIT".into()); - tracing_wasm::set_as_global_default(); + let config = tracing_wasm::WASMLayerConfigBuilder::default() + .set_console_config(tracing_wasm::ConsoleConfig::ReportWithoutConsoleColor) + .build(); + tracing_wasm::set_as_global_default_with_config(config); console_error_panic_hook::set_once(); diesel_wasm_sqlite::init_sqlite().await; }) diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index 2c49ceeea..652773ba0 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -132,6 +132,7 @@ impl ClientBuilder { } pub async fn new_test_client(owner: &impl InboxOwner) -> Client { + // crate::utils::wasm::init().await; let nonce = 1; let inbox_id = generate_inbox_id(&owner.get_address(), &nonce); From 0a3967dfbee2d7bd8bc46be61cc500d7a4829646 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 4 Oct 2024 17:35:30 -0400 Subject: [PATCH 66/97] dont use macos runner --- .github/workflows/test-webassembly.yml | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index 6582cd51a..2a1a0f77f 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -20,8 +20,7 @@ env: jobs: test: name: Test - # running with macos since it contains the safari driver - runs-on: warp-macos-14-arm64-6x + runs-on: warp-ubuntu-latest-x64-8x steps: - name: Checkout uses: actions/checkout@v4 @@ -33,9 +32,7 @@ jobs: workspaces: | . - name: Start Docker containers - run: | - dev/build_validation_service_local - dev/docker/up + run: dev/up - name: Build WebAssembly Packages run: cargo build --tests --release --target wasm32-unknown-unknown -p xmtp_id -p xmtp_mls -p xmtp_api_http --tests - name: test with chrome @@ -60,14 +57,3 @@ jobs: working-directory: ./ env: GECKODRIVER: "$GECKOWEBDRIVER" - - name: test with safari - run: | - cargo test --release -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ - --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ - --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ - --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ - --skip xmtp_mls::storage::encrypted_store::group::tests::test_find_groups \ - --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated - working-directory: ./ - env: - SAFARIWEBDRIVER: "$SAFARIWEBDRIVER" From fc1ea680ad916aaab7bcbb08e24d507f9bfc2bbe Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 4 Oct 2024 17:42:31 -0400 Subject: [PATCH 67/97] fix action --- .github/workflows/test-webassembly.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index 2a1a0f77f..50236008a 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -24,8 +24,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Install wasm-bindgen-test-runner - run: cargo install wasm-bindgen-cli + - uses: jetli/wasm-bindgen-action@v0.2.0 + with: + version: 'latest' - name: Cache uses: Swatinem/rust-cache@v2 with: @@ -34,7 +35,7 @@ jobs: - name: Start Docker containers run: dev/up - name: Build WebAssembly Packages - run: cargo build --tests --release --target wasm32-unknown-unknown -p xmtp_id -p xmtp_mls -p xmtp_api_http --tests + run: cargo build --tests --release --target wasm32-unknown-unknown -p xmtp_id -p xmtp_mls -p xmtp_api_http - name: test with chrome run: | cargo test --release -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ From 012b5ecebda7c2ba4198da500e3160b2cf5b2e76 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 4 Oct 2024 17:48:21 -0400 Subject: [PATCH 68/97] make sure to use wasm32 target --- .github/workflows/test-webassembly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index 50236008a..2cc9829d9 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -38,7 +38,7 @@ jobs: run: cargo build --tests --release --target wasm32-unknown-unknown -p xmtp_id -p xmtp_mls -p xmtp_api_http - name: test with chrome run: | - cargo test --release -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ + cargo test --release --target wasm32-unknown-unknown -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ @@ -49,7 +49,7 @@ jobs: CHROMEDRIVER: "$CHROMEWEBDRIVER" - name: test with firefox run: | - cargo test --release -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ + cargo test --release --target=wasm32-unknown-unknown -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ From f53b00adf21ab19ac08a57ede8ab1394910d6de6 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 4 Oct 2024 17:55:58 -0400 Subject: [PATCH 69/97] cannot use env vars like that --- .github/workflows/test-webassembly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index 2cc9829d9..3bc1d50a4 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -46,7 +46,7 @@ jobs: --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated working-directory: ./ env: - CHROMEDRIVER: "$CHROMEWEBDRIVER" + CHROMEDRIVER: "/usr/local/share/chromedriver-linux64" - name: test with firefox run: | cargo test --release --target=wasm32-unknown-unknown -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ @@ -57,4 +57,4 @@ jobs: --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated working-directory: ./ env: - GECKODRIVER: "$GECKOWEBDRIVER" + GECKODRIVER: "/usr/local/share/gecko_driver" From 3c2af0e877fe495d3e5bba235a5a9fc20b4315f1 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 4 Oct 2024 18:02:58 -0400 Subject: [PATCH 70/97] use bin name --- .github/workflows/test-webassembly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index 3bc1d50a4..efb5ccdcd 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -46,7 +46,7 @@ jobs: --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated working-directory: ./ env: - CHROMEDRIVER: "/usr/local/share/chromedriver-linux64" + CHROMEDRIVER: "chromedriver" - name: test with firefox run: | cargo test --release --target=wasm32-unknown-unknown -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ @@ -57,4 +57,4 @@ jobs: --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated working-directory: ./ env: - GECKODRIVER: "/usr/local/share/gecko_driver" + GECKODRIVER: "geckodriver" From a9d086e7a833c64aa5202b94c7aabcf418ab027d Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 7 Oct 2024 11:26:00 -0400 Subject: [PATCH 71/97] remove firefox tests, split build and test phases of CI --- .github/workflows/test-http-api.yml | 6 ++++-- .github/workflows/test-webassembly.yml | 11 ----------- .github/workflows/test-workspace.yml | 4 +++- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test-http-api.yml b/.github/workflows/test-http-api.yml index 6bdb3d80e..afc35ca3a 100644 --- a/.github/workflows/test-http-api.yml +++ b/.github/workflows/test-http-api.yml @@ -6,7 +6,7 @@ on: pull_request: # only run tests when related changes are made paths: - - ".github/workflows/test-workspace.yml" + - ".github/workflows/test-http-api.yml" - "dev/**" - "mls_validation_service/**" - "xmtp_api_http/**" @@ -40,5 +40,7 @@ jobs: run: dev/up - name: Install nextest uses: taiki-e/install-action@nextest - - name: Run cargo nextest on main workspace + - name: build tests + run: cargo build --tests --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --features http-api + - name: cargo test run: cargo nextest run --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --features http-api --test-threads 2 diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index efb5ccdcd..cde6f0afd 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -47,14 +47,3 @@ jobs: working-directory: ./ env: CHROMEDRIVER: "chromedriver" - - name: test with firefox - run: | - cargo test --release --target=wasm32-unknown-unknown -p xmtp_mls -p xmtp_id -p xmtp_api_http -- \ - --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ - --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ - --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ - --skip xmtp_mls::storage::encrypted_store::group::tests::test_find_groups \ - --skip xmtp_mls::storage::encrypted_store::group::tests::test_installations_last_checked_is_updated - working-directory: ./ - env: - GECKODRIVER: "geckodriver" diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index 3343dfee6..5e8330fc0 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -42,5 +42,7 @@ jobs: dev/docker/up - name: Install nextest uses: taiki-e/install-action@nextest - - name: Run cargo nextest on main workspace + - name: build tests + run: cargo build --workspace --tests --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm + - name: cargo test run: cargo nextest run --workspace --test-threads 2 --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm From abdd3def3ca93266876b856224adbd50915d4d9d Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Mon, 7 Oct 2024 15:10:47 -0700 Subject: [PATCH 72/97] Update WASM bindings (#1122) * Update VSCode workspace settings * Add WASM bindings * Clippy fixes * Use tokio Mutex --- .vscode/settings.json | 7 +- Cargo.lock | 5 + bindings_wasm/Cargo.toml | 13 +- bindings_wasm/src/consent_state.rs | 65 +++ bindings_wasm/src/conversations.rs | 176 ++++++++ bindings_wasm/src/encoded_content.rs | 73 +++ bindings_wasm/src/groups.rs | 644 +++++++++++++++++++++++++++ bindings_wasm/src/inbox_id.rs | 32 ++ bindings_wasm/src/inbox_state.rs | 39 ++ bindings_wasm/src/lib.rs | 8 + bindings_wasm/src/messages.rs | 102 +++++ bindings_wasm/src/mls_client.rs | 331 +++++++++----- bindings_wasm/src/permissions.rs | 176 ++++++++ bindings_wasm/tests/web.rs | 3 +- 14 files changed, 1555 insertions(+), 119 deletions(-) create mode 100644 bindings_wasm/src/consent_state.rs create mode 100644 bindings_wasm/src/conversations.rs create mode 100644 bindings_wasm/src/encoded_content.rs create mode 100644 bindings_wasm/src/groups.rs create mode 100644 bindings_wasm/src/inbox_id.rs create mode 100644 bindings_wasm/src/inbox_state.rs create mode 100644 bindings_wasm/src/messages.rs create mode 100644 bindings_wasm/src/permissions.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 34f9ee388..2a034caa1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,11 +1,6 @@ { "rust-analyzer.cargo.sysroot": "discover", - "rust-analyzer.linkedProjects": [ - "bindings_ffi/Cargo.toml", - "bindings_node/Cargo.toml", - "bindings_wasm/Cargo.toml", - "examples/cli/Cargo.toml" - ], + "rust-analyzer.linkedProjects": ["Cargo.toml"], "rust-analyzer.procMacro.enable": true, "rust-analyzer.procMacro.attributes.enable": true, "rust-analyzer.procMacro.ignored": { diff --git a/Cargo.lock b/Cargo.lock index 3f3816f8a..2955f0040 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -452,8 +452,12 @@ dependencies = [ name = "bindings_wasm" version = "0.0.1" dependencies = [ + "hex", "js-sys", + "prost", + "serde", "serde-wasm-bindgen", + "tokio", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", @@ -461,6 +465,7 @@ dependencies = [ "xmtp_cryptography", "xmtp_id", "xmtp_mls", + "xmtp_proto", ] [[package]] diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 746b79103..2cb631a35 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -7,15 +7,22 @@ version.workspace = true crate-type = ["cdylib", "rlib"] [dependencies] +hex.workspace = true js-sys.workspace = true +prost.workspace = true serde-wasm-bindgen = "0.6.5" -wasm-bindgen.workspace = true +serde.workspace = true +tokio.workspace = true wasm-bindgen-futures.workspace = true +wasm-bindgen.workspace = true xmtp_api_http = { path = "../xmtp_api_http" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } -xmtp_mls = { path = "../xmtp_mls", features = ["message-history"] } +xmtp_mls = { path = "../xmtp_mls", features = [ + "message-history", + "test-utils", +] } +xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } [dev-dependencies] wasm-bindgen-test.workspace = true - diff --git a/bindings_wasm/src/consent_state.rs b/bindings_wasm/src/consent_state.rs new file mode 100644 index 000000000..0b13f3df9 --- /dev/null +++ b/bindings_wasm/src/consent_state.rs @@ -0,0 +1,65 @@ +use wasm_bindgen::prelude::wasm_bindgen; +use xmtp_mls::storage::consent_record::{ConsentState, ConsentType, StoredConsentRecord}; + +#[wasm_bindgen] +#[derive(Clone, serde::Serialize)] +pub enum WasmConsentState { + Unknown, + Allowed, + Denied, +} + +impl From for WasmConsentState { + fn from(state: ConsentState) -> Self { + match state { + ConsentState::Unknown => WasmConsentState::Unknown, + ConsentState::Allowed => WasmConsentState::Allowed, + ConsentState::Denied => WasmConsentState::Denied, + } + } +} + +impl From for ConsentState { + fn from(state: WasmConsentState) -> Self { + match state { + WasmConsentState::Unknown => ConsentState::Unknown, + WasmConsentState::Allowed => ConsentState::Allowed, + WasmConsentState::Denied => ConsentState::Denied, + } + } +} + +#[wasm_bindgen] +#[derive(Clone)] +pub enum WasmConsentEntityType { + GroupId, + InboxId, + Address, +} + +impl From for ConsentType { + fn from(entity_type: WasmConsentEntityType) -> Self { + match entity_type { + WasmConsentEntityType::GroupId => ConsentType::GroupId, + WasmConsentEntityType::InboxId => ConsentType::InboxId, + WasmConsentEntityType::Address => ConsentType::Address, + } + } +} + +#[wasm_bindgen(getter_with_clone)] +pub struct WasmConsent { + pub entity_type: WasmConsentEntityType, + pub state: WasmConsentState, + pub entity: String, +} + +impl From for StoredConsentRecord { + fn from(consent: WasmConsent) -> Self { + Self { + entity_type: consent.entity_type.into(), + state: consent.state.into(), + entity: consent.entity, + } + } +} diff --git a/bindings_wasm/src/conversations.rs b/bindings_wasm/src/conversations.rs new file mode 100644 index 000000000..415018d7f --- /dev/null +++ b/bindings_wasm/src/conversations.rs @@ -0,0 +1,176 @@ +use std::sync::Arc; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::{JsError, JsValue}; +use xmtp_mls::client::FindGroupParams; +use xmtp_mls::groups::{GroupMetadataOptions, PreconfiguredPolicies}; + +use crate::messages::WasmMessage; +use crate::permissions::WasmGroupPermissionsOptions; +use crate::{groups::WasmGroup, mls_client::RustXmtpClient}; + +#[wasm_bindgen(getter_with_clone)] +pub struct WasmListConversationsOptions { + pub created_after_ns: Option, + pub created_before_ns: Option, + pub limit: Option, +} + +#[wasm_bindgen(getter_with_clone)] +#[derive(Clone)] +pub struct WasmCreateGroupOptions { + pub permissions: Option, + pub group_name: Option, + pub group_image_url_square: Option, + pub group_description: Option, + pub group_pinned_frame_url: Option, +} + +impl WasmCreateGroupOptions { + pub fn into_group_metadata_options(self) -> GroupMetadataOptions { + GroupMetadataOptions { + name: self.group_name, + image_url_square: self.group_image_url_square, + description: self.group_description, + pinned_frame_url: self.group_pinned_frame_url, + } + } +} + +#[wasm_bindgen] +pub struct WasmConversations { + inner_client: Arc, +} + +impl WasmConversations { + pub fn new(inner_client: Arc) -> Self { + Self { inner_client } + } +} + +#[wasm_bindgen] +impl WasmConversations { + #[wasm_bindgen] + pub async fn create_group( + &self, + account_addresses: Vec, + options: Option, + ) -> Result { + let options = match options { + Some(options) => options, + None => WasmCreateGroupOptions { + permissions: None, + group_name: None, + group_image_url_square: None, + group_description: None, + group_pinned_frame_url: None, + }, + }; + + let group_permissions = match options.permissions { + Some(WasmGroupPermissionsOptions::AllMembers) => { + Some(PreconfiguredPolicies::AllMembers.to_policy_set()) + } + Some(WasmGroupPermissionsOptions::AdminOnly) => { + Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()) + } + _ => None, + }; + + let metadata_options = options.clone().into_group_metadata_options(); + + let convo = if account_addresses.is_empty() { + self + .inner_client + .create_group(group_permissions, metadata_options) + .map_err(|e| JsError::new(format!("{}", e).as_str()))? + } else { + self + .inner_client + .create_group_with_members(account_addresses, group_permissions, metadata_options) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))? + }; + + let out = WasmGroup::new( + self.inner_client.clone(), + convo.group_id, + convo.created_at_ns, + ); + + Ok(out) + } + + #[wasm_bindgen] + pub fn find_group_by_id(&self, group_id: String) -> Result { + let group_id = hex::decode(group_id).map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + let group = self + .inner_client + .group(group_id) + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(WasmGroup::new( + self.inner_client.clone(), + group.group_id, + group.created_at_ns, + )) + } + + #[wasm_bindgen] + pub fn find_message_by_id(&self, message_id: String) -> Result { + let message_id = + hex::decode(message_id).map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + let message = self + .inner_client + .message(message_id) + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(WasmMessage::from(message)) + } + + #[wasm_bindgen] + pub async fn sync(&self) -> Result<(), JsError> { + self + .inner_client + .sync_welcomes() + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + Ok(()) + } + + #[wasm_bindgen] + pub async fn list( + &self, + opts: Option, + ) -> Result { + let opts = match opts { + Some(options) => options, + None => WasmListConversationsOptions { + created_after_ns: None, + created_before_ns: None, + limit: None, + }, + }; + let convo_list: js_sys::Array = self + .inner_client + .find_groups(FindGroupParams { + created_after_ns: opts.created_after_ns, + created_before_ns: opts.created_before_ns, + limit: opts.limit, + ..FindGroupParams::default() + }) + .map_err(|e| JsError::new(format!("{}", e).as_str()))? + .into_iter() + .map(|group| { + JsValue::from(WasmGroup::new( + self.inner_client.clone(), + group.group_id, + group.created_at_ns, + )) + }) + .collect(); + + Ok(convo_list) + } +} diff --git a/bindings_wasm/src/encoded_content.rs b/bindings_wasm/src/encoded_content.rs new file mode 100644 index 000000000..87b933b5e --- /dev/null +++ b/bindings_wasm/src/encoded_content.rs @@ -0,0 +1,73 @@ +use js_sys::Uint8Array; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; +use xmtp_proto::xmtp::mls::message_contents::{ContentTypeId, EncodedContent}; + +#[wasm_bindgen(getter_with_clone)] +#[derive(Clone)] +pub struct WasmContentTypeId { + pub authority_id: String, + pub type_id: String, + pub version_major: u32, + pub version_minor: u32, +} + +impl From for WasmContentTypeId { + fn from(content_type_id: ContentTypeId) -> WasmContentTypeId { + WasmContentTypeId { + authority_id: content_type_id.authority_id, + type_id: content_type_id.type_id, + version_major: content_type_id.version_major, + version_minor: content_type_id.version_minor, + } + } +} + +impl From for ContentTypeId { + fn from(content_type_id: WasmContentTypeId) -> Self { + ContentTypeId { + authority_id: content_type_id.authority_id, + type_id: content_type_id.type_id, + version_major: content_type_id.version_major, + version_minor: content_type_id.version_minor, + } + } +} + +#[wasm_bindgen(getter_with_clone)] +#[derive(Clone)] +pub struct WasmEncodedContent { + pub r#type: Option, + pub parameters: JsValue, + pub fallback: Option, + pub compression: Option, + pub content: Uint8Array, +} + +impl From for WasmEncodedContent { + fn from(content: EncodedContent) -> WasmEncodedContent { + let r#type = content.r#type.map(|v| v.into()); + + WasmEncodedContent { + r#type, + parameters: serde_wasm_bindgen::to_value(&content.parameters).unwrap(), + fallback: content.fallback, + compression: content.compression, + content: content.content.as_slice().into(), + } + } +} + +impl From for EncodedContent { + fn from(content: WasmEncodedContent) -> Self { + let r#type = content.r#type.map(|v| v.into()); + + EncodedContent { + r#type, + parameters: serde_wasm_bindgen::from_value(content.parameters).unwrap(), + fallback: content.fallback, + compression: content.compression, + content: content.content.to_vec(), + } + } +} diff --git a/bindings_wasm/src/groups.rs b/bindings_wasm/src/groups.rs new file mode 100644 index 000000000..91578677c --- /dev/null +++ b/bindings_wasm/src/groups.rs @@ -0,0 +1,644 @@ +use std::sync::Arc; +use wasm_bindgen::JsValue; +use wasm_bindgen::{prelude::wasm_bindgen, JsError}; + +use crate::encoded_content::WasmEncodedContent; +use crate::messages::{WasmListMessagesOptions, WasmMessage}; +use crate::mls_client::RustXmtpClient; +use crate::{consent_state::WasmConsentState, permissions::WasmGroupPermissions}; +use xmtp_cryptography::signature::ed25519_public_key_to_address; +use xmtp_mls::groups::{ + group_metadata::{ConversationType, GroupMetadata}, + members::PermissionLevel, + MlsGroup, UpdateAdminListType, +}; +use xmtp_proto::xmtp::mls::message_contents::EncodedContent; + +use prost::Message; + +#[wasm_bindgen] +pub struct WasmGroupMetadata { + inner: GroupMetadata, +} + +#[wasm_bindgen] +impl WasmGroupMetadata { + #[wasm_bindgen] + pub fn creator_inbox_id(&self) -> String { + self.inner.creator_inbox_id.clone() + } + + #[wasm_bindgen] + pub fn conversation_type(&self) -> String { + match self.inner.conversation_type { + ConversationType::Group => "group".to_string(), + ConversationType::Dm => "dm".to_string(), + ConversationType::Sync => "sync".to_string(), + } + } +} + +#[wasm_bindgen] +#[derive(Clone, serde::Serialize)] +pub enum WasmPermissionLevel { + Member, + Admin, + SuperAdmin, +} + +#[wasm_bindgen(getter_with_clone)] +#[derive(Clone, serde::Serialize)] +pub struct WasmGroupMember { + pub inbox_id: String, + pub account_addresses: Vec, + pub installation_ids: Vec, + pub permission_level: WasmPermissionLevel, + pub consent_state: WasmConsentState, +} + +#[wasm_bindgen] +pub struct WasmGroup { + inner_client: Arc, + group_id: Vec, + created_at_ns: i64, +} + +impl WasmGroup { + pub fn new(inner_client: Arc, group_id: Vec, created_at_ns: i64) -> Self { + Self { + inner_client, + group_id, + created_at_ns, + } + } +} + +#[wasm_bindgen] +impl WasmGroup { + #[wasm_bindgen] + pub fn id(&self) -> String { + hex::encode(self.group_id.clone()) + } + + #[wasm_bindgen] + pub async fn send(&self, encoded_content: WasmEncodedContent) -> Result { + let encoded_content: EncodedContent = encoded_content.into(); + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let message_id = group + .send_message( + encoded_content.encode_to_vec().as_slice(), + &self.inner_client, + ) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + Ok(hex::encode(message_id.clone())) + } + + /// send a message without immediately publishing to the delivery service. + #[wasm_bindgen] + pub fn send_optimistic(&self, encoded_content: WasmEncodedContent) -> Result { + let encoded_content: EncodedContent = encoded_content.into(); + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let id = group + .send_message_optimistic(encoded_content.encode_to_vec().as_slice()) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(hex::encode(id.clone())) + } + + /// Publish all unpublished messages + #[wasm_bindgen] + pub async fn publish_messages(&self) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .publish_messages(&self.inner_client) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + Ok(()) + } + + #[wasm_bindgen] + pub async fn sync(&self) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .sync(&self.inner_client) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub fn find_messages( + &self, + opts: Option, + ) -> Result, JsError> { + let opts = match opts { + Some(options) => options, + None => WasmListMessagesOptions { + sent_before_ns: None, + sent_after_ns: None, + limit: None, + delivery_status: None, + }, + }; + + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let delivery_status = opts.delivery_status.map(|status| status.into()); + + let messages: Vec = group + .find_messages( + None, + opts.sent_before_ns, + opts.sent_after_ns, + delivery_status, + opts.limit, + ) + .map_err(|e| JsError::new(&format!("{e}")))? + .into_iter() + .map(|msg| msg.into()) + .collect(); + + Ok(messages) + } + + #[wasm_bindgen] + pub async fn list_members(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let members: Vec = group + .members(&self.inner_client) + .await + .map_err(|e| JsError::new(&format!("{e}")))? + .into_iter() + .map(|member| WasmGroupMember { + inbox_id: member.inbox_id, + account_addresses: member.account_addresses, + installation_ids: member + .installation_ids + .into_iter() + .map(|id| ed25519_public_key_to_address(id.as_slice())) + .collect(), + permission_level: match member.permission_level { + PermissionLevel::Member => WasmPermissionLevel::Member, + PermissionLevel::Admin => WasmPermissionLevel::Admin, + PermissionLevel::SuperAdmin => WasmPermissionLevel::SuperAdmin, + }, + consent_state: member.consent_state.into(), + }) + .collect(); + + Ok(serde_wasm_bindgen::to_value(&members)?) + } + + #[wasm_bindgen] + pub fn admin_list(&self) -> Result, JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let admin_list = group + .admin_list( + group + .mls_provider() + .map_err(|e| JsError::new(&format!("{e}")))?, + ) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(admin_list) + } + + #[wasm_bindgen] + pub fn super_admin_list(&self) -> Result, JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let super_admin_list = group + .super_admin_list( + group + .mls_provider() + .map_err(|e| JsError::new(&format!("{e}")))?, + ) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(super_admin_list) + } + + #[wasm_bindgen] + pub fn is_admin(&self, inbox_id: String) -> Result { + let admin_list = self.admin_list()?; + Ok(admin_list.contains(&inbox_id)) + } + + #[wasm_bindgen] + pub fn is_super_admin(&self, inbox_id: String) -> Result { + let super_admin_list = self.super_admin_list()?; + Ok(super_admin_list.contains(&inbox_id)) + } + + #[wasm_bindgen] + pub async fn add_members(&self, account_addresses: Vec) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .add_members(&self.inner_client, account_addresses) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub async fn add_admin(&self, inbox_id: String) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .update_admin_list(&self.inner_client, UpdateAdminListType::Add, inbox_id) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub async fn remove_admin(&self, inbox_id: String) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .update_admin_list(&self.inner_client, UpdateAdminListType::Remove, inbox_id) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub async fn add_super_admin(&self, inbox_id: String) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .update_admin_list(&self.inner_client, UpdateAdminListType::AddSuper, inbox_id) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub async fn remove_super_admin(&self, inbox_id: String) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .update_admin_list( + &self.inner_client, + UpdateAdminListType::RemoveSuper, + inbox_id, + ) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub fn group_permissions(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let permissions = group + .permissions() + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(WasmGroupPermissions::new(permissions)) + } + + #[wasm_bindgen] + pub async fn add_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .add_members_by_inbox_id(&self.inner_client, inbox_ids) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub async fn remove_members(&self, account_addresses: Vec) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .remove_members(&self.inner_client, account_addresses) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub async fn remove_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .remove_members_by_inbox_id(&self.inner_client, inbox_ids) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub async fn update_group_name(&self, group_name: String) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_group_name(&self.inner_client, group_name) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub fn group_name(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let group_name = group + .group_name( + group + .mls_provider() + .map_err(|e| JsError::new(&format!("{e}")))?, + ) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(group_name) + } + + #[wasm_bindgen] + pub async fn update_group_image_url_square( + &self, + group_image_url_square: String, + ) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_group_image_url_square(&self.inner_client, group_image_url_square) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub fn group_image_url_square(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let group_image_url_square = group + .group_image_url_square( + group + .mls_provider() + .map_err(|e| JsError::new(&format!("{e}")))?, + ) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(group_image_url_square) + } + + #[wasm_bindgen] + pub async fn update_group_description(&self, group_description: String) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_group_description(&self.inner_client, group_description) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub fn group_description(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let group_description = group + .group_description( + group + .mls_provider() + .map_err(|e| JsError::new(&format!("{e}")))?, + ) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(group_description) + } + + #[wasm_bindgen] + pub async fn update_group_pinned_frame_url( + &self, + pinned_frame_url: String, + ) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_group_pinned_frame_url(&self.inner_client, pinned_frame_url) + .await + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } + + #[wasm_bindgen] + pub fn group_pinned_frame_url(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let group_pinned_frame_url = group + .group_pinned_frame_url( + group + .mls_provider() + .map_err(|e| JsError::new(&format!("{e}")))?, + ) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(group_pinned_frame_url) + } + + #[wasm_bindgen] + pub fn created_at_ns(&self) -> i64 { + self.created_at_ns + } + + #[wasm_bindgen] + pub fn is_active(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .is_active( + group + .mls_provider() + .map_err(|e| JsError::new(&format!("{e}")))?, + ) + .map_err(|e| JsError::new(&format!("{e}"))) + } + + #[wasm_bindgen] + pub fn added_by_inbox_id(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .added_by_inbox_id() + .map_err(|e| JsError::new(&format!("{e}"))) + } + + #[wasm_bindgen] + pub fn group_metadata(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let metadata = group + .metadata( + group + .mls_provider() + .map_err(|e| JsError::new(&format!("{e}")))?, + ) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(WasmGroupMetadata { inner: metadata }) + } + + #[wasm_bindgen] + pub fn consent_state(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let state = group + .consent_state() + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(state.into()) + } + + #[wasm_bindgen] + pub fn update_consent_state(&self, state: WasmConsentState) -> Result<(), JsError> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_consent_state(state.into()) + .map_err(|e| JsError::new(&format!("{e}")))?; + + Ok(()) + } +} diff --git a/bindings_wasm/src/inbox_id.rs b/bindings_wasm/src/inbox_id.rs new file mode 100644 index 000000000..93e5fc22b --- /dev/null +++ b/bindings_wasm/src/inbox_id.rs @@ -0,0 +1,32 @@ +use wasm_bindgen::prelude::{wasm_bindgen, JsError}; +use xmtp_api_http::XmtpHttpApiClient; +use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; +use xmtp_mls::api::ApiClientWrapper; +use xmtp_mls::retry::Retry; + +#[wasm_bindgen(js_name = getInboxIdForAddress)] +pub async fn get_inbox_id_for_address( + host: String, + account_address: String, +) -> Result, JsError> { + let account_address = account_address.to_lowercase(); + let api_client = ApiClientWrapper::new( + XmtpHttpApiClient::new(host.clone()).unwrap(), + Retry::default(), + ); + + let results = api_client + .get_inbox_ids(vec![account_address.clone()]) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(results.get(&account_address).cloned()) +} + +#[wasm_bindgen(js_name = generateInboxId)] +pub fn generate_inbox_id(account_address: String) -> String { + let account_address = account_address.to_lowercase(); + // ensure that the nonce is always 1 for now since this will only be used for the + // create_client function above, which also has a hard-coded nonce of 1 + xmtp_id_generate_inbox_id(&account_address, &1) +} diff --git a/bindings_wasm/src/inbox_state.rs b/bindings_wasm/src/inbox_state.rs new file mode 100644 index 000000000..0bd55eece --- /dev/null +++ b/bindings_wasm/src/inbox_state.rs @@ -0,0 +1,39 @@ +use wasm_bindgen::prelude::wasm_bindgen; +use xmtp_cryptography::signature::ed25519_public_key_to_address; +use xmtp_id::associations::{AssociationState, MemberIdentifier}; + +#[wasm_bindgen(getter_with_clone)] +#[derive(Clone)] +pub struct WasmInstallation { + pub id: String, + pub client_timestamp_ns: Option, +} + +#[wasm_bindgen(getter_with_clone)] +pub struct WasmInboxState { + pub inbox_id: String, + pub recovery_address: String, + pub installations: Vec, + pub account_addresses: Vec, +} + +impl From for WasmInboxState { + fn from(state: AssociationState) -> Self { + Self { + inbox_id: state.inbox_id().to_string(), + recovery_address: state.recovery_address().to_string(), + installations: state + .members() + .into_iter() + .filter_map(|m| match m.identifier { + MemberIdentifier::Address(_) => None, + MemberIdentifier::Installation(inst) => Some(WasmInstallation { + id: ed25519_public_key_to_address(inst.as_slice()), + client_timestamp_ns: m.client_timestamp_ns, + }), + }) + .collect(), + account_addresses: state.account_addresses(), + } + } +} diff --git a/bindings_wasm/src/lib.rs b/bindings_wasm/src/lib.rs index 9e31f7a45..7562d1e99 100644 --- a/bindings_wasm/src/lib.rs +++ b/bindings_wasm/src/lib.rs @@ -1 +1,9 @@ +pub mod consent_state; +pub mod conversations; +pub mod encoded_content; +pub mod groups; +pub mod inbox_id; +pub mod inbox_state; +pub mod messages; pub mod mls_client; +pub mod permissions; diff --git a/bindings_wasm/src/messages.rs b/bindings_wasm/src/messages.rs new file mode 100644 index 000000000..936c54ec6 --- /dev/null +++ b/bindings_wasm/src/messages.rs @@ -0,0 +1,102 @@ +use js_sys::Uint8Array; +use prost::Message; +use wasm_bindgen::prelude::wasm_bindgen; +use xmtp_mls::storage::group_message::{DeliveryStatus, GroupMessageKind, StoredGroupMessage}; +use xmtp_proto::xmtp::mls::message_contents::EncodedContent; + +use crate::encoded_content::WasmEncodedContent; + +#[wasm_bindgen] +#[derive(Clone)] +pub enum WasmGroupMessageKind { + Application, + MembershipChange, +} + +impl From for WasmGroupMessageKind { + fn from(kind: GroupMessageKind) -> Self { + match kind { + GroupMessageKind::Application => WasmGroupMessageKind::Application, + GroupMessageKind::MembershipChange => WasmGroupMessageKind::MembershipChange, + } + } +} + +#[wasm_bindgen] +#[derive(Clone)] +pub enum WasmDeliveryStatus { + Unpublished, + Published, + Failed, +} + +impl From for WasmDeliveryStatus { + fn from(status: DeliveryStatus) -> Self { + match status { + DeliveryStatus::Unpublished => WasmDeliveryStatus::Unpublished, + DeliveryStatus::Published => WasmDeliveryStatus::Published, + DeliveryStatus::Failed => WasmDeliveryStatus::Failed, + } + } +} + +impl From for DeliveryStatus { + fn from(status: WasmDeliveryStatus) -> Self { + match status { + WasmDeliveryStatus::Unpublished => DeliveryStatus::Unpublished, + WasmDeliveryStatus::Published => DeliveryStatus::Published, + WasmDeliveryStatus::Failed => DeliveryStatus::Failed, + } + } +} + +#[wasm_bindgen(getter_with_clone)] +pub struct WasmListMessagesOptions { + pub sent_before_ns: Option, + pub sent_after_ns: Option, + pub limit: Option, + pub delivery_status: Option, +} + +#[wasm_bindgen(getter_with_clone)] +#[derive(Clone)] +pub struct WasmMessage { + pub id: String, + pub sent_at_ns: i64, + pub convo_id: String, + pub sender_inbox_id: String, + pub content: WasmEncodedContent, + pub kind: WasmGroupMessageKind, + pub delivery_status: WasmDeliveryStatus, +} + +impl From for WasmMessage { + fn from(msg: StoredGroupMessage) -> Self { + let id = hex::encode(msg.id.clone()); + let convo_id = hex::encode(msg.group_id.clone()); + let contents = msg.decrypted_message_bytes.clone(); + let content: WasmEncodedContent = match EncodedContent::decode(contents.as_slice()) { + Ok(value) => value.into(), + Err(e) => { + println!("Error decoding content: {:?}", e); + WasmEncodedContent { + r#type: None, + parameters: Default::default(), + fallback: None, + compression: None, + content: Uint8Array::new_with_length(0), + } + } + }; + + Self { + id, + sent_at_ns: msg.sent_at_ns, + convo_id, + sender_inbox_id: msg.sender_inbox_id, + content, + kind: msg.kind.into(), + delivery_status: msg.delivery_status.into(), + } + } +} diff --git a/bindings_wasm/src/mls_client.rs b/bindings_wasm/src/mls_client.rs index 6e7594e82..e396afd69 100644 --- a/bindings_wasm/src/mls_client.rs +++ b/bindings_wasm/src/mls_client.rs @@ -1,41 +1,55 @@ use js_sys::Uint8Array; use std::collections::HashMap; use std::sync::Arc; +use tokio::sync::Mutex; use wasm_bindgen::prelude::{wasm_bindgen, JsError}; use wasm_bindgen::JsValue; use xmtp_api_http::XmtpHttpApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; -use xmtp_id::associations::{ - generate_inbox_id as xmtp_id_generate_inbox_id, unverified::UnverifiedSignature, AccountId, - MemberIdentifier, -}; -use xmtp_mls::api::ApiClientWrapper; +use xmtp_id::associations::builder::SignatureRequest; +use xmtp_id::associations::unverified::UnverifiedSignature; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::identity::IdentityStrategy; -use xmtp_mls::retry::Retry; +use xmtp_mls::storage::consent_record::StoredConsentRecord; use xmtp_mls::storage::{EncryptedMessageStore, EncryptionKey, StorageOption}; use xmtp_mls::Client as MlsClient; +use crate::consent_state::{WasmConsent, WasmConsentEntityType, WasmConsentState}; +use crate::conversations::WasmConversations; +use crate::inbox_state::WasmInboxState; + pub type RustXmtpClient = MlsClient; +#[wasm_bindgen] +#[derive(Clone, Eq, Hash, PartialEq)] +pub enum WasmSignatureRequestType { + AddWallet, + CreateInbox, + RevokeWallet, + RevokeInstallations, +} + #[wasm_bindgen] pub struct WasmClient { account_address: String, inner_client: Arc, - signatures: HashMap, + signature_requests: Arc>>, } -#[wasm_bindgen] +#[wasm_bindgen(js_name = createClient)] pub async fn create_client( host: String, inbox_id: String, account_address: String, + db_path: String, encryption_key: Option, history_sync_url: Option, ) -> Result { + xmtp_mls::utils::wasm::init().await; let api_client = XmtpHttpApiClient::new(host.clone()).unwrap(); - let storage_option = StorageOption::Ephemeral; + let storage_option = StorageOption::Persistent(db_path); + let store = match encryption_key { Some(key) => { let key: Vec = key.to_vec(); @@ -78,60 +92,33 @@ pub async fn create_client( Ok(WasmClient { account_address, inner_client: Arc::new(xmtp_client), - signatures: HashMap::new(), + signature_requests: Arc::new(Mutex::new(HashMap::new())), }) } -#[wasm_bindgen] -pub async fn get_inbox_id_for_address( - host: String, - account_address: String, -) -> Result, JsError> { - let account_address = account_address.to_lowercase(); - let api_client = ApiClientWrapper::new( - XmtpHttpApiClient::new(host.clone()).unwrap(), - Retry::default(), - ); - - let results = api_client - .get_inbox_ids(vec![account_address.clone()]) - .await - .map_err(|e| JsError::new(format!("{}", e).as_str()))?; - - Ok(results.get(&account_address).cloned()) -} - -#[wasm_bindgen] -pub fn generate_inbox_id(account_address: String) -> String { - let account_address = account_address.to_lowercase(); - // ensure that the nonce is always 1 for now since this will only be used for the - // create_client function above, which also has a hard-coded nonce of 1 - xmtp_id_generate_inbox_id(&account_address, &1) -} - #[wasm_bindgen] impl WasmClient { - #[wasm_bindgen(getter)] + #[wasm_bindgen(getter, js_name = accountAddress)] pub fn account_address(&self) -> String { self.account_address.clone() } - #[wasm_bindgen(getter)] + #[wasm_bindgen(getter, js_name = inboxId)] pub fn inbox_id(&self) -> String { self.inner_client.inbox_id() } - #[wasm_bindgen(getter)] + #[wasm_bindgen(getter, js_name = isRegistered)] pub fn is_registered(&self) -> bool { - self.inner_client.identity().signature_request().is_none() + self.inner_client.identity().is_ready() } - #[wasm_bindgen(getter)] + #[wasm_bindgen(getter, js_name = installationId)] pub fn installation_id(&self) -> String { ed25519_public_key_to_address(self.inner_client.installation_public_key().as_slice()) } - #[wasm_bindgen] + #[wasm_bindgen(js_name = canMessage)] pub async fn can_message(&self, account_addresses: Vec) -> Result { let results: HashMap = self .inner_client @@ -142,79 +129,128 @@ impl WasmClient { Ok(serde_wasm_bindgen::to_value(&results)?) } - #[wasm_bindgen] - pub fn add_ecdsa_signature(&mut self, signature_bytes: Uint8Array) -> Result<(), JsError> { + #[wasm_bindgen(js_name = registerIdentity)] + pub async fn register_identity(&self) -> Result<(), JsError> { if self.is_registered() { return Err(JsError::new( "An identity is already registered with this client", )); } - let signature = UnverifiedSignature::new_recoverable_ecdsa(signature_bytes.to_vec()); + let mut signature_requests = self.signature_requests.lock().await; - self.signatures.insert( - MemberIdentifier::Address(self.account_address.clone().to_lowercase()), - signature, - ); + let signature_request = signature_requests + .get(&WasmSignatureRequestType::CreateInbox) + .ok_or(JsError::new("No signature request found"))?; + + self + .inner_client + .register_identity(signature_request.clone()) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + signature_requests.remove(&WasmSignatureRequestType::CreateInbox); Ok(()) } - #[wasm_bindgen] - pub fn add_scw_signature( - &mut self, - signature_bytes: Uint8Array, - chain_id: u64, - account_address: String, - block_number: u64, - ) -> Result<(), JsError> { - if self.is_registered() { - return Err(JsError::new( - "An identity is already registered with this client", - )); - } + #[wasm_bindgen(js_name = createInboxSignatureText)] + pub async fn create_inbox_signature_text(&self) -> Result, JsError> { + let signature_request = match self.inner_client.identity().signature_request() { + Some(signature_req) => signature_req, + // this should never happen since we're checking for it above in is_registered + None => return Err(JsError::new("No signature request found")), + }; + let signature_text = signature_request.signature_text(); + let mut signature_requests = self.signature_requests.lock().await; - let account_id = AccountId::new_evm(chain_id, account_address.clone()); + signature_requests.insert(WasmSignatureRequestType::CreateInbox, signature_request); - let signature = UnverifiedSignature::new_smart_contract_wallet( - signature_bytes.to_vec(), - account_id, - block_number, - ); + Ok(Some(signature_text)) + } - self.signatures.insert( - MemberIdentifier::Address(account_address.clone().to_lowercase()), - signature, - ); + #[wasm_bindgen(js_name = addWalletSignatureText)] + pub async fn add_wallet_signature_text( + &self, + existing_wallet_address: String, + new_wallet_address: String, + ) -> Result { + let signature_request = self + .inner_client + .associate_wallet( + existing_wallet_address.to_lowercase(), + new_wallet_address.to_lowercase(), + ) + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + let signature_text = signature_request.signature_text(); + let mut signature_requests = self.signature_requests.lock().await; - Ok(()) + signature_requests.insert(WasmSignatureRequestType::AddWallet, signature_request); + + Ok(signature_text) } - #[wasm_bindgen] - pub async fn register_identity(&self) -> Result<(), JsError> { - if self.is_registered() { - return Err(JsError::new( - "An identity is already registered with this client", - )); - } + #[wasm_bindgen(js_name = revokeWalletSignatureText)] + pub async fn revoke_wallet_signature_text( + &self, + wallet_address: String, + ) -> Result { + let signature_request = self + .inner_client + .revoke_wallets(vec![wallet_address.to_lowercase()]) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + let signature_text = signature_request.signature_text(); + let mut signature_requests = self.signature_requests.lock().await; - if self.signatures.is_empty() { - return Err(JsError::new( - "No client signatures found, add at least 1 before registering", - )); - } + signature_requests.insert(WasmSignatureRequestType::RevokeWallet, signature_request); - let mut signature_request = match self.inner_client.identity().signature_request() { - Some(signature_req) => signature_req, - // this should never happen since we're checking for it above in is_registered - None => return Err(JsError::new("No signature request found")), - }; + Ok(signature_text) + } + + #[wasm_bindgen(js_name = revokeInstallationsSignatureText)] + pub async fn revoke_installations_signature_text(&self) -> Result { + let installation_id = self.inner_client.installation_public_key(); + let inbox_state = self + .inner_client + .inbox_state(true) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + let other_installation_ids = inbox_state + .installation_ids() + .into_iter() + .filter(|id| id != &installation_id) + .collect(); + let signature_request = self + .inner_client + .revoke_installations(other_installation_ids) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + let signature_text = signature_request.signature_text(); + let mut signature_requests = self.signature_requests.lock().await; + + signature_requests.insert( + WasmSignatureRequestType::RevokeInstallations, + signature_request, + ); + + Ok(signature_text) + } + + #[wasm_bindgen(js_name = addSignature)] + pub async fn add_signature( + &self, + signature_type: WasmSignatureRequestType, + signature_bytes: Uint8Array, + ) -> Result<(), JsError> { + let mut signature_requests = self.signature_requests.lock().await; + + if let Some(signature_request) = signature_requests.get_mut(&signature_type) { + let signature = UnverifiedSignature::new_recoverable_ecdsa(signature_bytes.to_vec()); - // apply added signatures to the signature request - for signature in self.signatures.values() { signature_request .add_signature( - signature.clone(), + signature, self .inner_client .smart_contract_signature_verifier() @@ -222,27 +258,40 @@ impl WasmClient { ) .await .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + } else { + return Err(JsError::new("Signature request not found")); } - self - .inner_client - .register_identity(signature_request) - .await - .map_err(|e| JsError::new(format!("{}", e).as_str()))?; - Ok(()) } - #[wasm_bindgen] - pub fn signature_text(&self) -> Option { - self - .inner_client - .identity() - .signature_request() - .map(|signature_req| signature_req.signature_text()) + #[wasm_bindgen(js_name = applySignatureRequests)] + pub async fn apply_signature_requests(&self) -> Result<(), JsError> { + let mut signature_requests = self.signature_requests.lock().await; + + let request_types: Vec = signature_requests.keys().cloned().collect(); + for signature_request_type in request_types { + // ignore the create inbox request since it's applied with register_identity + if signature_request_type == WasmSignatureRequestType::CreateInbox { + continue; + } + + if let Some(signature_request) = signature_requests.get(&signature_request_type) { + self + .inner_client + .apply_signature_request(signature_request.clone()) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + // remove the signature request after applying it + signature_requests.remove(&signature_request_type); + } + } + + Ok(()) } - #[wasm_bindgen] + #[wasm_bindgen(js_name = requestHistorySync)] pub async fn request_history_sync(&self) -> Result<(), JsError> { let _ = self .inner_client @@ -253,7 +302,7 @@ impl WasmClient { Ok(()) } - #[wasm_bindgen] + #[wasm_bindgen(js_name = findInboxIdByAddress)] pub async fn find_inbox_id_by_address(&self, address: String) -> Result, JsError> { let inbox_id = self .inner_client @@ -263,4 +312,68 @@ impl WasmClient { Ok(inbox_id) } + + /** + * Get the client's inbox state. + * + * If `refresh_from_network` is true, the client will go to the network first to refresh the state. + * Otherwise, the state will be read from the local database. + */ + #[wasm_bindgen(js_name = inboxState)] + pub async fn inbox_state(&self, refresh_from_network: bool) -> Result { + let state = self + .inner_client + .inbox_state(refresh_from_network) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + Ok(state.into()) + } + + #[wasm_bindgen(js_name = getLatestInboxState)] + pub async fn get_latest_inbox_state(&self, inbox_id: String) -> Result { + let conn = self + .inner_client + .store() + .conn() + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + let state = self + .inner_client + .get_latest_association_state(&conn, &inbox_id) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + Ok(state.into()) + } + + #[wasm_bindgen(js_name = setConsentStates)] + pub async fn set_consent_states(&self, records: Vec) -> Result<(), JsError> { + let inner = self.inner_client.as_ref(); + let stored_records: Vec = + records.into_iter().map(StoredConsentRecord::from).collect(); + + inner + .set_consent_states(stored_records) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + Ok(()) + } + + #[wasm_bindgen(js_name = getConsentState)] + pub async fn get_consent_state( + &self, + entity_type: WasmConsentEntityType, + entity: String, + ) -> Result { + let inner = self.inner_client.as_ref(); + let result = inner + .get_consent_state(entity_type.into(), entity) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(result.into()) + } + + #[wasm_bindgen] + pub fn conversations(&self) -> WasmConversations { + WasmConversations::new(self.inner_client.clone()) + } } diff --git a/bindings_wasm/src/permissions.rs b/bindings_wasm/src/permissions.rs new file mode 100644 index 000000000..24188ce2c --- /dev/null +++ b/bindings_wasm/src/permissions.rs @@ -0,0 +1,176 @@ +use wasm_bindgen::{prelude::wasm_bindgen, JsError}; +use xmtp_mls::groups::{ + group_mutable_metadata::MetadataField, + group_permissions::{ + BasePolicies, GroupMutablePermissions, MembershipPolicies, MetadataBasePolicies, + MetadataPolicies, PermissionsBasePolicies, PermissionsPolicies, + }, + intents::{PermissionPolicyOption, PermissionUpdateType}, + PreconfiguredPolicies, +}; + +#[wasm_bindgen] +#[derive(Clone)] +pub enum WasmGroupPermissionsOptions { + AllMembers, + AdminOnly, + CustomPolicy, +} + +#[wasm_bindgen] +pub enum WasmPermissionUpdateType { + AddMember, + RemoveMember, + AddAdmin, + RemoveAdmin, + UpdateMetadata, +} + +impl From<&WasmPermissionUpdateType> for PermissionUpdateType { + fn from(update_type: &WasmPermissionUpdateType) -> Self { + match update_type { + WasmPermissionUpdateType::AddMember => PermissionUpdateType::AddMember, + WasmPermissionUpdateType::RemoveMember => PermissionUpdateType::RemoveMember, + WasmPermissionUpdateType::AddAdmin => PermissionUpdateType::AddAdmin, + WasmPermissionUpdateType::RemoveAdmin => PermissionUpdateType::RemoveAdmin, + WasmPermissionUpdateType::UpdateMetadata => PermissionUpdateType::UpdateMetadata, + } + } +} + +#[wasm_bindgen] +#[derive(Clone)] +pub enum WasmPermissionPolicy { + Allow, + Deny, + Admin, + SuperAdmin, + DoesNotExist, + Other, +} + +impl TryInto for WasmPermissionPolicy { + type Error = JsError; + + fn try_into(self) -> Result { + match self { + WasmPermissionPolicy::Allow => Ok(PermissionPolicyOption::Allow), + WasmPermissionPolicy::Deny => Ok(PermissionPolicyOption::Deny), + WasmPermissionPolicy::Admin => Ok(PermissionPolicyOption::AdminOnly), + WasmPermissionPolicy::SuperAdmin => Ok(PermissionPolicyOption::SuperAdminOnly), + _ => Err(JsError::new("InvalidPermissionPolicyOption")), + } + } +} + +impl From<&MembershipPolicies> for WasmPermissionPolicy { + fn from(policies: &MembershipPolicies) -> Self { + if let MembershipPolicies::Standard(base_policy) = policies { + match base_policy { + BasePolicies::Allow => WasmPermissionPolicy::Allow, + BasePolicies::Deny => WasmPermissionPolicy::Deny, + BasePolicies::AllowSameMember => WasmPermissionPolicy::Other, + BasePolicies::AllowIfAdminOrSuperAdmin => WasmPermissionPolicy::Admin, + BasePolicies::AllowIfSuperAdmin => WasmPermissionPolicy::SuperAdmin, + } + } else { + WasmPermissionPolicy::Other + } + } +} + +impl From<&MetadataPolicies> for WasmPermissionPolicy { + fn from(policies: &MetadataPolicies) -> Self { + if let MetadataPolicies::Standard(base_policy) = policies { + match base_policy { + MetadataBasePolicies::Allow => WasmPermissionPolicy::Allow, + MetadataBasePolicies::Deny => WasmPermissionPolicy::Deny, + MetadataBasePolicies::AllowIfActorAdminOrSuperAdmin => WasmPermissionPolicy::Admin, + MetadataBasePolicies::AllowIfActorSuperAdmin => WasmPermissionPolicy::SuperAdmin, + } + } else { + WasmPermissionPolicy::Other + } + } +} + +impl From<&PermissionsPolicies> for WasmPermissionPolicy { + fn from(policies: &PermissionsPolicies) -> Self { + if let PermissionsPolicies::Standard(base_policy) = policies { + match base_policy { + PermissionsBasePolicies::Deny => WasmPermissionPolicy::Deny, + PermissionsBasePolicies::AllowIfActorAdminOrSuperAdmin => WasmPermissionPolicy::Admin, + PermissionsBasePolicies::AllowIfActorSuperAdmin => WasmPermissionPolicy::SuperAdmin, + } + } else { + WasmPermissionPolicy::Other + } + } +} + +#[wasm_bindgen(getter_with_clone)] +pub struct WasmPermissionPolicySet { + pub add_member_policy: WasmPermissionPolicy, + pub remove_member_policy: WasmPermissionPolicy, + pub add_admin_policy: WasmPermissionPolicy, + pub remove_admin_policy: WasmPermissionPolicy, + pub update_group_name_policy: WasmPermissionPolicy, + pub update_group_description_policy: WasmPermissionPolicy, + pub update_group_image_url_square_policy: WasmPermissionPolicy, + pub update_group_pinned_frame_url_policy: WasmPermissionPolicy, +} + +impl From for WasmGroupPermissionsOptions { + fn from(policy: PreconfiguredPolicies) -> Self { + match policy { + PreconfiguredPolicies::AllMembers => WasmGroupPermissionsOptions::AllMembers, + PreconfiguredPolicies::AdminsOnly => WasmGroupPermissionsOptions::AdminOnly, + } + } +} + +#[wasm_bindgen] +pub struct WasmGroupPermissions { + inner: GroupMutablePermissions, +} + +impl WasmGroupPermissions { + pub fn new(permissions: GroupMutablePermissions) -> Self { + Self { inner: permissions } + } +} + +#[wasm_bindgen] +impl WasmGroupPermissions { + #[wasm_bindgen] + #[wasm_bindgen] + pub fn policy_type(&self) -> Result { + if let Ok(preconfigured_policy) = self.inner.preconfigured_policy() { + Ok(preconfigured_policy.into()) + } else { + Ok(WasmGroupPermissionsOptions::CustomPolicy) + } + } + + #[wasm_bindgen] + pub fn policy_set(&self) -> Result { + let policy_set = &self.inner.policies; + let metadata_policy_map = &policy_set.update_metadata_policy; + let get_policy = |field: &str| { + metadata_policy_map + .get(field) + .map(WasmPermissionPolicy::from) + .unwrap_or(WasmPermissionPolicy::DoesNotExist) + }; + Ok(WasmPermissionPolicySet { + add_member_policy: WasmPermissionPolicy::from(&policy_set.add_member_policy), + remove_member_policy: WasmPermissionPolicy::from(&policy_set.remove_member_policy), + add_admin_policy: WasmPermissionPolicy::from(&policy_set.add_admin_policy), + remove_admin_policy: WasmPermissionPolicy::from(&policy_set.remove_admin_policy), + update_group_name_policy: get_policy(MetadataField::GroupName.as_str()), + update_group_description_policy: get_policy(MetadataField::Description.as_str()), + update_group_image_url_square_policy: get_policy(MetadataField::GroupImageUrlSquare.as_str()), + update_group_pinned_frame_url_policy: get_policy(MetadataField::GroupPinnedFrameUrl.as_str()), + }) + } +} diff --git a/bindings_wasm/tests/web.rs b/bindings_wasm/tests/web.rs index fb95ee39c..ba8e66004 100644 --- a/bindings_wasm/tests/web.rs +++ b/bindings_wasm/tests/web.rs @@ -1,4 +1,4 @@ -use bindings_wasm::mls_client::{create_client, get_inbox_id_for_address}; +use bindings_wasm::{inbox_id::get_inbox_id_for_address, mls_client::create_client}; use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; use xmtp_api_http::constants::ApiUrls; @@ -26,6 +26,7 @@ pub async fn test_create_client() { host.clone(), inbox_id.unwrap(), account_address.clone(), + "test".to_string(), None, None, ) From 5cb49ddf48d8ad9eafbb5bdcd664fc68eb929eb5 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 7 Oct 2024 18:25:00 -0400 Subject: [PATCH 73/97] use nextest instead of build --- .github/workflows/test-http-api.yml | 2 +- .github/workflows/test-workspace.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-http-api.yml b/.github/workflows/test-http-api.yml index afc35ca3a..e906f38aa 100644 --- a/.github/workflows/test-http-api.yml +++ b/.github/workflows/test-http-api.yml @@ -41,6 +41,6 @@ jobs: - name: Install nextest uses: taiki-e/install-action@nextest - name: build tests - run: cargo build --tests --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --features http-api + run: cargo nextest run --no-run --tests --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --features http-api - name: cargo test run: cargo nextest run --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --features http-api --test-threads 2 diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index 5e8330fc0..e565fe64c 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -43,6 +43,6 @@ jobs: - name: Install nextest uses: taiki-e/install-action@nextest - name: build tests - run: cargo build --workspace --tests --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm + run: cargo nextest run --no-run --workspace --tests --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm - name: cargo test run: cargo nextest run --workspace --test-threads 2 --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm From 30530060a8a558d14b489b270c3c2a6144196c56 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 9 Oct 2024 17:09:43 -0400 Subject: [PATCH 74/97] some kind of progress --- xmtp_api_http/src/lib.rs | 1 + .../scw_verifier/remote_signature_verifier.rs | 2 +- xmtp_mls/src/api/mod.rs | 2 +- xmtp_mls/src/builder.rs | 10 +- xmtp_mls/src/client.rs | 95 +++--- xmtp_mls/src/groups/members.rs | 21 +- xmtp_mls/src/groups/mod.rs | 286 ++++++++---------- xmtp_mls/src/groups/subscriptions.rs | 191 ++++++++---- xmtp_mls/src/groups/sync.rs | 250 ++++++--------- xmtp_mls/src/groups/validated_commit.rs | 12 +- xmtp_mls/src/identity_updates.rs | 17 +- xmtp_mls/src/lib.rs | 6 + xmtp_mls/src/storage/encrypted_store/mod.rs | 29 +- .../src/storage/encrypted_store/native.rs | 2 +- xmtp_mls/src/subscriptions.rs | 187 ++++-------- 15 files changed, 503 insertions(+), 608 deletions(-) diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index b3d84c8d7..b026f47df 100755 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -43,6 +43,7 @@ fn reqwest_builder() -> reqwest::ClientBuilder { reqwest::Client::builder().connection_verbose(true) } +#[derive(Clone)] pub struct XmtpHttpApiClient { http_client: reqwest::Client, host_url: String, diff --git a/xmtp_id/src/scw_verifier/remote_signature_verifier.rs b/xmtp_id/src/scw_verifier/remote_signature_verifier.rs index 82e4ec724..0b74947f0 100644 --- a/xmtp_id/src/scw_verifier/remote_signature_verifier.rs +++ b/xmtp_id/src/scw_verifier/remote_signature_verifier.rs @@ -10,7 +10,7 @@ use xmtp_proto::{ }, }; -pub struct RemoteSignatureVerifier { +pub struct RemoteSignatureVerifier { identity_client: C, } diff --git a/xmtp_mls/src/api/mod.rs b/xmtp_mls/src/api/mod.rs index 802bebe84..2b7b1d341 100644 --- a/xmtp_mls/src/api/mod.rs +++ b/xmtp_mls/src/api/mod.rs @@ -28,7 +28,7 @@ impl RetryableError for WrappedApiError { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct ApiClientWrapper { api_client: ApiClient, retry_strategy: Retry, diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index df343be17..1fa1f44fc 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -101,8 +101,8 @@ impl ClientBuilder { impl ClientBuilder where - ApiClient: XmtpApi + 'static, - V: SmartContractSignatureVerifier + 'static, + ApiClient: XmtpApi + Clone + 'static, + V: SmartContractSignatureVerifier + Clone + 'static, { /// Build with a custom smart contract wallet verifier pub async fn build_with_verifier(self) -> Result, ClientBuilderError> { @@ -112,7 +112,7 @@ where impl ClientBuilder> where - ApiClient: XmtpApi + 'static, + ApiClient: XmtpApi + Clone + 'static, { /// Build with the default [`RemoteSignatureVerifier`] pub async fn build(self) -> Result, ClientBuilderError> { @@ -122,8 +122,8 @@ where async fn inner_build(client: ClientBuilder) -> Result, ClientBuilderError> where - C: XmtpApi + 'static, - V: SmartContractSignatureVerifier + 'static, + C: XmtpApi + Clone + 'static, + V: SmartContractSignatureVerifier + Clone + 'static, { let ClientBuilder { mut api_client, diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 89d2e0fce..64788f888 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -233,11 +233,29 @@ pub struct Client> { pub(crate) context: Arc, #[cfg(feature = "message-history")] pub(crate) history_sync_url: Option, - pub(crate) local_events: broadcast::Sender, + pub(crate) local_events: broadcast::Sender>, /// The method of verifying smart contract wallet signatures for this Client pub(crate) scw_verifier: V, } +// most of these things are `Arc`'s +impl Clone for Client +where + ApiClient: Clone, + V: Clone, +{ + fn clone(&self) -> Self { + Self { + api_client: self.api_client.clone(), + context: self.context.clone(), + #[cfg(feature = "message-history")] + history_sync_url: self.history_sync_url.clone(), + local_events: self.local_events.clone(), + scw_verifier: self.scw_verifier.clone(), + } + } +} + /// The local context a XMTP MLS needs to function: /// - Sqlite Database /// - Identity for the User @@ -283,8 +301,8 @@ impl XmtpMlsLocalContext { impl Client where - ApiClient: XmtpApi + 'static, - V: 'static, + ApiClient: XmtpApi + Clone + 'static, + V: SmartContractSignatureVerifier + Clone + 'static, { /// Create a new client with the given network, identity, and store. /// It is expected that most users will use the [`ClientBuilder`](crate::builder::ClientBuilder) instead of instantiating @@ -322,7 +340,8 @@ where impl Client where - ApiClient: XmtpApi, + ApiClient: XmtpApi + Clone, + V: SmartContractSignatureVerifier + Clone, { pub fn installation_public_key(&self) -> Vec { self.context.installation_public_key() @@ -478,17 +497,17 @@ where &self, permissions_policy_set: Option, opts: GroupMetadataOptions, - ) -> Result { + ) -> Result, ClientError> { tracing::info!("creating group"); - let group = MlsGroup::create_and_insert( - self.context.clone(), + let group: MlsGroup> = MlsGroup::create_and_insert( + Arc::new(self.clone()), GroupMembershipState::Allowed, permissions_policy_set.unwrap_or_default(), opts, )?; - // notify any streams of the new group + // notify streams of our new group let _ = self.local_events.send(LocalEvents::NewGroup(group.clone())); Ok(group) @@ -499,26 +518,17 @@ where account_addresses: Vec, permissions_policy_set: Option, opts: GroupMetadataOptions, - ) -> Result { + ) -> Result, ClientError> { tracing::info!("creating group"); + let group = self.create_group(permissions_policy_set, opts)?; - let group = MlsGroup::create_and_insert( - self.context.clone(), - GroupMembershipState::Allowed, - permissions_policy_set.unwrap_or_default(), - opts, - )?; - - group.add_members(self, account_addresses).await?; - - // notify any streams of the new group - let _ = self.local_events.send(LocalEvents::NewGroup(group.clone())); + group.add_members(account_addresses).await?; Ok(group) } /// Create a new Direct Message with the default settings - pub async fn create_dm(&self, account_address: String) -> Result { + pub async fn create_dm(&self, account_address: String) -> Result, ClientError> { tracing::info!("creating dm with address: {}", account_address); let inbox_id = match self @@ -541,17 +551,17 @@ where pub async fn create_dm_by_inbox_id( &self, dm_target_inbox_id: InboxId, - ) -> Result { + ) -> Result, ClientError> { tracing::info!("creating dm with {}", dm_target_inbox_id); - let group = MlsGroup::create_dm_and_insert( - self.context.clone(), + let group: MlsGroup> = MlsGroup::create_dm_and_insert( + Arc::new(self.clone()), GroupMembershipState::Allowed, dm_target_inbox_id.clone(), )?; group - .add_members_by_inbox_id(self, vec![dm_target_inbox_id]) + .add_members_by_inbox_id(vec![dm_target_inbox_id]) .await?; // notify any streams of the new group @@ -570,15 +580,11 @@ where /// Look up a group by its ID /// Returns a [`MlsGroup`] if the group exists, or an error if it does not - pub fn group(&self, group_id: Vec) -> Result { + pub fn group(&self, group_id: Vec) -> Result, ClientError> { let conn = &mut self.store().conn()?; let stored_group: Option = conn.fetch(&group_id)?; match stored_group { - Some(group) => Ok(MlsGroup::new( - self.context.clone(), - group.id, - group.created_at_ns, - )), + Some(group) => Ok(MlsGroup::new(self.clone(), group.id, group.created_at_ns)), None => Err(ClientError::Storage(StorageError::NotFound(format!( "group {}", hex::encode(group_id) @@ -607,7 +613,7 @@ where /// - created_after_ns: only return groups created after the given timestamp (in nanoseconds) /// - created_before_ns: only return groups created before the given timestamp (in nanoseconds) /// - limit: only return the first `limit` groups - pub fn find_groups(&self, params: FindGroupParams) -> Result, ClientError> { + pub fn find_groups(&self, params: FindGroupParams) -> Result>, ClientError> { Ok(self .store() .conn()? @@ -620,11 +626,7 @@ where )? .into_iter() .map(|stored_group| { - MlsGroup::new( - self.context.clone(), - stored_group.id, - stored_group.created_at_ns, - ) + MlsGroup::new(self.clone(), stored_group.id, stored_group.created_at_ns) }) .collect()) } @@ -706,16 +708,15 @@ where .collect::>()?) } - pub(crate) async fn process_for_id( + pub(crate) async fn process_for_id( &self, entity_id: &Vec, entity_kind: EntityKind, cursor: u64, - process_envelope: ProcessingFn, + process_envelope: impl FnOnce(XmtpOpenMlsProvider) -> Fut, ) -> Result where Fut: Future>, - ProcessingFn: FnOnce(XmtpOpenMlsProvider) -> Fut, { self.store() .transaction_async(|provider| async move { @@ -733,12 +734,12 @@ where /// Download all unread welcome messages and convert to groups. /// Returns any new groups created in the operation - pub async fn sync_welcomes(&self) -> Result, ClientError> { + pub async fn sync_welcomes(&self) -> Result>, ClientError> { let envelopes = self.query_welcome_messages(&self.store().conn()?).await?; let num_envelopes = envelopes.len(); let id = self.installation_public_key(); - let groups: Vec = stream::iter(envelopes.into_iter()) + let groups: Vec> = stream::iter(envelopes.into_iter()) .filter_map(|envelope: WelcomeMessage| async { let welcome_v1 = match extract_welcome_message(envelope) { Ok(inner) => inner, @@ -757,7 +758,7 @@ where welcome_v1.id, |provider| async move { let result = MlsGroup::create_from_encrypted_welcome( - self, + Arc::new(self.clone()), &provider, welcome_v1.hpke_public_key.as_slice(), welcome_v1.data, @@ -803,7 +804,7 @@ where /// Sync all groups for the current user and return the number of groups that were synced. /// Only active groups will be synced. - pub async fn sync_all_groups(&self, groups: Vec) -> Result { + pub async fn sync_all_groups(&self, groups: Vec>) -> Result { // Acquire a single connection to be reused let provider: XmtpOpenMlsProvider = self.mls_provider()?; @@ -825,11 +826,9 @@ where mls_group.epoch() ); if mls_group.is_active() { - group - .maybe_update_installations(provider_ref, None, self) - .await?; + group.maybe_update_installations(provider_ref, None).await?; - group.sync_with_conn(provider_ref, self).await?; + group.sync_with_conn(provider_ref).await?; active_group_count.fetch_add(1, Ordering::SeqCst); } diff --git a/xmtp_mls/src/groups/members.rs b/xmtp_mls/src/groups/members.rs index 798a97191..71a4595c2 100644 --- a/xmtp_mls/src/groups/members.rs +++ b/xmtp_mls/src/groups/members.rs @@ -1,6 +1,6 @@ use xmtp_id::InboxId; -use super::{validated_commit::extract_group_membership, GroupError, MlsGroup}; +use super::{validated_commit::extract_group_membership, GroupError, MlsGroup, ScopedGroupClient}; use crate::{ storage::{ @@ -8,7 +8,6 @@ use crate::{ consent_record::{ConsentState, ConsentType}, }, xmtp_openmls_provider::XmtpOpenMlsProvider, - Client, XmtpApi, }; #[derive(Debug, Clone)] @@ -27,19 +26,18 @@ pub enum PermissionLevel { SuperAdmin, } -impl MlsGroup { +impl MlsGroup +where + ScopedClient: ScopedGroupClient, +{ // Load the member list for the group from the DB, merging together multiple installations into a single entry - pub async fn members( - &self, - client: &Client, - ) -> Result, GroupError> { + pub async fn members(&self) -> Result, GroupError> { let provider = self.mls_provider()?; - self.members_with_provider(client, &provider).await + self.members_with_provider(&provider).await } - pub async fn members_with_provider( + pub async fn members_with_provider( &self, - client: &Client, provider: &XmtpOpenMlsProvider, ) -> Result, GroupError> { let openmls_group = self.load_mls_group(provider)?; @@ -72,7 +70,8 @@ impl MlsGroup { }) .collect(); - let mut new_states = client + let mut new_states = self + .client .batch_get_association_state(conn, &missing_requests) .await?; association_states.append(&mut new_states); diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index bb4c79a5e..3b7a30060 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -4,6 +4,8 @@ pub mod group_mutable_metadata; pub mod group_permissions; pub mod intents; pub mod members; +pub mod scoped_client; + #[allow(dead_code)] #[cfg(feature = "message-history")] pub mod message_history; @@ -38,6 +40,7 @@ pub use self::group_permissions::PreconfiguredPolicies; pub use self::intents::{AddressesOrInstallationIds, IntentError}; #[cfg(feature = "message-history")] use self::message_history::MessageHistoryError; +pub(self) use self::scoped_client::ScopedGroupClient; use self::{ group_membership::GroupMembership, group_metadata::{extract_group_metadata, DmMembers}, @@ -92,7 +95,7 @@ use crate::{ }, utils::{id::calculate_message_id, time::now_ns}, xmtp_openmls_provider::XmtpOpenMlsProvider, - Client, Store, XmtpApi, + Store, }; #[derive(Debug, Error)] @@ -219,10 +222,10 @@ impl RetryableError for GroupError { } } -pub struct MlsGroup { +pub struct MlsGroup { pub group_id: Vec, pub created_at_ns: i64, - context: Arc, + pub(crate) client: Arc, mutex: Arc>, } @@ -234,12 +237,12 @@ pub struct GroupMetadataOptions { pub pinned_frame_url: Option, } -impl Clone for MlsGroup { +impl Clone for MlsGroup { fn clone(&self) -> Self { Self { - context: self.context.clone(), group_id: self.group_id.clone(), created_at_ns: self.created_at_ns, + client: self.client.clone(), mutex: self.mutex.clone(), } } @@ -253,22 +256,33 @@ pub enum UpdateAdminListType { RemoveSuper, } -impl MlsGroup { +impl MlsGroup +where + ScopedClient: ScopedGroupClient, +{ // Creates a new group instance. Does not validate that the group exists in the DB - pub fn new(context: Arc, group_id: Vec, created_at_ns: i64) -> Self { - let mut mutexes = context.mutexes.clone(); + pub fn new(client: ScopedClient, group_id: Vec, created_at_ns: i64) -> Self { + Self::new_from_arc(Arc::new(client), group_id, created_at_ns) + } + + pub fn new_from_arc(client: Arc, group_id: Vec, created_at_ns: i64) -> Self { + let mut mutexes = client.context().mutexes.clone(); Self { - context, group_id: group_id.clone(), created_at_ns, mutex: mutexes.get_mutex(group_id), + client, } } + pub(self) fn context(&self) -> &Arc { + self.client.context() + } + /// Instantiate a new [`XmtpOpenMlsProvider`] pulling a connection from the database. /// prefer to use an already-instantiated mls provider if possible. pub fn mls_provider(&self) -> Result { - Ok(self.context.mls_provider()?) + Ok(self.context().mls_provider()?) } // Load the stored MLS group from the OpenMLS provider's keystore @@ -287,11 +301,12 @@ impl MlsGroup { // Create a new group and save it to the DB pub fn create_and_insert( - context: Arc, + client: Arc, membership_state: GroupMembershipState, permissions_policy_set: PolicySet, opts: GroupMetadataOptions, ) -> Result { + let context = client.context(); let conn = context.store().conn()?; let provider = XmtpOpenMlsProvider::new(conn); let creator_inbox_id = context.inbox_id(); @@ -327,7 +342,7 @@ impl MlsGroup { ); stored_group.store(provider.conn_ref())?; - let new_group = Self::new(context.clone(), group_id, stored_group.created_at_ns); + let new_group = Self::new_from_arc(client.clone(), group_id, stored_group.created_at_ns); // Consent state defaults to allowed when the user creates the group new_group.update_consent_state(ConsentState::Allowed)?; @@ -336,10 +351,11 @@ impl MlsGroup { // Create a new DM and save it to the DB pub fn create_dm_and_insert( - context: Arc, + client: Arc, membership_state: GroupMembershipState, dm_target_inbox_id: InboxId, ) -> Result { + let context = client.context(); let conn = context.store().conn()?; let provider = XmtpOpenMlsProvider::new(conn); let protected_metadata = @@ -377,8 +393,8 @@ impl MlsGroup { ); stored_group.store(provider.conn_ref())?; - Ok(Self::new( - context.clone(), + Ok(Self::new_from_arc( + client.clone(), group_id, stored_group.created_at_ns, )) @@ -386,8 +402,8 @@ impl MlsGroup { // Create a group from a decrypted and decoded welcome message // If the group already exists in the store, overwrite the MLS state and do not update the group entry - async fn create_from_welcome( - client: &Client, + async fn create_from_welcome( + client: Arc, provider: &XmtpOpenMlsProvider, welcome: MlsWelcome, added_by_inbox: String, @@ -423,7 +439,7 @@ impl MlsGroup { dm_inbox_id, ), ConversationType::Dm => { - validate_dm_group(client, &mls_group, &added_by_inbox)?; + validate_dm_group(&client, &mls_group, &added_by_inbox)?; StoredGroup::new_from_welcome( group_id.clone(), now_ns(), @@ -445,20 +461,20 @@ impl MlsGroup { ), }; - validate_initial_group_membership(client, provider.conn_ref(), &mls_group).await?; + validate_initial_group_membership(&client, provider.conn_ref(), &mls_group).await?; let stored_group = provider.conn_ref().insert_or_replace_group(to_store)?; - Ok(Self::new( - client.context.clone(), + Ok(Self::new_from_arc( + client.clone(), stored_group.id, stored_group.created_at_ns, )) } // Decrypt a welcome message using HPKE and then create and save a group from the stored message - pub async fn create_from_encrypted_welcome( - client: &Client, + pub async fn create_from_encrypted_welcome( + client: Arc, provider: &XmtpOpenMlsProvider, hpke_public_key: &[u8], encrypted_welcome_bytes: Vec, @@ -535,26 +551,18 @@ impl MlsGroup { } /// Send a message on this users XMTP [`Client`]. - pub async fn send_message( - &self, - message: &[u8], - client: &Client, - ) -> Result, GroupError> - where - ApiClient: XmtpApi, - { + pub async fn send_message(&self, message: &[u8]) -> Result, GroupError> { let update_interval_ns = Some(SEND_MESSAGE_UPDATE_INSTALLATIONS_INTERVAL_NS); - let conn = self.context.store().conn()?; + let conn = self.context().store().conn()?; let provider = XmtpOpenMlsProvider::from(conn); - self.maybe_update_installations(&provider, update_interval_ns, client) + self.maybe_update_installations(&provider, update_interval_ns) .await?; let message_id = self.prepare_message(message, provider.conn_ref(), |now| { Self::into_envelope(message, now) }); - self.sync_until_last_intent_resolved(&provider, client) - .await?; + self.sync_until_last_intent_resolved(&provider).await?; // implicitly set group consent state to allowed self.update_consent_state(ConsentState::Allowed)?; @@ -563,20 +571,13 @@ impl MlsGroup { } /// Publish all unpublished messages - pub async fn publish_messages( - &self, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; + pub async fn publish_messages(&self) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let provider = XmtpOpenMlsProvider::from(conn); let update_interval_ns = Some(SEND_MESSAGE_UPDATE_INSTALLATIONS_INTERVAL_NS); - self.maybe_update_installations(&provider, update_interval_ns, client) - .await?; - self.sync_until_last_intent_resolved(&provider, client) + self.maybe_update_installations(&provider, update_interval_ns) .await?; + self.sync_until_last_intent_resolved(&provider).await?; // implicitly set group consent state to allowed self.update_consent_state(ConsentState::Allowed)?; @@ -585,23 +586,16 @@ impl MlsGroup { } /// Update group installations - pub async fn update_installations( - &self, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; + pub async fn update_installations(&self) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let provider = XmtpOpenMlsProvider::from(conn); - self.maybe_update_installations(&provider, Some(0), client) - .await?; + self.maybe_update_installations(&provider, Some(0)).await?; Ok(()) } /// Send a message, optimistically returning the ID of the message before the result of a message publish. pub fn send_message_optimistic(&self, message: &[u8]) -> Result, GroupError> { - let conn = self.context.store().conn()?; + let conn = self.context().store().conn()?; let message_id = self.prepare_message(message, &conn, |now| Self::into_envelope(message, now))?; Ok(message_id) @@ -643,8 +637,8 @@ impl MlsGroup { decrypted_message_bytes: message.to_vec(), sent_at_ns: now, kind: GroupMessageKind::Application, - sender_installation_id: self.context.installation_public_key(), - sender_inbox_id: self.context.inbox_id(), + sender_installation_id: self.context().installation_public_key(), + sender_inbox_id: self.context().inbox_id(), delivery_status: DeliveryStatus::Unpublished, }; group_message.store(conn)?; @@ -671,7 +665,7 @@ impl MlsGroup { delivery_status: Option, limit: Option, ) -> Result, GroupError> { - let conn = self.context.store().conn()?; + let conn = self.context().store().conn()?; let messages = conn.get_group_messages( &self.group_id, sent_after_ns, @@ -691,21 +685,18 @@ impl MlsGroup { * will be added as part of this process as well. */ #[tracing::instrument(level = "trace", skip_all)] - pub async fn add_members( + pub async fn add_members( &self, - client: &Client, account_addresses_to_add: Vec, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), GroupError> { let account_addresses = sanitize_evm_addresses(account_addresses_to_add)?; - let inbox_id_map = client - .api_client + let inbox_id_map = self + .client + .api() .get_inbox_ids(account_addresses.clone()) .await?; // get current number of users in group - let member_count = self.members(client).await?.len(); + let member_count = self.members().await?.len(); if member_count + inbox_id_map.len() > MAX_GROUP_SIZE as usize { return Err(GroupError::UserLimitExceeded); } @@ -719,19 +710,15 @@ impl MlsGroup { )); } - self.add_members_by_inbox_id(client, inbox_id_map.into_values().collect()) + self.add_members_by_inbox_id(inbox_id_map.into_values().collect()) .await } #[tracing::instrument(level = "trace", skip_all)] - pub async fn add_members_by_inbox_id( - &self, - client: &Client, - inbox_ids: Vec, - ) -> Result<(), GroupError> { - let provider = client.mls_provider()?; + pub async fn add_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<(), GroupError> { + let provider = self.client.mls_provider()?; let intent_data = self - .get_membership_update_intent(client, &provider, inbox_ids, vec![]) + .get_membership_update_intent(&provider, inbox_ids, vec![]) .await?; // TODO:nm this isn't the best test for whether the request is valid @@ -750,31 +737,30 @@ impl MlsGroup { intent_data.into(), ))?; - self.sync_until_intent_resolved(&provider, intent.id, client) - .await + self.sync_until_intent_resolved(&provider, intent.id).await } - pub async fn remove_members( + pub async fn remove_members( &self, - client: &Client, + client: ScopedClient, account_addresses_to_remove: Vec, ) -> Result<(), GroupError> { let account_addresses = sanitize_evm_addresses(account_addresses_to_remove)?; - let inbox_id_map = client.api_client.get_inbox_ids(account_addresses).await?; + let inbox_id_map = client.api().get_inbox_ids(account_addresses).await?; self.remove_members_by_inbox_id(client, inbox_id_map.into_values().collect()) .await } - pub async fn remove_members_by_inbox_id( + pub async fn remove_members_by_inbox_id( &self, - client: &Client, + client: ScopedClient, inbox_ids: Vec, ) -> Result<(), GroupError> { let provider = client.store().conn()?.into(); let intent_data = self - .get_membership_update_intent(client, &provider, vec![], inbox_ids) + .get_membership_update_intent(&provider, vec![], inbox_ids) .await?; let intent = provider @@ -785,19 +771,11 @@ impl MlsGroup { intent_data.into(), ))?; - self.sync_until_intent_resolved(&provider, intent.id, client) - .await + self.sync_until_intent_resolved(&provider, intent.id).await } - pub async fn update_group_name( - &self, - client: &Client, - group_name: String, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; + pub async fn update_group_name(&self, group_name: String) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let intent_data: Vec = UpdateMetadataIntentData::new_update_group_name(group_name).into(); let intent = conn.insert_group_intent(NewGroupIntent::new( @@ -806,18 +784,17 @@ impl MlsGroup { intent_data, ))?; - self.sync_until_intent_resolved(&conn.into(), intent.id, client) + self.sync_until_intent_resolved(&conn.into(), intent.id) .await } - pub async fn update_permission_policy( + pub async fn update_permission_policy( &self, - client: &Client, permission_update_type: PermissionUpdateType, permission_policy: PermissionPolicyOption, metadata_field: Option, ) -> Result<(), GroupError> { - let conn = client.store().conn()?; + let conn = self.client.store().conn()?; if permission_update_type == PermissionUpdateType::UpdateMetadata && metadata_field.is_none() @@ -838,7 +815,7 @@ impl MlsGroup { intent_data, ))?; - self.sync_until_intent_resolved(&conn.into(), intent.id, client) + self.sync_until_intent_resolved(&conn.into(), intent.id) .await } @@ -857,13 +834,9 @@ impl MlsGroup { pub async fn update_group_description( &self, - client: &Client, group_description: String, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; + ) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let intent_data: Vec = UpdateMetadataIntentData::new_update_group_description(group_description).into(); let intent = conn.insert_group_intent(NewGroupIntent::new( @@ -872,7 +845,7 @@ impl MlsGroup { intent_data, ))?; - self.sync_until_intent_resolved(&conn.into(), intent.id, client) + self.sync_until_intent_resolved(&conn.into(), intent.id) .await } @@ -889,15 +862,11 @@ impl MlsGroup { } } - pub async fn update_group_image_url_square( + pub async fn update_group_image_url_square( &self, - client: &Client, group_image_url_square: String, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; + ) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let intent_data: Vec = UpdateMetadataIntentData::new_update_group_image_url_square(group_image_url_square) .into(); @@ -907,7 +876,7 @@ impl MlsGroup { intent_data, ))?; - self.sync_until_intent_resolved(&conn.into(), intent.id, client) + self.sync_until_intent_resolved(&conn.into(), intent.id) .await } @@ -927,15 +896,11 @@ impl MlsGroup { } } - pub async fn update_group_pinned_frame_url( + pub async fn update_group_pinned_frame_url( &self, - client: &Client, pinned_frame_url: String, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; + ) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let intent_data: Vec = UpdateMetadataIntentData::new_update_group_pinned_frame_url(pinned_frame_url).into(); let intent = conn.insert_group_intent(NewGroupIntent::new( @@ -944,7 +909,7 @@ impl MlsGroup { intent_data, ))?; - self.sync_until_intent_resolved(&conn.into(), intent.id, client) + self.sync_until_intent_resolved(&conn.into(), intent.id) .await } @@ -995,16 +960,12 @@ impl MlsGroup { Ok(mutable_metadata.super_admin_list.contains(&inbox_id)) } - pub async fn update_admin_list( + pub async fn update_admin_list( &self, - client: &Client, action_type: UpdateAdminListType, inbox_id: String, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; + ) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let intent_action_type = match action_type { UpdateAdminListType::Add => AdminListActionType::Add, UpdateAdminListType::Remove => AdminListActionType::Remove, @@ -1019,13 +980,13 @@ impl MlsGroup { intent_data, ))?; - self.sync_until_intent_resolved(&conn.into(), intent.id, client) + self.sync_until_intent_resolved(&conn.into(), intent.id) .await } /// Find the `inbox_id` of the group member who added the member to the group pub fn added_by_inbox_id(&self) -> Result { - let conn = self.context.store().conn()?; + let conn = self.context().store().conn()?; conn.find_group(self.group_id.clone()) .map_err(GroupError::from) .and_then(|fetch_result| { @@ -1037,7 +998,7 @@ impl MlsGroup { /// Find the `consent_state` of the group pub fn consent_state(&self) -> Result { - let conn = self.context.store().conn()?; + let conn = self.context().store().conn()?; let record = conn.get_consent_record(hex::encode(self.group_id.clone()), ConsentType::GroupId)?; @@ -1048,7 +1009,7 @@ impl MlsGroup { } pub fn update_consent_state(&self, state: ConsentState) -> Result<(), GroupError> { - let conn = self.context.store().conn()?; + let conn = self.context().store().conn()?; conn.insert_or_replace_consent_records(vec![StoredConsentRecord::new( ConsentType::GroupId, state, @@ -1059,18 +1020,15 @@ impl MlsGroup { } // Update this installation's leaf key in the group by creating a key update commit - pub async fn key_update(&self, client: &Client) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; + pub async fn key_update(&self) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let intent = conn.insert_group_intent(NewGroupIntent::new( IntentKind::KeyUpdate, self.group_id.clone(), vec![], ))?; - self.sync_until_intent_resolved(&conn.into(), intent.id, client) + self.sync_until_intent_resolved(&conn.into(), intent.id) .await } @@ -1094,7 +1052,7 @@ impl MlsGroup { } pub fn permissions(&self) -> Result { - let conn = self.context.store().conn()?; + let conn = self.context().store().conn()?; let provider = XmtpOpenMlsProvider::new(conn); let mls_group = self.load_mls_group(&provider)?; @@ -1433,16 +1391,16 @@ fn build_group_config( .build()) } -async fn validate_initial_group_membership( - client: &Client, +async fn validate_initial_group_membership( + client: impl ScopedGroupClient, conn: &DbConnection, mls_group: &OpenMlsGroup, ) -> Result<(), GroupError> { tracing::info!("Validating initial group membership"); let membership = extract_group_membership(mls_group.extensions())?; - let needs_update = client.filter_inbox_ids_needing_updates(conn, membership.to_filters())?; + let needs_update = conn.filter_inbox_ids_needing_updates(membership.to_filters())?; if !needs_update.is_empty() { - load_identity_updates(&client.api_client, conn, needs_update).await?; + load_identity_updates(&client.api(), conn, needs_update).await?; } let mut expected_installation_ids = HashSet::>::new(); @@ -1474,8 +1432,8 @@ async fn validate_initial_group_membership( Ok(()) } -fn validate_dm_group( - client: &Client, +fn validate_dm_group( + client: impl ScopedGroupClient, mls_group: &OpenMlsGroup, added_by_inbox: &str, ) -> Result<(), GroupError> { @@ -1490,7 +1448,7 @@ fn validate_dm_group( // Check if DmMembers are set and validate their contents if let Some(dm_members) = metadata.dm_members { - let our_inbox_id = client.context.identity.inbox_id().clone(); + let our_inbox_id = client.context().identity.inbox_id().clone(); if !((dm_members.member_one_inbox_id == added_by_inbox && dm_members.member_two_inbox_id == our_inbox_id) || (dm_members.member_one_inbox_id == our_inbox_id @@ -1573,9 +1531,9 @@ pub(crate) mod tests { Client, InboxOwner, StreamHandle as _, XmtpApi, }; - use super::{group_permissions::PolicySet, MlsGroup}; + use super::{group_permissions::PolicySet, MlsGroup, ScopedGroupClient}; - async fn receive_group_invite(client: &Client) -> MlsGroup + async fn receive_group_invite(client: impl ScopedGroupClient) -> MlsGroup where ApiClient: XmtpApi, { @@ -1585,13 +1543,10 @@ pub(crate) mod tests { groups.remove(0) } - async fn get_latest_message( + async fn get_latest_message( group: &MlsGroup, - client: &Client, - ) -> StoredGroupMessage - where - ApiClient: XmtpApi, - { + client: impl ScopedGroupClient, + ) -> StoredGroupMessage { group.sync(client).await.unwrap(); let mut messages = group.find_messages(None, None, None, None, None).unwrap(); messages.pop().unwrap() @@ -1600,9 +1555,9 @@ pub(crate) mod tests { // Adds a member to the group without the usual validations on group membership // Used for testing adversarial scenarios #[cfg(not(target_arch = "wasm32"))] - async fn force_add_member( - sender_client: &Client, - new_member_client: &Client, + async fn force_add_member( + sender_client: impl ScopedGroupClient, + new_member_client: impl ScopedGroupClient, sender_group: &MlsGroup, sender_mls_group: &mut openmls::prelude::MlsGroup, sender_provider: &XmtpOpenMlsProvider, @@ -2188,6 +2143,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_add_missing_installations() { + crate::utils::wasm::init().await; // Setup for test let amal_wallet = generate_local_wallet(); let amal = ClientBuilder::new_test_client(&amal_wallet).await; @@ -3438,15 +3394,13 @@ pub(crate) mod tests { } // Create a membership update intent, but don't sync it yet - async fn create_membership_update_no_sync( + async fn create_membership_update_no_sync( group: &MlsGroup, provider: &XmtpOpenMlsProvider, - client: &Client, - ) where - ApiClient: XmtpApi, - { + client: impl ScopedGroupClient, + ) { let intent_data = group - .get_membership_update_intent(client, provider, vec![], vec![]) + .get_membership_update_intent(provider, vec![], vec![]) .await .unwrap(); diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index df022f53e..c702ac674 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -1,30 +1,32 @@ +use futures::{Stream, StreamExt}; use std::collections::HashMap; use std::sync::Arc; +use tokio::sync::oneshot; +use xmtp_proto::api_client::trait_impls::XmtpApi; -use futures::Stream; - -use super::{extract_message_v1, GroupError, MlsGroup}; +use super::{extract_message_v1, GroupError, MlsGroup, ScopedGroupClient}; +use crate::api::GroupFilter; +use crate::client::ClientError; +use crate::groups::extract_group_id; use crate::storage::group_message::StoredGroupMessage; use crate::storage::refresh_state::EntityKind; use crate::storage::StorageError; use crate::subscriptions::MessagesStreamInfo; -use crate::XmtpApi; -use crate::{retry::Retry, retry_async, Client}; +use crate::{retry::Retry, retry_async}; use prost::Message; use xmtp_proto::xmtp::mls::api::v1::GroupMessage; -impl MlsGroup { - pub(crate) async fn process_stream_entry( +impl MlsGroup +where + ScopedClient: ScopedGroupClient + Clone + Send + Sync, +{ + pub(crate) async fn process_stream_entry( &self, envelope: GroupMessage, - client: &Client, - ) -> Result, GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result, GroupError> { let msgv1 = extract_message_v1(envelope)?; let msg_id = msgv1.id; - let client_id = client.inbox_id(); + let client_id = self.client.inbox_id(); tracing::info!( "client [{}] is about to process streamed envelope: [{}]", &client_id.clone(), @@ -38,7 +40,7 @@ impl MlsGroup { (async { let client_id = client_id.clone(); let msgv1 = msgv1.clone(); - self.context + self.context() .store() .transaction_async(|provider| async move { let mut openmls_group = self.load_mls_group(&provider)?; @@ -51,15 +53,9 @@ impl MlsGroup { openmls_group.epoch() ); - self.process_message( - client, - &mut openmls_group, - &provider, - &msgv1, - false, - ) - .await - .map_err(GroupError::ReceiveError) + self.process_message(&mut openmls_group, &provider, &msgv1, false) + .await + .map_err(GroupError::ReceiveError) }) .await }) @@ -68,7 +64,7 @@ impl MlsGroup { if let Some(GroupError::ReceiveError(_)) = process_result.as_ref().err() { // Swallow errors here, since another process may have successfully saved the message // to the DB - match self.sync_with_conn(&client.mls_provider()?, client).await { + match self.sync_with_conn(&self.client.mls_provider()?).await { Ok(_) => { tracing::debug!("Sync triggered by streamed message successful") } @@ -84,7 +80,7 @@ impl MlsGroup { // Load the message from the DB to handle cases where it may have been already processed in // another thread let new_message = self - .context + .context() .store() .conn()? .get_group_message_by_timestamp(&self.group_id, created_ns as i64)?; @@ -95,7 +91,7 @@ impl MlsGroup { // Checks if a message has already been processed through a sync async fn has_already_synced(&self, id: u64) -> Result { let check_for_last_cursor = || -> Result { - let conn = self.context.store().conn()?; + let conn = self.context().store().conn()?; conn.get_last_cursor_for_id(&self.group_id, EntityKind::Group) }; @@ -103,62 +99,139 @@ impl MlsGroup { Ok(last_id >= id as i64) } - pub async fn process_streamed_group_message( + pub async fn process_streamed_group_message( &self, envelope_bytes: Vec, - client: &Client, - ) -> Result - where - ApiClient: XmtpApi, - { + ) -> Result { let envelope = GroupMessage::decode(envelope_bytes.as_slice()) .map_err(|e| GroupError::Generic(e.to_string()))?; - let message = self.process_stream_entry(envelope, client).await?; + let message = self.process_stream_entry(envelope).await?; message.ok_or(GroupError::MissingMessage) } - pub async fn stream<'a, ApiClient>( + pub async fn stream<'a>( &'a self, - client: &'a Client, ) -> Result + '_, GroupError> where - ApiClient: crate::XmtpApi + 'static, + ScopedClient: 'static, + ::ApiClient: 'static, { - Ok(client - .stream_messages(Arc::new(HashMap::from([( - self.group_id.clone(), - MessagesStreamInfo { - convo_created_at_ns: self.created_at_ns, - cursor: 0, - }, - )]))) - .await?) + let group_list = HashMap::from([( + self.group_id.clone(), + MessagesStreamInfo { + convo_created_at_ns: self.created_at_ns, + cursor: 0, + }, + )]); + Ok(stream_messages(&*self.client, Arc::new(group_list)).await?) } - pub fn stream_with_callback( - client: Arc>, + pub fn stream_with_callback( + client: ScopedClient, group_id: Vec, created_at_ns: i64, callback: impl FnMut(StoredGroupMessage) + Send + 'static, ) -> impl crate::StreamHandle> where - ApiClient: crate::XmtpApi + 'static, + ScopedClient: 'static, + ::ApiClient: 'static, { - Client::::stream_messages_with_callback( - client, - HashMap::from([( - group_id, - MessagesStreamInfo { - convo_created_at_ns: created_at_ns, - cursor: 0, - }, - )]), - callback, - ) + let group_list = HashMap::from([( + group_id, + MessagesStreamInfo { + convo_created_at_ns: created_at_ns, + cursor: 0, + }, + )]); + stream_messages_with_callback(Arc::new(client), group_list, callback) } } +/// Stream messages from groups in `group_id_to_info` +pub(crate) async fn stream_messages<'s, ScopedClient>( + client: &'s ScopedClient, + group_id_to_info: Arc, MessagesStreamInfo>>, +) -> Result + 's, ClientError> +where + ScopedClient: ScopedGroupClient + Clone + Sync + Send + 'static, + ::ApiClient: XmtpApi + 'static, +{ + let filters: Vec = group_id_to_info + .iter() + .map(|(group_id, info)| GroupFilter::new(group_id.clone(), Some(info.cursor))) + .collect(); + + let messages_subscription = client.api().subscribe_group_messages(filters).await?; + + let stream = messages_subscription + .map(move |res| { + let group_id_to_info = group_id_to_info.clone(); + async move { + match res { + Ok(envelope) => { + tracing::info!("Received message streaming payload"); + let group_id = extract_group_id(&envelope)?; + tracing::info!("Extracted group id {}", hex::encode(&group_id)); + let stream_info = group_id_to_info.get(&group_id).ok_or( + ClientError::StreamInconsistency( + "Received message for a non-subscribed group".to_string(), + ), + )?; + let mls_group = MlsGroup::new( + client.clone(), + group_id, + stream_info.convo_created_at_ns, + ); + mls_group.process_stream_entry(envelope).await + } + Err(err) => Err(GroupError::Api(err)), + } + } + }) + .filter_map(|res| async { + match res.await { + Ok(Some(message)) => Some(message), + Ok(None) => { + tracing::info!("Skipped message streaming payload"); + None + } + Err(err) => { + tracing::error!("Error processing stream entry: {:?}", err); + None + } + } + }); + Ok(stream) +} + +/// Stream messages from groups in `group_id_to_info`, passing +/// messages along to a callback. +pub(crate) fn stream_messages_with_callback( + client: Arc, + group_id_to_info: HashMap, MessagesStreamInfo>, + mut callback: impl FnMut(StoredGroupMessage) + Send + 'static, +) -> impl crate::StreamHandle> +where + ScopedClient: ScopedGroupClient + Send + Sync + Clone + 'static, + ::ApiClient: XmtpApi + 'static, +{ + let (tx, rx) = oneshot::channel(); + + let client = client.clone(); + crate::spawn(Some(rx), async move { + let client = Arc::clone(&client); + let stream = stream_messages(&client, Arc::new(group_id_to_info)).await?; + futures::pin_mut!(stream); + let _ = tx.send(()); + while let Some(message) = stream.next().await { + callback(message) + } + tracing::debug!("`stream_messages` stream ended, dropping stream"); + Ok::<_, ClientError>(()) + }) +} + #[cfg(test)] pub(crate) mod tests { #[cfg(target_arch = "wasm32")] diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index d12811303..ac1573b52 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -11,7 +11,7 @@ use super::{ UpdateAdminListIntentData, UpdateGroupMembershipIntentData, UpdatePermissionIntentData, }, validated_commit::extract_group_membership, - GroupError, MlsGroup, + GroupError, MlsGroup, ScopedGroupClient, }; #[cfg(feature = "message-history")] use crate::groups::message_history::MessageHistoryContent; @@ -37,7 +37,7 @@ use crate::{ }, utils::{hash::sha256, id::calculate_message_id}, xmtp_openmls_provider::XmtpOpenMlsProvider, - Client, Delete, Fetch, StoreOrIgnore, XmtpApi, + Delete, Fetch, StoreOrIgnore, }; use futures::future::try_join_all; use openmls::{ @@ -85,55 +85,50 @@ struct PublishIntentData { payload_to_publish: Vec, } -impl MlsGroup { - pub async fn sync(&self, client: &Client) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let conn = self.context.store().conn()?; +impl MlsGroup +where + ScopedClient: ScopedGroupClient, +{ + pub async fn sync(&self) -> Result<(), GroupError> { + let conn = self.context().store().conn()?; let mls_provider = XmtpOpenMlsProvider::from(conn); - tracing::info!("[{}] syncing group", client.inbox_id()); + tracing::info!("[{}] syncing group", self.client.inbox_id()); tracing::info!( "current epoch for [{}] in sync() is Epoch: [{}]", - client.inbox_id(), + self.client.inbox_id(), self.load_mls_group(&mls_provider)?.epoch() ); - self.maybe_update_installations(&mls_provider, None, client) - .await?; + self.maybe_update_installations(&mls_provider, None).await?; - self.sync_with_conn(&mls_provider, client).await + self.sync_with_conn(&mls_provider).await } - #[tracing::instrument(level = "trace", skip(self, provider, client))] - pub(crate) async fn sync_with_conn( + #[tracing::instrument(level = "trace", skip(self, provider))] + pub(crate) async fn sync_with_conn( &self, provider: &XmtpOpenMlsProvider, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), GroupError> { let _mutex = self.mutex.lock().await; let mut errors: Vec = vec![]; let conn = provider.conn_ref(); // Even if publish fails, continue to receiving - if let Err(publish_error) = self.publish_intents(provider, client).await { + if let Err(publish_error) = self.publish_intents(provider).await { tracing::error!("Sync: error publishing intents {:?}", publish_error); errors.push(publish_error); } // Even if receiving fails, continue to post_commit - if let Err(receive_error) = self.receive(provider, client).await { + if let Err(receive_error) = self.receive(provider).await { tracing::error!("receive error {:?}", receive_error); // We don't return an error if receive fails, because it's possible this is caused // by malicious data sent over the network, or messages from before the user was // added to the group } - if let Err(post_commit_err) = self.post_commit(conn, client).await { + if let Err(post_commit_err) = self.post_commit(conn).await { tracing::error!("post commit error {:?}", post_commit_err); errors.push(post_commit_err); } @@ -145,14 +140,10 @@ impl MlsGroup { Ok(()) } - pub(super) async fn sync_until_last_intent_resolved( + pub(super) async fn sync_until_last_intent_resolved( &self, provider: &XmtpOpenMlsProvider, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), GroupError> { let intents = provider.conn_ref().find_group_intents( self.group_id.clone(), Some(vec![IntentState::ToPublish, IntentState::Published]), @@ -163,7 +154,7 @@ impl MlsGroup { return Ok(()); } - self.sync_until_intent_resolved(provider, intents[intents.len() - 1].id, client) + self.sync_until_intent_resolved(provider, intents[intents.len() - 1].id) .await } @@ -174,21 +165,17 @@ impl MlsGroup { * * This method will retry up to `crate::configuration::MAX_GROUP_SYNC_RETRIES` times. */ - #[tracing::instrument(level = "trace", skip(client, self, provider))] - pub(super) async fn sync_until_intent_resolved( + #[tracing::instrument(level = "trace", skip(self, provider))] + pub(super) async fn sync_until_intent_resolved( &self, provider: &XmtpOpenMlsProvider, intent_id: ID, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), GroupError> { let mut num_attempts = 0; // Return the last error to the caller if we fail to sync let mut last_err: Option = None; while num_attempts < crate::configuration::MAX_GROUP_SYNC_RETRIES { - if let Err(err) = self.sync_with_conn(provider, client).await { + if let Err(err) = self.sync_with_conn(provider).await { tracing::error!("error syncing group {:?}", err); last_err = Some(err); } @@ -258,9 +245,8 @@ impl MlsGroup { #[allow(clippy::too_many_arguments)] #[tracing::instrument(level = "trace", skip_all)] - async fn process_own_message( + async fn process_own_message( &self, - client: &Client, intent: StoredGroupIntent, openmls_group: &mut OpenMlsGroup, provider: &XmtpOpenMlsProvider, @@ -274,7 +260,7 @@ impl MlsGroup { let group_epoch = openmls_group.epoch(); debug!( "[{}]-[{}] processing own message for intent {} / {:?}, group epoch: {}, message_epoch: {}", - self.context.inbox_id(), + self.context().inbox_id(), hex::encode(self.group_id.clone()), intent.id, intent.kind, @@ -311,13 +297,13 @@ impl MlsGroup { tracing::info!( "[{}] Validating commit for intent {}. Message timestamp: {}", - self.context.inbox_id(), + self.context().inbox_id(), intent.id, envelope_timestamp_ns ); let maybe_validated_commit = ValidatedCommit::from_staged_commit( - client, + &self.client, conn, &pending_commit, openmls_group, @@ -339,7 +325,7 @@ impl MlsGroup { tracing::info!( "[{}] merging pending commit for intent {}", - self.context.inbox_id(), + self.context().inbox_id(), intent.id ); if let Err(err) = openmls_group.merge_staged_commit(&provider, pending_commit) { @@ -352,7 +338,7 @@ impl MlsGroup { } IntentKind::SendMessage => { if !Self::is_valid_epoch( - self.context.inbox_id(), + self.context().inbox_id(), intent.id, group_epoch, message_epoch, @@ -370,9 +356,8 @@ impl MlsGroup { } #[tracing::instrument(level = "trace", skip_all)] - async fn process_external_message( + async fn process_external_message( &self, - client: &Client, openmls_group: &mut OpenMlsGroup, provider: &XmtpOpenMlsProvider, message: PrivateMessageIn, @@ -383,12 +368,15 @@ impl MlsGroup { extract_message_sender(openmls_group, &decrypted_message, envelope_timestamp_ns)?; tracing::info!( "[{}] extracted sender inbox id: {}", - self.context.inbox_id(), + self.context().inbox_id(), sender_inbox_id ); match decrypted_message.into_content() { ProcessedMessageContent::ApplicationMessage(application_message) => { - tracing::info!("[{}] decoding application message", self.context.inbox_id()); + tracing::info!( + "[{}] decoding application message", + self.context().inbox_id() + ); let message_bytes = application_message.into_bytes(); let mut bytes = Bytes::from(message_bytes.clone()); @@ -483,14 +471,14 @@ impl MlsGroup { ProcessedMessageContent::StagedCommitMessage(staged_commit) => { tracing::info!( "[{}] received staged commit. Merging and clearing any pending commits", - self.context.inbox_id() + self.context().inbox_id() ); let sc = *staged_commit; // Validate the commit let validated_commit = ValidatedCommit::from_staged_commit( - client, + &self.client, provider.conn_ref(), &sc, openmls_group, @@ -498,7 +486,7 @@ impl MlsGroup { .await?; tracing::info!( "[{}] staged commit is valid, will attempt to merge", - self.context.inbox_id() + self.context().inbox_id() ); openmls_group.merge_staged_commit(provider, sc)?; self.save_transcript_message( @@ -513,9 +501,8 @@ impl MlsGroup { } #[tracing::instrument(level = "trace", skip_all)] - pub(super) async fn process_message( + pub(super) async fn process_message( &self, - client: &Client, openmls_group: &mut OpenMlsGroup, provider: &XmtpOpenMlsProvider, envelope: &GroupMessageV1, @@ -544,13 +531,12 @@ impl MlsGroup { let intent_id = intent.id; tracing::info!( "client [{}] is about to process own envelope [{}] for intent [{}]", - client.inbox_id(), + self.client.inbox_id(), envelope.id, intent_id ); match self .process_own_message( - client, intent, openmls_group, provider, @@ -579,44 +565,34 @@ impl MlsGroup { Ok(None) => { tracing::info!( "client [{}] is about to process external envelope [{}]", - client.inbox_id(), + self.client.inbox_id(), envelope.id ); - self.process_external_message( - client, - openmls_group, - provider, - message, - envelope.created_ns, - ) - .await + self.process_external_message(openmls_group, provider, message, envelope.created_ns) + .await } Err(err) => Err(MessageProcessingError::Storage(err)), } } #[tracing::instrument(level = "trace", skip_all)] - async fn consume_message( + async fn consume_message( &self, envelope: &GroupMessage, openmls_group: &mut OpenMlsGroup, - client: &Client, - ) -> Result<(), MessageProcessingError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), MessageProcessingError> { let msgv1 = match &envelope.version { Some(GroupMessageVersion::V1(value)) => value, _ => return Err(MessageProcessingError::InvalidPayload), }; - client + self.client .process_for_id( &msgv1.group_id, EntityKind::Group, msgv1.id, |provider| async move { - self.process_message(client, openmls_group, &provider, msgv1, true) + self.process_message(openmls_group, &provider, msgv1, true) .await?; Ok(()) }, @@ -626,25 +602,18 @@ impl MlsGroup { } #[tracing::instrument(level = "trace", skip_all)] - pub async fn process_messages( + pub async fn process_messages( &self, messages: Vec, provider: &XmtpOpenMlsProvider, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), GroupError> { let mut openmls_group = self.load_mls_group(provider)?; let mut receive_errors = vec![]; for message in messages.into_iter() { let result = retry_async!( Retry::default(), - (async { - self.consume_message(&message, &mut openmls_group, client) - .await - }) + (async { self.consume_message(&message, &mut openmls_group).await }) ); if let Err(e) = result { let is_retryable = e.is_retryable(); @@ -671,18 +640,12 @@ impl MlsGroup { } #[tracing::instrument(level = "trace", skip_all)] - pub(super) async fn receive( - &self, - provider: &XmtpOpenMlsProvider, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { - let messages = client + pub(super) async fn receive(&self, provider: &XmtpOpenMlsProvider) -> Result<(), GroupError> { + let messages = self + .client .query_group_messages(&self.group_id, provider.conn_ref()) .await?; - self.process_messages(messages, provider, client).await?; + self.process_messages(messages, provider).await?; Ok(()) } @@ -698,7 +661,7 @@ impl MlsGroup { tracing::info!( "{}: Storing a transcript message with {} members added and {} members removed and {} metadata changes", - self.context.inbox_id(), + self.context().inbox_id(), validated_commit.added_inboxes.len(), validated_commit.removed_inboxes.len(), validated_commit.metadata_changes.metadata_field_changes.len(), @@ -733,15 +696,11 @@ impl MlsGroup { Ok(Some(msg)) } - #[tracing::instrument(level = "trace", skip(self, provider, client))] - pub(super) async fn publish_intents( + #[tracing::instrument(level = "trace", skip_all)] + pub(super) async fn publish_intents( &self, provider: &XmtpOpenMlsProvider, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), GroupError> { let mut openmls_group = self.load_mls_group(provider)?; let intents = provider.conn_ref().find_group_intents( @@ -754,7 +713,7 @@ impl MlsGroup { let result = retry_async!( Retry::default(), (async { - self.get_publish_intent_data(provider, client, &mut openmls_group, &intent) + self.get_publish_intent_data(provider, &mut openmls_group, &intent) .await }) ); @@ -792,18 +751,18 @@ impl MlsGroup { )?; tracing::debug!( "client [{}] set stored intent [{}] to state `published`", - client.inbox_id(), + self.client.inbox_id(), intent.id ); - client - .api_client + self.client + .api() .send_group_messages(vec![payload_slice]) .await?; tracing::info!( "[{}] published intent [{}] of type [{}]", - client.inbox_id(), + self.client.inbox_id(), intent.id, intent.kind ); @@ -827,22 +786,18 @@ impl MlsGroup { // A return value of [`Option::None`] means this intent would not change the group. #[allow(clippy::type_complexity)] #[tracing::instrument(level = "trace", skip_all)] - async fn get_publish_intent_data( + async fn get_publish_intent_data( &self, provider: &XmtpOpenMlsProvider, - client: &Client, openmls_group: &mut OpenMlsGroup, intent: &StoredGroupIntent, - ) -> Result, GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result, GroupError> { match intent.kind { IntentKind::UpdateGroupMembership => { let intent_data = UpdateGroupMembershipIntentData::try_from(&intent.data)?; - let signer = &self.context.identity.installation_keys; + let signer = &self.context().identity.installation_keys; apply_update_group_membership_intent( - client, + &self.client, provider, openmls_group, intent_data, @@ -856,7 +811,7 @@ impl MlsGroup { // TODO: Handle pending_proposal errors and UseAfterEviction errors let msg = openmls_group.create_message( &provider, - &self.context.identity.installation_keys, + &self.context().identity.installation_keys, intent_data.message.as_slice(), )?; @@ -869,7 +824,7 @@ impl MlsGroup { IntentKind::KeyUpdate => { let (commit, _, _) = openmls_group.self_update( &provider, - &self.context.identity.installation_keys, + &self.context().identity.installation_keys, LeafNodeParameters::default(), )?; @@ -890,7 +845,7 @@ impl MlsGroup { let (commit, _, _) = openmls_group.update_group_context_extensions( &provider, mutable_metadata_extensions, - &self.context.identity.installation_keys, + &self.context().identity.installation_keys, )?; let commit_bytes = commit.tls_serialize_detached()?; @@ -912,7 +867,7 @@ impl MlsGroup { let (commit, _, _) = openmls_group.update_group_context_extensions( provider, mutable_metadata_extensions, - &self.context.identity.installation_keys, + &self.context().identity.installation_keys, )?; let commit_bytes = commit.tls_serialize_detached()?; @@ -932,7 +887,7 @@ impl MlsGroup { let (commit, _, _) = openmls_group.update_group_context_extensions( provider, group_permissions_extensions, - &self.context.identity.installation_keys, + &self.context().identity.installation_keys, )?; let commit_bytes = commit.tls_serialize_detached()?; Ok(Some(PublishIntentData { @@ -945,14 +900,7 @@ impl MlsGroup { } #[tracing::instrument(level = "trace", skip_all)] - pub(crate) async fn post_commit( - &self, - conn: &DbConnection, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + pub(crate) async fn post_commit(&self, conn: &DbConnection) -> Result<(), GroupError> { let intents = conn.find_group_intents( self.group_id.clone(), Some(vec![IntentState::Committed]), @@ -964,7 +912,7 @@ impl MlsGroup { let post_commit_action = PostCommitAction::from_bytes(post_commit_data.as_slice())?; match post_commit_action { PostCommitAction::SendWelcomes(action) => { - self.send_welcomes(action, client).await?; + self.send_welcomes(action).await?; } } } @@ -975,15 +923,11 @@ impl MlsGroup { Ok(()) } - pub async fn maybe_update_installations( + pub async fn maybe_update_installations( &self, provider: &XmtpOpenMlsProvider, update_interval_ns: Option, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), GroupError> { // determine how long of an interval in time to use before updating list let interval_ns = match update_interval_ns { Some(val) => val, @@ -996,7 +940,7 @@ impl MlsGroup { .get_installations_time_checked(self.group_id.clone())?; let elapsed_ns = now_ns - last_ns; if elapsed_ns > interval_ns { - self.add_missing_installations(provider, client).await?; + self.add_missing_installations(provider).await?; provider .conn_ref() .update_installations_time_checked(self.group_id.clone())?; @@ -1013,16 +957,12 @@ impl MlsGroup { * This is designed to handle cases where existing members have added a new installation to their inbox * and the group has not been updated to include it. */ - pub(super) async fn add_missing_installations( + pub(super) async fn add_missing_installations( &self, provider: &XmtpOpenMlsProvider, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + ) -> Result<(), GroupError> { let intent_data = self - .get_membership_update_intent(client, provider, vec![], vec![]) + .get_membership_update_intent(provider, vec![], vec![]) .await?; // If there is nothing to do, stop here @@ -1039,8 +979,7 @@ impl MlsGroup { intent_data.into(), ))?; - self.sync_until_intent_resolved(provider, intent.id, client) - .await + self.sync_until_intent_resolved(provider, intent.id).await } /** @@ -1050,9 +989,8 @@ impl MlsGroup { * Callers may also include a list of added or removed inboxes */ #[tracing::instrument(level = "trace", skip_all)] - pub(super) async fn get_membership_update_intent( + pub(super) async fn get_membership_update_intent( &self, - client: &Client, provider: &XmtpOpenMlsProvider, inbox_ids_to_add: Vec, inbox_ids_to_remove: Vec, @@ -1065,7 +1003,7 @@ impl MlsGroup { inbox_ids.extend(inbox_ids_to_add); let conn = provider.conn_ref(); // Load any missing updates from the network - load_identity_updates(&client.api_client, conn, inbox_ids.clone()).await?; + load_identity_updates(&self.client.api(), conn, inbox_ids.clone()).await?; let latest_sequence_id_map = conn.get_latest_sequence_id(&inbox_ids)?; @@ -1109,14 +1047,7 @@ impl MlsGroup { } #[tracing::instrument(level = "trace", skip_all)] - pub(super) async fn send_welcomes( - &self, - action: SendWelcomesAction, - client: &Client, - ) -> Result<(), GroupError> - where - ApiClient: XmtpApi, - { + pub(super) async fn send_welcomes(&self, action: SendWelcomesAction) -> Result<(), GroupError> { let welcomes = action .installations .into_iter() @@ -1154,9 +1085,10 @@ impl MlsGroup { .unwrap_or(GRPC_DATA_LIMIT / usize::from(MAX_GROUP_SIZE)); tracing::debug!("welcome chunk_size={chunk_size}"); + let api = self.client.api(); let mut futures = vec![]; for welcomes in welcomes.chunks(chunk_size) { - futures.push(client.api_client.send_welcome_messages(welcomes)); + futures.push(api.send_welcome_messages(welcomes)); } try_join_all(futures).await?; Ok(()) @@ -1190,8 +1122,8 @@ fn extract_message_sender( // Takes UpdateGroupMembershipIntentData and applies it to the openmls group // returning the commit and post_commit_action #[tracing::instrument(level = "trace", skip_all)] -async fn apply_update_group_membership_intent( - client: &Client, +async fn apply_update_group_membership_intent( + client: impl ScopedGroupClient, provider: &XmtpOpenMlsProvider, openmls_group: &mut OpenMlsGroup, intent_data: UpdateGroupMembershipIntentData, @@ -1220,7 +1152,7 @@ async fn apply_update_group_membership_intent( let mut new_key_packages: Vec = vec![]; if !installation_diff.added_installations.is_empty() { - let my_installation_id = &client.installation_public_key(); + let my_installation_id = &client.context().installation_public_key(); // Go to the network and load the key packages for any new installation let key_packages = client .get_key_packages_for_installation_ids( diff --git a/xmtp_mls/src/groups/validated_commit.rs b/xmtp_mls/src/groups/validated_commit.rs index 1155e335e..bbef711c5 100644 --- a/xmtp_mls/src/groups/validated_commit.rs +++ b/xmtp_mls/src/groups/validated_commit.rs @@ -27,7 +27,6 @@ use crate::{ retry::RetryableError, retryable, storage::db_connection::DbConnection, - Client, XmtpApi, }; use super::{ @@ -39,6 +38,7 @@ use super::{ group_permissions::{ extract_group_permissions, GroupMutablePermissions, GroupMutablePermissionsError, }, + ScopedGroupClient, }; #[derive(Debug, Error)] @@ -214,8 +214,8 @@ pub struct ValidatedCommit { } impl ValidatedCommit { - pub async fn from_staged_commit( - client: &Client, + pub async fn from_staged_commit( + client: impl ScopedGroupClient, conn: &DbConnection, staged_commit: &StagedCommit, openmls_group: &OpenMlsGroup, @@ -275,7 +275,7 @@ impl ValidatedCommit { removed_inboxes, } = extract_expected_diff( conn, - client, + &client, staged_commit, existing_group_context, &immutable_metadata, @@ -451,9 +451,9 @@ struct ExpectedDiff { /// [`GroupMembership`] and the [`GroupMembership`] found in the [`StagedCommit`]. /// This requires loading the Inbox state from the network. /// Satisfies Rule 2 -async fn extract_expected_diff<'diff, ApiClient: XmtpApi>( +async fn extract_expected_diff<'diff>( conn: &DbConnection, - client: &Client, + client: impl ScopedGroupClient, staged_commit: &StagedCommit, existing_group_context: &GroupContext, immutable_metadata: &GroupMetadata, diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index f0f46b1f4..8100ad90c 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -1,6 +1,7 @@ use std::collections::{HashMap, HashSet}; use crate::{ + groups::scoped_client::ScopedGroupClient, retry::{Retry, RetryableError}, retry_async, retryable, storage::association_state::StoredAssociationState, @@ -55,18 +56,14 @@ impl RetryableError for InstallationDiffError { } } -impl<'a, ApiClient> Client -where - ApiClient: XmtpApi, -{ +impl DbConnection { /// Take a list of inbox_id/sequence_id tuples and determine which `inbox_id`s have missing entries /// in the local DB pub(crate) fn filter_inbox_ids_needing_updates + ToString>( &self, - conn: &DbConnection, filters: Vec<(InboxId, i64)>, ) -> Result, ClientError> { - let existing_sequence_ids = conn.get_latest_sequence_id( + let existing_sequence_ids = self.get_latest_sequence_id( &filters .iter() .map(|f| f.0.to_string()) @@ -89,7 +86,13 @@ where Ok(needs_update) } +} +impl<'a, ApiClient, V> Client +where + ApiClient: XmtpApi + Clone, + V: SmartContractSignatureVerifier + Clone, +{ pub async fn batch_get_association_state>( &self, conn: &DbConnection, @@ -388,7 +391,7 @@ where load_identity_updates( &self.api_client, conn, - self.filter_inbox_ids_needing_updates(conn, filters)?, + conn.filter_inbox_ids_needing_updates(filters)?, ) .await?; diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 468da0799..f02bbcd98 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -26,6 +26,12 @@ use storage::{DuplicateItem, StorageError}; pub use xmtp_id::InboxOwner; pub use xmtp_proto::api_client::trait_impls::*; +/// Global Marker trait for WebAssembly +#[cfg(target_arch = "wasm32")] +pub trait Wasm {} +#[cfg(target_arch = "wasm32")] +impl Wasm for T {} + /// Inserts a model to the underlying data store, erroring if it already exists pub trait Store { fn store(&self, into: &StorageConnection) -> Result<(), StorageError>; diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 5bff8d609..34588857a 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -31,14 +31,22 @@ mod wasm; pub use self::db_connection::DbConnection; #[cfg(not(target_arch = "wasm32"))] -pub use self::native::SqliteConnection; +pub use diesel::sqlite::{Sqlite, SqliteConnection}; +#[cfg(not(target_arch = "wasm32"))] +pub use native::RawDbConnection; +#[cfg(not(target_arch = "wasm32"))] +pub use sqlcipher_connection::EncryptedConnection; + #[cfg(target_arch = "wasm32")] pub use self::wasm::SqliteConnection; +#[cfg(target_arch = "wasm32")] +pub use diesel_wasm_sqlite::{ + connection::WasmSqliteConnection as RawDbConnection, WasmSqlite as Sqlite, +}; + use super::StorageError; use crate::{xmtp_openmls_provider::XmtpOpenMlsProviderPrivate, Store}; use db_connection::DbConnectionPrivate; -#[cfg(not(target_arch = "wasm32"))] -pub use diesel::sqlite::Sqlite; use diesel::{ connection::{LoadConnection, TransactionManager}, migration::MigrationConnection, @@ -47,19 +55,10 @@ use diesel::{ sql_query, }; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; -#[cfg(target_arch = "wasm32")] -pub use diesel_wasm_sqlite::WasmSqlite as Sqlite; -#[cfg(not(target_arch = "wasm32"))] -pub use sqlcipher_connection::EncryptedConnection; use std::sync::Arc; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations/"); -#[cfg(target_arch = "wasm32")] -pub use diesel_wasm_sqlite::connection::WasmSqliteConnection as RawDbConnection; -#[cfg(not(target_arch = "wasm32"))] -pub use native::RawDbConnection; - pub type EncryptionKey = [u8; 32]; // For PRAGMA query log statements @@ -76,12 +75,6 @@ pub enum StorageOption { Persistent(String), } -/// Global Marker trait for WebAssembly -#[cfg(target_arch = "wasm32")] -pub trait Wasm {} -#[cfg(target_arch = "wasm32")] -impl Wasm for T {} - #[allow(async_fn_in_trait)] pub trait XmtpDb { type Connection: diesel::Connection diff --git a/xmtp_mls/src/storage/encrypted_store/native.rs b/xmtp_mls/src/storage/encrypted_store/native.rs index 4d4b36421..f951116b3 100644 --- a/xmtp_mls/src/storage/encrypted_store/native.rs +++ b/xmtp_mls/src/storage/encrypted_store/native.rs @@ -1,7 +1,7 @@ /// Native SQLite connection using SqlCipher use crate::storage::encrypted_store::DbConnectionPrivate; use crate::storage::StorageError; -pub use diesel::sqlite::SqliteConnection; +use diesel::sqlite::SqliteConnection; use diesel::{ connection::{AnsiTransactionManager, SimpleConnection}, r2d2::{self, CustomizeConnection, PoolTransactionManager, PooledConnection}, diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index e4b2735af..3253bb0f7 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -5,12 +5,15 @@ use futures::{FutureExt, Stream, StreamExt}; use prost::Message; use tokio::{sync::oneshot, task::JoinHandle}; use tokio_stream::wrappers::errors::BroadcastStreamRecvError; +use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::xmtp::mls::api::v1::WelcomeMessage; use crate::{ api::GroupFilter, client::{extract_welcome_message, ClientError}, - groups::{extract_group_id, group_metadata::ConversationType, GroupError, MlsGroup}, + groups::{ + extract_group_id, group_metadata::ConversationType, subscriptions, GroupError, MlsGroup, + }, retry::Retry, retry_async, storage::{group::StoredGroup, group_message::StoredGroupMessage}, @@ -27,10 +30,18 @@ pub struct StreamHandle { /// Events local to this client /// are broadcast across all senders/receivers of streams -#[derive(Clone)] -pub(crate) enum LocalEvents { +pub(crate) enum LocalEvents { // a new group was created - NewGroup(MlsGroup), + NewGroup(MlsGroup), +} + +impl Clone for LocalEvents { + fn clone(&self) -> LocalEvents { + use LocalEvents::*; + match self { + NewGroup(c) => NewGroup(c.clone()), + } + } } impl StreamHandle { @@ -68,12 +79,13 @@ impl From for (Vec, MessagesStreamInfo) { impl Client where - ApiClient: XmtpApi + 'static, + ApiClient: XmtpApi + Clone + 'static, + V: SmartContractSignatureVerifier + Clone + 'static, { async fn process_streamed_welcome( &self, welcome: WelcomeMessage, - ) -> Result { + ) -> Result, ClientError> { let welcome_v1 = extract_welcome_message(welcome)?; let creation_result = retry_async!( Retry::default(), @@ -84,7 +96,7 @@ where .store() .transaction_async(|provider| async move { MlsGroup::create_from_encrypted_welcome( - self, + Arc::new(self.clone()), &provider, welcome_v1.hpke_public_key.as_slice(), welcome_v1.data, @@ -105,11 +117,7 @@ where "Loading existing group for welcome_id: {:?}", group.welcome_id ); - return Ok(MlsGroup::new( - self.context.clone(), - group.id, - group.created_at_ns, - )); + return Ok(MlsGroup::new(self.clone(), group.id, group.created_at_ns)); } Ok(None) => return Err(ClientError::Generic(err.to_string())), Err(e) => return Err(ClientError::Generic(e.to_string())), @@ -122,7 +130,7 @@ where pub async fn process_streamed_welcome_message( &self, envelope_bytes: Vec, - ) -> Result { + ) -> Result, ClientError> { let envelope = WelcomeMessage::decode(envelope_bytes.as_slice()) .map_err(|e| ClientError::Generic(e.to_string()))?; @@ -133,15 +141,20 @@ where pub async fn stream_conversations( &self, include_dm: bool, - ) -> Result + '_, ClientError> { - let provider = Arc::new(self.context.mls_provider()?); - + ) -> Result> + '_, ClientError> { let event_queue = tokio_stream::wrappers::BroadcastStream::new(self.local_events.subscribe()); // Helper function for filtering Dm groups - let filter_group = move |group: MlsGroup, provider: Arc| async move { - match group.metadata(provider.as_ref()) { + let filter_group = move |group: MlsGroup| async move { + let provider = match group.client.context().mls_provider() { + Ok(p) => Some(p), + Err(e) => { + tracing::error!("{}", e); + None + } + }?; + match group.metadata(provider) { Ok(metadata) => { if include_dm || metadata.conversation_type != ConversationType::Dm { Some(group) @@ -156,16 +169,12 @@ where } }; - let event_provider = Arc::clone(&provider); - let event_queue = event_queue.filter_map(move |event| { - let provider = Arc::clone(&event_provider); - async move { - match event { - Ok(LocalEvents::NewGroup(group)) => filter_group(group, provider).await, - Err(BroadcastStreamRecvError::Lagged(missed)) => { - tracing::warn!("Missed {missed} messages due to local event queue lagging"); - None - } + let event_queue = event_queue.filter_map(|event| async move { + match event { + Ok(LocalEvents::NewGroup(g)) => Some(g), + Err(BroadcastStreamRecvError::Lagged(missed)) => { + tracing::warn!("Missed {missed} messages due to local event queue lagging"); + None } } }); @@ -179,95 +188,36 @@ where .subscribe_welcome_messages(installation_key, Some(id_cursor)) .await?; - let stream_provider = Arc::clone(&provider); let stream = subscription .map(|welcome| async { tracing::info!("Received conversation streaming payload"); self.process_streamed_welcome(welcome?).await }) - .filter_map(move |res| { - let provider = Arc::clone(&stream_provider); - async move { - match res.await { - Ok(group) => filter_group(group, provider).await, - Err(err) => { - tracing::error!( - "Error processing stream entry for conversation: {:?}", - err - ); - None - } - } - } - }); - - Ok(futures::stream::select(stream, event_queue)) - } - - // #[tracing::instrument(skip(self, group_id_to_info))] - pub(crate) async fn stream_messages( - &self, - group_id_to_info: Arc, MessagesStreamInfo>>, - ) -> Result + '_, ClientError> - where - ApiClient: 'static, - { - let filters: Vec = group_id_to_info - .iter() - .map(|(group_id, info)| GroupFilter::new(group_id.clone(), Some(info.cursor))) - .collect(); - - let messages_subscription = self.api_client.subscribe_group_messages(filters).await?; - - let stream = messages_subscription - .map(move |res| { - let group_info = group_id_to_info.clone(); - async move { - match res { - Ok(envelope) => { - tracing::info!("Received message streaming payload"); - let group_id = extract_group_id(&envelope)?; - tracing::info!("Extracted group id {}", hex::encode(&group_id)); - let stream_info = group_info.get(&group_id).ok_or( - ClientError::StreamInconsistency( - "Received message for a non-subscribed group".to_string(), - ), - )?; - let mls_group = MlsGroup::new( - self.context.clone(), - group_id, - stream_info.convo_created_at_ns, - ); - mls_group.process_stream_entry(envelope, self).await - } - Err(err) => Err(GroupError::Api(err)), - } - } - }) - .filter_map(|res| async { + .filter_map(move |res| async { match res.await { - Ok(Some(message)) => Some(message), - Ok(None) => { - tracing::info!("Skipped message streaming payload"); - None - } + Ok(group) => Some(group), Err(err) => { - tracing::error!("Error processing stream entry: {:?}", err); + tracing::error!( + "Error processing stream entry for conversation: {:?}", + err + ); None } } }); - Ok(stream) + + Ok(futures::stream::select(stream, event_queue).filter_map(filter_group)) } } impl Client where - ApiClient: XmtpApi + 'static, + ApiClient: XmtpApi + Clone + Send + Sync + 'static, + V: SmartContractSignatureVerifier + Send + Sync + Clone + 'static, { pub fn stream_conversations_with_callback( - client: Arc>, - mut convo_callback: impl FnMut(MlsGroup) + Send + 'static, + client: Arc>, + mut convo_callback: impl FnMut(MlsGroup) + Send + 'static, include_dm: bool, ) -> impl crate::StreamHandle> { let (tx, rx) = oneshot::channel(); @@ -285,27 +235,6 @@ where }) } - pub(crate) fn stream_messages_with_callback( - client: Arc>, - group_id_to_info: HashMap, MessagesStreamInfo>, - mut callback: impl FnMut(StoredGroupMessage) + Send + 'static, - ) -> impl crate::StreamHandle> { - let (tx, rx) = oneshot::channel(); - - let client = client.clone(); - - crate::spawn(Some(rx), async move { - let stream = Self::stream_messages(&client, Arc::new(group_id_to_info)).await?; - futures::pin_mut!(stream); - let _ = tx.send(()); - while let Some(message) = stream.next().await { - callback(message) - } - tracing::debug!("`stream_messages` stream ended, dropping stream"); - Ok::<_, ClientError>(()) - }) - } - pub async fn stream_all_messages( &self, ) -> Result> + '_, ClientError> { @@ -320,9 +249,11 @@ where .collect::, MessagesStreamInfo>>(); let stream = async_stream::stream! { - let messages_stream = self - .stream_messages(Arc::new(group_id_to_info.clone())) - .await?; + let messages_stream = subscriptions::stream_messages( + self, + Arc::new(group_id_to_info.clone()) + ) + .await?; futures::pin_mut!(messages_stream); tracing::info!("Setting up conversation stream in stream_all_messages"); @@ -364,7 +295,10 @@ where cursor: 1, // For the new group, stream all messages since the group was created }, ); - let new_messages_stream = match self.stream_messages(Arc::new(group_id_to_info.clone())).await { + let new_messages_stream = match subscriptions::stream_messages( + self, + Arc::new(group_id_to_info.clone()) + ).await { Ok(stream) => stream, Err(e) => { tracing::error!("{}", e); @@ -387,13 +321,14 @@ where } pub fn stream_all_messages_with_callback( - client: Arc>, + client: Arc, mut callback: impl FnMut(StoredGroupMessage) + Send + Sync + 'static, ) -> impl crate::StreamHandle> { let (tx, rx) = oneshot::channel(); crate::spawn(Some(rx), async move { - let stream = Self::stream_all_messages(&client).await?; + let client = client.clone(); + let stream = client.stream_all_messages().await?; futures::pin_mut!(stream); let _ = tx.send(()); while let Some(message) = stream.next().await { From 7278c7c588049b08ab3d746d3c967b72694ea316 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 9 Oct 2024 18:30:09 -0400 Subject: [PATCH 75/97] tentative compilation WIP --- Cargo.lock | 7 +++++++ xmtp_mls/Cargo.toml | 1 + xmtp_mls/src/client.rs | 5 +++-- xmtp_mls/src/groups/mod.rs | 13 +++++-------- xmtp_mls/src/groups/subscriptions.rs | 11 ++++++----- xmtp_mls/src/subscriptions.rs | 10 +++++----- 6 files changed, 27 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dca8265cd..67915250a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4876,6 +4876,12 @@ dependencies = [ "serde", ] +[[package]] +name = "send-future" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224e328af6e080cddbab3c770b1cf50f0351ba0577091ef2410c3951d835ff87" + [[package]] name = "send_wrapper" version = "0.4.0" @@ -6900,6 +6906,7 @@ dependencies = [ "prost", "rand", "reqwest 0.12.8", + "send-future", "serde", "serde_json", "sha2 0.10.8", diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 677ace0ef..87be37d88 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -40,6 +40,7 @@ async-trait.workspace = true futures.workspace = true dyn-clone = "1" wasm-timer.workspace = true +send-future = "0.1" # XMTP/Local xmtp_cryptography = { workspace = true } diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 64788f888..5c427df06 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -708,15 +708,16 @@ where .collect::>()?) } - pub(crate) async fn process_for_id( + pub(crate) async fn process_for_id( &self, entity_id: &Vec, entity_kind: EntityKind, cursor: u64, - process_envelope: impl FnOnce(XmtpOpenMlsProvider) -> Fut, + process_envelope: ProcessingFn, ) -> Result where Fut: Future>, + ProcessingFn: FnOnce(XmtpOpenMlsProvider) -> Fut, { self.store() .transaction_async(|provider| async move { diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 3b7a30060..dc5f0cc3c 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -256,10 +256,7 @@ pub enum UpdateAdminListType { RemoveSuper, } -impl MlsGroup -where - ScopedClient: ScopedGroupClient, -{ +impl MlsGroup { // Creates a new group instance. Does not validate that the group exists in the DB pub fn new(client: ScopedClient, group_id: Vec, created_at_ns: i64) -> Self { Self::new_from_arc(Arc::new(client), group_id, created_at_ns) @@ -685,10 +682,10 @@ where * will be added as part of this process as well. */ #[tracing::instrument(level = "trace", skip_all)] - pub async fn add_members( - &self, - account_addresses_to_add: Vec, - ) -> Result<(), GroupError> { + pub async fn add_members(&self, account_addresses_to_add: Vec) -> Result<(), GroupError> + where + ScopedClient: Send + Sync, + { let account_addresses = sanitize_evm_addresses(account_addresses_to_add)?; let inbox_id_map = self .client diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index c702ac674..e47302faa 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -18,7 +18,7 @@ use xmtp_proto::xmtp::mls::api::v1::GroupMessage; impl MlsGroup where - ScopedClient: ScopedGroupClient + Clone + Send + Sync, + ScopedClient: ScopedGroupClient + Clone + Send, { pub(crate) async fn process_stream_entry( &self, @@ -154,7 +154,7 @@ pub(crate) async fn stream_messages<'s, ScopedClient>( group_id_to_info: Arc, MessagesStreamInfo>>, ) -> Result + 's, ClientError> where - ScopedClient: ScopedGroupClient + Clone + Sync + Send + 'static, + ScopedClient: ScopedGroupClient + Clone + Send + 'static, ::ApiClient: XmtpApi + 'static, { let filters: Vec = group_id_to_info @@ -213,14 +213,15 @@ pub(crate) fn stream_messages_with_callback( mut callback: impl FnMut(StoredGroupMessage) + Send + 'static, ) -> impl crate::StreamHandle> where - ScopedClient: ScopedGroupClient + Send + Sync + Clone + 'static, + ScopedClient: ScopedGroupClient + Send + Clone + 'static, ::ApiClient: XmtpApi + 'static, { let (tx, rx) = oneshot::channel(); - let client = client.clone(); + let client: Arc = client.clone(); crate::spawn(Some(rx), async move { - let client = Arc::clone(&client); + let _ = &client; + let client: Arc = Arc::clone(&client); let stream = stream_messages(&client, Arc::new(group_id_to_info)).await?; futures::pin_mut!(stream); let _ = tx.send(()); diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 3253bb0f7..0e6cdd81c 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -79,8 +79,8 @@ impl From for (Vec, MessagesStreamInfo) { impl Client where - ApiClient: XmtpApi + Clone + 'static, - V: SmartContractSignatureVerifier + Clone + 'static, + ApiClient: XmtpApi + Clone + Send + 'static, + V: SmartContractSignatureVerifier + Clone + Send + 'static, { async fn process_streamed_welcome( &self, @@ -212,8 +212,8 @@ where impl Client where - ApiClient: XmtpApi + Clone + Send + Sync + 'static, - V: SmartContractSignatureVerifier + Send + Sync + Clone + 'static, + ApiClient: XmtpApi + Clone + Send + 'static, + V: SmartContractSignatureVerifier + Send + Clone + 'static, { pub fn stream_conversations_with_callback( client: Arc>, @@ -326,8 +326,8 @@ where ) -> impl crate::StreamHandle> { let (tx, rx) = oneshot::channel(); + let client: Arc> = client.clone(); crate::spawn(Some(rx), async move { - let client = client.clone(); let stream = client.stream_all_messages().await?; futures::pin_mut!(stream); let _ = tx.send(()); From 3c1d04b5511196ed34460ef29c0cfdd80839b845 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 9 Oct 2024 18:37:48 -0400 Subject: [PATCH 76/97] WIP --- Cargo.lock | 7 ------- xmtp_mls/Cargo.toml | 1 - xmtp_mls/src/groups/mod.rs | 8 ++++---- xmtp_mls/src/groups/subscriptions.rs | 16 +++++----------- xmtp_mls/src/groups/sync.rs | 5 +---- xmtp_mls/src/identity_updates.rs | 1 - xmtp_mls/src/subscriptions.rs | 6 +----- 7 files changed, 11 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67915250a..dca8265cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4876,12 +4876,6 @@ dependencies = [ "serde", ] -[[package]] -name = "send-future" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224e328af6e080cddbab3c770b1cf50f0351ba0577091ef2410c3951d835ff87" - [[package]] name = "send_wrapper" version = "0.4.0" @@ -6906,7 +6900,6 @@ dependencies = [ "prost", "rand", "reqwest 0.12.8", - "send-future", "serde", "serde_json", "sha2 0.10.8", diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 87be37d88..677ace0ef 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -40,7 +40,6 @@ async-trait.workspace = true futures.workspace = true dyn-clone = "1" wasm-timer.workspace = true -send-future = "0.1" # XMTP/Local xmtp_cryptography = { workspace = true } diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index dc5f0cc3c..8fa9f81bf 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -682,10 +682,10 @@ impl MlsGroup { * will be added as part of this process as well. */ #[tracing::instrument(level = "trace", skip_all)] - pub async fn add_members(&self, account_addresses_to_add: Vec) -> Result<(), GroupError> - where - ScopedClient: Send + Sync, - { + pub async fn add_members( + &self, + account_addresses_to_add: Vec, + ) -> Result<(), GroupError> { let account_addresses = sanitize_evm_addresses(account_addresses_to_add)?; let inbox_id_map = self .client diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index e47302faa..fa5ba3687 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -16,10 +16,7 @@ use crate::{retry::Retry, retry_async}; use prost::Message; use xmtp_proto::xmtp::mls::api::v1::GroupMessage; -impl MlsGroup -where - ScopedClient: ScopedGroupClient + Clone + Send, -{ +impl MlsGroup { pub(crate) async fn process_stream_entry( &self, envelope: GroupMessage, @@ -154,7 +151,7 @@ pub(crate) async fn stream_messages<'s, ScopedClient>( group_id_to_info: Arc, MessagesStreamInfo>>, ) -> Result + 's, ClientError> where - ScopedClient: ScopedGroupClient + Clone + Send + 'static, + ScopedClient: ScopedGroupClient + 'static, ::ApiClient: XmtpApi + 'static, { let filters: Vec = group_id_to_info @@ -178,11 +175,8 @@ where "Received message for a non-subscribed group".to_string(), ), )?; - let mls_group = MlsGroup::new( - client.clone(), - group_id, - stream_info.convo_created_at_ns, - ); + let mls_group = + MlsGroup::new(client, group_id, stream_info.convo_created_at_ns); mls_group.process_stream_entry(envelope).await } Err(err) => Err(GroupError::Api(err)), @@ -213,7 +207,7 @@ pub(crate) fn stream_messages_with_callback( mut callback: impl FnMut(StoredGroupMessage) + Send + 'static, ) -> impl crate::StreamHandle> where - ScopedClient: ScopedGroupClient + Send + Clone + 'static, + ScopedClient: ScopedGroupClient + 'static, ::ApiClient: XmtpApi + 'static, { let (tx, rx) = oneshot::channel(); diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index ac1573b52..ebcf368cf 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -85,10 +85,7 @@ struct PublishIntentData { payload_to_publish: Vec, } -impl MlsGroup -where - ScopedClient: ScopedGroupClient, -{ +impl MlsGroup { pub async fn sync(&self) -> Result<(), GroupError> { let conn = self.context().store().conn()?; let mls_provider = XmtpOpenMlsProvider::from(conn); diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index 8100ad90c..605c3e4e2 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -1,7 +1,6 @@ use std::collections::{HashMap, HashSet}; use crate::{ - groups::scoped_client::ScopedGroupClient, retry::{Retry, RetryableError}, retry_async, retryable, storage::association_state::StoredAssociationState, diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 0e6cdd81c..b2b573559 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -1,6 +1,5 @@ use std::{collections::HashMap, sync::Arc}; -use crate::xmtp_openmls_provider::XmtpOpenMlsProvider; use futures::{FutureExt, Stream, StreamExt}; use prost::Message; use tokio::{sync::oneshot, task::JoinHandle}; @@ -9,11 +8,8 @@ use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::xmtp::mls::api::v1::WelcomeMessage; use crate::{ - api::GroupFilter, client::{extract_welcome_message, ClientError}, - groups::{ - extract_group_id, group_metadata::ConversationType, subscriptions, GroupError, MlsGroup, - }, + groups::{group_metadata::ConversationType, subscriptions, MlsGroup}, retry::Retry, retry_async, storage::{group::StoredGroup, group_message::StoredGroupMessage}, From 27a33461366482f8f263a23e3acf990bc2c64bb5 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 10 Oct 2024 11:28:35 -0400 Subject: [PATCH 77/97] compiler bug --- xmtp_mls/src/groups/mod.rs | 2 +- xmtp_mls/src/groups/scoped_client.rs | 374 +++++++++++++++++++++++++++ 2 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 xmtp_mls/src/groups/scoped_client.rs diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 8fa9f81bf..214cb8e8c 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -272,7 +272,7 @@ impl MlsGroup { } } - pub(self) fn context(&self) -> &Arc { + pub(self) fn context(&self) -> Arc { self.client.context() } diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs new file mode 100644 index 000000000..254fcca50 --- /dev/null +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -0,0 +1,374 @@ +use std::{future::Future, sync::Arc}; + +use openmls_traits::OpenMlsProvider; +use xmtp_id::{associations::AssociationState, scw_verifier::SmartContractSignatureVerifier}; +use xmtp_proto::{ + api_client::{trait_impls::XmtpApi, Error}, + xmtp::mls::api::v1::GroupMessage, +}; + +use crate::{ + api::ApiClientWrapper, + client::{ClientError, MessageProcessingError, XmtpMlsLocalContext}, + identity_updates::{InstallationDiff, InstallationDiffError}, + storage::{refresh_state::EntityKind, DbConnection, EncryptedMessageStore}, + verified_key_package_v2::VerifiedKeyPackageV2, + xmtp_openmls_provider::XmtpOpenMlsProvider, + Client, +}; + +use super::group_membership::{GroupMembership, MembershipDiff}; + +#[trait_variant::make(ScopedGroupClient: Send)] +pub trait LocalScopedGroupClient: Send + Sync { + type ApiClient: XmtpApi; + + fn api(&self) -> &ApiClientWrapper; + + fn store(&self) -> &EncryptedMessageStore { + self.context_ref().store() + } + + fn inbox_id(&self) -> String { + self.context().inbox_id() + } + + fn mls_provider(&self) -> Result { + self.context_ref().mls_provider() + } + + fn context_ref(&self) -> &Arc; + + fn context(&self) -> Arc { + self.context_ref().clone() + } + + async fn get_installation_diff( + &self, + conn: &DbConnection, + old_group_membership: &GroupMembership, + new_group_membership: &GroupMembership, + membership_diff: &MembershipDiff<'_>, + ) -> Result; + + async fn get_key_packages_for_installation_ids( + &self, + installation_ids: Vec>, + ) -> Result, ClientError>; + + async fn get_association_state( + &self, + conn: &DbConnection, + inbox_id: String, + to_sequence_id: Option, + ) -> Result; + + async fn batch_get_association_state( + &self, + conn: &DbConnection, + identifiers: &[(String, Option)], + ) -> Result, ClientError>; + + async fn query_group_messages( + &self, + group_id: &Vec, + conn: &DbConnection, + ) -> Result, ClientError>; + + async fn process_for_id( + &self, + entity_id: &Vec, + entity_kind: EntityKind, + cursor: u64, + process_envelope: ProcessingFn, + ) -> Result + where + Fut: Send + Future>, + ProcessingFn: Send + FnOnce(XmtpOpenMlsProvider) -> Fut; +} + +impl ScopedGroupClient for Client +where + ApiClient: XmtpApi + Clone, + Verifier: SmartContractSignatureVerifier + Clone, +{ + type ApiClient = ApiClient; + + fn api(&self) -> &ApiClientWrapper { + &self.api_client + } + + fn context_ref(&self) -> &Arc { + self.context() + } + + async fn get_installation_diff( + &self, + conn: &DbConnection, + old_group_membership: &GroupMembership, + new_group_membership: &GroupMembership, + membership_diff: &MembershipDiff<'_>, + ) -> Result { + crate::Client::::get_installation_diff( + self, + conn, + old_group_membership, + new_group_membership, + membership_diff, + ) + .await + } + + async fn get_key_packages_for_installation_ids( + &self, + installation_ids: Vec>, + ) -> Result, ClientError> { + crate::Client::::get_key_packages_for_installation_ids( + self, + installation_ids, + ) + .await + } + + async fn get_association_state( + &self, + conn: &DbConnection, + inbox_id: String, + to_sequence_id: Option, + ) -> Result { + crate::Client::::get_association_state( + self, + conn, + inbox_id, + to_sequence_id, + ) + .await + } + + async fn batch_get_association_state( + &self, + conn: &DbConnection, + identifiers: &[(String, Option)], + ) -> Result, ClientError> { + crate::Client::::batch_get_association_state(self, conn, identifiers) + .await + } + + async fn query_group_messages( + &self, + group_id: &Vec, + conn: &DbConnection, + ) -> Result, ClientError> { + crate::Client::::query_group_messages(self, group_id, conn).await + } + + async fn process_for_id( + &self, + entity_id: &Vec, + entity_kind: EntityKind, + cursor: u64, + process_envelope: ProcessingFn, + ) -> Result + where + Fut: Send + Future>, + ProcessingFn: Send + FnOnce(XmtpOpenMlsProvider) -> Fut, + { + crate::Client::process_for_id(self, entity_id, entity_kind, cursor, process_envelope).await + } +} + +impl ScopedGroupClient for &T +where + T: ScopedGroupClient, +{ + type ApiClient = ::ApiClient; + + fn api(&self) -> &ApiClientWrapper { + (**self).api() + } + + fn store(&self) -> &EncryptedMessageStore { + (**self).store() + } + + fn inbox_id(&self) -> String { + (**self).inbox_id() + } + + fn context_ref(&self) -> &Arc { + (**self).context_ref() + } + + fn mls_provider(&self) -> Result { + (**self).mls_provider() + } + + async fn get_installation_diff( + &self, + conn: &DbConnection, + old_group_membership: &GroupMembership, + new_group_membership: &GroupMembership, + membership_diff: &MembershipDiff<'_>, + ) -> Result { + (**self) + .get_installation_diff( + conn, + old_group_membership, + new_group_membership, + membership_diff, + ) + .await + } + + async fn get_key_packages_for_installation_ids( + &self, + installation_ids: Vec>, + ) -> Result, ClientError> { + (**self) + .get_key_packages_for_installation_ids(installation_ids) + .await + } + + async fn get_association_state( + &self, + conn: &DbConnection, + inbox_id: String, + to_sequence_id: Option, + ) -> Result { + (**self) + .get_association_state(conn, inbox_id, to_sequence_id) + .await + } + + async fn batch_get_association_state( + &self, + conn: &DbConnection, + identifiers: &[(String, Option)], + ) -> Result, ClientError> { + (**self) + .batch_get_association_state(conn, identifiers) + .await + } + + async fn query_group_messages( + &self, + group_id: &Vec, + conn: &DbConnection, + ) -> Result, ClientError> { + (**self).query_group_messages(group_id, conn).await + } + + async fn process_for_id( + &self, + entity_id: &Vec, + entity_kind: EntityKind, + cursor: u64, + process_envelope: ProcessingFn, + ) -> Result + where + Fut: Send + Future>, + ProcessingFn: Send + FnOnce(XmtpOpenMlsProvider) -> Fut, + { + (**self) + .process_for_id(entity_id, entity_kind, cursor, process_envelope) + .await + } +} + +impl ScopedGroupClient for Arc +where + T: ScopedGroupClient, +{ + type ApiClient = ::ApiClient; + + fn api(&self) -> &ApiClientWrapper { + (**self).api() + } + + fn store(&self) -> &EncryptedMessageStore { + (**self).store() + } + + fn inbox_id(&self) -> String { + (**self).inbox_id() + } + + fn context_ref(&self) -> &Arc { + (**self).context_ref() + } + + fn mls_provider(&self) -> Result { + (**self).mls_provider() + } + + async fn get_installation_diff( + &self, + conn: &DbConnection, + old_group_membership: &GroupMembership, + new_group_membership: &GroupMembership, + membership_diff: &MembershipDiff<'_>, + ) -> Result { + (**self) + .get_installation_diff( + conn, + old_group_membership, + new_group_membership, + membership_diff, + ) + .await + } + + async fn get_key_packages_for_installation_ids( + &self, + installation_ids: Vec>, + ) -> Result, ClientError> { + (**self) + .get_key_packages_for_installation_ids(installation_ids) + .await + } + + async fn get_association_state( + &self, + conn: &DbConnection, + inbox_id: String, + to_sequence_id: Option, + ) -> Result { + (**self) + .get_association_state(conn, inbox_id, to_sequence_id) + .await + } + + async fn batch_get_association_state( + &self, + conn: &DbConnection, + identifiers: &[(String, Option)], + ) -> Result, ClientError> { + (**self) + .batch_get_association_state(conn, identifiers) + .await + } + + async fn query_group_messages( + &self, + group_id: &Vec, + conn: &DbConnection, + ) -> Result, ClientError> { + (**self).query_group_messages(group_id, conn).await + } + + async fn process_for_id( + &self, + entity_id: &Vec, + entity_kind: EntityKind, + cursor: u64, + process_envelope: ProcessingFn, + ) -> Result + where + Fut: Send + Future>, + ProcessingFn: Send + FnOnce(XmtpOpenMlsProvider) -> Fut, + { + (**self) + .process_for_id(entity_id, entity_kind, cursor, process_envelope) + .await + } +} From ed096d6e9840459ae1153999f1d9c458b5608686 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 10 Oct 2024 12:12:10 -0400 Subject: [PATCH 78/97] WIP, before removing static --- Cargo.lock | 7 ++++++ xmtp_mls/Cargo.toml | 1 + xmtp_mls/src/groups/mod.rs | 4 ++-- xmtp_mls/src/groups/scoped_client.rs | 9 ++++--- xmtp_mls/src/groups/subscriptions.rs | 32 ++++++++++++++----------- xmtp_mls/src/groups/sync.rs | 2 +- xmtp_mls/src/groups/validated_commit.rs | 6 ++--- xmtp_mls/src/subscriptions.rs | 5 ++-- 8 files changed, 38 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dca8265cd..67915250a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4876,6 +4876,12 @@ dependencies = [ "serde", ] +[[package]] +name = "send-future" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224e328af6e080cddbab3c770b1cf50f0351ba0577091ef2410c3951d835ff87" + [[package]] name = "send_wrapper" version = "0.4.0" @@ -6900,6 +6906,7 @@ dependencies = [ "prost", "rand", "reqwest 0.12.8", + "send-future", "serde", "serde_json", "sha2 0.10.8", diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 677ace0ef..af60f5148 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -77,6 +77,7 @@ chrono = { workspace = true, features = ["clock"] } tokio = { workspace = true, features = ["macros", "tracing", "rt", "rt-multi-thread"] } diesel_migrations = { workspace = true, features = ["sqlite"] } openmls = { workspace = true, features = ["test-utils"] } +send-future = "0.1" [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 214cb8e8c..543819f2f 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -1389,7 +1389,7 @@ fn build_group_config( } async fn validate_initial_group_membership( - client: impl ScopedGroupClient, + client: &impl ScopedGroupClient, conn: &DbConnection, mls_group: &OpenMlsGroup, ) -> Result<(), GroupError> { @@ -1430,7 +1430,7 @@ async fn validate_initial_group_membership( } fn validate_dm_group( - client: impl ScopedGroupClient, + client: &impl ScopedGroupClient, mls_group: &OpenMlsGroup, added_by_inbox: &str, ) -> Result<(), GroupError> { diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs index 254fcca50..f57d62215 100644 --- a/xmtp_mls/src/groups/scoped_client.rs +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -1,6 +1,5 @@ use std::{future::Future, sync::Arc}; -use openmls_traits::OpenMlsProvider; use xmtp_id::{associations::AssociationState, scw_verifier::SmartContractSignatureVerifier}; use xmtp_proto::{ api_client::{trait_impls::XmtpApi, Error}, @@ -20,7 +19,7 @@ use crate::{ use super::group_membership::{GroupMembership, MembershipDiff}; #[trait_variant::make(ScopedGroupClient: Send)] -pub trait LocalScopedGroupClient: Send + Sync { +pub trait LocalScopedGroupClient: Send + Sync + Sized { type ApiClient: XmtpApi; fn api(&self) -> &ApiClientWrapper; @@ -176,7 +175,7 @@ where crate::Client::process_for_id(self, entity_id, entity_kind, cursor, process_envelope).await } } - +/* impl ScopedGroupClient for &T where T: ScopedGroupClient, @@ -274,10 +273,10 @@ where .await } } - +*/ impl ScopedGroupClient for Arc where - T: ScopedGroupClient, + T: ScopedGroupClient + Send, { type ApiClient = ::ApiClient; diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index fa5ba3687..3b5e6930e 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -111,8 +111,8 @@ impl MlsGroup { &'a self, ) -> Result + '_, GroupError> where - ScopedClient: 'static, - ::ApiClient: 'static, + ScopedClient: Clone + 'static, + ::ApiClient: Clone + 'static, { let group_list = HashMap::from([( self.group_id.clone(), @@ -131,8 +131,8 @@ impl MlsGroup { callback: impl FnMut(StoredGroupMessage) + Send + 'static, ) -> impl crate::StreamHandle> where - ScopedClient: 'static, - ::ApiClient: 'static, + ScopedClient: Clone + 'static, + ::ApiClient: Clone + 'static, { let group_list = HashMap::from([( group_id, @@ -146,14 +146,15 @@ impl MlsGroup { } /// Stream messages from groups in `group_id_to_info` -pub(crate) async fn stream_messages<'s, ScopedClient>( - client: &'s ScopedClient, +pub(crate) async fn stream_messages( + client: &ScopedClient, group_id_to_info: Arc, MessagesStreamInfo>>, -) -> Result + 's, ClientError> +) -> Result + '_, ClientError> where - ScopedClient: ScopedGroupClient + 'static, - ::ApiClient: XmtpApi + 'static, + ScopedClient: ScopedGroupClient + Clone + 'static, + ::ApiClient: XmtpApi + Clone + 'static, { + use send_future::SendFuture; let filters: Vec = group_id_to_info .iter() .map(|(group_id, info)| GroupFilter::new(group_id.clone(), Some(info.cursor))) @@ -175,8 +176,11 @@ where "Received message for a non-subscribed group".to_string(), ), )?; - let mls_group = - MlsGroup::new(client, group_id, stream_info.convo_created_at_ns); + let mls_group = MlsGroup::new( + client.clone(), + group_id, + stream_info.convo_created_at_ns, + ); mls_group.process_stream_entry(envelope).await } Err(err) => Err(GroupError::Api(err)), @@ -207,14 +211,14 @@ pub(crate) fn stream_messages_with_callback( mut callback: impl FnMut(StoredGroupMessage) + Send + 'static, ) -> impl crate::StreamHandle> where - ScopedClient: ScopedGroupClient + 'static, - ::ApiClient: XmtpApi + 'static, + ScopedClient: ScopedGroupClient + Clone + 'static, + ::ApiClient: XmtpApi + Clone + 'static, { + use send_future::SendFuture; let (tx, rx) = oneshot::channel(); let client: Arc = client.clone(); crate::spawn(Some(rx), async move { - let _ = &client; let client: Arc = Arc::clone(&client); let stream = stream_messages(&client, Arc::new(group_id_to_info)).await?; futures::pin_mut!(stream); diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index ebcf368cf..dcf5e7286 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -1120,7 +1120,7 @@ fn extract_message_sender( // returning the commit and post_commit_action #[tracing::instrument(level = "trace", skip_all)] async fn apply_update_group_membership_intent( - client: impl ScopedGroupClient, + client: &impl ScopedGroupClient, provider: &XmtpOpenMlsProvider, openmls_group: &mut OpenMlsGroup, intent_data: UpdateGroupMembershipIntentData, diff --git a/xmtp_mls/src/groups/validated_commit.rs b/xmtp_mls/src/groups/validated_commit.rs index bbef711c5..9e7626608 100644 --- a/xmtp_mls/src/groups/validated_commit.rs +++ b/xmtp_mls/src/groups/validated_commit.rs @@ -215,7 +215,7 @@ pub struct ValidatedCommit { impl ValidatedCommit { pub async fn from_staged_commit( - client: impl ScopedGroupClient, + client: &impl ScopedGroupClient, conn: &DbConnection, staged_commit: &StagedCommit, openmls_group: &OpenMlsGroup, @@ -275,7 +275,7 @@ impl ValidatedCommit { removed_inboxes, } = extract_expected_diff( conn, - &client, + client, staged_commit, existing_group_context, &immutable_metadata, @@ -453,7 +453,7 @@ struct ExpectedDiff { /// Satisfies Rule 2 async fn extract_expected_diff<'diff>( conn: &DbConnection, - client: impl ScopedGroupClient, + client: &impl ScopedGroupClient, staged_commit: &StagedCommit, existing_group_context: &GroupContext, immutable_metadata: &GroupMetadata, diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index b2b573559..997ea0322 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -317,12 +317,11 @@ where } pub fn stream_all_messages_with_callback( - client: Arc, + client: Arc>, mut callback: impl FnMut(StoredGroupMessage) + Send + Sync + 'static, - ) -> impl crate::StreamHandle> { + ) -> impl crate::StreamHandle> + 'static { let (tx, rx) = oneshot::channel(); - let client: Arc> = client.clone(); crate::spawn(Some(rx), async move { let stream = client.stream_all_messages().await?; futures::pin_mut!(stream); From aef1c6e40e048feb80d75ff2a42145e3af9b684c Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 10 Oct 2024 12:20:33 -0400 Subject: [PATCH 79/97] remove some 'static --- xmtp_id/src/associations/association_log.rs | 2 +- xmtp_mls/src/builder.rs | 10 +++++----- xmtp_mls/src/client.rs | 4 ++-- xmtp_mls/src/groups/subscriptions.rs | 4 ++-- xmtp_mls/src/subscriptions.rs | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/xmtp_id/src/associations/association_log.rs b/xmtp_id/src/associations/association_log.rs index cc821d762..d2f45d481 100644 --- a/xmtp_id/src/associations/association_log.rs +++ b/xmtp_id/src/associations/association_log.rs @@ -36,7 +36,7 @@ pub enum AssociationError { MissingIdentityUpdate, } -pub trait IdentityAction: Send + 'static { +pub trait IdentityAction: Send { fn update_state( &self, existing_state: Option, diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 1fa1f44fc..6be35e194 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -101,8 +101,8 @@ impl ClientBuilder { impl ClientBuilder where - ApiClient: XmtpApi + Clone + 'static, - V: SmartContractSignatureVerifier + Clone + 'static, + ApiClient: XmtpApi + Clone, + V: SmartContractSignatureVerifier + Clone, { /// Build with a custom smart contract wallet verifier pub async fn build_with_verifier(self) -> Result, ClientBuilderError> { @@ -112,7 +112,7 @@ where impl ClientBuilder> where - ApiClient: XmtpApi + Clone + 'static, + ApiClient: XmtpApi + Clone, { /// Build with the default [`RemoteSignatureVerifier`] pub async fn build(self) -> Result, ClientBuilderError> { @@ -122,8 +122,8 @@ where async fn inner_build(client: ClientBuilder) -> Result, ClientBuilderError> where - C: XmtpApi + Clone + 'static, - V: SmartContractSignatureVerifier + Clone + 'static, + C: XmtpApi + Clone, + V: SmartContractSignatureVerifier + Clone, { let ClientBuilder { mut api_client, diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 5c427df06..73a26bf70 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -301,8 +301,8 @@ impl XmtpMlsLocalContext { impl Client where - ApiClient: XmtpApi + Clone + 'static, - V: SmartContractSignatureVerifier + Clone + 'static, + ApiClient: XmtpApi + Clone, + V: SmartContractSignatureVerifier + Clone, { /// Create a new client with the given network, identity, and store. /// It is expected that most users will use the [`ClientBuilder`](crate::builder::ClientBuilder) instead of instantiating diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index 3b5e6930e..871322ae9 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -111,7 +111,7 @@ impl MlsGroup { &'a self, ) -> Result + '_, GroupError> where - ScopedClient: Clone + 'static, + ScopedClient: Clone, ::ApiClient: Clone + 'static, { let group_list = HashMap::from([( @@ -151,7 +151,7 @@ pub(crate) async fn stream_messages( group_id_to_info: Arc, MessagesStreamInfo>>, ) -> Result + '_, ClientError> where - ScopedClient: ScopedGroupClient + Clone + 'static, + ScopedClient: ScopedGroupClient + Clone, ::ApiClient: XmtpApi + Clone + 'static, { use send_future::SendFuture; diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 997ea0322..84e38466f 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -318,8 +318,8 @@ where pub fn stream_all_messages_with_callback( client: Arc>, - mut callback: impl FnMut(StoredGroupMessage) + Send + Sync + 'static, - ) -> impl crate::StreamHandle> + 'static { + mut callback: impl FnMut(StoredGroupMessage) + Send + 'static, + ) -> impl crate::StreamHandle> { let (tx, rx) = oneshot::channel(); crate::spawn(Some(rx), async move { From 68685f0384d036e582aba1783d9910997013fee2 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 10 Oct 2024 15:13:07 -0400 Subject: [PATCH 80/97] wasm compile --- Cargo.lock | 7 -- xmtp_mls/Cargo.toml | 1 - xmtp_mls/src/client.rs | 49 +++----- xmtp_mls/src/groups/mod.rs | 8 +- xmtp_mls/src/groups/scoped_client.rs | 151 +++++++++++++----------- xmtp_mls/src/groups/subscriptions.rs | 8 +- xmtp_mls/src/groups/sync.rs | 14 ++- xmtp_mls/src/groups/validated_commit.rs | 6 +- xmtp_mls/src/identity.rs | 2 +- xmtp_mls/src/lib.rs | 1 + xmtp_mls/src/subscriptions.rs | 8 +- 11 files changed, 124 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67915250a..dca8265cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4876,12 +4876,6 @@ dependencies = [ "serde", ] -[[package]] -name = "send-future" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224e328af6e080cddbab3c770b1cf50f0351ba0577091ef2410c3951d835ff87" - [[package]] name = "send_wrapper" version = "0.4.0" @@ -6906,7 +6900,6 @@ dependencies = [ "prost", "rand", "reqwest 0.12.8", - "send-future", "serde", "serde_json", "sha2 0.10.8", diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index af60f5148..677ace0ef 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -77,7 +77,6 @@ chrono = { workspace = true, features = ["clock"] } tokio = { workspace = true, features = ["macros", "tracing", "rt", "rt-multi-thread"] } diesel_migrations = { workspace = true, features = ["sqlite"] } openmls = { workspace = true, features = ["test-utils"] } -send-future = "0.1" [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 73a26bf70..0178fb327 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -7,10 +7,7 @@ use std::{ }, }; -use futures::{ - stream::{self, FuturesUnordered, StreamExt}, - Future, -}; +use futures::stream::{self, FuturesUnordered, StreamExt}; use openmls::{ credentials::errors::BasicCredentialError, framing::{MlsMessageBodyIn, MlsMessageIn}, @@ -46,6 +43,7 @@ use crate::{ }, identity::{parse_credential, Identity, IdentityError}, identity_updates::{load_identity_updates, IdentityUpdateError}, + intents::Intents, mutex_registry::MutexRegistry, retry::Retry, retry_async, retryable, @@ -230,6 +228,7 @@ pub struct FindGroupParams { /// Clients manage access to the network, identity, and data store pub struct Client> { pub(crate) api_client: ApiClientWrapper, + pub(crate) intents: Arc, pub(crate) context: Arc, #[cfg(feature = "message-history")] pub(crate) history_sync_url: Option, @@ -252,6 +251,7 @@ where history_sync_url: self.history_sync_url.clone(), local_events: self.local_events.clone(), scw_verifier: self.scw_verifier.clone(), + intents: self.intents.clone(), } } } @@ -317,19 +317,23 @@ where where V: SmartContractSignatureVerifier, { - let context = XmtpMlsLocalContext { + let context = Arc::new(XmtpMlsLocalContext { identity, store, mutexes: MutexRegistry::new(), - }; + }); + let intents = Arc::new(Intents { + context: context.clone(), + }); let (tx, _) = broadcast::channel(10); Self { api_client, - context: Arc::new(context), + context, #[cfg(feature = "message-history")] history_sync_url, local_events: tx, scw_verifier, + intents, } } @@ -351,6 +355,10 @@ where self.context.inbox_id() } + pub fn intents(&self) -> &Arc { + &self.intents + } + /// Pulls a connection and creates a new MLS Provider pub fn mls_provider(&self) -> Result { self.context.mls_provider() @@ -708,31 +716,6 @@ where .collect::>()?) } - pub(crate) async fn process_for_id( - &self, - entity_id: &Vec, - entity_kind: EntityKind, - cursor: u64, - process_envelope: ProcessingFn, - ) -> Result - where - Fut: Future>, - ProcessingFn: FnOnce(XmtpOpenMlsProvider) -> Fut, - { - self.store() - .transaction_async(|provider| async move { - let is_updated = - provider - .conn_ref() - .update_cursor(entity_id, entity_kind, cursor as i64)?; - if !is_updated { - return Err(MessageProcessingError::AlreadyProcessed(cursor)); - } - process_envelope(provider).await - }) - .await - } - /// Download all unread welcome messages and convert to groups. /// Returns any new groups created in the operation pub async fn sync_welcomes(&self) -> Result>, ClientError> { @@ -753,7 +736,7 @@ where Retry::default(), (async { let welcome_v1 = welcome_v1.clone(); - self.process_for_id( + self.intents.process_for_id( &id, EntityKind::Welcome, welcome_v1.id, diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 543819f2f..dcae38c80 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -436,7 +436,7 @@ impl MlsGroup { dm_inbox_id, ), ConversationType::Dm => { - validate_dm_group(&client, &mls_group, &added_by_inbox)?; + validate_dm_group(client.as_ref(), &mls_group, &added_by_inbox)?; StoredGroup::new_from_welcome( group_id.clone(), now_ns(), @@ -458,7 +458,7 @@ impl MlsGroup { ), }; - validate_initial_group_membership(&client, provider.conn_ref(), &mls_group).await?; + validate_initial_group_membership(client.as_ref(), provider.conn_ref(), &mls_group).await?; let stored_group = provider.conn_ref().insert_or_replace_group(to_store)?; @@ -1389,7 +1389,7 @@ fn build_group_config( } async fn validate_initial_group_membership( - client: &impl ScopedGroupClient, + client: impl ScopedGroupClient, conn: &DbConnection, mls_group: &OpenMlsGroup, ) -> Result<(), GroupError> { @@ -1430,7 +1430,7 @@ async fn validate_initial_group_membership( } fn validate_dm_group( - client: &impl ScopedGroupClient, + client: impl ScopedGroupClient, mls_group: &OpenMlsGroup, added_by_inbox: &str, ) -> Result<(), GroupError> { diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs index f57d62215..9665c90d9 100644 --- a/xmtp_mls/src/groups/scoped_client.rs +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -1,16 +1,14 @@ -use std::{future::Future, sync::Arc}; +use std::sync::Arc; use xmtp_id::{associations::AssociationState, scw_verifier::SmartContractSignatureVerifier}; -use xmtp_proto::{ - api_client::{trait_impls::XmtpApi, Error}, - xmtp::mls::api::v1::GroupMessage, -}; +use xmtp_proto::{api_client::trait_impls::XmtpApi, xmtp::mls::api::v1::GroupMessage}; use crate::{ api::ApiClientWrapper, - client::{ClientError, MessageProcessingError, XmtpMlsLocalContext}, + client::{ClientError, XmtpMlsLocalContext}, identity_updates::{InstallationDiff, InstallationDiffError}, - storage::{refresh_state::EntityKind, DbConnection, EncryptedMessageStore}, + intents::Intents, + storage::{DbConnection, EncryptedMessageStore}, verified_key_package_v2::VerifiedKeyPackageV2, xmtp_openmls_provider::XmtpOpenMlsProvider, Client, @@ -18,8 +16,9 @@ use crate::{ use super::group_membership::{GroupMembership, MembershipDiff}; -#[trait_variant::make(ScopedGroupClient: Send)] -pub trait LocalScopedGroupClient: Send + Sync + Sized { +#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(ScopedGroupClient: Send ))] +#[cfg(not(target_arch = "wasm32"))] +pub(crate) trait LocalScopedGroupClient: Send + Sync + Sized { type ApiClient: XmtpApi; fn api(&self) -> &ApiClientWrapper; @@ -36,6 +35,8 @@ pub trait LocalScopedGroupClient: Send + Sync + Sized { self.context_ref().mls_provider() } + fn intents(&self) -> &Arc; + fn context_ref(&self) -> &Arc; fn context(&self) -> Arc { @@ -73,17 +74,65 @@ pub trait LocalScopedGroupClient: Send + Sync + Sized { group_id: &Vec, conn: &DbConnection, ) -> Result, ClientError>; +} + +#[cfg(target_arch = "wasm32")] +pub(crate) trait ScopedGroupClient: Sized { + type ApiClient: XmtpApi; + + fn api(&self) -> &ApiClientWrapper; + + fn store(&self) -> &EncryptedMessageStore { + self.context_ref().store() + } + + fn inbox_id(&self) -> String { + self.context().inbox_id() + } + + fn mls_provider(&self) -> Result { + self.context_ref().mls_provider() + } + + fn intents(&self) -> &Arc; + + fn context_ref(&self) -> &Arc; + + fn context(&self) -> Arc { + self.context_ref().clone() + } + + async fn get_installation_diff( + &self, + conn: &DbConnection, + old_group_membership: &GroupMembership, + new_group_membership: &GroupMembership, + membership_diff: &MembershipDiff<'_>, + ) -> Result; + + async fn get_key_packages_for_installation_ids( + &self, + installation_ids: Vec>, + ) -> Result, ClientError>; + + async fn get_association_state( + &self, + conn: &DbConnection, + inbox_id: String, + to_sequence_id: Option, + ) -> Result; - async fn process_for_id( + async fn batch_get_association_state( &self, - entity_id: &Vec, - entity_kind: EntityKind, - cursor: u64, - process_envelope: ProcessingFn, - ) -> Result - where - Fut: Send + Future>, - ProcessingFn: Send + FnOnce(XmtpOpenMlsProvider) -> Fut; + conn: &DbConnection, + identifiers: &[(String, Option)], + ) -> Result, ClientError>; + + async fn query_group_messages( + &self, + group_id: &Vec, + conn: &DbConnection, + ) -> Result, ClientError>; } impl ScopedGroupClient for Client @@ -101,6 +150,10 @@ where self.context() } + fn intents(&self) -> &Arc { + crate::Client::::intents(self) + } + async fn get_installation_diff( &self, conn: &DbConnection, @@ -160,22 +213,8 @@ where ) -> Result, ClientError> { crate::Client::::query_group_messages(self, group_id, conn).await } - - async fn process_for_id( - &self, - entity_id: &Vec, - entity_kind: EntityKind, - cursor: u64, - process_envelope: ProcessingFn, - ) -> Result - where - Fut: Send + Future>, - ProcessingFn: Send + FnOnce(XmtpOpenMlsProvider) -> Fut, - { - crate::Client::process_for_id(self, entity_id, entity_kind, cursor, process_envelope).await - } } -/* + impl ScopedGroupClient for &T where T: ScopedGroupClient, @@ -190,6 +229,10 @@ where (**self).store() } + fn intents(&self) -> &Arc { + (**self).intents() + } + fn inbox_id(&self) -> String { (**self).inbox_id() } @@ -256,27 +299,12 @@ where ) -> Result, ClientError> { (**self).query_group_messages(group_id, conn).await } - - async fn process_for_id( - &self, - entity_id: &Vec, - entity_kind: EntityKind, - cursor: u64, - process_envelope: ProcessingFn, - ) -> Result - where - Fut: Send + Future>, - ProcessingFn: Send + FnOnce(XmtpOpenMlsProvider) -> Fut, - { - (**self) - .process_for_id(entity_id, entity_kind, cursor, process_envelope) - .await - } } -*/ + +/* impl ScopedGroupClient for Arc where - T: ScopedGroupClient + Send, + T: ScopedGroupClient, { type ApiClient = ::ApiClient; @@ -288,6 +316,10 @@ where (**self).store() } + fn intents(&self) -> &Arc { + (**self).intents() + } + fn inbox_id(&self) -> String { (**self).inbox_id() } @@ -354,20 +386,5 @@ where ) -> Result, ClientError> { (**self).query_group_messages(group_id, conn).await } - - async fn process_for_id( - &self, - entity_id: &Vec, - entity_kind: EntityKind, - cursor: u64, - process_envelope: ProcessingFn, - ) -> Result - where - Fut: Send + Future>, - ProcessingFn: Send + FnOnce(XmtpOpenMlsProvider) -> Fut, - { - (**self) - .process_for_id(entity_id, entity_kind, cursor, process_envelope) - .await - } } +*/ diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index 871322ae9..b7e8372e3 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -141,7 +141,7 @@ impl MlsGroup { cursor: 0, }, )]); - stream_messages_with_callback(Arc::new(client), group_list, callback) + stream_messages_with_callback(client, group_list, callback) } } @@ -154,7 +154,6 @@ where ScopedClient: ScopedGroupClient + Clone, ::ApiClient: XmtpApi + Clone + 'static, { - use send_future::SendFuture; let filters: Vec = group_id_to_info .iter() .map(|(group_id, info)| GroupFilter::new(group_id.clone(), Some(info.cursor))) @@ -206,7 +205,7 @@ where /// Stream messages from groups in `group_id_to_info`, passing /// messages along to a callback. pub(crate) fn stream_messages_with_callback( - client: Arc, + client: ScopedClient, group_id_to_info: HashMap, MessagesStreamInfo>, mut callback: impl FnMut(StoredGroupMessage) + Send + 'static, ) -> impl crate::StreamHandle> @@ -214,12 +213,9 @@ where ScopedClient: ScopedGroupClient + Clone + 'static, ::ApiClient: XmtpApi + Clone + 'static, { - use send_future::SendFuture; let (tx, rx) = oneshot::channel(); - let client: Arc = client.clone(); crate::spawn(Some(rx), async move { - let client: Arc = Arc::clone(&client); let stream = stream_messages(&client, Arc::new(group_id_to_info)).await?; futures::pin_mut!(stream); let _ = tx.send(()); diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index dcf5e7286..c19fb7d29 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -85,7 +85,10 @@ struct PublishIntentData { payload_to_publish: Vec, } -impl MlsGroup { +impl MlsGroup +where + ScopedClient: ScopedGroupClient, +{ pub async fn sync(&self) -> Result<(), GroupError> { let conn = self.context().store().conn()?; let mls_provider = XmtpOpenMlsProvider::from(conn); @@ -300,7 +303,7 @@ impl MlsGroup { ); let maybe_validated_commit = ValidatedCommit::from_staged_commit( - &self.client, + self.client.as_ref(), conn, &pending_commit, openmls_group, @@ -475,7 +478,7 @@ impl MlsGroup { // Validate the commit let validated_commit = ValidatedCommit::from_staged_commit( - &self.client, + self.client.as_ref(), provider.conn_ref(), &sc, openmls_group, @@ -584,6 +587,7 @@ impl MlsGroup { }; self.client + .intents() .process_for_id( &msgv1.group_id, EntityKind::Group, @@ -794,7 +798,7 @@ impl MlsGroup { let intent_data = UpdateGroupMembershipIntentData::try_from(&intent.data)?; let signer = &self.context().identity.installation_keys; apply_update_group_membership_intent( - &self.client, + self.client.as_ref(), provider, openmls_group, intent_data, @@ -1120,7 +1124,7 @@ fn extract_message_sender( // returning the commit and post_commit_action #[tracing::instrument(level = "trace", skip_all)] async fn apply_update_group_membership_intent( - client: &impl ScopedGroupClient, + client: impl ScopedGroupClient, provider: &XmtpOpenMlsProvider, openmls_group: &mut OpenMlsGroup, intent_data: UpdateGroupMembershipIntentData, diff --git a/xmtp_mls/src/groups/validated_commit.rs b/xmtp_mls/src/groups/validated_commit.rs index 9e7626608..bbef711c5 100644 --- a/xmtp_mls/src/groups/validated_commit.rs +++ b/xmtp_mls/src/groups/validated_commit.rs @@ -215,7 +215,7 @@ pub struct ValidatedCommit { impl ValidatedCommit { pub async fn from_staged_commit( - client: &impl ScopedGroupClient, + client: impl ScopedGroupClient, conn: &DbConnection, staged_commit: &StagedCommit, openmls_group: &OpenMlsGroup, @@ -275,7 +275,7 @@ impl ValidatedCommit { removed_inboxes, } = extract_expected_diff( conn, - client, + &client, staged_commit, existing_group_context, &immutable_metadata, @@ -453,7 +453,7 @@ struct ExpectedDiff { /// Satisfies Rule 2 async fn extract_expected_diff<'diff>( conn: &DbConnection, - client: &impl ScopedGroupClient, + client: impl ScopedGroupClient, staged_commit: &StagedCommit, existing_group_context: &GroupContext, immutable_metadata: &GroupMetadata, diff --git a/xmtp_mls/src/identity.rs b/xmtp_mls/src/identity.rs index a84a9630a..1934fa2d0 100644 --- a/xmtp_mls/src/identity.rs +++ b/xmtp_mls/src/identity.rs @@ -64,7 +64,7 @@ impl IdentityStrategy { self, api_client: &ApiClientWrapper, store: &EncryptedMessageStore, - scw_signature_verifier: &impl SmartContractSignatureVerifier, + scw_signature_verifier: impl SmartContractSignatureVerifier, ) -> Result { info!("Initializing identity"); let conn = store.conn()?; diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index f02bbcd98..0a1f45bb5 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -10,6 +10,7 @@ pub mod groups; mod hpke; pub mod identity; mod identity_updates; +mod intents; mod mutex_registry; pub mod retry; pub mod storage; diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 84e38466f..dba4da96a 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -75,8 +75,8 @@ impl From for (Vec, MessagesStreamInfo) { impl Client where - ApiClient: XmtpApi + Clone + Send + 'static, - V: SmartContractSignatureVerifier + Clone + Send + 'static, + ApiClient: XmtpApi + Clone + Send + Sync + 'static, + V: SmartContractSignatureVerifier + Clone + Send + Sync + 'static, { async fn process_streamed_welcome( &self, @@ -208,8 +208,8 @@ where impl Client where - ApiClient: XmtpApi + Clone + Send + 'static, - V: SmartContractSignatureVerifier + Send + Clone + 'static, + ApiClient: XmtpApi + Clone + Send + Sync + 'static, + V: SmartContractSignatureVerifier + Send + Sync + Clone + 'static, { pub fn stream_conversations_with_callback( client: Arc>, From 5d882b6e384eca5a8134ff139532989a7b2e732f Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 10 Oct 2024 15:29:04 -0400 Subject: [PATCH 81/97] compiles --- xmtp_api_grpc/src/lib.rs | 1 - xmtp_mls/src/groups/scoped_client.rs | 8 ++++---- xmtp_mls/src/subscriptions.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index de761fd5a..a37518a9d 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -1,7 +1,6 @@ pub mod auth_token; pub mod grpc_api_helper; mod identity; -pub mod util; pub const LOCALHOST_ADDRESS: &str = "http://localhost:5556"; pub const DEV_ADDRESS: &str = "https://grpc.dev.xmtp.network:443"; diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs index 9665c90d9..1905b380d 100644 --- a/xmtp_mls/src/groups/scoped_client.rs +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -18,7 +18,8 @@ use super::group_membership::{GroupMembership, MembershipDiff}; #[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(ScopedGroupClient: Send ))] #[cfg(not(target_arch = "wasm32"))] -pub(crate) trait LocalScopedGroupClient: Send + Sync + Sized { +#[allow(unused)] +pub trait LocalScopedGroupClient: Send + Sync + Sized { type ApiClient: XmtpApi; fn api(&self) -> &ApiClientWrapper; @@ -77,7 +78,8 @@ pub(crate) trait LocalScopedGroupClient: Send + Sync + Sized { } #[cfg(target_arch = "wasm32")] -pub(crate) trait ScopedGroupClient: Sized { +#[allow(async_fn_in_trait)] +pub trait ScopedGroupClient: Sized { type ApiClient: XmtpApi; fn api(&self) -> &ApiClientWrapper; @@ -301,7 +303,6 @@ where } } -/* impl ScopedGroupClient for Arc where T: ScopedGroupClient, @@ -387,4 +388,3 @@ where (**self).query_group_messages(group_id, conn).await } } -*/ diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index dba4da96a..3899eec03 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -209,7 +209,7 @@ where impl Client where ApiClient: XmtpApi + Clone + Send + Sync + 'static, - V: SmartContractSignatureVerifier + Send + Sync + Clone + 'static, + V: SmartContractSignatureVerifier + Clone + Send + Sync + 'static, { pub fn stream_conversations_with_callback( client: Arc>, From a050107a0b221ee090369dc095e90c321a0e4d82 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 10 Oct 2024 22:04:52 -0400 Subject: [PATCH 82/97] all works --- xmtp_api_grpc/Cargo.toml | 3 +- xmtp_api_grpc/src/lib.rs | 21 + xmtp_api_http/src/util.rs | 8 +- xmtp_mls/Cargo.toml | 1 + xmtp_mls/src/builder.rs | 43 +- xmtp_mls/src/client.rs | 43 +- xmtp_mls/src/groups/message_history.rs | 4 +- xmtp_mls/src/groups/mod.rs | 536 ++++++++++++------------- xmtp_mls/src/groups/subscriptions.rs | 39 +- xmtp_mls/src/groups/sync.rs | 4 +- xmtp_mls/src/identity_updates.rs | 16 +- xmtp_mls/src/intents.rs | 51 +++ xmtp_mls/src/subscriptions.rs | 109 ++--- xmtp_mls/src/utils/test/mod.rs | 25 +- 14 files changed, 463 insertions(+), 440 deletions(-) create mode 100644 xmtp_mls/src/intents.rs diff --git a/xmtp_api_grpc/Cargo.toml b/xmtp_api_grpc/Cargo.toml index c913c24ff..63976306a 100644 --- a/xmtp_api_grpc/Cargo.toml +++ b/xmtp_api_grpc/Cargo.toml @@ -20,6 +20,7 @@ xmtp_v2 = { path = "../xmtp_v2" } [dev-dependencies] uuid = { workspace = true, features = ["v4"] } +xmtp_proto = { path = "../xmtp_proto", features = ["test-utils"] } [features] -test-utils = [] +test-utils = ["xmtp_proto/test-utils"] diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index a37518a9d..57b1f9413 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -7,6 +7,27 @@ pub const DEV_ADDRESS: &str = "https://grpc.dev.xmtp.network:443"; pub use grpc_api_helper::{Client, GroupMessageStream, WelcomeMessageStream}; +mod utils { + #[cfg(feature = "test-utils")] + mod test { + use xmtp_proto::api_client::trait_impls::XmtpTestClient; + + impl XmtpTestClient for crate::Client { + async fn create_local() -> Self { + crate::Client::create("http://localhost:5556".into(), false) + .await + .unwrap() + } + + async fn create_dev() -> Self { + crate::Client::create("https://grpc.dev.xmtp.network:443".into(), false) + .await + .unwrap() + } + } + } +} + #[cfg(test)] pub mod tests { use std::time::{SystemTime, UNIX_EPOCH}; diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index 9b4e3687f..df253aff8 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -5,7 +5,7 @@ use futures::{ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::Deserializer; use std::io::Read; -use xmtp_proto::api_client::{Error, ErrorKind}; +use xmtp_proto::api_client::{trait_impls::XmtpTestClient, Error, ErrorKind}; #[derive(Deserialize, Serialize, Debug)] #[serde(untagged)] @@ -117,13 +117,13 @@ pub fn create_grpc_stream_inner< } #[cfg(feature = "test-utils")] -impl XmtpTestClient for XmtpHttpApiClient { +impl XmtpTestClient for crate::XmtpHttpApiClient { async fn create_local() -> Self { - XmtpHttpApiClient::new("http://localhost:5555".into()).unwrap() + crate::XmtpHttpApiClient::new("http://localhost:5555".into()).unwrap() } async fn create_dev() -> Self { - XmtpHttpApiClient::new("https://grpc.dev.xmtp.network:443".into()).unwrap() + crate::XmtpHttpApiClient::new("https://grpc.dev.xmtp.network:443".into()).unwrap() } } diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 677ace0ef..e6b51e1ab 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -103,6 +103,7 @@ anyhow.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] ethers = { workspace = true, features = ["openssl"] } xmtp_api_grpc = { path = "../xmtp_api_grpc", features = ["test-utils"] } +xmtp_api_http = { path = "../xmtp_api_http", features = ["test-utils"] } tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "ansi"] } tempfile = "3.5.0" mockito = "1.4.0" diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 6be35e194..447c4142b 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -55,6 +55,13 @@ pub struct ClientBuilder> { scw_verifier: Option, } +impl Client { + /// Ge tthe builder for this [`Client`] + pub fn builder(strategy: IdentityStrategy) -> ClientBuilder { + ClientBuilder::::new(strategy) + } +} + impl ClientBuilder { pub fn new(strategy: IdentityStrategy) -> Self { Self { @@ -213,6 +220,7 @@ pub(crate) mod tests { }; use xmtp_id::associations::ValidatedLegacySignedPublicKey; use xmtp_id::associations::{generate_inbox_id, test_utils::rand_u64}; + use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::xmtp::identity::api::v1::{ get_inbox_ids_response::Response as GetInboxIdsResponseItem, GetInboxIdsResponse, }; @@ -230,7 +238,10 @@ pub(crate) mod tests { Client, InboxOwner, }; - async fn register_client(client: &Client, owner: &impl InboxOwner) { + async fn register_client( + client: &Client, + owner: &impl InboxOwner, + ) { let mut signature_request = client.context.signature_request().unwrap(); let signature_text = signature_request.signature_text(); let scw_verifier = MockSmartContractSignatureVerifier::new(true); @@ -392,7 +403,8 @@ pub(crate) mod tests { .await .local_client() .await - .build() + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) + .build_with_verifier() .await; if let Some(err_string) = test_case.err { @@ -432,7 +444,8 @@ pub(crate) mod tests { .store(store.clone()) .local_client() .await - .build() + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) + .build_with_verifier() .await .unwrap(); assert!(client1.context.signature_request().is_none()); @@ -441,7 +454,8 @@ pub(crate) mod tests { .store(store.clone()) .local_client() .await - .build() + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) + .build_with_verifier() .await .unwrap(); assert!(client2.context.signature_request().is_none()); @@ -457,7 +471,8 @@ pub(crate) mod tests { .store(store.clone()) .local_client() .await - .build() + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) + .build_with_verifier() .await .unwrap(); assert!(client3.context.signature_request().is_none()); @@ -474,7 +489,8 @@ pub(crate) mod tests { .await .local_client() .await - .build() + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) + .build_with_verifier() .await .unwrap(); assert!(client4.context.signature_request().is_some()); @@ -660,7 +676,7 @@ pub(crate) mod tests { let nonce = 1; let inbox_id = generate_inbox_id(&wallet.get_address(), &nonce); - let client_a = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( + let client_a = Client::builder(IdentityStrategy::CreateIfNotFound( inbox_id.clone(), wallet.get_address(), nonce, @@ -669,7 +685,8 @@ pub(crate) mod tests { .local_client() .await .store(store_a) - .build() + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) + .build_with_verifier() .await .unwrap(); @@ -684,7 +701,7 @@ pub(crate) mod tests { .await .unwrap(); - let client_b = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( + let client_b = Client::builder(IdentityStrategy::CreateIfNotFound( inbox_id, wallet.get_address(), nonce, @@ -693,7 +710,8 @@ pub(crate) mod tests { .local_client() .await .store(store_b) - .build() + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) + .build_with_verifier() .await .unwrap(); let keybytes_b = client_b.installation_public_key(); @@ -723,11 +741,12 @@ pub(crate) mod tests { let store_d = EncryptedMessageStore::new(StorageOption::Persistent(tmpdb.clone()), db_key) .await .unwrap(); - let client_d = ClientBuilder::new(IdentityStrategy::CachedOnly) + let client_d = Client::builder(IdentityStrategy::CachedOnly) .local_client() .await .store(store_d) - .build() + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) + .build_with_verifier() .await .unwrap(); assert_eq!(client_d.installation_public_key(), keybytes_a); diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 0178fb327..418de8a07 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -579,9 +579,9 @@ where } #[cfg(feature = "message-history")] - pub(crate) fn create_sync_group(&self) -> Result { + pub(crate) fn create_sync_group(&self) -> Result, ClientError> { tracing::info!("creating sync group"); - let sync_group = MlsGroup::create_and_insert_sync_group(self.context.clone())?; + let sync_group = MlsGroup::create_and_insert_sync_group(Arc::new(self.clone()))?; Ok(sync_group) } @@ -910,7 +910,7 @@ pub(crate) mod tests { use super::Client; use diesel::RunQueryDsl; use xmtp_cryptography::utils::generate_local_wallet; - use xmtp_id::InboxOwner; + use xmtp_id::{scw_verifier::SmartContractSignatureVerifier, InboxOwner}; use crate::{ builder::ClientBuilder, @@ -939,7 +939,7 @@ pub(crate) mod tests { // Add both of Bola's installations to the group group - .add_members_by_inbox_id(&amal, vec![bola_a.inbox_id(), bola_b.inbox_id()]) + .add_members_by_inbox_id(vec![bola_a.inbox_id(), bola_b.inbox_id()]) .await .unwrap(); @@ -947,7 +947,7 @@ pub(crate) mod tests { conn.raw_query(|conn| diesel::delete(identity_updates::table).execute(conn)) .unwrap(); - let members = group.members(&amal).await.unwrap(); + let members = group.members().await.unwrap(); // // The three installations should count as two members assert_eq!(members.len(), 2); } @@ -1056,7 +1056,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); alice_bob_group - .add_members_by_inbox_id(&alice, vec![bob.inbox_id()]) + .add_members_by_inbox_id(vec![bob.inbox_id()]) .await .unwrap(); @@ -1087,11 +1087,11 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); alix_bo_group1 - .add_members_by_inbox_id(&alix, vec![bo.inbox_id()]) + .add_members_by_inbox_id(vec![bo.inbox_id()]) .await .unwrap(); alix_bo_group2 - .add_members_by_inbox_id(&alix, vec![bo.inbox_id()]) + .add_members_by_inbox_id(vec![bo.inbox_id()]) .await .unwrap(); @@ -1110,11 +1110,11 @@ pub(crate) mod tests { .unwrap(); assert_eq!(bo_messages2.len(), 0); alix_bo_group1 - .send_message(vec![1, 2, 3].as_slice(), &alix) + .send_message(vec![1, 2, 3].as_slice()) .await .unwrap(); alix_bo_group2 - .send_message(vec![1, 2, 3].as_slice(), &alix) + .send_message(vec![1, 2, 3].as_slice()) .await .unwrap(); @@ -1166,17 +1166,17 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); - assert_eq!(amal_group.members(&amal).await.unwrap().len(), 2); + assert_eq!(amal_group.members().await.unwrap().len(), 2); // Now remove bola amal_group - .remove_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .remove_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); - assert_eq!(amal_group.members(&amal).await.unwrap().len(), 1); + assert_eq!(amal_group.members().await.unwrap().len(), 1); tracing::info!("Syncing bolas welcomes"); // See if Bola can see that they were added to the group bola.sync_welcomes().await.unwrap(); @@ -1184,7 +1184,7 @@ pub(crate) mod tests { assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); tracing::info!("Syncing bolas messages"); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); // TODO: figure out why Bola's status is not updating to be inactive // assert!(!bola_group.is_active().unwrap()); @@ -1197,19 +1197,19 @@ pub(crate) mod tests { // Add Bola back to the group amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); bola.sync_welcomes().await.unwrap(); // Send a message from Amal, now that Bola is back in the group amal_group - .send_message(vec![1, 2, 3].as_slice(), &amal) + .send_message(vec![1, 2, 3].as_slice()) .await .unwrap(); // Sync Bola's state to get the latest - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); // Find Bola's updated list of messages bola_messages = bola_group .find_messages(None, None, None, None, None) @@ -1247,8 +1247,11 @@ pub(crate) mod tests { assert_eq!(address_consent, ConsentState::Denied); } - async fn get_key_package_init_key( - client: &Client, + async fn get_key_package_init_key< + ApiClient: XmtpApi + Clone, + Verifier: SmartContractSignatureVerifier + Clone, + >( + client: &Client, installation_id: &[u8], ) -> Vec { let kps = client diff --git a/xmtp_mls/src/groups/message_history.rs b/xmtp_mls/src/groups/message_history.rs index 292aedf6b..6c8a036f7 100644 --- a/xmtp_mls/src/groups/message_history.rs +++ b/xmtp_mls/src/groups/message_history.rs @@ -15,6 +15,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use xmtp_cryptography::utils as crypto_utils; +use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::{ xmtp::mls::message_contents::plaintext_envelope::v2::MessageType::{Reply, Request}, xmtp::mls::message_contents::plaintext_envelope::{Content, V2}, @@ -104,8 +105,9 @@ enum SyncableTables { impl Client where ApiClient: XmtpApi, + V: SmartContractSignatureVerifier, { - pub fn get_sync_group(&self) -> Result { + pub fn get_sync_group(&self) -> Result, GroupError> { let conn = self.store().conn()?; let sync_group_id = conn .find_sync_groups()? diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index dcae38c80..cdcc57e99 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -503,8 +503,9 @@ impl MlsGroup { #[cfg(feature = "message-history")] pub(crate) fn create_and_insert_sync_group( - context: Arc, - ) -> Result { + client: Arc, + ) -> Result, GroupError> { + let context = client.context(); let conn = context.store().conn()?; // let my_sequence_id = context.inbox_sequence_id(&conn)?; let creator_inbox_id = context.inbox_id().to_string(); @@ -540,8 +541,8 @@ impl MlsGroup { stored_group.store(provider.conn_ref())?; - Ok(Self::new( - context.clone(), + Ok(Self::new_from_arc( + client, stored_group.id, stored_group.created_at_ns, )) @@ -739,22 +740,20 @@ impl MlsGroup { pub async fn remove_members( &self, - client: ScopedClient, account_addresses_to_remove: Vec, ) -> Result<(), GroupError> { let account_addresses = sanitize_evm_addresses(account_addresses_to_remove)?; - let inbox_id_map = client.api().get_inbox_ids(account_addresses).await?; + let inbox_id_map = self.client.api().get_inbox_ids(account_addresses).await?; - self.remove_members_by_inbox_id(client, inbox_id_map.into_values().collect()) + self.remove_members_by_inbox_id(inbox_id_map.into_values().collect()) .await } pub async fn remove_members_by_inbox_id( &self, - client: ScopedClient, inbox_ids: Vec, ) -> Result<(), GroupError> { - let provider = client.store().conn()?.into(); + let provider = self.client.store().conn()?.into(); let intent_data = self .get_membership_update_intent(&provider, vec![], inbox_ids) @@ -1055,18 +1054,20 @@ impl MlsGroup { Ok(extract_group_permissions(&mls_group)?) } + /// Used for testing that dm group validation works as expected. /// /// See the `test_validate_dm_group` test function for more details. #[cfg(test)] pub fn create_test_dm_group( - context: Arc, + client: Arc, dm_target_inbox_id: InboxId, custom_protected_metadata: Option, custom_mutable_metadata: Option, custom_group_membership: Option, custom_mutable_permissions: Option, ) -> Result { + let context = client.context(); let conn = context.store().conn()?; let provider = XmtpOpenMlsProvider::new(conn); @@ -1111,8 +1112,8 @@ impl MlsGroup { ); stored_group.store(provider.conn_ref())?; - Ok(Self::new( - context.clone(), + Ok(Self::new_from_arc( + client, group_id, stored_group.created_at_ns, )) @@ -1524,27 +1525,22 @@ pub(crate) mod tests { group_intent::{IntentKind, IntentState, NewGroupIntent}, group_message::{GroupMessageKind, StoredGroupMessage}, }, + utils::test::FullXmtpClient, xmtp_openmls_provider::XmtpOpenMlsProvider, - Client, InboxOwner, StreamHandle as _, XmtpApi, + InboxOwner, StreamHandle as _, }; - use super::{group_permissions::PolicySet, MlsGroup, ScopedGroupClient}; + use super::{group_permissions::PolicySet, MlsGroup}; - async fn receive_group_invite(client: impl ScopedGroupClient) -> MlsGroup - where - ApiClient: XmtpApi, - { + async fn receive_group_invite(client: &FullXmtpClient) -> MlsGroup { client.sync_welcomes().await.unwrap(); let mut groups = client.find_groups(FindGroupParams::default()).unwrap(); groups.remove(0) } - async fn get_latest_message( - group: &MlsGroup, - client: impl ScopedGroupClient, - ) -> StoredGroupMessage { - group.sync(client).await.unwrap(); + async fn get_latest_message(group: &MlsGroup) -> StoredGroupMessage { + group.sync().await.unwrap(); let mut messages = group.find_messages(None, None, None, None, None).unwrap(); messages.pop().unwrap() } @@ -1553,9 +1549,9 @@ pub(crate) mod tests { // Used for testing adversarial scenarios #[cfg(not(target_arch = "wasm32"))] async fn force_add_member( - sender_client: impl ScopedGroupClient, - new_member_client: impl ScopedGroupClient, - sender_group: &MlsGroup, + sender_client: &FullXmtpClient, + new_member_client: &FullXmtpClient, + sender_group: &MlsGroup, sender_mls_group: &mut openmls::prelude::MlsGroup, sender_provider: &XmtpOpenMlsProvider, ) { @@ -1590,7 +1586,7 @@ pub(crate) mod tests { .await .unwrap(); sender_group - .send_welcomes(send_welcomes_action, sender_client) + .send_welcomes(send_welcomes_action) .await .unwrap(); } @@ -1603,10 +1599,7 @@ pub(crate) mod tests { let group = client .create_group(None, GroupMetadataOptions::default()) .expect("create group"); - group - .send_message(b"hello", &client) - .await - .expect("send message"); + group.send_message(b"hello").await.expect("send message"); let messages = client .api_client @@ -1625,13 +1618,10 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .expect("create group"); let msg = b"hello"; - group - .send_message(msg, &client) - .await - .expect("send message"); + group.send_message(msg).await.expect("send message"); group - .receive(&client.store().conn().unwrap().into(), &client) + .receive(&client.store().conn().unwrap().into()) .await .unwrap(); // Check for messages @@ -1649,26 +1639,26 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .expect("create group"); alix_group - .add_members_by_inbox_id(&alix, vec![bo.inbox_id()]) + .add_members_by_inbox_id(vec![bo.inbox_id()]) .await .unwrap(); let alix_message = b"hello from alix"; alix_group - .send_message(alix_message, &alix) + .send_message(alix_message) .await .expect("send message"); let bo_group = receive_group_invite(&bo).await; - let message = get_latest_message(&bo_group, &bo).await; + let message = get_latest_message(&bo_group).await; assert_eq!(message.decrypted_message_bytes, alix_message); let bo_message = b"hello from bo"; bo_group - .send_message(bo_message, &bo) + .send_message(bo_message) .await .expect("send message"); - let message = get_latest_message(&alix_group, &alix).await; + let message = get_latest_message(&alix_group).await; assert_eq!(message.decrypted_message_bytes, bo_message); } @@ -1683,7 +1673,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); @@ -1692,8 +1682,8 @@ pub(crate) mod tests { let bola_group = bola_groups.first().unwrap(); // Call sync for both - amal_group.sync(&amal).await.unwrap(); - bola_group.sync(&bola).await.unwrap(); + amal_group.sync().await.unwrap(); + bola_group.sync().await.unwrap(); // Verify bola can see the group name let bola_group_name = bola_group @@ -1702,8 +1692,8 @@ pub(crate) mod tests { assert_eq!(bola_group_name, ""); // Check if both clients can see the members correctly - let amal_members: Vec = amal_group.members(&amal).await.unwrap(); - let bola_members: Vec = bola_group.members(&bola).await.unwrap(); + let amal_members: Vec = amal_group.members().await.unwrap(); + let bola_members: Vec = bola_group.members().await.unwrap(); assert_eq!(amal_members.len(), 2); assert_eq!(bola_members.len(), 2); @@ -1739,29 +1729,29 @@ pub(crate) mod tests { .unwrap(); // Add bola amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); // Get bola's version of the same group let bola_groups = bola.sync_welcomes().await.unwrap(); let bola_group = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); tracing::info!("Adding charlie from amal"); // Have amal and bola both invite charlie. amal_group - .add_members_by_inbox_id(&amal, vec![charlie.inbox_id()]) + .add_members_by_inbox_id(vec![charlie.inbox_id()]) .await .expect("failed to add charlie"); tracing::info!("Adding charlie from bola"); bola_group - .add_members_by_inbox_id(&bola, vec![charlie.inbox_id()]) + .add_members_by_inbox_id(vec![charlie.inbox_id()]) .await .expect("bola's add should succeed in a no-op"); amal_group - .receive(&amal.store().conn().unwrap().into(), &amal) + .receive(&amal.store().conn().unwrap().into()) .await .expect_err("expected error"); @@ -1804,11 +1794,11 @@ pub(crate) mod tests { // Make sure sending and receiving both worked amal_group - .send_message("hello from amal".as_bytes(), &amal) + .send_message("hello from amal".as_bytes()) .await .unwrap(); bola_group - .send_message("hello from bola".as_bytes(), &bola) + .send_message("hello from bola".as_bytes()) .await .unwrap(); @@ -1831,7 +1821,7 @@ pub(crate) mod tests { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; - let alix_group: MlsGroup = alix + let alix_group = alix .create_group(None, GroupMetadataOptions::default()) .unwrap(); let provider = alix.mls_provider().unwrap(); @@ -1871,7 +1861,7 @@ pub(crate) mod tests { .expect("create group"); group - .add_members_by_inbox_id(&client, vec![client_2.inbox_id()]) + .add_members_by_inbox_id(vec![client_2.inbox_id()]) .await .unwrap(); @@ -1895,7 +1885,7 @@ pub(crate) mod tests { .expect("create group"); let result = group - .add_members_by_inbox_id(&client, vec!["1234".to_string()]) + .add_members_by_inbox_id(vec!["1234".to_string()]) .await; assert!(result.is_err()); @@ -1909,9 +1899,7 @@ pub(crate) mod tests { let group = amal .create_group(None, GroupMetadataOptions::default()) .unwrap(); - let result = group - .add_members(&amal, vec![unconnected_wallet_address]) - .await; + let result = group.add_members(vec![unconnected_wallet_address]).await; assert!(result.is_err()); } @@ -1927,7 +1915,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .expect("create group"); group - .add_members_by_inbox_id(&client_1, vec![client_2.inbox_id()]) + .add_members_by_inbox_id(vec![client_2.inbox_id()]) .await .expect("group create failure"); @@ -1936,7 +1924,7 @@ pub(crate) mod tests { // Try and add another member without merging the pending commit group - .remove_members_by_inbox_id(&client_1, vec![client_2.inbox_id()]) + .remove_members_by_inbox_id(vec![client_2.inbox_id()]) .await .expect("group remove members failure"); @@ -1965,11 +1953,11 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .expect("create group"); group - .add_members_by_inbox_id(&client, vec![bola_client.inbox_id()]) + .add_members_by_inbox_id(vec![bola_client.inbox_id()]) .await .unwrap(); - group.key_update(&client).await.unwrap(); + group.key_update().await.unwrap(); let messages = client .api_client @@ -1983,15 +1971,12 @@ pub(crate) mod tests { let pending_commit = mls_group.pending_commit(); assert!(pending_commit.is_none()); - group - .send_message(b"hello", &client) - .await - .expect("send message"); + group.send_message(b"hello").await.expect("send message"); bola_client.sync_welcomes().await.unwrap(); let bola_groups = bola_client.find_groups(FindGroupParams::default()).unwrap(); let bola_group = bola_groups.first().unwrap(); - bola_group.sync(&bola_client).await.unwrap(); + bola_group.sync().await.unwrap(); let bola_messages = bola_group .find_messages(None, None, None, None, None) .unwrap(); @@ -2008,7 +1993,7 @@ pub(crate) mod tests { .expect("create group"); group - .add_members_by_inbox_id(&client, vec![client_2.inbox_id()]) + .add_members_by_inbox_id(vec![client_2.inbox_id()]) .await .unwrap(); @@ -2035,14 +2020,14 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); group - .add_members( - &amal, - vec![bola_wallet.get_address(), charlie_wallet.get_address()], - ) + .add_members(vec![ + bola_wallet.get_address(), + charlie_wallet.get_address(), + ]) .await .unwrap(); tracing::info!("created the group with 2 additional members"); - assert_eq!(group.members(&bola).await.unwrap().len(), 3); + assert_eq!(group.members().await.unwrap().len(), 3); let messages = group.find_messages(None, None, None, None, None).unwrap(); assert_eq!(messages.len(), 1); assert_eq!(messages[0].kind, GroupMessageKind::MembershipChange); @@ -2053,10 +2038,10 @@ pub(crate) mod tests { assert_eq!(group_update.removed_inboxes.len(), 0); group - .remove_members(&amal, vec![bola_wallet.get_address()]) + .remove_members(vec![bola_wallet.get_address()]) .await .unwrap(); - assert_eq!(group.members(&bola).await.unwrap().len(), 2); + assert_eq!(group.members().await.unwrap().len(), 2); tracing::info!("removed bola"); let messages = group.find_messages(None, None, None, None, None).unwrap(); assert_eq!(messages.len(), 2); @@ -2068,7 +2053,7 @@ pub(crate) mod tests { assert_eq!(group_update.removed_inboxes.len(), 1); let bola_group = receive_group_invite(&bola).await; - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); assert!(!bola_group .is_active(bola_group.mls_provider().unwrap()) .unwrap()) @@ -2083,58 +2068,60 @@ pub(crate) mod tests { let charlie_wallet = &generate_local_wallet(); let charlie = ClientBuilder::new_test_client(charlie_wallet).await; - let group = amal + let amal_group = amal .create_group(None, GroupMetadataOptions::default()) .unwrap(); - group - .add_members( - &amal, - vec![bola_wallet.get_address(), charlie_wallet.get_address()], - ) + amal_group + .add_members(vec![ + bola_wallet.get_address(), + charlie_wallet.get_address(), + ]) .await .unwrap(); - assert_eq!(group.members(&bola).await.unwrap().len(), 3); + assert_eq!(amal_group.members().await.unwrap().len(), 3); - group - .remove_members(&amal, vec![bola_wallet.get_address()]) + amal_group + .remove_members(vec![bola_wallet.get_address()]) .await .unwrap(); - assert_eq!(group.members(&bola).await.unwrap().len(), 2); - assert!(group - .members(&bola) + assert_eq!(amal_group.members().await.unwrap().len(), 2); + assert!(amal_group + .members() .await .unwrap() .iter() .all(|m| m.inbox_id != bola.inbox_id())); - assert!(group - .members(&bola) + assert!(amal_group + .members() .await .unwrap() .iter() .any(|m| m.inbox_id == charlie.inbox_id())); - group.sync(&amal).await.expect("sync failed"); + amal_group.sync().await.expect("sync failed"); let message_text = b"hello"; - group - .send_message(message_text, &bola) + + let bola_group = MlsGroup::::new( + bola.clone(), + amal_group.group_id.clone(), + amal_group.created_at_ns, + ); + bola_group + .send_message(message_text) .await .expect_err("expected send_message to fail"); - group.sync(&bola).await.expect("sync failed"); - group.sync(&amal).await.expect("sync failed"); + amal_group.sync().await.expect("sync failed"); + amal_group.sync().await.expect("sync failed"); - let amal_messages = group + let amal_messages = amal_group .find_messages(Some(GroupMessageKind::Application), None, None, None, None) .unwrap() .into_iter() .collect::>(); - let message = amal_messages.first().unwrap(); - - // FIXME:st this is passing ONLY because the message IS being sent to the group - assert_eq!(message_text, &message.decrypted_message_bytes[..]); - assert_eq!(amal_messages.len(), 1); + assert!(amal_messages.is_empty()); } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] @@ -2150,11 +2137,11 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); - assert_eq!(group.members(&amal).await.unwrap().len(), 2); + assert_eq!(group.members().await.unwrap().len(), 2); let provider: XmtpOpenMlsProvider = amal.context.store().conn().unwrap().into(); // Finished with setup @@ -2163,10 +2150,10 @@ pub(crate) mod tests { let _amal_2nd = ClientBuilder::new_test_client(&amal_wallet).await; // test if adding the new installation(s) worked - let new_installations_were_added = group.add_missing_installations(&provider, &amal).await; + let new_installations_were_added = group.add_missing_installations(&provider).await; assert!(new_installations_were_added.is_ok()); - group.sync(&amal).await.unwrap(); + group.sync().await.unwrap(); let mls_group = group.load_mls_group(&provider).unwrap(); let num_members = mls_group.members().collect::>().len(); assert_eq!(num_members, 3); @@ -2188,35 +2175,35 @@ pub(crate) mod tests { .unwrap(); // Add bola to the group amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); let bola_group = receive_group_invite(&bola).await; - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); // Both Amal and Bola are up to date on the group state. Now each of them want to add someone else amal_group - .add_members_by_inbox_id(&amal, vec![charlie.inbox_id()]) + .add_members_by_inbox_id(vec![charlie.inbox_id()]) .await .unwrap(); bola_group - .add_members_by_inbox_id(&bola, vec![dave.inbox_id()]) + .add_members_by_inbox_id(vec![dave.inbox_id()]) .await .unwrap(); // Send a message to the group, now that everyone is invited - amal_group.sync(&amal).await.unwrap(); - amal_group.send_message(b"hello", &amal).await.unwrap(); + amal_group.sync().await.unwrap(); + amal_group.send_message(b"hello").await.unwrap(); let charlie_group = receive_group_invite(&charlie).await; let dave_group = receive_group_invite(&dave).await; let (amal_latest_message, bola_latest_message, charlie_latest_message, dave_latest_message) = tokio::join!( - get_latest_message(&amal_group, &amal), - get_latest_message(&bola_group, &bola), - get_latest_message(&charlie_group, &charlie), - get_latest_message(&dave_group, &dave) + get_latest_message(&amal_group), + get_latest_message(&bola_group), + get_latest_message(&charlie_group), + get_latest_message(&dave_group) ); let expected_latest_message = b"hello".to_vec(); @@ -2241,14 +2228,14 @@ pub(crate) mod tests { .unwrap(); // Add bola to the group amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); let bola_group = receive_group_invite(&bola).await; - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); assert!(bola_group - .add_members_by_inbox_id(&bola, vec![charlie.inbox_id()]) + .add_members_by_inbox_id(vec![charlie.inbox_id()]) .await .is_err(),); } @@ -2313,11 +2300,11 @@ pub(crate) mod tests { ClientBuilder::new_test_client(&wallet).await; clients.push(wallet.get_address()); } - amal_group.add_members(&amal, clients).await.unwrap(); + amal_group.add_members(clients).await.unwrap(); let bola_wallet = generate_local_wallet(); ClientBuilder::new_test_client(&bola_wallet).await; assert!(amal_group - .add_members_by_inbox_id(&amal, vec![bola_wallet.get_address()]) + .add_members_by_inbox_id(vec![bola_wallet.get_address()]) .await .is_err(),); } @@ -2330,10 +2317,10 @@ pub(crate) mod tests { // Create a group and verify it has the default group name let policy_set = Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()); - let amal_group: MlsGroup = amal + let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let group_mutable_metadata = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) @@ -2347,14 +2334,14 @@ pub(crate) mod tests { // Add bola to the group amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); let group_mutable_metadata = bola_group .mutable_metadata(bola_group.mls_provider().unwrap()) .unwrap(); @@ -2366,17 +2353,14 @@ pub(crate) mod tests { // Update group name amal_group - .update_group_name(&amal, "New Group Name 1".to_string()) + .update_group_name("New Group Name 1".to_string()) .await .unwrap(); - amal_group - .send_message("hello".as_bytes(), &amal) - .await - .unwrap(); + amal_group.send_message("hello".as_bytes()).await.unwrap(); // Verify amal group sees update - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let binding = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) .expect("msg"); @@ -2387,7 +2371,7 @@ pub(crate) mod tests { assert_eq!(amal_group_name, "New Group Name 1"); // Verify bola group sees update - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); let binding = bola_group .mutable_metadata(bola_group.mls_provider().unwrap()) .expect("msg"); @@ -2399,12 +2383,12 @@ pub(crate) mod tests { // Verify that bola can not update the group name since they are not the creator bola_group - .update_group_name(&bola, "New Group Name 2".to_string()) + .update_group_name("New Group Name 2".to_string()) .await .expect_err("expected err"); // Verify bola group does not see an update - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); let binding = bola_group .mutable_metadata(bola_group.mls_provider().unwrap()) .expect("msg"); @@ -2422,10 +2406,10 @@ pub(crate) mod tests { // Create a group and verify it has the default group name let policy_set = Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()); - let amal_group: MlsGroup = amal + let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let group_mutable_metadata = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) @@ -2438,12 +2422,12 @@ pub(crate) mod tests { // Update group name amal_group - .update_group_image_url_square(&amal, "a url".to_string()) + .update_group_image_url_square("a url".to_string()) .await .unwrap(); // Verify amal group sees update - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let binding = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) .expect("msg"); @@ -2461,10 +2445,10 @@ pub(crate) mod tests { // Create a group and verify it has the default group name let policy_set = Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()); - let amal_group: MlsGroup = amal + let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let group_mutable_metadata = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) @@ -2477,12 +2461,12 @@ pub(crate) mod tests { // Update group name amal_group - .update_group_pinned_frame_url(&amal, "a frame url".to_string()) + .update_group_pinned_frame_url("a frame url".to_string()) .await .unwrap(); // Verify amal group sees update - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let binding = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) .expect("msg"); @@ -2502,10 +2486,10 @@ pub(crate) mod tests { // Create a group and verify it has the default group name let policy_set = Some(PreconfiguredPolicies::AllMembers.to_policy_set()); - let amal_group: MlsGroup = amal + let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let group_mutable_metadata = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) @@ -2518,14 +2502,14 @@ pub(crate) mod tests { // Add bola to the group amal_group - .add_members(&amal, vec![bola_wallet.get_address()]) + .add_members(vec![bola_wallet.get_address()]) .await .unwrap(); bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); let group_mutable_metadata = bola_group .mutable_metadata(bola_group.mls_provider().unwrap()) .unwrap(); @@ -2537,12 +2521,12 @@ pub(crate) mod tests { // Update group name amal_group - .update_group_name(&amal, "New Group Name 1".to_string()) + .update_group_name("New Group Name 1".to_string()) .await .unwrap(); // Verify amal group sees update - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let binding = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) .unwrap(); @@ -2553,7 +2537,7 @@ pub(crate) mod tests { assert_eq!(amal_group_name, "New Group Name 1"); // Verify bola group sees update - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); let binding = bola_group .mutable_metadata(bola_group.mls_provider().unwrap()) .expect("msg"); @@ -2565,12 +2549,12 @@ pub(crate) mod tests { // Verify that bola CAN update the group name since everyone is admin for this group bola_group - .update_group_name(&bola, "New Group Name 2".to_string()) + .update_group_name("New Group Name 2".to_string()) .await .expect("non creator failed to udpate group name"); // Verify amal group sees an update - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let binding = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) .expect("msg"); @@ -2594,18 +2578,18 @@ pub(crate) mod tests { let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); // Add bola to the group amal_group - .add_members(&amal, vec![bola_wallet.get_address()]) + .add_members(vec![bola_wallet.get_address()]) .await .unwrap(); bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); // Verify Amal is the only admin and super admin let provider = amal_group.mls_provider().unwrap(); @@ -2620,20 +2604,20 @@ pub(crate) mod tests { bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); - let bola_group: &MlsGroup = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + let bola_group: &MlsGroup<_> = bola_groups.first().unwrap(); + bola_group.sync().await.unwrap(); bola_group - .add_members_by_inbox_id(&bola, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .expect_err("expected err"); // Add bola as an admin amal_group - .update_admin_list(&amal, UpdateAdminListType::Add, bola.inbox_id()) + .update_admin_list(UpdateAdminListType::Add, bola.inbox_id()) .await .unwrap(); - amal_group.sync(&amal).await.unwrap(); - bola_group.sync(&bola).await.unwrap(); + amal_group.sync().await.unwrap(); + bola_group.sync().await.unwrap(); assert_eq!( bola_group .admin_list(bola_group.mls_provider().unwrap()) @@ -2648,26 +2632,26 @@ pub(crate) mod tests { // Verify that bola can now add caro because they are an admin bola_group - .add_members_by_inbox_id(&bola, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); // Verify that bola can not remove amal as a super admin, because // Remove admin is super admin only permissions bola_group - .update_admin_list(&bola, UpdateAdminListType::RemoveSuper, amal.inbox_id()) + .update_admin_list(UpdateAdminListType::RemoveSuper, amal.inbox_id()) .await .expect_err("expected err"); // Now amal removes bola as an admin amal_group - .update_admin_list(&amal, UpdateAdminListType::Remove, bola.inbox_id()) + .update_admin_list(UpdateAdminListType::Remove, bola.inbox_id()) .await .unwrap(); - amal_group.sync(&amal).await.unwrap(); - bola_group.sync(&bola).await.unwrap(); + amal_group.sync().await.unwrap(); + bola_group.sync().await.unwrap(); assert_eq!( bola_group .admin_list(bola_group.mls_provider().unwrap()) @@ -2684,10 +2668,10 @@ pub(crate) mod tests { bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); - let bola_group: &MlsGroup = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + let bola_group: &MlsGroup<_> = bola_groups.first().unwrap(); + bola_group.sync().await.unwrap(); bola_group - .add_members_by_inbox_id(&bola, vec![charlie.inbox_id()]) + .add_members_by_inbox_id(vec![charlie.inbox_id()]) .await .expect_err("expected err"); } @@ -2703,18 +2687,18 @@ pub(crate) mod tests { let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); // Add bola to the group amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); // Verify Amal is the only super admin let provider = amal_group.mls_provider().unwrap(); @@ -2729,20 +2713,20 @@ pub(crate) mod tests { bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); - let bola_group: &MlsGroup = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + let bola_group: &MlsGroup<_> = bola_groups.first().unwrap(); + bola_group.sync().await.unwrap(); bola_group - .update_admin_list(&bola, UpdateAdminListType::Add, caro.inbox_id()) + .update_admin_list(UpdateAdminListType::Add, caro.inbox_id()) .await .expect_err("expected err"); // Add bola as a super admin amal_group - .update_admin_list(&amal, UpdateAdminListType::AddSuper, bola.inbox_id()) + .update_admin_list(UpdateAdminListType::AddSuper, bola.inbox_id()) .await .unwrap(); - amal_group.sync(&amal).await.unwrap(); - bola_group.sync(&bola).await.unwrap(); + amal_group.sync().await.unwrap(); + bola_group.sync().await.unwrap(); let provider = bola_group.mls_provider().unwrap(); assert_eq!(bola_group.super_admin_list(&provider).unwrap().len(), 2); assert!(bola_group @@ -2753,10 +2737,10 @@ pub(crate) mod tests { // Verify that bola can now add caro as an admin bola_group - .update_admin_list(&bola, UpdateAdminListType::Add, caro.inbox_id()) + .update_admin_list(UpdateAdminListType::Add, caro.inbox_id()) .await .unwrap(); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); let provider = bola_group.mls_provider().unwrap(); assert_eq!(bola_group.admin_list(&provider).unwrap().len(), 1); assert!(bola_group @@ -2767,16 +2751,16 @@ pub(crate) mod tests { // Verify that no one can remove a super admin from a group amal_group - .remove_members(&amal, vec![bola.inbox_id()]) + .remove_members(vec![bola.inbox_id()]) .await .expect_err("expected err"); // Verify that bola can now remove themself as a super admin bola_group - .update_admin_list(&bola, UpdateAdminListType::RemoveSuper, bola.inbox_id()) + .update_admin_list(UpdateAdminListType::RemoveSuper, bola.inbox_id()) .await .unwrap(); - bola_group.sync(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); let provider = bola_group.mls_provider().unwrap(); assert_eq!(bola_group.super_admin_list(&provider).unwrap().len(), 1); assert!(!bola_group @@ -2787,7 +2771,7 @@ pub(crate) mod tests { // Verify that amal can NOT remove themself as a super admin because they are the only remaining amal_group - .update_admin_list(&amal, UpdateAdminListType::RemoveSuper, amal.inbox_id()) + .update_admin_list(UpdateAdminListType::RemoveSuper, amal.inbox_id()) .await .expect_err("expected err"); } @@ -2803,17 +2787,17 @@ pub(crate) mod tests { let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); // Add Bola and Caro to the group amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id(), caro.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id(), caro.inbox_id()]) .await .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); // Initial checks for group members - let initial_members = amal_group.members(&amal).await.unwrap(); + let initial_members = amal_group.members().await.unwrap(); let mut count_member = 0; let mut count_admin = 0; let mut count_super_admin = 0; @@ -2835,13 +2819,13 @@ pub(crate) mod tests { // Add Bola as an admin amal_group - .update_admin_list(&amal, UpdateAdminListType::Add, bola.inbox_id()) + .update_admin_list(UpdateAdminListType::Add, bola.inbox_id()) .await .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); // Check after adding Bola as an admin - let members = amal_group.members(&amal).await.unwrap(); + let members = amal_group.members().await.unwrap(); let mut count_member = 0; let mut count_admin = 0; let mut count_super_admin = 0; @@ -2863,13 +2847,13 @@ pub(crate) mod tests { // Add Caro as a super admin amal_group - .update_admin_list(&amal, UpdateAdminListType::AddSuper, caro.inbox_id()) + .update_admin_list(UpdateAdminListType::AddSuper, caro.inbox_id()) .await .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); // Check after adding Caro as a super admin - let members = amal_group.members(&amal).await.unwrap(); + let members = amal_group.members().await.unwrap(); let mut count_member = 0; let mut count_admin = 0; let mut count_super_admin = 0; @@ -2904,7 +2888,7 @@ pub(crate) mod tests { // Amal adds Bola to the group amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); @@ -2939,7 +2923,7 @@ pub(crate) mod tests { let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let mutable_metadata = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) @@ -2967,25 +2951,25 @@ pub(crate) mod tests { let amal_group = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); // Step 2: Amal adds Bola to the group let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); // Step 3: Verify that Bola can update the group name, and amal sees the update bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); - let bola_group: &MlsGroup = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + let bola_group: &MlsGroup<_> = bola_groups.first().unwrap(); + bola_group.sync().await.unwrap(); bola_group - .update_group_name(&bola, "Name Update 1".to_string()) + .update_group_name("Name Update 1".to_string()) .await .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); let name = amal_group .group_name(amal_group.mls_provider().unwrap()) .unwrap(); @@ -2993,20 +2977,20 @@ pub(crate) mod tests { // Step 4: Bola attempts an action that they do not have permissions for like add admin, fails as expected let result = bola_group - .update_admin_list(&bola, UpdateAdminListType::Add, bola.inbox_id()) + .update_admin_list(UpdateAdminListType::Add, bola.inbox_id()) .await; if let Err(e) = &result { eprintln!("Error updating admin list: {:?}", e); } // Step 5: Now have Bola attempt to update the group name again bola_group - .update_group_name(&bola, "Name Update 2".to_string()) + .update_group_name("Name Update 2".to_string()) .await .unwrap(); // Step 6: Verify that both clients can sync without error and that the group name has been updated - amal_group.sync(&amal).await.unwrap(); - bola_group.sync(&bola).await.unwrap(); + amal_group.sync().await.unwrap(); + bola_group.sync().await.unwrap(); let binding = amal_group .mutable_metadata(amal_group.mls_provider().unwrap()) .expect("msg"); @@ -3030,14 +3014,14 @@ pub(crate) mod tests { async fn test_can_update_permissions_after_group_creation() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let policy_set = Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()); - let amal_group: MlsGroup = amal + let amal_group: MlsGroup<_> = amal .create_group(policy_set, GroupMetadataOptions::default()) .unwrap(); // Step 2: Amal adds Bola to the group let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); @@ -3045,10 +3029,10 @@ pub(crate) mod tests { let caro = ClientBuilder::new_test_client(&generate_local_wallet()).await; bola.sync_welcomes().await.unwrap(); let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); - let bola_group: &MlsGroup = bola_groups.first().unwrap(); - bola_group.sync(&bola).await.unwrap(); + let bola_group: &MlsGroup<_> = bola_groups.first().unwrap(); + bola_group.sync().await.unwrap(); let result = bola_group - .add_members_by_inbox_id(&bola, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await; if let Err(e) = &result { eprintln!("Error adding member: {:?}", e); @@ -3059,7 +3043,6 @@ pub(crate) mod tests { // Step 4: Bola attempts to update permissions but fails because they are not a super admin let result = bola_group .update_permission_policy( - &bola, PermissionUpdateType::AddMember, PermissionPolicyOption::Allow, None, @@ -3074,7 +3057,6 @@ pub(crate) mod tests { // Step 5: Amal updates group permissions so that all members can add amal_group .update_permission_policy( - &amal, PermissionUpdateType::AddMember, PermissionPolicyOption::Allow, None, @@ -3084,11 +3066,11 @@ pub(crate) mod tests { // Step 6: Bola can now add Caro to the group bola_group - .add_members_by_inbox_id(&bola, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); - bola_group.sync(&bola).await.unwrap(); - let members = bola_group.members(&bola).await.unwrap(); + bola_group.sync().await.unwrap(); + let members = bola_group.members().await.unwrap(); assert_eq!(members.len(), 3); } @@ -3101,10 +3083,10 @@ pub(crate) mod tests { let amal_group = amal .create_group(None, GroupMetadataOptions::default()) .unwrap(); - amal_group.sync(&amal).await.unwrap(); + amal_group.sync().await.unwrap(); // Add bola to the group amal_group - .add_members(&amal, vec![bola_wallet.get_address()]) + .add_members(vec![bola_wallet.get_address()]) .await .unwrap(); let bola_group = receive_group_invite(&bola).await; @@ -3160,8 +3142,8 @@ pub(crate) mod tests { ] ); - amal_group.publish_messages(&amal).await.unwrap(); - bola_group.sync(&bola).await.unwrap(); + amal_group.publish_messages().await.unwrap(); + bola_group.sync().await.unwrap(); let messages = bola_group .find_messages(None, None, None, None, None) @@ -3190,21 +3172,19 @@ pub(crate) mod tests { let caro = ClientBuilder::new_test_client(&generate_local_wallet()).await; // Amal creates a dm group targetting bola - let amal_dm: MlsGroup = amal.create_dm_by_inbox_id(bola.inbox_id()).await.unwrap(); + let amal_dm = amal.create_dm_by_inbox_id(bola.inbox_id()).await.unwrap(); // Amal can not add caro to the dm group - let result = amal_dm - .add_members_by_inbox_id(&amal, vec![caro.inbox_id()]) - .await; + let result = amal_dm.add_members_by_inbox_id(vec![caro.inbox_id()]).await; assert!(result.is_err()); // Bola is already a member let result = amal_dm - .add_members_by_inbox_id(&amal, vec![bola.inbox_id(), caro.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id(), caro.inbox_id()]) .await; assert!(result.is_err()); - amal_dm.sync(&amal).await.unwrap(); - let members = amal_dm.members(&amal).await.unwrap(); + amal_dm.sync().await.unwrap(); + let members = amal_dm.members().await.unwrap(); assert_eq!(members.len(), 2); // Bola can message amal @@ -3215,11 +3195,11 @@ pub(crate) mod tests { ..FindGroupParams::default() }) .unwrap(); - let bola_dm: &MlsGroup = bola_groups.first().unwrap(); - bola_dm.send_message(b"test one", &bola).await.unwrap(); + let bola_dm: &MlsGroup<_> = bola_groups.first().unwrap(); + bola_dm.send_message(b"test one").await.unwrap(); // Amal sync and reads message - amal_dm.sync(&amal).await.unwrap(); + amal_dm.sync().await.unwrap(); let messages = amal_dm.find_messages(None, None, None, None, None).unwrap(); assert_eq!(messages.len(), 2); let message = messages.last().unwrap(); @@ -3227,16 +3207,16 @@ pub(crate) mod tests { // Amal can not remove bola let result = amal_dm - .remove_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .remove_members_by_inbox_id(vec![bola.inbox_id()]) .await; assert!(result.is_err()); - amal_dm.sync(&amal).await.unwrap(); - let members = amal_dm.members(&amal).await.unwrap(); + amal_dm.sync().await.unwrap(); + let members = amal_dm.members().await.unwrap(); assert_eq!(members.len(), 2); // Neither Amal nor Bola is an admin or super admin - amal_dm.sync(&amal).await.unwrap(); - bola_dm.sync(&bola).await.unwrap(); + amal_dm.sync().await.unwrap(); + bola_dm.sync().await.unwrap(); let is_amal_admin = amal_dm .is_admin(amal.inbox_id(), amal.mls_provider().unwrap()) .unwrap(); @@ -3266,17 +3246,17 @@ pub(crate) mod tests { .unwrap(); alix_group - .add_members_by_inbox_id(&alix, vec![bo.inbox_id()]) + .add_members_by_inbox_id(vec![bo.inbox_id()]) .await .unwrap(); // Create two commits alix_group - .update_group_name(&alix, "foo".to_string()) + .update_group_name("foo".to_string()) .await .unwrap(); alix_group - .update_group_name(&alix, "bar".to_string()) + .update_group_name("bar".to_string()) .await .unwrap(); @@ -3297,7 +3277,7 @@ pub(crate) mod tests { }) .unwrap(); - let process_result = bo_group.process_messages(bo_messages, &conn_1, &bo).await; + let process_result = bo_group.process_messages(bo_messages, &conn_1).await; if let Some(GroupError::ReceiveErrors(errors)) = process_result.err() { assert_eq!(errors.len(), 1); assert!(errors @@ -3327,10 +3307,9 @@ pub(crate) mod tests { let sync_tasks: Vec<_> = (0..10) .map(|_| { let group_clone = alix1_group.clone(); - let client_clone = alix1.clone(); // Each of these syncs is going to trigger the client to invite alix2 to the group // because of the race - crate::spawn(None, async move { group_clone.sync(&client_clone).await }).join() + crate::spawn(None, async move { group_clone.sync().await }).join() }) .collect(); @@ -3361,18 +3340,18 @@ pub(crate) mod tests { // Send a message from alix1 alix1_group - .send_message("hi from alix1".as_bytes(), &alix1) + .send_message("hi from alix1".as_bytes()) .await .unwrap(); // Send a message from alix2 alix2_group - .send_message("hi from alix2".as_bytes(), &alix2) + .send_message("hi from alix2".as_bytes()) .await .unwrap(); // Sync both clients - alix1_group.sync(&alix1).await.unwrap(); - alix2_group.sync(&alix2).await.unwrap(); + alix1_group.sync().await.unwrap(); + alix2_group.sync().await.unwrap(); let alix1_messages = alix1_group .find_messages(None, None, None, None, None) @@ -3392,9 +3371,8 @@ pub(crate) mod tests { // Create a membership update intent, but don't sync it yet async fn create_membership_update_no_sync( - group: &MlsGroup, + group: &MlsGroup, provider: &XmtpOpenMlsProvider, - client: impl ScopedGroupClient, ) { let intent_data = group .get_membership_update_intent(provider, vec![], vec![]) @@ -3440,28 +3418,22 @@ pub(crate) mod tests { // We are going to run add_missing_installations TWICE // which will create two intents to add the installations - create_membership_update_no_sync(&alix1_group, &alix1_provider, &alix1).await; - create_membership_update_no_sync(&alix1_group, &alix1_provider, &alix1).await; + create_membership_update_no_sync(&alix1_group, &alix1_provider).await; + create_membership_update_no_sync(&alix1_group, &alix1_provider).await; // Now I am going to run publish intents multiple times alix1_group - .publish_intents(&alix1_provider, &alix1) + .publish_intents(&alix1_provider) .await .expect("Expect publish to be OK"); alix1_group - .publish_intents(&alix1_provider, &alix1) + .publish_intents(&alix1_provider) .await .expect("Expected publish to be OK"); // Now I am going to sync twice - alix1_group - .sync_with_conn(&alix1_provider, &alix1) - .await - .unwrap(); - alix1_group - .sync_with_conn(&alix1_provider, &alix1) - .await - .unwrap(); + alix1_group.sync_with_conn(&alix1_provider).await.unwrap(); + alix1_group.sync_with_conn(&alix1_provider).await.unwrap(); // Make sure that only one welcome was sent let alix2_welcomes = alix1 @@ -3484,18 +3456,18 @@ pub(crate) mod tests { // Send a message from alix1 alix1_group - .send_message("hi from alix1".as_bytes(), &alix1) + .send_message("hi from alix1".as_bytes()) .await .unwrap(); // Send a message from alix2 alix2_group - .send_message("hi from alix2".as_bytes(), &alix2) + .send_message("hi from alix2".as_bytes()) .await .unwrap(); // Sync both clients - alix1_group.sync(&alix1).await.unwrap(); - alix2_group.sync(&alix2).await.unwrap(); + alix1_group.sync().await.unwrap(); + alix2_group.sync().await.unwrap(); let alix1_messages = alix1_group .find_messages(None, None, None, None, None) @@ -3529,7 +3501,7 @@ pub(crate) mod tests { let _client_2 = ClientBuilder::new_test_client(&wallet).await; // Sync the group to get the message adding client_2 published to the network - group.sync(&client).await.unwrap(); + group.sync().await.unwrap(); // Retrieve the envelope for the commit from the network let messages = client @@ -3548,13 +3520,7 @@ pub(crate) mod tests { let provider = client.mls_provider().unwrap(); let mut openmls_group = group.load_mls_group(&provider).unwrap(); let process_result = group - .process_message( - &client, - &mut openmls_group, - &provider, - &first_message, - false, - ) + .process_message(&mut openmls_group, &provider, &first_message, false) .await; assert_err!( @@ -3582,7 +3548,7 @@ pub(crate) mod tests { assert_eq!(alix_group.consent_state().unwrap(), ConsentState::Denied); alix_group - .add_members_by_inbox_id(&alix, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); @@ -3593,7 +3559,7 @@ pub(crate) mod tests { assert_eq!(bola_group.consent_state().unwrap(), ConsentState::Unknown); bola_group - .send_message("hi from bola".as_bytes(), &bola) + .send_message("hi from bola".as_bytes()) .await .unwrap(); @@ -3601,7 +3567,7 @@ pub(crate) mod tests { assert_eq!(bola_group.consent_state().unwrap(), ConsentState::Allowed); alix_group - .add_members_by_inbox_id(&alix, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); @@ -3613,7 +3579,7 @@ pub(crate) mod tests { .send_message_optimistic("hi from caro".as_bytes()) .unwrap(); - caro_group.publish_messages(&caro).await.unwrap(); + caro_group.publish_messages().await.unwrap(); // group consent state should be allowed if user publishes a message to the group assert_eq!(caro_group.consent_state().unwrap(), ConsentState::Allowed); @@ -3628,8 +3594,8 @@ pub(crate) mod tests { let dm_target_inbox_id = added_by_inbox.to_string(); // Test case 1: Valid DM group - let valid_dm_group = MlsGroup::create_test_dm_group( - client.context.clone(), + let valid_dm_group = MlsGroup::::create_test_dm_group( + client.clone().into(), dm_target_inbox_id.clone(), None, None, @@ -3650,8 +3616,8 @@ pub(crate) mod tests { let invalid_protected_metadata = build_protected_metadata_extension(creator_inbox_id.clone(), Purpose::Conversation) .unwrap(); - let invalid_type_group = MlsGroup::create_test_dm_group( - client.context.clone(), + let invalid_type_group = MlsGroup::::create_test_dm_group( + client.clone().into(), dm_target_inbox_id.clone(), Some(invalid_protected_metadata), None, @@ -3673,8 +3639,8 @@ pub(crate) mod tests { "wrong_inbox_id".to_string(), ) .unwrap(); - let mismatched_dm_members_group = MlsGroup::create_test_dm_group( - client.context.clone(), + let mismatched_dm_members_group = MlsGroup::::create_test_dm_group( + client.clone().into(), dm_target_inbox_id.clone(), Some(mismatched_dm_members), None, @@ -3693,8 +3659,8 @@ pub(crate) mod tests { GroupMetadataOptions::default(), ) .unwrap(); - let non_empty_admin_list_group = MlsGroup::create_test_dm_group( - client.context.clone(), + let non_empty_admin_list_group = MlsGroup::::create_test_dm_group( + client.clone().into(), dm_target_inbox_id.clone(), None, Some(non_empty_admin_list), @@ -3712,8 +3678,8 @@ pub(crate) mod tests { // Test case 7: Invalid permissions let invalid_permissions = PolicySet::default(); - let invalid_permissions_group = MlsGroup::create_test_dm_group( - client.context.clone(), + let invalid_permissions_group = MlsGroup::::create_test_dm_group( + client.clone().into(), dm_target_inbox_id.clone(), None, None, diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index b7e8372e3..61df81c5e 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -257,14 +257,11 @@ pub(crate) mod tests { .unwrap(); // Add bola amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); - amal_group - .send_message("hello".as_bytes(), &amal) - .await - .unwrap(); + amal_group.send_message("hello".as_bytes()).await.unwrap(); let messages = amal .api_client .query_group_messages(amal_group.clone().group_id, None) @@ -274,7 +271,7 @@ pub(crate) mod tests { let mut message_bytes: Vec = Vec::new(); message.encode(&mut message_bytes).unwrap(); let message_again = amal_group - .process_streamed_group_message(message_bytes, &amal) + .process_streamed_group_message(message_bytes) .await; if let Ok(message) = message_again { @@ -298,7 +295,7 @@ pub(crate) mod tests { .unwrap(); // Add bola amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); @@ -306,14 +303,13 @@ pub(crate) mod tests { let bola_groups = bola.sync_welcomes().await.unwrap(); let bola_group = Arc::new(bola_groups.first().unwrap().clone()); - let bola_ptr = bola.clone(); let bola_group_ptr = bola_group.clone(); let notify = Delivery::new(Some(Duration::from_secs(10))); let notify_ptr = notify.clone(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let mut stream = UnboundedReceiverStream::new(rx); crate::spawn(None, async move { - let stream = bola_group_ptr.stream(&bola_ptr).await.unwrap(); + let stream = bola_group_ptr.stream().await.unwrap(); futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); @@ -321,10 +317,7 @@ pub(crate) mod tests { } }); - amal_group - .send_message("hello".as_bytes(), &amal) - .await - .unwrap(); + amal_group.send_message("hello".as_bytes()).await.unwrap(); notify .wait_for_delivery() .await @@ -332,10 +325,7 @@ pub(crate) mod tests { let first_val = stream.next().await.unwrap(); assert_eq!(first_val.decrypted_message_bytes, "hello".as_bytes()); - amal_group - .send_message("goodbye".as_bytes(), &amal) - .await - .unwrap(); + amal_group.send_message("goodbye".as_bytes()).await.unwrap(); notify .wait_for_delivery() @@ -359,10 +349,9 @@ pub(crate) mod tests { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); - let amal_ptr = amal.clone(); let group_ptr = group.clone(); crate::spawn(None, async move { - let stream = group_ptr.stream(&amal_ptr).await.unwrap(); + let stream = group_ptr.stream().await.unwrap(); futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); @@ -371,7 +360,7 @@ pub(crate) mod tests { for i in 0..10 { group - .send_message(format!("hello {}", i).as_bytes(), &amal) + .send_message(format!("hello {}", i).as_bytes()) .await .unwrap(); } @@ -400,7 +389,6 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); - let amal_ptr = amal.clone(); let amal_group_ptr = amal_group.clone(); let notify = Delivery::new(Some(Duration::from_secs(20))); let notify_ptr = notify.clone(); @@ -409,7 +397,7 @@ pub(crate) mod tests { let (start_tx, start_rx) = tokio::sync::oneshot::channel(); let mut stream = UnboundedReceiverStream::new(rx); crate::spawn(None, async move { - let stream = amal_group_ptr.stream(&amal_ptr).await.unwrap(); + let stream = amal_group_ptr.stream().await.unwrap(); let _ = start_tx.send(()); futures::pin_mut!(stream); while let Some(item) = stream.next().await { @@ -423,7 +411,7 @@ pub(crate) mod tests { crate::sleep(core::time::Duration::from_millis(100)).await; amal_group - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) + .add_members_by_inbox_id(vec![bola.inbox_id()]) .await .unwrap(); notify @@ -433,10 +421,7 @@ pub(crate) mod tests { let first_val = stream.next().await.unwrap(); assert_eq!(first_val.kind, GroupMessageKind::MembershipChange); - amal_group - .send_message("hello".as_bytes(), &amal) - .await - .unwrap(); + amal_group.send_message("hello".as_bytes()).await.unwrap(); notify .wait_for_delivery() .await diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index c19fb7d29..6eac793ab 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -1256,7 +1256,7 @@ pub(crate) mod tests { async fn publish_intents_worst_case_scenario() { let wallet = generate_local_wallet(); let amal = Arc::new(ClientBuilder::new_test_client(&wallet).await); - let amal_group: Arc = + let amal_group: Arc> = Arc::new(amal.create_group(None, Default::default()).unwrap()); amal_group.send_message_optimistic(b"1").unwrap(); @@ -1271,7 +1271,7 @@ pub(crate) mod tests { let mut futures = vec![]; for _ in 0..10 { - futures.push(amal_group.publish_intents(&provider, &amal)) + futures.push(amal_group.publish_intents(&provider)) } future::join_all(futures).await; } diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index 605c3e4e2..65fb49022 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -503,6 +503,7 @@ pub(crate) mod tests { builder::SignatureRequest, test_utils::add_wallet_signature, AssociationState, MemberIdentifier, }, + scw_verifier::SmartContractSignatureVerifier, InboxOwner, }; @@ -510,18 +511,19 @@ pub(crate) mod tests { builder::ClientBuilder, groups::group_membership::GroupMembership, storage::{db_connection::DbConnection, identity_update::StoredIdentityUpdate}, - utils::test::rand_vec, + utils::test::{rand_vec, FullXmtpClient}, Client, XmtpApi, }; use super::load_identity_updates; - async fn get_association_state( - client: &Client, + async fn get_association_state( + client: &Client, inbox_id: String, ) -> AssociationState where - ApiClient: XmtpApi, + ApiClient: XmtpApi + Clone, + Verifier: SmartContractSignatureVerifier + Clone, { let conn = client.store().conn().unwrap(); load_identity_updates(&client.api_client, &conn, vec![inbox_id.clone()]) @@ -674,7 +676,7 @@ pub(crate) mod tests { let filtered = // Inbox 1 is requesting an inbox ID higher than what is in the DB. Inbox 2 is requesting one that matches the DB. // Inbox 3 is requesting one lower than what is in the DB - client.filter_inbox_ids_needing_updates(&conn, vec![("inbox_1", 3), ("inbox_2", 2), ("inbox_3", 2)]); + conn.filter_inbox_ids_needing_updates(vec![("inbox_1", 3), ("inbox_2", 2), ("inbox_3", 2)]); assert_eq!(filtered.unwrap(), vec!["inbox_1"]); } @@ -848,8 +850,8 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] pub async fn revoke_installation() { let wallet = generate_local_wallet(); - let client1 = ClientBuilder::new_test_client(&wallet).await; - let client2 = ClientBuilder::new_test_client(&wallet).await; + let client1: FullXmtpClient = ClientBuilder::new_test_client(&wallet).await; + let client2: FullXmtpClient = ClientBuilder::new_test_client(&wallet).await; let association_state = get_association_state(&client1, client1.inbox_id()).await; // Ensure there are two installations on the inbox diff --git a/xmtp_mls/src/intents.rs b/xmtp_mls/src/intents.rs new file mode 100644 index 000000000..bd5c0b40a --- /dev/null +++ b/xmtp_mls/src/intents.rs @@ -0,0 +1,51 @@ +//! an "Intent" can be thought of as a commitment by a user to try and accomplish something +//! in a group chat. Examples of an Intent: +//! - Sending a message +//! - Adding a member +//! - Removing a member +//! Intents are written to local storage, before being published to the delivery service. An +//! intent is fully processed (success or failure) once it + +use std::{future::Future, sync::Arc}; + +use crate::{ + client::{MessageProcessingError, XmtpMlsLocalContext}, + storage::{refresh_state::EntityKind, EncryptedMessageStore}, + xmtp_openmls_provider::XmtpOpenMlsProvider, +}; + +/// Intents holding the context of this Client +pub struct Intents { + pub(crate) context: Arc, +} + +impl Intents { + pub(crate) fn store(&self) -> &EncryptedMessageStore { + self.context.store() + } + + pub(crate) async fn process_for_id( + &self, + entity_id: &Vec, + entity_kind: EntityKind, + cursor: u64, + process_envelope: ProcessingFn, + ) -> Result + where + Fut: Future>, + ProcessingFn: FnOnce(XmtpOpenMlsProvider) -> Fut, + { + self.store() + .transaction_async(|provider| async move { + let is_updated = + provider + .conn_ref() + .update_cursor(entity_id, entity_kind, cursor as i64)?; + if !is_updated { + return Err(MessageProcessingError::AlreadyProcessed(cursor)); + } + process_envelope(provider).await + }) + .await + } +} diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 3899eec03..8f34452ab 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -348,7 +348,7 @@ pub(crate) mod tests { client::FindGroupParams, groups::GroupMetadataOptions, storage::group_message::StoredGroupMessage, - utils::test::{Delivery, TestClient}, + utils::test::{Delivery, FullXmtpClient, TestClient}, Client, StreamHandle, }; use futures::StreamExt; @@ -387,7 +387,7 @@ pub(crate) mod tests { let group_id = alice_bob_group.group_id.clone(); alice_bob_group - .add_members_by_inbox_id(&alice, vec![bob.inbox_id()]) + .add_members_by_inbox_id(vec![bob.inbox_id()]) .await .unwrap(); @@ -410,7 +410,7 @@ pub(crate) mod tests { // let mut bob_stream = bob.stream_conversations().await.unwrap()warning: unused implementer of `futures::Future` that must be used; alice_group - .add_members_by_inbox_id(&alice, vec![bob.inbox_id()]) + .add_members_by_inbox_id(vec![bob.inbox_id()]) .await .unwrap(); let bob_group = bob.sync_welcomes().await.unwrap(); @@ -420,7 +420,7 @@ pub(crate) mod tests { let notify_ptr = notify.clone(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); crate::spawn(None, async move { - let stream = alice_group.stream(&alice).await.unwrap(); + let stream = alice_group.stream().await.unwrap(); futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); @@ -429,12 +429,12 @@ pub(crate) mod tests { }); let mut stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); - bob_group.send_message(b"hello", &bob).await.unwrap(); + bob_group.send_message(b"hello").await.unwrap(); notify.wait_for_delivery().await.unwrap(); let message = stream.next().await.unwrap(); assert_eq!(message.decrypted_message_bytes, b"hello"); - bob_group.send_message(b"hello2", &bob).await.unwrap(); + bob_group.send_message(b"hello2").await.unwrap(); notify.wait_for_delivery().await.unwrap(); let message = stream.next().await.unwrap(); assert_eq!(message.decrypted_message_bytes, b"hello2"); @@ -456,7 +456,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); alix_group - .add_members_by_inbox_id(&alix, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); @@ -464,7 +464,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); bo_group - .add_members_by_inbox_id(&bo, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); crate::sleep(core::time::Duration::from_millis(100)).await; @@ -474,7 +474,7 @@ pub(crate) mod tests { let notify = Delivery::new(None); let notify_pointer = notify.clone(); - let mut handle = Client::::stream_all_messages_with_callback( + let mut handle = Client::::stream_all_messages_with_callback( Arc::new(caro), move |message| { (*messages_clone.lock()).push(message); @@ -483,28 +483,16 @@ pub(crate) mod tests { ); handle.wait_for_ready().await; - alix_group - .send_message("first".as_bytes(), &alix) - .await - .unwrap(); + alix_group.send_message("first".as_bytes()).await.unwrap(); notify .wait_for_delivery() .await .expect("didn't get `first`"); - bo_group - .send_message("second".as_bytes(), &bo) - .await - .unwrap(); + bo_group.send_message("second".as_bytes()).await.unwrap(); notify.wait_for_delivery().await.unwrap(); - alix_group - .send_message("third".as_bytes(), &alix) - .await - .unwrap(); + alix_group.send_message("third".as_bytes()).await.unwrap(); notify.wait_for_delivery().await.unwrap(); - bo_group - .send_message("fourth".as_bytes(), &bo) - .await - .unwrap(); + bo_group.send_message("fourth".as_bytes()).await.unwrap(); notify.wait_for_delivery().await.unwrap(); let messages = messages.lock(); @@ -528,7 +516,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); alix_group - .add_members_by_inbox_id(&alix, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); @@ -536,17 +524,16 @@ pub(crate) mod tests { let messages_clone = messages.clone(); let delivery = Delivery::new(None); let delivery_pointer = delivery.clone(); - let mut handle = - Client::::stream_all_messages_with_callback(caro.clone(), move |message| { + let mut handle = Client::::stream_all_messages_with_callback( + caro.clone(), + move |message| { delivery_pointer.notify_one(); (*messages_clone.lock()).push(message); - }); + }, + ); handle.wait_for_ready().await; - alix_group - .send_message("first".as_bytes(), &alix) - .await - .unwrap(); + alix_group.send_message("first".as_bytes()).await.unwrap(); delivery .wait_for_delivery() .await @@ -556,23 +543,17 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); bo_group - .add_members_by_inbox_id(&bo, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); - bo_group - .send_message("second".as_bytes(), &bo) - .await - .unwrap(); + bo_group.send_message("second".as_bytes()).await.unwrap(); delivery .wait_for_delivery() .await .expect("timed out waiting for `second`"); - alix_group - .send_message("third".as_bytes(), &alix) - .await - .unwrap(); + alix_group.send_message("third".as_bytes()).await.unwrap(); delivery .wait_for_delivery() .await @@ -582,23 +563,17 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); alix_group_2 - .add_members_by_inbox_id(&alix, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); - alix_group - .send_message("fourth".as_bytes(), &alix) - .await - .unwrap(); + alix_group.send_message("fourth".as_bytes()).await.unwrap(); delivery .wait_for_delivery() .await .expect("timed out waiting for `fourth`"); - alix_group_2 - .send_message("fifth".as_bytes(), &alix) - .await - .unwrap(); + alix_group_2.send_message("fifth".as_bytes()).await.unwrap(); delivery .wait_for_delivery() .await @@ -615,7 +590,7 @@ pub(crate) mod tests { assert!(a.is_finished()); alix_group - .send_message("should not show up".as_bytes(), &alix) + .send_message("should not show up".as_bytes()) .await .unwrap(); crate::sleep(core::time::Duration::from_millis(100)).await; @@ -638,7 +613,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); alix_group - .add_members_by_inbox_id(&alix, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); @@ -648,21 +623,19 @@ pub(crate) mod tests { let blocked = Arc::new(AtomicU64::new(55)); let blocked_pointer = blocked.clone(); - let mut handle = - Client::::stream_all_messages_with_callback(caro.clone(), move |message| { + let mut handle = Client::::stream_all_messages_with_callback( + caro.clone(), + move |message| { (*messages_clone.lock()).push(message); blocked_pointer.fetch_sub(1, Ordering::SeqCst); - }); + }, + ); handle.wait_for_ready().await; let alix_group_pointer = alix_group.clone(); - let alix_pointer = alix.clone(); crate::spawn(None, async move { for _ in 0..50 { - alix_group_pointer - .send_message(b"spam", &alix_pointer) - .await - .unwrap(); + alix_group_pointer.send_message(b"spam").await.unwrap(); crate::sleep(core::time::Duration::from_micros(200)).await; } }); @@ -672,11 +645,11 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); new_group - .add_members_by_inbox_id(&alix, vec![caro.inbox_id()]) + .add_members_by_inbox_id(vec![caro.inbox_id()]) .await .unwrap(); new_group - .send_message(b"spam from new group", &alix) + .send_message(b"spam from new group") .await .unwrap(); } @@ -705,7 +678,7 @@ pub(crate) mod tests { let notify = Delivery::new(None); let (notify_pointer, groups_pointer) = (notify.clone(), groups.clone()); - let closer = Client::::stream_conversations_with_callback( + let closer = Client::::stream_conversations_with_callback( alix.clone(), move |g| { let mut groups = groups_pointer.lock(); @@ -732,7 +705,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); group - .add_members_by_inbox_id(&bo, vec![alix.inbox_id()]) + .add_members_by_inbox_id(vec![alix.inbox_id()]) .await .unwrap(); @@ -767,7 +740,7 @@ pub(crate) mod tests { let (notify_pointer, groups_pointer) = (notify.clone(), groups.clone()); // Start a stream with enableDm set to false - let closer = Client::::stream_conversations_with_callback( + let closer = Client::::stream_conversations_with_callback( alix.clone(), move |g| { let mut groups = groups_pointer.lock(); @@ -789,7 +762,7 @@ pub(crate) mod tests { // Wait for 2 seconds for the group creation to be streamed let notify = Delivery::new(Some(std::time::Duration::from_secs(60))); let (notify_pointer, groups_pointer) = (notify.clone(), groups.clone()); - let closer = Client::::stream_conversations_with_callback( + let closer = FullXmtpClient::stream_conversations_with_callback( alix.clone(), move |g| { let mut groups = groups_pointer.lock(); @@ -807,7 +780,7 @@ pub(crate) mod tests { } let dm = bo.create_dm_by_inbox_id(alix.inbox_id()).await.unwrap(); - dm.add_members_by_inbox_id(&bo, vec![alix.inbox_id()]) + dm.add_members_by_inbox_id(vec![alix.inbox_id()]) .await .unwrap(); notify.wait_for_delivery().await.unwrap(); diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index 44e462587..d831197a8 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -13,7 +13,7 @@ use xmtp_id::{ test_utils::MockSmartContractSignatureVerifier, unverified::{UnverifiedRecoverableEcdsaSignature, UnverifiedSignature}, }, - scw_verifier::MultiSmartContractSignatureVerifier, + scw_verifier::SmartContractSignatureVerifier, }; use crate::{ @@ -30,11 +30,10 @@ pub mod traced_test; #[cfg(not(target_arch = "wasm32"))] pub use traced_test::traced_test; -#[cfg(not(target_arch = "wasm32"))] -use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient; +pub type FullXmtpClient = Client; #[cfg(not(any(feature = "http-api", target_arch = "wasm32")))] -pub type TestClient = GrpcClient; +pub type TestClient = xmtp_api_grpc::grpc_api_helper::Client; #[cfg(any(feature = "http-api", target_arch = "wasm32"))] use xmtp_api_http::XmtpHttpApiClient; @@ -108,9 +107,7 @@ impl ClientBuilder { self.api_client(::create_local().await) } - pub async fn new_test_client( - owner: &impl InboxOwner, - ) -> Client { + pub async fn new_test_client(owner: &impl InboxOwner) -> FullXmtpClient { // crate::utils::wasm::init().await; let nonce = 1; let inbox_id = generate_inbox_id(&owner.get_address(), &nonce); @@ -126,6 +123,7 @@ impl ClientBuilder { .await .local_client() .await + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() .await .unwrap(); @@ -152,6 +150,7 @@ impl ClientBuilder { .temp_store() .await .api_client(dev_client) + .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() .await .unwrap(); @@ -187,7 +186,7 @@ impl Delivery { } } -impl Client { +impl FullXmtpClient { pub async fn is_registered(&self, address: &String) -> bool { let ids = self .api_client @@ -198,17 +197,17 @@ impl Client { } } -pub async fn register_client(client: &Client, owner: &impl InboxOwner) { +pub async fn register_client( + client: &Client, + owner: &impl InboxOwner, +) { let mut signature_request = client.context.signature_request().unwrap(); let signature_text = signature_request.signature_text(); let unverified_signature = UnverifiedSignature::RecoverableEcdsa( UnverifiedRecoverableEcdsaSignature::new(owner.sign(&signature_text).unwrap().into()), ); signature_request - .add_signature( - unverified_signature, - client.smart_contract_signature_verifier().as_ref(), - ) + .add_signature(unverified_signature, client.scw_verifier()) .await .unwrap(); From e9a75e9e543e5d4a5edd6ce3ae7e7542448d4dc8 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 10 Oct 2024 22:44:09 -0400 Subject: [PATCH 83/97] fix bindings_ffi --- bindings_ffi/Cargo.toml | 3 + bindings_ffi/src/mls.rs | 123 ++++++++++--------------- bindings_node/src/groups.rs | 109 ++++++++++------------ xmtp_api_http/src/util.rs | 6 +- xmtp_mls/Cargo.toml | 5 +- xmtp_mls/src/builder.rs | 10 +- xmtp_mls/src/groups/message_history.rs | 22 ++--- xmtp_mls/src/groups/mod.rs | 2 +- 8 files changed, 130 insertions(+), 150 deletions(-) diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index 5797871ac..c2dd3ff8e 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -37,3 +37,6 @@ tokio = { workspace = true, features = ["rt-multi-thread"] } uniffi = { version = "0.28.0", features = ["bindgen-tests"] } uuid = { workspace = true, features = ["v4", "fast-rng"] } xmtp_mls = { path = "../xmtp_mls", features = ["test-utils"] } +xmtp_proto = { path = "../xmtp_proto", features = ["test-utils"] } +xmtp_api_grpc = { path = "../xmtp_api_grpc", features = ["test-utils"] } + diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index fa5737b85..616736f2a 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -992,21 +992,19 @@ impl FfiCreateGroupOptions { impl FfiGroup { pub async fn send(&self, content_bytes: Vec) -> Result, GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - let message_id = group - .send_message(content_bytes.as_slice(), &self.inner_client) - .await?; + let message_id = group.send_message(content_bytes.as_slice()).await?; Ok(message_id) } /// send a message without immediately publishing to the delivery service. pub fn send_optimistic(&self, content_bytes: Vec) -> Result, GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1019,22 +1017,22 @@ impl FfiGroup { /// Publish all unpublished messages pub async fn publish_messages(&self) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group.publish_messages(&self.inner_client).await?; + group.publish_messages().await?; Ok(()) } pub async fn sync(&self) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group.sync(&self.inner_client).await?; + group.sync().await?; Ok(()) } @@ -1044,7 +1042,7 @@ impl FfiGroup { opts: FfiListMessagesOptions, ) -> Result, GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1071,13 +1069,11 @@ impl FfiGroup { envelope_bytes: Vec, ) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - let message = group - .process_streamed_group_message(envelope_bytes, &self.inner_client) - .await?; + let message = group.process_streamed_group_message(envelope_bytes).await?; let ffi_message = message.into(); Ok(ffi_message) @@ -1085,13 +1081,13 @@ impl FfiGroup { pub async fn list_members(&self) -> Result, GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); let members: Vec = group - .members(&self.inner_client) + .members() .await? .into_iter() .map(|member| FfiGroupMember { @@ -1114,14 +1110,12 @@ impl FfiGroup { log::info!("adding members: {}", account_addresses.join(",")); let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group - .add_members(&self.inner_client, account_addresses) - .await?; + group.add_members(account_addresses).await?; Ok(()) } @@ -1133,28 +1127,24 @@ impl FfiGroup { log::info!("adding members by inbox id: {}", inbox_ids.join(",")); let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group - .add_members_by_inbox_id(&self.inner_client, inbox_ids) - .await?; + group.add_members_by_inbox_id(inbox_ids).await?; Ok(()) } pub async fn remove_members(&self, account_addresses: Vec) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group - .remove_members(&self.inner_client, account_addresses) - .await?; + group.remove_members(account_addresses).await?; Ok(()) } @@ -1164,35 +1154,31 @@ impl FfiGroup { inbox_ids: Vec, ) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group - .remove_members_by_inbox_id(&self.inner_client, inbox_ids) - .await?; + group.remove_members_by_inbox_id(inbox_ids).await?; Ok(()) } pub async fn update_group_name(&self, group_name: String) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group - .update_group_name(&self.inner_client, group_name) - .await?; + group.update_group_name(group_name).await?; Ok(()) } pub fn group_name(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1208,13 +1194,13 @@ impl FfiGroup { group_image_url_square: String, ) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_image_url_square(&self.inner_client, group_image_url_square) + .update_group_image_url_square(group_image_url_square) .await?; Ok(()) @@ -1222,7 +1208,7 @@ impl FfiGroup { pub fn group_image_url_square(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1237,21 +1223,19 @@ impl FfiGroup { group_description: String, ) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group - .update_group_description(&self.inner_client, group_description) - .await?; + group.update_group_description(group_description).await?; Ok(()) } pub fn group_description(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1266,13 +1250,13 @@ impl FfiGroup { pinned_frame_url: String, ) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_pinned_frame_url(&self.inner_client, pinned_frame_url) + .update_group_pinned_frame_url(pinned_frame_url) .await?; Ok(()) @@ -1280,7 +1264,7 @@ impl FfiGroup { pub fn group_pinned_frame_url(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1292,7 +1276,7 @@ impl FfiGroup { pub fn admin_list(&self) -> Result, GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1304,7 +1288,7 @@ impl FfiGroup { pub fn super_admin_list(&self) -> Result, GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1326,12 +1310,12 @@ impl FfiGroup { pub async fn add_admin(&self, inbox_id: String) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::Add, inbox_id) + .update_admin_list(UpdateAdminListType::Add, inbox_id) .await?; Ok(()) @@ -1339,12 +1323,12 @@ impl FfiGroup { pub async fn remove_admin(&self, inbox_id: String) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::Remove, inbox_id) + .update_admin_list(UpdateAdminListType::Remove, inbox_id) .await?; Ok(()) @@ -1352,12 +1336,12 @@ impl FfiGroup { pub async fn add_super_admin(&self, inbox_id: String) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::AddSuper, inbox_id) + .update_admin_list(UpdateAdminListType::AddSuper, inbox_id) .await?; Ok(()) @@ -1365,16 +1349,12 @@ impl FfiGroup { pub async fn remove_super_admin(&self, inbox_id: String) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list( - &self.inner_client, - UpdateAdminListType::RemoveSuper, - inbox_id, - ) + .update_admin_list(UpdateAdminListType::RemoveSuper, inbox_id) .await?; Ok(()) @@ -1382,7 +1362,7 @@ impl FfiGroup { pub fn group_permissions(&self) -> Result, GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1400,13 +1380,12 @@ impl FfiGroup { metadata_field: Option, ) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group .update_permission_policy( - &self.inner_client, PermissionUpdateType::from(&permission_update_type), permission_policy_option.try_into()?, metadata_field.map(|field| MetadataField::from(&field)), @@ -1434,7 +1413,7 @@ impl FfiGroup { pub fn is_active(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1444,7 +1423,7 @@ impl FfiGroup { pub fn consent_state(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1456,7 +1435,7 @@ impl FfiGroup { pub fn update_consent_state(&self, state: FfiConsentState) -> Result<(), GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1468,7 +1447,7 @@ impl FfiGroup { pub fn added_by_inbox_id(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1478,7 +1457,7 @@ impl FfiGroup { pub fn group_metadata(&self) -> Result, GenericError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -1895,12 +1874,12 @@ mod tests { #[cfg(test)] async fn update_installations(&self) -> Result<(), GroupError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group.update_installations(&self.inner_client).await?; + group.update_installations().await?; Ok(()) } } diff --git a/bindings_node/src/groups.rs b/bindings_node/src/groups.rs index b025bb36d..5cf74247f 100644 --- a/bindings_node/src/groups.rs +++ b/bindings_node/src/groups.rs @@ -91,16 +91,13 @@ impl NapiGroup { pub async fn send(&self, encoded_content: NapiEncodedContent) -> Result { let encoded_content: EncodedContent = encoded_content.into(); let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); let message_id = group - .send_message( - encoded_content.encode_to_vec().as_slice(), - &self.inner_client, - ) + .send_message(encoded_content.encode_to_vec().as_slice()) .await .map_err(ErrorWrapper::from)?; Ok(hex::encode(message_id.clone())) @@ -111,7 +108,7 @@ impl NapiGroup { pub fn send_optimistic(&self, encoded_content: NapiEncodedContent) -> Result { let encoded_content: EncodedContent = encoded_content.into(); let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -127,29 +124,23 @@ impl NapiGroup { #[napi] pub async fn publish_messages(&self) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group - .publish_messages(&self.inner_client) - .await - .map_err(ErrorWrapper::from)?; + group.publish_messages().await.map_err(ErrorWrapper::from)?; Ok(()) } #[napi] pub async fn sync(&self) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); - group - .sync(&self.inner_client) - .await - .map_err(ErrorWrapper::from)?; + group.sync().await.map_err(ErrorWrapper::from)?; Ok(()) } @@ -167,7 +158,7 @@ impl NapiGroup { }; let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -196,13 +187,13 @@ impl NapiGroup { envelope_bytes: Uint8Array, ) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); let envelope_bytes: Vec = envelope_bytes.deref().to_vec(); let message = group - .process_streamed_group_message(envelope_bytes, &self.inner_client) + .process_streamed_group_message(envelope_bytes) .await .map_err(ErrorWrapper::from)?; @@ -212,13 +203,13 @@ impl NapiGroup { #[napi] pub async fn list_members(&self) -> Result> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); let members: Vec = group - .members(&self.inner_client) + .members() .await .map_err(ErrorWrapper::from)? .into_iter() @@ -245,7 +236,7 @@ impl NapiGroup { #[napi] pub fn admin_list(&self) -> Result> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -260,7 +251,7 @@ impl NapiGroup { #[napi] pub fn super_admin_list(&self) -> Result> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -287,13 +278,13 @@ impl NapiGroup { #[napi] pub async fn add_members(&self, account_addresses: Vec) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .add_members(&self.inner_client, account_addresses) + .add_members(account_addresses) .await .map_err(ErrorWrapper::from)?; @@ -303,12 +294,12 @@ impl NapiGroup { #[napi] pub async fn add_admin(&self, inbox_id: String) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::Add, inbox_id) + .update_admin_list(UpdateAdminListType::Add, inbox_id) .await .map_err(ErrorWrapper::from)?; @@ -318,12 +309,12 @@ impl NapiGroup { #[napi] pub async fn remove_admin(&self, inbox_id: String) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::Remove, inbox_id) + .update_admin_list(UpdateAdminListType::Remove, inbox_id) .await .map_err(ErrorWrapper::from)?; @@ -333,12 +324,12 @@ impl NapiGroup { #[napi] pub async fn add_super_admin(&self, inbox_id: String) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::AddSuper, inbox_id) + .update_admin_list(UpdateAdminListType::AddSuper, inbox_id) .await .map_err(ErrorWrapper::from)?; @@ -348,16 +339,12 @@ impl NapiGroup { #[napi] pub async fn remove_super_admin(&self, inbox_id: String) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list( - &self.inner_client, - UpdateAdminListType::RemoveSuper, - inbox_id, - ) + .update_admin_list(UpdateAdminListType::RemoveSuper, inbox_id) .await .map_err(ErrorWrapper::from)?; @@ -367,7 +354,7 @@ impl NapiGroup { #[napi] pub fn group_permissions(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -380,13 +367,13 @@ impl NapiGroup { #[napi] pub async fn add_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .add_members_by_inbox_id(&self.inner_client, inbox_ids) + .add_members_by_inbox_id(inbox_ids) .await .map_err(ErrorWrapper::from)?; @@ -396,13 +383,13 @@ impl NapiGroup { #[napi] pub async fn remove_members(&self, account_addresses: Vec) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .remove_members(&self.inner_client, account_addresses) + .remove_members(account_addresses) .await .map_err(ErrorWrapper::from)?; @@ -412,13 +399,13 @@ impl NapiGroup { #[napi] pub async fn remove_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .remove_members_by_inbox_id(&self.inner_client, inbox_ids) + .remove_members_by_inbox_id(inbox_ids) .await .map_err(ErrorWrapper::from)?; @@ -428,13 +415,13 @@ impl NapiGroup { #[napi] pub async fn update_group_name(&self, group_name: String) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_name(&self.inner_client, group_name) + .update_group_name(group_name) .await .map_err(ErrorWrapper::from)?; @@ -444,7 +431,7 @@ impl NapiGroup { #[napi] pub fn group_name(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -459,13 +446,13 @@ impl NapiGroup { #[napi] pub async fn update_group_image_url_square(&self, group_image_url_square: String) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_image_url_square(&self.inner_client, group_image_url_square) + .update_group_image_url_square(group_image_url_square) .await .map_err(ErrorWrapper::from)?; @@ -475,7 +462,7 @@ impl NapiGroup { #[napi] pub fn group_image_url_square(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -490,13 +477,13 @@ impl NapiGroup { #[napi] pub async fn update_group_description(&self, group_description: String) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_description(&self.inner_client, group_description) + .update_group_description(group_description) .await .map_err(ErrorWrapper::from)?; @@ -506,7 +493,7 @@ impl NapiGroup { #[napi] pub fn group_description(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -521,13 +508,13 @@ impl NapiGroup { #[napi] pub async fn update_group_pinned_frame_url(&self, pinned_frame_url: String) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_pinned_frame_url(&self.inner_client, pinned_frame_url) + .update_group_pinned_frame_url(pinned_frame_url) .await .map_err(ErrorWrapper::from)?; @@ -537,7 +524,7 @@ impl NapiGroup { #[napi] pub fn group_pinned_frame_url(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -573,7 +560,7 @@ impl NapiGroup { #[napi] pub fn is_active(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -588,7 +575,7 @@ impl NapiGroup { #[napi] pub fn added_by_inbox_id(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -599,7 +586,7 @@ impl NapiGroup { #[napi] pub fn group_metadata(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -614,7 +601,7 @@ impl NapiGroup { #[napi] pub fn consent_state(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -627,7 +614,7 @@ impl NapiGroup { #[napi] pub fn update_consent_state(&self, state: NapiConsentState) -> Result<()> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index df253aff8..412d602c8 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -119,11 +119,13 @@ pub fn create_grpc_stream_inner< #[cfg(feature = "test-utils")] impl XmtpTestClient for crate::XmtpHttpApiClient { async fn create_local() -> Self { - crate::XmtpHttpApiClient::new("http://localhost:5555".into()).unwrap() + crate::XmtpHttpApiClient::new("http://localhost:5555".into()) + .expect("could not create client") } async fn create_dev() -> Self { - crate::XmtpHttpApiClient::new("https://grpc.dev.xmtp.network:443".into()).unwrap() + crate::XmtpHttpApiClient::new("https://grpc.dev.xmtp.network:443".into()) + .expect("coult not create client") } } diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index e6b51e1ab..483894f14 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -9,11 +9,12 @@ rustdoc-args = ["--cfg", "docsrs"] targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown", "aarch64-apple-darwin"] [features] -default = [] -test-utils = ["xmtp_id/test-utils", "tracing-subscriber", "dep:xmtp_api_http", "dep:tracing-wasm", "dep:console_error_panic_hook"] +default = ["grpc-api"] +test-utils = ["xmtp_id/test-utils", "tracing-subscriber", "dep:tracing-wasm", "dep:console_error_panic_hook"] bench = ["test-utils", "indicatif", "tracing-subscriber", "anyhow", "tracing-flame", "once_cell", "dep:xmtp_api_grpc", "criterion"] update-schema = ["toml"] http-api = ["dep:xmtp_api_http"] +grpc-api = ["dep:xmtp_api_grpc"] message-history = ["dep:reqwest"] [dependencies] diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 447c4142b..e023c24c1 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -122,7 +122,15 @@ where ApiClient: XmtpApi + Clone, { /// Build with the default [`RemoteSignatureVerifier`] - pub async fn build(self) -> Result, ClientBuilderError> { + pub async fn build(mut self) -> Result, ClientBuilderError> { + let api_client = + self.api_client + .clone() + .take() + .ok_or(ClientBuilderError::MissingParameter { + parameter: "api_client", + })?; + self = self.scw_signature_verifier(RemoteSignatureVerifier::new(api_client)); inner_build::>(self).await } } diff --git a/xmtp_mls/src/groups/message_history.rs b/xmtp_mls/src/groups/message_history.rs index 6c8a036f7..9510d9135 100644 --- a/xmtp_mls/src/groups/message_history.rs +++ b/xmtp_mls/src/groups/message_history.rs @@ -104,8 +104,8 @@ enum SyncableTables { impl Client where - ApiClient: XmtpApi, - V: SmartContractSignatureVerifier, + ApiClient: XmtpApi + Clone, + V: SmartContractSignatureVerifier + Clone, { pub fn get_sync_group(&self) -> Result, GroupError> { let conn = self.store().conn()?; @@ -130,7 +130,7 @@ where }; // sync the group - sync_group.sync(self).await?; + sync_group.sync().await?; Ok(()) } @@ -140,7 +140,7 @@ where let groups = conn.find_groups(None, None, None, None, false)?; for group in groups { let group = self.group(group.id)?; - Box::pin(group.add_members_by_inbox_id(self, vec![inbox_id.clone()])).await?; + Box::pin(group.add_members_by_inbox_id(vec![inbox_id.clone()])).await?; } Ok(()) @@ -153,7 +153,7 @@ where let sync_group = self.get_sync_group()?; // sync the group - sync_group.sync(self).await?; + sync_group.sync().await?; let messages = sync_group.find_messages( Some(GroupMessageKind::Application), @@ -195,7 +195,7 @@ where })?; // publish the intent - if let Err(err) = sync_group.publish_intents(&conn.into(), self).await { + if let Err(err) = sync_group.publish_intents(&conn.into()).await { tracing::error!("error publishing sync group intents: {:?}", err); } @@ -211,7 +211,7 @@ where let sync_group = self.get_sync_group()?; // sync the group - Box::pin(sync_group.sync(self)).await?; + Box::pin(sync_group.sync()).await?; let messages = sync_group.find_messages( Some(GroupMessageKind::Application), @@ -267,7 +267,7 @@ where })?; // publish the intent - if let Err(err) = sync_group.publish_intents(&conn.into(), self).await { + if let Err(err) = sync_group.publish_intents(&conn.into()).await { tracing::error!("error publishing sync group intents: {:?}", err); } Ok(()) @@ -279,7 +279,7 @@ where let sync_group = self.get_sync_group()?; // sync the group - sync_group.sync(self).await?; + sync_group.sync().await?; let messages = sync_group.find_messages( Some(GroupMessageKind::Application), @@ -327,7 +327,7 @@ where let sync_group = self.get_sync_group()?; // sync the group - sync_group.sync(self).await?; + sync_group.sync().await?; let messages = sync_group.find_messages( Some(GroupMessageKind::Application), @@ -389,7 +389,7 @@ where let groups = conn.find_groups(None, None, None, None, false)?; for crate::storage::group::StoredGroup { id, .. } in groups.into_iter() { let group = self.group(id)?; - Box::pin(group.sync(self)).await?; + Box::pin(group.sync()).await?; } return Ok(()); diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index cdcc57e99..11403e103 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -828,7 +828,7 @@ impl MlsGroup { } } - pub async fn update_group_description( + pub async fn update_group_description( &self, group_description: String, ) -> Result<(), GroupError> { From 5d0c3ee694d203eac4f6d495f47b1968384b8743 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 11 Oct 2024 12:15:58 -0400 Subject: [PATCH 84/97] fix tests/benchmarks/cli-client --- bindings_wasm/Cargo.toml | 7 + bindings_wasm/src/groups.rs | 99 +++++++------- bindings_wasm/src/mls_client.rs | 8 +- examples/cli/cli-client.rs | 30 ++--- examples/cli/serializable.rs | 7 +- mls_validation_service/src/handlers.rs | 17 +-- mls_validation_service/src/main.rs | 2 +- xmtp_api_grpc/src/lib.rs | 2 +- xmtp_api_http/Cargo.toml | 5 +- xmtp_api_http/src/util.rs | 4 +- xmtp_id/src/lib.rs | 15 +++ .../src/scw_verifier/chain_rpc_verifier.rs | 16 ++- xmtp_id/src/scw_verifier/mod.rs | 35 +++-- .../scw_verifier/remote_signature_verifier.rs | 2 +- xmtp_mls/Cargo.toml | 5 +- xmtp_mls/benches/group_limit.rs | 63 +++------ xmtp_mls/src/api/test_utils.rs | 2 +- xmtp_mls/src/builder.rs | 29 ++-- xmtp_mls/src/client.rs | 4 +- xmtp_mls/src/groups/message_history.rs | 37 +++--- xmtp_mls/src/groups/mod.rs | 4 +- xmtp_mls/src/groups/scoped_client.rs | 10 +- xmtp_mls/src/groups/subscriptions.rs | 4 +- xmtp_mls/src/groups/sync.rs | 2 +- xmtp_mls/src/intents.rs | 16 ++- .../storage/encrypted_store/refresh_state.rs | 6 +- xmtp_mls/src/utils/bench.rs | 2 +- xmtp_mls/src/utils/test/mod.rs | 125 ++++++++++-------- xmtp_proto/src/api_client.rs | 21 +-- 29 files changed, 292 insertions(+), 287 deletions(-) diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 2cb631a35..dab1589ef 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -21,8 +21,15 @@ xmtp_id = { path = "../xmtp_id" } xmtp_mls = { path = "../xmtp_mls", features = [ "message-history", "test-utils", + "http-api" ] } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } [dev-dependencies] wasm-bindgen-test.workspace = true +xmtp_mls = { path = "../xmtp_mls", features = [ + "message-history", + "test-utils", + "http-api" +] } + diff --git a/bindings_wasm/src/groups.rs b/bindings_wasm/src/groups.rs index 91578677c..7876e27ca 100644 --- a/bindings_wasm/src/groups.rs +++ b/bindings_wasm/src/groups.rs @@ -84,16 +84,13 @@ impl WasmGroup { pub async fn send(&self, encoded_content: WasmEncodedContent) -> Result { let encoded_content: EncodedContent = encoded_content.into(); let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); let message_id = group - .send_message( - encoded_content.encode_to_vec().as_slice(), - &self.inner_client, - ) + .send_message(encoded_content.encode_to_vec().as_slice()) .await .map_err(|e| JsError::new(&format!("{e}")))?; Ok(hex::encode(message_id.clone())) @@ -104,7 +101,7 @@ impl WasmGroup { pub fn send_optimistic(&self, encoded_content: WasmEncodedContent) -> Result { let encoded_content: EncodedContent = encoded_content.into(); let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -120,12 +117,12 @@ impl WasmGroup { #[wasm_bindgen] pub async fn publish_messages(&self) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .publish_messages(&self.inner_client) + .publish_messages() .await .map_err(|e| JsError::new(&format!("{e}")))?; Ok(()) @@ -134,13 +131,13 @@ impl WasmGroup { #[wasm_bindgen] pub async fn sync(&self) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .sync(&self.inner_client) + .sync() .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -163,7 +160,7 @@ impl WasmGroup { }; let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -189,13 +186,13 @@ impl WasmGroup { #[wasm_bindgen] pub async fn list_members(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); let members: Vec = group - .members(&self.inner_client) + .members() .await .map_err(|e| JsError::new(&format!("{e}")))? .into_iter() @@ -222,7 +219,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn admin_list(&self) -> Result, JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -241,7 +238,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn super_admin_list(&self) -> Result, JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -272,13 +269,13 @@ impl WasmGroup { #[wasm_bindgen] pub async fn add_members(&self, account_addresses: Vec) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .add_members(&self.inner_client, account_addresses) + .add_members(account_addresses) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -288,12 +285,12 @@ impl WasmGroup { #[wasm_bindgen] pub async fn add_admin(&self, inbox_id: String) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::Add, inbox_id) + .update_admin_list(UpdateAdminListType::Add, inbox_id) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -303,12 +300,12 @@ impl WasmGroup { #[wasm_bindgen] pub async fn remove_admin(&self, inbox_id: String) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::Remove, inbox_id) + .update_admin_list(UpdateAdminListType::Remove, inbox_id) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -318,12 +315,12 @@ impl WasmGroup { #[wasm_bindgen] pub async fn add_super_admin(&self, inbox_id: String) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list(&self.inner_client, UpdateAdminListType::AddSuper, inbox_id) + .update_admin_list(UpdateAdminListType::AddSuper, inbox_id) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -333,16 +330,12 @@ impl WasmGroup { #[wasm_bindgen] pub async fn remove_super_admin(&self, inbox_id: String) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_admin_list( - &self.inner_client, - UpdateAdminListType::RemoveSuper, - inbox_id, - ) + .update_admin_list(UpdateAdminListType::RemoveSuper, inbox_id) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -352,7 +345,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn group_permissions(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -367,13 +360,13 @@ impl WasmGroup { #[wasm_bindgen] pub async fn add_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .add_members_by_inbox_id(&self.inner_client, inbox_ids) + .add_members_by_inbox_id(inbox_ids) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -383,13 +376,13 @@ impl WasmGroup { #[wasm_bindgen] pub async fn remove_members(&self, account_addresses: Vec) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .remove_members(&self.inner_client, account_addresses) + .remove_members(account_addresses) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -399,13 +392,13 @@ impl WasmGroup { #[wasm_bindgen] pub async fn remove_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .remove_members_by_inbox_id(&self.inner_client, inbox_ids) + .remove_members_by_inbox_id(inbox_ids) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -415,13 +408,13 @@ impl WasmGroup { #[wasm_bindgen] pub async fn update_group_name(&self, group_name: String) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_name(&self.inner_client, group_name) + .update_group_name(group_name) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -431,7 +424,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn group_name(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -453,13 +446,13 @@ impl WasmGroup { group_image_url_square: String, ) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_image_url_square(&self.inner_client, group_image_url_square) + .update_group_image_url_square(group_image_url_square) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -469,7 +462,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn group_image_url_square(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -488,13 +481,13 @@ impl WasmGroup { #[wasm_bindgen] pub async fn update_group_description(&self, group_description: String) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_description(&self.inner_client, group_description) + .update_group_description(group_description) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -504,7 +497,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn group_description(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -526,13 +519,13 @@ impl WasmGroup { pinned_frame_url: String, ) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); group - .update_group_pinned_frame_url(&self.inner_client, pinned_frame_url) + .update_group_pinned_frame_url(pinned_frame_url) .await .map_err(|e| JsError::new(&format!("{e}")))?; @@ -542,7 +535,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn group_pinned_frame_url(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -566,7 +559,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn is_active(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -583,7 +576,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn added_by_inbox_id(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -596,7 +589,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn group_metadata(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -615,7 +608,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn consent_state(&self) -> Result { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); @@ -630,7 +623,7 @@ impl WasmGroup { #[wasm_bindgen] pub fn update_consent_state(&self, state: WasmConsentState) -> Result<(), JsError> { let group = MlsGroup::new( - self.inner_client.context().clone(), + self.inner_client.clone(), self.group_id.clone(), self.created_at_ns, ); diff --git a/bindings_wasm/src/mls_client.rs b/bindings_wasm/src/mls_client.rs index e396afd69..09f3c343d 100644 --- a/bindings_wasm/src/mls_client.rs +++ b/bindings_wasm/src/mls_client.rs @@ -249,13 +249,7 @@ impl WasmClient { let signature = UnverifiedSignature::new_recoverable_ecdsa(signature_bytes.to_vec()); signature_request - .add_signature( - signature, - self - .inner_client - .smart_contract_signature_verifier() - .as_ref(), - ) + .add_signature(signature, self.inner_client.scw_verifier()) .await .map_err(|e| JsError::new(format!("{}", e).as_str()))?; } else { diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 1bee113aa..4c2b3126f 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -39,7 +39,7 @@ use xmtp_mls::{ builder::ClientBuilderError, client::ClientError, codecs::{text::TextCodec, ContentCodec}, - groups::{message_history::MessageHistoryUrls, GroupMetadataOptions, MlsGroup}, + groups::{message_history::MessageHistoryUrls, GroupMetadataOptions}, identity::IdentityStrategy, storage::{ group_message::StoredGroupMessage, EncryptedMessageStore, EncryptionKey, StorageError, @@ -50,6 +50,7 @@ use xmtp_mls::{ }; type Client = xmtp_mls::client::Client; type ClientBuilder = xmtp_mls::builder::ClientBuilder; +type MlsGroup = xmtp_mls::groups::MlsGroup; /// A fictional versioning CLI #[derive(Debug, Parser)] // requires `derive` feature @@ -213,12 +214,12 @@ async fn main() { .find_groups(FindGroupParams::default()) .expect("failed to list groups"); for group in group_list.iter() { - group.sync(&client).await.expect("error syncing group"); + group.sync().await.expect("error syncing group"); } let serializable_group_list = group_list .iter() - .map(|g| SerializableGroup::from(g, &client)) + .map(SerializableGroup::from) .collect::>(); let serializable_group_list = join_all(serializable_group_list).await; @@ -239,7 +240,7 @@ async fn main() { let group = get_group(&client, hex::decode(group_id).expect("group id decode")) .await .expect("failed to get group"); - send(group, msg.clone(), &client).await.unwrap(); + send(group, msg.clone()).await.unwrap(); info!("sent message", { command_output: true, group_id: group_id, message: msg }); } Commands::ListGroupMessages { group_id } => { @@ -282,7 +283,7 @@ async fn main() { .expect("failed to get group"); group - .add_members(&client, account_addresses.clone()) + .add_members(account_addresses.clone()) .await .expect("failed to add member"); @@ -304,7 +305,7 @@ async fn main() { .expect("failed to get group"); group - .remove_members(&client, account_addresses.clone()) + .remove_members(account_addresses.clone()) .await .expect("failed to add member"); @@ -340,8 +341,8 @@ async fn main() { let group = &client .group(hex::decode(group_id).expect("bad group id")) .expect("group not found"); - group.sync(&client).await.unwrap(); - let serializable = SerializableGroup::from(group, &client).await; + group.sync().await.unwrap(); + let serializable = SerializableGroup::from(group).await; info!("Group {}", group_id, { command_output: true, group_id: group_id, group_info: make_value(&serializable) }) } Commands::RequestHistorySync {} => { @@ -383,7 +384,7 @@ async fn main() { client.enable_history_sync().await.unwrap(); let group = client.get_sync_group().unwrap(); let group_id_str = hex::encode(group.group_id.clone()); - group.sync(&client).await.unwrap(); + group.sync().await.unwrap(); let messages = group .find_messages(Some(GroupMessageKind::Application), None, None, None, None) .unwrap(); @@ -468,10 +469,7 @@ async fn register(cli: &Cli, maybe_seed_phrase: Option) -> Result<(), Cl let signature = UnverifiedSignature::RecoverableEcdsa(UnverifiedRecoverableEcdsaSignature::new(sig_bytes)); signature_request - .add_signature( - signature, - client.smart_contract_signature_verifier().as_ref(), - ) + .add_signature(signature, client.scw_verifier()) .await .unwrap(); @@ -488,20 +486,20 @@ async fn get_group(client: &Client, group_id: Vec) -> Result Result<(), CliError> { +async fn send(group: MlsGroup, msg: String) -> Result<(), CliError> { let mut buf = Vec::new(); TextCodec::encode(msg.clone()) .unwrap() .encode(&mut buf) .unwrap(); - group.send_message(buf.as_slice(), client).await.unwrap(); + group.send_message(buf.as_slice()).await.unwrap(); Ok(()) } diff --git a/examples/cli/serializable.rs b/examples/cli/serializable.rs index 9153e0345..a8c8d6a6a 100644 --- a/examples/cli/serializable.rs +++ b/examples/cli/serializable.rs @@ -22,13 +22,12 @@ pub struct SerializableGroup { } impl SerializableGroup { - pub async fn from( - group: &MlsGroup, - client: &xmtp_mls::Client, + pub async fn from( + group: &MlsGroup>, ) -> Self { let group_id = hex::encode(group.group_id.clone()); let members = group - .members(client) + .members() .await .expect("could not load members") .into_iter() diff --git a/mls_validation_service/src/handlers.rs b/mls_validation_service/src/handlers.rs index 0d6188a45..b48b1ad7b 100644 --- a/mls_validation_service/src/handlers.rs +++ b/mls_validation_service/src/handlers.rs @@ -62,7 +62,7 @@ pub struct ValidationService { } impl ValidationService { - pub fn new(scw_verifier: impl SmartContractSignatureVerifier) -> Self { + pub fn new(scw_verifier: impl SmartContractSignatureVerifier + 'static) -> Self { Self { scw_verifier: Box::new(scw_verifier), } @@ -125,7 +125,7 @@ impl ValidationApi for ValidationService { new_updates, } = request.into_inner(); - get_association_state(old_updates, new_updates, self.scw_verifier.as_ref()) + get_association_state(old_updates, new_updates, &self.scw_verifier) .await .map(Response::new) .map_err(Into::into) @@ -137,7 +137,7 @@ impl ValidationApi for ValidationService { ) -> Result, Status> { let VerifySmartContractWalletSignaturesRequest { signatures } = request.into_inner(); - verify_smart_contract_wallet_signatures(signatures, self.scw_verifier.as_ref()).await + verify_smart_contract_wallet_signatures(signatures, &self.scw_verifier).await } async fn validate_inbox_id_key_packages( @@ -201,16 +201,17 @@ async fn validate_inbox_id_key_package( async fn verify_smart_contract_wallet_signatures( signatures: Vec, - scw_verifier: &dyn SmartContractSignatureVerifier, + scw_verifier: impl SmartContractSignatureVerifier, ) -> Result, Status> { let mut responses = vec![]; for signature in signatures { + let verifier = &scw_verifier; let handle = async move { let account_id = signature.account_id.try_into().map_err(|_e| { GrpcServerError::Deserialization(DeserializationError::InvalidAccountId) })?; - let response = scw_verifier + let response = verifier .is_valid_signature( account_id, signature.hash.try_into().map_err(|_| { @@ -255,7 +256,7 @@ async fn verify_smart_contract_wallet_signatures( async fn get_association_state( old_updates: Vec, new_updates: Vec, - scw_verifier: &dyn SmartContractSignatureVerifier, + scw_verifier: impl SmartContractSignatureVerifier, ) -> Result { let old_unverified_updates: Vec = try_map_vec(old_updates)?; let new_unverified_updates: Vec = try_map_vec(new_updates)?; @@ -263,13 +264,13 @@ async fn get_association_state( let old_updates = try_join_all( old_unverified_updates .iter() - .map(|u| u.to_verified(scw_verifier)), + .map(|u| u.to_verified(&scw_verifier)), ) .await?; let new_updates = try_join_all( new_unverified_updates .iter() - .map(|u| u.to_verified(scw_verifier)), + .map(|u| u.to_verified(&scw_verifier)), ) .await?; if old_updates.is_empty() { diff --git a/mls_validation_service/src/main.rs b/mls_validation_service/src/main.rs index dedcbc540..5df5db0c1 100644 --- a/mls_validation_service/src/main.rs +++ b/mls_validation_service/src/main.rs @@ -30,7 +30,7 @@ async fn main() -> Result<(), Box> { let health_server = health_check_server(args.health_check_port as u16); - let scw_verifier = MultiSmartContractSignatureVerifier::new_from_file("chain_urls.json"); + let scw_verifier = MultiSmartContractSignatureVerifier::new_from_file("chain_urls.json")?; let grpc_server = Server::builder() .add_service(ValidationApiServer::new(ValidationService::new( diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index 57b1f9413..265f6f107 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -10,7 +10,7 @@ pub use grpc_api_helper::{Client, GroupMessageStream, WelcomeMessageStream}; mod utils { #[cfg(feature = "test-utils")] mod test { - use xmtp_proto::api_client::trait_impls::XmtpTestClient; + use xmtp_proto::api_client::XmtpTestClient; impl XmtpTestClient for crate::Client { async fn create_local() -> Self { diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml index 1becdc165..ff5035fb4 100644 --- a/xmtp_api_http/Cargo.toml +++ b/xmtp_api_http/Cargo.toml @@ -17,6 +17,9 @@ thiserror = "1.0" tokio = { workspace = true, features = ["sync", "rt", "macros"] } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } +[dev-dependencies] +xmtp_proto = { path = "../xmtp_proto", features = ["test-utils"] } + [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } @@ -25,4 +28,4 @@ tokio = { workspace = true, features = ["macros", "time"] } wasm-bindgen-test.workspace = true [features] -test-utils = [] +test-utils = ["xmtp_proto/test-utils"] diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index 412d602c8..f8d2b3b11 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -5,7 +5,7 @@ use futures::{ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::Deserializer; use std::io::Read; -use xmtp_proto::api_client::{trait_impls::XmtpTestClient, Error, ErrorKind}; +use xmtp_proto::api_client::{Error, ErrorKind}; #[derive(Deserialize, Serialize, Debug)] #[serde(untagged)] @@ -117,7 +117,7 @@ pub fn create_grpc_stream_inner< } #[cfg(feature = "test-utils")] -impl XmtpTestClient for crate::XmtpHttpApiClient { +impl xmtp_proto::api_client::XmtpTestClient for crate::XmtpHttpApiClient { async fn create_local() -> Self { crate::XmtpHttpApiClient::new("http://localhost:5555".into()) .expect("could not create client") diff --git a/xmtp_id/src/lib.rs b/xmtp_id/src/lib.rs index 2a7d7ea09..9c1b7b034 100755 --- a/xmtp_id/src/lib.rs +++ b/xmtp_id/src/lib.rs @@ -60,8 +60,23 @@ impl InboxOwner for LocalWallet { } } +impl InboxOwner for &T +where + T: InboxOwner, +{ + fn get_address(&self) -> String { + (**self).get_address() + } + + fn sign(&self, text: &str) -> Result { + (**self).sign(text) + } +} + #[cfg(test)] mod tests { + #![allow(clippy::unwrap_used)] + use ethers::contract::abigen; #[cfg(target_arch = "wasm32")] diff --git a/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs b/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs index 9c036bedf..d467bead3 100644 --- a/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs +++ b/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs @@ -32,9 +32,9 @@ pub struct RpcSmartContractWalletVerifier { } impl RpcSmartContractWalletVerifier { - pub fn new(url: String) -> Self { - let provider = Arc::new(Provider::::try_from(url).unwrap()); - Self { provider } + pub fn new(url: String) -> Result { + let provider = Arc::new(Provider::::try_from(url)?); + Ok(Self { provider }) } } @@ -55,7 +55,7 @@ impl SmartContractSignatureVerifier for RpcSmartContractWalletVerifier { signature: Bytes, block_number: Option, ) -> Result { - let code = hex::decode(VALIDATE_SIG_OFFCHAIN_BYTECODE).unwrap(); + let code = hex::decode(VALIDATE_SIG_OFFCHAIN_BYTECODE)?; let account_address: Address = signer .account_address .parse() @@ -113,6 +113,7 @@ impl SmartContractSignatureVerifier for RpcSmartContractWalletVerifier { // because its a wrapper over the system-binary #[cfg(all(test, not(target_arch = "wasm32")))] pub(crate) mod tests { + #![allow(clippy::unwrap_used)] use crate::is_smart_contract; use super::*; @@ -227,7 +228,7 @@ pub(crate) mod tests { ); let hash: [u8; 32] = H256::random().into(); let replay_safe_hash = smart_wallet.replay_safe_hash(hash).call().await.unwrap(); - let verifier = RpcSmartContractWalletVerifier::new(anvil.endpoint()); + let verifier = RpcSmartContractWalletVerifier::new(anvil.endpoint()).unwrap(); // verify owner0 is a valid owner let sig0 = owner0.sign_hash(replay_safe_hash.into()).unwrap(); @@ -359,7 +360,7 @@ pub(crate) mod tests { ])]) .into(); - let verifier = RpcSmartContractWalletVerifier::new(anvil.endpoint()); + let verifier = RpcSmartContractWalletVerifier::new(anvil.endpoint()).unwrap(); let account_id = AccountId::new_evm(anvil.chain_id(), format!("{:?}", smart_wallet_address)); @@ -425,7 +426,8 @@ pub(crate) mod tests { let hash = hash_message(hash); let signature = Bytes::from_hex("0x000000000000000000000000bf07a0df119ca234634588fbdb5625594e2a5bca00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000038449c81579000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000004836a472ab1dd406ecb8d0f933a985541ee3921f0000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000007a7f00000000000000000000000000000000000000000000000000000000000000017f7f0f292b79d9ce101861526459da50f62368077ae24affe97b792bf4bdd2e171553d602d80604d3d3981f3363d3d373d3d3d363d732a2b85eb1054d6f0c6c2e37da05ed3e5fea684ef5af43d82803e903d91602b57fd5bf300000000000000000000000000000000000000000000000000000000000000000000000002246171d1c9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000004836a472ab1dd406ecb8d0f933a985541ee3921f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000942f9ce5d9a33a82f88d233aeb3292e6802303480000000000000000000000000000000000000000000000000014c3c6ef1cdc01000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042f2eaaebf45fc0340eb55f11c52a30e2ca7f48539d0a1f1cdc240482210326494545def903e8ed4441bd5438109abe950f1f79baf032f184728ba2d4161dea32e1b0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042c0f8db6019888d87a0afc1299e81ef45d3abce64f63072c8d7a6ef00f5f82c1522958ff110afa98b8c0d23b558376db1d2fbab4944e708f8bf6dc7b977ee07201b000000000000000000000000000000000000000000000000000000000000006492649264926492649264926492649264926492649264926492649264926492").unwrap(); - let verifier = RpcSmartContractWalletVerifier::new("https://polygon-rpc.com".to_string()); + let verifier = + RpcSmartContractWalletVerifier::new("https://polygon-rpc.com".to_string()).unwrap(); assert!( verifier .is_valid_signature(AccountId::new_evm(1, signer), hash.into(), signature, None) diff --git a/xmtp_id/src/scw_verifier/mod.rs b/xmtp_id/src/scw_verifier/mod.rs index f11fb59da..83fe780dd 100644 --- a/xmtp_id/src/scw_verifier/mod.rs +++ b/xmtp_id/src/scw_verifier/mod.rs @@ -30,6 +30,12 @@ pub enum VerifierError { Provider(#[from] ethers::providers::ProviderError), #[error(transparent)] ApiClient(#[from] xmtp_proto::api_client::Error), + #[error(transparent)] + Url(#[from] url::ParseError), + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + Serde(#[from] serde_json::Error), } #[cfg(not(target_arch = "wasm32"))] @@ -104,45 +110,38 @@ pub struct MultiSmartContractSignatureVerifier { } impl MultiSmartContractSignatureVerifier { - pub fn new(urls: HashMap) -> Self { + pub fn new(urls: HashMap) -> Result { let verifiers = urls .into_iter() .map(|(chain_id, url)| { - ( + Ok::<_, VerifierError>(( chain_id, - Box::new(RpcSmartContractWalletVerifier::new(url.to_string())) + Box::new(RpcSmartContractWalletVerifier::new(url.to_string())?) as Box, - ) + )) }) - .collect(); + .collect::, _>>()?; - Self { verifiers } + Ok(Self { verifiers }) } - pub fn new_from_file(path: impl AsRef) -> Self { + pub fn new_from_file(path: impl AsRef) -> Result { let path = path.as_ref(); let file_str; let json = if path.exists() { - file_str = fs::read_to_string(path).unwrap_or_else(|_| panic!("{path:?} is missing")); + file_str = fs::read_to_string(path)?; &file_str } else { DEFAULT_CHAIN_URLS }; - let json: HashMap = - serde_json::from_str(json).unwrap_or_else(|_| panic!("{path:?} is malformatted")); + let json: HashMap = serde_json::from_str(json)?; let urls = json .into_iter() - .map(|(id, url)| { - ( - id, - Url::from_str(&url) - .unwrap_or_else(|_| panic!("unable to parse url in {path:?} ({url})")), - ) - }) - .collect(); + .map(|(id, url)| Ok::<_, VerifierError>((id, Url::from_str(&url)?))) + .collect::>()?; Self::new(urls) } diff --git a/xmtp_id/src/scw_verifier/remote_signature_verifier.rs b/xmtp_id/src/scw_verifier/remote_signature_verifier.rs index 0b74947f0..1c0d3fce5 100644 --- a/xmtp_id/src/scw_verifier/remote_signature_verifier.rs +++ b/xmtp_id/src/scw_verifier/remote_signature_verifier.rs @@ -55,7 +55,7 @@ where impl Clone for RemoteSignatureVerifier where - T: Clone + ?Sized, + T: Clone, { fn clone(&self) -> Self { Self { diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 483894f14..be11c2ac2 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -10,7 +10,7 @@ targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown", "aarch64-apple- [features] default = ["grpc-api"] -test-utils = ["xmtp_id/test-utils", "tracing-subscriber", "dep:tracing-wasm", "dep:console_error_panic_hook"] +test-utils = ["tracing-subscriber", "dep:tracing-wasm", "dep:console_error_panic_hook", "xmtp_id/test-utils", "xmtp_proto/test-utils", "xmtp_api_http/test-utils", "xmtp_api_grpc/test-utils"] bench = ["test-utils", "indicatif", "tracing-subscriber", "anyhow", "tracing-flame", "once_cell", "dep:xmtp_api_grpc", "criterion"] update-schema = ["toml"] http-api = ["dep:xmtp_api_http"] @@ -128,7 +128,10 @@ required-features = ["update-schema"] [[bench]] name = "group_limit" harness = false +required-features = ["bench"] [[bench]] name = "crypto" harness = false +required-features = ["bench"] + diff --git a/xmtp_mls/benches/group_limit.rs b/xmtp_mls/benches/group_limit.rs index 7319f5364..d2466a02b 100755 --- a/xmtp_mls/benches/group_limit.rs +++ b/xmtp_mls/benches/group_limit.rs @@ -40,11 +40,11 @@ fn setup() -> (Arc, Vec, Runtime) { tracing::info!("Using Dev GRPC"); Arc::new(ClientBuilder::new_dev_client(&wallet).await) } else { - Arc::new(ClientBuilder::new_test_client(&wallet).await) + Arc::new(ClientBuilder::new_local_client(&wallet).await) }; let identities: Vec = - create_identities_if_dont_exist(MAX_IDENTITIES, &client, is_dev_network).await; + create_identities_if_dont_exist(MAX_IDENTITIES, client.as_ref(), is_dev_network).await; (client, identities) }); @@ -84,7 +84,6 @@ fn add_to_empty_group(c: &mut Criterion) { b.to_async(&runtime).iter_batched( || { ( - client.clone(), client .create_group(None, GroupMetadataOptions::default()) .unwrap(), @@ -92,12 +91,8 @@ fn add_to_empty_group(c: &mut Criterion) { span.clone(), ) }, - |(client, group, addrs, span)| async move { - group - .add_members(&client, addrs) - .instrument(span) - .await - .unwrap(); + |(group, addrs, span)| async move { + group.add_members(addrs).instrument(span).await.unwrap(); }, BatchSize::SmallInput, ); @@ -127,7 +122,6 @@ fn add_to_empty_group_by_inbox_id(c: &mut Criterion) { b.to_async(&runtime).iter_batched( || { ( - client.clone(), client .create_group(None, GroupMetadataOptions::default()) .unwrap(), @@ -135,9 +129,9 @@ fn add_to_empty_group_by_inbox_id(c: &mut Criterion) { ids.clone(), ) }, - |(client, group, span, ids)| async move { + |(group, span, ids)| async move { group - .add_members_by_inbox_id(&client, ids) + .add_members_by_inbox_id(ids) .instrument(span) .await .unwrap(); @@ -176,7 +170,6 @@ fn add_to_100_member_group_by_inbox_id(c: &mut Criterion) { .unwrap(); group .add_members_by_inbox_id( - &client, // it is OK to take from the back for now because we aren't getting // near MAX_IDENTITIES inbox_ids.iter().rev().take(100).cloned().collect(), @@ -184,12 +177,12 @@ fn add_to_100_member_group_by_inbox_id(c: &mut Criterion) { .await .unwrap(); - (client.clone(), group, span.clone(), ids.clone()) + (group, span.clone(), ids.clone()) }) }, - |(client, group, span, ids)| async move { + |(group, span, ids)| async move { group - .add_members_by_inbox_id(&client, ids) + .add_members_by_inbox_id(ids) .instrument(span) .await .unwrap(); @@ -226,16 +219,13 @@ fn remove_all_members_from_group(c: &mut Criterion) { let group = client .create_group(None, GroupMetadataOptions::default()) .unwrap(); - group - .add_members_by_inbox_id(&client, ids.clone()) - .await - .unwrap(); - (client.clone(), group, span.clone(), ids.clone()) + group.add_members_by_inbox_id(ids.clone()).await.unwrap(); + (group, span.clone(), ids.clone()) }) }, - |(client, group, span, ids)| async move { + |(group, span, ids)| async move { group - .remove_members_by_inbox_id(&client, ids) + .remove_members_by_inbox_id(ids) .instrument(span) .await .unwrap(); @@ -272,21 +262,13 @@ fn remove_half_members_from_group(c: &mut Criterion) { let group = client .create_group(None, GroupMetadataOptions::default()) .unwrap(); - group - .add_members_by_inbox_id(&client, ids.clone()) - .await - .unwrap(); - ( - client.clone(), - group, - span.clone(), - ids[0..(size / 2)].into(), - ) + group.add_members_by_inbox_id(ids.clone()).await.unwrap(); + (group, span.clone(), ids[0..(size / 2)].into()) }) }, - |(client, group, span, ids)| async move { + |(group, span, ids)| async move { group - .remove_members_by_inbox_id(&client, ids) + .remove_members_by_inbox_id(ids) .instrument(span) .await .unwrap(); @@ -323,17 +305,14 @@ fn add_1_member_to_group(c: &mut Criterion) { let group = client .create_group(None, GroupMetadataOptions::default()) .unwrap(); - group - .add_members_by_inbox_id(&client, ids.clone()) - .await - .unwrap(); + group.add_members_by_inbox_id(ids.clone()).await.unwrap(); let member = inbox_ids.last().unwrap().clone(); - (client.clone(), group, vec![member], span.clone()) + (group, vec![member], span.clone()) }) }, - |(client, group, member, span)| async move { + |(group, member, span)| async move { group - .add_members_by_inbox_id(&client, member) + .add_members_by_inbox_id(member) .instrument(span) .await .unwrap(); diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index d71e97d9d..09e58743a 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -23,7 +23,7 @@ use xmtp_proto::{ #[cfg(any(feature = "http-api", target_arch = "wasm32"))] use xmtp_proto::xmtp::mls::api::v1::WelcomeMessage; -use crate::XmtpTestClient; +use xmtp_proto::api_client::XmtpTestClient; pub fn build_group_messages(num_messages: usize, group_id: Vec) -> Vec { let mut out: Vec = vec![]; diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index e023c24c1..945033821 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -212,6 +212,7 @@ pub(crate) mod tests { use crate::builder::ClientBuilderError; use crate::identity::IdentityError; use crate::retry::Retry; + use crate::utils::test::TestClient; use crate::XmtpApi; use crate::{ api::test_utils::*, identity::Identity, storage::identity::StoredIdentity, @@ -229,6 +230,7 @@ pub(crate) mod tests { use xmtp_id::associations::ValidatedLegacySignedPublicKey; use xmtp_id::associations::{generate_inbox_id, test_utils::rand_u64}; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; + use xmtp_proto::api_client::XmtpTestClient; use xmtp_proto::xmtp::identity::api::v1::{ get_inbox_ids_response::Response as GetInboxIdsResponseItem, GetInboxIdsResponse, }; @@ -409,8 +411,7 @@ pub(crate) mod tests { let result = ClientBuilder::new(test_case.strategy) .temp_store() .await - .local_client() - .await + .api_client(::create_local().await) .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() .await; @@ -450,8 +451,7 @@ pub(crate) mod tests { let client1 = ClientBuilder::new(identity_strategy.clone()) .store(store.clone()) - .local_client() - .await + .api_client(::create_local().await) .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() .await @@ -460,8 +460,7 @@ pub(crate) mod tests { let client2 = ClientBuilder::new(IdentityStrategy::CachedOnly) .store(store.clone()) - .local_client() - .await + .api_client(::create_local().await) .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() .await @@ -477,8 +476,7 @@ pub(crate) mod tests { None, )) .store(store.clone()) - .local_client() - .await + .api_client(::create_local().await) .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() .await @@ -495,8 +493,7 @@ pub(crate) mod tests { )) .temp_store() .await - .local_client() - .await + .api_client(::create_local().await) .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() .await @@ -690,8 +687,7 @@ pub(crate) mod tests { nonce, None, )) - .local_client() - .await + .api_client(::create_local().await) .store(store_a) .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() @@ -715,8 +711,7 @@ pub(crate) mod tests { nonce, None, )) - .local_client() - .await + .api_client(::create_local().await) .store(store_b) .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() @@ -738,8 +733,7 @@ pub(crate) mod tests { // generate_local_wallet().get_address(), // None, // )) - // .local_client() - // .await + // .api_client(::create_local().await) // .store(store_c) // .build() // .await @@ -750,8 +744,7 @@ pub(crate) mod tests { .await .unwrap(); let client_d = Client::builder(IdentityStrategy::CachedOnly) - .local_client() - .await + .api_client(::create_local().await) .store(store_d) .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) .build_with_verifier() diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 418de8a07..e208602cc 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -674,14 +674,14 @@ where pub(crate) async fn query_group_messages( &self, - group_id: &Vec, + group_id: &[u8], conn: &DbConnection, ) -> Result, ClientError> { let id_cursor = conn.get_last_cursor_for_id(group_id, EntityKind::Group)?; let welcomes = self .api_client - .query_group_messages(group_id.clone(), Some(id_cursor as u64)) + .query_group_messages(group_id.to_vec(), Some(id_cursor as u64)) .await?; Ok(welcomes) diff --git a/xmtp_mls/src/groups/message_history.rs b/xmtp_mls/src/groups/message_history.rs index 9510d9135..83c7f6573 100644 --- a/xmtp_mls/src/groups/message_history.rs +++ b/xmtp_mls/src/groups/message_history.rs @@ -928,14 +928,14 @@ pub(crate) mod tests { assert_eq!(amal_a_sync_groups.len(), 1); // get the first sync group let amal_a_sync_group = amal_a.group(amal_a_sync_groups[0].id.clone()).unwrap(); - amal_a_sync_group.sync(&amal_a).await.expect("sync"); + amal_a_sync_group.sync().await.expect("sync"); // find the sync group (it should be the same as amal_a's sync group) let amal_b_sync_groups = amal_b.store().conn().unwrap().find_sync_groups().unwrap(); assert_eq!(amal_b_sync_groups.len(), 1); // get the first sync group let amal_b_sync_group = amal_b.group(amal_b_sync_groups[0].id.clone()).unwrap(); - amal_b_sync_group.sync(&amal_b).await.expect("sync"); + amal_b_sync_group.sync().await.expect("sync"); // make sure they are the same group assert_eq!(amal_a_sync_group.group_id, amal_b_sync_group.group_id); @@ -960,7 +960,7 @@ pub(crate) mod tests { assert_eq!(amal_a_sync_groups.len(), 1); // get the first sync group let amal_a_sync_group = amal_a.group(amal_a_sync_groups[0].id.clone()).unwrap(); - amal_a_sync_group.sync(&amal_a).await.expect("sync"); + amal_a_sync_group.sync().await.expect("sync"); let pin_challenge_result = amal_a.verify_pin(&request_id, &pin_code); assert_ok!(pin_challenge_result); @@ -1035,7 +1035,7 @@ pub(crate) mod tests { assert_eq!(amal_a_sync_groups.len(), 1); // get the first sync group let amal_a_sync_group = amal_a.group(amal_a_sync_groups[0].id.clone()).unwrap(); - amal_a_sync_group.sync(&amal_a).await.expect("sync"); + amal_a_sync_group.sync().await.expect("sync"); // amal_a builds and sends a message history reply back let history_reply = HistoryReply::new(&new_request_id(), &history_sync_url, encryption_key); @@ -1044,13 +1044,13 @@ pub(crate) mod tests { .await .expect("send reply"); - amal_a_sync_group.sync(&amal_a).await.expect("sync"); + amal_a_sync_group.sync().await.expect("sync"); // amal_b should have received the reply let amal_b_sync_groups = amal_b.store().conn().unwrap().find_sync_groups().unwrap(); assert_eq!(amal_b_sync_groups.len(), 1); let amal_b_sync_group = amal_b.group(amal_b_sync_groups[0].id.clone()).unwrap(); - amal_b_sync_group.sync(&amal_b).await.expect("sync"); + amal_b_sync_group.sync().await.expect("sync"); let amal_b_conn = amal_b.store().conn().unwrap(); let amal_b_messages = amal_b_conn @@ -1086,10 +1086,10 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .expect("create group"); - group_a.send_message(b"hi", &amal_a).await.expect("send"); - group_a.send_message(b"hi x2", &amal_a).await.expect("send"); - group_b.send_message(b"hi", &amal_a).await.expect("send"); - group_b.send_message(b"hi x2", &amal_a).await.expect("send"); + group_a.send_message(b"hi").await.expect("send"); + group_a.send_message(b"hi x2").await.expect("send"); + group_b.send_message(b"hi").await.expect("send"); + group_b.send_message(b"hi x2").await.expect("send"); let messages_result = amal_a.prepare_messages_to_sync().await.unwrap(); assert_eq!(messages_result.len(), 4); @@ -1106,10 +1106,10 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .expect("create group"); - group_a.send_message(b"hi", &amal_a).await.expect("send"); - group_a.send_message(b"hi", &amal_a).await.expect("send"); - group_b.send_message(b"hi", &amal_a).await.expect("send"); - group_b.send_message(b"hi", &amal_a).await.expect("send"); + group_a.send_message(b"hi").await.expect("send"); + group_a.send_message(b"hi").await.expect("send"); + group_b.send_message(b"hi").await.expect("send"); + group_b.send_message(b"hi").await.expect("send"); let groups = amal_a.prepare_groups_to_sync().await.unwrap(); let messages = amal_a.prepare_messages_to_sync().await.unwrap(); @@ -1404,10 +1404,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .expect("create group"); - group_a - .send_message(b"hi", &amal_a) - .await - .expect("send message"); + group_a.send_message(b"hi").await.expect("send message"); let (bundle_path, enc_key) = amal_a .write_history_bundle() @@ -1449,9 +1446,7 @@ pub(crate) mod tests { // try to join amal's sync group let sync_group_id = amal_sync_groups[0].id.clone(); let group = amal.group(sync_group_id).expect("get group"); - let result = group - .add_members(&external_client, vec![external_wallet.get_address()]) - .await; + let result = group.add_members(vec![external_wallet.get_address()]).await; assert!(result.is_err()); } diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 11403e103..f11dab344 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -40,7 +40,7 @@ pub use self::group_permissions::PreconfiguredPolicies; pub use self::intents::{AddressesOrInstallationIds, IntentError}; #[cfg(feature = "message-history")] use self::message_history::MessageHistoryError; -pub(self) use self::scoped_client::ScopedGroupClient; +use self::scoped_client::ScopedGroupClient; use self::{ group_membership::GroupMembership, group_metadata::{extract_group_metadata, DmMembers}, @@ -1398,7 +1398,7 @@ async fn validate_initial_group_membership( let membership = extract_group_membership(mls_group.extensions())?; let needs_update = conn.filter_inbox_ids_needing_updates(membership.to_filters())?; if !needs_update.is_empty() { - load_identity_updates(&client.api(), conn, needs_update).await?; + load_identity_updates(client.api(), conn, needs_update).await?; } let mut expected_installation_ids = HashSet::>::new(); diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs index 1905b380d..10460cffa 100644 --- a/xmtp_mls/src/groups/scoped_client.rs +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -72,7 +72,7 @@ pub trait LocalScopedGroupClient: Send + Sync + Sized { async fn query_group_messages( &self, - group_id: &Vec, + group_id: &[u8], conn: &DbConnection, ) -> Result, ClientError>; } @@ -132,7 +132,7 @@ pub trait ScopedGroupClient: Sized { async fn query_group_messages( &self, - group_id: &Vec, + group_id: &[u8], conn: &DbConnection, ) -> Result, ClientError>; } @@ -210,7 +210,7 @@ where async fn query_group_messages( &self, - group_id: &Vec, + group_id: &[u8], conn: &DbConnection, ) -> Result, ClientError> { crate::Client::::query_group_messages(self, group_id, conn).await @@ -296,7 +296,7 @@ where async fn query_group_messages( &self, - group_id: &Vec, + group_id: &[u8], conn: &DbConnection, ) -> Result, ClientError> { (**self).query_group_messages(group_id, conn).await @@ -382,7 +382,7 @@ where async fn query_group_messages( &self, - group_id: &Vec, + group_id: &[u8], conn: &DbConnection, ) -> Result, ClientError> { (**self).query_group_messages(group_id, conn).await diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index 61df81c5e..6005099db 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -107,9 +107,7 @@ impl MlsGroup { message.ok_or(GroupError::MissingMessage) } - pub async fn stream<'a>( - &'a self, - ) -> Result + '_, GroupError> + pub async fn stream(&self) -> Result + '_, GroupError> where ScopedClient: Clone, ::ApiClient: Clone + 'static, diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index 6eac793ab..552f2e1b0 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -1004,7 +1004,7 @@ where inbox_ids.extend(inbox_ids_to_add); let conn = provider.conn_ref(); // Load any missing updates from the network - load_identity_updates(&self.client.api(), conn, inbox_ids.clone()).await?; + load_identity_updates(self.client.api(), conn, inbox_ids.clone()).await?; let latest_sequence_id_map = conn.get_latest_sequence_id(&inbox_ids)?; diff --git a/xmtp_mls/src/intents.rs b/xmtp_mls/src/intents.rs index bd5c0b40a..95ed0a371 100644 --- a/xmtp_mls/src/intents.rs +++ b/xmtp_mls/src/intents.rs @@ -1,10 +1,12 @@ -//! an "Intent" can be thought of as a commitment by a user to try and accomplish something -//! in a group chat. Examples of an Intent: -//! - Sending a message -//! - Adding a member -//! - Removing a member -//! Intents are written to local storage, before being published to the delivery service. An -//! intent is fully processed (success or failure) once it +//! an "Intent" can be thought of as a commitment by an individual 'user', which drives +//! the state of a group chat forward. +//! Examples of an Intent: +//! - Sending a message +//! - Adding a member +//! - Removing a member +//! +//! Intents are written to local storage (SQLite), before being published to the delivery service via gRPC. An +//! intent is fully resolved (success or failure) once it use std::{future::Future, sync::Arc}; diff --git a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs index 536d2975d..19b6b28cc 100644 --- a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs +++ b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs @@ -54,7 +54,7 @@ impl_store!(RefreshState, refresh_state); impl_store_or_ignore!(RefreshState, refresh_state); impl DbConnection { - pub fn get_refresh_state>>( + pub fn get_refresh_state>( &self, entity_id: EntityId, entity_kind: EntityKind, @@ -70,7 +70,7 @@ impl DbConnection { Ok(res) } - pub fn get_last_cursor_for_id>>( + pub fn get_last_cursor_for_id>( &self, id: IdType, entity_kind: EntityKind, @@ -80,7 +80,7 @@ impl DbConnection { Some(state) => Ok(state.cursor), None => { let new_state = RefreshState { - entity_id: id.as_ref().clone(), + entity_id: id.as_ref().to_vec(), entity_kind, cursor: 0, }; diff --git a/xmtp_mls/src/utils/bench.rs b/xmtp_mls/src/utils/bench.rs index 99f833cae..3dffb4ba7 100644 --- a/xmtp_mls/src/utils/bench.rs +++ b/xmtp_mls/src/utils/bench.rs @@ -130,7 +130,7 @@ async fn create_identity(is_dev_network: bool) -> Identity { let client = if is_dev_network { ClientBuilder::new_dev_client(&wallet).await } else { - ClientBuilder::new_test_client(&wallet).await + ClientBuilder::new_local_client(&wallet).await }; Identity::new(client.inbox_id(), wallet.get_address()) } diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index d831197a8..6393d445b 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -1,6 +1,5 @@ #![allow(clippy::unwrap_used)] -use crate::XmtpTestClient; use rand::{ distributions::{Alphanumeric, DistString}, Rng, RngCore, @@ -13,8 +12,9 @@ use xmtp_id::{ test_utils::MockSmartContractSignatureVerifier, unverified::{UnverifiedRecoverableEcdsaSignature, UnverifiedSignature}, }, - scw_verifier::SmartContractSignatureVerifier, + scw_verifier::{RemoteSignatureVerifier, SmartContractSignatureVerifier}, }; +use xmtp_proto::api_client::XmtpTestClient; use crate::{ builder::ClientBuilder, @@ -90,7 +90,7 @@ impl EncryptedMessageStore { pub fn remove_db_files>(_path: P) {} } -impl ClientBuilder { +impl ClientBuilder { pub async fn temp_store(self) -> Self { let tmpdb = tmp_path(); self.store( @@ -102,65 +102,82 @@ impl ClientBuilder { .unwrap(), ) } +} - pub async fn local_client(self) -> Self { - self.api_client(::create_local().await) - } - +impl ClientBuilder { pub async fn new_test_client(owner: &impl InboxOwner) -> FullXmtpClient { - // crate::utils::wasm::init().await; - let nonce = 1; - let inbox_id = generate_inbox_id(&owner.get_address(), &nonce); - - let client = Self::new(IdentityStrategy::CreateIfNotFound( - inbox_id, - owner.get_address(), - nonce, - None, - )) - .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) - .temp_store() - .await - .local_client() - .await - .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) - .build_with_verifier() + let api_client = ::create_local().await; + inner_build( + owner, + &api_client, + MockSmartContractSignatureVerifier::new(true), + ) .await - .unwrap(); - - register_client(&client, owner).await; - - client } - pub async fn new_dev_client( - owner: &impl InboxOwner, + /// A client pointed at the dev network with a Mock verifier (never fail to verify) + pub async fn new_mock_dev_client( + owner: impl InboxOwner, ) -> Client { - let nonce = 1; - let inbox_id = generate_inbox_id(&owner.get_address(), &nonce); - let dev_client = ::create_dev().await; - - let client = Self::new(IdentityStrategy::CreateIfNotFound( - inbox_id, - owner.get_address(), - nonce, - None, - )) - .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) - .temp_store() - .await - .api_client(dev_client) - .scw_signature_verifier(MockSmartContractSignatureVerifier::new(true)) - .build_with_verifier() + let api_client = ::create_dev().await; + inner_build( + owner, + &api_client, + MockSmartContractSignatureVerifier::new(true), + ) .await - .unwrap(); + } +} - register_client(&client, owner).await; +impl ClientBuilder { + /// Createa client pointed at the local containe with the default remote verifier + pub async fn new_local_client(owner: &impl InboxOwner) -> Client { + let api_client = ::create_local().await; + inner_build( + owner, + &api_client, + RemoteSignatureVerifier::new(api_client.clone()), + ) + .await + } - client + pub async fn new_dev_client(owner: &impl InboxOwner) -> Client { + let api_client = ::create_dev().await; + inner_build( + owner, + &api_client, + RemoteSignatureVerifier::new(api_client.clone()), + ) + .await } } +async fn inner_build(owner: impl InboxOwner, api_client: &A, scw_verifier: V) -> Client +where + A: XmtpApi + Clone, + V: SmartContractSignatureVerifier + Clone, +{ + let nonce = 1; + let inbox_id = generate_inbox_id(&owner.get_address(), &nonce); + + let client = Client::::builder(IdentityStrategy::CreateIfNotFound( + inbox_id, + owner.get_address(), + nonce, + None, + )) + .temp_store() + .await + .api_client(api_client.clone()) + .scw_signature_verifier(scw_verifier) + .build_with_verifier() + .await + .unwrap(); + + register_client(&client, owner).await; + + client +} /// wrapper over a `Notify` with a 60-scond timeout for waiting #[derive(Clone, Default)] pub struct Delivery { @@ -186,7 +203,11 @@ impl Delivery { } } -impl FullXmtpClient { +impl Client +where + ApiClient: XmtpApi + Clone, + V: SmartContractSignatureVerifier + Clone, +{ pub async fn is_registered(&self, address: &String) -> bool { let ids = self .api_client @@ -199,7 +220,7 @@ impl FullXmtpClient { pub async fn register_client( client: &Client, - owner: &impl InboxOwner, + owner: impl InboxOwner, ) { let mut signature_request = client.context.signature_request().unwrap(); let signature_text = signature_request.signature_text(); diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index b3bc9562d..2ee341a6a 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -19,17 +19,20 @@ use crate::xmtp::mls::api::v1::{ SubscribeWelcomeMessagesRequest, UploadKeyPackageRequest, WelcomeMessage, }; +#[cfg(any(test, feature = "test-utils"))] +#[trait_variant::make(XmtpTestClient: Send)] +pub trait LocalXmtpTestClient { + async fn create_local() -> Self; + async fn create_dev() -> Self; +} + /// XMTP Api Super Trait /// Implements all Trait Network APIs for convenience. pub mod trait_impls { - pub use inner::*; - + #[allow(unused)] #[cfg(any(test, feature = "test-utils"))] - #[trait_variant::make(XmtpTestClient: Send)] - pub trait LocalXmtpTestClient { - async fn create_local() -> Self; - async fn create_dev() -> Self; - } + use super::{LocalXmtpTestClient, XmtpTestClient}; + pub use inner::*; // native, release #[cfg(all(not(feature = "test-utils"), not(target_arch = "wasm32")))] @@ -129,7 +132,7 @@ pub mod trait_impls { Self: LocalXmtpMlsClient + LocalXmtpMlsStreams + LocalXmtpIdentityClient - + crate::LocalXmtpTestClient + + super::LocalXmtpTestClient + ClientWithMetadata, { } @@ -138,7 +141,7 @@ pub mod trait_impls { T: LocalXmtpMlsClient + LocalXmtpMlsStreams + LocalXmtpIdentityClient - + crate::LocalXmtpTestClient + + super::LocalXmtpTestClient + ClientWithMetadata + Send + Sync From 02a42fe1d9462647387d61fcdd80de3c4a7ba9b7 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 11 Oct 2024 15:10:25 -0400 Subject: [PATCH 85/97] fix diesel patch --- Cargo.lock | 126 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 6 +-- 2 files changed, 64 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d0ba8c7f..234a169a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -638,9 +638,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.24" +version = "1.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +checksum = "58e804ac3194a48bb129643eb1d62fcc20d18c6b8c181704489353d13120bcd1" dependencies = [ "jobserver", "libc", @@ -731,9 +731,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -741,9 +741,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -1173,7 +1173,7 @@ dependencies = [ [[package]] name = "diesel" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" dependencies = [ "diesel_derives", "downcast-rs", @@ -1203,7 +1203,7 @@ dependencies = [ [[package]] name = "diesel_derives" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", @@ -1215,7 +1215,7 @@ dependencies = [ [[package]] name = "diesel_migrations" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" dependencies = [ "diesel", "migrations_internals", @@ -1225,7 +1225,7 @@ dependencies = [ [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" dependencies = [ "syn 2.0.79", ] @@ -1308,7 +1308,7 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dsl_auto_type" version = "0.1.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" dependencies = [ "darling", "either", @@ -1981,9 +1981,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1996,9 +1996,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -2006,15 +2006,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -2023,9 +2023,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-locks" @@ -2039,9 +2039,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -2050,15 +2050,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -2072,9 +2072,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -3081,7 +3081,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" dependencies = [ "serde", "toml 0.8.19", @@ -3090,7 +3090,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" dependencies = [ "migrations_internals", "proc-macro2", @@ -3435,12 +3435,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" -dependencies = [ - "portable-atomic", -] +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" @@ -3919,18 +3916,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", @@ -4129,9 +4126,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -4747,9 +4744,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ "windows-sys 0.59.0", ] @@ -6019,9 +6016,9 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "uniffi" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2db87def739fe4183947f8419d572d1849a4a09355eba4e988a2105cfd0ac6a7" +checksum = "51ce6280c581045879e11b400bae14686a819df22b97171215d15549efa04ddb" dependencies = [ "anyhow", "camino", @@ -6035,9 +6032,9 @@ dependencies = [ [[package]] name = "uniffi_bindgen" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a112599c9556d1581e4a3d72019a74c2c3e122cc27f4af12577a429c4d5e614" +checksum = "5e9f25730c9db2e878521d606f54e921edb719cdd94d735e7f97705d6796d024" dependencies = [ "anyhow", "askama", @@ -6059,9 +6056,9 @@ dependencies = [ [[package]] name = "uniffi_build" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b12684401d2a8508ca9c72a95bbc45906417e42fc80942abaf033bbf01aa33" +checksum = "88dba57ac699bd8ec53d6a352c8dd0e479b33f698c5659831bb1e4ce468c07bd" dependencies = [ "anyhow", "camino", @@ -6070,9 +6067,9 @@ dependencies = [ [[package]] name = "uniffi_checksum_derive" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22dbe67c1c957ac6e7611bdf605a6218aa86b0eebeb8be58b70ae85ad7d73dc" +checksum = "d2c801f0f05b06df456a2da4c41b9c2c4fdccc6b9916643c6c67275c4c9e4d07" dependencies = [ "quote", "syn 2.0.79", @@ -6080,14 +6077,13 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0c35aaad30e3a9e6d4fe34e358d64dbc92ee09045b48591b05fc9f12e0905b" +checksum = "61049e4db6212d0ede80982adf0e1d6fa224e6118387324c5cfbe3083dfb2252" dependencies = [ "anyhow", "async-compat", "bytes", - "camino", "log", "once_cell", "paste", @@ -6096,9 +6092,9 @@ dependencies = [ [[package]] name = "uniffi_macros" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db66474c5c61b0f7afc3b4995fecf9b72b340daa5ca0ef3da7778d75eb5482ea" +checksum = "b40fd2249e0c5dcbd2bfa3c263db1ec981f7273dca7f4132bf06a272359a586c" dependencies = [ "bincode", "camino", @@ -6114,9 +6110,9 @@ dependencies = [ [[package]] name = "uniffi_meta" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d898893f102e0e39b8bcb7e3d2188f4156ba280db32db9e8af1f122d057e9526" +checksum = "c9ad57039b4fafdbf77428d74fff40e0908e5a1731e023c19cfe538f6d4a8ed6" dependencies = [ "anyhow", "bytes", @@ -6126,9 +6122,9 @@ dependencies = [ [[package]] name = "uniffi_testing" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6aa4f0cf9d12172d84fc00a35a6c1f3522b526daad05ae739f709f6941b9b6" +checksum = "21fa171d4d258dc51bbd01893cc9608c1b62273d2f9ea55fb64f639e77824567" dependencies = [ "anyhow", "camino", @@ -6139,9 +6135,9 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b044e9c519e0bb51e516ab6f6d8f4f4dcf900ce30d5ad07c03f924e2824f28e" +checksum = "f52299e247419e7e2934bef2f94d7cccb0e6566f3248b1d48b160d8f369a2668" dependencies = [ "anyhow", "textwrap", @@ -6443,9 +6439,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 251e07dba..22cf9869e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,7 +123,7 @@ opt-level = "s" # are made public for third-party dependencies: https://github.com/diesel-rs/diesel/pull/4236 # (cfg-specific patche support does not exist) [patch.crates-io] -diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } diesel-wasm-sqlite = { git = "https://github.com/xmtp/diesel-wasm-sqlite", branch = "main" } +diesel = { git = "https://github.com/diesel-rs/diesel", branch = "master" } +diesel_derives = { git = "https://github.com/diesel-rs/diesel", branch = "master" } +diesel_migrations = { git = "https://github.com/diesel-rs/diesel", branch = "master" } From 16487dad523af8d3fe4c0cece1b149174930f5e3 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 11 Oct 2024 15:28:42 -0400 Subject: [PATCH 86/97] fix message history test --- xmtp_id/src/utils/mod.rs | 12 ++++++++---- xmtp_mls/src/groups/message_history.rs | 12 ++++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/xmtp_id/src/utils/mod.rs b/xmtp_id/src/utils/mod.rs index df958eb64..da320286c 100644 --- a/xmtp_id/src/utils/mod.rs +++ b/xmtp_id/src/utils/mod.rs @@ -13,14 +13,12 @@ pub fn now_ns() -> i64 { #[cfg(any(test, feature = "test-utils"))] pub mod test { #![allow(clippy::unwrap_used)] - use std::sync::Arc; use ethers::{ contract::abigen, middleware::SignerMiddleware, providers::{Http, Provider}, - signers::{LocalWallet, Signer}, - utils::{Anvil, AnvilInstance}, + signers::LocalWallet, }; abigen!( CoinbaseSmartWallet, @@ -40,6 +38,7 @@ pub mod test { } impl SmartContracts { + #[cfg(not(target_arch = "wasm32"))] fn new( coinbase_smart_wallet_factory: CoinbaseSmartWalletFactory< SignerMiddleware, LocalWallet>, @@ -57,17 +56,22 @@ pub mod test { } } + // anvil can't be used in wasm because it is a system binary /// Test harness that loads a local anvil node with deployed smart contracts. + #[cfg(not(target_arch = "wasm32"))] pub async fn with_smart_contracts(fun: Func) where Func: FnOnce( - AnvilInstance, + ethers::utils::AnvilInstance, Provider, SignerMiddleware, LocalWallet>, SmartContracts, ) -> Fut, Fut: futures::Future, { + use ethers::signers::Signer; + use ethers::utils::Anvil; + use std::sync::Arc; let anvil = Anvil::new().args(vec!["--base-fee", "100"]).spawn(); let contract_deployer: LocalWallet = anvil.keys()[9].clone().into(); let provider = Provider::::try_from(anvil.endpoint()).unwrap(); diff --git a/xmtp_mls/src/groups/message_history.rs b/xmtp_mls/src/groups/message_history.rs index 6658c85d7..1dc1c45b1 100644 --- a/xmtp_mls/src/groups/message_history.rs +++ b/xmtp_mls/src/groups/message_history.rs @@ -1445,8 +1445,16 @@ pub(crate) mod tests { // try to join amal's sync group let sync_group_id = amal_sync_groups[0].id.clone(); - let group = amal.group(sync_group_id).expect("get group"); - let result = group.add_members(vec![external_wallet.get_address()]).await; + let created_at_ns = amal_sync_groups[0].created_at_ns; + + let external_client_group = MlsGroup::new( + external_client.clone(), + sync_group_id.clone(), + created_at_ns, + ); + let result = external_client_group + .add_members(vec![external_wallet.get_address()]) + .await; assert!(result.is_err()); } From 033f31f0731200a1a9c1cee50f69097272bbb2e1 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 11 Oct 2024 15:58:21 -0400 Subject: [PATCH 87/97] remove patch --- features.patch | 270 ------------------------------------------------- 1 file changed, 270 deletions(-) delete mode 100644 features.patch diff --git a/features.patch b/features.patch deleted file mode 100644 index 28b2ca9cc..000000000 --- a/features.patch +++ /dev/null @@ -1,270 +0,0 @@ -diff --git a/Cargo.toml b/Cargo.toml -index 61590654..12392f80 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -72,7 +72,7 @@ js-sys = "0.3" - # for i686-linux-android targets. https://github.com/sfackler/rust-openssl/issues/2163 - openssl-sys = "=0.9.92" - openssl = "=0.10.57" --libsqlite3-sys = { version = "0.29", features = ["bundled-sqlcipher-vendored-openssl" ] } -+libsqlite3-sys = { version = "0.29", features = ["bundled-sqlcipher-vendored-openssl"] } - - # Internal Crate Dependencies - xmtp_cryptography = { path = "xmtp_cryptography" } -diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml -index aefb3e62..2d591e95 100644 ---- a/bindings_ffi/Cargo.toml -+++ b/bindings_ffi/Cargo.toml -@@ -13,12 +13,12 @@ parking_lot.workspace = true - thiserror.workspace = true - thread-id = "4.2.1" - tokio = { workspace = true, features = ["macros"] } --uniffi = { version = "0.28.0", features = ["tokio", "cli"] } -+uniffi = { version = "0.28.0", features = ["cli", "tokio"] } - xmtp_api_grpc = { path = "../xmtp_api_grpc" } - xmtp_cryptography = { path = "../xmtp_cryptography" } - xmtp_id = { path = "../xmtp_id" } --xmtp_mls = { path = "../xmtp_mls", features = ["message-history"] } --xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } -+xmtp_mls = { path = "../xmtp_mls", version = "*", features = ["message-history"] } -+xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"], version = "*" } - xmtp_user_preferences = { path = "../xmtp_user_preferences" } - xmtp_v2 = { path = "../xmtp_v2" } - -@@ -36,5 +36,5 @@ rand = "0.8.5" - tokio = { version = "1.28.1", features = ["full"] } - tokio-test = "0.4" - uniffi = { version = "0.28.0", features = ["bindgen-tests"] } --uuid = { version = "1.9", features = ["v4", "fast-rng"] } --xmtp_mls = { path = "../xmtp_mls", features = ["test-utils"] } -+uuid = { version = "1.9", features = ["fast-rng", "v4"] } -+xmtp_mls = { path = "../xmtp_mls", version = "*", features = ["test-utils"] } -diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml -index cb3617ea..df2b130e 100644 ---- a/bindings_node/Cargo.toml -+++ b/bindings_node/Cargo.toml -@@ -10,19 +10,15 @@ crate-type = ["cdylib"] - # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix - hex.workspace = true - tracing.workspace = true --napi = { version = "2.12.2", default-features = false, features = [ -- "napi4", -- "napi6", -- "async", --] } -+napi = { version = "2.12.2", default-features = false, features = ["napi6", "tokio_rt"] } - napi-derive = "2.12.2" - prost.workspace = true --tokio = { workspace = true, features = ["full"]} -+tokio = { workspace = true, features = ["full"] } - xmtp_api_grpc = { path = "../xmtp_api_grpc" } - xmtp_cryptography = { path = "../xmtp_cryptography" } - xmtp_id = { path = "../xmtp_id" } --xmtp_mls = { path = "../xmtp_mls", features = ["message-history"]} --xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } -+xmtp_mls = { path = "../xmtp_mls", version = "*", features = ["message-history"] } -+xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"], version = "*" } - - [build-dependencies] - napi-build = "2.0.1" -diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml -index 31ef2be4..336f42a5 100644 ---- a/bindings_wasm/Cargo.toml -+++ b/bindings_wasm/Cargo.toml -@@ -14,7 +14,7 @@ wasm-bindgen-futures.workspace = true - xmtp_api_http = { path = "../xmtp_api_http" } - xmtp_cryptography = { path = "../xmtp_cryptography" } - xmtp_id = { path = "../xmtp_id" } --xmtp_mls = { path = "../xmtp_mls", features = ["message-history"] } -+xmtp_mls = { path = "../xmtp_mls", version = "*", features = ["message-history"] } - - [dev-dependencies] - wasm-bindgen-test.workspace = true -diff --git a/examples/cli/Cargo.toml b/examples/cli/Cargo.toml -index 5779b189..7644a4aa 100644 ---- a/examples/cli/Cargo.toml -+++ b/examples/cli/Cargo.toml -@@ -19,11 +19,7 @@ femme = "2.2.1" - futures.workspace = true - hex = "0.4.3" - kv-log-macro = "1.0.7" --log = { version = "0.4", features = [ -- "kv_unstable", -- "std", -- "kv_unstable_serde", --] } -+log = { version = "0.4", features = ["kv_unstable_serde"] } - prost.workspace = true - serde = { workspace = true, features = ["derive"] } - serde_json.workspace = true -@@ -33,5 +29,5 @@ tokio = "1.28.1" - xmtp_api_grpc = { path = "../../xmtp_api_grpc" } - xmtp_cryptography = { path = "../../xmtp_cryptography" } - xmtp_id = { path = "../../xmtp_id" } --xmtp_mls = { path = "../../xmtp_mls", features = ["message-history"]} --xmtp_proto = { path = "../../xmtp_proto", features = ["proto_full"] } -+xmtp_mls = { path = "../../xmtp_mls", version = "*", features = ["message-history"] } -+xmtp_proto = { path = "../../xmtp_proto", features = ["proto_full"], version = "*" } -diff --git a/mls_validation_service/Cargo.toml b/mls_validation_service/Cargo.toml -index 11d5cf2b..398af90d 100644 ---- a/mls_validation_service/Cargo.toml -+++ b/mls_validation_service/Cargo.toml -@@ -20,10 +20,7 @@ tonic = { workspace = true } - warp = "0.3.6" - xmtp_id.workspace = true - xmtp_mls.workspace = true --xmtp_proto = { path = "../xmtp_proto", features = [ -- "proto_full", -- "convert", --] } -+xmtp_proto = { path = "../xmtp_proto", features = ["convert"], version = "*" } - tracing.workspace = true - tracing-subscriber = { workspace = true, features = ["env-filter"] } - -diff --git a/xmtp_api_grpc/Cargo.toml b/xmtp_api_grpc/Cargo.toml -index 017de33b..3bcf93a1 100644 ---- a/xmtp_api_grpc/Cargo.toml -+++ b/xmtp_api_grpc/Cargo.toml -@@ -10,13 +10,9 @@ futures.workspace = true - hex.workspace = true - prost = { workspace = true, features = ["prost-derive"] } - tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } --tonic = { workspace = true, features = [ -- "tls", -- "tls-native-roots", -- "tls-webpki-roots", --] } -+tonic = { workspace = true, features = ["tls-native-roots", "tls-webpki-roots"] } - tracing.workspace = true --xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } -+xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"], version = "*" } - xmtp_v2 = { path = "../xmtp_v2" } - - [dev-dependencies] -diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml -index 66a6b272..ffe448f7 100644 ---- a/xmtp_api_http/Cargo.toml -+++ b/xmtp_api_http/Cargo.toml -@@ -14,8 +14,8 @@ reqwest = { version = "0.12.5", features = ["json", "stream"] } - serde = { workspace = true } - serde_json = { workspace = true } - thiserror = "1.0" --tokio = { workspace = true, features = ["sync", "rt", "macros"] } --xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } -+tokio = { workspace = true, features = ["macros", "rt", "sync"] } -+xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"], version = "*" } - - [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] - tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } -diff --git a/xmtp_cryptography/Cargo.toml b/xmtp_cryptography/Cargo.toml -index 14c5e3a0..e5e29843 100644 ---- a/xmtp_cryptography/Cargo.toml -+++ b/xmtp_cryptography/Cargo.toml -@@ -26,4 +26,4 @@ getrandom = { workspace = true, features = ["js"] } - ws = ["ethers/ws"] - - [dev-dependencies] --tokio = { version = "1.28.1", features = ["rt", "macros"] } -+tokio = { version = "1.28.1", features = ["macros", "rt"] } -diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml -index 1cb6c6b1..6ce1d90e 100644 ---- a/xmtp_mls/Cargo.toml -+++ b/xmtp_mls/Cargo.toml -@@ -35,7 +35,7 @@ rand = { workspace = true } - serde = { workspace = true } - serde_json.workspace = true - thiserror = { workspace = true } --tokio-stream = { version = "0.1", features = ["sync"] } -+tokio-stream = { version = "0.1", features = ["sync"] } - async-trait.workspace = true - futures.workspace = true - reqwest = { version = "0.12.4", features = ["stream"] } -@@ -45,7 +45,7 @@ wasm-timer.workspace = true - # XMTP/Local - xmtp_cryptography = { workspace = true } - xmtp_id = { path = "../xmtp_id" } --xmtp_proto = { workspace = true, features = ["proto_full", "convert"] } -+xmtp_proto = { workspace = true, features = ["convert"] } - - # Optional/Features - toml = { version = "0.8.4", optional = true } -@@ -58,7 +58,7 @@ indicatif = { version = "0.17", optional = true } - anyhow = { workspace = true, optional = true } - tracing-flame = { version = "0.2", optional = true } - once_cell = { version = "1.19", optional = true } --criterion = { version = "0.5", features = ["html_reports", "async_tokio"], optional = true } -+criterion = { version = "0.5", features = ["async_tokio", "html_reports"], optional = true } - - - [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -@@ -66,29 +66,22 @@ criterion = { version = "0.5", features = ["html_reports", "async_tokio"], optio - libsqlite3-sys = { workspace = true } - openssl-sys.workspace = true - openssl.workspace = true --diesel = { workspace = true, features = [ -- "r2d2", -- "returning_clauses_for_sqlite_3_35", -- "sqlite", --] } -+diesel = { workspace = true, features = ["r2d2", "returning_clauses_for_sqlite_3_35", "sqlite"] } - xmtp_api_grpc = { path = "../xmtp_api_grpc", optional = true } - chrono = { workspace = true, features = ["clock"] } --tokio = { workspace = true, features = ["macros", "tracing", "rt", "rt-multi-thread"] } -+tokio = { workspace = true, features = ["macros", "rt-multi-thread", "tracing"] } - diesel_migrations = { workspace = true, features = ["sqlite"] } - openmls = { workspace = true, features = ["test-utils"] } - - - [target.'cfg(target_arch = "wasm32")'.dependencies] - diesel-wasm-sqlite = { workspace = true, features = ["r2d2"] } --diesel = { workspace = true, features = [ -- "r2d2", -- "returning_clauses_for_sqlite_3_35", --] } -+diesel = { workspace = true, features = ["r2d2", "returning_clauses_for_sqlite_3_35"] } - diesel_migrations.workspace = true - getrandom = { workspace = true, features = ["js"] } - chrono = { workspace = true, features = ["wasmbind"] } - tokio = { workspace = true, features = ["macros", "rt"] } --openmls = { workspace = true, features = ["test-utils", "js"] } -+openmls = { workspace = true, features = ["js", "test-utils"] } - gloo-timers = { workspace = true, features = ["futures"] } - wasm-bindgen-futures.workspace = true - web-sys.workspace = true -@@ -96,7 +89,7 @@ web-sys.workspace = true - [dev-dependencies] - ethers.workspace = true - mockall = "0.13.0" --xmtp_id = { path = "../xmtp_id", features = ["test-utils"] } -+xmtp_id = { path = "../xmtp_id", version = "*", features = ["test-utils"] } - anyhow.workspace = true - tracing-subscriber = { workspace = true, features = ["env-filter"] } - -@@ -110,7 +103,7 @@ ctor.workspace = true - [target.'cfg(target_arch = "wasm32")'.dev-dependencies] - xmtp_api_http = { path = "../xmtp_api_http" } - tracing-wasm = { version = "0.2" } --diesel-wasm-sqlite = { workspace = true, features = ["unsafe-debug-query", "r2d2"] } -+diesel-wasm-sqlite = { workspace = true, features = ["r2d2", "unsafe-debug-query"] } - console_error_panic_hook = { version = "0.1"} - wasm-bindgen-test.workspace = true - tracing-subscriber = { workspace = true, features = ["env-filter"] } -diff --git a/xmtp_user_preferences/Cargo.toml b/xmtp_user_preferences/Cargo.toml -index 7f7ba0f2..f3e6a659 100644 ---- a/xmtp_user_preferences/Cargo.toml -+++ b/xmtp_user_preferences/Cargo.toml -@@ -7,12 +7,9 @@ version.workspace = true - base64 = "0.22.1" - # Need to include this as a dep or compile will fail because of a version mismatch - prost = { workspace = true, features = ["prost-derive"] } --xmtp_proto = { path = "../xmtp_proto", features = ["xmtp-message_contents"] } -+xmtp_proto = { path = "../xmtp_proto", version = "*", features = ["xmtp-message_contents"] } - xmtp_v2 = { path = "../xmtp_v2" } - - [dev-dependencies] --libsecp256k1 = { version = "0.7.1", default-features = false, features = [ -- "hmac", -- "static-context", --] } -+libsecp256k1 = { version = "0.7.1", default-features = false, features = ["hmac", "static-context"] } - rand = "0.8.5" From fce85c00cb00481f374669cc24afb08671a3830a Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 11 Oct 2024 16:32:50 -0400 Subject: [PATCH 88/97] fix ci --- .github/workflows/test-webassembly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index 71afd027b..51005528d 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -38,7 +38,7 @@ jobs: run: cargo build --tests --release --target wasm32-unknown-unknown -p xmtp_id -p xmtp_mls -p xmtp_api_http -p xmtp_cryptography - name: test with chrome run: | - cargo test --release --target wasm32-unknown-unknown -p xmtp_mls -p xmtp_id -p xmtp_api_http -p xmtp_cryptography \ + cargo test --release --target wasm32-unknown-unknown -p xmtp_mls -p xmtp_id -p xmtp_api_http -p xmtp_cryptography -- \ --skip xmtp_mls::subscriptions --skip xmtp_mls::groups::subscriptions \ --skip xmtp_mls::storage::encrypted_store::group_message::tests::it_cannot_insert_message_without_group \ --skip xmtp_mls::groups::tests::process_messages_abort_on_retryable_error \ From 3242eb78ec8a06c62cf2f95beef827f4cd82f43e Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 11 Oct 2024 16:42:01 -0400 Subject: [PATCH 89/97] update diesel-wasm-sqlite --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 234a169a5..10937045f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "diesel-wasm-sqlite" version = "0.0.1" -source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#77b1e2ebff3dc0aeb645aa130175745aedc3346e" +source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#eac6c9064f346b32e226379d60c624d9424e08bb" dependencies = [ "diesel", "diesel_derives", From 24a691740fd668ab581a3cdc29e2718ab636ed36 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 15 Oct 2024 12:14:29 -0400 Subject: [PATCH 90/97] add split linked modules environment variable --- .github/workflows/test-webassembly.yml | 5 ++-- Cargo.lock | 33 +++++++++++++------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index 51005528d..dcfbf3c8b 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -17,6 +17,7 @@ env: CARGO_TERM_COLOR: always WASM_BINDGEN_TEST_TIMEOUT: 120 WASM_BINDGEN_TEST_ONLY_WEB: 1 + WASM_BINDGEN_SPLIT_LINKED_MODULES: 1 jobs: test: name: Test @@ -24,9 +25,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - uses: jetli/wasm-bindgen-action@v0.2.0 - with: - version: 'latest' + - uses: taiki-e/install-action@wasm-bindgen - name: Cache uses: Swatinem/rust-cache@v2 with: diff --git a/Cargo.lock b/Cargo.lock index 10937045f..a5caa0e37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -638,9 +638,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.29" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e804ac3194a48bb129643eb1d62fcc20d18c6b8c181704489353d13120bcd1" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", @@ -1173,7 +1173,7 @@ dependencies = [ [[package]] name = "diesel" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" +source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" dependencies = [ "diesel_derives", "downcast-rs", @@ -1185,7 +1185,6 @@ dependencies = [ [[package]] name = "diesel-wasm-sqlite" version = "0.0.1" -source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#eac6c9064f346b32e226379d60c624d9424e08bb" dependencies = [ "diesel", "diesel_derives", @@ -1203,7 +1202,7 @@ dependencies = [ [[package]] name = "diesel_derives" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" +source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", @@ -1215,7 +1214,7 @@ dependencies = [ [[package]] name = "diesel_migrations" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" +source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" dependencies = [ "diesel", "migrations_internals", @@ -1225,7 +1224,7 @@ dependencies = [ [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" +source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" dependencies = [ "syn 2.0.79", ] @@ -1308,7 +1307,7 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dsl_auto_type" version = "0.1.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" +source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" dependencies = [ "darling", "either", @@ -2942,7 +2941,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -3081,7 +3080,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" +source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" dependencies = [ "serde", "toml 0.8.19", @@ -3090,7 +3089,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#9ed7de24c0b9a0afce8dbae845316d74fb795258" +source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" dependencies = [ "migrations_internals", "proc-macro2", @@ -3253,9 +3252,9 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "napi" -version = "2.16.11" +version = "2.16.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53575dfa17f208dd1ce3a2da2da4659aae393b256a472f2738a8586a6c4107fd" +checksum = "3a84fdaf64da2b2d86b1be5db1b81963353bf00f7bef4b9e2668bbe6f72e8eb3" dependencies = [ "bitflags 2.6.0", "ctor", @@ -4663,9 +4662,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -4690,9 +4689,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" From fd4b02cb3f72c3a6c935d6829f555c6931ba9895 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 15 Oct 2024 16:20:12 -0400 Subject: [PATCH 91/97] remove tracing init from tests --- Cargo.lock | 75 +++++++++++++++++++++++++++ xmtp_mls/src/groups/group_metadata.rs | 3 +- xmtp_mls/src/groups/mod.rs | 1 - 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a62faa38..c32202839 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -827,6 +827,33 @@ dependencies = [ "thiserror", ] +[[package]] +name = "color-eyre" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colorchoice" version = "1.0.2" @@ -3656,6 +3683,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + [[package]] name = "p256" version = "0.13.2" @@ -5843,6 +5876,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", ] [[package]] @@ -6227,6 +6271,12 @@ dependencies = [ "rand", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "value-bag" version = "1.9.0" @@ -7002,6 +7052,31 @@ dependencies = [ "xmtp_v2", ] +[[package]] +name = "xshell" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" + +[[package]] +name = "xtask" +version = "0.0.1" +dependencies = [ + "color-eyre", + "tracing", + "tracing-subscriber", + "xshell", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/xmtp_mls/src/groups/group_metadata.rs b/xmtp_mls/src/groups/group_metadata.rs index 2fc55a9b0..920450d43 100644 --- a/xmtp_mls/src/groups/group_metadata.rs +++ b/xmtp_mls/src/groups/group_metadata.rs @@ -50,8 +50,7 @@ impl TryFrom for Vec { type Error = GroupMetadataError; fn try_from(value: GroupMetadata) -> Result { - let conversation_type: ConversationTypeProto = value.conversation_type.into( - ); + let conversation_type: ConversationTypeProto = value.conversation_type.into(); let proto_val = GroupMetadataProto { conversation_type: conversation_type as i32, creator_inbox_id: value.creator_inbox_id.clone(), diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index c95feb0c8..f2e691c9a 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -2133,7 +2133,6 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_add_missing_installations() { - crate::utils::wasm::init().await; // Setup for test let amal_wallet = generate_local_wallet(); let amal = ClientBuilder::new_test_client(&amal_wallet).await; From fe27ed178bec888d4920fd1a88891249e4e24495 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 16 Oct 2024 10:06:29 -0400 Subject: [PATCH 92/97] clean up subscriptions a little more --- .cargo/config.toml | 3 +++ Cargo.lock | 1 + xmtp_cryptography/Cargo.toml | 3 +++ xmtp_id/Cargo.toml | 3 +++ xmtp_mls/Cargo.toml | 2 +- xmtp_mls/src/lib.rs | 2 +- xmtp_mls/src/subscriptions.rs | 8 +------- xmtp_v2/Cargo.toml | 4 +++- 8 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 4ec2f3b86..c99b3e6e4 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,5 @@ [target.wasm32-unknown-unknown] runner = 'wasm-bindgen-test-runner' + +[alias] +xtask = "run --package xtask --" diff --git a/Cargo.lock b/Cargo.lock index 8a62faa38..6f03589df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6971,6 +6971,7 @@ dependencies = [ "aes-gcm", "ecdsa 0.15.1", "generic-array", + "getrandom", "hex", "hkdf", "k256 0.12.0", diff --git a/xmtp_cryptography/Cargo.toml b/xmtp_cryptography/Cargo.toml index 59f82cb3d..118b6bf28 100644 --- a/xmtp_cryptography/Cargo.toml +++ b/xmtp_cryptography/Cargo.toml @@ -4,6 +4,9 @@ name = "xmtp_cryptography" rust-version = "1.70" version.workspace = true +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown", "aarch64-apple-darwin"] + [dependencies] tracing.workspace = true curve25519-dalek = "4" diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index 2801b7329..9210c997d 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -3,6 +3,9 @@ edition = "2021" name = "xmtp_id" version.workspace = true +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown", "aarch64-apple-darwin"] + [dependencies] url = { workspace = true, features = ["serde"] } async-trait.workspace = true diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index be11c2ac2..f30977038 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -48,9 +48,9 @@ xmtp_id = { path = "../xmtp_id" } xmtp_proto = { workspace = true, features = ["convert"] } # Optional/Features +xmtp_api_http = { path = "../xmtp_api_http", optional = true } toml = { version = "0.8.4", optional = true } tracing-wasm = { version = "0.2", optional = true } -xmtp_api_http = { path = "../xmtp_api_http", optional = true } reqwest = { version = "0.12.4", features = ["stream"], optional = true } console_error_panic_hook = { version = "0.1", optional = true } diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 757da0351..b1f0d788a 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -71,7 +71,7 @@ pub async fn sleep(duration: core::time::Duration) { tokio::time::sleep(duration).await } -/// Turn the Result into an `Option`, logging the error with `tracing::error` and +/// Turn the `Result` into an `Option`, logging the error with `tracing::error` and /// returning `None` if the value matches on Result::Err(). /// Optionally pass a message as the second argument. #[macro_export] diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 3408219b7..752ad109c 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -165,13 +165,7 @@ where let metadata = crate::optify!(group.metadata(provider), "error processing group metadata"); metadata - .filter(|m| { - if &Some(m.conversation_type) == conversation_type { - true - } else { - conversation_type.is_none() - } - }) + .filter(|m| conversation_type.map_or(true, |ct| ct == m.conversation_type)) .map(|_| group) }; diff --git a/xmtp_v2/Cargo.toml b/xmtp_v2/Cargo.toml index 20573e1e0..2f78a864a 100644 --- a/xmtp_v2/Cargo.toml +++ b/xmtp_v2/Cargo.toml @@ -8,7 +8,6 @@ version.workspace = true aes-gcm = "0.10.1" ecdsa = "0.15.1" generic-array = "0.14.6" -# getrandom = { workspace = true, features = ["js"] } hex = { workspace = true } hkdf = "0.12.3" k256 = { version = "0.12.0", features = ["ecdh"] } @@ -16,4 +15,7 @@ rand = { workspace = true } sha2 = "0.10.6" sha3 = "0.10.6" +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { workspace = true, features = ["js"] } + [dev-dependencies] From f8f89a0ac2395bd594dd72883c423ff89bc59ced Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Wed, 16 Oct 2024 15:10:21 -0400 Subject: [PATCH 93/97] lint --- .../src/scw_verifier/chain_rpc_verifier.rs | 29 +------------------ xmtp_mls/src/builder.rs | 5 ++-- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs b/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs index 687d21d59..a8d47f929 100644 --- a/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs +++ b/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs @@ -120,11 +120,7 @@ pub(crate) mod tests { use super::*; use ethers::{ abi::{self, Token}, - core::{ - k256::{elliptic_curve::SecretKey, Secp256k1}, - utils::Anvil, - }, - middleware::{MiddlewareBuilder, SignerMiddleware}, + middleware::MiddlewareBuilder, signers::{LocalWallet, Signer as _}, types::{H256, U256}, utils::hash_message, @@ -142,29 +138,6 @@ pub(crate) mod tests { derives(serde::Serialize, serde::Deserialize) ); - pub struct SmartContracts { - coinbase_smart_wallet_factory: - CoinbaseSmartWalletFactory, LocalWallet>>, - } - - impl SmartContracts { - fn new( - coinbase_smart_wallet_factory: CoinbaseSmartWalletFactory< - SignerMiddleware, LocalWallet>, - >, - ) -> Self { - Self { - coinbase_smart_wallet_factory, - } - } - - pub fn coinbase_smart_wallet_factory( - &self, - ) -> &CoinbaseSmartWalletFactory, LocalWallet>> { - &self.coinbase_smart_wallet_factory - } - } - #[tokio::test] async fn test_coinbase_smart_wallet() { with_smart_contracts(|anvil, provider, client, smart_contracts| { diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 44b54683b..71377901b 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -766,11 +766,10 @@ pub(crate) mod tests { }; use std::sync::Arc; use xmtp_id::associations::AccountId; - use xmtp_id::scw_verifier::MultiSmartContractSignatureVerifier; - use xmtp_id::utils::test::{with_smart_contracts, CoinbaseSmartWallet}; + use xmtp_id::utils::test::CoinbaseSmartWallet; use xmtp_id::{ associations::unverified::NewUnverifiedSmartContractWalletSignature, - scw_verifier::tests::with_docker_smart_contracts, + utils::test::with_docker_smart_contracts, }; with_docker_smart_contracts( From 055d2d18c7a743419c997b1fa9302a0c9613a032 Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Wed, 16 Oct 2024 15:14:28 -0400 Subject: [PATCH 94/97] lint --- xmtp_mls/src/builder.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 71377901b..f581415d7 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -790,20 +790,6 @@ pub(crate) mod tests { contract_call.send().await.unwrap().await.unwrap(); let account_id = AccountId::new_evm(anvil_meta.chain_id, format!("{scw_addr:?}")); - let account_id_string: String = account_id.clone().into(); - - let identity_strategy = IdentityStrategy::CreateIfNotFound( - generate_inbox_id(&account_id_string, &0), - account_id_string, - 0, - None, - ); - let store = EncryptedMessageStore::new( - StorageOption::Persistent(tmp_path()), - EncryptedMessageStore::generate_enc_key(), - ) - .await - .unwrap(); let xmtp_client = ClientBuilder::new_local_client(&wallet).await; @@ -829,10 +815,10 @@ pub(crate) mod tests { .add_new_unverified_smart_contract_signature( NewUnverifiedSmartContractWalletSignature::new( signature_bytes.to_vec(), - account_id.clone(), + account_id, None, ), - xmtp_client.context.scw_verifier.as_ref(), + &xmtp_client.scw_verifier, ) .await .unwrap(); From c92b3adccf31f246d9b91027fc64e4a80e353c57 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 16 Oct 2024 18:57:37 -0400 Subject: [PATCH 95/97] fix failing scw test --- Cargo.lock | 521 ++++++++++++++++++++++++++++++++- Cargo.toml | 1 + xmtp_cryptography/Cargo.toml | 4 + xmtp_cryptography/src/lib.rs | 6 + xmtp_mls/src/builder.rs | 18 +- xmtp_mls/src/utils/test/mod.rs | 9 + xmtp_proto/Cargo.toml | 5 +- xmtp_proto/src/lib.rs | 6 + 8 files changed, 559 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f03589df..1e50e115b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,6 +162,15 @@ version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -297,6 +306,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "auto_impl" version = "1.2.0" @@ -427,6 +447,24 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "binary-install" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5252e41a4ed7657f79827123f232443077984ec55c540adf48e8fe67b6ec0763" +dependencies = [ + "anyhow", + "dirs-next", + "flate2", + "fs4", + "hex", + "is_executable", + "siphasher", + "tar", + "ureq", + "zip 2.2.0", +] + [[package]] name = "bincode" version = "1.3.3" @@ -754,7 +792,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", ] [[package]] @@ -827,6 +865,33 @@ dependencies = [ "thiserror", ] +[[package]] +name = "color-eyre" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colorchoice" version = "1.0.2" @@ -891,6 +956,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "convert_case" version = "0.6.0" @@ -925,6 +996,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.2" @@ -1114,7 +1200,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", "syn 2.0.79", ] @@ -1135,6 +1221,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "deflate64" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + [[package]] name = "der" version = "0.6.1" @@ -1165,6 +1257,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "derive_more" version = "0.99.18" @@ -1176,6 +1279,18 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "dialoguer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +dependencies = [ + "console", + "shell-words", + "tempfile", + "zeroize", +] + [[package]] name = "diesel" version = "2.2.0" @@ -1299,6 +1414,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "downcast" version = "0.11.0" @@ -1478,6 +1604,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1881,6 +2016,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "fixed-hash" version = "0.8.0" @@ -1979,6 +2126,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs4" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "funty" version = "2.0.0" @@ -2305,6 +2462,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.9" @@ -2482,6 +2648,22 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "human-panic" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f016c89920bbb30951a8405ecacbb4540db5524313b9445736e7e1855cf370" +dependencies = [ + "anstream", + "anstyle", + "backtrace", + "os_info", + "serde", + "serde_derive", + "toml 0.8.19", + "uuid 1.10.0", +] + [[package]] name = "hyper" version = "0.14.31" @@ -2773,6 +2955,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_executable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577" +dependencies = [ + "winapi", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -2965,6 +3156,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", + "redox_syscall 0.5.7", ] [[package]] @@ -3043,6 +3235,12 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "lockfree-object-pool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" + [[package]] name = "log" version = "0.4.22" @@ -3053,6 +3251,16 @@ dependencies = [ "value-bag", ] +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder", + "crc", +] + [[package]] name = "matchers" version = "0.1.0" @@ -3650,12 +3858,29 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "os_info" +version = "3.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +dependencies = [ + "log", + "serde", + "windows-sys 0.52.0", +] + [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + [[package]] name = "p256" version = "0.13.2" @@ -3769,6 +3994,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "path-clean" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" + [[package]] name = "path-slash" version = "0.2.1" @@ -4136,7 +4367,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit", + "toml_edit 0.22.22", ] [[package]] @@ -4941,6 +5172,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_ignored" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8e319a36d1b52126a0d608f24e93b2d81297091818cd70625fcf50a15d84ddf" +dependencies = [ + "serde", +] + [[package]] name = "serde_json" version = "1.0.128" @@ -5028,6 +5268,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "shlex" version = "1.3.0" @@ -5053,6 +5299,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "similar" version = "2.6.0" @@ -5134,6 +5386,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spinach" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb127edbed8b91951c7a35237d0c4ba5f01338bb11ecc2a75e5a93365b24302" + [[package]] name = "spki" version = "0.6.0" @@ -5173,6 +5431,12 @@ dependencies = [ "precomputed-hash", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.1" @@ -5302,7 +5566,7 @@ dependencies = [ "sha2 0.10.8", "thiserror", "url", - "zip", + "zip 0.6.6", ] [[package]] @@ -5399,6 +5663,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.13.0" @@ -5699,6 +5974,18 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + [[package]] name = "toml" version = "0.8.19" @@ -5708,7 +5995,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.22.22", ] [[package]] @@ -5720,6 +6007,19 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.6.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.40", +] + [[package]] name = "toml_edit" version = "0.22.22" @@ -5730,7 +6030,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.20", ] [[package]] @@ -5843,6 +6143,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", ] [[package]] @@ -6183,6 +6494,24 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +dependencies = [ + "base64 0.22.1", + "flate2", + "log", + "once_cell", + "rustls 0.23.14", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.6", +] + [[package]] name = "url" version = "2.5.2" @@ -6227,6 +6556,12 @@ dependencies = [ "rand", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "value-bag" version = "1.9.0" @@ -6424,6 +6759,39 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "wasm-pack" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcb9f254996b4bbce2c7d738273739ce515834a49b1910e85a6a3fee5b6405d" +dependencies = [ + "anyhow", + "atty", + "binary-install", + "cargo_metadata 0.15.4", + "chrono", + "clap", + "console", + "dialoguer", + "env_logger", + "glob", + "human-panic", + "log", + "parking_lot 0.12.3", + "path-clean", + "semver", + "serde", + "serde_derive", + "serde_ignored", + "serde_json", + "siphasher", + "strsim 0.10.0", + "toml 0.7.8", + "ureq", + "walkdir", + "which", +] + [[package]] name = "wasm-streams" version = "0.4.1" @@ -6486,6 +6854,18 @@ dependencies = [ "nom", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "winapi" version = "0.3.9" @@ -6704,6 +7084,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.6.20" @@ -6763,6 +7152,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "xflags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9e15fbb3de55454b0106e314b28e671279009b363e6f1d8e39fdc3bf048944" +dependencies = [ + "xflags-macros", +] + +[[package]] +name = "xflags-macros" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155" + [[package]] name = "xmtp_api_grpc" version = "0.0.1" @@ -6950,6 +7365,7 @@ dependencies = [ "serde", "tonic", "trait-variant", + "wasm-bindgen-test", ] [[package]] @@ -7003,6 +7419,32 @@ dependencies = [ "xmtp_v2", ] +[[package]] +name = "xshell" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" + +[[package]] +name = "xtask" +version = "0.0.1" +dependencies = [ + "color-eyre", + "spinach", + "wasm-pack", + "xflags", + "xshell", +] + [[package]] name = "yansi" version = "0.5.1" @@ -7059,7 +7501,7 @@ dependencies = [ "aes", "byteorder", "bzip2", - "constant_time_eq", + "constant_time_eq 0.1.5", "crc32fast", "crossbeam-utils", "flate2", @@ -7067,7 +7509,50 @@ dependencies = [ "pbkdf2 0.11.0", "sha1", "time", - "zstd", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zip" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" +dependencies = [ + "aes", + "arbitrary", + "bzip2", + "constant_time_eq 0.3.1", + "crc32fast", + "crossbeam-utils", + "deflate64", + "displaydoc", + "flate2", + "hmac 0.12.1", + "indexmap 2.6.0", + "lzma-rs", + "memchr", + "pbkdf2 0.12.2", + "rand", + "sha1", + "thiserror", + "time", + "zeroize", + "zopfli", + "zstd 0.13.2", +] + +[[package]] +name = "zopfli" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +dependencies = [ + "bumpalo", + "crc32fast", + "lockfree-object-pool", + "log", + "once_cell", + "simd-adler32", ] [[package]] @@ -7076,7 +7561,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe 7.2.1", ] [[package]] @@ -7089,6 +7583,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.13+zstd.1.5.6" diff --git a/Cargo.toml b/Cargo.toml index 22cf9869e..700f2c267 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "bindings_wasm", "bindings_node", "bindings_ffi", + "xtask" ] # Make the feature resolver explicit. diff --git a/xmtp_cryptography/Cargo.toml b/xmtp_cryptography/Cargo.toml index 118b6bf28..c6c82b2a5 100644 --- a/xmtp_cryptography/Cargo.toml +++ b/xmtp_cryptography/Cargo.toml @@ -32,3 +32,7 @@ ws = ["ethers/ws"] [dev-dependencies] tokio = { version = "1.28.1", features = ["rt", "macros"] } + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test.workspace = true + diff --git a/xmtp_cryptography/src/lib.rs b/xmtp_cryptography/src/lib.rs index 42327bc87..0e26c257a 100644 --- a/xmtp_cryptography/src/lib.rs +++ b/xmtp_cryptography/src/lib.rs @@ -1,3 +1,9 @@ pub mod hash; pub mod signature; pub mod utils; + +#[cfg(test)] +pub mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); +} diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index f581415d7..b304bde01 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -790,13 +790,29 @@ pub(crate) mod tests { contract_call.send().await.unwrap().await.unwrap(); let account_id = AccountId::new_evm(anvil_meta.chain_id, format!("{scw_addr:?}")); + let account_id_string: String = account_id.clone().into(); - let xmtp_client = ClientBuilder::new_local_client(&wallet).await; + let identity_strategy = IdentityStrategy::CreateIfNotFound( + generate_inbox_id(&account_id_string, &0), + account_id_string, + 0, + None, + ); + + let xmtp_client = Client::::builder(identity_strategy) + .temp_store() + .await + .local_client() + .await + .build() + .await + .unwrap(); let smart_wallet = CoinbaseSmartWallet::new( scw_addr, Arc::new(client.with_signer(wallet.clone().with_chain_id(anvil_meta.chain_id))), ); + let mut signature_request = xmtp_client.context.signature_request().unwrap(); let signature_text = signature_request.signature_text(); let hash_to_sign = hash_message(signature_text); diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index 734da0a8a..8e9801d5e 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -150,6 +150,15 @@ impl ClientBuilder { ) .await } + + /// Add the local client to this builder + pub async fn local_client(self) -> Self { + self.api_client(::create_local().await) + } + + pub async fn dev_client(self) -> Self { + self.api_client(::create_dev().await) + } } async fn inner_build(owner: impl InboxOwner, api_client: &A, scw_verifier: V) -> Client diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index 0a20bdaae..108923546 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -15,6 +15,9 @@ trait-variant = "0.1.2" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tonic = { workspace = true } +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test.workspace = true + [features] convert = ["openmls", "proto_full"] test-utils = [] @@ -35,4 +38,4 @@ proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations "xmtp-mls-message_contents" = [] "xmtp-mls_validation-v1" = ["xmtp-identity-api-v1","xmtp-identity-associations"] "xmtp-xmtpv4" = ["xmtp-identity-associations","xmtp-mls-api-v1"] -## @@protoc_insertion_point(features) \ No newline at end of file +## @@protoc_insertion_point(features) diff --git a/xmtp_proto/src/lib.rs b/xmtp_proto/src/lib.rs index 5ca38f761..9e398ac76 100644 --- a/xmtp_proto/src/lib.rs +++ b/xmtp_proto/src/lib.rs @@ -9,3 +9,9 @@ pub mod api_client; #[cfg(feature = "convert")] pub mod convert; + +#[cfg(test)] +pub mod test { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); +} From 80d8feb82db3a8915d0b52ef3a5e20dd3907f7d9 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 16 Oct 2024 18:58:06 -0400 Subject: [PATCH 96/97] remove xtask --- Cargo.lock | 520 +---------------------------------------------------- Cargo.toml | 1 - 2 files changed, 9 insertions(+), 512 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e50e115b..ca861666b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,15 +162,6 @@ version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" -[[package]] -name = "arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "arrayref" version = "0.3.9" @@ -306,17 +297,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "auto_impl" version = "1.2.0" @@ -447,24 +427,6 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" -[[package]] -name = "binary-install" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252e41a4ed7657f79827123f232443077984ec55c540adf48e8fe67b6ec0763" -dependencies = [ - "anyhow", - "dirs-next", - "flate2", - "fs4", - "hex", - "is_executable", - "siphasher", - "tar", - "ureq", - "zip 2.2.0", -] - [[package]] name = "bincode" version = "1.3.3" @@ -792,7 +754,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.1", + "strsim", ] [[package]] @@ -865,33 +827,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "color-eyre" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - [[package]] name = "colorchoice" version = "1.0.2" @@ -956,12 +891,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - [[package]] name = "convert_case" version = "0.6.0" @@ -996,21 +925,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - [[package]] name = "crc32fast" version = "1.4.2" @@ -1200,7 +1114,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.11.1", + "strsim", "syn 2.0.79", ] @@ -1221,12 +1135,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" -[[package]] -name = "deflate64" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" - [[package]] name = "der" version = "0.6.1" @@ -1257,17 +1165,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "derive_arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "derive_more" version = "0.99.18" @@ -1279,18 +1176,6 @@ dependencies = [ "syn 2.0.79", ] -[[package]] -name = "dialoguer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" -dependencies = [ - "console", - "shell-words", - "tempfile", - "zeroize", -] - [[package]] name = "diesel" version = "2.2.0" @@ -1414,17 +1299,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "downcast" version = "0.11.0" @@ -1604,15 +1478,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "log", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -2016,18 +1881,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - [[package]] name = "fixed-hash" version = "0.8.0" @@ -2126,16 +1979,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "fs4" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" -dependencies = [ - "rustix", - "windows-sys 0.48.0", -] - [[package]] name = "funty" version = "2.0.0" @@ -2462,15 +2305,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.9" @@ -2648,22 +2482,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "human-panic" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f016c89920bbb30951a8405ecacbb4540db5524313b9445736e7e1855cf370" -dependencies = [ - "anstream", - "anstyle", - "backtrace", - "os_info", - "serde", - "serde_derive", - "toml 0.8.19", - "uuid 1.10.0", -] - [[package]] name = "hyper" version = "0.14.31" @@ -2955,15 +2773,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "is_executable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577" -dependencies = [ - "winapi", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -3156,7 +2965,6 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.7", ] [[package]] @@ -3235,12 +3043,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" version = "0.4.22" @@ -3251,16 +3053,6 @@ dependencies = [ "value-bag", ] -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder", - "crc", -] - [[package]] name = "matchers" version = "0.1.0" @@ -3858,29 +3650,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "os_info" -version = "3.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" -dependencies = [ - "log", - "serde", - "windows-sys 0.52.0", -] - [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - [[package]] name = "p256" version = "0.13.2" @@ -3994,12 +3769,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "path-clean" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" - [[package]] name = "path-slash" version = "0.2.1" @@ -4367,7 +4136,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.22", + "toml_edit", ] [[package]] @@ -5172,15 +4941,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_ignored" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e319a36d1b52126a0d608f24e93b2d81297091818cd70625fcf50a15d84ddf" -dependencies = [ - "serde", -] - [[package]] name = "serde_json" version = "1.0.128" @@ -5268,12 +5028,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shell-words" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" - [[package]] name = "shlex" version = "1.3.0" @@ -5299,12 +5053,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - [[package]] name = "similar" version = "2.6.0" @@ -5386,12 +5134,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spinach" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb127edbed8b91951c7a35237d0c4ba5f01338bb11ecc2a75e5a93365b24302" - [[package]] name = "spki" version = "0.6.0" @@ -5431,12 +5173,6 @@ dependencies = [ "precomputed-hash", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" @@ -5566,7 +5302,7 @@ dependencies = [ "sha2 0.10.8", "thiserror", "url", - "zip 0.6.6", + "zip", ] [[package]] @@ -5663,17 +5399,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "tar" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "tempfile" version = "3.13.0" @@ -5974,18 +5699,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.15", -] - [[package]] name = "toml" version = "0.8.19" @@ -5995,7 +5708,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit", ] [[package]] @@ -6007,19 +5720,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.6.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.22.22" @@ -6030,7 +5730,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow", ] [[package]] @@ -6143,17 +5843,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" -dependencies = [ - "tracing", - "tracing-subscriber", ] [[package]] @@ -6494,24 +6183,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" -dependencies = [ - "base64 0.22.1", - "flate2", - "log", - "once_cell", - "rustls 0.23.14", - "rustls-pki-types", - "serde", - "serde_json", - "url", - "webpki-roots 0.26.6", -] - [[package]] name = "url" version = "2.5.2" @@ -6556,12 +6227,6 @@ dependencies = [ "rand", ] -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "value-bag" version = "1.9.0" @@ -6759,39 +6424,6 @@ dependencies = [ "syn 2.0.79", ] -[[package]] -name = "wasm-pack" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcb9f254996b4bbce2c7d738273739ce515834a49b1910e85a6a3fee5b6405d" -dependencies = [ - "anyhow", - "atty", - "binary-install", - "cargo_metadata 0.15.4", - "chrono", - "clap", - "console", - "dialoguer", - "env_logger", - "glob", - "human-panic", - "log", - "parking_lot 0.12.3", - "path-clean", - "semver", - "serde", - "serde_derive", - "serde_ignored", - "serde_json", - "siphasher", - "strsim 0.10.0", - "toml 0.7.8", - "ureq", - "walkdir", - "which", -] - [[package]] name = "wasm-streams" version = "0.4.1" @@ -6854,18 +6486,6 @@ dependencies = [ "nom", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "winapi" version = "0.3.9" @@ -7084,15 +6704,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.6.20" @@ -7152,32 +6763,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "xattr" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" -dependencies = [ - "libc", - "linux-raw-sys", - "rustix", -] - -[[package]] -name = "xflags" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9e15fbb3de55454b0106e314b28e671279009b363e6f1d8e39fdc3bf048944" -dependencies = [ - "xflags-macros", -] - -[[package]] -name = "xflags-macros" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155" - [[package]] name = "xmtp_api_grpc" version = "0.0.1" @@ -7419,32 +7004,6 @@ dependencies = [ "xmtp_v2", ] -[[package]] -name = "xshell" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" -dependencies = [ - "xshell-macros", -] - -[[package]] -name = "xshell-macros" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" - -[[package]] -name = "xtask" -version = "0.0.1" -dependencies = [ - "color-eyre", - "spinach", - "wasm-pack", - "xflags", - "xshell", -] - [[package]] name = "yansi" version = "0.5.1" @@ -7501,7 +7060,7 @@ dependencies = [ "aes", "byteorder", "bzip2", - "constant_time_eq 0.1.5", + "constant_time_eq", "crc32fast", "crossbeam-utils", "flate2", @@ -7509,50 +7068,7 @@ dependencies = [ "pbkdf2 0.11.0", "sha1", "time", - "zstd 0.11.2+zstd.1.5.2", -] - -[[package]] -name = "zip" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" -dependencies = [ - "aes", - "arbitrary", - "bzip2", - "constant_time_eq 0.3.1", - "crc32fast", - "crossbeam-utils", - "deflate64", - "displaydoc", - "flate2", - "hmac 0.12.1", - "indexmap 2.6.0", - "lzma-rs", - "memchr", - "pbkdf2 0.12.2", - "rand", - "sha1", - "thiserror", - "time", - "zeroize", - "zopfli", - "zstd 0.13.2", -] - -[[package]] -name = "zopfli" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" -dependencies = [ - "bumpalo", - "crc32fast", - "lockfree-object-pool", - "log", - "once_cell", - "simd-adler32", + "zstd", ] [[package]] @@ -7561,16 +7077,7 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe 5.0.2+zstd.1.5.2", -] - -[[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe 7.2.1", + "zstd-safe", ] [[package]] @@ -7583,15 +7090,6 @@ dependencies = [ "zstd-sys", ] -[[package]] -name = "zstd-safe" -version = "7.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" -dependencies = [ - "zstd-sys", -] - [[package]] name = "zstd-sys" version = "2.0.13+zstd.1.5.6" diff --git a/Cargo.toml b/Cargo.toml index 700f2c267..22cf9869e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ members = [ "bindings_wasm", "bindings_node", "bindings_ffi", - "xtask" ] # Make the feature resolver explicit. From a1214ac881991e736befb3ff918029bcf4b2e50c Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 16 Oct 2024 19:09:55 -0400 Subject: [PATCH 97/97] dont pin openssl --- Cargo.lock | 115 +++++++++++++++++++++++------------------------------ Cargo.toml | 4 +- 2 files changed, 52 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca861666b..6646378d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,19 +14,13 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -363,17 +357,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -1179,7 +1173,7 @@ dependencies = [ [[package]] name = "diesel" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" +source = "git+https://github.com/diesel-rs/diesel?branch=master#efd59557a15322f1a54a5c263b1eb4ec0b5a0783" dependencies = [ "diesel_derives", "downcast-rs", @@ -1209,7 +1203,7 @@ dependencies = [ [[package]] name = "diesel_derives" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" +source = "git+https://github.com/diesel-rs/diesel?branch=master#efd59557a15322f1a54a5c263b1eb4ec0b5a0783" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", @@ -1221,7 +1215,7 @@ dependencies = [ [[package]] name = "diesel_migrations" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" +source = "git+https://github.com/diesel-rs/diesel?branch=master#efd59557a15322f1a54a5c263b1eb4ec0b5a0783" dependencies = [ "diesel", "migrations_internals", @@ -1231,7 +1225,7 @@ dependencies = [ [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" +source = "git+https://github.com/diesel-rs/diesel?branch=master#efd59557a15322f1a54a5c263b1eb4ec0b5a0783" dependencies = [ "syn 2.0.79", ] @@ -1314,7 +1308,7 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dsl_auto_type" version = "0.1.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" +source = "git+https://github.com/diesel-rs/diesel?branch=master#efd59557a15322f1a54a5c263b1eb4ec0b5a0783" dependencies = [ "darling", "either", @@ -1906,7 +1900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -2139,9 +2133,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -2551,7 +2545,7 @@ dependencies = [ "http 1.1.0", "hyper 1.5.0", "hyper-util", - "rustls 0.23.14", + "rustls 0.23.15", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -3087,7 +3081,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" +source = "git+https://github.com/diesel-rs/diesel?branch=master#efd59557a15322f1a54a5c263b1eb4ec0b5a0783" dependencies = [ "serde", "toml 0.8.19", @@ -3096,7 +3090,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#a3ea5242567b1a44f3b606d9b552bdd23065e001" +source = "git+https://github.com/diesel-rs/diesel?branch=master#efd59557a15322f1a54a5c263b1eb4ec0b5a0783" dependencies = [ "migrations_internals", "proc-macro2", @@ -3135,15 +3129,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -3441,9 +3426,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] @@ -3592,9 +3577,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -3624,18 +3609,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.28.2+1.1.1w" +version = "300.3.2+3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb1830e20a48a975ca898ca8c1d036a36c3c6c5cb7dabc1c216706587857920f" +checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.92" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -4141,9 +4126,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -4632,9 +4617,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "log", "once_cell", @@ -5209,15 +5194,15 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sval" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf38d1fa2ce984086ea42fb856a9f374d94680a4f796831a7fc868d7f2af1b9" +checksum = "f6dc0f9830c49db20e73273ffae9b5240f63c42e515af1da1fceefb69fceafd8" [[package]] name = "sval_buffer" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81682ff859964ca1d7cf3d3d0f9ec7204ea04c2c32acb8cc2cf68ecbd3127354" +checksum = "429922f7ad43c0ef8fd7309e14d750e38899e32eb7e8da656ea169dd28ee212f" dependencies = [ "sval", "sval_ref", @@ -5225,18 +5210,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a213b93bb4c6f4c9f9b17f2e740e077fd18746bbf7c80c72bbadcac68fa7ee4" +checksum = "68f16ff5d839396c11a30019b659b0976348f3803db0626f736764c473b50ff4" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6902c6d3fb52c89206fe0dc93546c0123f7d48b5997fd14e61c9e64ff0b63275" +checksum = "c01c27a80b6151b0557f9ccbe89c11db571dc5f68113690c1e028d7e974bae94" dependencies = [ "itoa", "ryu", @@ -5245,9 +5230,9 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a28041ea78cdc394b930ae6b897d36246dc240a29a6edf82d76562487fb0b4" +checksum = "0deef63c70da622b2a8069d8600cf4b05396459e665862e7bdb290fd6cf3f155" dependencies = [ "itoa", "ryu", @@ -5256,9 +5241,9 @@ dependencies = [ [[package]] name = "sval_nested" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850346e4b0742a7f2fd2697d703ff80084d0b658f0f2e336d71b8a06abf9b68e" +checksum = "a39ce5976ae1feb814c35d290cf7cf8cd4f045782fe1548d6bc32e21f6156e9f" dependencies = [ "sval", "sval_buffer", @@ -5267,18 +5252,18 @@ dependencies = [ [[package]] name = "sval_ref" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824afd97a8919f28a35b0fdea979845cc2ae461a8a3aaa129455cb89c88bb77a" +checksum = "bb7c6ee3751795a728bc9316a092023529ffea1783499afbc5c66f5fabebb1fa" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ada7520dd719ed672c786c7db7de4f5230f4d504b0821bd8305cd30ca442315" +checksum = "2a5572d0321b68109a343634e3a5d576bf131b82180c6c442dee06349dfc652a" dependencies = [ "serde", "sval", @@ -5631,7 +5616,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.14", + "rustls 0.23.15", "rustls-pki-types", "tokio", ] @@ -6219,9 +6204,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", "rand", @@ -6775,7 +6760,7 @@ dependencies = [ "tokio", "tonic", "tracing", - "uuid 1.10.0", + "uuid 1.11.0", "xmtp_proto", "xmtp_v2", ] @@ -6994,7 +6979,7 @@ dependencies = [ "thread-id", "tokio", "uniffi", - "uuid 1.10.0", + "uuid 1.11.0", "xmtp_api_grpc", "xmtp_cryptography", "xmtp_id", diff --git a/Cargo.toml b/Cargo.toml index 22cf9869e..6e8a90adf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,8 +71,8 @@ web-sys = "0.3" js-sys = "0.3" # NOTE: A regression in openssl-sys exists where libatomic is dynamically linked # for i686-linux-android targets. https://github.com/sfackler/rust-openssl/issues/2163 -openssl-sys = "=0.9.92" -openssl = "=0.10.57" +openssl-sys = "0.9.104" +openssl = "0.10.68" libsqlite3-sys = { version = "0.29", features = ["bundled-sqlcipher-vendored-openssl" ] } dyn-clone = "1" trait-variant = "0.1.2"

  • cz*r&RHEbae z__h%6D_g*=g+LtQ0o_9&df+ACLq39iWeD_60^5>K(7On%H*~?GzAMb#1lH%f2?Pzp z1Xeqv1cH)f0-r92g#yhH;cE&J;WIv>ecQT-x>0x0AnGmR1Vcq!BJdO#Fbp@^0nKm` zR}3^AA>y_HvXLTQ$uA-=DiOt&l!)ZIUq#j@eig|D$3^lk$3^ZTCq$Z(6QY(SCq<3c zl!{u0oEC}cjEEO-ze0oJAmnbM)jmpUJpB?`)rSdt!L`;xv&@Jb>~zDYiHI*Kd<=AE%vj+mnI{7JrDnhZVZs|nD{>bV!#UB z`_QyrD}j#Z*gExpCSv0rL+GJD%}YY)E9xSE{(mM8!w1MWfY1YoH-JP2CjEekQDAZl zOcDvajH-2bOPTdo{jD7w+}*=^_USips6{}4CZtQipkV>Sv1)xJkZ$FSlK<_o8f0Gp z5ZQ~3x){0@b8t2jR?qmDo)pX&cz9PoIE5dH?=l=1NjDgtD`vNGkYacf5n}+aAAaY<&gdo^_DX7Kjt=_Ba)b z#BVFmTH`Ia0Qw8J3H~A>Kahl+o2VJN@tWcE@GiE(dVqHZ{(8VXA7*AxzygZt3`cOA zy^e$FBVbeGw<|W=@Fj29>i@EEM*t=_7AowbljhL6!hZr>+_<@xYKr4`QR9aB%{b29`!Q{#>La(449S3!%jbK@iS9 zdr_^$T@LX`&)`9#oE{2T$+n}NLO{=&GO zxFNC%n}^_&1t8Z?jir1ZTVB0U+KWI5=i=cxEktiO_e_D^AT%L@Lx2&q2Zi-f1ee@WQVbT*l$VdjU*6VSb8K^hSEZkt&3O zEqdlI;=&N(Bha(VJ{B2ofH2>lNL4)27Y?35I4B50zI(Iq;m-W9dn_zR=ahuuR)HyYmW#U7FmqjMSUbIFUiqX zP-qOXCpcLtn$jF*=2Qz=8850ApNY=OsuVn7JP{uo?#8knXDlHJ*AsOmLJftXM%sa^ zIqE0?@khdig|Eh67JS4TO<^!I-t&lGjgn~&Q#h9e^HkJ4>$g)uxe2$vuz4X~6WBPw zz;cu&IL~>arLdNohgP{r;LLf!PZaILd4D9u3wt6Do(S2~m`fH@I9G1WL2tyL2>Ups z;R({Ti1Of7vwv)YZ z#L*k>rF>I6W@Z*n80c9>Uo0l(I}xs{C`%yWWE?Boec*@(O8KXd5<8Cd@13Z_r^eQh z1#Z?Ra5F&kJ;s5q*b;s!SVVVih1>|45C>EzaXiNK&t_IP9vI;s;tk`IaJT$~?~S8% z3*$&X86zPZyIWw_e6GOJTK)T5f++VmCV496RwJt=4g4w0xiYRd~F z(5ou6}Uo4?jNKBD8-$+K&24Hii%YQ>mmk=J#$0&yT{S0k}=1#@JITjlx}C zJW%l02}Hbi{Jz{xz8vFZ72f{o%e@m+aqmRVN^p`hRuLFqdClq3l6Sbh!1`U5ij6KJ z%-msgSIEYg@yKIu^pCJmj-H^D8vj@eh!?QfOb9U2uqFZDBc9r#DY2WbO^x>$OTELa9-@V@aKq3q z^0+)>_?X449C`8HtTl)%OD(c+>otgEyjR9r4#2n;fSbV)|E13BT2GxGY2;Xi`&^l5 zv#dpY?rUtc@x!RX))N@L>5&2-JB0avbxq8|3^0a_nFpntC+tR#_@=Um$2uqwBV`cu zAiT8`h1+gXSapQ)<9T7YAzaGE%QI;Y?v3xZSc-SLTH&_sA=FnMUv2RS_sZ2gAJmKw zW`qEY_9C>T-Gooc2usBn>rql!!Z2g029TU9pXs6@RVA-!YWJ7#RF<_6`$3eC+4rGn1z<2^|IEMCuHjs)1j5;&3zj*Y8Iy2Lm zEeq{G3xAAT&5K9NQe$3NCtN3c2T5`7@Rx#3n02D5!b6al7KFS932?E(avkrG;1Jrt zJ5dnbv|opfP{b|={f^5rHQ4HC&joTlxSrUs zn~BZ3+1wm13-`enVS{ctHsw}fLvAfL;x=LvZZo$9+iyFt^|lA{@b=;joP*pU?iXyg z9pOr_;dYWcgP|H55{)ES z5-JIk^pfM8Y?21qs1j?!SMRvID=m4-=sNyDWBrGuoyq$8!H zq+_J1(h1Tu=`87N>0Id&>2m2>=?3XW=~ijJbhq?~v_yJLdP;g$`kS;&dR_Xbv|9Q? z`d0c*%E^Q>YniRgQx+iWC<~T_%DTyV$|7ZhWzn)xvN5vBvYE13vbnM)vgNWu**;mZ z?6B;J?5M0nc1l(%J1aXcE0^7sRm$$m{**nF@vMYa)>gJw9j$_`Lan-4^|T7N>SHy? zD%xt4)flT(t0`7ft!7!xwOVKOlht9X605UT7p*Q^U9+mNdT#a7inI2!_P1_ht+fuZ z?q(fk-Pbz8I?DPR>p9k0)(fl`Td%ZUYrWa}d+R*wLhD`DKUn{0z1R8|>%-P1)~Bpb zTbEhiw#J|@7swmP8_MnEj&f(YQtl~lBM*?bmA8|(mj}v&%u z6dx5mZ6j<4+eX<&+b*!pvHj8ZplylmuePUcD77aNVK8;g-W~hdU0H4%H6iXyGVwlsZ~FDjb!LogKS4>KqFk3muCbaWdxA#7XVs z;pFS&@6_5U&?&^Ji&HnJ2&Yshol}w1F{jf`WllGp?mCgPgR_&fo3qk6(s`isAm_o( z(atf>qnt-O$2liCr#sJd);Z@m=Q`&(=R1>&z(wfN#wEa|txE?NjY~(DPA;8Yy1GQT zM7hMcjCaX!(YefWneDRKWsA#pmwcB(mmMxUU3R+^xg2u&)8&!NW0xl`|G4N~s$8DC zd~hMxrmkMDZCu;Bc5n@G4R?)jjdGprI>WWZwaoR3>s8l#uJ>L4a{b3u@A};JrRytK zYUI^ue51*YrZigLsHD*cTz&u6ZKE5xTe>UU9o?1gE!=(G+q;LjcXy9)AL2gLeYpEb z_ZauF?y2rN_iXnZ_ciXh?)mOT?)%*jx)-}2c0b~N)csfYQ|_nT&%6KTUgmzyy~6#D zd!_qh_kY}Z%G;^;Gpz^;Y#!^;JcvqE)k1b5-+IIjU8vb*c@j zT-9dPR@FAuc2%Bgw`z~-f~rh)S#?EqRaLHfsiG#9O=L}!O&T}xXyVzVWs~VmzHYL< z$=)Wno7`_gO+%VSH{Hs@*6i12HO;7bO7qm_oO-M}K|M}AUY)2;QYWiZ z)T!zT>NIt_IzyeQo~T}_E>WLUpHi2q|5QIxKUV*xexm+c{Z##rTCc8BSF70sKHFoC z$6Swj9$6mQ9`ijGcr5f-61o(PIdyV#r^NROM_L|_8=9S@<={3n~y4MV^Z@gxC zJ@9(y^|x1**K@D8ULU<`A!1YQ?d|RBo#LJ9J=0s~o$HeI}pxsTeX zg^!1ir%x*%U!Nc!ozHrR@vMd*PtI51EA+MS75Q5FihU)%QeT;`m9Mq0+*jdi<7?~N z(AUn_-q*p`(bvh>+1JI_)whwao3GMWzHNQm`*!fv_;&OS_6_x2>$~3f zJKs&dxxSly-}`>>HTVks{QPqKmiv9{m+M#JR}I0TN`FuP?*0+}{rsc-b^Z(dfAB9c z3KQKIUJ_1y&TpbzyIlL+oNZ;>YPQvGqwi(gt+p$+E4O=Y580l)J!O09_Vn!;+h=T_ zxm~w?)Aro$e{Qed{v3-ZhdgCo<2>Iy|Gd<^33*fUX5?k(&Cgqymy?&9SCjWH?|mK* zA`&d}MfuWvS$>oJX8G#;7WuyUZS&jb2j++5XXNYhXXWqBKaqbSzbwBp|9O5*{(CIQ zBn8b2dLuLL%E~Hj*=aJ?0C52&mE6<{I%on z9Zz@sv!fad#jV$iuAjqVaON$;EdyQ?GT=sa>N|Sh;C-X_ZtvaSd%X92-~N5@`;hmY z-*BJvp@yM`VTR#`5r&b5XhV!)lwq_X)-cA9YM5ZyXvj7EYB+1SY`AHtG~74*VR&G8 zXn1V+%kYokt>FU>zO2w~**ZG{S40R`CEIZ!csFYbR>C=48QyBr@p7>mRq}oLq5Mve zo2}z-;^#uza~W2jxDO(T5abGQX9{w8+gWNXwU&b{2V*5?FLoCz#agirt1@hKV%;T^ zC?s|gC#<@(k`PIRBwF&dWG2Kb1!AQ%SQ;&z3_(lL)(}>t;3@c+&BGM^6=M`S&((of$6lRvb;H$-SGQdK{%XP1-Bm;$ze8WGr)uBo-0B~yk5ym7&2z;w-)E`M{(Po* z9`ZcmIlb_G(e8!rMed7JFDhTq%aE6yUcP-vuR>l$yn6qt>uVi*8IG=D+-P$k{^5p?ZzmA-gpA||E@^RLvkbPJY`M|0!cuS9LfluJFFq)~DsC!C zlc`@ibBO{MTMe9(cY%JO_a@Kn{1mkHUh`Cj*}g;9V;9gIVCuK<78RwTHU>RMD?2L z!s@ftkE?5{EuXnP8~kkSv&qjEJv;d9^s}4KK0Nbzp8UM<`Pt`>pVvH>yzqK4;>Cs+ zXJ0&dVg0iE%cz%=UoLuC^zz`#l9#7nN?!TAN`6)N>inzPSM6W-d_C^GLN0%|?tQQ22mSLUKyxlqoTzW8>oD$0m#$pO~D2w?Q&9Crz1}k{OeblKJXh{P>ir zaq-FbV&W1~((pasu`zK~DOJX+*2X|a{Sh1cFz(@)__1RX{u-b7G%+c;DmCqSTKbEO z%vTd9O`1Gq>e!4)Q)2GjyBGKHVM0n(RaNGzS5qidw^Jy+#QS{N#F!@IMVQZS|1y~v z{^j&9i;<46yyHXn$^oIBdUsV$ZlPo!vBHA}QvEtL9T>43|f*cd_|#Al6+s#2! zO`Sipe)O`c^~~uvcp+xJghH1V38jzibS4IIh*>Y;BXt5ZETGSRyM?;+Nv01Tc64cw zn(nlDMWb$&kY?>Fd?mXxjqX=VzuetH2VzcAP;yhc9Nq~61u9AW#D`p$U!uPo)sn{# zuJkxKk6s1LqAtJq(1yR}(B9^$6gp!hU0W7NU(F7r4KD*};mA4E;_YFoaqmEP4Xa7M zMo2cTsz?&GkdoY!=;DmFBtD0ujlKtH;}|V@KN(4f)S2|~?^5bG?HRoZ6w&hj3+Vm$ zC*=OaNU|Khn0)yIY1)TwRJ~(7DT^;s+n4L;kAg-tB4!y`y8KCV*Tzw9!;!Q&WGv|_ z45UsE$4;OhogHXLXY$i&+Wlx6zX9z-*rpQUG6jc9s~ipDja zPUXq($k%%k*>&hl`x>62<4)hvt`iVM9*%q2*!Z3IbvOEBf;X){h1dE=5$(M^o%ZIf zrgo9#bUpYrZB;l@_{0ws`<*AHUf)5Zr`OQbqCw@TF>d2%?VuRi`96$h%&efsaRB_V zifOp^D%sz?PJ=t(-Np6G>2l*1)MDOax<5FaPM!59%RlU?^6PWtP!d5e8s(8=|0 zNi%8dud^velT8cKC)1uqQIvB1FnMnuO)rn0qs8A;QS)QCs&lq0oxRbPTI64*Ut<=N z?HSwyZ{Cn>yRD}aLr&1?lU*qM$7MtgFX(FLUF6Z@A$=^zx6Y1yAh(t0DfNP$8U(+h zr_Xfs)1%{5igyQA2v^dv3Blwe{)wbrUr@H~2HK&VMn3yCQP^^bRrYU1vPgVU0 zPtG*7cP90jaFx0aNG7TH7)p|2T;!aag==nAD2jrAi=gHG)c4)tL0Rp4{CZcA)m(l+Jj;%JJRYqvuUe# zHFaM3k*ww|BEQhPv^?-Tx|6zy91c7p%ilYYUAvYvOqWYhx)r3bSx)lD6_lvkL$~nW zUi%z54RM@EqrSJJm~+2S>HMEb5ptL=KNnDsOf~(z|25re{0m7M7SjCYttfW(L=tys zP1Y-&sb5ebHQM?s?fGXn4Qp;oNxz1Z_tXtkGH^BVwX;cF{hC^aETSa8wG_BlL^7ov zRU98mua@J@>Rr94&)M%OuibC-XF*%qv3w=n=`@y{M&G50i>hes!v6H(Ry*3gc?bP& z=SMJ*?EOuO4Ie}Q2oI1)oG%R;c$C5nxTf^>XUaVCf?BNjop$JaY0RS6BsgbB?;2as zjR%dW<4@aYkjqkP`i|SB%0U#CcPP+ zOQ&=%X(x7V?mS&b+F`|1b~lM~O5Mrx)_&UBEQn~&I@PI|eatdYi(nDO#J46- z$9WWf_zC*c9$Jd8I>^j8Sh?v^3!XsST4z#@At7_olwT<&yIIwe-`LE7WSZg!aDeL^e0i z(bq@HX#K5Yw8P;ro!#;cS&kboT!`uXTa8au8p_4LfAz9*u{yQY|~N3EfkrK`v)d@(75w$rvjBdMYG2hz1) zMdy_qO}I0U&fMKkN26ciW2`pVbHG)ZqMh_(Ng4ISClTG=Thpqv~6mIaVy9ZLF0G*NWUe2N5N^+=#tzB7mL#%({k|DzRU9BN7rzmBGi ziUnk4=SAN*%4o)zmBe}2)268t@maScG_Y$G-N4-a^hN_(c<5(3vHAn~<*Vsg@^M;u zvMp8Q52U^M`{?3%YqFj1O(}!gkk`QZwD!UubWQm)jUQ1+!JZq)X5@MLDD6r2UcRR# z9g^t&JTLm|>Kyv8w}7hjm&hmJ47Cc3q4ugSy z(D*!gM&729Q`bo9^es839;Ad-vD7>&nza4(G}A^-FZbEdhjXu}O|dtir^mz3)148~ z6u)FWEpJ^#XB-Yv%;5EOZ%{Gyn|+EZf)#XULU;0Zy+eB(H zt7&F-9%c7lO>Zx?CDrnuXxglvwC19ULN-AjLRci-%LtFwpU|6lw1MSEDQ;^^>bT+uIy_xU+xp!m^_|g_aPJPSTj@mk9;;~Vg%%|K zXD@Zxq@+G;&Qj{E(KKUv6O#YzPkFDFP{VkWqAwVDBuP$#v^S~^^e zjQn2fP_`}J#^xLIg8y`gKUo=_a4n-sk6X_fZUm@LKA z5jn+kXC^y6kYmR32i&JNVk5p-srp+F{ecft}eE!?S!TYMTAF4hsciy)| z^Cm2<snTL=OAwk1IM&za`(F zUNf~y+kM6NPwZTD#nbwItvQ%hrS0f{H?rD&Y4MZAi`u^(SEW7rRRis!`3p6f=TiP2 zI=V{R{BN6y8*Y4Ce07*$PUX-lZFH-k;5Sd#X$pTH>z6g4O8Z^=dFN(5T3X!b#)rlc z;Z@qj$G3M0O{f)wCa#nLM>U z=-o4(JC4ZGXt)2^_kv%Q_W2|CH7&z*nmg0)$8~L4r5#~8K|Af>x5eL#es%Bnrd3+M z9pa>WZ)R!k-F1KUog2#kXo~ZCRmb9-8#l{lI#y}-N@QuX+AY*b`46_wwXM=FJ$GUL z@`lNpfvtiI_Q@Iwuk-)(TwZ*xAgEp5Gre|+cR!aJ(c0oM z6~d(5Pxac%ZC3_AzBHlu&8CNKZava#?OZPWu5ymvlXQ>Hn#Z_6pY z*4I|9U1C_FxqIb$wdZlYwrJ1PUoPZK)Tlk%mft+8*G{S&@b}?HD>PPjKCb<-82Q;c zf!eHGTAb(g-NYY%)@yrgU2*&T-K^qHV=ivFxnHjx*0_rBL_^TVq;oNT?Qcy44+(Tr_+?e4!?&Y%3%oMPqi^KH6q)oTY29ys~Vg%!ok z8b{7*zeTT&b(*0oR1DIj7xcawxmmAm(Rjqss-IRA|JGsVn2ou5?W~{MWbLvYSA6uQ zG}9J#eL>Q}s`$~xt(@aDKW@@%`(;-S=y+RKJZELUw_n44F*s^Qto!8RjFC?tXTo0e z^}>>#`gz3}-+bSF9qbGKjCAvNnpb=#zSF?JVZU-!JmTDj9F2DP-M$G3ztQ*MKi~GB zR-DECo!$`X8DA1V;N#Pk8vkRy+&{2KCSKcd@9#Lxs6H3lzCijrUHqxl$<5itw$8x= z)W~m}b{(GWPgqgh;6m@U^HCmd2B)AoBXq^PN}F_ZMtLOcC>ntz6Ge4|nRdhDRqiMDLF)Uesluy+7)!%g7f) zX1|`MX*Ln zSl<8ixh{wF+QPRl8+Y!!yf~uI-A%I&>$Sa>jJck8c5d+@(b?2zC3>y;!m^eh_Ds;^ zRBxTN?1WzXOSxa|1r;Xp{BKW z&!_9l(4T%OzH;f8WyQmr1^>t|M}PCvZ}2;xqZ#~@Z-b3D^xB`I(v#;T%+VbEI3;pC z`q$p?maP8m_gTeLUtBpl9{n$?^||GfoEK?!U5Q$|>9Jn>?#88_OQ+=&kJ-Q2L!{Sh z5AD7^@W%1T;`era4{mv(*M_{_-qCtnPI1tXhl|tRqWo9vYX9=u*y6Ae@1IXJpuH{_ zJpR6ZS#eK`&Avs#D(!D~MoO+5GBlTu^~!O>c(ZfO@^|kKFDn+iT_5@@#-pEPdwh2% zr)xI!pL=J$6UM`jn}+%Su|zYq%rJ6?68uBNmzGw}(e%1B$mf~5N*nLor~RJaMr-yx zvRIkas!BW7X?dd8_;^i1PStH?yDIJFedlL8F3=UfJ3c&8it#n&ok2T%*V5wY^F=+q z!>Y7B3NqX8w#q4fKHthRt8bMyPtF2OGGj|8?l8# zD7WsDqKr#ROG#5EB#%i+ONz-zNJ*w1iHX>aOjM4Vk`bp&kDHJghYeHel9CjYkZfY7 z{&DGxd4NlM7bfIAYAo;iA~atwqZDUp`ggtWNP87XP_29TMOnwBy;4&sNpF^;&&5Sf%t z17i|1qB(yxq-$w1^&Qdv5b>8aQgS2AfvN@E%(CLkAmGhrK}Oo~fl z;UgQ6I|8mzndwugM>2#SrDdifP0I8s=^1fJ%F!{9DD;U7E~zPLF=+{jQF%x4F z5{;SekvuUbF#(?9;>J^FCMd}}HjYK7gzTj8@E;TFostYs#vGc0rY?24G?oTJMwxX^ zfvBa?tP)VHY(sg}6lH20L`Z!ux{QP*BoFeL{>?mw?Nn3ul=KW`Lb@_GWm57dOJ;If zT+HaP#*~J}#v5$iwIQGr60az~@Trk&YJe**XBCnoI>@EcC9E<3_W(L)$Y)Ussx_RS3vR&Y)1U z0i}uT8EZTxIi9|nk~AtMF=4c^kd=ukDXGTxVLT)F#54fyBPk|%iZUe?8D-^f%)Ge{ zkW*uo#KxtMPD@Bdn?qVZRcj|42Yf+h?P~Pcgv3~7U6W)?b;Z+-HP25il0L=FT0uJV z%8IXk44+z7ESiY1Y$v5;BJh;aqahCGs|1jOjn|g<5*|; zSI-(9!wxs#)GagF)R36}grwBOI98UX+Dbwbz?lf^2*^3BLsO^efsUGyFeU-PrlEsO z1a}uxU9&)9ln}HP7n8&?V(e(2OUlf}+9qq6=1yi}PiIZp*vrzXHwr>IHYQy;Dh{=g z9)~<3j)=6BjFizSiRSueC2CHgsl$J+9oB9~ft=1t#@x`-QKoSjNN9RS0tA?`zGJQr zL~L%M;pPl~uA5JBPD(>tGG^a6f|x`5L^fvpQ;YbQb9!bfMgvx)Um25N3WRz1OzHD4 z+b8d1Vv^Vx@^9X{zWJYs#(}_GOjO7C@3i%a%b1jsHvUuhud~uJt}j|7&HgdSo*ob%{j(UGukv{eJ%x-s?Uy{W0H-zj7vs08H4dvX)0l5`q<12 z<1qDkXp2ci^NO9qDmgVR1xI2S@jp}RyP{{Hry2X^*qG#4^ossyujnkF2eE#cDVPi5 zCXbGbi$&s)6^xq+nMtVS%;Z=aWUO|xlX1of$Ap$JHYHUVgGmXaF+BA*w;$#BI8$YP zE`VNeVGTKMa;k9*tg{;%HhL(=)mUPVlfaY~Hx8pZdKrfE^td$RL=<}YPoeZ%?t9)) zs^<1VdT%pswnZcUN_?}Yl<&uvS`hcd>3(t#iY*QR{L8EH&LLdhiHTdXMBGNrJ+tF zA;_U(96}SD@ia8%ZxJxHvWvlWvL zC}z%Lh>pU4==vu@-1w%@Jm_`}7{BpHEHiq=FKFeAM}aUIj~oO6`ynxocA)SJ+S0$l zV~g;hyV)>zRt$?$vEX=khH=;_j`E4VjduFq&H$jT8N%iYYkmGAo*RTcpz-%rbN})A~l(%;?h0b}2WiHJAIH?{GY>m1NR!> zE%4tB%h;>YzL@%^nMr>K?LF`T_z2We=;=2?sjUHK3;=9kFe)a0<}nEV%nli=Bmjhf z1t0<}0Wlx}qyWy5$qKNB$GtW6Jj&t7B)QrEwm<`*zQ=~J*Ll>vg-6!(?cit+H~@}- z6W|QE0ImR2jm)|mVmtwljoI*~1em)DKaGJVKvSR@&>W1p?}XBM7C)?p6xm!fj4agg zd?Gcvia!tx^a2I}u|OiQ5ZDa-2pj~C0vCXCpc42KcnVYlZ-7R(h*|;BKn9QvYygUY zOTZ(*0NCBexC>~3fxs|eJTM9P8kh?#16Bjy0Y$)Z;2Ka3NbeB20YN}4kOV9Nb^_;s zyTCJmkM3;`v;c6Cf;t090aZcuK+QI7dt=+1Ooj591>C% z@ICMga1D3{NHF{~2eiN-AQhMkECKR>L%1p$P@4bf`MpYIuy)fIH9)=nD)3#sQgt4p;)L2l9dAz**ov zz(%^RKr*ll*aut${sNu>9|0*wKyM%b2nMx$^cK)P08gML;01UCK0qsgDPQP*=&P0ASV--E z!qicTMbO^v$O5Af1W25D6D5SfD1=xd-|Tn00dy?6J-mNmpXE%Pc*=LXcQF z=fcuf+tnNlDUJRl(I&gX6bjk0#jc|Hr?URG3AzFjSP9SbxQ;FAe4B>C@(`pLK8)*C zgrI_1rf9`C2S$C|>iA80@@{6fo0F|VYUC4Inky939x|nf`BVTjpw2(yVJghY7++}h zTx4Z>b5me-zU`t-_PXK|ATc%y7Yn0L{Io(@+p@Brhq88ZH>bp$(^V+z1`r=!24dTd z9kCjYvHO$_Tp}X7nC8N|kfxjHY`!uo8)U&7@L5b5kL*Z1|dB_La*l zgF$getrx-4JRIJX^}G#lP#3wWs#}}WTnXlG3kKB@O-ZwEY_=;+aju4LY<%WsazDh> zQtJ|xgPx>fMLVBm(_Am$F{%~lR*ljA%0RSmM}af}XC<@jK=n37o2`bWZ2=0kS&ZeU z>gt3HG*`(#*|SY_wm>i{9@g+`JhK!nKuCiSM+-a$mN3gov{DbmQ3gx1@iC^P>&)Kv zgqV_E7w!U-peMS`LJR3E-gmIH@GWsRvNcAC)~s#|Iy?awMJ1itd4 z*>@9&hG2{gg?=4*MfuaYApF2Q26`{(GXbVrBT7E>8FnT;HyVRF$_bSm`TzmjgykYY z1a=3>VvHE*bvYJNo(6^-W)O#AXn;ZP#!3Z~+OKFMtk;E>z_rnFv<9>`GN6We(BF>4 zunwKgO}O^)7(8sL%)+fjGH8dl0<5U>Hur zVD;9;#KdBPTO}iEVW?)rz9=K6%+X~p2QdW1H8402L(65#=(GC?BNMZSf}w;lh)_aI z)iJQbV2Uw3W(;%Du9>Q1U^-KbA!h{`X16mr7~@A2EC)<6hJ#>`_duC2Wn@t5(Ba|A z>jZKoBWDl(f?UJMok7lCiQwbRIWYQ`mC$Gtw=wu4#*l_i$doaGUoccK1}oP7p#D<` zx>aDvFo$4duq-iFB=f*>kk1%4q5m>vV$gjm#V%kdV+=1lnHY>|u>3beO?`&C5b8>i zg^>F#LePH^LVbqQ^%?3ysH-RzLN#M}^+gEv8P=>uLDw-DkX98E8CnEaURU@pVTOQC z6nY*8zLEAArcQ7&Di)_op{tv*sT&-^fbNU{RmWEsve_A5Y(x`SgRt{30i1wA$ijwW zCCu&MXjF`wg_4+GyAvThRsgp*Ny^05Z4yut91&kXC}V=oLQA7#u3oQ&#I{%Y#Gni5umvdD#Z zHcI3&!*Xm9?Suh)C1@xInbQ!^PQxI7)Tv&8j9kgcQ6N_{^8RQOnT4!k%`AH}$U{M1 z!wd!8DRdhQe2xvDMa+rCTEYy)A?UWBXcf$97-)}SkpIADYp72psoMhbaFBCgkoPgq zMW1q+&&VS{KFACsu}yaZ22*~@j833cGDAfqg+Bd6t6@&jpk;4`puz zSWp=lmtPlCK43%_V%5FfLTbyxN-%?QwZal)8wg)<+~=Wp90=phNQ6Ge>0d!vnrzr} z_@DEkK=Y9NByc4IDL^U^YHs(&B4P>4|8H@Xfy?8|uwI+XlZ9o4Ha+;VDQ!W>ZoY-o ziLL3FVss(s!#>lC7@e*4m}2$u1-$}vc^&;zudaqGZvty81t6cna|lz&m8qrW!afNsJ<8vGwU%_ zgF)^aZH)3$8bY&oAh8pXf;BKWi|e;4q`>T*7()qTU=ImQF#_vW^%)*BhJ6J_`X>ff z=uEK?a&{sGbGMir7{S;v^Wkbt!9f`QO9Ye5F-(U4O2%;0JR8;d$LWYsO$9^tE--Yc zztBVy>oXKFhN0#{staLSy$~uGgG>E&97330FAcigU|80~6en|MdHA{>Lq20@*y-O4 zGwLyvF@`B-hPpJ&G&8VV)G&sbTmBt_u3iYad%&>#i!^*wkKr_9u=^qnv+6NaGlr>O zFwCyUu%-wM(e;)rESq!cF_bWdF<&sut;g_~F(iJ$Fs~j%&JSQ1`2|B(J%)pfA?^!? z?0O89jA8s24D;(TWd8_;Q`k3Pin+5~EU3pDT*HPSyZEUd>+0S4X>%rg&QF!kkX z=Cla)r27fYc^|e-n5qjsbPZg2i$Tt3UUL1|5d8`GBKoE)lzrM}|zQ!_+QP# zE$J#nAI(l#BDXd7Qt4_m#ujqxkaRG+uyHUP3^TI1?y$->tYu_mIwhJULuM7VT+;Xd zzRx+mPIx|jJ(vIQxxCNwocDd+=XpO(8c};HH4w8VN(}^pZ?j43*!=_DTp{Kp%++F^ zz{|flpE-Fm=48w+0>SU8zBAfK;chXfU@jK(#c(~ddhBB^7xQe)RT2ncF+O#R{(PQH z^9ePWLqDY|V#qAJ1-7+5jaxKn*yk!lBRdGTgFa2UXy##eDnui@3bxBWjUyM$eC!Jp z3-M*A!IpuA^}=L&jZous(ibTf ze{fcBS(&0*N#ZKV1Zla;zpPSGt;U*VQf2w8szoLFr5tZrvNs~mSEFm|O;q}zN>3Eu zOeH1iJyCT%mF&J;Q=@a+b!zmgd^P5yYT(~`QQ69|=qH4hmUblcUe2i( zX#MA860Aj#DT1r&Zs0HY6hWy7uIRff>RrcF!a4-iBIwDMm^l9uvJtpGLlAZYK@Ngq z5wukTeH2VptVd9V!0Kj|eVIUjzRGrdPSOT!P6>4G$s8qM*m5LkBer}A+`~EY9-qx4 zNt>`$5D2}Xu1g;-hu!EmE@Lx-^=BqGuvIz1;P~vwLMiY4$AgB<*WWR3q z4wDFycQ6hK<|n3%Lnf)#&oR5je3#lq^Y((R)N3v$5b8DS!(_UGFUarMiD01l7iJnL znTa_fSj5J%IRAkXfky7u&? z)RdKji&aW97cZ4v_#^7X!$Z3Ntc+8yQn)cHU+15An71y#GN?;G{g|A^Bh*O?cN?<=6fN$U+l))kR z7Ci7Be9xfe><$bXb+jGl2Ow?=Cl9;&X_^hcH!S6XBWd&*(k`JX7{IA%ILiSps69)p z5%}T~UgiUV&b(@p$H~vIc{d|HhPb%oD9WImEd1?JR9q4mwAgZ(X8Zt0;3)hE%hxja_vY~bav^OY+G_IkNY%9NguOGP zJ(}H=8NHG(O7dBOk*^!N4)|xWrG3DMKS{K52fH4LTmiP(E98Qy+seTk+y-?anAY3( zu}rB)gzxFJ`p^IxVsK$7vZOvk6Uq8WLz;lUtBG+awFAEn@d#dGYvMS$JWr=&!8!m0IgrN_*U(WI2mdF)HDu z;9=m)Tea}PkJNg8wTCO&sVy)#bBe0IeN8~VpwL8K@ryrxwvHY2#HkjT1$=emsH%r{E8yn z8~VU$UM2hD_k;f6VDJXu4}_N?f_`yQ#4Cgc0srymr!?&~cpV1A8}KH)1#iPU@GcC2 zXf7e6EHLQRt?PKff@2_qI~3zEcn@M=IE;W;7zv{w4&vc`7!6}!tl|TFapUmEQ%S<1 zz@WMlh)je-%lY+WP&0{BENddUE_e&lLumVWCge~f`8u9IOg#v5gD zeNToZ2wbof#4W>L4jHflR>CUCq=u=7$*`J87OVkrYwo5A_96)&%Tj6B)~K+>N5C re;6|{g6BOmvVJG-^gXascJ|=^bGi{dg+75NMmlwjn9dKSVV!>gvf)~B literal 0 HcmV?d00001 diff --git a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js similarity index 100% rename from diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js rename to diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js diff --git a/diesel-wasm-sqlite/yarn.lock b/diesel-wasm-sqlite/yarn.lock index ad0011cfa..89fcaa79a 100644 --- a/diesel-wasm-sqlite/yarn.lock +++ b/diesel-wasm-sqlite/yarn.lock @@ -94,26 +94,7 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-typescript@npm:^11.1.6": - version: 11.1.6 - resolution: "@rollup/plugin-typescript@npm:11.1.6" - dependencies: - "@rollup/pluginutils": "npm:^5.1.0" - resolve: "npm:^1.22.1" - peerDependencies: - rollup: ^2.14.0||^3.0.0||^4.0.0 - tslib: "*" - typescript: ">=3.7.0" - peerDependenciesMeta: - rollup: - optional: true - tslib: - optional: true - checksum: 10/4ae4d6cfc929393171288df2f18b5eb837fa53d8689118d9661b3064567341f6f6cf8389af55f1d5f015e3682abf30a64ab609fdf75ecb5a84224505e407eb69 - languageName: node - linkType: hard - -"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0": +"@rollup/pluginutils@npm:^5.0.1": version: 5.1.0 resolution: "@rollup/pluginutils@npm:5.1.0" dependencies: @@ -503,7 +484,6 @@ __metadata: resolution: "diesel-wasm-sqlite@workspace:." dependencies: "@rollup/plugin-node-resolve": "npm:^15.2.3" - "@rollup/plugin-typescript": "npm:^11.1.6" "@sqlite.org/sqlite-wasm": "npm:latest" rollup: "npm:^4.19.0" rollup-plugin-copy: "npm:^3.5.0" From f2cc495ae3d29df77ee927252b380f81c72d9b68 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 30 Aug 2024 11:35:58 -0400 Subject: [PATCH 08/97] fix vscode configuration for backend --- diesel-wasm-sqlite/.vscode/settings.json | 64 ++++++++++++------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/diesel-wasm-sqlite/.vscode/settings.json b/diesel-wasm-sqlite/.vscode/settings.json index 7f7e17ce9..e861191a0 100644 --- a/diesel-wasm-sqlite/.vscode/settings.json +++ b/diesel-wasm-sqlite/.vscode/settings.json @@ -1,34 +1,34 @@ { - "rust-analyzer": { - "cargo": { - "sysroot": "discover", - "allTargets": false, - "target": "wasm32-unknown-unknown" - }, - "procMacro": { - "enable": true, - "attributes.enable": true, - "ignored": { - "async-trait": ["async_trait"], - "napi-derive": ["napi"], - "async-recursion": ["async_recursion"], - "ctor": ["ctor"], - "tokio": ["test"], - "diesel": ["table"], - "wasm-bindgen": ["wasm-bindgen"], - } - } - }, - "[toml]": { - "editor.defaultFormatter": "tamasfe.even-better-toml" - }, - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - } + "rust-analyzer": { + "cargo": { + "sysroot": "discover", + "allTargets": false, + "target": "wasm32-unknown-unknown" + }, + "procMacro": { + "enable": true, + "attributes.enable": true, + "ignored": { + "async-trait": ["async_trait"], + "napi-derive": ["napi"], + "async-recursion": ["async_recursion"], + "ctor": ["ctor"], + "tokio": ["test"], + "diesel": ["table"], + "wasm-bindgen": ["wasm-bindgen"] + } + } + }, + "[toml]": { + "editor.defaultFormatter": "tamasfe.even-better-toml" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } } From deb6fc963cb70fca36a28c0db1db98d439e7a7b3 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Sun, 1 Sep 2024 18:32:47 -0400 Subject: [PATCH 09/97] docs.rs should only compile docs for wasm32 --- diesel-wasm-sqlite/Cargo.toml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index c390eedfe..5bf311c42 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -11,14 +11,19 @@ license = "MIT" keywords = ["orm", "database", "sql", "wasm"] categories = ["database", "wasm"] +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +targets = ["wasm32-unknown-unknown"] + [dependencies] talc = { version = "4.4", default-features = false, features = ["lock_api"] } diesel = { version = "2.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } diesel_derives = "2.2" wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" -js-sys = { version = "0.3" } -tracing = "0.1" +js-sys = { version = "0.3" } +tracing = "0.1" tokio = { version = "1.38", default-features = false, features = ["sync"] } serde = { version = "1.0", default-features = false, features = ["derive"] } serde-wasm-bindgen = "0.6" From a33d4b84d728033a764a1a17e9a1a5cea37db1e7 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 3 Sep 2024 13:29:15 -0400 Subject: [PATCH 10/97] returning clauses for sqlite --- diesel-wasm-sqlite/Cargo.lock | 62 +++++++++++++++---- diesel-wasm-sqlite/Cargo.toml | 5 ++ diesel-wasm-sqlite/src/connection/mod.rs | 4 ++ diesel-wasm-sqlite/src/connection/stmt.rs | 11 +++- diesel-wasm-sqlite/src/query_builder/mod.rs | 2 +- .../src/query_builder/returning.rs | 4 +- 6 files changed, 71 insertions(+), 17 deletions(-) diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index acb70ecf9..7330147ed 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -161,12 +161,12 @@ dependencies = [ [[package]] name = "diesel" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e13bab2796f412722112327f3e575601a3e9cdcbe426f0d30dbf43f3f5dc71" +version = "2.2.0" +source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" dependencies = [ "chrono", - "diesel_derives", + "diesel_derives 2.2.0", + "downcast-rs", "r2d2", ] @@ -178,7 +178,7 @@ dependencies = [ "console_error_panic_hook", "ctor", "diesel", - "diesel_derives", + "diesel_derives 2.2.2", "diesel_migrations", "getrandom", "js-sys", @@ -196,14 +196,26 @@ dependencies = [ "web-sys", ] +[[package]] +name = "diesel_derives" +version = "2.2.0" +source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +dependencies = [ + "diesel_table_macro_syntax 0.2.0 (git+https://github.com/insipx/diesel?branch=insipx/skip-from-public)", + "dsl_auto_type 0.1.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "diesel_derives" version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" dependencies = [ - "diesel_table_macro_syntax", - "dsl_auto_type", + "diesel_table_macro_syntax 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dsl_auto_type 0.1.2", "proc-macro2", "quote", "syn", @@ -212,8 +224,7 @@ dependencies = [ [[package]] name = "diesel_migrations" version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6" +source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" dependencies = [ "diesel", "migrations_internals", @@ -229,6 +240,33 @@ dependencies = [ "syn", ] +[[package]] +name = "diesel_table_macro_syntax" +version = "0.2.0" +source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +dependencies = [ + "syn", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dsl_auto_type" +version = "0.1.0" +source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dsl_auto_type" version = "0.1.2" @@ -377,8 +415,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff" +source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" dependencies = [ "serde", "toml", @@ -387,8 +424,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd" +source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" dependencies = [ "migrations_internals", "proc-macro2", diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index 5bf311c42..514b52803 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -42,6 +42,11 @@ tracing-wasm = { version = "0.2" } ctor = "0.2" +[patch.crates-io] +diesel = { git = "https://github.com/insipx/diesel", branch = "insipx/skip-from-public" } +diesel_derives = { git = "https://github.com/insipx/diesel", branch = "insipx/skip-from-public" } +diesel_migrations = { git = "https://github.com/insipx/diesel", branch = "insipx/skip-from-public" } + [lib] crate-type = ["cdylib", "rlib"] diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index 6c8ca78dc..4b120455f 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -102,6 +102,10 @@ impl Connection for WasmSqliteConnection { { &mut self.transaction_manager } + + fn set_prepared_statement_cache_size(&mut self, size: diesel::connection::CacheSize) { + self.statement_cache.set_cache_size(size) + } } impl LoadConnection for WasmSqliteConnection { diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 428d4163c..5ae596468 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -37,11 +37,13 @@ impl Statement { is_cached: PrepareForCache, ) -> QueryResult { let sqlite3 = crate::get_sqlite_unchecked(); - let flags = if matches!(is_cached, PrepareForCache::Yes) { + + let flags = if matches!(is_cached, PrepareForCache::Yes { counter: _}) { Some(*ffi::SQLITE_PREPARE_PERSISTENT) } else { None }; + let wasm = sqlite3.inner().wasm(); let stack = wasm.pstack().pointer(); @@ -59,7 +61,14 @@ impl Statement { let p_stmt = wasm.peek_ptr(&pp_stmt); ensure_sqlite_ok(prepare_result, &raw_connection.internal_connection)?; + wasm.pstack().restore(&stack); + // sqlite3_prepare_v3 returns a null pointer for empty statements. This includes + // empty or only whitespace strings or any other non-op query string like a comment + if p_stmt.is_null() { + return Err(diesel::result::Error::QueryBuilderError(Box::new(diesel::result::EmptyQuery))) + } + Ok(Self { inner_statement: p_stmt, }) diff --git a/diesel-wasm-sqlite/src/query_builder/mod.rs b/diesel-wasm-sqlite/src/query_builder/mod.rs index 09232cbb9..4d573a758 100644 --- a/diesel-wasm-sqlite/src/query_builder/mod.rs +++ b/diesel-wasm-sqlite/src/query_builder/mod.rs @@ -7,7 +7,7 @@ use diesel::result::QueryResult; pub(super) mod insert_with_default_sqlite; mod limit_offset; // mod query_fragment_impls; -// mod returning; +mod returning; /// Constructs SQL queries for use with the SQLite backend #[allow(missing_debug_implementations)] diff --git a/diesel-wasm-sqlite/src/query_builder/returning.rs b/diesel-wasm-sqlite/src/query_builder/returning.rs index 055cab509..edc466034 100644 --- a/diesel-wasm-sqlite/src/query_builder/returning.rs +++ b/diesel-wasm-sqlite/src/query_builder/returning.rs @@ -2,7 +2,7 @@ use crate::backend::{SqliteReturningClause, WasmSqlite}; use diesel::query_builder::ReturningClause; use diesel::query_builder::{AstPass, QueryFragment}; use diesel::result::QueryResult; -/* + impl QueryFragment for ReturningClause where Expr: QueryFragment, @@ -13,4 +13,4 @@ where self.0.walk_ast(out.reborrow())?; Ok(()) } -}*/ +} From 3f4f2f5536621567c81fe148991a153c19f24205 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 3 Sep 2024 13:40:09 -0400 Subject: [PATCH 11/97] use xmtp diesel --- diesel-wasm-sqlite/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index 514b52803..fb3542127 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -43,9 +43,9 @@ ctor = "0.2" [patch.crates-io] -diesel = { git = "https://github.com/insipx/diesel", branch = "insipx/skip-from-public" } -diesel_derives = { git = "https://github.com/insipx/diesel", branch = "insipx/skip-from-public" } -diesel_migrations = { git = "https://github.com/insipx/diesel", branch = "insipx/skip-from-public" } +diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/skip-from-public" } +diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/skip-from-public" } +diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/skip-from-public" } [lib] crate-type = ["cdylib", "rlib"] From c12ae276d11c1cd8bca26dae55bbaf6a4040079b Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 3 Sep 2024 15:12:34 -0400 Subject: [PATCH 12/97] fix insert and ignore --- diesel-wasm-sqlite/Cargo.lock | 16 ++++++++-------- diesel-wasm-sqlite/Cargo.toml | 6 +++--- diesel-wasm-sqlite/src/sqlite_fixes.rs | 7 +------ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index 7330147ed..847f4aee7 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -162,7 +162,7 @@ dependencies = [ [[package]] name = "diesel" version = "2.2.0" -source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" dependencies = [ "chrono", "diesel_derives 2.2.0", @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "diesel_derives" version = "2.2.0" -source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" dependencies = [ - "diesel_table_macro_syntax 0.2.0 (git+https://github.com/insipx/diesel?branch=insipx/skip-from-public)", + "diesel_table_macro_syntax 0.2.0 (git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub)", "dsl_auto_type 0.1.0", "proc-macro2", "quote", @@ -224,7 +224,7 @@ dependencies = [ [[package]] name = "diesel_migrations" version = "2.2.0" -source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" dependencies = [ "diesel", "migrations_internals", @@ -243,7 +243,7 @@ dependencies = [ [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" -source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" dependencies = [ "syn", ] @@ -257,7 +257,7 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dsl_auto_type" version = "0.1.0" -source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" dependencies = [ "darling", "either", @@ -415,7 +415,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" version = "2.2.0" -source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" dependencies = [ "serde", "toml", @@ -424,7 +424,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "git+https://github.com/insipx/diesel?branch=insipx/skip-from-public#18dde8741343fa1c5bf5505afb384c94f8f13599" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" dependencies = [ "migrations_internals", "proc-macro2", diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index fb3542127..8151e4030 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -43,9 +43,9 @@ ctor = "0.2" [patch.crates-io] -diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/skip-from-public" } -diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/skip-from-public" } -diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/skip-from-public" } +diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } [lib] crate-type = ["cdylib", "rlib"] diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs index f752df2ac..35287766f 100644 --- a/diesel-wasm-sqlite/src/sqlite_fixes.rs +++ b/diesel-wasm-sqlite/src/sqlite_fixes.rs @@ -4,6 +4,7 @@ use diesel::{ query_builder::AstPass, query_builder::NoFromClause, query_builder::QueryFragment, + query_builder::{InsertOrIgnore, Replace}, AppearsOnTable, Column, Expression, QueryId, QueryResult, }; @@ -38,9 +39,6 @@ where } } -#[derive(Debug, Copy, Clone, QueryId)] -pub struct InsertOrIgnore; - impl QueryFragment for InsertOrIgnore { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { out.push_sql("INSERT OR IGNORE"); @@ -48,9 +46,6 @@ impl QueryFragment for InsertOrIgnore { } } -#[derive(Debug, Copy, Clone, QueryId)] -pub struct Replace; - impl QueryFragment for Replace { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { out.push_sql("REPLACE"); From f2d02081c6e012fd89efaaf48a350c68adb38b0c Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 3 Sep 2024 15:53:21 -0400 Subject: [PATCH 13/97] fix bind blob --- diesel-wasm-sqlite/package.js | 2 +- .../src/js/wa-sqlite-diesel-bundle.js | 2 +- diesel-wasm-sqlite/tests/test/web.rs | 59 ++++++++++++++++++- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index d2b30155b..7a784fe11 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -79,7 +79,7 @@ export class SQLite { } bind_blob(stmt, i, value, len, flags) { - return this.sqlite3.capi.sqlite_bind_blob(stmt, i, value); + return this.sqlite3.capi.sqlite3_bind_blob(stmt, i, value, len, flags); } bind_text(stmt, i, value, len, flags) { diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js index f6d2fbe51..75fc2893b 100644 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js @@ -14485,7 +14485,7 @@ class SQLite { } bind_blob(stmt, i, value, len, flags) { - return this.sqlite3.capi.sqlite_bind_blob(stmt, i, value); + return this.sqlite3.capi.sqlite3_bind_blob(stmt, i, value, len, flags); } bind_text(stmt, i, value, len, flags) { diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index 0679a1ba0..7b96ddb84 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -12,9 +12,18 @@ mod schema { // published_year -> Timestamp, } } + + diesel::table! { + test_table (id, id2) { + id -> Text, + id2 -> BigInt, + timestamp_ns -> BigInt, + payload -> Binary, + } + } } -use schema::books; +use schema::{books, test_table}; #[derive(Deserialize, Insertable, Debug, PartialEq, Clone)] #[diesel(table_name = books)] @@ -172,3 +181,51 @@ async fn test_orm_insert() { ] ) } + + +/// StoredIdentityUpdate holds a serialized IdentityUpdate record +#[derive(Insertable, Identifiable, Queryable, Debug, Clone, PartialEq, Eq)] +#[diesel(table_name = test_table)] +#[diesel(primary_key(id, id2))] +pub struct Item { + pub id: String, + pub id2: i64, + pub timestamp_ns: i64, + pub payload: Vec, +} + +fn insert_or_ignore(updates: &[Item], conn: &mut WasmSqliteConnection) { + use schema::test_table::dsl::*; + + diesel::insert_or_ignore_into(test_table) + .values(updates) + .execute(conn).unwrap(); + +} + +#[wasm_bindgen_test] +async fn can_insert_or_ignore() { + use schema::books::dsl::*; + + init().await; + let mut conn = establish_connection().await; + let updates = vec![ + Item { + id: "test".into(), + id2: 13, + timestamp_ns: 1231232, + payload: b"testing this testing this".to_vec() + }, + Item { + id: "test2".into(), + id2: 14, + timestamp_ns: 1201222, + payload: b"222testing this testing this".to_vec() + + } + ]; + insert_or_ignore(&updates, &mut conn); + +} + + From 7b2e353015204fc48ffcea23cf4601ac8789269b Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 3 Sep 2024 16:30:43 -0400 Subject: [PATCH 14/97] try to repro last compiler error --- diesel-wasm-sqlite/tests/common/mod.rs | 4 +++- .../2024-09-03-193701_test_table/down.sql | 1 + .../2024-09-03-193701_test_table/up.sql | 15 +++++++++++++++ diesel-wasm-sqlite/tests/test/web.rs | 10 ++++------ 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql create mode 100644 diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql diff --git a/diesel-wasm-sqlite/tests/common/mod.rs b/diesel-wasm-sqlite/tests/common/mod.rs index 6a3418476..16e4dab4d 100644 --- a/diesel-wasm-sqlite/tests/common/mod.rs +++ b/diesel-wasm-sqlite/tests/common/mod.rs @@ -34,9 +34,11 @@ pub mod prelude { }; pub(crate) use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; pub(crate) use diesel_wasm_sqlite::{ - connection::WasmSqliteConnection, DebugQueryWrapper, WasmSqlite, + connection::WasmSqliteConnection, WasmSqlite, }; pub(crate) use serde::Deserialize; pub(crate) use wasm_bindgen_test::*; pub(crate) use web_sys::console; + #[cfg(feature = "unsafe-debug-query")] + pub(crate) use diesel_wasm_sqlite::DebugQueryWrapper; } diff --git a/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql new file mode 100644 index 000000000..d9a93fe9a --- /dev/null +++ b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` diff --git a/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql new file mode 100644 index 000000000..6a2721ecb --- /dev/null +++ b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql @@ -0,0 +1,15 @@ +CREATE TABLE test_table( + -- The inbox_id the update refers to + "id" text NOT NULL, + -- The sequence_id of the update + "id2" bigint NOT NULL, + -- Based on the timestamp given by the server + "timestamp_ns" bigint NOT NULL, + -- Random ID generated by group creator + "payload" BLOB NOT NULL, + -- Compound primary key of the `inbox_id` and `sequence_id` + PRIMARY KEY (id, id2) +); + + +CREATE INDEX idx_test_table_id_id2_asc ON test_table(id, id2 ASC); diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index 7b96ddb84..2ba0c42ce 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -59,8 +59,8 @@ async fn establish_connection() -> WasmSqliteConnection { fn insert_books(conn: &mut WasmSqliteConnection, new_books: Vec) -> QueryResult { use schema::books::dsl::*; let query = insert_into(books).values(new_books); - let sql = DebugQueryWrapper::<_, WasmSqlite>::new(&query).to_string(); - tracing::info!("QUERY = {}", sql); + // let sql = DebugQueryWrapper::<_, WasmSqlite>::new(&query).to_string(); + // tracing::info!("QUERY = {}", sql); let rows_changed = query.execute(conn)?; Ok(rows_changed) } @@ -205,8 +205,6 @@ fn insert_or_ignore(updates: &[Item], conn: &mut WasmSqliteConnection) { #[wasm_bindgen_test] async fn can_insert_or_ignore() { - use schema::books::dsl::*; - init().await; let mut conn = establish_connection().await; let updates = vec![ @@ -214,13 +212,13 @@ async fn can_insert_or_ignore() { id: "test".into(), id2: 13, timestamp_ns: 1231232, - payload: b"testing this testing this".to_vec() + payload: b"testing 1".to_vec() }, Item { id: "test2".into(), id2: 14, timestamp_ns: 1201222, - payload: b"222testing this testing this".to_vec() + payload: b"testing 2".to_vec() } ]; From 0d64420b0e7b8bc7c92d2acd359cca9335d8cf44 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 4 Sep 2024 10:41:17 -0400 Subject: [PATCH 15/97] UpdateAndFetchResults --- diesel-wasm-sqlite/src/sqlite_fixes.rs | 32 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs index 35287766f..d164d29ff 100644 --- a/diesel-wasm-sqlite/src/sqlite_fixes.rs +++ b/diesel-wasm-sqlite/src/sqlite_fixes.rs @@ -1,11 +1,6 @@ -use crate::WasmSqlite; +use crate::{connection::WasmSqliteConnection, WasmSqlite}; use diesel::{ - insertable::{ColumnInsertValue, DefaultableColumnInsertValue, InsertValues}, - query_builder::AstPass, - query_builder::NoFromClause, - query_builder::QueryFragment, - query_builder::{InsertOrIgnore, Replace}, - AppearsOnTable, Column, Expression, QueryId, QueryResult, + RunQueryDsl, associations::HasTable, dsl::{Find, Update}, expression::{is_aggregate, MixedAggregates, ValidGrouping}, insertable::{ColumnInsertValue, DefaultableColumnInsertValue, InsertValues}, prelude::{AsChangeset, Identifiable}, query_builder::{AstPass, InsertOrIgnore, IntoUpdateTarget, NoFromClause, QueryFragment, Replace}, query_dsl::{methods::{ExecuteDsl, FindDsl, LoadQuery}, UpdateAndFetchResults}, AppearsOnTable, Column, Expression, QueryId, QueryResult, Table }; impl InsertValues @@ -53,12 +48,29 @@ impl QueryFragment for Replace { } } +impl<'b, Changes, Output> UpdateAndFetchResults for WasmSqliteConnection +where + Changes: Copy + Identifiable, + Changes: AsChangeset::Table> + IntoUpdateTarget, + Changes::Table: FindDsl, + Update: ExecuteDsl, + Find: LoadQuery<'b, WasmSqliteConnection, Output>, + ::AllColumns: ValidGrouping<()>, + <::AllColumns as ValidGrouping<()>>::IsAggregate: + MixedAggregates, +{ + fn update_and_fetch(&mut self, changeset: Changes) -> QueryResult { + diesel::update(changeset).set(changeset).execute(self)?; + Changes::table().find(changeset.id()).get_result(self) + } +} + mod parenthesis_wrapper { use super::*; use crate::WasmSqlite; // use diesel::query_builder::combination_clause::SupportsCombinationClause; - use diesel::query_builder::{AstPass, QueryFragment}; + use diesel::{dsl::{Distinct, Except, Intersect, Union}, query_builder::{AstPass, QueryFragment}}; #[derive(Debug, Copy, Clone, QueryId)] /// Wrapper used to wrap rhs sql in parenthesis when supported by backend @@ -86,12 +98,12 @@ mod parenthesis_wrapper { Ok(()) } } - /* +/* impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} - */ +*/ } // Anything commented here are implementation present in diesel From cf719407ef5cc8eb0382dcddfa42564f804a010d Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 4 Sep 2024 10:53:58 -0400 Subject: [PATCH 16/97] remove unused --- diesel-wasm-sqlite/src/sqlite_fixes.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs index d164d29ff..34d69204f 100644 --- a/diesel-wasm-sqlite/src/sqlite_fixes.rs +++ b/diesel-wasm-sqlite/src/sqlite_fixes.rs @@ -109,24 +109,6 @@ mod parenthesis_wrapper { // Anything commented here are implementation present in diesel // but not possible because parts of it exist as private types in diesel. -/* -impl<'b, Changes, Output> UpdateAndFetchResults for SqliteConnection -where - Changes: Copy + Identifiable, - Changes: AsChangeset::Table> + IntoUpdateTarget, - Changes::Table: FindDsl, - Update: ExecuteDsl, - Find: LoadQuery<'b, SqliteConnection, Output>, - ::AllColumns: ValidGrouping<()>, - <::AllColumns as ValidGrouping<()>>::IsAggregate: - MixedAggregates, -{ - fn update_and_fetch(&mut self, changeset: Changes) -> QueryResult { - crate::update(changeset).set(changeset).execute(self)?; - Changes::table().find(changeset.id()).get_result(self) - } -} -*/ /* impl AsExpression for now { type Expression = Coerce; From bb8536b9f9e4497187fb90a72f946cf212a8515a Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 4 Sep 2024 15:11:55 -0400 Subject: [PATCH 17/97] Last few backend impls (#1030) * fix bind blob * try to repro last compiler error * UpdateAndFetchResults * remove unused * workaround for insert_with_default * clippy --- diesel-wasm-sqlite/Cargo.lock | 14 +- diesel-wasm-sqlite/package.js | 6 +- diesel-wasm-sqlite/src/connection/mod.rs | 2 +- diesel-wasm-sqlite/src/connection/raw.rs | 9 +- .../src/connection/sqlite_value.rs | 10 +- diesel-wasm-sqlite/src/connection/stmt.rs | 2 +- diesel-wasm-sqlite/src/ffi.rs | 4 +- diesel-wasm-sqlite/src/ffi/constants.rs | 4 +- .../src/js/wa-sqlite-diesel-bundle.js | 2 +- diesel-wasm-sqlite/src/lib.rs | 1 + .../insert_with_default_sqlite.rs | 29 ++-- diesel-wasm-sqlite/src/sqlite_fixes.rs | 157 +++++++++++++----- diesel-wasm-sqlite/tests/common/mod.rs | 4 +- .../2024-09-03-193701_test_table/down.sql | 1 + .../2024-09-03-193701_test_table/up.sql | 15 ++ diesel-wasm-sqlite/tests/test/row.rs | 2 +- diesel-wasm-sqlite/tests/test/web.rs | 62 ++++++- 17 files changed, 234 insertions(+), 90 deletions(-) create mode 100644 diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql create mode 100644 diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index 847f4aee7..29c87a369 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -162,7 +162,7 @@ dependencies = [ [[package]] name = "diesel" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "chrono", "diesel_derives 2.2.0", @@ -199,7 +199,7 @@ dependencies = [ [[package]] name = "diesel_derives" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "diesel_table_macro_syntax 0.2.0 (git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub)", "dsl_auto_type 0.1.0", @@ -224,7 +224,7 @@ dependencies = [ [[package]] name = "diesel_migrations" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "diesel", "migrations_internals", @@ -243,7 +243,7 @@ dependencies = [ [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "syn", ] @@ -257,7 +257,7 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dsl_auto_type" version = "0.1.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "darling", "either", @@ -415,7 +415,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "serde", "toml", @@ -424,7 +424,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#e4cb5e4fe408cec9f7c568a2c8e92b91bca15135" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "migrations_internals", "proc-macro2", diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index d2b30155b..54cbd39da 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -79,7 +79,7 @@ export class SQLite { } bind_blob(stmt, i, value, len, flags) { - return this.sqlite3.capi.sqlite_bind_blob(stmt, i, value); + return this.sqlite3.capi.sqlite3_bind_blob(stmt, i, value, len, flags); } bind_text(stmt, i, value, len, flags) { @@ -164,9 +164,7 @@ export class SQLite { exec(db, query) { try { return db.exec(query, { - callback: (row) => { - log(`exec'd ${row}`); - }, + callback: (row) => {}, }); } catch (error) { throw error; diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index 4b120455f..083bc5dac 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -15,7 +15,7 @@ pub use self::sqlite_value::SqliteValue; use self::raw::RawConnection; pub use self::statement_iterator::*; use self::stmt::{Statement, StatementUse}; -pub(self) use err::*; +use err::*; // use diesel::connection::DynInstrumentation; use diesel::{ connection::WithMetadataLookup, diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs index 03ac436a0..3d6a759df 100755 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -2,7 +2,7 @@ // functions are needed, but missing functionality means they aren't used yet. use crate::{WasmSqlite, WasmSqliteError}; -use diesel::{result::*, serialize::ToSql, sql_types::HasSqlType}; +use diesel::{result::*, sql_types::HasSqlType}; use wasm_bindgen::{closure::Closure, JsValue}; #[allow(missing_copy_implementations)] @@ -34,8 +34,8 @@ impl RawConnection { pub(super) fn exec(&self, query: &str) -> QueryResult<()> { let sqlite3 = crate::get_sqlite_unchecked(); - let result = sqlite3.exec(&self.internal_connection, query).unwrap(); - Ok(result) + sqlite3.exec(&self.internal_connection, query).map_err(WasmSqliteError::from)?; + Ok(()) } pub(super) fn rows_affected_by_last_query(&self) -> usize { @@ -43,7 +43,7 @@ impl RawConnection { sqlite3.changes(&self.internal_connection) } - pub(super) fn register_sql_function( + pub(super) fn register_sql_function( &self, fn_name: &str, num_args: usize, @@ -52,7 +52,6 @@ impl RawConnection { ) -> QueryResult<()> where F: FnMut(JsValue, Vec) -> JsValue + 'static, - Ret: ToSql, WasmSqlite: HasSqlType, { let sqlite3 = crate::get_sqlite_unchecked(); diff --git a/diesel-wasm-sqlite/src/connection/sqlite_value.rs b/diesel-wasm-sqlite/src/connection/sqlite_value.rs index 13f3603c6..2772d954d 100644 --- a/diesel-wasm-sqlite/src/connection/sqlite_value.rs +++ b/diesel-wasm-sqlite/src/connection/sqlite_value.rs @@ -32,7 +32,7 @@ pub struct SqliteValue<'row, 'stmt, 'query> { value: *mut u8, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub(super) struct OwnedSqliteValue { // maybe make JsValue? pub(super) value: *mut u8, @@ -60,7 +60,6 @@ impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { .get(col_idx as usize) .and_then(|v| v.as_ref())? .value - .clone(), }; let ret = Self { @@ -82,8 +81,7 @@ impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { .values .get(col_idx as usize) .and_then(|v| v.as_ref())? - .value - .clone(); + .value; let ret = Self { _row: None, value }; if ret.value_type().is_none() { None @@ -98,7 +96,7 @@ impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { // TODO: If we share memory with SQLITE, we can return a &'value str here rathre than an // allocated String - pub(crate) fn parse_string<'value, R>(&self, f: impl FnOnce(String) -> R) -> R { + pub(crate) fn parse_string(&self, f: impl FnOnce(String) -> R) -> R { let sqlite3 = crate::get_sqlite_unchecked(); // TODO: // for some reason sqlite3_value_text returns the String and not a @@ -180,7 +178,7 @@ impl OwnedSqliteValue { let sqlite3 = crate::get_sqlite_unchecked(); let value = sqlite3.value_dup(self.value); OwnedSqliteValue { - value: value.into(), + value } } } diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 5ae596468..32cbe3e58 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -194,7 +194,7 @@ impl Drop for Statement { fn drop(&mut self) { let sqlite3 = crate::get_sqlite_unchecked(); tracing::trace!("Statement dropped & finalized!"); - let _ = sqlite3 + sqlite3 .finalize(&self.inner_statement) .expect("Error finalized SQLite prepared statement"); } diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index a338e13cb..018598d18 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -57,7 +57,7 @@ struct Opts { /// array into this wasm module's own linear memory, initializing /// the memory destination provided. /// -/// # Unsafety +/// # Safety /// /// This function requires `dst` to point to a buffer /// large enough to fit this array's contents. @@ -75,7 +75,7 @@ pub fn raw_copy_to_sqlite>(bytes: B, dst: *mut u8) { /// array into this wasm module's own linear memory, initializing /// the memory destination provided. /// -/// # Unsafety +/// # Safety /// /// This function requires `buf` to point to a buffer /// large enough to fit this array's contents. diff --git a/diesel-wasm-sqlite/src/ffi/constants.rs b/diesel-wasm-sqlite/src/ffi/constants.rs index 5ed3708cc..3282911f9 100644 --- a/diesel-wasm-sqlite/src/ffi/constants.rs +++ b/diesel-wasm-sqlite/src/ffi/constants.rs @@ -1,5 +1,5 @@ //! WASM Constant bindings -use std::cell::LazyCell; +use std::sync::LazyLock; use wasm_bindgen::prelude::*; /// Normally, statics or methods cannot be pattern-matched. @@ -24,7 +24,7 @@ use wasm_bindgen::prelude::*; /// than on every access thus reducing the context-switching between wasm-js barrier. macro_rules! generate_sqlite_constant { ($fn_name:ident, $ty: ident) => { - pub const $fn_name: LazyCell<$ty> = LazyCell::new(|| { + pub static $fn_name: LazyLock<$ty> = LazyLock::new(|| { let capi: CApi = crate::get_sqlite_unchecked().inner().capi(); CApi::$fn_name(&capi) }); diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js index f6d2fbe51..75fc2893b 100644 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js @@ -14485,7 +14485,7 @@ class SQLite { } bind_blob(stmt, i, value, len, flags) { - return this.sqlite3.capi.sqlite_bind_blob(stmt, i, value); + return this.sqlite3.capi.sqlite3_bind_blob(stmt, i, value, len, flags); } bind_text(stmt, i, value, len, flags) { diff --git a/diesel-wasm-sqlite/src/lib.rs b/diesel-wasm-sqlite/src/lib.rs index 0bbd97545..0707acaa1 100755 --- a/diesel-wasm-sqlite/src/lib.rs +++ b/diesel-wasm-sqlite/src/lib.rs @@ -20,6 +20,7 @@ use wasm_bindgen::JsValue; pub use backend::{SqliteType, WasmSqlite}; pub(crate) use ffi::get_sqlite_unchecked; pub use ffi::init_sqlite; +pub use sqlite_fixes::dsl; #[derive(thiserror::Error, Debug)] pub enum WasmSqliteError { diff --git a/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs b/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs index 344db3b68..bc5a11f8d 100644 --- a/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs +++ b/diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs @@ -1,12 +1,12 @@ -use crate::{connection::WasmSqliteConnection, WasmSqlite}; +use crate::{WasmSqlite, dsl::ExecuteDsl}; use diesel::connection::Connection; use diesel::insertable::InsertValues; use diesel::insertable::{CanInsertInSingleQuery, ColumnInsertValue, DefaultableColumnInsertValue}; -use diesel::prelude::RunQueryDsl; +// use diesel::prelude::RunQueryDsl; use diesel::query_builder::QueryFragment; use diesel::query_builder::{AstPass, QueryId, ValuesClause}; use diesel::query_builder::{BatchInsert, InsertStatement}; -use diesel::query_dsl::load_dsl::ExecuteDsl; +// use diesel::query_dsl::load_dsl::ExecuteDsl; use diesel::{QueryResult, QuerySource, Table}; #[cfg(any(feature = "unsafe-debug-query", test))] @@ -367,40 +367,42 @@ where type Out = T::Out; } -impl ExecuteDsl +impl ExecuteDsl for InsertStatement>, T, QId, STATIC_QUERY_ID>, Op> where T: QuerySource, + C: Connection, V: ContainsDefaultableValue, O: Default, - (O, Self): ExecuteDsl, + (O, Self): ExecuteDsl, { - fn execute(query: Self, conn: &mut WasmSqliteConnection) -> QueryResult { - <(O, Self) as ExecuteDsl>::execute( + fn execute(query: Self, conn: &mut C) -> QueryResult { + <(O, Self) as ExecuteDsl>::execute( (O::default(), query), conn, ) } } -impl ExecuteDsl +impl ExecuteDsl for ( Yes, InsertStatement>, T, QId, STATIC_QUERY_ID>, Op>, ) where T: Table + Copy + QueryId + 'static, + C: Connection, T::FromClause: QueryFragment, Op: Copy + QueryId + QueryFragment, V: InsertValues + CanInsertInSingleQuery + QueryId, { - fn execute((Yes, query): Self, conn: &mut WasmSqliteConnection) -> QueryResult { + fn execute((Yes, query): Self, conn: &mut C) -> QueryResult { conn.transaction(|conn| { let mut result = 0; for record in &query.records.values { let stmt = InsertStatement::new(query.target, record, query.operator, query.returning); - result += stmt.execute(conn)?; + result += ExecuteDsl::::execute(stmt, conn)?; } Ok(result) }) @@ -475,7 +477,7 @@ where as QueryId>::HAS_STATIC_QUERY_ID; } -impl ExecuteDsl +impl ExecuteDsl for ( No, InsertStatement, Op>, @@ -483,18 +485,19 @@ impl ExecuteDsl, + C: Connection, Op: QueryFragment + QueryId, SqliteBatchInsertWrapper: QueryFragment + QueryId + CanInsertInSingleQuery, { - fn execute((No, query): Self, conn: &mut WasmSqliteConnection) -> QueryResult { + fn execute((No, query): Self, conn: &mut C) -> QueryResult { let query = InsertStatement::new( query.target, SqliteBatchInsertWrapper(query.records), query.operator, query.returning, ); - query.execute(conn) + ExecuteDsl::::execute(query, conn) } } diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs index 35287766f..235fc50f3 100644 --- a/diesel-wasm-sqlite/src/sqlite_fixes.rs +++ b/diesel-wasm-sqlite/src/sqlite_fixes.rs @@ -1,13 +1,99 @@ -use crate::WasmSqlite; +use crate::{connection::WasmSqliteConnection, WasmSqlite}; use diesel::{ + associations::HasTable, + dsl::{Find, Update}, + expression::{is_aggregate, MixedAggregates, ValidGrouping}, insertable::{ColumnInsertValue, DefaultableColumnInsertValue, InsertValues}, - query_builder::AstPass, - query_builder::NoFromClause, - query_builder::QueryFragment, - query_builder::{InsertOrIgnore, Replace}, - AppearsOnTable, Column, Expression, QueryId, QueryResult, + prelude::{AsChangeset, Identifiable}, + query_builder::{ + AstPass, InsertOrIgnore, IntoUpdateTarget, NoFromClause, QueryFragment, Replace, + }, + query_dsl::{ + methods::{ExecuteDsl, FindDsl, LoadQuery}, + UpdateAndFetchResults, + }, + AppearsOnTable, Column, Expression, QueryResult, RunQueryDsl, Table, }; +/// We re-define Dsl traits to make `insert_with_default_sqlite.rs` generic over all `Connection` +/// implementations with `WasmSqlite` backend`. This works around Rusts orphan rules. +pub mod dsl { + use diesel::{ + backend::Backend, + dsl::Limit, + query_builder::{QueryFragment, QueryId}, + query_dsl::methods::{LimitDsl, LoadQuery}, + Connection, QueryResult, + }; + + pub trait ExecuteDsl< + Conn: Connection, + DB: Backend = ::Backend, + >: Sized + { + fn execute(query: Self, conn: &mut Conn) -> QueryResult; + } + + impl ExecuteDsl for T + where + Conn: Connection, + DB: Backend, + T: QueryFragment + QueryId, + { + fn execute(query: T, conn: &mut Conn) -> QueryResult { + conn.execute_returning_count(&query) + } + } + + pub trait RunQueryDsl: Sized + diesel::query_dsl::RunQueryDsl { + fn execute(self, conn: &mut Conn) -> QueryResult + where + Conn: Connection, + Self: ExecuteDsl, + { + ExecuteDsl::execute(self, conn) + } + + fn load<'query, U>(self, conn: &mut Conn) -> QueryResult> + where + Self: LoadQuery<'query, Conn, U>, + { + >::load(self, conn) + } + fn load_iter<'conn, 'query: 'conn, U, B>( + self, + conn: &'conn mut Conn, + ) -> QueryResult> + where + U: 'conn, + Self: LoadQuery<'query, Conn, U, B> + 'conn, + { + >::load_iter(self, conn) + } + fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult + where + Self: LoadQuery<'query, Conn, U>, + { + >::get_result(self, conn) + } + fn get_results<'query, U>(self, conn: &mut Conn) -> QueryResult> + where + Self: LoadQuery<'query, Conn, U>, + { + >::get_results(self, conn) + } + fn first<'query, U>(self, conn: &mut Conn) -> QueryResult + where + Self: LimitDsl, + Limit: LoadQuery<'query, Conn, U>, + { + >::first(self, conn) + } + } + + impl RunQueryDsl for T where T: diesel::query_dsl::RunQueryDsl {} +} + impl InsertValues for DefaultableColumnInsertValue> where @@ -53,27 +139,31 @@ impl QueryFragment for Replace { } } +impl<'b, Changes, Output> UpdateAndFetchResults for WasmSqliteConnection +where + Changes: Copy + Identifiable, + Changes: AsChangeset::Table> + IntoUpdateTarget, + Changes::Table: FindDsl, + Update: ExecuteDsl, + Find: LoadQuery<'b, WasmSqliteConnection, Output>, + ::AllColumns: ValidGrouping<()>, + <::AllColumns as ValidGrouping<()>>::IsAggregate: + MixedAggregates, +{ + fn update_and_fetch(&mut self, changeset: Changes) -> QueryResult { + diesel::update(changeset).set(changeset).execute(self)?; + Changes::table().find(changeset.id()).get_result(self) + } +} + mod parenthesis_wrapper { use super::*; use crate::WasmSqlite; // use diesel::query_builder::combination_clause::SupportsCombinationClause; - use diesel::query_builder::{AstPass, QueryFragment}; - - #[derive(Debug, Copy, Clone, QueryId)] - /// Wrapper used to wrap rhs sql in parenthesis when supported by backend - pub struct ParenthesisWrapper(T); - - #[derive(Debug, Copy, Clone, QueryId)] - /// Keep duplicate rows in the result - pub struct All; - - impl QueryFragment for All { - fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { - out.push_sql("ALL "); - Ok(()) - } - } + use diesel::query_builder::{ + All, AstPass, Distinct, Except, Intersect, QueryFragment, SupportsCombinationClause, Union, ParenthesisWrapper + }; impl> QueryFragment for ParenthesisWrapper { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { @@ -81,40 +171,21 @@ mod parenthesis_wrapper { // we can emulate this by construct a fake outer // SELECT * FROM (inner_query) statement out.push_sql("SELECT * FROM ("); - self.0.walk_ast(out.reborrow())?; + self.inner.walk_ast(out.reborrow())?; out.push_sql(")"); Ok(()) } } - /* + impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} - */ } // Anything commented here are implementation present in diesel // but not possible because parts of it exist as private types in diesel. -/* -impl<'b, Changes, Output> UpdateAndFetchResults for SqliteConnection -where - Changes: Copy + Identifiable, - Changes: AsChangeset::Table> + IntoUpdateTarget, - Changes::Table: FindDsl, - Update: ExecuteDsl, - Find: LoadQuery<'b, SqliteConnection, Output>, - ::AllColumns: ValidGrouping<()>, - <::AllColumns as ValidGrouping<()>>::IsAggregate: - MixedAggregates, -{ - fn update_and_fetch(&mut self, changeset: Changes) -> QueryResult { - crate::update(changeset).set(changeset).execute(self)?; - Changes::table().find(changeset.id()).get_result(self) - } -} -*/ /* impl AsExpression for now { type Expression = Coerce; diff --git a/diesel-wasm-sqlite/tests/common/mod.rs b/diesel-wasm-sqlite/tests/common/mod.rs index 6a3418476..16e4dab4d 100644 --- a/diesel-wasm-sqlite/tests/common/mod.rs +++ b/diesel-wasm-sqlite/tests/common/mod.rs @@ -34,9 +34,11 @@ pub mod prelude { }; pub(crate) use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; pub(crate) use diesel_wasm_sqlite::{ - connection::WasmSqliteConnection, DebugQueryWrapper, WasmSqlite, + connection::WasmSqliteConnection, WasmSqlite, }; pub(crate) use serde::Deserialize; pub(crate) use wasm_bindgen_test::*; pub(crate) use web_sys::console; + #[cfg(feature = "unsafe-debug-query")] + pub(crate) use diesel_wasm_sqlite::DebugQueryWrapper; } diff --git a/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql new file mode 100644 index 000000000..d9a93fe9a --- /dev/null +++ b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` diff --git a/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql new file mode 100644 index 000000000..6a2721ecb --- /dev/null +++ b/diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql @@ -0,0 +1,15 @@ +CREATE TABLE test_table( + -- The inbox_id the update refers to + "id" text NOT NULL, + -- The sequence_id of the update + "id2" bigint NOT NULL, + -- Based on the timestamp given by the server + "timestamp_ns" bigint NOT NULL, + -- Random ID generated by group creator + "payload" BLOB NOT NULL, + -- Compound primary key of the `inbox_id` and `sequence_id` + PRIMARY KEY (id, id2) +); + + +CREATE INDEX idx_test_table_id_id2_asc ON test_table(id, id2 ASC); diff --git a/diesel-wasm-sqlite/tests/test/row.rs b/diesel-wasm-sqlite/tests/test/row.rs index 193e0da66..f7871d090 100644 --- a/diesel-wasm-sqlite/tests/test/row.rs +++ b/diesel-wasm-sqlite/tests/test/row.rs @@ -1,4 +1,5 @@ use crate::common::{connection, prelude::*}; +use diesel_wasm_sqlite::dsl::{ExecuteDsl, RunQueryDsl}; // test copied from diesel #[wasm_bindgen_test] @@ -15,7 +16,6 @@ async fn fun_with_row_iters() { use diesel::connection::LoadConnection; use diesel::deserialize::{FromSql, FromSqlRow}; - use diesel::prelude::*; use diesel::row::{Field, Row}; use diesel::sql_types; diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index 0679a1ba0..766c2de4b 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -1,5 +1,6 @@ //! General tests for migrations/diesel ORM/persistant databases use crate::common::prelude::*; +use diesel_wasm_sqlite::dsl::RunQueryDsl; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/migrations/"); @@ -12,9 +13,18 @@ mod schema { // published_year -> Timestamp, } } + + diesel::table! { + test_table (id, id2) { + id -> Text, + id2 -> BigInt, + timestamp_ns -> BigInt, + payload -> Binary, + } + } } -use schema::books; +use schema::{books, test_table}; #[derive(Deserialize, Insertable, Debug, PartialEq, Clone)] #[diesel(table_name = books)] @@ -50,8 +60,8 @@ async fn establish_connection() -> WasmSqliteConnection { fn insert_books(conn: &mut WasmSqliteConnection, new_books: Vec) -> QueryResult { use schema::books::dsl::*; let query = insert_into(books).values(new_books); - let sql = DebugQueryWrapper::<_, WasmSqlite>::new(&query).to_string(); - tracing::info!("QUERY = {}", sql); + // let sql = DebugQueryWrapper::<_, WasmSqlite>::new(&query).to_string(); + // tracing::info!("QUERY = {}", sql); let rows_changed = query.execute(conn)?; Ok(rows_changed) } @@ -172,3 +182,49 @@ async fn test_orm_insert() { ] ) } + + +/// StoredIdentityUpdate holds a serialized IdentityUpdate record +#[derive(Insertable, Identifiable, Queryable, Debug, Clone, PartialEq, Eq)] +#[diesel(table_name = test_table)] +#[diesel(primary_key(id, id2))] +pub struct Item { + pub id: String, + pub id2: i64, + pub timestamp_ns: i64, + pub payload: Vec, +} + +fn insert_or_ignore(updates: &[Item], conn: &mut WasmSqliteConnection) { + use schema::test_table::dsl::*; + + diesel::insert_or_ignore_into(test_table) + .values(updates) + .execute(conn).unwrap(); + +} + +#[wasm_bindgen_test] +async fn can_insert_or_ignore() { + init().await; + let mut conn = establish_connection().await; + let updates = vec![ + Item { + id: "test".into(), + id2: 13, + timestamp_ns: 1231232, + payload: b"testing 1".to_vec() + }, + Item { + id: "test2".into(), + id2: 14, + timestamp_ns: 1201222, + payload: b"testing 2".to_vec() + + } + ]; + insert_or_ignore(&updates, &mut conn); + +} + + From 9f4ffe40850c21a012f50ff953ced140e5f441a1 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 4 Sep 2024 16:23:41 -0400 Subject: [PATCH 18/97] use exact wasm-bindgen version --- diesel-wasm-sqlite/Cargo.toml | 2 +- diesel-wasm-sqlite/tests/test/row.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index 8151e4030..3371f205a 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -20,7 +20,7 @@ targets = ["wasm32-unknown-unknown"] talc = { version = "4.4", default-features = false, features = ["lock_api"] } diesel = { version = "2.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } diesel_derives = "2.2" -wasm-bindgen = "0.2" +wasm-bindgen = "0.2.92" wasm-bindgen-futures = "0.4" js-sys = { version = "0.3" } tracing = "0.1" diff --git a/diesel-wasm-sqlite/tests/test/row.rs b/diesel-wasm-sqlite/tests/test/row.rs index f7871d090..eaa7d2814 100644 --- a/diesel-wasm-sqlite/tests/test/row.rs +++ b/diesel-wasm-sqlite/tests/test/row.rs @@ -1,5 +1,5 @@ use crate::common::{connection, prelude::*}; -use diesel_wasm_sqlite::dsl::{ExecuteDsl, RunQueryDsl}; +use diesel_wasm_sqlite::dsl::RunQueryDsl; // test copied from diesel #[wasm_bindgen_test] From acbe8414c855c361daa95bab8ac3bee4866c73e4 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 5 Sep 2024 14:59:26 -0400 Subject: [PATCH 19/97] compile `xmtp_id` and `xmtp_mls` to wasm32 (#1026) * compile xmtp_id and xmtp_mls to wasm32 * remove `native` features * remove unsafe & dup trait * annotate all tests with wasm-bindgen-test for wasm32 * xmtp_mls tests compile for wasm32 * dont create a new file for database in wasm32 * fix compile for bindings_wasm * pin to wasm-bindgen 0.2.92 * fix wasm-bindgen-test version --- Cargo.lock | 289 ++++++++++++------ Cargo.toml | 19 +- bindings_ffi/Cargo.lock | 195 +++++++++--- bindings_ffi/Cargo.toml | 4 +- bindings_ffi/src/v2.rs | 2 +- bindings_node/Cargo.lock | 192 +++++++++--- bindings_node/Cargo.toml | 2 +- bindings_node/src/mls_client.rs | 9 +- bindings_wasm/Cargo.toml | 18 +- bindings_wasm/src/mls_client.rs | 9 +- diesel-wasm-sqlite/Cargo.lock | 19 +- diesel-wasm-sqlite/Cargo.toml | 6 +- .../src/js/wa-sqlite-diesel-bundle.js | 4 +- diesel-wasm-sqlite/tests/test/web.rs | 15 +- examples/cli/Cargo.toml | 2 +- xmtp_api_grpc/src/lib.rs | 2 +- xmtp_api_http/Cargo.toml | 9 +- xmtp_api_http/src/lib.rs | 5 +- xmtp_api_http/src/util.rs | 8 +- xmtp_cryptography/src/signature.rs | 6 +- xmtp_cryptography/src/utils.rs | 2 +- xmtp_id/Cargo.toml | 20 +- xmtp_id/src/associations/association_log.rs | 26 +- xmtp_id/src/associations/builder.rs | 27 +- xmtp_id/src/associations/member.rs | 8 +- xmtp_id/src/associations/mod.rs | 50 +-- xmtp_id/src/associations/serialization.rs | 19 +- xmtp_id/src/associations/signature.rs | 54 ++-- xmtp_id/src/associations/state.rs | 11 +- xmtp_id/src/associations/test_utils.rs | 4 +- xmtp_id/src/associations/unsigned_actions.rs | 8 +- xmtp_id/src/lib.rs | 16 +- xmtp_id/src/scw_verifier.rs | 6 +- xmtp_id/src/utils/mod.rs | 12 +- xmtp_id/src/utils/time.rs | 10 - xmtp_mls/Cargo.toml | 148 +++++---- xmtp_mls/src/api/identity.rs | 14 +- xmtp_mls/src/api/mls.rs | 21 +- xmtp_mls/src/api/test_utils.rs | 47 ++- xmtp_mls/src/builder.rs | 31 +- xmtp_mls/src/client.rs | 80 +++-- xmtp_mls/src/codecs/group_updated.rs | 8 +- xmtp_mls/src/codecs/membership_change.rs | 8 +- xmtp_mls/src/codecs/text.rs | 8 +- xmtp_mls/src/groups/group_membership.rs | 11 +- xmtp_mls/src/groups/group_permissions.rs | 44 ++- xmtp_mls/src/groups/intents.rs | 14 +- xmtp_mls/src/groups/members.rs | 43 --- xmtp_mls/src/groups/message_history.rs | 6 +- xmtp_mls/src/groups/mod.rs | 143 ++++++--- xmtp_mls/src/groups/subscriptions.rs | 49 ++- xmtp_mls/src/groups/sync.rs | 8 +- xmtp_mls/src/groups/validated_commit.rs | 203 ------------ xmtp_mls/src/identity.rs | 3 - xmtp_mls/src/identity_updates.rs | 30 +- xmtp_mls/src/lib.rs | 56 +++- xmtp_mls/src/owner/evm_owner.rs | 16 - xmtp_mls/src/owner/mod.rs | 1 - xmtp_mls/src/retry.rs | 75 +++-- .../encrypted_store/association_state.rs | 8 +- xmtp_mls/src/storage/encrypted_store/group.rs | 27 +- .../storage/encrypted_store/group_intent.rs | 28 +- .../storage/encrypted_store/group_message.rs | 25 +- .../src/storage/encrypted_store/identity.rs | 8 +- .../encrypted_store/identity_update.rs | 21 +- xmtp_mls/src/storage/encrypted_store/mod.rs | 96 +++--- .../storage/encrypted_store/refresh_state.rs | 21 +- xmtp_mls/src/storage/mod.rs | 2 +- xmtp_mls/src/storage/sql_key_store.rs | 14 +- xmtp_mls/src/subscriptions.rs | 92 ++++-- xmtp_mls/src/utils/bench.rs | 8 +- xmtp_mls/src/utils/test.rs | 28 +- 72 files changed, 1532 insertions(+), 1001 deletions(-) delete mode 100644 xmtp_mls/src/owner/evm_owner.rs delete mode 100644 xmtp_mls/src/owner/mod.rs diff --git a/Cargo.lock b/Cargo.lock index dcfbe4341..e71b3de99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,25 +187,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "async-barrier" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04b50fe84d0aea412a4e751cb01b9e26e2be533b2708607c2a2a739b192ee45a" -dependencies = [ - "async-mutex", - "event-listener", -] - -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", -] - [[package]] name = "async-stream" version = "0.3.5" @@ -1065,24 +1046,53 @@ dependencies = [ [[package]] name = "diesel" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" +version = "2.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ - "diesel_derives", + "diesel_derives 2.2.0", + "downcast-rs", "libsqlite3-sys", "r2d2", "time", ] +[[package]] +name = "diesel-wasm-sqlite" +version = "0.0.1" +dependencies = [ + "diesel", + "diesel_derives 2.2.2", + "js-sys", + "serde", + "serde-wasm-bindgen", + "talc", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "diesel_derives" +version = "2.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +dependencies = [ + "diesel_table_macro_syntax 0.2.0 (git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub)", + "dsl_auto_type 0.1.0", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "diesel_derives" version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" dependencies = [ - "diesel_table_macro_syntax", - "dsl_auto_type", + "diesel_table_macro_syntax 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dsl_auto_type 0.1.2", "proc-macro2", "quote", "syn 2.0.72", @@ -1091,8 +1101,7 @@ dependencies = [ [[package]] name = "diesel_migrations" version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "diesel", "migrations_internals", @@ -1108,6 +1117,14 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "diesel_table_macro_syntax" +version = "0.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +dependencies = [ + "syn 2.0.72", +] + [[package]] name = "digest" version = "0.9.0" @@ -1177,6 +1194,25 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dsl_auto_type" +version = "0.1.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "dsl_auto_type" version = "0.1.2" @@ -1707,12 +1743,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "eyre" version = "0.6.12" @@ -1800,15 +1830,18 @@ dependencies = [ ] [[package]] -name = "flume" -version = "0.11.0" +name = "fluvio-wasm-timer" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "b768c170dc045fa587a8f948c91f9bcfb87f774930477c6215addf54317f137f" dependencies = [ - "futures-core", - "futures-sink", - "nanorand", - "spin 0.9.8", + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", ] [[package]] @@ -1950,7 +1983,7 @@ version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ - "gloo-timers", + "gloo-timers 0.2.6", "send_wrapper 0.4.0", ] @@ -2039,6 +2072,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "group" version = "0.12.1" @@ -2594,6 +2639,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -2646,15 +2694,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -2926,8 +2965,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "serde", "toml", @@ -2936,8 +2974,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" dependencies = [ "migrations_internals", "proc-macro2", @@ -3084,15 +3121,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" -dependencies = [ - "getrandom", -] - [[package]] name = "native-tls" version = "0.2.12" @@ -3256,6 +3284,8 @@ version = "0.6.0-pre.2" source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" dependencies = [ "backtrace", + "fluvio-wasm-timer", + "getrandom", "itertools 0.10.5", "log", "once_cell", @@ -3461,6 +3491,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -3468,7 +3509,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -3479,7 +3534,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.3", "smallvec", "windows-targets 0.52.6", ] @@ -3902,7 +3957,7 @@ checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" dependencies = [ "bytes", "heck", - "itertools 0.12.1", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -3922,7 +3977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.72", @@ -3953,7 +4008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ "log", - "parking_lot", + "parking_lot 0.12.3", "scheduled-thread-pool", ] @@ -4022,6 +4077,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.3" @@ -4481,7 +4545,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -4599,6 +4663,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.205" @@ -4764,17 +4839,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "smart-default" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - [[package]] name = "socket2" version = "0.5.7" @@ -4810,9 +4874,6 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] [[package]] name = "spki" @@ -4848,7 +4909,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "phf_shared 0.10.0", "precomputed-hash", ] @@ -5040,6 +5101,15 @@ dependencies = [ "libc", ] +[[package]] +name = "talc" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" +dependencies = [ + "lock_api", +] + [[package]] name = "tap" version = "1.0.1" @@ -5213,7 +5283,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -5531,6 +5601,17 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "tracing-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" +dependencies = [ + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -5926,6 +6007,21 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.69" @@ -5973,7 +6069,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -6254,6 +6350,7 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "wasm-bindgen-test", "xmtp_proto", ] @@ -6312,12 +6409,12 @@ version = "0.0.1" dependencies = [ "async-trait", "chrono", - "ctor", "ed25519", "ed25519-dalek", "ethers", - "ethers-core", "futures", + "getrandom", + "gloo-timers 0.3.0", "hex", "log", "openmls", @@ -6334,6 +6431,8 @@ dependencies = [ "tokio", "tracing", "url", + "wasm-bindgen-test", + "wasm-timer", "xmtp_cryptography", "xmtp_proto", "xmtp_v2", @@ -6341,24 +6440,25 @@ dependencies = [ [[package]] name = "xmtp_mls" -version = "0.0.1" +version = "0.1.0" dependencies = [ "aes-gcm", "anyhow", - "async-barrier", "async-stream", "async-trait", "bincode", "chrono", + "console_error_panic_hook", "criterion", "ctor", "diesel", + "diesel-wasm-sqlite", "diesel_migrations", "ed25519-dalek", "ethers", - "ethers-core", - "flume", "futures", + "getrandom", + "gloo-timers 0.3.0", "hex", "indicatif", "libsqlite3-sys", @@ -6370,14 +6470,13 @@ dependencies = [ "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", - "parking_lot", + "parking_lot 0.12.3", "prost", "rand", "reqwest 0.12.5", "serde", "serde_json", "sha2 0.10.8", - "smart-default", "tempfile", "thiserror", "tls_codec", @@ -6389,6 +6488,8 @@ dependencies = [ "tracing-log", "tracing-subscriber", "tracing-test", + "tracing-wasm", + "wasm-bindgen-test", "xmtp_api_grpc", "xmtp_api_http", "xmtp_cryptography", diff --git a/Cargo.toml b/Cargo.toml index d357f9f20..972a7d5e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,10 +62,27 @@ tokio = { version = "1.35.1", default-features = false } tonic = "^0.12" tracing = { version = "0.1" } tracing-subscriber = "0.3" -url = "2.5.0" +diesel = { version = "2.2", default-features = false } +diesel-wasm-sqlite = "0.0.1" +diesel_migrations = { version = "2.2", default-features = false } +wasm-bindgen-test = "0.3.42" +gloo-timers = "0.3" # Internal Crate Dependencies xmtp_cryptography = { path = "xmtp_cryptography" } xmtp_id = { path = "xmtp_id" } xmtp_mls = { path = "xmtp_mls" } xmtp_proto = { path = "xmtp_proto" } + +[profile.release] +opt-level = "s" + +# patch needed until some items +# are made public for third-party dependencies: https://github.com/diesel-rs/diesel/pull/4236 +# (cfg-specific patche support does not exist) +[patch.crates-io] +diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +diesel-wasm-sqlite = { path = "./diesel-wasm-sqlite" } + diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 5a3700f04..31d4e0d19 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -989,6 +989,25 @@ dependencies = [ "time", ] +[[package]] +name = "diesel-wasm-sqlite" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "174378a6e27ada82d3faaac17ec226044f2b2590554bcb549622d3d2317f9909" +dependencies = [ + "diesel", + "diesel_derives", + "js-sys", + "serde", + "serde-wasm-bindgen", + "talc", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", +] + [[package]] name = "diesel_derives" version = "2.2.0" @@ -1665,6 +1684,21 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fluvio-wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b768c170dc045fa587a8f948c91f9bcfb87f774930477c6215addf54317f137f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1807,7 +1841,7 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" dependencies = [ - "gloo-timers", + "gloo-timers 0.2.6", "send_wrapper 0.4.0", ] @@ -1896,6 +1930,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "goblin" version = "0.8.2" @@ -2002,9 +2048,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -2383,6 +2429,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -2558,7 +2607,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ "bitflags 2.4.2", "libc", - "redox_syscall", + "redox_syscall 0.4.1", ] [[package]] @@ -2680,13 +2729,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2858,6 +2908,8 @@ version = "0.6.0-pre.2" source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" dependencies = [ "backtrace", + "fluvio-wasm-timer", + "getrandom", "itertools 0.10.5", "log", "once_cell", @@ -3063,6 +3115,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -3070,7 +3133,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -3081,7 +3158,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "smallvec", "windows-targets 0.48.5", ] @@ -3502,7 +3579,7 @@ checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.11.0", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -3522,7 +3599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.48", @@ -3553,7 +3630,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ "log", - "parking_lot", + "parking_lot 0.12.3", "scheduled-thread-pool", ] @@ -3622,6 +3699,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -4085,7 +4171,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -4223,6 +4309,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.195" @@ -4359,17 +4456,6 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" -[[package]] -name = "smart-default" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - [[package]] name = "smawk" version = "0.3.2" @@ -4446,7 +4532,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "phf_shared 0.10.0", "precomputed-hash", ] @@ -4566,6 +4652,15 @@ dependencies = [ "libc", ] +[[package]] +name = "talc" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" +dependencies = [ + "lock_api", +] + [[package]] name = "tap" version = "1.0.1" @@ -4580,7 +4675,7 @@ checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.4.1", "rustix", "windows-sys 0.52.0", ] @@ -4724,29 +4819,28 @@ dependencies = [ [[package]] name = "tokio" -version = "1.35.1" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -5282,9 +5376,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -5470,6 +5564,21 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.67" @@ -5795,8 +5904,8 @@ dependencies = [ "ed25519", "ed25519-dalek", "ethers", - "ethers-core", "futures", + "getrandom", "hex", "log", "openmls", @@ -5813,13 +5922,14 @@ dependencies = [ "tokio", "tracing", "url", + "wasm-timer", "xmtp_cryptography", "xmtp_proto", ] [[package]] name = "xmtp_mls" -version = "0.0.1" +version = "0.1.0" dependencies = [ "aes-gcm", "async-stream", @@ -5827,11 +5937,12 @@ dependencies = [ "bincode", "chrono", "diesel", + "diesel-wasm-sqlite", "diesel_migrations", "ed25519-dalek", - "ethers", - "ethers-core", "futures", + "getrandom", + "gloo-timers 0.3.0", "hex", "libsqlite3-sys", "log", @@ -5839,19 +5950,17 @@ dependencies = [ "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", - "parking_lot", + "parking_lot 0.12.3", "prost", "rand", "reqwest 0.12.4", "serde", "serde_json", "sha2", - "smart-default", "thiserror", "tls_codec", "tokio", "tokio-stream", - "toml 0.8.8", "tracing", "xmtp_cryptography", "xmtp_id", @@ -5913,7 +6022,7 @@ dependencies = [ "ethers-core", "futures", "log", - "parking_lot", + "parking_lot 0.12.3", "tempfile", "thiserror", "thread-id", diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index 4685dcb6f..b09d6aa19 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -19,13 +19,13 @@ uniffi_macros = "0.28.0" xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } -xmtp_mls = { path = "../xmtp_mls", features = ["native"] } +xmtp_mls = { path = "../xmtp_mls" } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } xmtp_user_preferences = { path = "../xmtp_user_preferences" } xmtp_v2 = { path = "../xmtp_v2" } tracing-subscriber = { version = "0.3", features = ["env-filter"] } -# NOTE: A regression in openssl-sys exists where libatomic is dynamically linked +# NOTE: A regression in openssl-sys exists where libatomic is dynamically linked # for i686-linux-android targets. https://github.com/sfackler/rust-openssl/issues/2163 # # This is fixed in the openssl-sys fork at diff --git a/bindings_ffi/src/v2.rs b/bindings_ffi/src/v2.rs index 090306e97..f98a9a803 100644 --- a/bindings_ffi/src/v2.rs +++ b/bindings_ffi/src/v2.rs @@ -591,7 +591,7 @@ mod tests { let msg = "TestVector1"; let sig_hash = "19d6bec562518e365d07ba3cce26d08a5fffa2cbb1e7fe03c1f2d6a722fd3a5e544097b91f8f8cd11d43b032659f30529139ab1a9ecb6c81ed4a762179e87db81c"; - let sig_bytes = ethers_core::utils::hex::decode(sig_hash).unwrap(); + let sig_bytes = ethers::core::utils::hex::decode(sig_hash).unwrap(); let recovered_addr = crate::v2::recover_address(sig_bytes, msg.to_string()).unwrap(); assert_eq!(recovered_addr, addr.to_lowercase()); } diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index e5c2040a8..b064133cf 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -858,6 +858,25 @@ dependencies = [ "time", ] +[[package]] +name = "diesel-wasm-sqlite" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "174378a6e27ada82d3faaac17ec226044f2b2590554bcb549622d3d2317f9909" +dependencies = [ + "diesel", + "diesel_derives", + "js-sys", + "serde", + "serde-wasm-bindgen", + "talc", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", +] + [[package]] name = "diesel_derives" version = "2.2.0" @@ -1505,6 +1524,21 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fluvio-wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b768c170dc045fa587a8f948c91f9bcfb87f774930477c6215addf54317f137f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1638,7 +1672,7 @@ version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ - "gloo-timers", + "gloo-timers 0.2.6", "send_wrapper 0.4.0", ] @@ -1727,6 +1761,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "group" version = "0.12.1" @@ -2197,6 +2243,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -2223,15 +2272,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -2478,13 +2518,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2692,6 +2733,8 @@ version = "0.6.0-pre.2" source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" dependencies = [ "backtrace", + "fluvio-wasm-timer", + "getrandom", "itertools 0.10.5", "log", "once_cell", @@ -2891,6 +2934,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -2898,7 +2952,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -2909,7 +2977,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", "windows-targets 0.52.5", ] @@ -3275,7 +3343,7 @@ checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.12.1", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -3295,7 +3363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.64", @@ -3326,7 +3394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ "log", - "parking_lot", + "parking_lot 0.12.3", "scheduled-thread-pool", ] @@ -3395,6 +3463,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.1" @@ -3838,7 +3915,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -3956,6 +4033,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.202" @@ -4074,17 +4162,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "smart-default" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.64", -] - [[package]] name = "socket2" version = "0.5.7" @@ -4155,7 +4232,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "phf_shared 0.10.0", "precomputed-hash", ] @@ -4269,6 +4346,15 @@ dependencies = [ "libc", ] +[[package]] +name = "talc" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" +dependencies = [ + "lock_api", +] + [[package]] name = "tap" version = "1.0.1" @@ -4397,27 +4483,26 @@ dependencies = [ [[package]] name = "tokio" -version = "1.37.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -4754,9 +4839,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -4920,6 +5005,21 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.69" @@ -5252,8 +5352,8 @@ dependencies = [ "ed25519", "ed25519-dalek", "ethers", - "ethers-core", "futures", + "getrandom", "hex", "log", "openmls", @@ -5270,13 +5370,14 @@ dependencies = [ "tokio", "tracing", "url", + "wasm-timer", "xmtp_cryptography", "xmtp_proto", ] [[package]] name = "xmtp_mls" -version = "0.0.1" +version = "0.1.0" dependencies = [ "aes-gcm", "async-stream", @@ -5284,11 +5385,12 @@ dependencies = [ "bincode", "chrono", "diesel", + "diesel-wasm-sqlite", "diesel_migrations", "ed25519-dalek", - "ethers", - "ethers-core", "futures", + "getrandom", + "gloo-timers 0.3.0", "hex", "libsqlite3-sys", "log", @@ -5296,19 +5398,17 @@ dependencies = [ "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", - "parking_lot", + "parking_lot 0.12.3", "prost", "rand", "reqwest 0.12.4", "serde", "serde_json", "sha2", - "smart-default", "thiserror", "tls_codec", "tokio", "tokio-stream", - "toml", "tracing", "xmtp_cryptography", "xmtp_id", diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml index 9d10429ad..241d40cbd 100644 --- a/bindings_node/Cargo.toml +++ b/bindings_node/Cargo.toml @@ -24,7 +24,7 @@ tonic = { version = "^0.12", features = ["tls"] } xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } -xmtp_mls = { path = "../xmtp_mls", features = ["native"] } +xmtp_mls = { path = "../xmtp_mls" } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } [build-dependencies] diff --git a/bindings_node/src/mls_client.rs b/bindings_node/src/mls_client.rs index bf5af92e4..d27b67cea 100644 --- a/bindings_node/src/mls_client.rs +++ b/bindings_node/src/mls_client.rs @@ -7,8 +7,11 @@ use std::sync::Arc; pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; -use xmtp_id::associations::{ - AccountId, MemberIdentifier, RecoverableEcdsaSignature, Signature, SmartContractWalletSignature, +use xmtp_id::{ + associations::{ + AccountId, MemberIdentifier, RecoverableEcdsaSignature, SmartContractWalletSignature, + }, + GenericSignature, }; use xmtp_mls::api::ApiClientWrapper; use xmtp_mls::builder::ClientBuilder; @@ -22,7 +25,7 @@ pub type RustXmtpClient = MlsClient; #[napi] pub struct NapiClient { inner_client: Arc, - signatures: HashMap>, + signatures: HashMap, pub account_address: String, } diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index eeb652421..4b263d945 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -2,6 +2,7 @@ edition = "2021" name = "bindings_wasm" version = "0.1.0" +resolver = "2" [lib] crate-type = ["cdylib", "rlib"] @@ -10,7 +11,7 @@ crate-type = ["cdylib", "rlib"] js-sys = "0.3" serde = { version = "1.0", features = ["derive"] } serde-wasm-bindgen = "0.6.5" -wasm-bindgen = "0.2.91" +wasm-bindgen = "=0.2.92" wasm-bindgen-futures = "0.4.41" xmtp_api_http = { path = "../xmtp_api_http" } xmtp_cryptography = { path = "../xmtp_cryptography" } @@ -19,7 +20,20 @@ xmtp_mls = { path = "../xmtp_mls", features = [] } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } [dev-dependencies] -wasm-bindgen-test = "0.3.41" +wasm-bindgen-test = "0.3.42" [profile.release] opt-level = "s" + +# patch needed until some items +# are made public for third-party dependencies: https://github.com/diesel-rs/diesel/pull/4236 +# (cfg-specific patch support does not exist) +[patch.crates-io] +diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +diesel-wasm-sqlite = { path = "../diesel-wasm-sqlite" } + +[build] +target = "wasm32-unknown-unknown" + diff --git a/bindings_wasm/src/mls_client.rs b/bindings_wasm/src/mls_client.rs index 2afad6c74..ae4f73a6d 100644 --- a/bindings_wasm/src/mls_client.rs +++ b/bindings_wasm/src/mls_client.rs @@ -6,8 +6,11 @@ use wasm_bindgen::JsValue; use xmtp_api_http::XmtpHttpApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; -use xmtp_id::associations::{ - AccountId, MemberIdentifier, RecoverableEcdsaSignature, Signature, SmartContractWalletSignature, +use xmtp_id::{ + associations::{ + AccountId, MemberIdentifier, RecoverableEcdsaSignature, SmartContractWalletSignature, + }, + GenericSignature, }; use xmtp_mls::api::ApiClientWrapper; use xmtp_mls::builder::ClientBuilder; @@ -22,7 +25,7 @@ pub type RustXmtpClient = MlsClient; pub struct WasmClient { account_address: String, inner_client: Arc, - signatures: HashMap>, + signatures: HashMap, } #[wasm_bindgen] diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index 29c87a369..b795f340e 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -162,7 +162,7 @@ dependencies = [ [[package]] name = "diesel" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ "chrono", "diesel_derives 2.2.0", @@ -199,7 +199,7 @@ dependencies = [ [[package]] name = "diesel_derives" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ "diesel_table_macro_syntax 0.2.0 (git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub)", "dsl_auto_type 0.1.0", @@ -224,7 +224,7 @@ dependencies = [ [[package]] name = "diesel_migrations" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ "diesel", "migrations_internals", @@ -243,7 +243,7 @@ dependencies = [ [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ "syn", ] @@ -257,7 +257,7 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dsl_auto_type" version = "0.1.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ "darling", "either", @@ -415,7 +415,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ "serde", "toml", @@ -424,7 +424,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#ae5dfca02366e23058a94396c1df0753fe9ac4b3" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" dependencies = [ "migrations_internals", "proc-macro2", @@ -1020,3 +1020,8 @@ dependencies = [ "quote", "syn", ] + +[[patch.unused]] +name = "wasm-bindgen" +version = "0.2.93" +source = "git+https://github.com/rustwasm/wasm-bindgen?branch=main#e4f8c4540aee2f3c0798fdae51ac7dace28e102b" diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index 3371f205a..b766beb7c 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -20,7 +20,7 @@ targets = ["wasm32-unknown-unknown"] talc = { version = "4.4", default-features = false, features = ["lock_api"] } diesel = { version = "2.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } diesel_derives = "2.2" -wasm-bindgen = "0.2.92" +wasm-bindgen = "=0.2.92" wasm-bindgen-futures = "0.4" js-sys = { version = "0.3" } tracing = "0.1" @@ -41,11 +41,13 @@ diesel = { version = "2.2", features = ["chrono"]} tracing-wasm = { version = "0.2" } ctor = "0.2" - [patch.crates-io] diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } +wasm-bindgen = { git = "https://github.com/rustwasm/wasm-bindgen", branch = "main" } +# [profile.release] +# opt-level = "s" [lib] crate-type = ["cdylib", "rlib"] diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js index 75fc2893b..7b1a30884 100644 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js @@ -14570,9 +14570,7 @@ class SQLite { exec(db, query) { try { return db.exec(query, { - callback: (row) => { - log(`exec'd ${row}`); - }, + callback: (row) => {}, }); } catch (error) { throw error; diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index 766c2de4b..e486d35f1 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -183,7 +183,6 @@ async fn test_orm_insert() { ) } - /// StoredIdentityUpdate holds a serialized IdentityUpdate record #[derive(Insertable, Identifiable, Queryable, Debug, Clone, PartialEq, Eq)] #[diesel(table_name = test_table)] @@ -200,8 +199,8 @@ fn insert_or_ignore(updates: &[Item], conn: &mut WasmSqliteConnection) { diesel::insert_or_ignore_into(test_table) .values(updates) - .execute(conn).unwrap(); - + .execute(conn) + .unwrap(); } #[wasm_bindgen_test] @@ -213,18 +212,14 @@ async fn can_insert_or_ignore() { id: "test".into(), id2: 13, timestamp_ns: 1231232, - payload: b"testing 1".to_vec() + payload: b"testing 1".to_vec(), }, Item { id: "test2".into(), id2: 14, timestamp_ns: 1201222, - payload: b"testing 2".to_vec() - - } + payload: b"testing 2".to_vec(), + }, ]; insert_or_ignore(&updates, &mut conn); - } - - diff --git a/examples/cli/Cargo.toml b/examples/cli/Cargo.toml index 861e168a0..548f276b7 100644 --- a/examples/cli/Cargo.toml +++ b/examples/cli/Cargo.toml @@ -36,5 +36,5 @@ url = "2.3.1" xmtp_api_grpc = { path = "../../xmtp_api_grpc" } xmtp_cryptography = { path = "../../xmtp_cryptography" } xmtp_id = { path = "../../xmtp_id" } -xmtp_mls = { path = "../../xmtp_mls", features = ["native"] } +xmtp_mls = { path = "../../xmtp_mls" } xmtp_proto = { path = "../../xmtp_proto", features = ["proto_full"] } diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index 10472c2a8..67dffa905 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -8,7 +8,7 @@ pub const DEV_ADDRESS: &str = "https://grpc.dev.xmtp.network:443"; pub use grpc_api_helper::Client; #[cfg(test)] -mod tests { +pub mod tests { use std::time::{SystemTime, UNIX_EPOCH}; use self::auth_token::Authenticator; diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml index 13852a3dc..cf229dd10 100644 --- a/xmtp_api_http/Cargo.toml +++ b/xmtp_api_http/Cargo.toml @@ -21,8 +21,11 @@ tokio-stream = { version = "0.1", default-features = false } tracing.workspace = true xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } -[dev-dependencies] +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } -[profile.release] -opt-level = "s" +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +tokio = { workspace = true, features = ["macros", "time"] } +wasm-bindgen-test.workspace = true + + diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index aa6fca4b4..8e4852861 100755 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -320,13 +320,16 @@ impl XmtpIdentityClient for XmtpHttpApiClient { // tests #[cfg(test)] mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); use xmtp_proto::xmtp::mls::api::v1::KeyPackageUpload; use crate::constants::ApiUrls; use super::*; - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_upload_key_package() { let client = XmtpHttpApiClient::new(ApiUrls::LOCAL_ADDRESS.to_string()).unwrap(); let result = client diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index 056471eef..46e2b9099 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -118,10 +118,14 @@ fn create_grpc_stream_inner< } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_error_handler_on_unit_value() { handle_error::<_, ()>(b"{}".as_slice()).unwrap(); } diff --git a/xmtp_cryptography/src/signature.rs b/xmtp_cryptography/src/signature.rs index 4f25414fe..687b3bce8 100644 --- a/xmtp_cryptography/src/signature.rs +++ b/xmtp_cryptography/src/signature.rs @@ -1,6 +1,6 @@ use curve25519_dalek::{edwards::CompressedEdwardsY, traits::IsIdentity}; +use ethers::core::types::{self as ethers_types, H160}; use ethers::types::Address; -use ethers_core::types::{self as ethers_types, H160}; pub use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey}; use k256::Secp256k1; use serde::{Deserialize, Serialize}; @@ -98,8 +98,8 @@ impl From<(ecdsa::Signature, RecoveryId)> for RecoverableSignature { } } -impl From for RecoverableSignature { - fn from(value: ethers_core::types::Signature) -> Self { +impl From for RecoverableSignature { + fn from(value: ethers::core::types::Signature) -> Self { RecoverableSignature::Eip191Signature(value.to_vec()) } } diff --git a/xmtp_cryptography/src/utils.rs b/xmtp_cryptography/src/utils.rs index efbc1c502..35e13d4ba 100644 --- a/xmtp_cryptography/src/utils.rs +++ b/xmtp_cryptography/src/utils.rs @@ -1,5 +1,5 @@ +use ethers::core::utils::keccak256; pub use ethers::prelude::LocalWallet; -use ethers_core::utils::keccak256; use k256::ecdsa::VerifyingKey; use rand::{CryptoRng, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index 449c5f5fa..319e8b236 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -4,16 +4,15 @@ name = "xmtp_id" version.workspace = true [dependencies] +url = "2.5.2" async-trait.workspace = true chrono.workspace = true ed25519-dalek = { workspace = true, features = ["digest"] } ed25519.workspace = true -ethers-core.workspace = true ethers.workspace = true futures.workspace = true hex.workspace = true log.workspace = true -openmls.workspace = true openmls_basic_credential.workspace = true openmls_rust_crypto.workspace = true openmls_traits.workspace = true @@ -26,17 +25,24 @@ sha2.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["macros"] } tracing.workspace = true -url.workspace = true xmtp_cryptography.workspace = true xmtp_proto = { workspace = true, features = ["proto_full"] } +wasm-timer = "0.2" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2", features = ["js"] } +openmls = { workspace = true, features = ["js"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +openmls.workspace = true [dev-dependencies] -ctor = "0.2.5" ed25519-dalek = { workspace = true, features = ["digest"] } -futures = "0.3" -regex = "1.10" -tokio = { workspace = true, features = ["macros", "time"] } xmtp_v2 = { path = "../xmtp_v2" } +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test.workspace = true +gloo-timers.workspace = true + [features] test-utils = [] diff --git a/xmtp_id/src/associations/association_log.rs b/xmtp_id/src/associations/association_log.rs index 2bccf68d0..79e20aeb1 100644 --- a/xmtp_id/src/associations/association_log.rs +++ b/xmtp_id/src/associations/association_log.rs @@ -1,9 +1,10 @@ +use crate::GenericSignature; + use super::hashes::generate_inbox_id; use super::member::{Member, MemberIdentifier, MemberKind}; use super::serialization::{from_identity_update_proto, DeserializationError}; -use super::signature::{Signature, SignatureError, SignatureKind}; +use super::signature::{SignatureError, SignatureKind}; use super::state::AssociationState; -use async_trait::async_trait; use prost::Message; use thiserror::Error; use xmtp_proto::xmtp::identity::associations::IdentityUpdate as IdentityUpdateProto; @@ -38,8 +39,7 @@ pub enum AssociationError { MissingIdentityUpdate, } -#[async_trait] -pub trait IdentityAction: Send + 'static { +pub(crate) trait IdentityAction { async fn update_state( &self, existing_state: Option, @@ -62,10 +62,9 @@ pub trait IdentityAction: Send + 'static { pub struct CreateInbox { pub nonce: u64, pub account_address: String, - pub initial_address_signature: Box, + pub initial_address_signature: GenericSignature, } -#[async_trait] impl IdentityAction for CreateInbox { async fn update_state( &self, @@ -105,12 +104,11 @@ impl IdentityAction for CreateInbox { /// AddAssociation Action #[derive(Debug, Clone)] pub struct AddAssociation { - pub new_member_signature: Box, + pub new_member_signature: GenericSignature, pub new_member_identifier: MemberIdentifier, - pub existing_member_signature: Box, + pub existing_member_signature: GenericSignature, } -#[async_trait::async_trait] impl IdentityAction for AddAssociation { async fn update_state( &self, @@ -201,11 +199,10 @@ impl IdentityAction for AddAssociation { /// RevokeAssociation Action #[derive(Debug, Clone)] pub struct RevokeAssociation { - pub recovery_address_signature: Box, + pub recovery_address_signature: GenericSignature, pub revoked_member: MemberIdentifier, } -#[async_trait] impl IdentityAction for RevokeAssociation { async fn update_state( &self, @@ -257,11 +254,10 @@ impl IdentityAction for RevokeAssociation { /// ChangeRecoveryAddress Action #[derive(Debug, Clone)] pub struct ChangeRecoveryAddress { - pub recovery_address_signature: Box, + pub recovery_address_signature: GenericSignature, pub new_recovery_address: String, } -#[async_trait] impl IdentityAction for ChangeRecoveryAddress { async fn update_state( &self, @@ -299,7 +295,6 @@ pub enum Action { ChangeRecoveryAddress(ChangeRecoveryAddress), } -#[async_trait] impl IdentityAction for Action { async fn update_state( &self, @@ -366,7 +361,6 @@ impl TryFrom> for IdentityUpdate { } } -#[async_trait] impl IdentityAction for IdentityUpdate { async fn update_state( &self, @@ -401,7 +395,7 @@ impl IdentityAction for IdentityUpdate { } #[allow(clippy::borrowed_box)] -fn is_legacy_signature(signature: &Box) -> bool { +fn is_legacy_signature(signature: &GenericSignature) -> bool { signature.signature_kind() == SignatureKind::LegacyDelegated } diff --git a/xmtp_id/src/associations/builder.rs b/xmtp_id/src/associations/builder.rs index 041b4aef4..f47cf6a99 100644 --- a/xmtp_id/src/associations/builder.rs +++ b/xmtp_id/src/associations/builder.rs @@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet}; -use crate::utils::now_ns; +use crate::{utils::now_ns, GenericSignature}; use thiserror::Error; use super::{ @@ -14,7 +14,7 @@ use super::{ UnsignedChangeRecoveryAddress, UnsignedCreateInbox, UnsignedIdentityUpdate, UnsignedRevokeAssociation, }, - Action, IdentityUpdate, MemberIdentifier, MemberKind, Signature, SignatureError, + Action, IdentityUpdate, MemberIdentifier, MemberKind, SignatureError, }; /// The SignatureField is used to map the signatures from a [SignatureRequest] back to the correct @@ -169,7 +169,7 @@ pub enum SignatureRequestError { pub struct SignatureRequest { pending_actions: Vec, signature_text: String, - signatures: HashMap>, + signatures: HashMap, client_timestamp_ns: u64, inbox_id: String, } @@ -218,7 +218,7 @@ impl SignatureRequest { pub async fn add_signature( &mut self, - signature: Box, + signature: GenericSignature, ) -> Result<(), SignatureRequestError> { let signer_identity = signature.recover_signer().await?; let missing_signatures = self.missing_signatures(); @@ -269,7 +269,7 @@ impl SignatureRequest { fn build_action( pending_action: PendingIdentityAction, - signatures: &HashMap>, + signatures: &HashMap, ) -> Result { match pending_action.unsigned_action { UnsignedAction::CreateInbox(unsigned_action) => { @@ -363,7 +363,10 @@ fn get_signature_text( } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::associations::{ get_state, hashes::generate_inbox_id, @@ -394,7 +397,8 @@ mod tests { } } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn create_inbox() { let account_address = "account_address".to_string(); let nonce = 0; @@ -414,7 +418,8 @@ mod tests { .expect("should be valid"); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn create_and_add_identity() { let account_address = "account_address".to_string(); let nonce = 0; @@ -439,7 +444,8 @@ mod tests { assert_eq!(state.members().len(), 2); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn create_and_revoke() { let account_address = "account_address".to_string(); let nonce = 0; @@ -464,7 +470,8 @@ mod tests { assert_eq!(state.members().len(), 0); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn attempt_adding_unknown_signer() { let account_address = "account_address".to_string(); let nonce = 0; diff --git a/xmtp_id/src/associations/member.rs b/xmtp_id/src/associations/member.rs index 44a31cde9..1f3c73800 100644 --- a/xmtp_id/src/associations/member.rs +++ b/xmtp_id/src/associations/member.rs @@ -99,7 +99,10 @@ impl PartialEq for Member { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::associations::test_utils; use super::*; @@ -122,7 +125,8 @@ mod tests { } } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_identifier_comparisons() { let address_1 = MemberIdentifier::Address("0x123".to_string()); let address_2 = MemberIdentifier::Address("0x456".to_string()); diff --git a/xmtp_id/src/associations/mod.rs b/xmtp_id/src/associations/mod.rs index 198a84a26..0d78e0efd 100644 --- a/xmtp_id/src/associations/mod.rs +++ b/xmtp_id/src/associations/mod.rs @@ -1,10 +1,10 @@ mod association_log; pub mod builder; mod hashes; -mod member; -mod serialization; +pub(super) mod member; +pub(super) mod serialization; pub mod signature; -mod state; +pub(super) mod state; #[cfg(any(test, feature = "test-utils"))] pub mod test_utils; pub mod unsigned_actions; @@ -104,7 +104,10 @@ pub mod test_defaults { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use self::test_utils::{rand_string, rand_vec, MockSignature}; use super::*; @@ -141,7 +144,8 @@ mod tests { .unwrap() } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_create_inbox() { let create_request = CreateInbox::default(); let inbox_id = generate_inbox_id(&create_request.account_address, &create_request.nonce); @@ -155,7 +159,8 @@ mod tests { assert!(existing_entity.identifier.eq(&account_address.into())); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn create_and_add_separately() { let initial_state = new_test_inbox().await; let inbox_id = initial_state.inbox_id().clone(); @@ -190,7 +195,8 @@ mod tests { assert_eq!(new_member.added_by_entity, Some(first_member)); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn create_and_add_together() { let create_action = CreateInbox::default(); let account_address = create_action.account_address.clone(); @@ -227,7 +233,8 @@ mod tests { ); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn create_from_legacy_key() { let member_identifier: MemberIdentifier = rand_string().into(); let create_action = CreateInbox { @@ -268,7 +275,8 @@ mod tests { assert!(matches!(update_result, Err(AssociationError::Replay))); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn add_wallet_from_installation_key() { let initial_state = new_test_inbox_with_installation().await; let inbox_id = initial_state.inbox_id().clone(); @@ -305,7 +313,8 @@ mod tests { assert_eq!(new_state.members().len(), 3); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn reject_invalid_signature_on_create() { let bad_signature = MockSignature::new_boxed(false, rand_string().into(), SignatureKind::Erc191, None); @@ -326,7 +335,8 @@ mod tests { )); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn reject_invalid_signature_on_update() { let initial_state = new_test_inbox().await; let inbox_id = initial_state.inbox_id().clone(); @@ -370,7 +380,8 @@ mod tests { )); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn reject_if_signer_not_existing_member() { let create_inbox = CreateInbox::default(); let inbox_id = generate_inbox_id(&create_inbox.account_address, &create_inbox.nonce); @@ -398,7 +409,8 @@ mod tests { )); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn reject_if_installation_adding_installation() { let existing_state = new_test_inbox_with_installation().await; let inbox_id = existing_state.inbox_id().clone(); @@ -436,7 +448,8 @@ mod tests { )); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn revoke() { let initial_state = new_test_inbox_with_installation().await; let inbox_id = initial_state.inbox_id().clone(); @@ -465,7 +478,8 @@ mod tests { assert!(new_state.get(&installation_id).is_none()); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn revoke_children() { let initial_state = new_test_inbox_with_installation().await; let inbox_id = initial_state.inbox_id().clone(); @@ -514,7 +528,8 @@ mod tests { assert_eq!(new_state.members().len(), 0); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn revoke_and_re_add() { let initial_state = new_test_inbox().await; let wallet_address = initial_state @@ -589,7 +604,8 @@ mod tests { assert_eq!(state_after_re_add.members().len(), 2); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn change_recovery_address() { let initial_state = new_test_inbox_with_installation().await; let inbox_id = initial_state.inbox_id().clone(); diff --git a/xmtp_id/src/associations/serialization.rs b/xmtp_id/src/associations/serialization.rs index 10de98549..54d427117 100644 --- a/xmtp_id/src/associations/serialization.rs +++ b/xmtp_id/src/associations/serialization.rs @@ -1,5 +1,7 @@ use std::collections::{HashMap, HashSet}; +use crate::GenericSignature; + use super::{ association_log::{ Action, AddAssociation, ChangeRecoveryAddress, CreateInbox, RevokeAssociation, @@ -15,7 +17,7 @@ use super::{ UnsignedChangeRecoveryAddress, UnsignedCreateInbox, UnsignedIdentityUpdate, UnsignedRevokeAssociation, }, - IdentityUpdate, MemberIdentifier, Signature, SignatureError, + IdentityUpdate, MemberIdentifier, SignatureError, }; use prost::{DecodeError, Message}; use regex::Regex; @@ -204,7 +206,7 @@ impl From for MemberIdentifier { fn from_signature_proto_option( proto: Option, signature_text: String, -) -> Result, DeserializationError> { +) -> Result { match proto { None => Err(DeserializationError::Signature), Some(signature_proto) => match signature_proto.signature { @@ -217,7 +219,7 @@ fn from_signature_proto_option( fn from_signature_kind_proto( proto: SignatureKindProto, signature_text: String, -) -> Result, DeserializationError> { +) -> Result { Ok(match proto { SignatureKindProto::InstallationKey(installation_key_signature) => { Box::new(InstallationKeySignature::new( @@ -540,7 +542,10 @@ impl From for String { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::associations::{ hashes::generate_inbox_id, test_utils::{rand_string, rand_u64}, @@ -548,7 +553,8 @@ mod tests { use super::*; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_round_trip() { let account_address = rand_string(); let nonce = rand_u64(); @@ -583,7 +589,8 @@ mod tests { assert_eq!(serialized_update, reserialized); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_accound_id() { // valid evm chain let text = "eip155:1:0xab16a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb".to_string(); diff --git a/xmtp_id/src/associations/signature.rs b/xmtp_id/src/associations/signature.rs index 7a4190d51..c64f7c25a 100644 --- a/xmtp_id/src/associations/signature.rs +++ b/xmtp_id/src/associations/signature.rs @@ -1,5 +1,5 @@ use super::MemberIdentifier; -use crate::constants::INSTALLATION_KEY_SIGNATURE_CONTEXT; +use crate::{constants::INSTALLATION_KEY_SIGNATURE_CONTEXT, GenericSignature}; use async_trait::async_trait; use ed25519_dalek::{Signature as Ed25519Signature, VerifyingKey}; use ethers::{ @@ -81,8 +81,9 @@ impl std::fmt::Display for SignatureKind { } } -#[async_trait] -pub trait Signature: SignatureClone + std::fmt::Debug + Send + Sync + 'static { +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +pub trait Signature: SignatureClone + std::fmt::Debug + 'static { async fn recover_signer(&self) -> Result; fn signature_kind(&self) -> SignatureKind; fn bytes(&self) -> Vec; @@ -90,20 +91,20 @@ pub trait Signature: SignatureClone + std::fmt::Debug + Send + Sync + 'static { } pub trait SignatureClone { - fn clone_box(&self) -> Box; + fn clone_box(&self) -> GenericSignature; } impl SignatureClone for T where - T: 'static + Signature + Clone, + T: Signature + Clone + Send + Sync + 'static, { - fn clone_box(&self) -> Box { + fn clone_box(&self) -> GenericSignature { Box::new(self.clone()) } } -impl Clone for Box { - fn clone(&self) -> Box { +impl Clone for GenericSignature { + fn clone(&self) -> GenericSignature { self.clone_box() } } @@ -124,7 +125,8 @@ impl RecoverableEcdsaSignature { } } -#[async_trait] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl Signature for RecoverableEcdsaSignature { async fn recover_signer(&self) -> Result { let signature = ethers::types::Signature::try_from(self.bytes().as_slice())?; @@ -182,8 +184,6 @@ pub struct SmartContractWalletSignature { chain_rpc_url: String, } -unsafe impl Send for SmartContractWalletSignature {} - impl SmartContractWalletSignature { pub fn new( signature_text: String, @@ -223,7 +223,8 @@ impl SmartContractWalletSignature { } } -#[async_trait] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl Signature for SmartContractWalletSignature { async fn recover_signer(&self) -> Result { let verifier = @@ -287,7 +288,8 @@ impl InstallationKeySignature { } } -#[async_trait] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl Signature for InstallationKeySignature { async fn recover_signer(&self) -> Result { let signature: Ed25519Signature = @@ -342,7 +344,8 @@ impl LegacyDelegatedSignature { } } -#[async_trait] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl Signature for LegacyDelegatedSignature { async fn recover_signer(&self) -> Result { // Recover the RecoverableEcdsaSignature of the legacy signer(address of the legacy key) @@ -463,7 +466,10 @@ impl ValidatedLegacySignedPublicKey { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; use crate::{ associations::{ @@ -481,7 +487,8 @@ mod tests { use xmtp_proto::xmtp::message_contents::SignedPublicKey as LegacySignedPublicKeyProto; use xmtp_v2::k256_helper::sign_sha256; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn validate_good_key_round_trip() { let proto_bytes = vec![ 10, 79, 8, 192, 195, 165, 174, 203, 153, 231, 213, 23, 26, 67, 10, 65, 4, 216, 84, 174, @@ -504,7 +511,8 @@ mod tests { assert_eq!(validated_key.account_address(), account_address); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn validate_malformed_key() { let proto_bytes = vec![ 10, 79, 8, 192, 195, 165, 174, 203, 153, 231, 213, 23, 26, 67, 10, 65, 4, 216, 84, 174, @@ -524,7 +532,8 @@ mod tests { )); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn recover_signer_ecdsa() { let wallet: LocalWallet = LocalWallet::new(&mut rand::thread_rng()); let unsigned_action = UnsignedCreateInbox { @@ -544,7 +553,8 @@ mod tests { assert_eq!(expected, actual); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn recover_signer_erc1271() { let wallet: LocalWallet = LocalWallet::new(&mut rand::thread_rng()); @@ -560,7 +570,8 @@ mod tests { assert_eq!(expected, actual); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn recover_signer_installation() { let signing_key: SigningKey = SigningKey::generate(&mut rand::thread_rng()); let verifying_key = signing_key.verifying_key(); @@ -585,7 +596,8 @@ mod tests { } // Test the happy path with LocalWallet & fail path with a secp256k1 signer. - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn recover_signer_legacy() { let signature_text = "test_legacy_signature".to_string(); let account_address = "0x0bd00b21af9a2d538103c3aaf95cb507f8af1b28".to_string(); diff --git a/xmtp_id/src/associations/state.rs b/xmtp_id/src/associations/state.rs index 83cc8752e..405007b00 100644 --- a/xmtp_id/src/associations/state.rs +++ b/xmtp_id/src/associations/state.rs @@ -178,12 +178,16 @@ impl AssociationState { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::associations::test_utils::rand_string; use super::*; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn can_add_remove() { let starting_state = AssociationState::new(rand_string(), 0); let new_entity = Member::default(); @@ -192,7 +196,8 @@ mod tests { assert!(starting_state.get(&new_entity.identifier).is_none()); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn can_diff() { let starting_state = AssociationState::new(rand_string(), 0); let entity_1 = Member::default(); diff --git a/xmtp_id/src/associations/test_utils.rs b/xmtp_id/src/associations/test_utils.rs index f3cd5f2b7..e02699386 100644 --- a/xmtp_id/src/associations/test_utils.rs +++ b/xmtp_id/src/associations/test_utils.rs @@ -61,8 +61,8 @@ impl MockSignature { }) } } - -#[async_trait::async_trait] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] impl Signature for MockSignature { fn signature_kind(&self) -> SignatureKind { self.signature_kind.clone() diff --git a/xmtp_id/src/associations/unsigned_actions.rs b/xmtp_id/src/associations/unsigned_actions.rs index 4c89e2d31..13f3480c3 100644 --- a/xmtp_id/src/associations/unsigned_actions.rs +++ b/xmtp_id/src/associations/unsigned_actions.rs @@ -138,12 +138,16 @@ fn pretty_timestamp(ns_date: u64) -> String { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::associations::hashes::generate_inbox_id; use super::*; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn create_signatures() { let account_address = "0x123".to_string(); let client_timestamp_ns: u64 = 12; diff --git a/xmtp_id/src/lib.rs b/xmtp_id/src/lib.rs index bf7ee091a..f68f5599c 100644 --- a/xmtp_id/src/lib.rs +++ b/xmtp_id/src/lib.rs @@ -12,6 +12,10 @@ use openmls_traits::types::CryptoError; use thiserror::Error; use xmtp_cryptography::signature::{h160addr_to_string, RecoverableSignature, SignatureError}; +use crate::associations::Signature; + +pub type GenericSignature = Box; + #[derive(Debug, Error)] pub enum IdentityError { #[error("generating key-pairs: {0}")] @@ -40,7 +44,6 @@ pub async fn is_smart_contract( Ok(!code.is_empty()) } -// TODO: Remove this trait pub trait InboxOwner { /// Get address of the wallet. fn get_address(&self) -> String; @@ -54,7 +57,7 @@ impl InboxOwner for LocalWallet { } fn sign(&self, text: &str) -> Result { - let message_hash = ethers_core::utils::hash_message(text); + let message_hash = ethers::core::utils::hash_message(text); Ok(self.sign_hash(message_hash)?.to_vec().into()) } } @@ -62,9 +65,11 @@ impl InboxOwner for LocalWallet { #[cfg(test)] mod tests { use super::*; - use crate::scw_verifier::tests::with_smart_contracts; use ethers::contract::abigen; + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + abigen!( CoinbaseSmartWallet, "artifact/CoinbaseSmartWallet.json", @@ -77,8 +82,11 @@ mod tests { derives(serde::Serialize, serde::Deserialize) ); - #[tokio::test] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[cfg(not(target_arch = "wasm32"))] async fn test_is_smart_contract() { + use crate::scw_verifier::tests::with_smart_contracts; + with_smart_contracts(|anvil, _provider, _client, smart_contracts| async move { let deployer: LocalWallet = anvil.keys()[0].clone().into(); let factory = smart_contracts.coinbase_smart_wallet_factory(); diff --git a/xmtp_id/src/scw_verifier.rs b/xmtp_id/src/scw_verifier.rs index bde5ce5ea..4bc2c8b85 100644 --- a/xmtp_id/src/scw_verifier.rs +++ b/xmtp_id/src/scw_verifier.rs @@ -98,8 +98,10 @@ impl SmartContractWalletVerifier { } } -#[cfg(test)] -pub mod tests { +// Anvil does not work with WASM +// because its a wrapper over the system-binary +#[cfg(all(test, not(target_arch = "wasm32")))] +pub(crate) mod tests { use crate::is_smart_contract; use super::*; diff --git a/xmtp_id/src/utils/mod.rs b/xmtp_id/src/utils/mod.rs index 891194f27..2b4d79f2a 100644 --- a/xmtp_id/src/utils/mod.rs +++ b/xmtp_id/src/utils/mod.rs @@ -1,3 +1,11 @@ -pub mod time; +use wasm_timer::{SystemTime, UNIX_EPOCH}; -pub use time::*; +pub const NS_IN_SEC: i64 = 1_000_000_000; + +pub fn now_ns() -> i64 { + let now = SystemTime::now(); + + now.duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_nanos() as i64 +} diff --git a/xmtp_id/src/utils/time.rs b/xmtp_id/src/utils/time.rs index 71917ed39..8b1378917 100644 --- a/xmtp_id/src/utils/time.rs +++ b/xmtp_id/src/utils/time.rs @@ -1,11 +1 @@ -use std::time::{SystemTime, UNIX_EPOCH}; -pub const NS_IN_SEC: i64 = 1_000_000_000; - -pub fn now_ns() -> i64 { - let now = SystemTime::now(); - - now.duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_nanos() as i64 -} diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index c992137ba..3b071cf11 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -1,103 +1,127 @@ [package] edition = "2021" name = "xmtp_mls" -version.workspace = true +version = "0.1.0" -[[bin]] -doc = false -name = "update-schema" -path = "src/bin/update-schema.rs" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown", "aarch64-apple-darwin"] [features] -bench = [ - "test-utils", - "indicatif", - "tracing-subscriber", - "anyhow", - "tracing-flame", - "once_cell", - "xmtp_api_grpc", -] -default = ["native"] -http-api = ["xmtp_api_http"] -native = ["libsqlite3-sys/bundled-sqlcipher-vendored-openssl"] +default = [] test-utils = [] +bench = ["test-utils", "indicatif", "tracing-subscriber", "anyhow", "tracing-flame", "once_cell", "xmtp_api_grpc", "criterion"] +update-schema = ["toml"] +http-api = ["xmtp_api_http"] [dependencies] -aes-gcm = { version = "0.10.3", features = ["std"] } -async-stream.workspace = true -async-trait.workspace = true bincode = "1.3.3" -chrono = { workspace = true } -diesel = { version = "2.2.2", features = [ - "sqlite", - "r2d2", - "returning_clauses_for_sqlite_3_35", -] } -diesel_migrations = { version = "2.2.0", features = ["sqlite"] } -ed25519-dalek = "2.1.1" -ethers-core.workspace = true -ethers.workspace = true -futures.workspace = true +parking_lot = "0.12.3" hex.workspace = true -libsqlite3-sys = { version = "0.29.0", optional = true } log.workspace = true -openmls = { workspace = true, features = ["test-utils"] } +tracing.workspace = true openmls_basic_credential = { workspace = true } openmls_rust_crypto = { workspace = true } openmls_traits = { workspace = true } -parking_lot = "0.12.3" +aes-gcm = { version = "0.10.3", features = ["std"] } +ed25519-dalek = "2.1.1" +sha2.workspace = true +tls_codec = { workspace = true } prost = { workspace = true, features = ["prost-derive"] } rand = { workspace = true } -reqwest = { version = "0.12.4", features = ["stream"] } serde = { workspace = true } serde_json.workspace = true -sha2.workspace = true -smart-default = "0.7.1" thiserror = { workspace = true } -tls_codec = { workspace = true } -tokio = { workspace = true, features = [ - "macros", - "rt-multi-thread", - "tracing", -] } -tokio-stream = { version = "0.1", features = ["sync"] } -toml = "0.8.4" -tracing.workspace = true +tokio-stream = { version = "0.1", features = ["sync"] } +async-stream.workspace = true +async-trait.workspace = true +futures.workspace = true +reqwest = { version = "0.12.4", features = ["stream"] } + +# XMTP/Local xmtp_cryptography = { workspace = true } xmtp_id = { path = "../xmtp_id" } xmtp_proto = { workspace = true, features = ["proto_full", "convert"] } xmtp_v2 = { path = "../xmtp_v2" } +# Optional/Features +toml = { version = "0.8.4", optional = true } +# for tests outside of the wasm environment +xmtp_api_http = { path = "../xmtp_api_http", optional = true } + # Test/Bench Utils -anyhow = { workspace = true, optional = true } +tracing-subscriber = { workspace = true, features = ["env-filter"], optional = true } indicatif = { version = "0.17", optional = true } -once_cell = { version = "1.19", optional = true } +anyhow = { workspace = true, optional = true } tracing-flame = { version = "0.2", optional = true } -tracing-subscriber = { workspace = true, optional = true } +once_cell = { version = "1.19", optional = true } +criterion = { version = "0.5", features = ["html_reports", "async_tokio"], optional = true } + + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +# Native Dependencies +libsqlite3-sys = { version = "0.29.0", features = ["bundled-sqlcipher-vendored-openssl" ] } +diesel = { workspace = true, features = [ + "r2d2", + "returning_clauses_for_sqlite_3_35", + "sqlite", +] } xmtp_api_grpc = { path = "../xmtp_api_grpc", optional = true } -xmtp_api_http = { path = "../xmtp_api_http", optional = true } +chrono = { workspace = true, features = ["clock"] } +tokio = { workspace = true, features = ["macros", "tracing", "rt", "rt-multi-thread"] } +diesel_migrations = { workspace = true, features = ["sqlite"] } +openmls = { workspace = true, features = ["test-utils"] } + + +[target.'cfg(target_arch = "wasm32")'.dependencies] +diesel-wasm-sqlite = { workspace = true, features = ["r2d2"] } +diesel = { workspace = true, features = [ + "r2d2", + "returning_clauses_for_sqlite_3_35", +] } +diesel_migrations.workspace = true +getrandom = { version = "0.2", features = ["js"] } +chrono = { workspace = true, features = ["wasmbind"] } +tokio = { workspace = true, features = ["macros", "rt"] } +openmls = { workspace = true, features = ["test-utils", "js"] } +gloo-timers = { workspace = true, features = ["futures"] } + [dev-dependencies] -anyhow.workspace = true -async-barrier = "1.1" -criterion = { version = "0.5", features = ["html_reports", "async_tokio"] } -ctor.workspace = true -flume = "0.11" +ethers.workspace = true mockall = "0.13.0" -mockito = "1.4.0" -tempfile = "3.5.0" tracing-log = "0.2.0" -tracing-subscriber.workspace = true tracing-test = "0.2.4" -tracing.workspace = true -xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_id = { path = "../xmtp_id", features = ["test-utils"] } +anyhow.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +xmtp_api_grpc = { path = "../xmtp_api_grpc" } +tracing-subscriber.workspace = true +tempfile = "3.5.0" +mockito = "1.4.0" +ctor.workspace = true + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +xmtp_api_http = { path = "../xmtp_api_http" } +tracing-wasm = { version = "0.2" } +diesel-wasm-sqlite = { workspace = true, features = ["unsafe-debug-query", "r2d2"] } +console_error_panic_hook = { version = "0.1"} +wasm-bindgen-test.workspace = true + +[[bin]] +doc = false +name = "update-schema" +path = "src/bin/update-schema.rs" +required-features = ["update-schema"] [[bench]] -harness = false name = "group_limit" +harness = false [[bench]] -harness = false name = "crypto" +harness = false + + diff --git a/xmtp_mls/src/api/identity.rs b/xmtp_mls/src/api/identity.rs index 5a7a5a245..57d01c972 100644 --- a/xmtp_mls/src/api/identity.rs +++ b/xmtp_mls/src/api/identity.rs @@ -151,7 +151,10 @@ where } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::super::test_utils::*; use super::GetIdentityUpdatesV2Filter; use crate::{api::ApiClientWrapper, retry::Retry}; @@ -168,7 +171,8 @@ mod tests { IdentityUpdate::new_test(vec![Action::CreateInbox(CreateInbox::default())], inbox_id) } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn publish_identity_update() { let mut mock_api = MockApiClient::new(); let inbox_id = rand_string(); @@ -185,7 +189,8 @@ mod tests { assert!(result.is_ok()); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn get_identity_update_v2() { let mut mock_api = MockApiClient::new(); let inbox_id = rand_string(); @@ -231,7 +236,8 @@ mod tests { ); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn get_inbox_ids() { let mut mock_api = MockApiClient::new(); let inbox_id = rand_string(); diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index 7ac073f26..23826e41a 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -290,6 +290,9 @@ where #[cfg(test)] pub mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::super::test_utils::*; use super::super::*; @@ -301,7 +304,8 @@ pub mod tests { }, }; - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] async fn test_upload_key_package() { let mut mock_api = MockApiClient::new(); let key_package = vec![1, 2, 3]; @@ -322,7 +326,8 @@ pub mod tests { assert!(result.is_ok()); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_fetch_key_packages() { let mut mock_api = MockApiClient::new(); let installation_keys: Vec> = vec![vec![1, 2, 3], vec![4, 5, 6]]; @@ -354,7 +359,8 @@ pub mod tests { } } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_read_group_messages_single_page() { let mut mock_api = MockApiClient::new(); let group_id = vec![1, 2, 3, 4]; @@ -384,7 +390,8 @@ pub mod tests { assert_eq!(result.len(), 10); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_read_group_messages_single_page_exactly_100_results() { let mut mock_api = MockApiClient::new(); let group_id = vec![1, 2, 3, 4]; @@ -415,7 +422,8 @@ pub mod tests { assert_eq!(result.len(), 100); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_read_topic_multi_page() { let mut mock_api = MockApiClient::new(); let group_id = vec![1, 2, 3, 4]; @@ -465,7 +473,8 @@ pub mod tests { assert_eq!(result.len(), 200); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn it_retries_twice_then_succeeds() { let mut mock_api = MockApiClient::new(); let group_id = vec![1, 2, 3]; diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index 973ab17b4..cd1e1ba7e 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use mockall::mock; use xmtp_proto::{ api_client::{ @@ -38,6 +37,8 @@ pub fn build_group_messages(num_messages: usize, group_id: Vec) -> Vec Result<(), Error>; } - #[async_trait] + #[async_trait::async_trait] impl XmtpMlsClient for ApiClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error>; async fn fetch_key_packages( @@ -61,14 +62,52 @@ mock! { async fn subscribe_welcome_messages(&self, request: SubscribeWelcomeMessagesRequest) -> Result; } - #[async_trait] + #[async_trait::async_trait] impl XmtpIdentityClient for ApiClient { async fn publish_identity_update(&self, request: PublishIdentityUpdateRequest) -> Result; async fn get_identity_updates_v2(&self, request: GetIdentityUpdatesV2Request) -> Result; async fn get_inbox_ids(&self, request: GetInboxIdsRequest) -> Result; } - #[async_trait] + #[async_trait::async_trait] + impl XmtpTestClient for ApiClient { + async fn create_local() -> Self { ApiClient } + async fn create_dev() -> Self { ApiClient } + } +} + +#[cfg(target_arch = "wasm32")] +mock! { + pub ApiClient {} + + impl ClientWithMetadata for ApiClient { + fn set_libxmtp_version(&mut self, version: String) -> Result<(), Error>; + fn set_app_version(&mut self, version: String) -> Result<(), Error>; + } + + #[async_trait::async_trait(?Send)] + impl XmtpMlsClient for ApiClient { + async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error>; + async fn fetch_key_packages( + &self, + request: FetchKeyPackagesRequest, + ) -> Result; + async fn send_group_messages(&self, request: SendGroupMessagesRequest) -> Result<(), Error>; + async fn send_welcome_messages(&self, request: SendWelcomeMessagesRequest) -> Result<(), Error>; + async fn query_group_messages(&self, request: QueryGroupMessagesRequest) -> Result; + async fn query_welcome_messages(&self, request: QueryWelcomeMessagesRequest) -> Result; + async fn subscribe_group_messages(&self, request: SubscribeGroupMessagesRequest) -> Result; + async fn subscribe_welcome_messages(&self, request: SubscribeWelcomeMessagesRequest) -> Result; + } + + #[async_trait::async_trait(?Send)] + impl XmtpIdentityClient for ApiClient { + async fn publish_identity_update(&self, request: PublishIdentityUpdateRequest) -> Result; + async fn get_identity_updates_v2(&self, request: GetIdentityUpdatesV2Request) -> Result; + async fn get_inbox_ids(&self, request: GetInboxIdsRequest) -> Result; + } + + #[async_trait::async_trait(?Send)] impl XmtpTestClient for ApiClient { async fn create_local() -> Self { ApiClient } async fn create_dev() -> Self { ApiClient } diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index dce196d84..51816ec41 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -132,7 +132,10 @@ where } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::api::ApiClientWrapper; use crate::builder::ClientBuilderError; use crate::identity::IdentityError; @@ -142,8 +145,8 @@ mod tests { api::test_utils::*, identity::Identity, storage::identity::StoredIdentity, utils::test::rand_vec, Store, }; + use ethers::core::k256; use ethers::signers::Signer; - use ethers_core::k256; use openmls::credentials::{Credential, CredentialType}; use openmls_basic_credential::SignatureKeyPair; use openmls_traits::types::SignatureScheme; @@ -228,7 +231,8 @@ mod tests { (buf, address.to_lowercase()) } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn builder_test() { let wallet = generate_local_wallet(); let client = ClientBuilder::new_test_client(&wallet).await; @@ -236,7 +240,8 @@ mod tests { } // Test client creation using various identity strategies that creates new inboxes - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_client_creation() { struct IdentityStrategyTestCase { strategy: IdentityStrategy, @@ -346,7 +351,8 @@ mod tests { // - create client2 from same db with [IdentityStrategy::CachedOnly] // - create client3 from same db with [IdentityStrategy::CreateIfNotFound] // - create client4 with different db. - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_2nd_time_client_creation() { let (legacy_key, legacy_account_address) = generate_random_legacy_key().await; let identity_strategy = IdentityStrategy::CreateIfNotFound( @@ -412,7 +418,8 @@ mod tests { } // Should return error if inbox associated with given account_address doesn't match the provided one. - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn api_identity_mismatch() { let mut mock_api = MockApiClient::new(); let tmpdb = tmp_path(); @@ -448,7 +455,8 @@ mod tests { } // Use the account_address associated inbox - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn api_identity_happy_path() { let mut mock_api = MockApiClient::new(); let tmpdb = tmp_path(); @@ -477,7 +485,8 @@ mod tests { } // Use a stored identity as long as the inbox_id matches the one provided. - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn stored_identity_happy_path() { let mock_api = MockApiClient::new(); let tmpdb = tmp_path(); @@ -503,7 +512,8 @@ mod tests { assert!(identity.initialize_identity(&wrapper, &store).await.is_ok()); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn stored_identity_mismatch() { let mock_api = MockApiClient::new(); @@ -541,7 +551,8 @@ mod tests { ); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn identity_persistence_test() { let tmpdb = tmp_path(); let wallet = &generate_local_wallet(); diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 7fb3219b1..2352defe6 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -555,7 +555,7 @@ where ) -> Result where Fut: Future>, - ProcessingFn: FnOnce(XmtpOpenMlsProvider) -> Fut + Send, + ProcessingFn: FnOnce(XmtpOpenMlsProvider) -> Fut, { self.store() .transaction_async(|provider| async move { @@ -746,7 +746,10 @@ pub fn deserialize_welcome(welcome_bytes: &Vec) -> Result for GroupUpdatedCodec { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use xmtp_proto::xmtp::mls::message_contents::{group_updated::Inbox, GroupUpdated}; use crate::utils::test::rand_string; use super::*; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_encode_decode() { let new_member = Inbox { inbox_id: rand_string(), diff --git a/xmtp_mls/src/codecs/membership_change.rs b/xmtp_mls/src/codecs/membership_change.rs index d1597d93e..e64f50df6 100644 --- a/xmtp_mls/src/codecs/membership_change.rs +++ b/xmtp_mls/src/codecs/membership_change.rs @@ -48,14 +48,18 @@ impl ContentCodec for GroupMembershipChangeCodec { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use xmtp_proto::xmtp::mls::message_contents::MembershipChange; use crate::utils::test::{rand_string, rand_vec}; use super::*; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_encode_decode() { let new_member = MembershipChange { installation_ids: vec![rand_vec()], diff --git a/xmtp_mls/src/codecs/text.rs b/xmtp_mls/src/codecs/text.rs index 5823f595c..d016f1513 100644 --- a/xmtp_mls/src/codecs/text.rs +++ b/xmtp_mls/src/codecs/text.rs @@ -54,10 +54,14 @@ impl ContentCodec for TextCodec { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::codecs::{text::TextCodec, ContentCodec}; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn can_encode_and_decode_text() { let text = "Hello, world!"; let encoded_content = diff --git a/xmtp_mls/src/groups/group_membership.rs b/xmtp_mls/src/groups/group_membership.rs index a614a7ea2..05979903b 100644 --- a/xmtp_mls/src/groups/group_membership.rs +++ b/xmtp_mls/src/groups/group_membership.rs @@ -113,10 +113,14 @@ pub struct MembershipDiff<'inbox_id> { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::GroupMembership; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_equality_works() { let inbox_id_1 = "inbox_1".to_string(); let sequence_id_1: u64 = 1; @@ -135,7 +139,8 @@ mod tests { assert!(member_map_1.ne(&member_map_2)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_diff() { let mut initial_members = GroupMembership::new(); initial_members.add("inbox_1".into(), 1); diff --git a/xmtp_mls/src/groups/group_permissions.rs b/xmtp_mls/src/groups/group_permissions.rs index 05d6f691c..665d20fd1 100644 --- a/xmtp_mls/src/groups/group_permissions.rs +++ b/xmtp_mls/src/groups/group_permissions.rs @@ -1149,7 +1149,10 @@ impl std::fmt::Display for PreconfiguredPolicies { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::{ groups::{group_mutable_metadata::MetadataField, validated_commit::MutableMetadataChanges}, utils::test::{rand_string, rand_vec}, @@ -1225,7 +1228,8 @@ mod tests { } } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_allow_all() { let permissions = PolicySet::new( MembershipPolicies::allow(), @@ -1240,7 +1244,8 @@ mod tests { assert!(permissions.evaluate_commit(&commit)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_deny() { let permissions = PolicySet::new( MembershipPolicies::deny(), @@ -1260,7 +1265,8 @@ mod tests { assert!(!permissions.evaluate_commit(&member_removed_commit)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_actor_is_creator() { let permissions = PolicySet::new( MembershipPolicies::allow_if_actor_super_admin(), @@ -1285,7 +1291,8 @@ mod tests { assert!(!permissions.evaluate_commit(&commit_without_creator)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_allow_same_member() { let permissions = PolicySet::new( MembershipPolicies::allow_same_member(), @@ -1305,7 +1312,8 @@ mod tests { assert!(!permissions.evaluate_commit(&commit_with_different_member)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_and_condition() { let permissions = PolicySet::new( MembershipPolicies::and(vec![ @@ -1324,7 +1332,8 @@ mod tests { assert!(!permissions.evaluate_commit(&member_added_commit)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_any_condition() { let permissions = PolicySet::new( MembershipPolicies::any(vec![ @@ -1343,7 +1352,8 @@ mod tests { assert!(permissions.evaluate_commit(&member_added_commit)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_serialize() { let permissions = PolicySet::new( MembershipPolicies::any(vec![ @@ -1370,7 +1380,8 @@ mod tests { assert!(permissions.eq(&restored)) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_update_group_name() { let allow_permissions = PolicySet::new( MembershipPolicies::allow(), @@ -1404,7 +1415,8 @@ mod tests { assert!(!deny_permissions.evaluate_commit(&member_added_commit)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_disallow_serialize_allow_same_member() { let permissions = PolicySet::new( MembershipPolicies::allow_same_member(), @@ -1419,7 +1431,8 @@ mod tests { assert!(proto_result.is_err()); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_preconfigured_policy() { let group_permissions = GroupMutablePermissions::new(policy_all_members()); @@ -1439,7 +1452,8 @@ mod tests { ); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_preconfigured_policy_equality_new_metadata() { let mut metadata_policies_map = MetadataPolicies::default_map(MetadataPolicies::allow()); metadata_policies_map.insert("new_metadata_field".to_string(), MetadataPolicies::allow()); @@ -1472,7 +1486,8 @@ mod tests { assert!(is_policy_admin_only(&policy_set_new_metadata_permission).unwrap()); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_permission_update() { let permissions = PolicySet::new( MembershipPolicies::allow(), @@ -1492,7 +1507,8 @@ mod tests { assert!(permissions.evaluate_commit(&commit)); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_evaluate_field_with_unknown_policy() { // Create a group whose default metadata can be updated by any member let permissions = PolicySet::new( diff --git a/xmtp_mls/src/groups/intents.rs b/xmtp_mls/src/groups/intents.rs index 588c832d9..170012504 100644 --- a/xmtp_mls/src/groups/intents.rs +++ b/xmtp_mls/src/groups/intents.rs @@ -668,10 +668,14 @@ impl TryFrom> for PostCommitAction { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_serialize_send_message() { let message = vec![1, 2, 3]; let intent = SendMessageIntentData::new(message.clone()); @@ -681,7 +685,8 @@ mod tests { assert_eq!(restored_intent.message, message); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_serialize_update_membership() { let mut membership_updates = HashMap::new(); membership_updates.insert("foo".to_string(), 123); @@ -700,7 +705,8 @@ mod tests { assert_eq!(intent.removed_members, restored_intent.removed_members); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_serialize_update_metadata() { let intent = UpdateMetadataIntentData::new_update_group_name("group name".to_string()); let as_bytes: Vec = intent.clone().into(); diff --git a/xmtp_mls/src/groups/members.rs b/xmtp_mls/src/groups/members.rs index 0cdedf843..53fe6e038 100644 --- a/xmtp_mls/src/groups/members.rs +++ b/xmtp_mls/src/groups/members.rs @@ -83,46 +83,3 @@ impl MlsGroup { Ok(members) } } - -#[cfg(test)] -mod tests { - // use xmtp_cryptography::utils::generate_local_wallet; - - // use crate::builder::ClientBuilder; - - #[tokio::test] - #[ignore] - async fn test_member_list() { - // let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; - // let bola_wallet = generate_local_wallet(); - // // Add two separate installations for Bola - // let bola_a = ClientBuilder::new_test_client(&bola_wallet).await; - // let bola_b = ClientBuilder::new_test_client(&bola_wallet).await; - - // let group = amal.create_group(None).unwrap(); - // Add both of Bola's installations to the group - // group - // .add_members_by_installation_id( - // vec![ - // bola_a.installation_public_key(), - // bola_b.installation_public_key(), - // ], - // &amal, - // ) - // .await - // .unwrap(); - - // let members = group.members().unwrap(); - // // The three installations should count as two members - // assert_eq!(members.len(), 2); - - // for member in members { - // if member.account_address.eq(&amal.account_address()) { - // assert_eq!(member.installation_ids.len(), 1); - // } - // if member.account_address.eq(&bola_a.account_address()) { - // assert_eq!(member.installation_ids.len(), 2); - // } - // } - } -} diff --git a/xmtp_mls/src/groups/message_history.rs b/xmtp_mls/src/groups/message_history.rs index 0f0768397..379410d03 100644 --- a/xmtp_mls/src/groups/message_history.rs +++ b/xmtp_mls/src/groups/message_history.rs @@ -779,8 +779,10 @@ fn new_pin() -> String { format!("{:04}", pin) } -#[cfg(test)] -mod tests { +#[cfg(all(not(target_arch = "wasm32"), test))] +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); const HISTORY_SERVER_HOST: &str = "0.0.0.0"; const HISTORY_SERVER_PORT: u16 = 5558; diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 8499fd121..3349de508 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -6,8 +6,8 @@ pub mod intents; pub mod members; #[allow(dead_code)] pub mod message_history; -mod subscriptions; -mod sync; +pub(super) mod subscriptions; +pub(super) mod sync; pub mod validated_commit; use intents::SendMessageIntentData; @@ -1273,13 +1273,15 @@ fn build_group_join_config() -> MlsGroupJoinConfig { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use diesel::connection::SimpleConnection; use futures::future::join_all; use openmls::prelude::{tls_codec::Serialize, Member, MlsGroup as OpenMlsGroup}; use prost::Message; use std::sync::Arc; - use tracing_test::traced_test; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_proto::xmtp::mls::message_contents::EncodedContent; @@ -1375,7 +1377,8 @@ mod tests { .unwrap(); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_send_message() { let wallet = generate_local_wallet(); let client = ClientBuilder::new_test_client(&wallet).await; @@ -1395,7 +1398,8 @@ mod tests { assert_eq!(messages.len(), 2); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_receive_self_message() { let wallet = generate_local_wallet(); let client = ClientBuilder::new_test_client(&wallet).await; @@ -1418,7 +1422,8 @@ mod tests { assert_eq!(messages.first().unwrap().decrypted_message_bytes, msg); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_receive_message_from_other() { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1450,7 +1455,8 @@ mod tests { } // Test members function from non group creator - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_members_func_from_non_creator() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1503,7 +1509,8 @@ mod tests { // Amal and Bola will both try and add Charlie from the same epoch. // The group should resolve to a consistent state - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_add_member_conflict() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1597,9 +1604,16 @@ mod tests { assert!(matching_message.is_some()); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] - #[traced_test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 1) + )] + #[tracing_test::traced_test] async fn test_create_from_welcome_validation() { + if cfg!(target_arch = "wasm32") { + let _ = tracing_log::LogTracer::init_with_filter(log::LevelFilter::Debug); + } let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1632,7 +1646,8 @@ mod tests { assert_logged!("failed to create group from welcome", 1); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_add_inbox() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let client_2 = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1656,7 +1671,8 @@ mod tests { assert_eq!(messages.len(), 1); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_add_invalid_member() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let group = client @@ -1670,7 +1686,8 @@ mod tests { assert!(result.is_err()); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_add_unregistered_member() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let unconnected_wallet_address = generate_local_wallet().get_address(); @@ -1684,7 +1701,8 @@ mod tests { assert!(result.is_err()); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_remove_inbox() { let client_1 = ClientBuilder::new_test_client(&generate_local_wallet()).await; // Add another client onto the network @@ -1722,7 +1740,8 @@ mod tests { assert_eq!(messages.len(), 2); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_key_update() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_client = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1764,7 +1783,8 @@ mod tests { assert_eq!(bola_messages.len(), 1); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_post_commit() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let client_2 = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1787,7 +1807,8 @@ mod tests { assert_eq!(welcome_messages.len(), 1); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_remove_by_account_address() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_wallet = &generate_local_wallet(); @@ -1838,7 +1859,8 @@ mod tests { .unwrap()) } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_removed_members_cannot_send_message_to_others() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_wallet = &generate_local_wallet(); @@ -1898,9 +1920,8 @@ mod tests { assert_eq!(amal_messages.len(), 1); } - // TODO:nm add more tests for filling in missing installations - - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_add_missing_installations() { // Setup for test let amal_wallet = generate_local_wallet(); @@ -1933,7 +1954,11 @@ mod tests { assert_eq!(num_members, 3); } - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 10) + )] async fn test_self_resolve_epoch_mismatch() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1983,7 +2008,8 @@ mod tests { assert!(expected_latest_message.eq(&dave_latest_message.decrypted_message_bytes)); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_group_permissions() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2009,7 +2035,8 @@ mod tests { .is_err(),); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_group_options() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2051,9 +2078,8 @@ mod tests { assert_eq!(amal_group_pinned_frame_url, "pinned frame"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] - // TODO: Need to enforce limits on max wallets on `add_members_by_inbox_id` and break up - // requests into multiple transactions + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] #[ignore] async fn test_max_limit_add() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2078,7 +2104,8 @@ mod tests { .is_err(),); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_group_mutable_data() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2170,7 +2197,8 @@ mod tests { assert_eq!(bola_group_name, "New Group Name 1"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_update_group_image_url_square() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2208,7 +2236,8 @@ mod tests { assert_eq!(amal_group_image_url, "a url"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_update_group_pinned_frame_url() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2246,7 +2275,8 @@ mod tests { assert_eq!(amal_group_pinned_frame_url, "a frame url"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_group_mutable_data_group_permissions() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_wallet = generate_local_wallet(); @@ -2333,7 +2363,8 @@ mod tests { assert_eq!(amal_group_name, "New Group Name 2"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_group_admin_list_update() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_wallet = generate_local_wallet(); @@ -2443,7 +2474,8 @@ mod tests { .expect_err("expected err"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_group_super_admin_list_update() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2542,7 +2574,8 @@ mod tests { .expect_err("expected err"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_group_members_permission_level_update() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2639,7 +2672,8 @@ mod tests { assert_eq!(count_member, 0, "no members have no admin status"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_staged_welcome() { // Create Clients let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2679,7 +2713,8 @@ mod tests { ); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_can_read_group_creator_inbox_id() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let policy_set = Some(PreconfiguredPolicies::AllMembers.to_policy_set()); @@ -2705,7 +2740,8 @@ mod tests { assert_eq!(protected_metadata.creator_inbox_id, amal.inbox_id()); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_can_update_gce_after_failed_commit() { // Step 1: Amal creates a group let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2771,7 +2807,8 @@ mod tests { assert_eq!(bola_group_name, "Name Update 2"); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_can_update_permissions_after_group_creation() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let policy_set = Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()); @@ -2837,7 +2874,8 @@ mod tests { assert_eq!(members.len(), 3); } - #[tokio::test(flavor = "multi_thread")] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] async fn test_optimistic_send() { let amal = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bola_wallet = generate_local_wallet(); @@ -2926,7 +2964,8 @@ mod tests { ); } - #[tokio::test(flavor = "multi_thread")] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] async fn process_messages_abort_on_retryable_error() { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2976,8 +3015,12 @@ mod tests { } } - #[tokio::test(flavor = "multi_thread", worker_threads = 5)] - async fn test_paralell_syncs() { + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 5) + )] + async fn test_parallel_syncs() { let wallet = generate_local_wallet(); let alix1 = Arc::new(ClientBuilder::new_test_client(&wallet).await); let alix1_group = alix1 @@ -2992,7 +3035,7 @@ mod tests { let client_clone = alix1.clone(); // Each of these syncs is going to trigger the client to invite alix2 to the group // because of the race - tokio::spawn(async move { group_clone.sync(&client_clone).await }) + crate::spawn(async move { group_clone.sync(&client_clone).await }) }) .collect(); @@ -3086,7 +3129,11 @@ mod tests { * We need to be safe even in situations where there are multiple * intents that do the same thing, leading to conflicts */ - #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 5) + )] async fn add_missing_installs_reentrancy() { let wallet = generate_local_wallet(); let alix1 = ClientBuilder::new_test_client(&wallet).await; @@ -3173,7 +3220,11 @@ mod tests { .any(|m| m.decrypted_message_bytes == "hi from alix1".as_bytes())); } - #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 5) + )] async fn respect_allow_epoch_increment() { let wallet = generate_local_wallet(); let client = ClientBuilder::new_test_client(&wallet).await; diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index cb8894271..01b564697 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::pin::Pin; use std::sync::Arc; use futures::Stream; @@ -124,7 +123,7 @@ impl MlsGroup { pub async fn stream( &self, client: Arc>, - ) -> Result + Send + '_>>, GroupError> + ) -> Result, GroupError> where ApiClient: crate::XmtpApi, { @@ -163,7 +162,10 @@ impl MlsGroup { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; use std::time::Duration; use tokio_stream::wrappers::UnboundedReceiverStream; @@ -175,7 +177,11 @@ mod tests { }; use futures::StreamExt; - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 1) + )] async fn test_decode_group_message_bytes() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -212,7 +218,11 @@ mod tests { } } - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 10) + )] async fn test_subscribe_messages() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); @@ -236,8 +246,9 @@ mod tests { let notify_ptr = notify.clone(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let mut stream = UnboundedReceiverStream::new(rx); - tokio::spawn(async move { - let mut stream = bola_group_ptr.stream(bola_ptr).await.unwrap(); + crate::spawn(async move { + let stream = bola_group_ptr.stream(bola_ptr).await.unwrap(); + futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); notify_ptr.notify_one(); @@ -268,7 +279,11 @@ mod tests { assert_eq!(second_val.decrypted_message_bytes, "goodbye".as_bytes()); } - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 10) + )] async fn test_subscribe_multiple() { let amal = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let group = Arc::new( @@ -280,8 +295,9 @@ mod tests { let stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); let amal_ptr = amal.clone(); let group_ptr = group.clone(); - tokio::spawn(async move { - let mut stream = group_ptr.stream(amal_ptr).await.unwrap(); + crate::spawn(async move { + let stream = group_ptr.stream(amal_ptr).await.unwrap(); + futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); } @@ -305,7 +321,11 @@ mod tests { } } - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 5) + )] async fn test_subscribe_membership_changes() { let amal = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -322,9 +342,10 @@ mod tests { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let (start_tx, start_rx) = tokio::sync::oneshot::channel(); let mut stream = UnboundedReceiverStream::new(rx); - tokio::spawn(async move { - let mut stream = amal_group_ptr.stream(amal_ptr).await.unwrap(); + crate::spawn(async move { + let stream = amal_group_ptr.stream(amal_ptr).await.unwrap(); let _ = start_tx.send(()); + futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); notify_ptr.notify_one(); @@ -333,7 +354,7 @@ mod tests { // just to make sure stream is started let _ = start_rx.await; // Adding in a sleep, since the HTTP API client may acknowledge requests before they are ready - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + crate::sleep(tokio::time::Duration::from_millis(100)).await; amal_group .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index bbcfbc41d..fe39c8179 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -1304,14 +1304,18 @@ fn decode_staged_commit(data: Vec) -> Result for GroupUpdatedProto { } } } - -// TODO:nm bring these tests back in add/remove members PR -/* -#[cfg(test)] -mod tests { - use openmls::{ - credentials::{BasicCredential, CredentialWithKey}, - extensions::ExtensionType, - messages::proposals::ProposalType, - prelude::Capabilities, - prelude_test::KeyPackage, - }; - use xmtp_api_grpc::Client as GrpcClient; - use xmtp_cryptography::utils::generate_local_wallet; - - use super::ValidatedCommit; - use crate::{ - builder::ClientBuilder, - configuration::{ - CIPHERSUITE, GROUP_MEMBERSHIP_EXTENSION_ID, MUTABLE_METADATA_EXTENSION_ID, - }, - Client, - }; - - fn get_key_package(client: &Client) -> KeyPackage { - client - .identity() - .new_key_package(client.mls_provider().unwrap()) - .unwrap() - } - - #[tokio::test] - async fn test_membership_changes() { - let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; - let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; - let bola_key_package = get_key_package(&bola); - - let amal_group = amal.create_group(None, Default::default()).unwrap(); - let amal_provider = amal.mls_provider().unwrap(); - let mut mls_group = amal_group.load_mls_group(&amal_provider).unwrap(); - // Create a pending commit to add bola to the group - mls_group - .add_members( - &amal_provider, - &amal.identity().installation_keys, - &[bola_key_package], - ) - .unwrap(); - - let mut staged_commit = mls_group.pending_commit().unwrap(); - - let validated_commit = ValidatedCommit::from_staged_commit( - &amal, - amal_provider.conn_ref(), - staged_commit, - &mls_group, - ) - .await - .unwrap(); - - assert_eq!(validated_commit.added_inboxes.len(), 1); - assert_eq!(validated_commit.added_inboxes[0].inbox_id, bola.inbox_id()); - // Amal is the creator of the group and the actor - assert!(validated_commit.actor.is_creator); - // Bola is not the creator of the group - assert!(!validated_commit.added_inboxes[0].is_creator); - - // Merge the commit adding bola - mls_group.merge_pending_commit(&amal_provider).unwrap(); - // Now we are going to remove bola - - let bola_leaf_node = mls_group - .members() - .find(|m| { - m.signature_key - .eq(&bola.identity().installation_keys.public()) - }) - .unwrap() - .index; - mls_group - .remove_members( - &amal_provider, - &amal.identity().installation_keys, - &[bola_leaf_node], - ) - .unwrap(); - - staged_commit = mls_group.pending_commit().unwrap(); - let remove_message = ValidatedCommit::from_staged_commit( - &amal, - amal_provider.conn_ref(), - staged_commit, - &mls_group, - ) - .await - .unwrap(); - - assert_eq!(remove_message.removed_inboxes.len(), 1); - } - - #[tokio::test] - async fn test_installation_changes() { - let wallet = generate_local_wallet(); - let amal_1 = ClientBuilder::new_test_client(&wallet).await; - let amal_2 = ClientBuilder::new_test_client(&wallet).await; - - let amal_1_provider = amal_1.mls_provider().unwrap(); - let amal_2_provider = amal_2.mls_provider().unwrap(); - - let amal_group = amal_1.create_group(None, Default::default()).unwrap(); - let mut amal_mls_group = amal_group.load_mls_group(&amal_1_provider).unwrap(); - - let amal_2_kp = amal_2.identity().new_key_package(&amal_2_provider).unwrap(); - - // Add Amal's second installation to the existing group - amal_mls_group - .add_members( - &amal_1_provider, - &amal_1.identity().installation_keys, - &[amal_2_kp], - ) - .unwrap(); - - let staged_commit = amal_mls_group.pending_commit().unwrap(); - - let validated_commit = ValidatedCommit::from_staged_commit( - &amal_1, - amal_1_provider.conn_ref(), - staged_commit, - &amal_mls_group, - ) - .await - .unwrap(); - - assert_eq!(validated_commit.added_inboxes.len(), 1); - assert_eq!( - validated_commit.added_inboxes[0].inbox_id, - amal_2.inbox_id() - ) - } - - #[tokio::test] - async fn test_bad_key_package() { - let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; - let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; - - let amal_provider = amal.mls_provider().unwrap(); - let bola_provider = bola.mls_provider().unwrap(); - - let amal_group = amal.create_group(None, Default::default()).unwrap(); - let mut amal_mls_group = amal_group.load_mls_group(&amal_provider).unwrap(); - - let capabilities = Capabilities::new( - None, - Some(&[CIPHERSUITE]), - Some(&[ - ExtensionType::LastResort, - ExtensionType::ApplicationId, - ExtensionType::Unknown(MUTABLE_METADATA_EXTENSION_ID), - ExtensionType::Unknown(GROUP_MEMBERSHIP_EXTENSION_ID), - ExtensionType::ImmutableMetadata, - ]), - Some(&[ProposalType::GroupContextExtensions]), - None, - ); - - // Create a key package with a malformed credential - let bad_key_package = KeyPackage::builder() - .leaf_node_capabilities(capabilities) - .build( - CIPHERSUITE, - &bola_provider, - &bola.identity().installation_keys, - CredentialWithKey { - // Broken credential - credential: BasicCredential::new(vec![1, 2, 3]).into(), - signature_key: bola.identity().installation_keys.to_public_vec().into(), - }, - ) - .unwrap(); - - amal_mls_group - .add_members( - &amal_provider, - &amal.identity().installation_keys, - &[bad_key_package.key_package().clone()], - ) - .unwrap(); - - let staged_commit = amal_mls_group.pending_commit().unwrap(); - - let validated_commit = ValidatedCommit::from_staged_commit( - &amal, - amal_provider.conn_ref(), - staged_commit, - &amal_mls_group, - ) - .await; - - assert!(validated_commit.is_err()); - } -} -*/ diff --git a/xmtp_mls/src/identity.rs b/xmtp_mls/src/identity.rs index 27eadbfd2..bbbf77aee 100644 --- a/xmtp_mls/src/identity.rs +++ b/xmtp_mls/src/identity.rs @@ -15,7 +15,6 @@ use crate::{ }; use crate::{retryable, Fetch, Store}; use ed25519_dalek::SigningKey; -use ethers::signers::WalletError; use log::debug; use log::info; use openmls::prelude::tls_codec::Serialize; @@ -141,8 +140,6 @@ pub enum IdentityError { #[error("legacy key does not match address")] LegacyKeyMismatch, #[error(transparent)] - WalletError(#[from] WalletError), - #[error(transparent)] OpenMls(#[from] openmls::prelude::Error), #[error(transparent)] StorageError(#[from] crate::storage::StorageError), diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index b4350eb53..7520d6b62 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -445,8 +445,10 @@ pub async fn load_identity_updates( #[cfg(test)] pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use ethers::signers::LocalWallet; - use tracing_test::traced_test; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::{ associations::{builder::SignatureRequest, AssociationState, RecoverableEcdsaSignature}, @@ -508,7 +510,8 @@ pub(crate) mod tests { .expect("insert should succeed"); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn create_inbox_round_trip() { let wallet = generate_local_wallet(); let wallet_address = wallet.get_address(); @@ -534,7 +537,8 @@ pub(crate) mod tests { assert!(association_state.get(&wallet_address.into()).is_some()) } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn add_association() { let wallet = generate_local_wallet(); let wallet_2 = generate_local_wallet(); @@ -561,9 +565,13 @@ pub(crate) mod tests { assert!(association_state.get(&wallet_2_address.into()).is_some()); } - #[tokio::test] - #[traced_test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[tracing_test::traced_test] async fn cache_association_state() { + if cfg!(target_arch = "wasm32") { + let _ = tracing_log::LogTracer::init_with_filter(log::LevelFilter::Debug); + } let wallet = generate_local_wallet(); let wallet_2 = generate_local_wallet(); let wallet_address = wallet.get_address(); @@ -614,7 +622,8 @@ pub(crate) mod tests { assert!(association_state.get(&wallet_2_address.into()).is_some()); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn load_identity_updates_if_needed() { let wallet = generate_local_wallet(); let client = ClientBuilder::new_test_client(&wallet).await; @@ -631,7 +640,8 @@ pub(crate) mod tests { assert_eq!(filtered.unwrap(), vec!["inbox_1"]); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn get_installation_diff() { let wallet_1 = generate_local_wallet(); let wallet_2 = generate_local_wallet(); @@ -739,7 +749,8 @@ pub(crate) mod tests { .contains(&client_2_installation_key)); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] pub async fn revoke_wallet() { let recovery_wallet = generate_local_wallet(); let second_wallet = generate_local_wallet(); @@ -794,7 +805,8 @@ pub(crate) mod tests { assert_eq!(inbox_ids.len(), 0); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] pub async fn revoke_installation() { let wallet = generate_local_wallet(); let client1 = ClientBuilder::new_test_client(&wallet).await; diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 9d330f0bc..8d5f5e534 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -11,7 +11,6 @@ mod hpke; pub mod identity; mod identity_updates; mod mutex_registry; -pub mod owner; pub mod retry; pub mod storage; pub mod subscriptions; @@ -21,8 +20,9 @@ pub mod verified_key_package_v2; mod xmtp_openmls_provider; pub use client::{Client, Network}; +use std::future::Future; use storage::StorageError; -use xmtp_cryptography::signature::{RecoverableSignature, SignatureError}; +use tokio::task::JoinHandle; use xmtp_proto::api_client::{ClientWithMetadata, XmtpIdentityClient, XmtpMlsClient}; /// XMTP Api Super Trait @@ -50,18 +50,14 @@ impl XmtpApi for T where } #[cfg(any(test, feature = "test-utils", feature = "bench"))] -#[async_trait::async_trait] +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] pub trait XmtpTestClient { async fn create_local() -> Self; async fn create_dev() -> Self; } -pub trait InboxOwner { - /// Get address of the wallet. - fn get_address(&self) -> String; - /// Sign text with the wallet. - fn sign(&self, text: &str) -> Result; -} +pub use xmtp_id::InboxOwner; /// Inserts a model to the underlying data store, erroring if it already exists pub trait Store { @@ -85,18 +81,46 @@ pub trait Delete { fn delete(&self, key: Self::Key) -> Result; } -#[cfg(test)] -mod tests { - use log::LevelFilter; - use tracing_test::traced_test; +#[cfg(target_arch = "wasm32")] +fn spawn(future: F) -> JoinHandle +where + F: Future + 'static, + F::Output: 'static, +{ + tokio::task::spawn_local(future) +} + +#[cfg(not(target_arch = "wasm32"))] +fn spawn(future: F) -> JoinHandle +where + F: Future + Send + 'static, + F::Output: 'static + Send, +{ + tokio::task::spawn(future) +} + +#[cfg(target_arch = "wasm32")] +#[doc(hidden)] +pub async fn sleep(duration: std::time::Duration) { + gloo_timers::future::TimeoutFuture::new(duration.as_millis() as u32).await; +} +#[cfg(not(target_arch = "wasm32"))] +#[doc(hidden)] +pub async fn sleep(duration: std::time::Duration) { + tokio::time::sleep(duration).await +} + +#[cfg(test)] +pub(crate) mod tests { // Execute once before any tests are run - #[ctor::ctor] + #[cfg_attr(not(target_arch = "wasm32"), ctor::ctor)] // Capture traces in a variable that can be checked in tests, as well as outputting them to stdout on test failure - #[traced_test] + #[cfg_attr(not(target_arch = "wasm32"), tracing_test::traced_test)] + #[cfg(not(target_arch = "wasm32"))] fn setup() { // Capture logs (e.g. log::info!()) as traces too - let _ = tracing_log::LogTracer::init_with_filter(LevelFilter::Debug); + let _ = tracing_log::LogTracer::init_with_filter(log::LevelFilter::Debug); } /// Note: tests that use this must have the #[traced_test] attribute diff --git a/xmtp_mls/src/owner/evm_owner.rs b/xmtp_mls/src/owner/evm_owner.rs deleted file mode 100644 index bbf4fbf19..000000000 --- a/xmtp_mls/src/owner/evm_owner.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub use ethers::signers::{LocalWallet, Signer}; - -use xmtp_cryptography::signature::{h160addr_to_string, RecoverableSignature, SignatureError}; - -use crate::InboxOwner; - -impl InboxOwner for LocalWallet { - fn get_address(&self) -> String { - h160addr_to_string(self.address()) - } - - fn sign(&self, text: &str) -> Result { - let message_hash = ethers_core::utils::hash_message(text); - Ok(self.sign_hash(message_hash)?.to_vec().into()) - } -} diff --git a/xmtp_mls/src/owner/mod.rs b/xmtp_mls/src/owner/mod.rs deleted file mode 100644 index 1b15ea292..000000000 --- a/xmtp_mls/src/owner/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod evm_owner; diff --git a/xmtp_mls/src/retry.rs b/xmtp_mls/src/retry.rs index 6bab96703..1359b649f 100644 --- a/xmtp_mls/src/retry.rs +++ b/xmtp_mls/src/retry.rs @@ -19,7 +19,6 @@ use std::time::Duration; use rand::Rng; -use smart_default::SmartDefault; /// Specifies which errors are retryable. /// All Errors are not retryable by-default. @@ -28,19 +27,26 @@ pub trait RetryableError: std::error::Error { } /// Options to specify how to retry a function -#[derive(SmartDefault, Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct Retry { - #[default = 5] retries: usize, - #[default(_code = "std::time::Duration::from_millis(50)")] duration: std::time::Duration, - #[default = 3] // The amount to multiply the duration on each subsequent attempt multiplier: u32, - #[default = 25] max_jitter_ms: usize, } +impl Default for Retry { + fn default() -> Self { + Self { + retries: 5, + duration: std::time::Duration::from_millis(50), + multiplier: 3, + max_jitter_ms: 25, + } + } +} + impl Retry { /// Get the number of retries this is configured with. pub fn retries(&self) -> usize { @@ -119,7 +125,7 @@ impl Retry { /// ``` /// use xmtp_mls::{retry_async, retry::{RetryableError, Retry}}; /// use thiserror::Error; -/// use flume::bounded; +/// use tokio::sync::mpsc; /// /// #[derive(Debug, Error)] /// enum MyError { @@ -138,8 +144,8 @@ impl Retry { /// } /// } /// -/// async fn fallable_fn(rx: &flume::Receiver) -> Result<(), MyError> { -/// if rx.recv_async().await.unwrap() == 2 { +/// async fn fallable_fn(rx: &mut mpsc::Receiver) -> Result<(), MyError> { +/// if rx.recv().await.unwrap() == 2 { /// return Ok(()); /// } /// Err(MyError::Retryable) @@ -147,14 +153,14 @@ impl Retry { /// /// #[tokio::main] /// async fn main() -> Result<(), MyError> { -/// -/// let (tx, rx) = flume::bounded(3); +/// +/// let (tx, mut rx) = mpsc::channel(3); /// /// for i in 0..3 { -/// tx.send(i).unwrap(); +/// tx.send(i).await.unwrap(); /// } /// retry_async!(Retry::default(), (async { -/// fallable_fn(&rx.clone()).await +/// fallable_fn(&mut rx).await /// })) /// } /// ``` @@ -176,7 +182,7 @@ macro_rules! retry_async { if (&e).is_retryable() && attempts < $retry.retries() { log::warn!("retrying function that failed with error={}", e.to_string()); attempts += 1; - tokio::time::sleep($retry.duration(attempts)).await; + $crate::sleep($retry.duration(attempts)).await; } else { log::info!("error is not retryable. {:?}", e); break Err(e); @@ -208,9 +214,13 @@ impl RetryableError for xmtp_proto::api_client::Error { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; use thiserror::Error; + use tokio::sync::mpsc; #[derive(Debug, Error)] enum SomeError { @@ -235,7 +245,8 @@ mod tests { Err(SomeError::ARetryableError) } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn it_retries_twice_and_succeeds() { let mut i = 0; let mut test_fn = || -> Result<(), SomeError> { @@ -250,7 +261,8 @@ mod tests { retry_async!(Retry::default(), (async { test_fn() })).unwrap(); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn it_works_with_random_args() { let mut i = 0; let list = vec!["String".into(), "Foo".into()]; @@ -265,7 +277,8 @@ mod tests { retry_async!(Retry::default(), (async { test_fn() })).unwrap(); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn it_fails_on_three_retries() { let closure = || -> Result<(), SomeError> { retry_error_fn()?; @@ -276,7 +289,8 @@ mod tests { assert!(result.is_err()) } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn it_only_runs_non_retryable_once() { let mut attempts = 0; let mut test_fn = || -> Result<(), SomeError> { @@ -289,32 +303,34 @@ mod tests { assert_eq!(attempts, 1); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn it_works_async() { - async fn retryable_async_fn(rx: &flume::Receiver) -> Result<(), SomeError> { - let val = rx.recv_async().await.unwrap(); + async fn retryable_async_fn(rx: &mut mpsc::Receiver) -> Result<(), SomeError> { + let val = rx.recv().await.unwrap(); if val == 2 { return Ok(()); } // do some work - tokio::time::sleep(std::time::Duration::from_nanos(100)).await; + crate::sleep(std::time::Duration::from_nanos(100)).await; Err(SomeError::ARetryableError) } - let (tx, rx) = flume::bounded(3); + let (tx, mut rx) = mpsc::channel(3); for i in 0..3 { - tx.send(i).unwrap(); + tx.send(i).await.unwrap(); } retry_async!( Retry::default(), - (async { retryable_async_fn(&rx.clone()).await }) + (async { retryable_async_fn(&mut rx).await }) ) .unwrap(); assert!(rx.is_empty()); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn it_works_async_mut() { async fn retryable_async_fn(data: &mut usize) -> Result<(), SomeError> { if *data == 2 { @@ -322,7 +338,7 @@ mod tests { } *data += 1; // do some work - tokio::time::sleep(std::time::Duration::from_nanos(100)).await; + crate::sleep(std::time::Duration::from_nanos(100)).await; Err(SomeError::ARetryableError) } @@ -334,7 +350,8 @@ mod tests { .unwrap(); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn backoff_retry() { let backoff_retry = Retry::default(); diff --git a/xmtp_mls/src/storage/encrypted_store/association_state.rs b/xmtp_mls/src/storage/encrypted_store/association_state.rs index 079c6ec47..72cabb530 100644 --- a/xmtp_mls/src/storage/encrypted_store/association_state.rs +++ b/xmtp_mls/src/storage/encrypted_store/association_state.rs @@ -119,12 +119,16 @@ impl StoredAssociationState { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::storage::encrypted_store::tests::with_connection; use super::*; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_batch_read() { with_connection(|conn| { let association_state = AssociationState::new("1234".to_string(), 0); diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index d5516e7ec..482dbe2e2 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -7,13 +7,14 @@ use diesel::{ prelude::*, serialize::{self, IsNull, Output, ToSql}, sql_types::Integer, - sqlite::Sqlite, }; + use serde::{Deserialize, Serialize}; use super::{ db_connection::DbConnection, schema::{groups, groups::dsl}, + Sqlite, }; use crate::{impl_fetch, impl_store, StorageError}; @@ -312,6 +313,8 @@ where #[cfg(test)] pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); use super::*; use crate::{ @@ -334,7 +337,8 @@ pub(crate) mod tests { ) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_it_stores_group() { with_connection(|conn| { let test_group = generate_group(None); @@ -348,7 +352,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_it_fetches_group() { with_connection(|conn| { let test_group = generate_group(None); @@ -365,7 +370,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_it_updates_group_membership_state() { with_connection(|conn| { let test_group = generate_group(Some(GroupMembershipState::Pending)); @@ -384,8 +390,8 @@ pub(crate) mod tests { ); }) } - - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_find_groups() { with_connection(|conn| { let test_group_1 = generate_group(Some(GroupMembershipState::Pending)); @@ -421,7 +427,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_installations_last_checked_is_updated() { with_connection(|conn| { let test_group = generate_group(None); @@ -442,7 +449,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_new_group_has_correct_purpose() { with_connection(|conn| { let test_group = generate_group(None); @@ -461,7 +469,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_new_sync_group() { with_connection(|conn| { let id = rand_vec(); diff --git a/xmtp_mls/src/storage/encrypted_store/group_intent.rs b/xmtp_mls/src/storage/encrypted_store/group_intent.rs index 4ff7615e7..89d895529 100644 --- a/xmtp_mls/src/storage/encrypted_store/group_intent.rs +++ b/xmtp_mls/src/storage/encrypted_store/group_intent.rs @@ -5,7 +5,6 @@ use diesel::{ prelude::*, serialize::{self, IsNull, Output, ToSql}, sql_types::Integer, - sqlite::Sqlite, }; use prost::Message; @@ -13,6 +12,7 @@ use super::{ db_connection::DbConnection, group, schema::{group_intents, group_intents::dsl}, + Sqlite, }; use crate::{ groups::{intents::SendMessageIntentData, IntentError}, @@ -387,7 +387,10 @@ where } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; use crate::{ storage::encrypted_store::{ @@ -435,7 +438,8 @@ mod tests { .unwrap() } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_store_and_fetch() { let group_id = rand_vec(); let data = rand_vec(); @@ -467,7 +471,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_query() { let group_id = rand_vec(); @@ -545,7 +550,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn find_by_payload_hash() { let group_id = rand_vec(); @@ -586,7 +592,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_happy_path_state_transitions() { let group_id = rand_vec(); @@ -630,7 +637,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_republish_state_transition() { let group_id = rand_vec(); @@ -673,7 +681,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_invalid_state_transition() { let group_id = rand_vec(); @@ -707,7 +716,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_increment_publish_attempts() { let group_id = rand_vec(); with_connection(|conn| { diff --git a/xmtp_mls/src/storage/encrypted_store/group_message.rs b/xmtp_mls/src/storage/encrypted_store/group_message.rs index b6436c75e..db0e83e16 100644 --- a/xmtp_mls/src/storage/encrypted_store/group_message.rs +++ b/xmtp_mls/src/storage/encrypted_store/group_message.rs @@ -5,13 +5,13 @@ use diesel::{ prelude::*, serialize::{self, IsNull, Output, ToSql}, sql_types::Integer, - sqlite::Sqlite, }; use serde::{Deserialize, Serialize}; use super::{ db_connection::DbConnection, schema::{group_messages, group_messages::dsl}, + Sqlite, }; use crate::{impl_fetch, impl_store, impl_store_or_ignore, StorageError}; @@ -204,7 +204,10 @@ impl DbConnection { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; use crate::{ assert_err, assert_ok, @@ -230,7 +233,8 @@ mod tests { } } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_does_not_error_on_empty_messages() { with_connection(|conn| { let id = vec![0x0]; @@ -238,7 +242,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_gets_messages() { with_connection(|conn| { let group = generate_group(None); @@ -253,7 +258,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_cannot_insert_message_without_group() { use diesel::result::{DatabaseErrorKind::ForeignKeyViolation, Error::DatabaseError}; @@ -266,7 +272,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_gets_many_messages() { use crate::storage::encrypted_store::schema::group_messages::dsl; @@ -300,7 +307,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_gets_messages_by_time() { with_connection(|conn| { let group = generate_group(None); @@ -331,7 +339,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_gets_messages_by_kind() { with_connection(|conn| { let group = generate_group(None); diff --git a/xmtp_mls/src/storage/encrypted_store/identity.rs b/xmtp_mls/src/storage/encrypted_store/identity.rs index ad54cdd65..e583c8cbb 100644 --- a/xmtp_mls/src/storage/encrypted_store/identity.rs +++ b/xmtp_mls/src/storage/encrypted_store/identity.rs @@ -60,14 +60,18 @@ impl TryFrom for Identity { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::{ super::{EncryptedMessageStore, StorageOption}, StoredIdentity, }; use crate::{utils::test::rand_vec, Store}; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn can_only_store_one_identity() { let store = EncryptedMessageStore::new( StorageOption::Ephemeral, diff --git a/xmtp_mls/src/storage/encrypted_store/identity_update.rs b/xmtp_mls/src/storage/encrypted_store/identity_update.rs index a8a8bca8f..15119fff7 100644 --- a/xmtp_mls/src/storage/encrypted_store/identity_update.rs +++ b/xmtp_mls/src/storage/encrypted_store/identity_update.rs @@ -7,6 +7,10 @@ use super::{ schema::identity_updates::{self, dsl}, }; use diesel::{dsl::max, prelude::*}; + +#[cfg(target_arch = "wasm32")] +use diesel_wasm_sqlite::dsl::RunQueryDsl; + use xmtp_id::associations::{AssociationError, IdentityUpdate}; /// StoredIdentityUpdate holds a serialized IdentityUpdate record @@ -126,7 +130,10 @@ impl DbConnection { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::{ storage::encrypted_store::tests::with_connection, utils::test::{rand_time, rand_vec}, @@ -139,7 +146,8 @@ mod tests { StoredIdentityUpdate::new(inbox_id.to_string(), sequence_id, rand_time(), rand_vec()) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn insert_and_read() { with_connection(|conn| { let inbox_id = "inbox_1"; @@ -163,7 +171,8 @@ mod tests { }); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_filter() { with_connection(|conn| { let inbox_id = "inbox_1"; @@ -195,7 +204,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_get_latest_sequence_id() { with_connection(|conn| { let inbox_1 = "inbox_1"; @@ -230,7 +240,8 @@ mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn get_single_sequence_id() { with_connection(|conn| { let inbox_id = "inbox_1"; diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index f5d2f843d..e892b58d2 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -26,7 +26,7 @@ use std::{borrow::Cow, sync::Arc}; use diesel::{ connection::{AnsiTransactionManager, SimpleConnection, TransactionManager}, prelude::*, - r2d2::{ConnectionManager, Pool, PoolTransactionManager, PooledConnection}, + r2d2::{self, PoolTransactionManager}, result::{DatabaseErrorKind, Error}, sql_query, }; @@ -36,6 +36,11 @@ use parking_lot::RwLock; use rand::RngCore; use xmtp_cryptography::utils as crypto_utils; +#[cfg(not(target_arch = "wasm32"))] +pub use diesel::sqlite::Sqlite; +#[cfg(target_arch = "wasm32")] +pub use diesel_wasm_sqlite::WasmSqlite as Sqlite; + use self::db_connection::DbConnection; use super::StorageError; @@ -43,7 +48,14 @@ use crate::{xmtp_openmls_provider::XmtpOpenMlsProvider, Store}; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations/"); -pub type RawDbConnection = PooledConnection>; +#[cfg(not(target_arch = "wasm32"))] +pub type ConnectionManager = r2d2::ConnectionManager; +#[cfg(target_arch = "wasm32")] +pub type ConnectionManager = + r2d2::ConnectionManager; + +pub type RawDbConnection = r2d2::PooledConnection; +pub type Pool = r2d2::Pool; pub type EncryptionKey = [u8; 32]; @@ -90,7 +102,7 @@ pub fn ignore_unique_violation( /// Manages a Sqlite db for persisting messages and other objects. pub struct EncryptedMessageStore { connect_opt: StorageOption, - pool: Arc>>>>, + pool: Arc>>, enc_key: Option, } @@ -115,15 +127,14 @@ impl EncryptedMessageStore { enc_key: Option, ) -> Result { log::info!("Setting up DB connection pool"); - let pool = - match opts { - StorageOption::Ephemeral => Pool::builder() - .max_size(1) - .build(ConnectionManager::::new(":memory:"))?, - StorageOption::Persistent(ref path) => Pool::builder() - .max_size(25) - .build(ConnectionManager::::new(path))?, - }; + let pool = match opts { + StorageOption::Ephemeral => Pool::builder() + .max_size(1) + .build(ConnectionManager::new(":memory:"))?, + StorageOption::Persistent(ref path) => Pool::builder() + .max_size(25) + .build(ConnectionManager::new(path))?, + }; // TODO: Validate that sqlite is correctly configured. Bad EncKey is not detected until the // migrations run which returns an unhelpful error. @@ -175,9 +186,7 @@ impl EncryptedMessageStore { Ok(()) } - pub(crate) fn raw_conn( - &self, - ) -> Result>, StorageError> { + pub(crate) fn raw_conn(&self) -> Result { let pool_guard = self.pool.read(); let pool = pool_guard @@ -333,15 +342,14 @@ impl EncryptedMessageStore { } pub fn reconnect(&self) -> Result<(), StorageError> { - let pool = - match self.connect_opt { - StorageOption::Ephemeral => Pool::builder() - .max_size(1) - .build(ConnectionManager::::new(":memory:"))?, - StorageOption::Persistent(ref path) => Pool::builder() - .max_size(25) - .build(ConnectionManager::::new(path))?, - }; + let pool = match self.connect_opt { + StorageOption::Ephemeral => Pool::builder() + .max_size(1) + .build(ConnectionManager::new(":memory:"))?, + StorageOption::Persistent(ref path) => Pool::builder() + .max_size(25) + .build(ConnectionManager::new(path))?, + }; let mut pool_write = self.pool.write(); *pool_write = Some(pool); @@ -446,7 +454,10 @@ where } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::{ db_connection::DbConnection, identity::StoredIdentity, EncryptedMessageStore, StorageError, StorageOption, @@ -485,7 +496,8 @@ mod tests { } } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn ephemeral_store() { let store = EncryptedMessageStore::new( StorageOption::Ephemeral, @@ -503,7 +515,8 @@ mod tests { assert_eq!(fetched_identity.inbox_id, inbox_id); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn persistent_store() { let db_path = tmp_path(); { @@ -526,7 +539,8 @@ mod tests { fs::remove_file(db_path).unwrap(); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn releases_db_lock() { let db_path = tmp_path(); { @@ -557,7 +571,8 @@ mod tests { fs::remove_file(db_path).unwrap(); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn mismatched_encryption_key() { let mut enc_key = [1u8; 32]; @@ -584,7 +599,8 @@ mod tests { fs::remove_file(db_path).unwrap(); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn encrypted_db_with_multiple_connections() { let db_path = tmp_path(); let store = EncryptedMessageStore::new( @@ -604,7 +620,8 @@ mod tests { assert_eq!(fetched_identity.inbox_id, inbox_id); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_returns_ok_when_given_ok_result() { let result: Result<(), diesel::result::Error> = Ok(()); assert!( @@ -613,7 +630,8 @@ mod tests { ); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_returns_ok_on_unique_violation_error() { let result: Result<(), diesel::result::Error> = Err(diesel::result::Error::DatabaseError( diesel::result::DatabaseErrorKind::UniqueViolation, @@ -625,7 +643,8 @@ mod tests { ); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_returns_err_on_non_unique_violation_database_errors() { let result: Result<(), diesel::result::Error> = Err(diesel::result::Error::DatabaseError( diesel::result::DatabaseErrorKind::NotNullViolation, @@ -637,7 +656,8 @@ mod tests { ); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn it_returns_err_on_non_database_errors() { let result: Result<(), diesel::result::Error> = Err(diesel::result::Error::NotFound); assert!( @@ -651,7 +671,8 @@ mod tests { // try to write with second connection // write should fail & rollback // first thread succeeds - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_transaction_rollback() { let db_path = tmp_path(); let store = EncryptedMessageStore::new( @@ -714,7 +735,8 @@ mod tests { assert_eq!(groups, None); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_async_transaction() { let db_path = tmp_path(); @@ -726,7 +748,7 @@ mod tests { let store_pointer = store.clone(); - let handle = tokio::spawn(async move { + let handle = crate::spawn(async move { store_pointer .transaction_async(|provider| async move { let conn1 = provider.conn_ref(); diff --git a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs index a72d92e32..f3864ca70 100644 --- a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs +++ b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs @@ -5,10 +5,9 @@ use diesel::{ prelude::*, serialize::{self, IsNull, Output, ToSql}, sql_types::Integer, - sqlite::Sqlite, }; -use super::{db_connection::DbConnection, schema::refresh_state}; +use super::{db_connection::DbConnection, schema::refresh_state, Sqlite}; use crate::{impl_store, impl_store_or_ignore, storage::StorageError, StoreOrIgnore}; #[repr(i32)] @@ -120,10 +119,14 @@ impl DbConnection { #[cfg(test)] pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::*; use crate::{storage::encrypted_store::tests::with_connection, Store}; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn get_cursor_with_no_existing_state() { with_connection(|conn| { let id = vec![1, 2, 3]; @@ -136,7 +139,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn get_timestamp_with_existing_state() { with_connection(|conn| { let id = vec![1, 2, 3]; @@ -151,7 +155,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn update_timestamp_when_bigger() { with_connection(|conn| { let id = vec![1, 2, 3]; @@ -168,7 +173,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn dont_update_timestamp_when_smaller() { with_connection(|conn| { let entity_id = vec![1, 2, 3]; @@ -187,7 +193,8 @@ pub(crate) mod tests { }) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn allow_installation_and_welcome_same_id() { with_connection(|conn| { let entity_id = vec![1, 2, 3]; diff --git a/xmtp_mls/src/storage/mod.rs b/xmtp_mls/src/storage/mod.rs index dcc9663c9..0ce88f647 100644 --- a/xmtp_mls/src/storage/mod.rs +++ b/xmtp_mls/src/storage/mod.rs @@ -1,4 +1,4 @@ -mod encrypted_store; +pub(super) mod encrypted_store; mod errors; pub mod serialization; pub mod sql_key_store; diff --git a/xmtp_mls/src/storage/sql_key_store.rs b/xmtp_mls/src/storage/sql_key_store.rs index 12f795115..e53bec56b 100644 --- a/xmtp_mls/src/storage/sql_key_store.rs +++ b/xmtp_mls/src/storage/sql_key_store.rs @@ -1013,7 +1013,10 @@ impl From for SqlKeyStoreError { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use openmls::group::GroupId; use openmls_basic_credential::{SignatureKeyPair, StorageId}; use openmls_traits::{ @@ -1033,7 +1036,8 @@ mod tests { xmtp_openmls_provider::XmtpOpenMlsProvider, }; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn store_read_delete() { let db_path = tmp_path(); let store = EncryptedMessageStore::new( @@ -1082,7 +1086,8 @@ mod tests { impl Key for ProposalRef {} impl Entity for ProposalRef {} - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn list_append_remove() { let db_path = tmp_path(); let store = EncryptedMessageStore::new( @@ -1164,7 +1169,8 @@ mod tests { assert!(proposals_read.unwrap().is_empty()); } - #[tokio::test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn group_state() { let db_path = tmp_path(); let store = EncryptedMessageStore::new( diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 6c3fd03e1..87e5c73f5 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, pin::Pin, sync::Arc}; +use std::{collections::HashMap, sync::Arc}; use futures::{FutureExt, Stream, StreamExt}; use prost::Message; @@ -130,7 +130,7 @@ where pub async fn stream_conversations( &self, - ) -> Result + Send + '_>>, ClientError> { + ) -> Result + '_, ClientError> { let event_queue = tokio_stream::wrappers::BroadcastStream::new(self.local_events.subscribe()); @@ -167,14 +167,14 @@ where } }); - Ok(Box::pin(futures::stream::select(stream, event_queue))) + Ok(futures::stream::select(stream, event_queue)) } #[tracing::instrument(skip(self, group_id_to_info))] pub(crate) async fn stream_messages( self: Arc, group_id_to_info: HashMap, MessagesStreamInfo>, - ) -> Result + Send>>, ClientError> { + ) -> Result, ClientError> { let filters: Vec = group_id_to_info .iter() .map(|(group_id, info)| GroupFilter::new(group_id.clone(), Some(info.cursor))) @@ -221,8 +221,7 @@ where } } }); - - Ok(Box::pin(stream)) + Ok(stream) } } @@ -236,8 +235,9 @@ where ) -> StreamHandle> { let (tx, rx) = oneshot::channel(); - let handle = tokio::spawn(async move { - let mut stream = client.stream_conversations().await?; + let handle = crate::spawn(async move { + let stream = client.stream_conversations().await?; + futures::pin_mut!(stream); let _ = tx.send(()); while let Some(convo) = stream.next().await { convo_callback(convo) @@ -258,8 +258,10 @@ where ) -> StreamHandle> { let (tx, rx) = oneshot::channel(); - let handle = tokio::spawn(async move { - let mut stream = Self::stream_messages(client, group_id_to_info).await?; + let handle = crate::spawn(async move { + let stream = Self::stream_messages(client, group_id_to_info).await?; + futures::pin_mut!(stream); + let _ = tx.send(()); while let Some(message) = stream.next().await { callback(message) @@ -288,11 +290,15 @@ where let stream = async_stream::stream! { let client = client.clone(); - let mut messages_stream = client + + let messages_stream = client .clone() .stream_messages(group_id_to_info.clone()) .await?; - let mut convo_stream = Self::stream_conversations(&client).await?; + futures::pin_mut!(messages_stream); + + let convo_stream = Self::stream_conversations(&client).await?; + futures::pin_mut!(convo_stream); let mut extra_messages = Vec::new(); loop { @@ -341,13 +347,13 @@ where while let Some(Some(message)) = messages_stream.next().now_or_never() { extra_messages.push(message); } - let _ = std::mem::replace(&mut messages_stream, new_messages_stream); + messages_stream.set(new_messages_stream); }, } } }; - Ok(Box::pin(stream)) + Ok(stream) } pub fn stream_all_messages_with_callback( @@ -356,8 +362,9 @@ where ) -> StreamHandle> { let (tx, rx) = oneshot::channel(); - let handle = tokio::spawn(async move { - let mut stream = Self::stream_all_messages(client).await?; + let handle = crate::spawn(async move { + let stream = Self::stream_all_messages(client).await?; + futures::pin_mut!(stream); let _ = tx.send(()); while let Some(message) = stream.next().await { match message { @@ -376,7 +383,10 @@ where } #[cfg(test)] -mod tests { +pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use crate::utils::test::{Delivery, TestClient}; use crate::{ builder::ClientBuilder, groups::GroupMetadataOptions, @@ -390,7 +400,8 @@ mod tests { }; use xmtp_cryptography::utils::generate_local_wallet; - #[tokio::test(flavor = "current_thread")] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] async fn test_stream_welcomes() { let alice = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bob = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); @@ -407,8 +418,9 @@ mod tests { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let mut stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); let bob_ptr = bob.clone(); - tokio::spawn(async move { - let mut bob_stream = bob_ptr.stream_conversations().await.unwrap(); + crate::spawn(async move { + let bob_stream = bob_ptr.stream_conversations().await.unwrap(); + futures::pin_mut!(bob_stream); while let Some(item) = bob_stream.next().await { let _ = tx.send(item); } @@ -424,7 +436,11 @@ mod tests { assert_eq!(bob_received_groups.group_id, group_id); } - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 10) + )] async fn test_stream_messages() { let alice = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bob = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -444,8 +460,9 @@ mod tests { let notify = Delivery::new(None); let notify_ptr = notify.clone(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - tokio::spawn(async move { - let mut stream = alice_group.stream(alice).await.unwrap(); + crate::spawn(async move { + let stream = alice_group.stream(alice).await.unwrap(); + futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); notify_ptr.notify_one(); @@ -466,7 +483,11 @@ mod tests { // assert_eq!(bob_received_groups.group_id, alice_bob_group.group_id); } - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 10) + )] async fn test_stream_all_messages_unchanging_group_list() { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -487,7 +508,7 @@ mod tests { .add_members_by_inbox_id(&bo, vec![caro.inbox_id()]) .await .unwrap(); - tokio::time::sleep(std::time::Duration::from_millis(100)).await; + crate::sleep(std::time::Duration::from_millis(100)).await; let messages: Arc>> = Arc::new(Mutex::new(Vec::new())); let messages_clone = messages.clone(); @@ -534,7 +555,11 @@ mod tests { assert_eq!(messages[3].decrypted_message_bytes, b"fourth"); } - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 10) + )] async fn test_stream_all_messages_changing_group_list() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -634,14 +659,18 @@ mod tests { .send_message("should not show up".as_bytes(), &alix) .await .unwrap(); - tokio::time::sleep(std::time::Duration::from_millis(100)).await; + crate::sleep(std::time::Duration::from_millis(100)).await; let messages = messages.lock(); assert_eq!(messages.len(), 5); } #[ignore] - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 10) + )] async fn test_stream_all_messages_does_not_lose_messages() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let caro = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); @@ -669,13 +698,13 @@ mod tests { let alix_group_pointer = alix_group.clone(); let alix_pointer = alix.clone(); - tokio::spawn(async move { + crate::spawn(async move { for _ in 0..50 { alix_group_pointer .send_message(b"spam", &alix_pointer) .await .unwrap(); - tokio::time::sleep(std::time::Duration::from_micros(200)).await; + crate::sleep(std::time::Duration::from_micros(200)).await; } }); @@ -707,7 +736,8 @@ mod tests { } } - #[tokio::test(flavor = "multi_thread")] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] async fn test_self_group_creation() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); diff --git a/xmtp_mls/src/utils/bench.rs b/xmtp_mls/src/utils/bench.rs index 61ac2d590..5d89e405d 100644 --- a/xmtp_mls/src/utils/bench.rs +++ b/xmtp_mls/src/utils/bench.rs @@ -4,7 +4,6 @@ #![allow(clippy::unwrap_used)] use crate::{builder::ClientBuilder, Client}; -use ethers::signers::{LocalWallet, Signer}; use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; @@ -18,7 +17,8 @@ use tracing_subscriber::{ util::SubscriberInitExt, EnvFilter, }; -use xmtp_cryptography::utils::rng; +use xmtp_cryptography::utils::generate_local_wallet; +use xmtp_id::InboxOwner; use super::test::TestClient; @@ -126,13 +126,13 @@ impl Identity { } async fn create_identity(is_dev_network: bool) -> Identity { - let wallet = LocalWallet::new(&mut rng()); + let wallet = generate_local_wallet(); let client = if is_dev_network { ClientBuilder::new_dev_client(&wallet).await } else { ClientBuilder::new_test_client(&wallet).await }; - Identity::new(client.inbox_id(), format!("0x{:x}", wallet.address())) + Identity::new(client.inbox_id(), wallet.get_address()) } async fn create_identities(n: usize, is_dev_network: bool) -> Vec { diff --git a/xmtp_mls/src/utils/test.rs b/xmtp_mls/src/utils/test.rs index 5fc724d5e..2d4538d79 100755 --- a/xmtp_mls/src/utils/test.rs +++ b/xmtp_mls/src/utils/test.rs @@ -1,5 +1,4 @@ #![allow(clippy::unwrap_used)] -use std::env; use rand::{ distributions::{Alphanumeric, DistString}, @@ -7,7 +6,6 @@ use rand::{ }; use std::sync::Arc; use tokio::{sync::Notify, time::error::Elapsed}; -use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient; use xmtp_id::associations::{generate_inbox_id, RecoverableEcdsaSignature}; use crate::{ @@ -18,13 +16,16 @@ use crate::{ Client, InboxOwner, XmtpApi, XmtpTestClient, }; -#[cfg(feature = "http-api")] +#[cfg(not(target_arch = "wasm32"))] +use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient; + +#[cfg(any(feature = "http-api", target_arch = "wasm32"))] use xmtp_api_http::XmtpHttpApiClient; -#[cfg(not(feature = "http-api"))] +#[cfg(not(any(feature = "http-api", target_arch = "wasm32")))] pub type TestClient = GrpcClient; -#[cfg(feature = "http-api")] +#[cfg(any(feature = "http-api", target_arch = "wasm32"))] pub type TestClient = XmtpHttpApiClient; pub fn rand_string() -> String { @@ -39,9 +40,16 @@ pub fn rand_vec() -> Vec { rand::thread_rng().gen::<[u8; 24]>().to_vec() } +#[cfg(not(target_arch = "wasm32"))] +pub fn tmp_path() -> String { + let db_name = rand_string(); + format!("{}/{}.db3", std::env::temp_dir().to_str().unwrap(), db_name) +} + +#[cfg(target_arch = "wasm32")] pub fn tmp_path() -> String { let db_name = rand_string(); - format!("{}/{}.db3", env::temp_dir().to_str().unwrap(), db_name) + format!("{}/{}.db3", "test_db", db_name) } pub fn rand_time() -> i64 { @@ -49,8 +57,9 @@ pub fn rand_time() -> i64 { rng.gen_range(0..1_000_000_000) } -#[async_trait::async_trait] -#[cfg(feature = "http-api")] +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] +#[cfg(any(feature = "http-api", target_arch = "wasm32"))] impl XmtpTestClient for XmtpHttpApiClient { async fn create_local() -> Self { XmtpHttpApiClient::new("http://localhost:5555".into()).unwrap() @@ -61,7 +70,8 @@ impl XmtpTestClient for XmtpHttpApiClient { } } -#[async_trait::async_trait] +#[cfg(not(target_arch = "wasm32"))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl XmtpTestClient for GrpcClient { async fn create_local() -> Self { GrpcClient::create("http://localhost:5556".into(), false) From 7c0e18d0ab0272f4372b4ecce10d1f74d7d4dc8f Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 5 Sep 2024 21:55:03 -0400 Subject: [PATCH 20/97] stack-based streams all the way down --- Cargo.lock | 31 ++++---- Cargo.toml | 1 - bindings_ffi/Cargo.lock | 22 ++++-- bindings_ffi/Cargo.toml | 1 - bindings_ffi/src/mls.rs | 4 +- bindings_ffi/src/v2.rs | 2 +- examples/cli/Cargo.toml | 1 - xmtp_api_grpc/src/grpc_api_helper.rs | 14 ++-- xmtp_api_grpc/src/identity.rs | 2 - xmtp_cryptography/Cargo.toml | 1 - xmtp_cryptography/src/signature.rs | 6 +- xmtp_cryptography/src/utils.rs | 2 +- xmtp_id/Cargo.toml | 1 - xmtp_id/src/associations/association_log.rs | 10 +-- xmtp_id/src/associations/mod.rs | 2 + xmtp_id/src/associations/signature.rs | 2 - xmtp_id/src/lib.rs | 3 +- xmtp_mls/Cargo.toml | 2 - xmtp_mls/benches/group_limit.rs | 3 +- xmtp_mls/src/api/mls.rs | 4 +- xmtp_mls/src/builder.rs | 2 - xmtp_mls/src/groups/subscriptions.rs | 21 +++-- xmtp_mls/src/identity.rs | 3 - xmtp_mls/src/identity_updates.rs | 3 +- xmtp_mls/src/lib.rs | 8 +- xmtp_mls/src/owner/evm_owner.rs | 16 ---- xmtp_mls/src/owner/mod.rs | 1 - xmtp_mls/src/subscriptions.rs | 88 +++++++++++---------- xmtp_mls/src/utils/bench.rs | 1 - xmtp_proto/Cargo.toml | 4 +- xmtp_proto/src/api_client.rs | 26 +++--- 31 files changed, 120 insertions(+), 167 deletions(-) delete mode 100644 xmtp_mls/src/owner/evm_owner.rs delete mode 100644 xmtp_mls/src/owner/mod.rs diff --git a/Cargo.lock b/Cargo.lock index dcfbe4341..1520b68a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2646,15 +2646,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -3902,7 +3893,7 @@ checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" dependencies = [ "bytes", "heck", - "itertools 0.12.1", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -3922,7 +3913,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.72", @@ -5531,6 +5522,17 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -6263,7 +6265,6 @@ version = "0.1.0" dependencies = [ "clap", "ethers", - "ethers-core", "femme", "futures", "hex", @@ -6291,7 +6292,6 @@ dependencies = [ "curve25519-dalek", "ecdsa 0.16.9", "ethers", - "ethers-core", "getrandom", "hex", "k256 0.13.3", @@ -6316,7 +6316,6 @@ dependencies = [ "ed25519", "ed25519-dalek", "ethers", - "ethers-core", "futures", "hex", "log", @@ -6355,8 +6354,6 @@ dependencies = [ "diesel", "diesel_migrations", "ed25519-dalek", - "ethers", - "ethers-core", "flume", "futures", "hex", @@ -6401,7 +6398,6 @@ dependencies = [ name = "xmtp_proto" version = "0.0.1" dependencies = [ - "async-trait", "futures", "futures-core", "openmls", @@ -6412,6 +6408,7 @@ dependencies = [ "prost-types", "serde", "tonic", + "trait-variant", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cefde727d..ecec55098 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,6 @@ ctor = "0.2" ed25519 = "2.2.3" ed25519-dalek = "2.1.1" ethers = "2.0.11" -ethers-core = "2.0.4" futures = "0.3.30" futures-core = "0.3.30" getrandom = { version = "0.2", default-features = false } diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 5a3700f04..c3c13ea2f 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -3502,7 +3502,7 @@ checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.11.0", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -3522,7 +3522,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.48", @@ -5040,6 +5040,17 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -5772,7 +5783,6 @@ dependencies = [ "curve25519-dalek", "ecdsa 0.16.9", "ethers", - "ethers-core", "getrandom", "hex", "k256 0.13.3", @@ -5795,7 +5805,6 @@ dependencies = [ "ed25519", "ed25519-dalek", "ethers", - "ethers-core", "futures", "hex", "log", @@ -5829,8 +5838,6 @@ dependencies = [ "diesel", "diesel_migrations", "ed25519-dalek", - "ethers", - "ethers-core", "futures", "hex", "libsqlite3-sys", @@ -5863,7 +5870,6 @@ dependencies = [ name = "xmtp_proto" version = "0.0.1" dependencies = [ - "async-trait", "futures", "futures-core", "openmls", @@ -5874,6 +5880,7 @@ dependencies = [ "prost-types", "serde", "tonic", + "trait-variant", ] [[package]] @@ -5910,7 +5917,6 @@ version = "0.0.1" dependencies = [ "env_logger", "ethers", - "ethers-core", "futures", "log", "parking_lot", diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index 4685dcb6f..89cfc4892 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -43,7 +43,6 @@ path = "src/bin.rs" [dev-dependencies] ethers = "2.0.13" -ethers-core = "2.0.13" tempfile = "3.5.0" tokio = { version = "1.28.1", features = ["full"] } tokio-test = "0.4" diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 8f4a4121b..ef55f77d8 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -1576,11 +1576,11 @@ mod tests { }; use super::{create_client, FfiMessage, FfiMessageCallback, FfiXmtpClient}; - use ethers::utils::hex; - use ethers_core::rand::{ + use ethers::core::rand::{ self, distributions::{Alphanumeric, DistString}, }; + use ethers::utils::hex; use tokio::{sync::Notify, time::error::Elapsed}; use xmtp_cryptography::{signature::RecoverableSignature, utils::rng}; use xmtp_id::associations::generate_inbox_id; diff --git a/bindings_ffi/src/v2.rs b/bindings_ffi/src/v2.rs index 090306e97..f98a9a803 100644 --- a/bindings_ffi/src/v2.rs +++ b/bindings_ffi/src/v2.rs @@ -591,7 +591,7 @@ mod tests { let msg = "TestVector1"; let sig_hash = "19d6bec562518e365d07ba3cce26d08a5fffa2cbb1e7fe03c1f2d6a722fd3a5e544097b91f8f8cd11d43b032659f30529139ab1a9ecb6c81ed4a762179e87db81c"; - let sig_bytes = ethers_core::utils::hex::decode(sig_hash).unwrap(); + let sig_bytes = ethers::core::utils::hex::decode(sig_hash).unwrap(); let recovered_addr = crate::v2::recover_address(sig_bytes, msg.to_string()).unwrap(); assert_eq!(recovered_addr, addr.to_lowercase()); } diff --git a/examples/cli/Cargo.toml b/examples/cli/Cargo.toml index 861e168a0..3f8329805 100644 --- a/examples/cli/Cargo.toml +++ b/examples/cli/Cargo.toml @@ -15,7 +15,6 @@ path = "cli-client.rs" [dependencies] clap = { version = "4.4.6", features = ["derive"] } ethers = "2.0.4" -ethers-core = "2.0.4" femme = "2.2.1" futures = "0.3.28" hex = "0.4.3" diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 7f9235405..3c8ce7dbd 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -10,10 +10,10 @@ use tonic::transport::ClientTlsConfig; use tonic::{async_trait, metadata::MetadataValue, transport::Channel, Request, Streaming}; use xmtp_proto::api_client::ClientWithMetadata; +use xmtp_proto::xmtp::mls::api::v1::{GroupMessage, WelcomeMessage}; use xmtp_proto::{ api_client::{ - Error, ErrorKind, GroupMessageStream, MutableApiSubscription, WelcomeMessageStream, - XmtpApiClient, XmtpApiSubscription, XmtpMlsClient, + Error, ErrorKind, MutableApiSubscription, XmtpApiClient, XmtpApiSubscription, XmtpMlsClient, }, xmtp::identity::api::v1::identity_api_client::IdentityApiClient as ProtoIdentityApiClient, xmtp::message_api::v1::{ @@ -131,7 +131,6 @@ impl ClientWithMetadata for Client { } } -#[async_trait] impl XmtpApiClient for Client { type Subscription = Subscription; type MutableSubscription = GrpcMutableSubscription; @@ -335,7 +334,6 @@ impl MutableApiSubscription for GrpcMutableSubscription { } } -#[async_trait] impl XmtpMlsClient for Client { #[tracing::instrument(level = "trace", skip_all)] async fn upload_key_package(&self, req: UploadKeyPackageRequest) -> Result<(), Error> { @@ -409,7 +407,7 @@ impl XmtpMlsClient for Client { async fn subscribe_group_messages( &self, req: SubscribeGroupMessagesRequest, - ) -> Result { + ) -> Result> + Send, Error> { let client = &mut self.mls_client.clone(); let res = client .subscribe_group_messages(self.build_request(req)) @@ -420,13 +418,13 @@ impl XmtpMlsClient for Client { let new_stream = stream.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)); - Ok(Box::pin(new_stream)) + Ok(new_stream) } async fn subscribe_welcome_messages( &self, req: SubscribeWelcomeMessagesRequest, - ) -> Result { + ) -> Result> + Send, Error> { let client = &mut self.mls_client.clone(); let res = client .subscribe_welcome_messages(self.build_request(req)) @@ -437,6 +435,6 @@ impl XmtpMlsClient for Client { let new_stream = stream.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)); - Ok(Box::pin(new_stream)) + Ok(new_stream) } } diff --git a/xmtp_api_grpc/src/identity.rs b/xmtp_api_grpc/src/identity.rs index 0fbb27e6d..92531e0a6 100644 --- a/xmtp_api_grpc/src/identity.rs +++ b/xmtp_api_grpc/src/identity.rs @@ -1,4 +1,3 @@ -use tonic::async_trait; use xmtp_proto::{ api_client::{Error, ErrorKind, XmtpIdentityClient}, xmtp::identity::api::v1::{ @@ -10,7 +9,6 @@ use xmtp_proto::{ use crate::Client; -#[async_trait] impl XmtpIdentityClient for Client { #[tracing::instrument(level = "trace", skip_all)] async fn publish_identity_update( diff --git a/xmtp_cryptography/Cargo.toml b/xmtp_cryptography/Cargo.toml index 7e06749f0..67ab6baa2 100644 --- a/xmtp_cryptography/Cargo.toml +++ b/xmtp_cryptography/Cargo.toml @@ -8,7 +8,6 @@ version.workspace = true curve25519-dalek = "4" ecdsa = "0.16.9" ethers = { workspace = true } -ethers-core = { workspace = true } hex = { workspace = true } k256 = { version = "0.13.3", features = ["ecdh"] } log = { workspace = true } diff --git a/xmtp_cryptography/src/signature.rs b/xmtp_cryptography/src/signature.rs index 4f25414fe..687b3bce8 100644 --- a/xmtp_cryptography/src/signature.rs +++ b/xmtp_cryptography/src/signature.rs @@ -1,6 +1,6 @@ use curve25519_dalek::{edwards::CompressedEdwardsY, traits::IsIdentity}; +use ethers::core::types::{self as ethers_types, H160}; use ethers::types::Address; -use ethers_core::types::{self as ethers_types, H160}; pub use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey}; use k256::Secp256k1; use serde::{Deserialize, Serialize}; @@ -98,8 +98,8 @@ impl From<(ecdsa::Signature, RecoveryId)> for RecoverableSignature { } } -impl From for RecoverableSignature { - fn from(value: ethers_core::types::Signature) -> Self { +impl From for RecoverableSignature { + fn from(value: ethers::core::types::Signature) -> Self { RecoverableSignature::Eip191Signature(value.to_vec()) } } diff --git a/xmtp_cryptography/src/utils.rs b/xmtp_cryptography/src/utils.rs index efbc1c502..35e13d4ba 100644 --- a/xmtp_cryptography/src/utils.rs +++ b/xmtp_cryptography/src/utils.rs @@ -1,5 +1,5 @@ +use ethers::core::utils::keccak256; pub use ethers::prelude::LocalWallet; -use ethers_core::utils::keccak256; use k256::ecdsa::VerifyingKey; use rand::{CryptoRng, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index 449c5f5fa..94f82f343 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -8,7 +8,6 @@ async-trait.workspace = true chrono.workspace = true ed25519-dalek = { workspace = true, features = ["digest"] } ed25519.workspace = true -ethers-core.workspace = true ethers.workspace = true futures.workspace = true hex.workspace = true diff --git a/xmtp_id/src/associations/association_log.rs b/xmtp_id/src/associations/association_log.rs index 2bccf68d0..bf54b4688 100644 --- a/xmtp_id/src/associations/association_log.rs +++ b/xmtp_id/src/associations/association_log.rs @@ -3,7 +3,6 @@ use super::member::{Member, MemberIdentifier, MemberKind}; use super::serialization::{from_identity_update_proto, DeserializationError}; use super::signature::{Signature, SignatureError, SignatureKind}; use super::state::AssociationState; -use async_trait::async_trait; use prost::Message; use thiserror::Error; use xmtp_proto::xmtp::identity::associations::IdentityUpdate as IdentityUpdateProto; @@ -38,8 +37,7 @@ pub enum AssociationError { MissingIdentityUpdate, } -#[async_trait] -pub trait IdentityAction: Send + 'static { +pub(crate) trait IdentityAction: Send + 'static { async fn update_state( &self, existing_state: Option, @@ -65,7 +63,6 @@ pub struct CreateInbox { pub initial_address_signature: Box, } -#[async_trait] impl IdentityAction for CreateInbox { async fn update_state( &self, @@ -110,7 +107,6 @@ pub struct AddAssociation { pub existing_member_signature: Box, } -#[async_trait::async_trait] impl IdentityAction for AddAssociation { async fn update_state( &self, @@ -205,7 +201,6 @@ pub struct RevokeAssociation { pub revoked_member: MemberIdentifier, } -#[async_trait] impl IdentityAction for RevokeAssociation { async fn update_state( &self, @@ -261,7 +256,6 @@ pub struct ChangeRecoveryAddress { pub new_recovery_address: String, } -#[async_trait] impl IdentityAction for ChangeRecoveryAddress { async fn update_state( &self, @@ -299,7 +293,6 @@ pub enum Action { ChangeRecoveryAddress(ChangeRecoveryAddress), } -#[async_trait] impl IdentityAction for Action { async fn update_state( &self, @@ -366,7 +359,6 @@ impl TryFrom> for IdentityUpdate { } } -#[async_trait] impl IdentityAction for IdentityUpdate { async fn update_state( &self, diff --git a/xmtp_id/src/associations/mod.rs b/xmtp_id/src/associations/mod.rs index 198a84a26..7e1c423d0 100644 --- a/xmtp_id/src/associations/mod.rs +++ b/xmtp_id/src/associations/mod.rs @@ -16,6 +16,8 @@ pub use self::serialization::{map_vec, try_map_vec, DeserializationError}; pub use self::signature::*; pub use self::state::{AssociationState, AssociationStateDiff}; +use crate::associations::association_log::IdentityAction; + // Apply a single IdentityUpdate to an existing AssociationState pub async fn apply_update( initial_state: AssociationState, diff --git a/xmtp_id/src/associations/signature.rs b/xmtp_id/src/associations/signature.rs index 7a4190d51..fefb5fb4c 100644 --- a/xmtp_id/src/associations/signature.rs +++ b/xmtp_id/src/associations/signature.rs @@ -182,8 +182,6 @@ pub struct SmartContractWalletSignature { chain_rpc_url: String, } -unsafe impl Send for SmartContractWalletSignature {} - impl SmartContractWalletSignature { pub fn new( signature_text: String, diff --git a/xmtp_id/src/lib.rs b/xmtp_id/src/lib.rs index bf7ee091a..f6fa1ad29 100644 --- a/xmtp_id/src/lib.rs +++ b/xmtp_id/src/lib.rs @@ -40,7 +40,6 @@ pub async fn is_smart_contract( Ok(!code.is_empty()) } -// TODO: Remove this trait pub trait InboxOwner { /// Get address of the wallet. fn get_address(&self) -> String; @@ -54,7 +53,7 @@ impl InboxOwner for LocalWallet { } fn sign(&self, text: &str) -> Result { - let message_hash = ethers_core::utils::hash_message(text); + let message_hash = ethers::core::utils::hash_message(text); Ok(self.sign_hash(message_hash)?.to_vec().into()) } } diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index c992137ba..384751048 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -36,8 +36,6 @@ diesel = { version = "2.2.2", features = [ ] } diesel_migrations = { version = "2.2.0", features = ["sqlite"] } ed25519-dalek = "2.1.1" -ethers-core.workspace = true -ethers.workspace = true futures.workspace = true hex.workspace = true libsqlite3-sys = { version = "0.29.0", optional = true } diff --git a/xmtp_mls/benches/group_limit.rs b/xmtp_mls/benches/group_limit.rs index 8408bd305..03b57f455 100755 --- a/xmtp_mls/benches/group_limit.rs +++ b/xmtp_mls/benches/group_limit.rs @@ -3,7 +3,6 @@ //! using `RUST_LOG=trace` will additionally output a `tracing.folded` file, which //! may be used to generate a flamegraph of execution from tracing logs. use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput}; -use ethers::signers::LocalWallet; use std::{collections::HashMap, sync::Arc}; use tokio::runtime::{Builder, Handle, Runtime}; use tracing::{trace_span, Instrument}; @@ -33,7 +32,7 @@ fn setup() -> (Arc, Vec, Runtime) { .unwrap(); let (client, identities) = runtime.block_on(async { - let wallet = LocalWallet::new(&mut rng()); + let wallet = xmtp_cryptography::generate_local_wallet(); // use dev network if `DEV_GRPC` is set let dev = std::env::var("DEV_GRPC"); diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index 7ac073f26..5a1921b1e 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -264,7 +264,7 @@ where pub async fn subscribe_group_messages( &self, filters: Vec, - ) -> Result { + ) -> Result> + '_, ApiError> { self.api_client .subscribe_group_messages(SubscribeGroupMessagesRequest { filters: filters.into_iter().map(|f| f.into()).collect(), @@ -276,7 +276,7 @@ where &self, installation_key: Vec, id_cursor: Option, - ) -> Result { + ) -> Result> + '_, ApiError> { self.api_client .subscribe_welcome_messages(SubscribeWelcomeMessagesRequest { filters: vec![WelcomeFilterProto { diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index dce196d84..569d68b05 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -142,8 +142,6 @@ mod tests { api::test_utils::*, identity::Identity, storage::identity::StoredIdentity, utils::test::rand_vec, Store, }; - use ethers::signers::Signer; - use ethers_core::k256; use openmls::credentials::{Credential, CredentialType}; use openmls_basic_credential::SignatureKeyPair; use openmls_traits::types::SignatureScheme; diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index cb8894271..f3a858b3e 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::pin::Pin; use std::sync::Arc; use futures::Stream; @@ -18,7 +17,7 @@ impl MlsGroup { pub(crate) async fn process_stream_entry( &self, envelope: GroupMessage, - client: Arc>, + client: &Client, ) -> Result, GroupError> where ApiClient: XmtpApi, @@ -34,11 +33,9 @@ impl MlsGroup { let created_ns = msgv1.created_ns; if !self.has_already_synced(msg_id).await? { - let client_pointer = client.clone(); let process_result = retry_async!( Retry::default(), (async { - let client_pointer = client_pointer.clone(); let client_id = client_id.clone(); let msgv1 = msgv1.clone(); self.context @@ -55,7 +52,7 @@ impl MlsGroup { ); self.process_message( - client_pointer.as_ref(), + client, &mut openmls_group, &provider, &msgv1, @@ -109,7 +106,7 @@ impl MlsGroup { pub async fn process_streamed_group_message( &self, envelope_bytes: Vec, - client: Arc>, + client: &Client, ) -> Result where ApiClient: XmtpApi, @@ -121,12 +118,12 @@ impl MlsGroup { message.ok_or(GroupError::MissingMessage) } - pub async fn stream( - &self, - client: Arc>, - ) -> Result + Send + '_>>, GroupError> + pub async fn stream<'a, ApiClient>( + &'a self, + client: &'a Client, + ) -> Result + '_, GroupError> where - ApiClient: crate::XmtpApi, + ApiClient: crate::XmtpApi + 'static, { Ok(client .stream_messages(HashMap::from([( @@ -146,7 +143,7 @@ impl MlsGroup { callback: impl FnMut(StoredGroupMessage) + Send + 'static, ) -> StreamHandle> where - ApiClient: crate::XmtpApi, + ApiClient: crate::XmtpApi + 'static, { Client::::stream_messages_with_callback( client, diff --git a/xmtp_mls/src/identity.rs b/xmtp_mls/src/identity.rs index 27eadbfd2..bbbf77aee 100644 --- a/xmtp_mls/src/identity.rs +++ b/xmtp_mls/src/identity.rs @@ -15,7 +15,6 @@ use crate::{ }; use crate::{retryable, Fetch, Store}; use ed25519_dalek::SigningKey; -use ethers::signers::WalletError; use log::debug; use log::info; use openmls::prelude::tls_codec::Serialize; @@ -141,8 +140,6 @@ pub enum IdentityError { #[error("legacy key does not match address")] LegacyKeyMismatch, #[error(transparent)] - WalletError(#[from] WalletError), - #[error(transparent)] OpenMls(#[from] openmls::prelude::Error), #[error(transparent)] StorageError(#[from] crate::storage::StorageError), diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index b4350eb53..e9860755e 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -445,7 +445,6 @@ pub async fn load_identity_updates( #[cfg(test)] pub(crate) mod tests { - use ethers::signers::LocalWallet; use tracing_test::traced_test; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::{ @@ -465,7 +464,7 @@ pub(crate) mod tests { use super::load_identity_updates; pub(crate) async fn sign_with_wallet( - wallet: &LocalWallet, + wallet: &impl InboxOwner, signature_request: &mut SignatureRequest, ) { let wallet_signature: Vec = wallet diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 9d330f0bc..f025b4508 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -11,7 +11,6 @@ mod hpke; pub mod identity; mod identity_updates; mod mutex_registry; -pub mod owner; pub mod retry; pub mod storage; pub mod subscriptions; @@ -56,12 +55,7 @@ pub trait XmtpTestClient { async fn create_dev() -> Self; } -pub trait InboxOwner { - /// Get address of the wallet. - fn get_address(&self) -> String; - /// Sign text with the wallet. - fn sign(&self, text: &str) -> Result; -} +pub use xmtp_id::InboxOwner; /// Inserts a model to the underlying data store, erroring if it already exists pub trait Store { diff --git a/xmtp_mls/src/owner/evm_owner.rs b/xmtp_mls/src/owner/evm_owner.rs deleted file mode 100644 index bbf4fbf19..000000000 --- a/xmtp_mls/src/owner/evm_owner.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub use ethers::signers::{LocalWallet, Signer}; - -use xmtp_cryptography::signature::{h160addr_to_string, RecoverableSignature, SignatureError}; - -use crate::InboxOwner; - -impl InboxOwner for LocalWallet { - fn get_address(&self) -> String { - h160addr_to_string(self.address()) - } - - fn sign(&self, text: &str) -> Result { - let message_hash = ethers_core::utils::hash_message(text); - Ok(self.sign_hash(message_hash)?.to_vec().into()) - } -} diff --git a/xmtp_mls/src/owner/mod.rs b/xmtp_mls/src/owner/mod.rs deleted file mode 100644 index 1b15ea292..000000000 --- a/xmtp_mls/src/owner/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod evm_owner; diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 6c3fd03e1..69d0cb7ea 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, pin::Pin, sync::Arc}; +use std::{collections::HashMap, sync::Arc}; use futures::{FutureExt, Stream, StreamExt}; use prost::Message; @@ -67,7 +67,7 @@ impl From for (Vec, MessagesStreamInfo) { impl Client where - ApiClient: XmtpApi, + ApiClient: XmtpApi + 'static, { async fn process_streamed_welcome( &self, @@ -130,7 +130,7 @@ where pub async fn stream_conversations( &self, - ) -> Result + Send + '_>>, ClientError> { + ) -> Result + Send + '_, ClientError> { let event_queue = tokio_stream::wrappers::BroadcastStream::new(self.local_events.subscribe()); @@ -167,48 +167,50 @@ where } }); - Ok(Box::pin(futures::stream::select(stream, event_queue))) + Ok(futures::stream::select(stream, event_queue)) } - #[tracing::instrument(skip(self, group_id_to_info))] - pub(crate) async fn stream_messages( - self: Arc, + // #[tracing::instrument(skip(self, group_id_to_info))] + pub(crate) async fn stream_messages<'a>( + &'a self, group_id_to_info: HashMap, MessagesStreamInfo>, - ) -> Result + Send>>, ClientError> { + ) -> Result + Send + '_, ClientError> + where + ApiClient: 'static, + { let filters: Vec = group_id_to_info .iter() .map(|(group_id, info)| GroupFilter::new(group_id.clone(), Some(info.cursor))) .collect(); + let messages_subscription = self.api_client.subscribe_group_messages(filters).await?; let stream = messages_subscription .map(move |res| { - let context = self.context.clone(); - let client = self.clone(); - - let group_id_to_info = group_id_to_info.clone(); + let group_info = group_id_to_info.clone(); async move { match res { Ok(envelope) => { log::info!("Received message streaming payload"); let group_id = extract_group_id(&envelope)?; log::info!("Extracted group id {}", hex::encode(&group_id)); - let stream_info = group_id_to_info.get(&group_id).ok_or( + let stream_info = group_info.get(&group_id).ok_or( ClientError::StreamInconsistency( "Received message for a non-subscribed group".to_string(), ), )?; - let mls_group = - MlsGroup::new(context, group_id, stream_info.convo_created_at_ns); - mls_group - .process_stream_entry(envelope.clone(), client.clone()) - .await + let mls_group = MlsGroup::new( + self.context.clone(), + group_id, + stream_info.convo_created_at_ns, + ); + mls_group.process_stream_entry(envelope, self).await } Err(err) => Err(GroupError::Api(err)), } } }) - .filter_map(move |res| async { + .filter_map(|res| async { match res.await { Ok(Some(message)) => Some(message), Ok(None) => { @@ -221,14 +223,13 @@ where } } }); - - Ok(Box::pin(stream)) + Ok(stream) } } impl Client where - ApiClient: XmtpApi, + ApiClient: XmtpApi + 'static, { pub fn stream_conversations_with_callback( client: Arc>, @@ -237,7 +238,8 @@ where let (tx, rx) = oneshot::channel(); let handle = tokio::spawn(async move { - let mut stream = client.stream_conversations().await?; + let stream = client.stream_conversations().await?; + futures::pin_mut!(stream); let _ = tx.send(()); while let Some(convo) = stream.next().await { convo_callback(convo) @@ -258,9 +260,11 @@ where ) -> StreamHandle> { let (tx, rx) = oneshot::channel(); + let client = client.clone(); let handle = tokio::spawn(async move { - let mut stream = Self::stream_messages(client, group_id_to_info).await?; + let stream = Self::stream_messages(&client, group_id_to_info).await?; let _ = tx.send(()); + futures::pin_mut!(stream); while let Some(message) = stream.next().await { callback(message) } @@ -274,11 +278,12 @@ where } pub async fn stream_all_messages( - client: Arc>, - ) -> Result>, ClientError> { - client.sync_welcomes().await?; + &self, + ) -> Result> + Send + '_, ClientError> + { + self.sync_welcomes().await?; - let mut group_id_to_info = client + let mut group_id_to_info = self .store() .conn()? .find_groups(None, None, None, None)? @@ -287,12 +292,14 @@ where .collect::, MessagesStreamInfo>>(); let stream = async_stream::stream! { - let client = client.clone(); - let mut messages_stream = client - .clone() + let messages_stream = self .stream_messages(group_id_to_info.clone()) .await?; - let mut convo_stream = Self::stream_conversations(&client).await?; + futures::pin_mut!(messages_stream); + + let convo_stream = self.stream_conversations().await?; + futures::pin_mut!(convo_stream); + let mut extra_messages = Vec::new(); loop { @@ -316,19 +323,19 @@ where if group_id_to_info.contains_key(&new_group.group_id) { continue; } - - for info in group_id_to_info.values_mut() { + let mut new_group_id_to_info = group_id_to_info.clone(); + for info in new_group_id_to_info.values_mut() { info.cursor = 0; } - group_id_to_info.insert( + new_group_id_to_info.insert( new_group.group_id, MessagesStreamInfo { convo_created_at_ns: new_group.created_at_ns, cursor: 1, // For the new group, stream all messages since the group was created }, ); - - let new_messages_stream = match client.clone().stream_messages(group_id_to_info.clone()).await { + std::mem::swap(&mut group_id_to_info, &mut new_group_id_to_info); + let new_messages_stream = match self.stream_messages(group_id_to_info.clone()).await { Ok(stream) => stream, Err(e) => { log::error!("{}", e); @@ -341,13 +348,13 @@ where while let Some(Some(message)) = messages_stream.next().now_or_never() { extra_messages.push(message); } - let _ = std::mem::replace(&mut messages_stream, new_messages_stream); + messages_stream.set(new_messages_stream); }, } } }; - Ok(Box::pin(stream)) + Ok(stream) } pub fn stream_all_messages_with_callback( @@ -357,8 +364,9 @@ where let (tx, rx) = oneshot::channel(); let handle = tokio::spawn(async move { - let mut stream = Self::stream_all_messages(client).await?; + let stream = Self::stream_all_messages(&client).await?; let _ = tx.send(()); + futures::pin_mut!(stream); while let Some(message) = stream.next().await { match message { Ok(m) => callback(m), diff --git a/xmtp_mls/src/utils/bench.rs b/xmtp_mls/src/utils/bench.rs index 61ac2d590..51ea81b78 100644 --- a/xmtp_mls/src/utils/bench.rs +++ b/xmtp_mls/src/utils/bench.rs @@ -4,7 +4,6 @@ #![allow(clippy::unwrap_used)] use crate::{builder::ClientBuilder, Client}; -use ethers::signers::{LocalWallet, Signer}; use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index fa6da32e0..6217214fc 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -4,7 +4,6 @@ name = "xmtp_proto" version.workspace = true [dependencies] -async-trait = { workspace = true } futures = { workspace = true } futures-core = { workspace = true } pbjson-types.workspace = true @@ -15,6 +14,7 @@ prost-types = { workspace = true } serde = { workspace = true } openmls_basic_credential = { workspace = true, optional = true } openmls = { workspace = true, optional = true } +trait-variant = "0.1.2" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tonic = { workspace = true } @@ -39,4 +39,4 @@ proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations "xmtp-mls-message_contents" = [] "xmtp-mls_validation-v1" = ["xmtp-identity-associations"] "xmtp-xmtpv4" = ["xmtp-identity-associations","xmtp-mls-api-v1"] -## @@protoc_insertion_point(features) \ No newline at end of file +## @@protoc_insertion_point(features) diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index cd0dd6160..8d466c46d 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -1,6 +1,5 @@ use std::{error::Error as StdError, fmt}; -use async_trait::async_trait; use futures::{stream, Stream}; pub use super::xmtp::message_api::v1::{ @@ -103,8 +102,7 @@ pub trait XmtpApiSubscription { fn close_stream(&mut self); } -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[allow(async_fn_in_trait)] pub trait MutableApiSubscription: Stream> + Send { async fn update(&mut self, req: SubscribeRequest) -> Result<(), Error>; fn close(&self); @@ -116,9 +114,8 @@ pub trait ClientWithMetadata: Send + Sync { } // Wasm futures don't have `Send` or `Sync` bounds. -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait XmtpApiClient: Send + Sync { +#[allow(async_fn_in_trait)] +pub trait XmtpApiClient { type Subscription: XmtpApiSubscription; type MutableSubscription: MutableApiSubscription; @@ -151,9 +148,9 @@ pub type WelcomeMessageStream = stream::BoxStream<'static, Result>; // Wasm futures don't have `Send` or `Sync` bounds. -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait XmtpMlsClient: Send + Sync + 'static { +#[allow(async_fn_in_trait)] +#[trait_variant::make(XmtpMlsClient: Send)] +pub trait LocalXmtpMlsClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error>; async fn fetch_key_packages( &self, @@ -173,17 +170,16 @@ pub trait XmtpMlsClient: Send + Sync + 'static { async fn subscribe_group_messages( &self, request: SubscribeGroupMessagesRequest, - ) -> Result; + ) -> Result> + Send, Error>; async fn subscribe_welcome_messages( &self, request: SubscribeWelcomeMessagesRequest, - ) -> Result; + ) -> Result> + Send, Error>; } -// Wasm futures don't have `Send` or `Sync` bounds. -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait XmtpIdentityClient: Send + Sync + 'static { +#[allow(async_fn_in_trait)] +#[trait_variant::make(XmtpIdentityClient: Send)] +pub trait LocalXmtpIdentityClient { async fn publish_identity_update( &self, request: PublishIdentityUpdateRequest, From 23393e3ca81cfcabcafa58643cc5cdf971eff81b Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 5 Sep 2024 21:55:32 -0400 Subject: [PATCH 21/97] dont use mem::swap --- xmtp_mls/src/subscriptions.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 69d0cb7ea..3f6075afc 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -323,18 +323,16 @@ where if group_id_to_info.contains_key(&new_group.group_id) { continue; } - let mut new_group_id_to_info = group_id_to_info.clone(); - for info in new_group_id_to_info.values_mut() { + for info in group_id_to_info.values_mut() { info.cursor = 0; } - new_group_id_to_info.insert( + group_id_to_info.insert( new_group.group_id, MessagesStreamInfo { convo_created_at_ns: new_group.created_at_ns, cursor: 1, // For the new group, stream all messages since the group was created }, ); - std::mem::swap(&mut group_id_to_info, &mut new_group_id_to_info); let new_messages_stream = match self.stream_messages(group_id_to_info.clone()).await { Ok(stream) => stream, Err(e) => { From 4854f7af8f8024e491da8164c649dcf1b3bca5a0 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 6 Sep 2024 11:25:50 -0400 Subject: [PATCH 22/97] turn Stream into a real type for mockall --- Cargo.lock | 1 + xmtp_api_grpc/src/grpc_api_helper.rs | 19 +++------ xmtp_mls/Cargo.toml | 1 + xmtp_mls/src/api/mls.rs | 4 +- xmtp_mls/src/api/test_utils.rs | 31 ++++++++------- xmtp_mls/src/builder.rs | 8 ++-- xmtp_mls/src/groups/subscriptions.rs | 11 ++++-- xmtp_mls/src/lib.rs | 2 - xmtp_mls/src/subscriptions.rs | 6 ++- xmtp_mls/src/utils/test.rs | 2 - xmtp_proto/src/api_client.rs | 59 ++++++++++++++++++++++------ 11 files changed, 88 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1520b68a7..91f62d6fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6354,6 +6354,7 @@ dependencies = [ "diesel", "diesel_migrations", "ed25519-dalek", + "ethers", "flume", "futures", "hex", diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 3c8ce7dbd..0625513b7 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -7,10 +7,9 @@ use futures::stream::{AbortHandle, Abortable}; use futures::{SinkExt, Stream, StreamExt, TryStreamExt}; use tokio::sync::oneshot; use tonic::transport::ClientTlsConfig; -use tonic::{async_trait, metadata::MetadataValue, transport::Channel, Request, Streaming}; +use tonic::{metadata::MetadataValue, transport::Channel, Request, Streaming}; -use xmtp_proto::api_client::ClientWithMetadata; -use xmtp_proto::xmtp::mls::api::v1::{GroupMessage, WelcomeMessage}; +use xmtp_proto::api_client::{ClientWithMetadata, GroupMessageStream, WelcomeMessageStream}; use xmtp_proto::{ api_client::{ Error, ErrorKind, MutableApiSubscription, XmtpApiClient, XmtpApiSubscription, XmtpMlsClient, @@ -317,7 +316,6 @@ impl Stream for GrpcMutableSubscription { } } -#[async_trait] impl MutableApiSubscription for GrpcMutableSubscription { async fn update(&mut self, req: SubscribeRequest) -> Result<(), Error> { self.update_channel @@ -333,7 +331,6 @@ impl MutableApiSubscription for GrpcMutableSubscription { self.update_channel.close_channel(); } } - impl XmtpMlsClient for Client { #[tracing::instrument(level = "trace", skip_all)] async fn upload_key_package(&self, req: UploadKeyPackageRequest) -> Result<(), Error> { @@ -407,7 +404,7 @@ impl XmtpMlsClient for Client { async fn subscribe_group_messages( &self, req: SubscribeGroupMessagesRequest, - ) -> Result> + Send, Error> { + ) -> Result { let client = &mut self.mls_client.clone(); let res = client .subscribe_group_messages(self.build_request(req)) @@ -416,15 +413,13 @@ impl XmtpMlsClient for Client { let stream = res.into_inner(); - let new_stream = stream.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)); - - Ok(new_stream) + Ok(stream.into()) } async fn subscribe_welcome_messages( &self, req: SubscribeWelcomeMessagesRequest, - ) -> Result> + Send, Error> { + ) -> Result { let client = &mut self.mls_client.clone(); let res = client .subscribe_welcome_messages(self.build_request(req)) @@ -433,8 +428,6 @@ impl XmtpMlsClient for Client { let stream = res.into_inner(); - let new_stream = stream.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)); - - Ok(new_stream) + Ok(stream.into()) } } diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 384751048..2e8034237 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -91,6 +91,7 @@ tracing-test = "0.2.4" tracing.workspace = true xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_id = { path = "../xmtp_id", features = ["test-utils"] } +ethers.workspace = true [[bench]] harness = false diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index 5a1921b1e..dd79a1a76 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -2,9 +2,7 @@ use std::collections::HashMap; use super::ApiClientWrapper; use crate::{retry_async, XmtpApi}; -use xmtp_proto::api_client::{ - Error as ApiError, ErrorKind, GroupMessageStream, WelcomeMessageStream, -}; +use xmtp_proto::api_client::{Error as ApiError, ErrorKind}; use xmtp_proto::xmtp::mls::api::v1::{ group_message_input::{Version as GroupMessageInputVersion, V1 as GroupMessageInputV1}, subscribe_group_messages_request::Filter as GroupFilterProto, diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index 973ab17b4..3d150b525 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -1,21 +1,23 @@ -use async_trait::async_trait; use mockall::mock; use xmtp_proto::{ api_client::{ ClientWithMetadata, Error, GroupMessageStream, WelcomeMessageStream, XmtpIdentityClient, XmtpMlsClient, }, - xmtp::identity::api::v1::{ - GetIdentityUpdatesRequest as GetIdentityUpdatesV2Request, - GetIdentityUpdatesResponse as GetIdentityUpdatesV2Response, GetInboxIdsRequest, - GetInboxIdsResponse, PublishIdentityUpdateRequest, PublishIdentityUpdateResponse, - }, - xmtp::mls::api::v1::{ - group_message::{Version as GroupMessageVersion, V1 as GroupMessageV1}, - FetchKeyPackagesRequest, FetchKeyPackagesResponse, GroupMessage, QueryGroupMessagesRequest, - QueryGroupMessagesResponse, QueryWelcomeMessagesRequest, QueryWelcomeMessagesResponse, - SendGroupMessagesRequest, SendWelcomeMessagesRequest, SubscribeGroupMessagesRequest, - SubscribeWelcomeMessagesRequest, UploadKeyPackageRequest, + xmtp::{ + identity::api::v1::{ + GetIdentityUpdatesRequest as GetIdentityUpdatesV2Request, + GetIdentityUpdatesResponse as GetIdentityUpdatesV2Response, GetInboxIdsRequest, + GetInboxIdsResponse, PublishIdentityUpdateRequest, PublishIdentityUpdateResponse, + }, + mls::api::v1::{ + group_message::{Version as GroupMessageVersion, V1 as GroupMessageV1}, + FetchKeyPackagesRequest, FetchKeyPackagesResponse, GroupMessage, + QueryGroupMessagesRequest, QueryGroupMessagesResponse, QueryWelcomeMessagesRequest, + QueryWelcomeMessagesResponse, SendGroupMessagesRequest, SendWelcomeMessagesRequest, + SubscribeGroupMessagesRequest, SubscribeWelcomeMessagesRequest, + UploadKeyPackageRequest, WelcomeMessage, + }, }, }; @@ -37,6 +39,8 @@ pub fn build_group_messages(num_messages: usize, group_id: Vec) -> Vec Result<(), Error>; } - #[async_trait] impl XmtpMlsClient for ApiClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error>; async fn fetch_key_packages( @@ -61,14 +64,12 @@ mock! { async fn subscribe_welcome_messages(&self, request: SubscribeWelcomeMessagesRequest) -> Result; } - #[async_trait] impl XmtpIdentityClient for ApiClient { async fn publish_identity_update(&self, request: PublishIdentityUpdateRequest) -> Result; async fn get_identity_updates_v2(&self, request: GetIdentityUpdatesV2Request) -> Result; async fn get_inbox_ids(&self, request: GetInboxIdsRequest) -> Result; } - #[async_trait] impl XmtpTestClient for ApiClient { async fn create_local() -> Self { ApiClient } async fn create_dev() -> Self { ApiClient } diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 569d68b05..603037113 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -186,10 +186,10 @@ mod tests { /// Generate a random legacy key proto bytes and corresponding account address. async fn generate_random_legacy_key() -> (Vec, String) { let wallet = generate_local_wallet(); - let address = h160addr_to_string(wallet.address()); + let address = wallet.get_address(); let created_ns = rand_u64(); - let secret_key = k256::ecdsa::SigningKey::random(&mut rng()); - let public_key = k256::ecdsa::VerifyingKey::from(&secret_key); + let secret_key = ethers::core::k256::ecdsa::SigningKey::random(&mut rng()); + let public_key = ethers::core::k256::ecdsa::VerifyingKey::from(&secret_key); let public_key_bytes = public_key.to_sec1_bytes().to_vec(); let mut public_key_buf = vec![]; UnsignedPublicKey { @@ -203,7 +203,7 @@ mod tests { .encode(&mut public_key_buf) .unwrap(); let message = ValidatedLegacySignedPublicKey::text(&public_key_buf); - let signed_public_key = wallet.sign_message(message).await.unwrap().to_vec(); + let signed_public_key: Vec = wallet.sign(&message).unwrap().into(); let (bytes, recovery_id) = signed_public_key.as_slice().split_at(64); let recovery_id = recovery_id[0]; let signed_private_key: SignedPrivateKey = SignedPrivateKey { diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index f3a858b3e..132ac7a3d 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -199,7 +199,7 @@ mod tests { let mut message_bytes: Vec = Vec::new(); message.encode(&mut message_bytes).unwrap(); let message_again = amal_group - .process_streamed_group_message(message_bytes, Arc::new(amal)) + .process_streamed_group_message(message_bytes, &amal) .await; if let Ok(message) = message_again { @@ -234,7 +234,8 @@ mod tests { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let mut stream = UnboundedReceiverStream::new(rx); tokio::spawn(async move { - let mut stream = bola_group_ptr.stream(bola_ptr).await.unwrap(); + let stream = bola_group_ptr.stream(&bola_ptr).await.unwrap(); + futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); notify_ptr.notify_one(); @@ -278,7 +279,8 @@ mod tests { let amal_ptr = amal.clone(); let group_ptr = group.clone(); tokio::spawn(async move { - let mut stream = group_ptr.stream(amal_ptr).await.unwrap(); + let stream = group_ptr.stream(&amal_ptr).await.unwrap(); + futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); } @@ -320,7 +322,8 @@ mod tests { let (start_tx, start_rx) = tokio::sync::oneshot::channel(); let mut stream = UnboundedReceiverStream::new(rx); tokio::spawn(async move { - let mut stream = amal_group_ptr.stream(amal_ptr).await.unwrap(); + let mut stream = amal_group_ptr.stream(&amal_ptr).await.unwrap(); + futures::pin_mut!(stream); let _ = start_tx.send(()); while let Some(item) = stream.next().await { let _ = tx.send(item); diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index f025b4508..c97a6e04a 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -21,7 +21,6 @@ mod xmtp_openmls_provider; pub use client::{Client, Network}; use storage::StorageError; -use xmtp_cryptography::signature::{RecoverableSignature, SignatureError}; use xmtp_proto::api_client::{ClientWithMetadata, XmtpIdentityClient, XmtpMlsClient}; /// XMTP Api Super Trait @@ -49,7 +48,6 @@ impl XmtpApi for T where } #[cfg(any(test, feature = "test-utils", feature = "bench"))] -#[async_trait::async_trait] pub trait XmtpTestClient { async fn create_local() -> Self; async fn create_dev() -> Self; diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 3f6075afc..e87ad7649 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -414,7 +414,8 @@ mod tests { let mut stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); let bob_ptr = bob.clone(); tokio::spawn(async move { - let mut bob_stream = bob_ptr.stream_conversations().await.unwrap(); + let bob_stream = bob_ptr.stream_conversations().await.unwrap(); + futures::pin_mut!(bob_stream); while let Some(item) = bob_stream.next().await { let _ = tx.send(item); } @@ -451,7 +452,8 @@ mod tests { let notify_ptr = notify.clone(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); tokio::spawn(async move { - let mut stream = alice_group.stream(alice).await.unwrap(); + let stream = alice_group.stream(&alice).await.unwrap(); + futures::pin_mut!(stream); while let Some(item) = stream.next().await { let _ = tx.send(item); notify_ptr.notify_one(); diff --git a/xmtp_mls/src/utils/test.rs b/xmtp_mls/src/utils/test.rs index 5fc724d5e..2ca1378d8 100755 --- a/xmtp_mls/src/utils/test.rs +++ b/xmtp_mls/src/utils/test.rs @@ -49,7 +49,6 @@ pub fn rand_time() -> i64 { rng.gen_range(0..1_000_000_000) } -#[async_trait::async_trait] #[cfg(feature = "http-api")] impl XmtpTestClient for XmtpHttpApiClient { async fn create_local() -> Self { @@ -61,7 +60,6 @@ impl XmtpTestClient for XmtpHttpApiClient { } } -#[async_trait::async_trait] impl XmtpTestClient for GrpcClient { async fn create_local() -> Self { GrpcClient::create("http://localhost:5556".into(), false) diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index 8d466c46d..fb323872e 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -1,6 +1,7 @@ +use std::pin::Pin; use std::{error::Error as StdError, fmt}; -use futures::{stream, Stream}; +use futures::{Stream, StreamExt}; pub use super::xmtp::message_api::v1::{ BatchQueryRequest, BatchQueryResponse, Envelope, PagingInfo, PublishRequest, PublishResponse, @@ -137,15 +138,51 @@ pub trait XmtpApiClient { async fn batch_query(&self, request: BatchQueryRequest) -> Result; } -#[cfg(not(target_arch = "wasm32"))] -pub type GroupMessageStream = stream::BoxStream<'static, Result>; -#[cfg(target_arch = "wasm32")] -pub type GroupMessageStream = stream::LocalBoxStream<'static, Result>; +pub struct GroupMessageStream { + inner: tonic::codec::Streaming, +} + +impl From> for GroupMessageStream { + fn from(inner: tonic::codec::Streaming) -> Self { + GroupMessageStream { inner } + } +} + +impl Stream for GroupMessageStream { + type Item = Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.inner + .poll_next_unpin(cx) + .map(|data| data.map(|v| v.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)))) + } +} -#[cfg(not(target_arch = "wasm32"))] -pub type WelcomeMessageStream = stream::BoxStream<'static, Result>; -#[cfg(target_arch = "wasm32")] -pub type WelcomeMessageStream = stream::LocalBoxStream<'static, Result>; +pub struct WelcomeMessageStream { + inner: tonic::codec::Streaming, +} + +impl From> for WelcomeMessageStream { + fn from(inner: tonic::codec::Streaming) -> Self { + WelcomeMessageStream { inner } + } +} + +impl Stream for WelcomeMessageStream { + type Item = Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.inner + .poll_next_unpin(cx) + .map(|data| data.map(|v| v.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)))) + } +} // Wasm futures don't have `Send` or `Sync` bounds. #[allow(async_fn_in_trait)] @@ -170,11 +207,11 @@ pub trait LocalXmtpMlsClient { async fn subscribe_group_messages( &self, request: SubscribeGroupMessagesRequest, - ) -> Result> + Send, Error>; + ) -> Result; async fn subscribe_welcome_messages( &self, request: SubscribeWelcomeMessagesRequest, - ) -> Result> + Send, Error>; + ) -> Result; } #[allow(async_fn_in_trait)] From 82c45f49c9c9938cefc2307833130e8e08abec15 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 6 Sep 2024 15:16:24 -0400 Subject: [PATCH 23/97] async fn in trait works well --- Cargo.lock | 5 +- Cargo.toml | 1 + xmtp_api_grpc/src/grpc_api_helper.rs | 61 +++++++++++++- xmtp_api_http/Cargo.toml | 2 - xmtp_api_http/src/lib.rs | 36 +++++--- xmtp_api_http/src/util.rs | 15 ++-- xmtp_mls/Cargo.toml | 2 +- xmtp_mls/src/api/test_utils.rs | 10 +-- xmtp_mls/src/groups/subscriptions.rs | 2 +- xmtp_mls/src/lib.rs | 119 ++++++++++++++++++++++----- xmtp_mls/src/subscriptions.rs | 7 +- xmtp_proto/Cargo.toml | 6 ++ xmtp_proto/src/api_client.rs | 100 +++++++++++----------- 13 files changed, 255 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91f62d6fc..af7e51c69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6245,8 +6245,6 @@ name = "xmtp_api_http" version = "0.0.1" dependencies = [ "async-stream", - "async-trait", - "bytes", "futures", "log", "reqwest 0.12.5", @@ -6346,7 +6344,6 @@ dependencies = [ "anyhow", "async-barrier", "async-stream", - "async-trait", "bincode", "chrono", "criterion", @@ -6387,6 +6384,7 @@ dependencies = [ "tracing-log", "tracing-subscriber", "tracing-test", + "trait-variant", "xmtp_api_grpc", "xmtp_api_http", "xmtp_cryptography", @@ -6401,6 +6399,7 @@ version = "0.0.1" dependencies = [ "futures", "futures-core", + "mockall", "openmls", "openmls_basic_credential", "pbjson", diff --git a/Cargo.toml b/Cargo.toml index ecec55098..947953a45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ version = "0.0.1" anyhow = "1.0" async-stream = "0.3" async-trait = "0.1.77" +trait-variant = "0.1.2" chrono = "0.4.38" ctor = "0.2" ed25519 = "2.2.3" diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 0625513b7..07a917d29 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -9,7 +9,8 @@ use tokio::sync::oneshot; use tonic::transport::ClientTlsConfig; use tonic::{metadata::MetadataValue, transport::Channel, Request, Streaming}; -use xmtp_proto::api_client::{ClientWithMetadata, GroupMessageStream, WelcomeMessageStream}; +use xmtp_proto::api_client::{ClientWithMetadata, XmtpMlsStreams}; +use xmtp_proto::xmtp::mls::api::v1::{GroupMessage, WelcomeMessage}; use xmtp_proto::{ api_client::{ Error, ErrorKind, MutableApiSubscription, XmtpApiClient, XmtpApiSubscription, XmtpMlsClient, @@ -400,11 +401,62 @@ impl XmtpMlsClient for Client { res.map(|r| r.into_inner()) .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) } +} + +pub struct GroupMessageStream { + inner: tonic::codec::Streaming, +} + +impl From> for GroupMessageStream { + fn from(inner: tonic::codec::Streaming) -> Self { + GroupMessageStream { inner } + } +} + +impl Stream for GroupMessageStream { + type Item = Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.inner + .poll_next_unpin(cx) + .map(|data| data.map(|v| v.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)))) + } +} + +pub struct WelcomeMessageStream { + inner: tonic::codec::Streaming, +} + +impl From> for WelcomeMessageStream { + fn from(inner: tonic::codec::Streaming) -> Self { + WelcomeMessageStream { inner } + } +} + +impl Stream for WelcomeMessageStream { + type Item = Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.inner + .poll_next_unpin(cx) + .map(|data| data.map(|v| v.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)))) + } +} + +impl XmtpMlsStreams for Client { + type GroupMessageStream<'a> = GroupMessageStream; + type WelcomeMessageStream<'a> = WelcomeMessageStream; async fn subscribe_group_messages( &self, req: SubscribeGroupMessagesRequest, - ) -> Result { + ) -> Result, Error> { let client = &mut self.mls_client.clone(); let res = client .subscribe_group_messages(self.build_request(req)) @@ -412,14 +464,14 @@ impl XmtpMlsClient for Client { .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; let stream = res.into_inner(); - + // let stream = stream.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)); Ok(stream.into()) } async fn subscribe_welcome_messages( &self, req: SubscribeWelcomeMessagesRequest, - ) -> Result { + ) -> Result, Error> { let client = &mut self.mls_client.clone(); let res = client .subscribe_welcome_messages(self.build_request(req)) @@ -427,6 +479,7 @@ impl XmtpMlsClient for Client { .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; let stream = res.into_inner(); + // let stream = stream.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)); Ok(stream.into()) } diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml index 13852a3dc..2a2b9cb8d 100644 --- a/xmtp_api_http/Cargo.toml +++ b/xmtp_api_http/Cargo.toml @@ -8,8 +8,6 @@ crate-type = ["cdylib", "rlib"] [dependencies] async-stream.workspace = true -async-trait = { workspace = true } -bytes = "1.7" futures = { workspace = true } log.workspace = true reqwest = { version = "0.12.5", features = ["json", "stream"] } diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index aa6fca4b4..8be12efd9 100755 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -3,10 +3,10 @@ pub mod constants; mod util; -use async_trait::async_trait; +use futures::stream; use reqwest::header; use util::{create_grpc_stream, handle_error}; -use xmtp_proto::api_client::{ClientWithMetadata, Error, ErrorKind, XmtpIdentityClient}; +use xmtp_proto::api_client::{ClientWithMetadata, Error, ErrorKind, LocalXmtpIdentityClient}; use xmtp_proto::xmtp::identity::api::v1::{ GetIdentityUpdatesRequest as GetIdentityUpdatesV2Request, GetIdentityUpdatesResponse as GetIdentityUpdatesV2Response, GetInboxIdsRequest, @@ -14,7 +14,7 @@ use xmtp_proto::xmtp::identity::api::v1::{ }; use xmtp_proto::xmtp::mls::api::v1::{GroupMessage, WelcomeMessage}; use xmtp_proto::{ - api_client::{GroupMessageStream, WelcomeMessageStream, XmtpMlsClient}, + api_client::{LocalXmtpMlsClient, LocalXmtpMlsStreams}, xmtp::mls::api::v1::{ FetchKeyPackagesRequest, FetchKeyPackagesResponse, QueryGroupMessagesRequest, QueryGroupMessagesResponse, QueryWelcomeMessagesRequest, QueryWelcomeMessagesResponse, @@ -120,9 +120,7 @@ impl ClientWithMetadata for XmtpHttpApiClient { } } -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -impl XmtpMlsClient for XmtpHttpApiClient { +impl LocalXmtpMlsClient for XmtpHttpApiClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error> { let res = self .http_client @@ -230,11 +228,29 @@ impl XmtpMlsClient for XmtpHttpApiClient { log::debug!("query_welcome_messages"); handle_error(&*res) } +} + +impl LocalXmtpMlsStreams for XmtpHttpApiClient { + // hard to avoid boxing here: + // 1.) use `hyper` instead of `reqwest` and create our own `Stream` type + // 2.) ise `impl Stream` in return of `XmtpMlsStreams` but that + // breaks the `mockall::` functionality, since `mockall` does not support `impl Trait` in + // `Trait` yet. + + #[cfg(not(target_arch = "wasm32"))] + type GroupMessageStream<'a> = stream::BoxStream<'a, Result>; + #[cfg(not(target_arch = "wasm32"))] + type WelcomeMessageStream<'a> = stream::BoxStream<'a, Result>; + + #[cfg(target_arch = "wasm32")] + type GroupMessageStream<'a> = stream::LocalBoxStream<'a, Result>; + #[cfg(target_arch = "wasm32")] + type WelcomeMessageStream<'a> = stream::LocalBoxStream<'a, Result>; async fn subscribe_group_messages( &self, request: SubscribeGroupMessagesRequest, - ) -> Result { + ) -> Result, Error> { log::debug!("subscribe_group_messages"); Ok(create_grpc_stream::<_, GroupMessage>( request, @@ -246,7 +262,7 @@ impl XmtpMlsClient for XmtpHttpApiClient { async fn subscribe_welcome_messages( &self, request: SubscribeWelcomeMessagesRequest, - ) -> Result { + ) -> Result, Error> { log::debug!("subscribe_welcome_messages"); Ok(create_grpc_stream::<_, WelcomeMessage>( request, @@ -256,9 +272,7 @@ impl XmtpMlsClient for XmtpHttpApiClient { } } -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -impl XmtpIdentityClient for XmtpHttpApiClient { +impl LocalXmtpIdentityClient for XmtpHttpApiClient { async fn publish_identity_update( &self, request: PublishIdentityUpdateRequest, diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index 056471eef..52051b1b8 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -1,4 +1,7 @@ -use futures::{stream, Stream, StreamExt}; +use futures::{ + stream::{self, StreamExt}, + Stream, +}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::Deserializer; use std::io::Read; @@ -49,9 +52,7 @@ pub fn create_grpc_stream< endpoint: String, http_client: reqwest::Client, ) -> stream::LocalBoxStream<'static, Result> { - log::info!("About to spawn stream"); - let stream = create_grpc_stream_inner(request, endpoint, http_client); - stream.boxed_local() + create_grpc_stream_inner(request, endpoint, http_client).boxed_local() } #[cfg(not(target_arch = "wasm32"))] @@ -63,12 +64,10 @@ pub fn create_grpc_stream< endpoint: String, http_client: reqwest::Client, ) -> stream::BoxStream<'static, Result> { - log::info!("About to spawn stream"); - let stream = create_grpc_stream_inner(request, endpoint, http_client); - stream.boxed() + create_grpc_stream_inner(request, endpoint, http_client).boxed() } -fn create_grpc_stream_inner< +pub fn create_grpc_stream_inner< T: Serialize + Send + 'static, R: DeserializeOwned + Send + std::fmt::Debug + 'static, >( diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 2e8034237..da06659a1 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -26,7 +26,7 @@ test-utils = [] [dependencies] aes-gcm = { version = "0.10.3", features = ["std"] } async-stream.workspace = true -async-trait.workspace = true +trait-variant.workspace = true bincode = "1.3.3" chrono = { workspace = true } diesel = { version = "2.2.2", features = [ diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index 3d150b525..122e94bfe 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -1,9 +1,6 @@ use mockall::mock; use xmtp_proto::{ - api_client::{ - ClientWithMetadata, Error, GroupMessageStream, WelcomeMessageStream, XmtpIdentityClient, - XmtpMlsClient, - }, + api_client::{ClientWithMetadata, Error, XmtpIdentityClient, XmtpMlsClient, XmtpMlsStreams}, xmtp::{ identity::api::v1::{ GetIdentityUpdatesRequest as GetIdentityUpdatesV2Request, @@ -60,7 +57,10 @@ mock! { async fn send_welcome_messages(&self, request: SendWelcomeMessagesRequest) -> Result<(), Error>; async fn query_group_messages(&self, request: QueryGroupMessagesRequest) -> Result; async fn query_welcome_messages(&self, request: QueryWelcomeMessagesRequest) -> Result; - async fn subscribe_group_messages(&self, request: SubscribeGroupMessagesRequest) -> Result; + } + + impl XmtpMlsStreams for ApiClient { + async fn subscribe_group_messages(&self, request: SubscribeGroupMessagesRequest) -> Result> + Send, Error>; async fn subscribe_welcome_messages(&self, request: SubscribeWelcomeMessagesRequest) -> Result; } diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index 132ac7a3d..eaf826f50 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -322,7 +322,7 @@ mod tests { let (start_tx, start_rx) = tokio::sync::oneshot::channel(); let mut stream = UnboundedReceiverStream::new(rx); tokio::spawn(async move { - let mut stream = amal_group_ptr.stream(&amal_ptr).await.unwrap(); + let stream = amal_group_ptr.stream(&amal_ptr).await.unwrap(); futures::pin_mut!(stream); let _ = start_tx.send(()); while let Some(item) = stream.next().await { diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index c97a6e04a..7d533e8e7 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -21,34 +21,113 @@ mod xmtp_openmls_provider; pub use client::{Client, Network}; use storage::StorageError; -use xmtp_proto::api_client::{ClientWithMetadata, XmtpIdentityClient, XmtpMlsClient}; +use xmtp_proto::api_client::{ + ClientWithMetadata, XmtpIdentityClient, XmtpMlsClient, XmtpMlsStreams, +}; +pub use trait_impls::*; /// XMTP Api Super Trait /// Implements all Trait Network APIs for convenience. -#[cfg(not(test))] -pub trait XmtpApi -where - Self: XmtpMlsClient + XmtpIdentityClient + ClientWithMetadata, -{ -} -#[cfg(not(test))] -impl XmtpApi for T where T: XmtpMlsClient + XmtpIdentityClient + ClientWithMetadata + ?Sized {} +mod trait_impls { + use super::*; + pub use inner::*; + + // native, release + #[cfg(all(not(test), not(target_arch = "wasm32")))] + mod inner { + use super::*; + pub trait XmtpApi + where + Self: XmtpMlsClient + + XmtpMlsStreams + + XmtpIdentityClient + + ClientWithMetadata + + Send + + Sync, + { + } + impl XmtpApi for T where + T: XmtpMlsClient + + XmtpMlsStreams + + XmtpIdentityClient + + ClientWithMetadata + + Send + + Sync + + ?Sized + { + } + } -#[cfg(test)] -pub trait XmtpApi -where - Self: XmtpMlsClient + XmtpIdentityClient + XmtpTestClient + ClientWithMetadata, -{ -} + // wasm32, release + #[cfg(all(not(test), target_arch = "wasm32"))] + mod inner { + use super::*; + + pub trait XmtpApi + where + Self: LocalXmtpMlsClient + + LocalXmtpMlsStreams + + LocalXmtpIdentityClient + + LocalClientWithMetadata, + { + } + impl XmtpApi for T where + T: LocalXmtpMlsClient + + LocalXmtpMlsStreams + + LocalXmtpIdentityClient + + LocalClientWithMetadata + + ?Sized + { + } + } -#[cfg(test)] -impl XmtpApi for T where - T: XmtpMlsClient + XmtpIdentityClient + XmtpTestClient + ClientWithMetadata + ?Sized -{ + // test, native + #[cfg(all(test, not(target_arch = "wasm32")))] + mod inner { + use super::*; + + pub trait XmtpApi + where + Self: XmtpMlsClient + + XmtpMlsStreams + + XmtpIdentityClient + + XmtpTestClient + + ClientWithMetadata + + Send + + Sync, + { + } + impl XmtpApi for T where + T: XmtpMlsClient + + XmtpMlsStreams + + XmtpIdentityClient + + XmtpTestClient + + ClientWithMetadata + + Send + + Sync + + ?Sized + { + } + } + + // test, wasm32 + #[cfg(all(test, target_arch = "wasm32"))] + mod inner { + pub trait XmtpApi + where + Self: LocalXmtpMlsClient + + LocalXmtpMlsStreams + + LocalXmtpIdentityClient + + LocalXmtpTestClient + + LocalClientWithMetadata, + { + } + } } #[cfg(any(test, feature = "test-utils", feature = "bench"))] -pub trait XmtpTestClient { +#[trait_variant::make(XmtpTestClient: Send)] +pub trait LocalXmtpTestClient { async fn create_local() -> Self; async fn create_dev() -> Self; } diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index e87ad7649..e0c442bfa 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -130,7 +130,7 @@ where pub async fn stream_conversations( &self, - ) -> Result + Send + '_, ClientError> { + ) -> Result + '_, ClientError> { let event_queue = tokio_stream::wrappers::BroadcastStream::new(self.local_events.subscribe()); @@ -174,7 +174,7 @@ where pub(crate) async fn stream_messages<'a>( &'a self, group_id_to_info: HashMap, MessagesStreamInfo>, - ) -> Result + Send + '_, ClientError> + ) -> Result + '_, ClientError> where ApiClient: 'static, { @@ -279,8 +279,7 @@ where pub async fn stream_all_messages( &self, - ) -> Result> + Send + '_, ClientError> - { + ) -> Result> + '_, ClientError> { self.sync_welcomes().await?; let mut group_id_to_info = self diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index 6217214fc..d4e052856 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -16,12 +16,18 @@ openmls_basic_credential = { workspace = true, optional = true } openmls = { workspace = true, optional = true } trait-variant = "0.1.2" +mockall = { version = "0.13", optional = true } + +[dev-dependencies] +mockall = { version = "0.13" } + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tonic = { workspace = true } [features] convert = ["openmls_basic_credential", "openmls", "proto_full"] +test-utils = ["dep:mockall"] default = [] # @@protoc_deletion_point(features) diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index fb323872e..3efbeded2 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -1,7 +1,7 @@ -use std::pin::Pin; +use std::future::Future; use std::{error::Error as StdError, fmt}; -use futures::{Stream, StreamExt}; +use futures::Stream; pub use super::xmtp::message_api::v1::{ BatchQueryRequest, BatchQueryResponse, Envelope, PagingInfo, PublishRequest, PublishResponse, @@ -109,14 +109,16 @@ pub trait MutableApiSubscription: Stream> + Send fn close(&self); } -pub trait ClientWithMetadata: Send + Sync { +pub trait ClientWithMetadata { fn set_libxmtp_version(&mut self, version: String) -> Result<(), Error>; fn set_app_version(&mut self, version: String) -> Result<(), Error>; } // Wasm futures don't have `Send` or `Sync` bounds. #[allow(async_fn_in_trait)] -pub trait XmtpApiClient { +#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] +#[trait_variant::make(XmtpApiClient: Send)] +pub trait LocalXmtpApiClient { type Subscription: XmtpApiSubscription; type MutableSubscription: MutableApiSubscription; @@ -138,55 +140,10 @@ pub trait XmtpApiClient { async fn batch_query(&self, request: BatchQueryRequest) -> Result; } -pub struct GroupMessageStream { - inner: tonic::codec::Streaming, -} - -impl From> for GroupMessageStream { - fn from(inner: tonic::codec::Streaming) -> Self { - GroupMessageStream { inner } - } -} - -impl Stream for GroupMessageStream { - type Item = Result; - - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - self.inner - .poll_next_unpin(cx) - .map(|data| data.map(|v| v.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)))) - } -} - -pub struct WelcomeMessageStream { - inner: tonic::codec::Streaming, -} - -impl From> for WelcomeMessageStream { - fn from(inner: tonic::codec::Streaming) -> Self { - WelcomeMessageStream { inner } - } -} - -impl Stream for WelcomeMessageStream { - type Item = Result; - - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - self.inner - .poll_next_unpin(cx) - .map(|data| data.map(|v| v.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)))) - } -} - // Wasm futures don't have `Send` or `Sync` bounds. #[allow(async_fn_in_trait)] #[trait_variant::make(XmtpMlsClient: Send)] +#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] pub trait LocalXmtpMlsClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error>; async fn fetch_key_packages( @@ -204,18 +161,57 @@ pub trait LocalXmtpMlsClient { &self, request: QueryWelcomeMessagesRequest, ) -> Result; +} + +// #[trait_variant::make(XmtpMlsStreams: Send)] +#[allow(async_fn_in_trait)] +#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] +pub trait LocalXmtpMlsStreams { + type GroupMessageStream<'a>: Stream> + 'a + where + Self: 'a; + + type WelcomeMessageStream<'a>: Stream> + 'a + where + Self: 'a; + async fn subscribe_group_messages( &self, request: SubscribeGroupMessagesRequest, - ) -> Result; + ) -> Result, Error>; async fn subscribe_welcome_messages( &self, request: SubscribeWelcomeMessagesRequest, - ) -> Result; + ) -> Result, Error>; +} + +// we manually make a Local+Non-Local trait variant here b/c the +// macro breaks with GATs +#[allow(async_fn_in_trait)] +#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] +pub trait XmtpMlsStreams: Send { + type GroupMessageStream<'a>: Stream> + Send + 'a + where + Self: 'a; + + type WelcomeMessageStream<'a>: Stream> + Send + 'a + where + Self: 'a; + + fn subscribe_group_messages( + &self, + request: SubscribeGroupMessagesRequest, + ) -> impl Future, Error>> + Send; + + fn subscribe_welcome_messages( + &self, + request: SubscribeWelcomeMessagesRequest, + ) -> impl Future, Error>> + Send; } #[allow(async_fn_in_trait)] #[trait_variant::make(XmtpIdentityClient: Send)] +#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] pub trait LocalXmtpIdentityClient { async fn publish_identity_update( &self, From cb10a0913246efda70ea321ce1561a76c647da2c Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 6 Sep 2024 16:56:19 -0400 Subject: [PATCH 24/97] fix http --- Cargo.lock | 1 + xmtp_api_grpc/src/lib.rs | 2 +- xmtp_api_http/Cargo.toml | 1 + xmtp_api_http/src/lib.rs | 54 +++++++++++++++++++++++++++------- xmtp_api_http/src/util.rs | 2 +- xmtp_mls/src/api/test_utils.rs | 17 ++++++++--- 6 files changed, 60 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af7e51c69..5f73f1bfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6246,6 +6246,7 @@ version = "0.0.1" dependencies = [ "async-stream", "futures", + "hyper 1.4.1", "log", "reqwest 0.12.5", "serde", diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index 10472c2a8..a774b86bc 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -5,7 +5,7 @@ mod identity; pub const LOCALHOST_ADDRESS: &str = "http://localhost:5556"; pub const DEV_ADDRESS: &str = "https://grpc.dev.xmtp.network:443"; -pub use grpc_api_helper::Client; +pub use grpc_api_helper::{Client, GroupMessageStream, WelcomeMessageStream}; #[cfg(test)] mod tests { diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml index 2a2b9cb8d..a2e34e3ed 100644 --- a/xmtp_api_http/Cargo.toml +++ b/xmtp_api_http/Cargo.toml @@ -11,6 +11,7 @@ async-stream.workspace = true futures = { workspace = true } log.workspace = true reqwest = { version = "0.12.5", features = ["json", "stream"] } +hyper = "1.4" serde = { workspace = true } serde_json = { workspace = true } thiserror = "1.0" diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index 8be12efd9..c902f701c 100755 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -6,7 +6,9 @@ mod util; use futures::stream; use reqwest::header; use util::{create_grpc_stream, handle_error}; -use xmtp_proto::api_client::{ClientWithMetadata, Error, ErrorKind, LocalXmtpIdentityClient}; +// #[cfg(not(target_arch = "wasm32"))] +// use xmtp_proto::api_client::XmtpMlsStreams; +use xmtp_proto::api_client::{ClientWithMetadata, Error, ErrorKind, XmtpIdentityClient}; use xmtp_proto::xmtp::identity::api::v1::{ GetIdentityUpdatesRequest as GetIdentityUpdatesV2Request, GetIdentityUpdatesResponse as GetIdentityUpdatesV2Response, GetInboxIdsRequest, @@ -14,7 +16,7 @@ use xmtp_proto::xmtp::identity::api::v1::{ }; use xmtp_proto::xmtp::mls::api::v1::{GroupMessage, WelcomeMessage}; use xmtp_proto::{ - api_client::{LocalXmtpMlsClient, LocalXmtpMlsStreams}, + api_client::{XmtpMlsClient, XmtpMlsStreams}, xmtp::mls::api::v1::{ FetchKeyPackagesRequest, FetchKeyPackagesResponse, QueryGroupMessagesRequest, QueryGroupMessagesResponse, QueryWelcomeMessagesRequest, QueryWelcomeMessagesResponse, @@ -120,7 +122,7 @@ impl ClientWithMetadata for XmtpHttpApiClient { } } -impl LocalXmtpMlsClient for XmtpHttpApiClient { +impl XmtpMlsClient for XmtpHttpApiClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error> { let res = self .http_client @@ -230,22 +232,51 @@ impl LocalXmtpMlsClient for XmtpHttpApiClient { } } -impl LocalXmtpMlsStreams for XmtpHttpApiClient { +impl XmtpMlsStreams for XmtpHttpApiClient { // hard to avoid boxing here: // 1.) use `hyper` instead of `reqwest` and create our own `Stream` type // 2.) ise `impl Stream` in return of `XmtpMlsStreams` but that // breaks the `mockall::` functionality, since `mockall` does not support `impl Trait` in // `Trait` yet. - #[cfg(not(target_arch = "wasm32"))] type GroupMessageStream<'a> = stream::BoxStream<'a, Result>; - #[cfg(not(target_arch = "wasm32"))] type WelcomeMessageStream<'a> = stream::BoxStream<'a, Result>; - #[cfg(target_arch = "wasm32")] - type GroupMessageStream<'a> = stream::LocalBoxStream<'a, Result>; - #[cfg(target_arch = "wasm32")] - type WelcomeMessageStream<'a> = stream::LocalBoxStream<'a, Result>; + async fn subscribe_group_messages( + &self, + request: SubscribeGroupMessagesRequest, + ) -> Result, Error> { + log::debug!("subscribe_group_messages"); + Ok(create_grpc_stream::<_, GroupMessage>( + request, + self.endpoint(ApiEndpoints::SUBSCRIBE_GROUP_MESSAGES), + self.http_client.clone(), + )) + } + + async fn subscribe_welcome_messages( + &self, + request: SubscribeWelcomeMessagesRequest, + ) -> Result, Error> { + log::debug!("subscribe_welcome_messages"); + Ok(create_grpc_stream::<_, WelcomeMessage>( + request, + self.endpoint(ApiEndpoints::SUBSCRIBE_WELCOME_MESSAGES), + self.http_client.clone(), + )) + } +} + +/* +#[cfg(not(target_arch = "wasm32"))] +impl XmtpMlsStreams for XmtpHttpApiClient { + // hard to avoid boxing here: + // 1.) use `hyper` instead of `reqwest` and create our own `Stream` type + // 2.) ise `impl Stream` in return of `XmtpMlsStreams` but that + // breaks the `mockall::` functionality, since `mockall` does not support `impl Trait` in + // `Trait` yet. + type GroupMessageStream<'a> = stream::BoxStream<'a, Result>; + type WelcomeMessageStream<'a> = stream::BoxStream<'a, Result>; async fn subscribe_group_messages( &self, @@ -271,8 +302,9 @@ impl LocalXmtpMlsStreams for XmtpHttpApiClient { )) } } +*/ -impl LocalXmtpIdentityClient for XmtpHttpApiClient { +impl XmtpIdentityClient for XmtpHttpApiClient { async fn publish_identity_update( &self, request: PublishIdentityUpdateRequest, diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index 52051b1b8..2b73ee8a0 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -51,7 +51,7 @@ pub fn create_grpc_stream< request: T, endpoint: String, http_client: reqwest::Client, -) -> stream::LocalBoxStream<'static, Result> { +) -> LocalBoxStream<'static, Result> { create_grpc_stream_inner(request, endpoint, http_client).boxed_local() } diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index 122e94bfe..d473a5fd2 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -36,8 +36,6 @@ pub fn build_group_messages(num_messages: usize, group_id: Vec) -> Vec Result> + Send, Error>; - async fn subscribe_welcome_messages(&self, request: SubscribeWelcomeMessagesRequest) -> Result; + #[cfg(not(feature = "http-api"))] + type GroupMessageStream<'a> = xmtp_api_grpc::GroupMessageStream; + #[cfg(not(feature = "http-api"))] + type WelcomeMessageStream<'a> = xmtp_api_grpc::WelcomeMessageStream; + + #[cfg(feature = "http-api")] + type GroupMessageStream<'a> = futures::stream::BoxStream<'static, Result>; + #[cfg(feature = "http-api")] + type WelcomeMessageStream<'a> = futures::stream::BoxStream<'static, Result>; + + + async fn subscribe_group_messages(&self, request: SubscribeGroupMessagesRequest) -> Result<::GroupMessageStream<'static>, Error>; + async fn subscribe_welcome_messages(&self, request: SubscribeWelcomeMessagesRequest) -> Result<::WelcomeMessageStream<'static>, Error>; } impl XmtpIdentityClient for ApiClient { From c01938b6a8ba0038a4378769d28c091196615d94 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 6 Sep 2024 17:28:41 -0400 Subject: [PATCH 25/97] fix wasm --- xmtp_api_grpc/src/grpc_api_helper.rs | 2 -- xmtp_api_http/src/lib.rs | 43 ++++------------------------ xmtp_api_http/src/util.rs | 2 +- xmtp_mls/src/builder.rs | 1 - xmtp_proto/src/api_client.rs | 19 ++++++++---- 5 files changed, 21 insertions(+), 46 deletions(-) diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 07a917d29..6e61a81ac 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -464,7 +464,6 @@ impl XmtpMlsStreams for Client { .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; let stream = res.into_inner(); - // let stream = stream.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)); Ok(stream.into()) } @@ -479,7 +478,6 @@ impl XmtpMlsStreams for Client { .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; let stream = res.into_inner(); - // let stream = stream.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)); Ok(stream.into()) } diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index c902f701c..2823c81f6 100755 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -6,7 +6,6 @@ mod util; use futures::stream; use reqwest::header; use util::{create_grpc_stream, handle_error}; -// #[cfg(not(target_arch = "wasm32"))] // use xmtp_proto::api_client::XmtpMlsStreams; use xmtp_proto::api_client::{ClientWithMetadata, Error, ErrorKind, XmtpIdentityClient}; use xmtp_proto::xmtp::identity::api::v1::{ @@ -239,44 +238,15 @@ impl XmtpMlsStreams for XmtpHttpApiClient { // breaks the `mockall::` functionality, since `mockall` does not support `impl Trait` in // `Trait` yet. + #[cfg(not(target_arch = "wasm32"))] type GroupMessageStream<'a> = stream::BoxStream<'a, Result>; + #[cfg(not(target_arch = "wasm32"))] type WelcomeMessageStream<'a> = stream::BoxStream<'a, Result>; - async fn subscribe_group_messages( - &self, - request: SubscribeGroupMessagesRequest, - ) -> Result, Error> { - log::debug!("subscribe_group_messages"); - Ok(create_grpc_stream::<_, GroupMessage>( - request, - self.endpoint(ApiEndpoints::SUBSCRIBE_GROUP_MESSAGES), - self.http_client.clone(), - )) - } - - async fn subscribe_welcome_messages( - &self, - request: SubscribeWelcomeMessagesRequest, - ) -> Result, Error> { - log::debug!("subscribe_welcome_messages"); - Ok(create_grpc_stream::<_, WelcomeMessage>( - request, - self.endpoint(ApiEndpoints::SUBSCRIBE_WELCOME_MESSAGES), - self.http_client.clone(), - )) - } -} - -/* -#[cfg(not(target_arch = "wasm32"))] -impl XmtpMlsStreams for XmtpHttpApiClient { - // hard to avoid boxing here: - // 1.) use `hyper` instead of `reqwest` and create our own `Stream` type - // 2.) ise `impl Stream` in return of `XmtpMlsStreams` but that - // breaks the `mockall::` functionality, since `mockall` does not support `impl Trait` in - // `Trait` yet. - type GroupMessageStream<'a> = stream::BoxStream<'a, Result>; - type WelcomeMessageStream<'a> = stream::BoxStream<'a, Result>; + #[cfg(target_arch = "wasm32")] + type GroupMessageStream<'a> = stream::LocalBoxStream<'a, Result>; + #[cfg(target_arch = "wasm32")] + type WelcomeMessageStream<'a> = stream::LocalBoxStream<'a, Result>; async fn subscribe_group_messages( &self, @@ -302,7 +272,6 @@ impl XmtpMlsStreams for XmtpHttpApiClient { )) } } -*/ impl XmtpIdentityClient for XmtpHttpApiClient { async fn publish_identity_update( diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index 2b73ee8a0..52051b1b8 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -51,7 +51,7 @@ pub fn create_grpc_stream< request: T, endpoint: String, http_client: reqwest::Client, -) -> LocalBoxStream<'static, Result> { +) -> stream::LocalBoxStream<'static, Result> { create_grpc_stream_inner(request, endpoint, http_client).boxed_local() } diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 603037113..cf1353cf3 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -146,7 +146,6 @@ mod tests { use openmls_basic_credential::SignatureKeyPair; use openmls_traits::types::SignatureScheme; use prost::Message; - use xmtp_cryptography::signature::h160addr_to_string; use xmtp_cryptography::utils::{generate_local_wallet, rng}; use xmtp_id::associations::ValidatedLegacySignedPublicKey; use xmtp_id::associations::{ diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index 3efbeded2..6624efbc0 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -1,4 +1,3 @@ -use std::future::Future; use std::{error::Error as StdError, fmt}; use futures::Stream; @@ -114,10 +113,17 @@ pub trait ClientWithMetadata { fn set_app_version(&mut self, version: String) -> Result<(), Error>; } +/// Global Marker trait for WebAssembly +#[cfg(target_arch = "wasm32")] +pub trait Wasm {} +#[cfg(target_arch = "wasm32")] +impl Wasm for T {} + // Wasm futures don't have `Send` or `Sync` bounds. #[allow(async_fn_in_trait)] +#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(XmtpApiClient: Send))] +#[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpApiClient: Wasm))] #[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] -#[trait_variant::make(XmtpApiClient: Send)] pub trait LocalXmtpApiClient { type Subscription: XmtpApiSubscription; type MutableSubscription: MutableApiSubscription; @@ -142,7 +148,8 @@ pub trait LocalXmtpApiClient { // Wasm futures don't have `Send` or `Sync` bounds. #[allow(async_fn_in_trait)] -#[trait_variant::make(XmtpMlsClient: Send)] +#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(XmtpMlsClient: Send))] +#[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpMlsClient: Wasm))] #[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] pub trait LocalXmtpMlsClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error>; @@ -163,9 +170,9 @@ pub trait LocalXmtpMlsClient { ) -> Result; } -// #[trait_variant::make(XmtpMlsStreams: Send)] #[allow(async_fn_in_trait)] #[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] +#[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpMlsStreams: Wasm))] pub trait LocalXmtpMlsStreams { type GroupMessageStream<'a>: Stream> + 'a where @@ -189,6 +196,7 @@ pub trait LocalXmtpMlsStreams { // macro breaks with GATs #[allow(async_fn_in_trait)] #[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] +#[cfg(not(target_arch = "wasm32"))] pub trait XmtpMlsStreams: Send { type GroupMessageStream<'a>: Stream> + Send + 'a where @@ -210,7 +218,8 @@ pub trait XmtpMlsStreams: Send { } #[allow(async_fn_in_trait)] -#[trait_variant::make(XmtpIdentityClient: Send)] +#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(XmtpIdentityClient: Send))] +#[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpIdentityClient: Wasm))] #[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] pub trait LocalXmtpIdentityClient { async fn publish_identity_update( From 13346e58386b452632ef225b34daa66d76cd0ca2 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 6 Sep 2024 19:45:03 -0400 Subject: [PATCH 26/97] fix build --- xmtp_mls/benches/group_limit.rs | 3 +-- xmtp_mls/src/groups/subscriptions.rs | 2 +- xmtp_mls/src/subscriptions.rs | 4 ++-- xmtp_proto/src/api_client.rs | 5 ----- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/xmtp_mls/benches/group_limit.rs b/xmtp_mls/benches/group_limit.rs index 03b57f455..6d41676c2 100755 --- a/xmtp_mls/benches/group_limit.rs +++ b/xmtp_mls/benches/group_limit.rs @@ -6,7 +6,6 @@ use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criteri use std::{collections::HashMap, sync::Arc}; use tokio::runtime::{Builder, Handle, Runtime}; use tracing::{trace_span, Instrument}; -use xmtp_cryptography::utils::rng; use xmtp_mls::{ builder::ClientBuilder, groups::GroupMetadataOptions, @@ -32,7 +31,7 @@ fn setup() -> (Arc, Vec, Runtime) { .unwrap(); let (client, identities) = runtime.block_on(async { - let wallet = xmtp_cryptography::generate_local_wallet(); + let wallet = xmtp_cryptography::utils::generate_local_wallet(); // use dev network if `DEV_GRPC` is set let dev = std::env::var("DEV_GRPC"); diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index ccc1d276d..9bf1f13a6 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -68,7 +68,7 @@ impl MlsGroup { if let Some(GroupError::ReceiveError(_)) = process_result.as_ref().err() { // Swallow errors here, since another process may have successfully saved the message // to the DB - match self.sync_with_conn(&client.mls_provider()?, &client).await { + match self.sync_with_conn(&client.mls_provider()?, client).await { Ok(_) => { log::debug!("Sync triggered by streamed message successful") } diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 50f5c80ab..a17386939 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -171,8 +171,8 @@ where } // #[tracing::instrument(skip(self, group_id_to_info))] - pub(crate) async fn stream_messages<'a>( - &'a self, + pub(crate) async fn stream_messages( + &self, group_id_to_info: HashMap, MessagesStreamInfo>, ) -> Result + '_, ClientError> where diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index 1d704ba64..60db8e4e9 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -123,7 +123,6 @@ impl Wasm for T {} #[allow(async_fn_in_trait)] #[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(XmtpApiClient: Send))] #[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpApiClient: Wasm))] -#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] pub trait LocalXmtpApiClient { type Subscription: XmtpApiSubscription; type MutableSubscription: MutableApiSubscription; @@ -150,7 +149,6 @@ pub trait LocalXmtpApiClient { #[allow(async_fn_in_trait)] #[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(XmtpMlsClient: Send))] #[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpMlsClient: Wasm))] -#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] pub trait LocalXmtpMlsClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error>; async fn fetch_key_packages( @@ -171,7 +169,6 @@ pub trait LocalXmtpMlsClient { } #[allow(async_fn_in_trait)] -#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] #[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpMlsStreams: Wasm))] pub trait LocalXmtpMlsStreams { type GroupMessageStream<'a>: Stream> + 'a @@ -195,7 +192,6 @@ pub trait LocalXmtpMlsStreams { // we manually make a Local+Non-Local trait variant here b/c the // macro breaks with GATs #[allow(async_fn_in_trait)] -#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] #[cfg(not(target_arch = "wasm32"))] pub trait XmtpMlsStreams: Send { type GroupMessageStream<'a>: Stream> + Send + 'a @@ -220,7 +216,6 @@ pub trait XmtpMlsStreams: Send { #[allow(async_fn_in_trait)] #[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(XmtpIdentityClient: Send))] #[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpIdentityClient: Wasm))] -#[cfg_attr(any(test, feature = "test-utils"), mockall::automock)] pub trait LocalXmtpIdentityClient { async fn publish_identity_update( &self, From fe6a6652123ab0aecdfcc3b5a9c0d05fef415923 Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Thu, 12 Sep 2024 15:23:36 -0400 Subject: [PATCH 27/97] Allocate queries in wasm space to skip JS space copy --- diesel-wasm-sqlite/src/connection/stmt.rs | 20 ++++++++++++++++---- diesel-wasm-sqlite/src/ffi.rs | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 32cbe3e58..5a7d876e1 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -14,6 +14,7 @@ use diesel::{ query_builder::{QueryFragment, QueryId}, result::{Error, QueryResult}, }; +use std::ffi::CString; use std::{cell::OnceCell, ptr::NonNull}; use wasm_bindgen::JsValue; @@ -38,7 +39,7 @@ impl Statement { ) -> QueryResult { let sqlite3 = crate::get_sqlite_unchecked(); - let flags = if matches!(is_cached, PrepareForCache::Yes { counter: _}) { + let flags = if matches!(is_cached, PrepareForCache::Yes { counter: _ }) { Some(*ffi::SQLITE_PREPARE_PERSISTENT) } else { None @@ -47,12 +48,21 @@ impl Statement { let wasm = sqlite3.inner().wasm(); let stack = wasm.pstack().pointer(); + // convert the query to a cstring + let sql = CString::new(sql)?; + let sql_bytes_with_nul = sql.as_bytes_with_nul(); + // we want to move the query over to sqlite-wasm + // allocate space for the query in sqlite-wasm space + let sql_ptr = wasm.alloc(sql_bytes_with_nul.len() as u32); + // copy cstring query to sqlite-wasm + ffi::raw_copy_to_sqlite(sql_bytes_with_nul, sql_ptr); + // allocate one 64bit pointer value let pp_stmt = wasm.pstack().alloc(8); let prepare_result = sqlite3.prepare_v3( &raw_connection.internal_connection, - sql, - -1, + sql_ptr, + sql_bytes_with_nul.len() as i32, flags.unwrap_or(0), &pp_stmt, &JsValue::NULL, @@ -66,7 +76,9 @@ impl Statement { // sqlite3_prepare_v3 returns a null pointer for empty statements. This includes // empty or only whitespace strings or any other non-op query string like a comment if p_stmt.is_null() { - return Err(diesel::result::Error::QueryBuilderError(Box::new(diesel::result::EmptyQuery))) + return Err(diesel::result::Error::QueryBuilderError(Box::new( + diesel::result::EmptyQuery, + ))); } Ok(Self { diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 018598d18..a946e32fe 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -296,7 +296,7 @@ extern "C" { pub fn prepare_v3( this: &SQLite, database: &JsValue, - sql: &str, + sql: *mut u8, n_byte: i32, prep_flags: u32, stmt: &JsValue, From a3068ec49444d812d7841b24901dcd0188da8e1e Mon Sep 17 00:00:00 2001 From: vking45 Date: Sat, 31 Aug 2024 17:22:11 +0530 Subject: [PATCH 28/97] added ser and deser for diesel-wasm-sqlite --- diesel-wasm-sqlite/package.js | 20 ++++++-- diesel-wasm-sqlite/src/connection/raw.rs | 64 ++++++++++++++---------- diesel-wasm-sqlite/src/ffi.rs | 19 +++++++ 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index 54cbd39da..e3c442295 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -311,9 +311,21 @@ export class SQLite { return this.sqlite3.capi.sqlite3_value_free(value); } - /* - serialize(database, zSchema, size, flags) { - return this.module._sqlite3_serialize(database, zSchema, size, flags); + sqlite3_serialize(database, z_schema, p_size, m_flags) { + try { + return this.sqlite3.capi.sqlite3_serialize(database, z_schema, p_size, m_flags); + } catch (error) { + console.log("error serializing"); + throw error; + } + } + + sqlite3_deserialize(database, z_schema, p_data, sz_database, sz_buffer, m_flags) { + try { + return this.sqlite3.capi.sqlite3_deserialize(database, z_schema, p_data, sz_database, sz_buffer, m_flags); + } catch (error) { + console.log("error deserializing"); + throw error; + } } - */ } diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs index 3d6a759df..0b7bccef6 100755 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -84,37 +84,49 @@ impl RawConnection { flags as i32 } - /* possible to implement this, but would need to fill in the missing wa-sqlite functions - pub(super) fn serialize(&mut self) -> SerializedDatabase { - unsafe { - let mut size: ffi::sqlite3_int64 = 0; - let data_ptr = ffi::sqlite3_serialize( - self.internal_connection.as_ptr(), - std::ptr::null(), - &mut size as *mut _, - 0, - ); - SerializedDatabase::new(data_ptr, size as usize) + pub(super) fn serialize(&self, schema: &str, flags: u32) -> SerializedDatabase { + let sqlite3 = crate::get_sqlite_unchecked(); + let mut p_size: i64 = 0; + + let data_ptr = unsafe { + sqlite3.sqlite3_serialize( + &self.internal_connection, + schema, + Some(&mut p_size), + flags + )}; + + if data_ptr.is_null() { + panic!("Serialization failed"); } + + unsafe { SerializedDatabase::new(data_ptr, p_size as usize) } } - pub(super) fn deserialize(&mut self, data: &[u8]) -> QueryResult<()> { - // the cast for `ffi::SQLITE_DESERIALIZE_READONLY` is required for old libsqlite3-sys versions - #[allow(clippy::unnecessary_cast)] - unsafe { - let result = ffi::sqlite3_deserialize( - self.internal_connection.as_ptr(), - std::ptr::null(), - data.as_ptr() as *mut u8, - data.len() as i64, - data.len() as i64, - ffi::SQLITE_DESERIALIZE_READONLY as u32, - ); - - ensure_sqlite_ok(result, self.internal_connection.as_ptr()) + pub(super) fn deserialize(&self, schema: &str, serialized_db: SerializedDatabase, total_size: usize, flags: u32) -> i32 { + let sqlite3 = crate::get_sqlite_unchecked(); + + if serialized_db.len > total_size { + panic!("Serialized database size exceeds the buffer size"); } + + let result = unsafe { + sqlite.sqlite3_deserialize( + &self.internal_connection, + schema, + serialized_db.data, + serialized_db.len as i64, + total_size as i64, + flags, + ) + }; + + if result != 0 { + panic!("Deserialization failed"); + } + + result } - */ } impl Drop for RawConnection { diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 018598d18..bc721d454 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -328,4 +328,23 @@ extern "C" { #[wasm_bindgen(method)] pub fn value_free(this: &SQLite, value: *mut u8); + #[wasm_bindgen(method)] + pub fn sqlite3_serialize( + this: &SQLite, + database: &JsValue, + z_schema: &str, + p_size: Option<&mut i64>, + m_flags: u32 + ) -> *mut u8; + + #[wasm_bindgen(method)] + pub fn sqlite3_deserialize( + this: &SQLite, + database: &JsValue, + z_schema: &str, + p_data: &mut u8, + sz_database: i64, + sz_buffer: i64, + m_flags: u32 + ) -> i32; } From 86c1b012347c7b761884eef8440525a299a02d39 Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Fri, 13 Sep 2024 14:33:58 -0400 Subject: [PATCH 29/97] make updates to serialize and deserialize functions --- diesel-wasm-sqlite/package.js | 46 +++++++++--- diesel-wasm-sqlite/src/connection/mod.rs | 1 + diesel-wasm-sqlite/src/connection/raw.rs | 70 +++++++++++-------- .../src/connection/serialized_database.rs | 14 ++-- diesel-wasm-sqlite/src/ffi.rs | 13 ++-- 5 files changed, 94 insertions(+), 50 deletions(-) diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index e3c442295..ccd06dad3 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -16,7 +16,7 @@ export class SQLite { constructor(sqlite3) { if (typeof sqlite3 === "undefined") { throw new Error( - "`sqliteObject` must be defined before calling constructor", + "`sqliteObject` must be defined before calling constructor" ); } this.sqlite3 = sqlite3; @@ -202,7 +202,7 @@ export class SQLite { nByte, prepFlags, ppStmt, - pzTail, + pzTail ); } @@ -246,7 +246,7 @@ export class SQLite { pApp, xFunc, xStep, - xFinal, + xFinal ) { try { this.sqlite3.capi.sqlite3_create_function( @@ -257,7 +257,7 @@ export class SQLite { pApp, // pApp is ignored xFunc, xStep, - xFinal, + xFinal ); console.log("create function"); } catch (error) { @@ -297,9 +297,9 @@ export class SQLite { log(`Created trigger for ${table_name}`); log(row); log(`------------------------------------`); - }, + } ); - }, + } ); } catch (error) { console.log("error creating diesel trigger"); @@ -313,19 +313,47 @@ export class SQLite { sqlite3_serialize(database, z_schema, p_size, m_flags) { try { - return this.sqlite3.capi.sqlite3_serialize(database, z_schema, p_size, m_flags); + return this.sqlite3.capi.sqlite3_serialize( + database, + z_schema, + p_size, + m_flags + ); } catch (error) { console.log("error serializing"); throw error; } } - sqlite3_deserialize(database, z_schema, p_data, sz_database, sz_buffer, m_flags) { + sqlite3_deserialize( + database, + z_schema, + p_data, + sz_database, + sz_buffer, + m_flags + ) { try { - return this.sqlite3.capi.sqlite3_deserialize(database, z_schema, p_data, sz_database, sz_buffer, m_flags); + return this.sqlite3.capi.sqlite3_deserialize( + database, + z_schema, + p_data, + sz_database, + sz_buffer, + m_flags + ); } catch (error) { console.log("error deserializing"); throw error; } } + + sqlite3_free(database, arg1) { + try { + this.sqlite3.capi.sqlite3_free(arg1); + } catch (error) { + console.log("error freeing value"); + throw error; + } + } } diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index 083bc5dac..c4c2975ca 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -3,6 +3,7 @@ mod err; mod owned_row; mod raw; mod row; +mod serialized_database; mod sqlite_value; mod statement_iterator; mod stmt; diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs index 0b7bccef6..1b7369f6c 100755 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -1,10 +1,14 @@ #![allow(dead_code)] // functions are needed, but missing functionality means they aren't used yet. -use crate::{WasmSqlite, WasmSqliteError}; -use diesel::{result::*, sql_types::HasSqlType}; +use std::ptr; + +use crate::{ffi, WasmSqlite, WasmSqliteError}; +use diesel::{result::*, sql_types::HasSqlType, IntoSql}; use wasm_bindgen::{closure::Closure, JsValue}; +use super::serialized_database::SerializedDatabase; + #[allow(missing_copy_implementations)] pub(super) struct RawConnection { pub(super) internal_connection: JsValue, @@ -34,7 +38,9 @@ impl RawConnection { pub(super) fn exec(&self, query: &str) -> QueryResult<()> { let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.exec(&self.internal_connection, query).map_err(WasmSqliteError::from)?; + sqlite3 + .exec(&self.internal_connection, query) + .map_err(WasmSqliteError::from)?; Ok(()) } @@ -84,43 +90,48 @@ impl RawConnection { flags as i32 } + /// Serializes the database from sqlite to be stored by the user/client. pub(super) fn serialize(&self, schema: &str, flags: u32) -> SerializedDatabase { let sqlite3 = crate::get_sqlite_unchecked(); - let mut p_size: i64 = 0; + let wasm = sqlite3.inner().wasm(); - let data_ptr = unsafe { - sqlite3.sqlite3_serialize( - &self.internal_connection, - schema, - Some(&mut p_size), - flags - )}; + const I64_LEN: usize = std::mem::size_of::(); + let p_size = wasm.alloc(I64_LEN as u32); + let data_ptr = sqlite3.sqlite3_serialize(&self.internal_connection, schema, p_size, flags); if data_ptr.is_null() { panic!("Serialization failed"); } - unsafe { SerializedDatabase::new(data_ptr, p_size as usize) } + let size = unsafe { + let mut buf = [0; I64_LEN]; + ffi::raw_copy_from_sqlite(p_size, I64_LEN as u32, &mut buf); + i64::from_le_bytes(buf) + }; + + unsafe { SerializedDatabase::new(data_ptr, size) } } - pub(super) fn deserialize(&self, schema: &str, serialized_db: SerializedDatabase, total_size: usize, flags: u32) -> i32 { + /// Deserializes the database from the data slice given to be loaded + /// by sqlite in the wasm space. + pub(super) fn deserialize(&self, data: &[u8], schema: &str) -> i32 { let sqlite3 = crate::get_sqlite_unchecked(); + let wasm = sqlite3.inner().wasm(); + + // allocate the space in wasm, and copy the buffer to the wasm + // memory space. + let p_data = wasm.alloc(data.len() as u32); + ffi::raw_copy_to_sqlite(data, p_data); + + let result = sqlite3.sqlite3_deserialize( + &self.internal_connection, + schema, + p_data, + data.len() as i64, + data.len() as i64, + 0, + ); - if serialized_db.len > total_size { - panic!("Serialized database size exceeds the buffer size"); - } - - let result = unsafe { - sqlite.sqlite3_deserialize( - &self.internal_connection, - schema, - serialized_db.data, - serialized_db.len as i64, - total_size as i64, - flags, - ) - }; - if result != 0 { panic!("Deserialization failed"); } @@ -132,9 +143,8 @@ impl RawConnection { impl Drop for RawConnection { fn drop(&mut self) { let sqlite3 = crate::get_sqlite_unchecked(); - - let result = sqlite3.close(&self.internal_connection); + let result = sqlite3.close(&self.internal_connection); if result != *crate::ffi::SQLITE_OK { let error_message = super::error_message(result); panic!("Error closing SQLite connection: {}", error_message); diff --git a/diesel-wasm-sqlite/src/connection/serialized_database.rs b/diesel-wasm-sqlite/src/connection/serialized_database.rs index e302a097c..0887a6ddc 100644 --- a/diesel-wasm-sqlite/src/connection/serialized_database.rs +++ b/diesel-wasm-sqlite/src/connection/serialized_database.rs @@ -1,11 +1,13 @@ use std::ops::Deref; +use crate::ffi; + /// `SerializedDatabase` is a wrapper for a serialized database that is dynamically allocated by calling `sqlite3_serialize`. /// This RAII wrapper is necessary to deallocate the memory when it goes out of scope with `sqlite3_free`. #[derive(Debug)] pub struct SerializedDatabase { - data: JsValue, - len: usize, + pub(super) data: *mut u8, + pub(super) len: i64, } impl SerializedDatabase { @@ -13,14 +15,14 @@ impl SerializedDatabase { /// /// SAFETY: The data pointer needs to be returned by sqlite /// and the length must match the underlying buffer pointer - pub(crate) unsafe fn new(data: *mut u8, len: usize) -> Self { + pub(crate) unsafe fn new(data: *mut u8, len: i64) -> Self { Self { data, len } } /// Returns a slice of the serialized database. pub fn as_slice(&self) -> &[u8] { // The pointer is never null because we don't pass the NO_COPY flag - unsafe { std::slice::from_raw_parts(self.data, self.len) } + unsafe { std::slice::from_raw_parts(self.data, self.len as usize) } } } @@ -35,8 +37,6 @@ impl Deref for SerializedDatabase { impl Drop for SerializedDatabase { /// Deallocates the memory of the serialized database when it goes out of scope. fn drop(&mut self) { - unsafe { - ffi::sqlite3_free(self.data as _); - } + ffi::sqlite3_free(self.data as _); } } diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index bc721d454..78fe14062 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -333,8 +333,8 @@ extern "C" { this: &SQLite, database: &JsValue, z_schema: &str, - p_size: Option<&mut i64>, - m_flags: u32 + p_size: *mut u8, + m_flags: u32, ) -> *mut u8; #[wasm_bindgen(method)] @@ -342,9 +342,14 @@ extern "C" { this: &SQLite, database: &JsValue, z_schema: &str, - p_data: &mut u8, + p_data: *mut u8, sz_database: i64, sz_buffer: i64, - m_flags: u32 + m_flags: u32, ) -> i32; } + +#[wasm_bindgen] +extern "C" { + pub fn sqlite3_free(arg1: *mut u8); +} From 1c991ee8ffdd830f7122bd9e5a9be22054cae28f Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Fri, 13 Sep 2024 17:42:29 -0400 Subject: [PATCH 30/97] wip --- bindings_node/Cargo.lock | 1 - diesel-wasm-sqlite/src/connection/mod.rs | 11 ++++- diesel-wasm-sqlite/src/connection/raw.rs | 31 +++++++------ .../src/connection/serialized_database.rs | 31 +------------ diesel-wasm-sqlite/src/ffi.rs | 14 +++--- diesel-wasm-sqlite/src/sqlite_fixes.rs | 3 +- diesel-wasm-sqlite/tests/test/web.rs | 43 ++++++++++++++++++- 7 files changed, 79 insertions(+), 55 deletions(-) diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index b064133cf..20c9d9734 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -5329,7 +5329,6 @@ dependencies = [ "curve25519-dalek", "ecdsa 0.16.9", "ethers", - "ethers-core", "getrandom", "hex", "k256 0.13.3", diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index c4c2975ca..76ace8b6a 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -36,8 +36,9 @@ use diesel::{ query_builder::{QueryFragment, QueryId}, QueryResult, }; +use serialized_database::SerializedDatabase; -use crate::{get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; +use crate::{ffi, get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; // This relies on the invariant that RawConnection or Statement are never // leaked. If a reference to one of those was held on a different thread, this @@ -325,6 +326,14 @@ impl WasmSqliteConnection { metadata_lookup: (), }) } + + pub fn serialize(&self) -> SerializedDatabase { + self.raw_connection.serialize() + } + + pub fn deserialize(&self, data: &[u8]) -> i32 { + self.raw_connection.deserialize(data) + } } pub struct Nothing; diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs index 1b7369f6c..3a4dc5550 100755 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -1,10 +1,10 @@ #![allow(dead_code)] // functions are needed, but missing functionality means they aren't used yet. -use std::ptr; - use crate::{ffi, WasmSqlite, WasmSqliteError}; -use diesel::{result::*, sql_types::HasSqlType, IntoSql}; +use diesel::{result::*, sql_types::HasSqlType}; +use js_sys::Uint8Array; +use serde::Serialize; use wasm_bindgen::{closure::Closure, JsValue}; use super::serialized_database::SerializedDatabase; @@ -91,30 +91,29 @@ impl RawConnection { } /// Serializes the database from sqlite to be stored by the user/client. - pub(super) fn serialize(&self, schema: &str, flags: u32) -> SerializedDatabase { + pub(super) fn serialize(&self) -> SerializedDatabase { let sqlite3 = crate::get_sqlite_unchecked(); let wasm = sqlite3.inner().wasm(); - const I64_LEN: usize = std::mem::size_of::(); - let p_size = wasm.alloc(I64_LEN as u32); - - let data_ptr = sqlite3.sqlite3_serialize(&self.internal_connection, schema, p_size, flags); + let p_size = wasm.pstack().alloc(std::mem::size_of::() as u32); + let data_ptr = sqlite3.sqlite3_serialize(&self.internal_connection, "main", &p_size, 0); if data_ptr.is_null() { panic!("Serialization failed"); } - let size = unsafe { - let mut buf = [0; I64_LEN]; - ffi::raw_copy_from_sqlite(p_size, I64_LEN as u32, &mut buf); - i64::from_le_bytes(buf) - }; + let len = p_size.as_f64().unwrap() as usize; + let mut data = vec![0; len as usize]; + + unsafe { + ffi::raw_copy_from_sqlite(data_ptr, len as u32, data.as_mut_slice()); + } - unsafe { SerializedDatabase::new(data_ptr, size) } + SerializedDatabase { data } } /// Deserializes the database from the data slice given to be loaded /// by sqlite in the wasm space. - pub(super) fn deserialize(&self, data: &[u8], schema: &str) -> i32 { + pub(super) fn deserialize(&self, data: &[u8]) -> i32 { let sqlite3 = crate::get_sqlite_unchecked(); let wasm = sqlite3.inner().wasm(); @@ -125,7 +124,7 @@ impl RawConnection { let result = sqlite3.sqlite3_deserialize( &self.internal_connection, - schema, + "main", p_data, data.len() as i64, data.len() as i64, diff --git a/diesel-wasm-sqlite/src/connection/serialized_database.rs b/diesel-wasm-sqlite/src/connection/serialized_database.rs index 0887a6ddc..491abf9b1 100644 --- a/diesel-wasm-sqlite/src/connection/serialized_database.rs +++ b/diesel-wasm-sqlite/src/connection/serialized_database.rs @@ -1,42 +1,15 @@ -use std::ops::Deref; - use crate::ffi; /// `SerializedDatabase` is a wrapper for a serialized database that is dynamically allocated by calling `sqlite3_serialize`. /// This RAII wrapper is necessary to deallocate the memory when it goes out of scope with `sqlite3_free`. #[derive(Debug)] pub struct SerializedDatabase { - pub(super) data: *mut u8, - pub(super) len: i64, -} - -impl SerializedDatabase { - /// Creates a new `SerializedDatabase` with the given data pointer and length. - /// - /// SAFETY: The data pointer needs to be returned by sqlite - /// and the length must match the underlying buffer pointer - pub(crate) unsafe fn new(data: *mut u8, len: i64) -> Self { - Self { data, len } - } - - /// Returns a slice of the serialized database. - pub fn as_slice(&self) -> &[u8] { - // The pointer is never null because we don't pass the NO_COPY flag - unsafe { std::slice::from_raw_parts(self.data, self.len as usize) } - } -} - -impl Deref for SerializedDatabase { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - self.as_slice() - } + pub data: Vec, } impl Drop for SerializedDatabase { /// Deallocates the memory of the serialized database when it goes out of scope. fn drop(&mut self) { - ffi::sqlite3_free(self.data as _); + // ffi::sqlite3_free(self.data as _); } } diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 78fe14062..ea8940eec 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -82,11 +82,13 @@ pub fn raw_copy_to_sqlite>(bytes: B, dst: *mut u8) { pub unsafe fn raw_copy_from_sqlite(src: *mut u8, len: u32, buf: &mut [u8]) { let wasm = crate::get_sqlite_unchecked().inner().wasm(); let mem = wasm.heap8u(); - let offset = (src as u32) / std::mem::size_of::() as u32; - // this is safe because we view the slice and immediately copy it into - // our memory. - let view = Uint8Array::new_with_byte_offset_and_length(&mem, offset, len); - view.raw_copy_to_ptr(buf.as_mut_ptr()) + mem.slice(src as u32, src as u32 + len) + .raw_copy_to_ptr(buf.as_mut_ptr()); + //let offset = (src as u32) / std::mem::size_of::() as u32; + //// this is safe because we view the slice and immediately copy it into + //// our memory. + //let view = Uint8Array::new_with_byte_offset_and_length(&mem, offset, len); + //view.raw_copy_to_ptr(buf.as_mut_ptr()) } pub async fn init_sqlite() { @@ -333,7 +335,7 @@ extern "C" { this: &SQLite, database: &JsValue, z_schema: &str, - p_size: *mut u8, + p_size: &JsValue, m_flags: u32, ) -> *mut u8; diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs index 235fc50f3..79402396c 100644 --- a/diesel-wasm-sqlite/src/sqlite_fixes.rs +++ b/diesel-wasm-sqlite/src/sqlite_fixes.rs @@ -162,7 +162,8 @@ mod parenthesis_wrapper { use crate::WasmSqlite; // use diesel::query_builder::combination_clause::SupportsCombinationClause; use diesel::query_builder::{ - All, AstPass, Distinct, Except, Intersect, QueryFragment, SupportsCombinationClause, Union, ParenthesisWrapper + All, AstPass, Distinct, Except, Intersect, ParenthesisWrapper, QueryFragment, + SupportsCombinationClause, Union, }; impl> QueryFragment for ParenthesisWrapper { diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index e486d35f1..8440e7577 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -1,5 +1,6 @@ //! General tests for migrations/diesel ORM/persistant databases use crate::common::prelude::*; +use diesel::dsl::count; use diesel_wasm_sqlite::dsl::RunQueryDsl; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/migrations/"); @@ -46,7 +47,7 @@ pub struct StoredBook { // published_year: NaiveDateTime, } -async fn establish_connection() -> WasmSqliteConnection { +pub async fn establish_connection() -> WasmSqliteConnection { diesel_wasm_sqlite::init_sqlite().await; let rng: u16 = rand::random(); @@ -223,3 +224,43 @@ async fn can_insert_or_ignore() { ]; insert_or_ignore(&updates, &mut conn); } + +#[wasm_bindgen_test] +async fn serializing() { + use schema::test_table::dsl::*; + + init().await; + let mut conn = establish_connection().await; + let new_books = vec![BookForm { + title: "Game of Thrones".into(), + author: Some("George R.R".into()), + // published_year: NaiveDate::from_ymd_opt(2015, 5, 3).unwrap(), + }]; + let rows_changed = insert_books(&mut conn, new_books).unwrap(); + assert_eq!(rows_changed, 1); + + let serialized = conn.serialize(); + + let loaded_books = schema::books::dsl::books + .select(StoredBook::as_select()) + .load(&mut conn); + assert_eq!(loaded_books.unwrap().len(), 1); + + // delete all the books + diesel::delete(schema::books::table) + .execute(&mut conn) + .unwrap(); + + let loaded_books = schema::books::dsl::books + .select(StoredBook::as_select()) + .load(&mut conn); + assert_eq!(loaded_books.unwrap().len(), 0); + + let result = conn.deserialize(&serialized.data); + assert_eq!(result, 0); + + let loaded_books = schema::books::dsl::books + .select(StoredBook::as_select()) + .load(&mut conn); + assert_eq!(loaded_books.unwrap().len(), 1); +} From 6fa253a49a7904c8773a80cd0afd90a0d15f8f7d Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Fri, 13 Sep 2024 17:54:19 -0400 Subject: [PATCH 31/97] prettier --- .../src/js/sqlite3-opfs-async-proxy.js | 200 +- .../src/js/wa-sqlite-diesel-bundle.js | 6523 ++++++++--------- 2 files changed, 3205 insertions(+), 3518 deletions(-) diff --git a/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js b/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js index 07d4ac1f8..6fe506ea1 100644 --- a/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js +++ b/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js @@ -52,15 +52,15 @@ const wPost = (type, ...args) => postMessage({ type, payload: args }); const installAsyncProxy = function () { const toss = function (...args) { - throw new Error(args.join(' ')); + throw new Error(args.join(" ")); }; if (globalThis.window === globalThis) { toss( - 'This code cannot run from the main thread.', - 'Load it as a Worker from a separate Worker.', + "This code cannot run from the main thread.", + "Load it as a Worker from a separate Worker." ); } else if (!navigator?.storage?.getDirectory) { - toss('This API requires navigator.storage.getDirectory.'); + toss("This API requires navigator.storage.getDirectory."); } const state = Object.create(null); @@ -73,7 +73,7 @@ const installAsyncProxy = function () { 2: console.log.bind(console), }; const logImpl = (level, ...args) => { - if (state.verbose > level) loggers[level]('OPFS asyncer:', ...args); + if (state.verbose > level) loggers[level]("OPFS asyncer:", ...args); }; const log = (...args) => logImpl(2, ...args); const warn = (...args) => logImpl(1, ...args); @@ -84,8 +84,8 @@ const installAsyncProxy = function () { const __implicitLocks = new Set(); const getResolvedPath = function (filename, splitIt) { - const p = new URL(filename, 'file://irrelevant').pathname; - return splitIt ? p.split('/').filter((v) => !!v) : p; + const p = new URL(filename, "file://irrelevant").pathname; + return splitIt ? p.split("/").filter((v) => !!v) : p; }; const getDirForFilename = async function f(absFilename, createDirs = false) { @@ -102,7 +102,7 @@ const installAsyncProxy = function () { const closeSyncHandle = async (fh) => { if (fh.syncHandle) { - log('Closing sync handle for', fh.filenameAbs); + log("Closing sync handle for", fh.filenameAbs); const h = fh.syncHandle; delete fh.syncHandle; delete fh.xLock; @@ -115,7 +115,7 @@ const installAsyncProxy = function () { try { await closeSyncHandle(fh); } catch (e) { - warn('closeSyncHandleNoThrow() ignoring:', e, fh); + warn("closeSyncHandleNoThrow() ignoring:", e, fh); } }; @@ -124,7 +124,7 @@ const installAsyncProxy = function () { for (const fid of __implicitLocks) { const fh = __openFiles[fid]; await closeSyncHandleNoThrow(fh); - log('Auto-unlocked', fid, fh.filenameAbs); + log("Auto-unlocked", fid, fh.filenameAbs); } } }; @@ -138,27 +138,27 @@ const installAsyncProxy = function () { class GetSyncHandleError extends Error { constructor(errorObject, ...msg) { super( - [...msg, ': ' + errorObject.name + ':', errorObject.message].join(' '), + [...msg, ": " + errorObject.name + ":", errorObject.message].join(" "), { cause: errorObject, - }, + } ); - this.name = 'GetSyncHandleError'; + this.name = "GetSyncHandleError"; } } GetSyncHandleError.convertRc = (e, rc) => { if (e instanceof GetSyncHandleError) { if ( - e.cause.name === 'NoModificationAllowedError' || - (e.cause.name === 'DOMException' && - 0 === e.cause.message.indexOf('Access Handles cannot')) + e.cause.name === "NoModificationAllowedError" || + (e.cause.name === "DOMException" && + 0 === e.cause.message.indexOf("Access Handles cannot")) ) { return state.sq3Codes.SQLITE_BUSY; - } else if ('NotFoundError' === e.cause.name) { + } else if ("NotFoundError" === e.cause.name) { return state.sq3Codes.SQLITE_CANTOPEN; } - } else if ('NotFoundError' === e?.name) { + } else if ("NotFoundError" === e?.name) { return state.sq3Codes.SQLITE_CANTOPEN; } return rc; @@ -167,7 +167,7 @@ const installAsyncProxy = function () { const getSyncHandle = async (fh, opName) => { if (!fh.syncHandle) { const t = performance.now(); - log('Acquiring sync handle for', fh.filenameAbs); + log("Acquiring sync handle for", fh.filenameAbs); const maxTries = 6, msBase = state.asyncIdleWaitTime * 2; let i = 1, @@ -180,39 +180,39 @@ const installAsyncProxy = function () { if (i === maxTries) { throw new GetSyncHandleError( e, - 'Error getting sync handle for', - opName + '().', + "Error getting sync handle for", + opName + "().", maxTries, - 'attempts failed.', - fh.filenameAbs, + "attempts failed.", + fh.filenameAbs ); } warn( - 'Error getting sync handle for', - opName + '(). Waiting', + "Error getting sync handle for", + opName + "(). Waiting", ms, - 'ms and trying again.', + "ms and trying again.", fh.filenameAbs, - e, + e ); Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms); } } log( - 'Got', - opName + '() sync handle for', + "Got", + opName + "() sync handle for", fh.filenameAbs, - 'in', + "in", performance.now() - t, - 'ms', + "ms" ); if (!fh.xLock) { __implicitLocks.add(fh.fid); log( - 'Acquired implicit lock for', - opName + '()', + "Acquired implicit lock for", + opName + "()", fh.fid, - fh.filenameAbs, + fh.filenameAbs ); } } @@ -220,31 +220,31 @@ const installAsyncProxy = function () { }; const storeAndNotify = (opName, value) => { - log(opName + '() => notify(', value, ')'); + log(opName + "() => notify(", value, ")"); Atomics.store(state.sabOPView, state.opIds.rc, value); Atomics.notify(state.sabOPView, state.opIds.rc); }; const affirmNotRO = function (opName, fh) { - if (fh.readOnly) toss(opName + '(): File is read-only: ' + fh.filenameAbs); + if (fh.readOnly) toss(opName + "(): File is read-only: " + fh.filenameAbs); }; let flagAsyncShutdown = false; const vfsAsyncImpls = { - 'opfs-async-shutdown': async () => { + "opfs-async-shutdown": async () => { flagAsyncShutdown = true; - storeAndNotify('opfs-async-shutdown', 0); + storeAndNotify("opfs-async-shutdown", 0); }, mkdir: async (dirname) => { let rc = 0; try { - await getDirForFilename(dirname + '/filepart', true); + await getDirForFilename(dirname + "/filepart", true); } catch (e) { state.s11n.storeException(2, e); rc = state.sq3Codes.SQLITE_IOERR; } - storeAndNotify('mkdir', rc); + storeAndNotify("mkdir", rc); }, xAccess: async (filename) => { let rc = 0; @@ -255,10 +255,10 @@ const installAsyncProxy = function () { state.s11n.storeException(2, e); rc = state.sq3Codes.SQLITE_IOERR; } - storeAndNotify('xAccess', rc); + storeAndNotify("xAccess", rc); }, xClose: async function (fid) { - const opName = 'xClose'; + const opName = "xClose"; __implicitLocks.delete(fid); const fh = __openFiles[fid]; let rc = 0; @@ -269,7 +269,7 @@ const installAsyncProxy = function () { try { await fh.dirHandle.removeEntry(fh.filenamePart); } catch (e) { - warn('Ignoring dirHandle.removeEntry() failure of', fh, e); + warn("Ignoring dirHandle.removeEntry() failure of", fh, e); } } } else { @@ -280,7 +280,7 @@ const installAsyncProxy = function () { }, xDelete: async function (...args) { const rc = await vfsAsyncImpls.xDeleteNoWait(...args); - storeAndNotify('xDelete', rc); + storeAndNotify("xDelete", rc); }, xDeleteNoWait: async function (filename, syncDir = 0, recursive = false) { let rc = 0; @@ -293,7 +293,7 @@ const installAsyncProxy = function () { recursive = false; filename = getResolvedPath(filename, true); filename.pop(); - filename = filename.join('/'); + filename = filename.join("/"); } } catch (e) { state.s11n.storeException(2, e); @@ -305,14 +305,14 @@ const installAsyncProxy = function () { const fh = __openFiles[fid]; let rc = 0; try { - const sz = await (await getSyncHandle(fh, 'xFileSize')).getSize(); + const sz = await (await getSyncHandle(fh, "xFileSize")).getSize(); state.s11n.serialize(Number(sz)); } catch (e) { state.s11n.storeException(1, e); rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR); } await releaseImplicitLock(fh); - storeAndNotify('xFileSize', rc); + storeAndNotify("xFileSize", rc); }, xLock: async function (fid, lockType) { const fh = __openFiles[fid]; @@ -321,21 +321,21 @@ const installAsyncProxy = function () { fh.xLock = lockType; if (!fh.syncHandle) { try { - await getSyncHandle(fh, 'xLock'); + await getSyncHandle(fh, "xLock"); __implicitLocks.delete(fid); } catch (e) { state.s11n.storeException(1, e); rc = GetSyncHandleError.convertRc( e, - state.sq3Codes.SQLITE_IOERR_LOCK, + state.sq3Codes.SQLITE_IOERR_LOCK ); fh.xLock = oldLockType; } } - storeAndNotify('xLock', rc); + storeAndNotify("xLock", rc); }, xOpen: async function (fid, filename, flags, opfsFlags) { - const opName = 'xOpen'; + const opName = "xOpen"; const create = state.sq3Codes.SQLITE_OPEN_CREATE & flags; try { let hDir, filenamePart; @@ -380,21 +380,21 @@ const installAsyncProxy = function () { nRead; const fh = __openFiles[fid]; try { - nRead = (await getSyncHandle(fh, 'xRead')).read( + nRead = (await getSyncHandle(fh, "xRead")).read( fh.sabView.subarray(0, n), - { at: Number(offset64) }, + { at: Number(offset64) } ); if (nRead < n) { fh.sabView.fill(0, nRead, n); rc = state.sq3Codes.SQLITE_IOERR_SHORT_READ; } } catch (e) { - error('xRead() failed', e, fh); + error("xRead() failed", e, fh); state.s11n.storeException(1, e); rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_READ); } await releaseImplicitLock(fh); - storeAndNotify('xRead', rc); + storeAndNotify("xRead", rc); }, xSync: async function (fid, flags) { const fh = __openFiles[fid]; @@ -407,24 +407,24 @@ const installAsyncProxy = function () { rc = state.sq3Codes.SQLITE_IOERR_FSYNC; } } - storeAndNotify('xSync', rc); + storeAndNotify("xSync", rc); }, xTruncate: async function (fid, size) { let rc = 0; const fh = __openFiles[fid]; try { - affirmNotRO('xTruncate', fh); - await (await getSyncHandle(fh, 'xTruncate')).truncate(size); + affirmNotRO("xTruncate", fh); + await (await getSyncHandle(fh, "xTruncate")).truncate(size); } catch (e) { - error('xTruncate():', e, fh); + error("xTruncate():", e, fh); state.s11n.storeException(2, e); rc = GetSyncHandleError.convertRc( e, - state.sq3Codes.SQLITE_IOERR_TRUNCATE, + state.sq3Codes.SQLITE_IOERR_TRUNCATE ); } await releaseImplicitLock(fh); - storeAndNotify('xTruncate', rc); + storeAndNotify("xTruncate", rc); }, xUnlock: async function (fid, lockType) { let rc = 0; @@ -437,68 +437,68 @@ const installAsyncProxy = function () { rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; } } - storeAndNotify('xUnlock', rc); + storeAndNotify("xUnlock", rc); }, xWrite: async function (fid, n, offset64) { let rc; const fh = __openFiles[fid]; try { - affirmNotRO('xWrite', fh); + affirmNotRO("xWrite", fh); rc = n === - (await getSyncHandle(fh, 'xWrite')).write(fh.sabView.subarray(0, n), { + (await getSyncHandle(fh, "xWrite")).write(fh.sabView.subarray(0, n), { at: Number(offset64), }) ? 0 : state.sq3Codes.SQLITE_IOERR_WRITE; } catch (e) { - error('xWrite():', e, fh); + error("xWrite():", e, fh); state.s11n.storeException(1, e); rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_WRITE); } await releaseImplicitLock(fh); - storeAndNotify('xWrite', rc); + storeAndNotify("xWrite", rc); }, }; const initS11n = () => { if (state.s11n) return state.s11n; const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder('utf-8'), + textEncoder = new TextEncoder("utf-8"), viewU8 = new Uint8Array( state.sabIO, state.sabS11nOffset, - state.sabS11nSize, + state.sabS11nSize ), viewDV = new DataView( state.sabIO, state.sabS11nOffset, - state.sabS11nSize, + state.sabS11nSize ); state.s11n = Object.create(null); const TypeIds = Object.create(null); TypeIds.number = { id: 1, size: 8, - getter: 'getFloat64', - setter: 'setFloat64', + getter: "getFloat64", + setter: "setFloat64", }; TypeIds.bigint = { id: 2, size: 8, - getter: 'getBigInt64', - setter: 'setBigInt64', + getter: "getBigInt64", + setter: "setBigInt64", }; TypeIds.boolean = { id: 3, size: 4, - getter: 'getInt32', - setter: 'setInt32', + getter: "getInt32", + setter: "setInt32", }; TypeIds.string = { id: 4 }; const getTypeId = (v) => TypeIds[typeof v] || - toss('Maintenance required: this value type cannot be serialized.', v); + toss("Maintenance required: this value type cannot be serialized.", v); const getTypeIdById = (tid) => { switch (tid) { case TypeIds.number.id: @@ -510,7 +510,7 @@ const installAsyncProxy = function () { case TypeIds.string.id: return TypeIds.string; default: - toss('Invalid type ID:', tid); + toss("Invalid type ID:", tid); } }; state.s11n.deserialize = function (clear = false) { @@ -574,7 +574,7 @@ const installAsyncProxy = function () { state.s11n.storeException = state.asyncS11nExceptions ? (priority, e) => { if (priority <= state.asyncS11nExceptions) { - state.s11n.serialize([e.name, ': ', e.message].join('')); + state.s11n.serialize([e.name, ": ", e.message].join("")); } } : () => {}; @@ -595,12 +595,12 @@ const installAsyncProxy = function () { while (!flagAsyncShutdown) { try { if ( - 'not-equal' !== + "not-equal" !== Atomics.wait( state.sabOPView, state.opIds.whichOp, 0, - state.asyncIdleWaitTime, + state.asyncIdleWaitTime ) ) { await releaseImplicitLocks(); @@ -609,13 +609,13 @@ const installAsyncProxy = function () { const opId = Atomics.load(state.sabOPView, state.opIds.whichOp); Atomics.store(state.sabOPView, state.opIds.whichOp, 0); const hnd = - opHandlers[opId] ?? toss('No waitLoop handler for whichOp #', opId); + opHandlers[opId] ?? toss("No waitLoop handler for whichOp #", opId); const args = state.s11n.deserialize(true) || []; if (hnd.f) await hnd.f(...args); - else error('Missing callback for opId', opId); + else error("Missing callback for opId", opId); } catch (e) { - error('in waitLoop():', e); + error("in waitLoop():", e); } } }; @@ -626,7 +626,7 @@ const installAsyncProxy = function () { state.rootDir = d; globalThis.onmessage = function ({ data }) { switch (data.type) { - case 'opfs-async-init': { + case "opfs-async-init": { const opt = data.args; for (const k in opt) state[k] = opt[k]; state.verbose = opt.verbose ?? 1; @@ -634,28 +634,28 @@ const installAsyncProxy = function () { state.sabFileBufView = new Uint8Array( state.sabIO, 0, - state.fileBufferSize, + state.fileBufferSize ); state.sabS11nView = new Uint8Array( state.sabIO, state.sabS11nOffset, - state.sabS11nSize, + state.sabS11nSize ); Object.keys(vfsAsyncImpls).forEach((k) => { if (!Number.isFinite(state.opIds[k])) { - toss('Maintenance required: missing state.opIds[', k, ']'); + toss("Maintenance required: missing state.opIds[", k, "]"); } }); initS11n(); - log('init state', state); - wPost('opfs-async-inited'); + log("init state", state); + wPost("opfs-async-inited"); waitLoop(); break; } - case 'opfs-async-restart': + case "opfs-async-restart": if (flagAsyncShutdown) { warn( - 'Restarting after opfs-async-shutdown. Might or might not work.', + "Restarting after opfs-async-shutdown. Might or might not work." ); flagAsyncShutdown = false; waitLoop(); @@ -663,21 +663,21 @@ const installAsyncProxy = function () { break; } }; - wPost('opfs-async-loaded'); + wPost("opfs-async-loaded"); }) - .catch((e) => error('error initializing OPFS asyncer:', e)); + .catch((e) => error("error initializing OPFS asyncer:", e)); }; if (!globalThis.SharedArrayBuffer) { wPost( - 'opfs-unavailable', - 'Missing SharedArrayBuffer API.', - 'The server must emit the COOP/COEP response headers to enable that.', + "opfs-unavailable", + "Missing SharedArrayBuffer API.", + "The server must emit the COOP/COEP response headers to enable that." ); } else if (!globalThis.Atomics) { wPost( - 'opfs-unavailable', - 'Missing Atomics API.', - 'The server must emit the COOP/COEP response headers to enable that.', + "opfs-unavailable", + "Missing Atomics API.", + "The server must emit the COOP/COEP response headers to enable that." ); } else if ( !globalThis.FileSystemHandle || @@ -686,7 +686,7 @@ if (!globalThis.SharedArrayBuffer) { !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || !navigator?.storage?.getDirectory ) { - wPost('opfs-unavailable', 'Missing required OPFS APIs.'); + wPost("opfs-unavailable", "Missing required OPFS APIs."); } else { installAsyncProxy(); } diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js index 7b1a30884..824fef44e 100644 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js @@ -40,10 +40,10 @@ var sqlite3InitModule = (() => { var sqlite3InitModule = config || {}; var Module = - typeof sqlite3InitModule != 'undefined' ? sqlite3InitModule : {}; + typeof sqlite3InitModule != "undefined" ? sqlite3InitModule : {}; var readyPromiseResolve, readyPromiseReject; - Module['ready'] = new Promise(function (resolve, reject) { + Module["ready"] = new Promise(function (resolve, reject) { readyPromiseResolve = resolve; readyPromiseReject = reject; }); @@ -55,23 +55,23 @@ var sqlite3InitModule = (() => { }); delete globalThis.sqlite3InitModuleState; sqlite3InitModuleState.debugModule( - 'globalThis.location =', - globalThis.location, + "globalThis.location =", + globalThis.location ); - const xNameOfInstantiateWasm = 'emscripten-bug-17951'; + const xNameOfInstantiateWasm = "emscripten-bug-17951"; Module[xNameOfInstantiateWasm] = function callee(imports, onSuccess) { imports.env.foo = function () {}; const uri = Module.locateFile( callee.uri, - 'undefined' === typeof scriptDirectory ? '' : scriptDirectory, + "undefined" === typeof scriptDirectory ? "" : scriptDirectory ); - sqlite3InitModuleState.debugModule('instantiateWasm() uri =', uri); - const wfetch = () => fetch(uri, { credentials: 'same-origin' }); + sqlite3InitModuleState.debugModule("instantiateWasm() uri =", uri); + const wfetch = () => fetch(uri, { credentials: "same-origin" }); const loadWasm = WebAssembly.instantiateStreaming ? async () => { return WebAssembly.instantiateStreaming(wfetch(), imports).then( - (arg) => onSuccess(arg.instance, arg.module), + (arg) => onSuccess(arg.instance, arg.module) ); } : async () => { @@ -84,22 +84,22 @@ var sqlite3InitModule = (() => { return {}; }; - Module[xNameOfInstantiateWasm].uri = 'sqlite3.wasm'; + Module[xNameOfInstantiateWasm].uri = "sqlite3.wasm"; var moduleOverrides = Object.assign({}, Module); - var thisProgram = './this.program'; + var thisProgram = "./this.program"; - var ENVIRONMENT_IS_WEB = typeof window == 'object'; - var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'; + var ENVIRONMENT_IS_WEB = typeof window == "object"; + var ENVIRONMENT_IS_WORKER = typeof importScripts == "function"; - typeof process == 'object' && - typeof process.versions == 'object' && - typeof process.versions.node == 'string'; + typeof process == "object" && + typeof process.versions == "object" && + typeof process.versions.node == "string"; - var scriptDirectory = ''; + var scriptDirectory = ""; function locateFile(path) { - if (Module['locateFile']) { - return Module['locateFile'](path, scriptDirectory); + if (Module["locateFile"]) { + return Module["locateFile"](path, scriptDirectory); } return scriptDirectory + path; } @@ -109,7 +109,7 @@ var sqlite3InitModule = (() => { if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { if (ENVIRONMENT_IS_WORKER) { scriptDirectory = self.location.href; - } else if (typeof document != 'undefined' && document.currentScript) { + } else if (typeof document != "undefined" && document.currentScript) { scriptDirectory = document.currentScript.src; } @@ -117,19 +117,19 @@ var sqlite3InitModule = (() => { scriptDirectory = _scriptDir; } - if (scriptDirectory.indexOf('blob:') !== 0) { + if (scriptDirectory.indexOf("blob:") !== 0) { scriptDirectory = scriptDirectory.substr( 0, - scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1, + scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1 ); } else { - scriptDirectory = ''; + scriptDirectory = ""; } { read_ = (url) => { var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); + xhr.open("GET", url, false); xhr.send(null); return xhr.responseText; }; @@ -137,8 +137,8 @@ var sqlite3InitModule = (() => { if (ENVIRONMENT_IS_WORKER) { readBinary = (url) => { var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - xhr.responseType = 'arraybuffer'; + xhr.open("GET", url, false); + xhr.responseType = "arraybuffer"; xhr.send(null); return new Uint8Array(xhr.response); }; @@ -146,8 +146,8 @@ var sqlite3InitModule = (() => { readAsync = (url, onload, onerror) => { var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.responseType = 'arraybuffer'; + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; xhr.onload = () => { if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { onload(xhr.response); @@ -161,25 +161,25 @@ var sqlite3InitModule = (() => { } } - var out = Module['print'] || console.log.bind(console); - var err = Module['printErr'] || console.warn.bind(console); + var out = Module["print"] || console.log.bind(console); + var err = Module["printErr"] || console.warn.bind(console); Object.assign(Module, moduleOverrides); moduleOverrides = null; - if (Module['arguments']) Module['arguments']; + if (Module["arguments"]) Module["arguments"]; - if (Module['thisProgram']) thisProgram = Module['thisProgram']; + if (Module["thisProgram"]) thisProgram = Module["thisProgram"]; - if (Module['quit']) Module['quit']; + if (Module["quit"]) Module["quit"]; var wasmBinary; - if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; - Module['noExitRuntime'] || true; + if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"]; + Module["noExitRuntime"] || true; - if (typeof WebAssembly != 'object') { - abort('no native wasm support detected'); + if (typeof WebAssembly != "object") { + abort("no native wasm support detected"); } var wasmMemory; @@ -193,7 +193,7 @@ var sqlite3InitModule = (() => { } var UTF8Decoder = - typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; + typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : undefined; function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) { var endIdx = idx + maxBytesToRead; @@ -204,7 +204,7 @@ var sqlite3InitModule = (() => { if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); } - var str = ''; + var str = ""; while (idx < endPtr) { var u0 = heapOrArray[idx++]; @@ -234,7 +234,7 @@ var sqlite3InitModule = (() => { var ch = u0 - 0x10000; str += String.fromCharCode( 0xd800 | (ch >> 10), - 0xdc00 | (ch & 0x3ff), + 0xdc00 | (ch & 0x3ff) ); } } @@ -242,7 +242,7 @@ var sqlite3InitModule = (() => { } function UTF8ToString(ptr, maxBytesToRead) { - return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ""; } function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { @@ -303,30 +303,26 @@ var sqlite3InitModule = (() => { return len; } - var HEAP8, - HEAPU8, - HEAP16, - HEAP32, - HEAPU32; + var HEAP8, HEAPU8, HEAP16, HEAP32, HEAPU32; function updateMemoryViews() { var b = wasmMemory.buffer; - Module['HEAP8'] = HEAP8 = new Int8Array(b); - Module['HEAP16'] = HEAP16 = new Int16Array(b); - Module['HEAP32'] = HEAP32 = new Int32Array(b); - Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); - Module['HEAPU16'] = new Uint16Array(b); - Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); - Module['HEAPF32'] = new Float32Array(b); - Module['HEAPF64'] = new Float64Array(b); - Module['HEAP64'] = new BigInt64Array(b); - Module['HEAPU64'] = new BigUint64Array(b); + Module["HEAP8"] = HEAP8 = new Int8Array(b); + Module["HEAP16"] = HEAP16 = new Int16Array(b); + Module["HEAP32"] = HEAP32 = new Int32Array(b); + Module["HEAPU8"] = HEAPU8 = new Uint8Array(b); + Module["HEAPU16"] = new Uint16Array(b); + Module["HEAPU32"] = HEAPU32 = new Uint32Array(b); + Module["HEAPF32"] = new Float32Array(b); + Module["HEAPF64"] = new Float64Array(b); + Module["HEAP64"] = new BigInt64Array(b); + Module["HEAPU64"] = new BigUint64Array(b); } - var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216; + var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 16777216; - if (Module['wasmMemory']) { - wasmMemory = Module['wasmMemory']; + if (Module["wasmMemory"]) { + wasmMemory = Module["wasmMemory"]; } else { wasmMemory = new WebAssembly.Memory({ initial: INITIAL_MEMORY / 65536, @@ -344,11 +340,11 @@ var sqlite3InitModule = (() => { var __ATPOSTRUN__ = []; function preRun() { - if (Module['preRun']) { - if (typeof Module['preRun'] == 'function') - Module['preRun'] = [Module['preRun']]; - while (Module['preRun'].length) { - addOnPreRun(Module['preRun'].shift()); + if (Module["preRun"]) { + if (typeof Module["preRun"] == "function") + Module["preRun"] = [Module["preRun"]]; + while (Module["preRun"].length) { + addOnPreRun(Module["preRun"].shift()); } } @@ -356,18 +352,17 @@ var sqlite3InitModule = (() => { } function initRuntime() { - - if (!Module['noFSInit'] && !FS.init.initialized) FS.init(); + if (!Module["noFSInit"] && !FS.init.initialized) FS.init(); FS.ignorePermissions = false; callRuntimeCallbacks(__ATINIT__); } function postRun() { - if (Module['postRun']) { - if (typeof Module['postRun'] == 'function') - Module['postRun'] = [Module['postRun']]; - while (Module['postRun'].length) { - addOnPostRun(Module['postRun'].shift()); + if (Module["postRun"]) { + if (typeof Module["postRun"] == "function") + Module["postRun"] = [Module["postRun"]]; + while (Module["postRun"].length) { + addOnPostRun(Module["postRun"].shift()); } } @@ -396,16 +391,16 @@ var sqlite3InitModule = (() => { function addRunDependency(id) { runDependencies++; - if (Module['monitorRunDependencies']) { - Module['monitorRunDependencies'](runDependencies); + if (Module["monitorRunDependencies"]) { + Module["monitorRunDependencies"](runDependencies); } } function removeRunDependency(id) { runDependencies--; - if (Module['monitorRunDependencies']) { - Module['monitorRunDependencies'](runDependencies); + if (Module["monitorRunDependencies"]) { + Module["monitorRunDependencies"](runDependencies); } if (runDependencies == 0) { @@ -418,17 +413,17 @@ var sqlite3InitModule = (() => { } function abort(what) { - if (Module['onAbort']) { - Module['onAbort'](what); + if (Module["onAbort"]) { + Module["onAbort"](what); } - what = 'Aborted(' + what + ')'; + what = "Aborted(" + what + ")"; err(what); ABORT = true; - what += '. Build with -sASSERTIONS for more info.'; + what += ". Build with -sASSERTIONS for more info."; var e = new WebAssembly.RuntimeError(what); @@ -437,20 +432,20 @@ var sqlite3InitModule = (() => { throw e; } - var dataURIPrefix = 'data:application/octet-stream;base64,'; + var dataURIPrefix = "data:application/octet-stream;base64,"; function isDataURI(filename) { return filename.startsWith(dataURIPrefix); } var wasmBinaryFile; - if (Module['locateFile']) { - wasmBinaryFile = 'sqlite3.wasm'; + if (Module["locateFile"]) { + wasmBinaryFile = "sqlite3.wasm"; if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(wasmBinaryFile); } } else { - wasmBinaryFile = new URL('sqlite3.wasm', import.meta.url).href; + wasmBinaryFile = new URL("sqlite3.wasm", import.meta.url).href; } function getBinary(file) { @@ -461,7 +456,7 @@ var sqlite3InitModule = (() => { if (readBinary) { return readBinary(file); } - throw 'both async and sync fetching of the wasm failed'; + throw "both async and sync fetching of the wasm failed"; } catch (err) { abort(err); } @@ -469,15 +464,15 @@ var sqlite3InitModule = (() => { function getBinaryPromise() { if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { - if (typeof fetch == 'function') { - return fetch(wasmBinaryFile, { credentials: 'same-origin' }) + if (typeof fetch == "function") { + return fetch(wasmBinaryFile, { credentials: "same-origin" }) .then(function (response) { - if (!response['ok']) { + if (!response["ok"]) { throw ( "failed to load wasm binary file at '" + wasmBinaryFile + "'" ); } - return response['arrayBuffer'](); + return response["arrayBuffer"](); }) .catch(function () { return getBinary(wasmBinaryFile); @@ -499,11 +494,11 @@ var sqlite3InitModule = (() => { function receiveInstance(instance, module) { var exports = instance.exports; - Module['asm'] = exports; + Module["asm"] = exports; - Module['asm']['__indirect_function_table']; + Module["asm"]["__indirect_function_table"]; - addOnInit(Module['asm']['__wasm_call_ctors']); + addOnInit(Module["asm"]["__wasm_call_ctors"]); removeRunDependency(); } @@ -511,7 +506,7 @@ var sqlite3InitModule = (() => { addRunDependency(); function receiveInstantiationResult(result) { - receiveInstance(result['instance']); + receiveInstance(result["instance"]); } function instantiateArrayBuffer(receiver) { @@ -523,7 +518,7 @@ var sqlite3InitModule = (() => { return instance; }) .then(receiver, function (reason) { - err('failed to asynchronously prepare wasm: ' + reason); + err("failed to asynchronously prepare wasm: " + reason); abort(reason); }); @@ -532,32 +527,32 @@ var sqlite3InitModule = (() => { function instantiateAsync() { if ( !wasmBinary && - typeof WebAssembly.instantiateStreaming == 'function' && + typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(wasmBinaryFile) && - typeof fetch == 'function' + typeof fetch == "function" ) { - return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then( + return fetch(wasmBinaryFile, { credentials: "same-origin" }).then( function (response) { var result = WebAssembly.instantiateStreaming(response, info); return result.then(receiveInstantiationResult, function (reason) { - err('wasm streaming compile failed: ' + reason); - err('falling back to ArrayBuffer instantiation'); + err("wasm streaming compile failed: " + reason); + err("falling back to ArrayBuffer instantiation"); return instantiateArrayBuffer(receiveInstantiationResult); }); - }, + } ); } else { return instantiateArrayBuffer(receiveInstantiationResult); } } - if (Module['instantiateWasm']) { + if (Module["instantiateWasm"]) { try { - var exports = Module['instantiateWasm'](info, receiveInstance); + var exports = Module["instantiateWasm"](info, receiveInstance); return exports; } catch (e) { - err('Module.instantiateWasm callback failed with error: ' + e); + err("Module.instantiateWasm callback failed with error: " + e); readyPromiseReject(e); } @@ -577,7 +572,7 @@ var sqlite3InitModule = (() => { } var PATH = { - isAbs: (path) => path.charAt(0) === '/', + isAbs: (path) => path.charAt(0) === "/", splitPath: (filename) => { var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; @@ -587,9 +582,9 @@ var sqlite3InitModule = (() => { var up = 0; for (var i = parts.length - 1; i >= 0; i--) { var last = parts[i]; - if (last === '.') { + if (last === ".") { parts.splice(i, 1); - } else if (last === '..') { + } else if (last === "..") { parts.splice(i, 1); up++; } else if (up) { @@ -600,33 +595,33 @@ var sqlite3InitModule = (() => { if (allowAboveRoot) { for (; up; up--) { - parts.unshift('..'); + parts.unshift(".."); } } return parts; }, normalize: (path) => { var isAbsolute = PATH.isAbs(path), - trailingSlash = path.substr(-1) === '/'; + trailingSlash = path.substr(-1) === "/"; path = PATH.normalizeArray( - path.split('/').filter((p) => !!p), - !isAbsolute, - ).join('/'); + path.split("/").filter((p) => !!p), + !isAbsolute + ).join("/"); if (!path && !isAbsolute) { - path = '.'; + path = "."; } if (path && trailingSlash) { - path += '/'; + path += "/"; } - return (isAbsolute ? '/' : '') + path; + return (isAbsolute ? "/" : "") + path; }, dirname: (path) => { var result = PATH.splitPath(path), root = result[0], dir = result[1]; if (!root && !dir) { - return '.'; + return "."; } if (dir) { dir = dir.substr(0, dir.length - 1); @@ -634,56 +629,56 @@ var sqlite3InitModule = (() => { return root + dir; }, basename: (path) => { - if (path === '/') return '/'; + if (path === "/") return "/"; path = PATH.normalize(path); - path = path.replace(/\/$/, ''); - var lastSlash = path.lastIndexOf('/'); + path = path.replace(/\/$/, ""); + var lastSlash = path.lastIndexOf("/"); if (lastSlash === -1) return path; return path.substr(lastSlash + 1); }, join: function () { var paths = Array.prototype.slice.call(arguments); - return PATH.normalize(paths.join('/')); + return PATH.normalize(paths.join("/")); }, join2: (l, r) => { - return PATH.normalize(l + '/' + r); + return PATH.normalize(l + "/" + r); }, }; function getRandomDevice() { if ( - typeof crypto == 'object' && - typeof crypto['getRandomValues'] == 'function' + typeof crypto == "object" && + typeof crypto["getRandomValues"] == "function" ) { var randomBuffer = new Uint8Array(1); return () => { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; }; - } else return () => abort('randomDevice'); + } else return () => abort("randomDevice"); } var PATH_FS = { resolve: function () { - var resolvedPath = '', + var resolvedPath = "", resolvedAbsolute = false; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { var path = i >= 0 ? arguments[i] : FS.cwd(); - if (typeof path != 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); + if (typeof path != "string") { + throw new TypeError("Arguments to path.resolve must be strings"); } else if (!path) { - return ''; + return ""; } - resolvedPath = path + '/' + resolvedPath; + resolvedPath = path + "/" + resolvedPath; resolvedAbsolute = PATH.isAbs(path); } resolvedPath = PATH.normalizeArray( - resolvedPath.split('/').filter((p) => !!p), - !resolvedAbsolute, - ).join('/'); - return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'; + resolvedPath.split("/").filter((p) => !!p), + !resolvedAbsolute + ).join("/"); + return (resolvedAbsolute ? "/" : "") + resolvedPath || "."; }, relative: (from, to) => { from = PATH_FS.resolve(from).substr(1); @@ -691,17 +686,17 @@ var sqlite3InitModule = (() => { function trim(arr) { var start = 0; for (; start < arr.length; start++) { - if (arr[start] !== '') break; + if (arr[start] !== "") break; } var end = arr.length - 1; for (; end >= 0; end--) { - if (arr[end] !== '') break; + if (arr[end] !== "") break; } if (start > end) return []; return arr.slice(start, end - start + 1); } - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); + var fromParts = trim(from.split("/")); + var toParts = trim(to.split("/")); var length = Math.min(fromParts.length, toParts.length); var samePartsLength = length; for (var i = 0; i < length; i++) { @@ -712,10 +707,10 @@ var sqlite3InitModule = (() => { } var outputParts = []; for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); + outputParts.push(".."); } outputParts = outputParts.concat(toParts.slice(samePartsLength)); - return outputParts.join('/'); + return outputParts.join("/"); }, }; @@ -726,7 +721,7 @@ var sqlite3InitModule = (() => { stringy, u8array, 0, - u8array.length, + u8array.length ); u8array.length = numBytesWritten; return u8array; @@ -800,17 +795,17 @@ var sqlite3InitModule = (() => { if (!tty.input.length) { var result = null; if ( - typeof window != 'undefined' && - typeof window.prompt == 'function' + typeof window != "undefined" && + typeof window.prompt == "function" ) { - result = window.prompt('Input: '); + result = window.prompt("Input: "); if (result !== null) { - result += '\n'; + result += "\n"; } - } else if (typeof readline == 'function') { + } else if (typeof readline == "function") { result = readline(); if (result !== null) { - result += '\n'; + result += "\n"; } } if (!result) { @@ -870,7 +865,7 @@ var sqlite3InitModule = (() => { var MEMFS = { ops_table: null, mount: function (mount) { - return MEMFS.createNode(null, '/', 16384 | 511, 0); + return MEMFS.createNode(null, "/", 16384 | 511, 0); }, createNode: function (parent, name, mode, dev) { if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { @@ -966,7 +961,7 @@ var sqlite3InitModule = (() => { newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> - 0, + 0 ); if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); var oldContents = node.contents; @@ -984,7 +979,7 @@ var sqlite3InitModule = (() => { node.contents = new Uint8Array(newSize); if (oldContents) { node.contents.set( - oldContents.subarray(0, Math.min(newSize, node.usedBytes)), + oldContents.subarray(0, Math.min(newSize, node.usedBytes)) ); } node.usedBytes = newSize; @@ -1068,7 +1063,7 @@ var sqlite3InitModule = (() => { parent.timestamp = Date.now(); }, readdir: function (node) { - var entries = ['.', '..']; + var entries = [".", ".."]; for (var key in node.contents) { if (!node.contents.hasOwnProperty(key)) { continue; @@ -1123,7 +1118,7 @@ var sqlite3InitModule = (() => { } else if (position + length <= node.usedBytes) { node.contents.set( buffer.subarray(offset, offset + length), - position, + position ); return length; } @@ -1133,7 +1128,7 @@ var sqlite3InitModule = (() => { if (node.contents.subarray && buffer.subarray) { node.contents.set( buffer.subarray(offset, offset + length), - position, + position ); } else { for (var i = 0; i < length; i++) { @@ -1161,7 +1156,7 @@ var sqlite3InitModule = (() => { MEMFS.expandFileStorage(stream.node, offset + length); stream.node.usedBytes = Math.max( stream.node.usedBytes, - offset + length, + offset + length ); }, mmap: function (stream, length, position, prot, flags) { @@ -1183,7 +1178,7 @@ var sqlite3InitModule = (() => { contents = Array.prototype.slice.call( contents, position, - position + length, + position + length ); } } @@ -1205,13 +1200,13 @@ var sqlite3InitModule = (() => { }; function asyncLoad(url, onload, onerror, noRunDep) { - var dep = getUniqueRunDependency('al ' + url) ; + var dep = getUniqueRunDependency("al " + url); readAsync( url, (arrayBuffer) => { assert( arrayBuffer, - 'Loading data file "' + url + '" failed (no arrayBuffer).', + 'Loading data file "' + url + '" failed (no arrayBuffer).' ); onload(new Uint8Array(arrayBuffer)); if (dep) removeRunDependency(); @@ -1222,7 +1217,7 @@ var sqlite3InitModule = (() => { } else { throw 'Loading data file "' + url + '" failed.'; } - }, + } ); if (dep) addRunDependency(); } @@ -1234,7 +1229,7 @@ var sqlite3InitModule = (() => { streams: [], nextInode: 1, nameTable: null, - currentPath: '/', + currentPath: "/", initialized: false, ignorePermissions: true, ErrnoError: null, @@ -1244,7 +1239,7 @@ var sqlite3InitModule = (() => { lookupPath: (path, opts = {}) => { path = PATH_FS.resolve(path); - if (!path) return { path: '', node: null }; + if (!path) return { path: "", node: null }; var defaults = { follow_mount: true, @@ -1256,10 +1251,10 @@ var sqlite3InitModule = (() => { throw new FS.ErrnoError(32); } - var parts = path.split('/').filter((p) => !!p); + var parts = path.split("/").filter((p) => !!p); var current = FS.root; - var current_path = '/'; + var current_path = "/"; for (var i = 0; i < parts.length; i++) { var islast = i === parts.length - 1; @@ -1302,11 +1297,11 @@ var sqlite3InitModule = (() => { if (FS.isRoot(node)) { var mount = node.mount.mountpoint; if (!path) return mount; - return mount[mount.length - 1] !== '/' - ? mount + '/' + path + return mount[mount.length - 1] !== "/" + ? mount + "/" + path : mount + path; } - path = path ? node.name + '/' + path : node.name; + path = path ? node.name + "/" + path : node.name; node = node.parent; } }, @@ -1390,18 +1385,18 @@ var sqlite3InitModule = (() => { isSocket: (mode) => { return (mode & 49152) === 49152; }, - flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 }, + flagModes: { r: 0, "r+": 2, w: 577, "w+": 578, a: 1089, "a+": 1090 }, modeStringToFlags: (str) => { var flags = FS.flagModes[str]; - if (typeof flags == 'undefined') { - throw new Error('Unknown file open mode: ' + str); + if (typeof flags == "undefined") { + throw new Error("Unknown file open mode: " + str); } return flags; }, flagsToPermissionString: (flag) => { - var perms = ['r', 'w', 'rw'][flag & 3]; + var perms = ["r", "w", "rw"][flag & 3]; if (flag & 512) { - perms += 'w'; + perms += "w"; } return perms; }, @@ -1410,17 +1405,17 @@ var sqlite3InitModule = (() => { return 0; } - if (perms.includes('r') && !(node.mode & 292)) { + if (perms.includes("r") && !(node.mode & 292)) { return 2; - } else if (perms.includes('w') && !(node.mode & 146)) { + } else if (perms.includes("w") && !(node.mode & 146)) { return 2; - } else if (perms.includes('x') && !(node.mode & 73)) { + } else if (perms.includes("x") && !(node.mode & 73)) { return 2; } return 0; }, mayLookup: (dir) => { - var errCode = FS.nodePermissions(dir, 'x'); + var errCode = FS.nodePermissions(dir, "x"); if (errCode) return errCode; if (!dir.node_ops.lookup) return 2; return 0; @@ -1430,7 +1425,7 @@ var sqlite3InitModule = (() => { var node = FS.lookupNode(dir, name); return 20; } catch (e) {} - return FS.nodePermissions(dir, 'wx'); + return FS.nodePermissions(dir, "wx"); }, mayDelete: (dir, name, isdir) => { var node; @@ -1439,7 +1434,7 @@ var sqlite3InitModule = (() => { } catch (e) { return e.errno; } - var errCode = FS.nodePermissions(dir, 'wx'); + var errCode = FS.nodePermissions(dir, "wx"); if (errCode) { return errCode; } @@ -1464,7 +1459,7 @@ var sqlite3InitModule = (() => { if (FS.isLink(node.mode)) { return 32; } else if (FS.isDir(node.mode)) { - if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) { + if (FS.flagsToPermissionString(flags) !== "r" || flags & 512) { return 31; } } @@ -1577,7 +1572,7 @@ var sqlite3InitModule = (() => { return mounts; }, syncfs: (populate, callback) => { - if (typeof populate == 'function') { + if (typeof populate == "function") { callback = populate; populate = false; } @@ -1586,9 +1581,9 @@ var sqlite3InitModule = (() => { if (FS.syncFSRequests > 1) { err( - 'warning: ' + + "warning: " + FS.syncFSRequests + - ' FS.syncfs operations in flight at once, probably just doing extra work', + " FS.syncfs operations in flight at once, probably just doing extra work" ); } @@ -1621,7 +1616,7 @@ var sqlite3InitModule = (() => { }); }, mount: (type, opts, mountpoint) => { - var root = mountpoint === '/'; + var root = mountpoint === "/"; var pseudo = !mountpoint; var node; @@ -1702,7 +1697,7 @@ var sqlite3InitModule = (() => { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; var name = PATH.basename(path); - if (!name || name === '.' || name === '..') { + if (!name || name === "." || name === "..") { throw new FS.ErrnoError(28); } var errCode = FS.mayCreate(parent, name); @@ -1727,11 +1722,11 @@ var sqlite3InitModule = (() => { return FS.mknod(path, mode, 0); }, mkdirTree: (path, mode) => { - var dirs = path.split('/'); - var d = ''; + var dirs = path.split("/"); + var d = ""; for (var i = 0; i < dirs.length; ++i) { if (!dirs[i]) continue; - d += '/' + dirs[i]; + d += "/" + dirs[i]; try { FS.mkdir(d, mode); } catch (e) { @@ -1740,7 +1735,7 @@ var sqlite3InitModule = (() => { } }, mkdev: (path, mode, dev) => { - if (typeof dev == 'undefined') { + if (typeof dev == "undefined") { dev = mode; mode = 438; } @@ -1788,12 +1783,12 @@ var sqlite3InitModule = (() => { var old_node = FS.lookupNode(old_dir, old_name); var relative = PATH_FS.relative(old_path, new_dirname); - if (relative.charAt(0) !== '.') { + if (relative.charAt(0) !== ".") { throw new FS.ErrnoError(28); } relative = PATH_FS.relative(new_path, old_dirname); - if (relative.charAt(0) !== '.') { + if (relative.charAt(0) !== ".") { throw new FS.ErrnoError(55); } @@ -1829,7 +1824,7 @@ var sqlite3InitModule = (() => { } if (new_dir !== old_dir) { - errCode = FS.nodePermissions(old_dir, 'w'); + errCode = FS.nodePermissions(old_dir, "w"); if (errCode) { throw new FS.ErrnoError(errCode); } @@ -1903,7 +1898,7 @@ var sqlite3InitModule = (() => { } return PATH_FS.resolve( FS.getPath(link.parent), - link.node_ops.readlink(link), + link.node_ops.readlink(link) ); }, stat: (path, dontFollow) => { @@ -1922,7 +1917,7 @@ var sqlite3InitModule = (() => { }, chmod: (path, mode, dontFollow) => { var node; - if (typeof path == 'string') { + if (typeof path == "string") { var lookup = FS.lookupPath(path, { follow: !dontFollow }); node = lookup.node; } else { @@ -1948,7 +1943,7 @@ var sqlite3InitModule = (() => { }, chown: (path, uid, gid, dontFollow) => { var node; - if (typeof path == 'string') { + if (typeof path == "string") { var lookup = FS.lookupPath(path, { follow: !dontFollow }); node = lookup.node; } else { @@ -1976,7 +1971,7 @@ var sqlite3InitModule = (() => { throw new FS.ErrnoError(28); } var node; - if (typeof path == 'string') { + if (typeof path == "string") { var lookup = FS.lookupPath(path, { follow: true }); node = lookup.node; } else { @@ -1991,7 +1986,7 @@ var sqlite3InitModule = (() => { if (!FS.isFile(node.mode)) { throw new FS.ErrnoError(28); } - var errCode = FS.nodePermissions(node, 'w'); + var errCode = FS.nodePermissions(node, "w"); if (errCode) { throw new FS.ErrnoError(errCode); } @@ -2018,18 +2013,18 @@ var sqlite3InitModule = (() => { }); }, open: (path, flags, mode) => { - if (path === '') { + if (path === "") { throw new FS.ErrnoError(44); } - flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; - mode = typeof mode == 'undefined' ? 438 : mode; + flags = typeof flags == "string" ? FS.modeStringToFlags(flags) : flags; + mode = typeof mode == "undefined" ? 438 : mode; if (flags & 64) { mode = (mode & 4095) | 32768; } else { mode = 0; } var node; - if (typeof path == 'object') { + if (typeof path == "object") { node = path; } else { path = PATH.normalize(path); @@ -2092,7 +2087,7 @@ var sqlite3InitModule = (() => { if (stream.stream_ops.open) { stream.stream_ops.open(stream); } - if (Module['logReadFiles'] && !(flags & 1)) { + if (Module["logReadFiles"] && !(flags & 1)) { if (!FS.readFiles) FS.readFiles = {}; if (!(path in FS.readFiles)) { FS.readFiles[path] = 1; @@ -2149,7 +2144,7 @@ var sqlite3InitModule = (() => { if (!stream.stream_ops.read) { throw new FS.ErrnoError(28); } - var seeking = typeof position != 'undefined'; + var seeking = typeof position != "undefined"; if (!seeking) { position = stream.position; } else if (!stream.seekable) { @@ -2160,7 +2155,7 @@ var sqlite3InitModule = (() => { buffer, offset, length, - position, + position ); if (!seeking) stream.position += bytesRead; return bytesRead; @@ -2184,7 +2179,7 @@ var sqlite3InitModule = (() => { if (stream.seekable && stream.flags & 1024) { FS.llseek(stream, 0, 2); } - var seeking = typeof position != 'undefined'; + var seeking = typeof position != "undefined"; if (!seeking) { position = stream.position; } else if (!stream.seekable) { @@ -2196,7 +2191,7 @@ var sqlite3InitModule = (() => { offset, length, position, - canOwn, + canOwn ); if (!seeking) stream.position += bytesWritten; return bytesWritten; @@ -2244,7 +2239,7 @@ var sqlite3InitModule = (() => { buffer, offset, length, - mmapFlags, + mmapFlags ); }, munmap: (stream) => 0, @@ -2256,8 +2251,8 @@ var sqlite3InitModule = (() => { }, readFile: (path, opts = {}) => { opts.flags = opts.flags || 0; - opts.encoding = opts.encoding || 'binary'; - if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { + opts.encoding = opts.encoding || "binary"; + if (opts.encoding !== "utf8" && opts.encoding !== "binary") { throw new Error('Invalid encoding type "' + opts.encoding + '"'); } var ret; @@ -2266,9 +2261,9 @@ var sqlite3InitModule = (() => { var length = stat.size; var buf = new Uint8Array(length); FS.read(stream, buf, 0, length, 0); - if (opts.encoding === 'utf8') { + if (opts.encoding === "utf8") { ret = UTF8ArrayToString(buf, 0); - } else if (opts.encoding === 'binary') { + } else if (opts.encoding === "binary") { ret = buf; } FS.close(stream); @@ -2277,14 +2272,14 @@ var sqlite3InitModule = (() => { writeFile: (path, data, opts = {}) => { opts.flags = opts.flags || 577; var stream = FS.open(path, opts.flags, opts.mode); - if (typeof data == 'string') { + if (typeof data == "string") { var buf = new Uint8Array(lengthBytesUTF8(data) + 1); var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn); } else if (ArrayBuffer.isView(data)) { FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); } else { - throw new Error('Unsupported data type'); + throw new Error("Unsupported data type"); } FS.close(stream); }, @@ -2297,46 +2292,46 @@ var sqlite3InitModule = (() => { if (!FS.isDir(lookup.node.mode)) { throw new FS.ErrnoError(54); } - var errCode = FS.nodePermissions(lookup.node, 'x'); + var errCode = FS.nodePermissions(lookup.node, "x"); if (errCode) { throw new FS.ErrnoError(errCode); } FS.currentPath = lookup.path; }, createDefaultDirectories: () => { - FS.mkdir('/tmp'); - FS.mkdir('/home'); - FS.mkdir('/home/web_user'); + FS.mkdir("/tmp"); + FS.mkdir("/home"); + FS.mkdir("/home/web_user"); }, createDefaultDevices: () => { - FS.mkdir('/dev'); + FS.mkdir("/dev"); FS.registerDevice(FS.makedev(1, 3), { read: () => 0, write: (stream, buffer, offset, length, pos) => length, }); - FS.mkdev('/dev/null', FS.makedev(1, 3)); + FS.mkdev("/dev/null", FS.makedev(1, 3)); TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); - FS.mkdev('/dev/tty', FS.makedev(5, 0)); - FS.mkdev('/dev/tty1', FS.makedev(6, 0)); + FS.mkdev("/dev/tty", FS.makedev(5, 0)); + FS.mkdev("/dev/tty1", FS.makedev(6, 0)); var random_device = getRandomDevice(); - FS.createDevice('/dev', 'random', random_device); - FS.createDevice('/dev', 'urandom', random_device); + FS.createDevice("/dev", "random", random_device); + FS.createDevice("/dev", "urandom", random_device); - FS.mkdir('/dev/shm'); - FS.mkdir('/dev/shm/tmp'); + FS.mkdir("/dev/shm"); + FS.mkdir("/dev/shm/tmp"); }, createSpecialDirectories: () => { - FS.mkdir('/proc'); - var proc_self = FS.mkdir('/proc/self'); - FS.mkdir('/proc/self/fd'); + FS.mkdir("/proc"); + var proc_self = FS.mkdir("/proc/self"); + FS.mkdir("/proc/self/fd"); FS.mount( { mount: () => { - var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73); + var node = FS.createNode(proc_self, "fd", 16384 | 511, 73); node.node_ops = { lookup: (parent, name) => { var fd = +name; @@ -2344,7 +2339,7 @@ var sqlite3InitModule = (() => { if (!stream) throw new FS.ErrnoError(8); var ret = { parent: null, - mount: { mountpoint: 'fake' }, + mount: { mountpoint: "fake" }, node_ops: { readlink: () => stream.path }, }; ret.parent = ret; @@ -2355,29 +2350,29 @@ var sqlite3InitModule = (() => { }, }, {}, - '/proc/self/fd', + "/proc/self/fd" ); }, createStandardStreams: () => { - if (Module['stdin']) { - FS.createDevice('/dev', 'stdin', Module['stdin']); + if (Module["stdin"]) { + FS.createDevice("/dev", "stdin", Module["stdin"]); } else { - FS.symlink('/dev/tty', '/dev/stdin'); + FS.symlink("/dev/tty", "/dev/stdin"); } - if (Module['stdout']) { - FS.createDevice('/dev', 'stdout', null, Module['stdout']); + if (Module["stdout"]) { + FS.createDevice("/dev", "stdout", null, Module["stdout"]); } else { - FS.symlink('/dev/tty', '/dev/stdout'); + FS.symlink("/dev/tty", "/dev/stdout"); } - if (Module['stderr']) { - FS.createDevice('/dev', 'stderr', null, Module['stderr']); + if (Module["stderr"]) { + FS.createDevice("/dev", "stderr", null, Module["stderr"]); } else { - FS.symlink('/dev/tty1', '/dev/stderr'); + FS.symlink("/dev/tty1", "/dev/stderr"); } - FS.open('/dev/stdin', 0); - FS.open('/dev/stdout', 1); - FS.open('/dev/stderr', 1); + FS.open("/dev/stdin", 0); + FS.open("/dev/stdout", 1); + FS.open("/dev/stderr", 1); }, ensureErrnoError: () => { if (FS.ErrnoError) return; @@ -2387,14 +2382,14 @@ var sqlite3InitModule = (() => { this.errno = errno; }; this.setErrno(errno); - this.message = 'FS error'; + this.message = "FS error"; }; FS.ErrnoError.prototype = new Error(); FS.ErrnoError.prototype.constructor = FS.ErrnoError; [44].forEach((code) => { FS.genericErrors[code] = new FS.ErrnoError(code); - FS.genericErrors[code].stack = ''; + FS.genericErrors[code].stack = ""; }); }, staticInit: () => { @@ -2402,7 +2397,7 @@ var sqlite3InitModule = (() => { FS.nameTable = new Array(4096); - FS.mount(MEMFS, {}, '/'); + FS.mount(MEMFS, {}, "/"); FS.createDefaultDirectories(); FS.createDefaultDevices(); @@ -2417,9 +2412,9 @@ var sqlite3InitModule = (() => { FS.ensureErrnoError(); - Module['stdin'] = input || Module['stdin']; - Module['stdout'] = output || Module['stdout']; - Module['stderr'] = error || Module['stderr']; + Module["stdin"] = input || Module["stdin"]; + Module["stdout"] = output || Module["stdout"]; + Module["stderr"] = error || Module["stderr"]; FS.createStandardStreams(); }, @@ -2474,15 +2469,15 @@ var sqlite3InitModule = (() => { ret.path = lookup.path; ret.object = lookup.node; ret.name = lookup.node.name; - ret.isRoot = lookup.path === '/'; + ret.isRoot = lookup.path === "/"; } catch (e) { ret.error = e.errno; } return ret; }, createPath: (parent, path, canRead, canWrite) => { - parent = typeof parent == 'string' ? parent : FS.getPath(parent); - var parts = path.split('/').reverse(); + parent = typeof parent == "string" ? parent : FS.getPath(parent); + var parts = path.split("/").reverse(); while (parts.length) { var part = parts.pop(); if (!part) continue; @@ -2496,8 +2491,8 @@ var sqlite3InitModule = (() => { }, createFile: (parent, name, properties, canRead, canWrite) => { var path = PATH.join2( - typeof parent == 'string' ? parent : FS.getPath(parent), - name, + typeof parent == "string" ? parent : FS.getPath(parent), + name ); var mode = FS.getMode(canRead, canWrite); return FS.create(path, mode); @@ -2505,13 +2500,13 @@ var sqlite3InitModule = (() => { createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { var path = name; if (parent) { - parent = typeof parent == 'string' ? parent : FS.getPath(parent); + parent = typeof parent == "string" ? parent : FS.getPath(parent); path = name ? PATH.join2(parent, name) : parent; } var mode = FS.getMode(canRead, canWrite); var node = FS.create(path, mode); if (data) { - if (typeof data == 'string') { + if (typeof data == "string") { var arr = new Array(data.length); for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); @@ -2528,8 +2523,8 @@ var sqlite3InitModule = (() => { }, createDevice: (parent, name, input, output) => { var path = PATH.join2( - typeof parent == 'string' ? parent : FS.getPath(parent), - name, + typeof parent == "string" ? parent : FS.getPath(parent), + name ); var mode = FS.getMode(!!input, !!output); if (!FS.createDevice.major) FS.createDevice.major = 64; @@ -2584,9 +2579,9 @@ var sqlite3InitModule = (() => { forceLoadFile: (obj) => { if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; - if (typeof XMLHttpRequest != 'undefined') { + if (typeof XMLHttpRequest != "undefined") { throw new Error( - 'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.', + "Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread." ); } else if (read_) { try { @@ -2596,7 +2591,7 @@ var sqlite3InitModule = (() => { throw new FS.ErrnoError(29); } } else { - throw new Error('Cannot load without read() or XMLHttpRequest.'); + throw new Error("Cannot load without read() or XMLHttpRequest."); } }, createLazyFile: (parent, name, url, canRead, canWrite) => { @@ -2619,22 +2614,22 @@ var sqlite3InitModule = (() => { LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() { var xhr = new XMLHttpRequest(); - xhr.open('HEAD', url, false); + xhr.open("HEAD", url, false); xhr.send(null); if ( !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) ) throw new Error( - "Couldn't load " + url + '. Status: ' + xhr.status, + "Couldn't load " + url + ". Status: " + xhr.status ); - var datalength = Number(xhr.getResponseHeader('Content-length')); + var datalength = Number(xhr.getResponseHeader("Content-length")); var header; var hasByteServing = - (header = xhr.getResponseHeader('Accept-Ranges')) && - header === 'bytes'; + (header = xhr.getResponseHeader("Accept-Ranges")) && + header === "bytes"; var usesGzip = - (header = xhr.getResponseHeader('Content-Encoding')) && - header === 'gzip'; + (header = xhr.getResponseHeader("Content-Encoding")) && + header === "gzip"; var chunkSize = 1024 * 1024; @@ -2643,25 +2638,25 @@ var sqlite3InitModule = (() => { var doXHR = (from, to) => { if (from > to) throw new Error( - 'invalid range (' + + "invalid range (" + from + - ', ' + + ", " + to + - ') or no bytes requested!', + ") or no bytes requested!" ); if (to > datalength - 1) throw new Error( - 'only ' + datalength + ' bytes available! programmer error!', + "only " + datalength + " bytes available! programmer error!" ); var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); + xhr.open("GET", url, false); if (datalength !== chunkSize) - xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to); + xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); - xhr.responseType = 'arraybuffer'; + xhr.responseType = "arraybuffer"; if (xhr.overrideMimeType) { - xhr.overrideMimeType('text/plain; charset=x-user-defined'); + xhr.overrideMimeType("text/plain; charset=x-user-defined"); } xhr.send(null); @@ -2669,23 +2664,23 @@ var sqlite3InitModule = (() => { !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) ) throw new Error( - "Couldn't load " + url + '. Status: ' + xhr.status, + "Couldn't load " + url + ". Status: " + xhr.status ); if (xhr.response !== undefined) { return new Uint8Array(xhr.response || []); } - return intArrayFromString(xhr.responseText || ''); + return intArrayFromString(xhr.responseText || ""); }; var lazyArray = this; lazyArray.setDataGetter((chunkNum) => { var start = chunkNum * chunkSize; var end = (chunkNum + 1) * chunkSize - 1; end = Math.min(end, datalength - 1); - if (typeof lazyArray.chunks[chunkNum] == 'undefined') { + if (typeof lazyArray.chunks[chunkNum] == "undefined") { lazyArray.chunks[chunkNum] = doXHR(start, end); } - if (typeof lazyArray.chunks[chunkNum] == 'undefined') - throw new Error('doXHR failed!'); + if (typeof lazyArray.chunks[chunkNum] == "undefined") + throw new Error("doXHR failed!"); return lazyArray.chunks[chunkNum]; }); @@ -2694,7 +2689,7 @@ var sqlite3InitModule = (() => { datalength = this.getter(0).length; chunkSize = datalength; out( - 'LazyFiles on gzip forces download of the whole file when length is accessed', + "LazyFiles on gzip forces download of the whole file when length is accessed" ); } @@ -2702,9 +2697,9 @@ var sqlite3InitModule = (() => { this._chunkSize = chunkSize; this.lengthKnown = true; }; - if (typeof XMLHttpRequest != 'undefined') { + if (typeof XMLHttpRequest != "undefined") { if (!ENVIRONMENT_IS_WORKER) - throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; + throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc"; var lazyArray = new LazyUint8Array(); Object.defineProperties(lazyArray, { length: { @@ -2799,7 +2794,7 @@ var sqlite3InitModule = (() => { onerror, dontCreateFile, canOwn, - preFinish, + preFinish ) => { var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) @@ -2814,7 +2809,7 @@ var sqlite3InitModule = (() => { byteArray, canRead, canWrite, - canOwn, + canOwn ); } if (onload) onload(); @@ -2831,7 +2826,7 @@ var sqlite3InitModule = (() => { finish(byteArray); } addRunDependency(); - if (typeof url == 'string') { + if (typeof url == "string") { asyncLoad(url, (byteArray) => processData(byteArray), onerror); } else { processData(url); @@ -2846,10 +2841,10 @@ var sqlite3InitModule = (() => { ); }, DB_NAME: () => { - return 'EM_FS_' + window.location.pathname; + return "EM_FS_" + window.location.pathname; }, DB_VERSION: 20, - DB_STORE_NAME: 'FILE_DATA', + DB_STORE_NAME: "FILE_DATA", saveFilesToDB: (paths, onload, onerror) => { onload = onload || (() => {}); onerror = onerror || (() => {}); @@ -2860,13 +2855,13 @@ var sqlite3InitModule = (() => { return onerror(e); } openRequest.onupgradeneeded = () => { - out('creating db'); + out("creating db"); var db = openRequest.result; db.createObjectStore(FS.DB_STORE_NAME); }; openRequest.onsuccess = () => { var db = openRequest.result; - var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite'); + var transaction = db.transaction([FS.DB_STORE_NAME], "readwrite"); var files = transaction.objectStore(FS.DB_STORE_NAME); var ok = 0, fail = 0, @@ -2878,7 +2873,7 @@ var sqlite3InitModule = (() => { paths.forEach((path) => { var putRequest = files.put( FS.analyzePath(path).object.contents, - path, + path ); putRequest.onsuccess = () => { ok++; @@ -2906,7 +2901,7 @@ var sqlite3InitModule = (() => { openRequest.onsuccess = () => { var db = openRequest.result; try { - var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly'); + var transaction = db.transaction([FS.DB_STORE_NAME], "readonly"); } catch (e) { onerror(e); return; @@ -2931,7 +2926,7 @@ var sqlite3InitModule = (() => { getRequest.result, true, true, - true, + true ); ok++; if (ok + fail == total) finish(); @@ -2995,12 +2990,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, + 4294967295.0 ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 ) >>> 0 : 0), ]), @@ -3018,12 +3013,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, + 4294967295.0 ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 ) >>> 0 : 0), ]), @@ -3037,12 +3032,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, + 4294967295.0 ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 ) >>> 0 : 0), ]), @@ -3056,12 +3051,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, + 4294967295.0 ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 ) >>> 0 : 0), ]), @@ -3075,12 +3070,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, + 4294967295.0 ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 ) >>> 0 : 0), ]), @@ -3120,7 +3115,7 @@ var sqlite3InitModule = (() => { FS.chmod(path, mode); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3137,16 +3132,16 @@ var sqlite3InitModule = (() => { if (!node) { return -44; } - var perms = ''; - if (amode & 4) perms += 'r'; - if (amode & 2) perms += 'w'; - if (amode & 1) perms += 'x'; + var perms = ""; + if (amode & 4) perms += "r"; + if (amode & 2) perms += "w"; + if (amode & 1) perms += "x"; if (perms && FS.nodePermissions(node, perms)) { return -2; } return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3156,7 +3151,7 @@ var sqlite3InitModule = (() => { FS.fchmod(fd, mode); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3166,7 +3161,7 @@ var sqlite3InitModule = (() => { FS.fchown(fd, owner, group); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3221,7 +3216,7 @@ var sqlite3InitModule = (() => { } } } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3231,7 +3226,7 @@ var sqlite3InitModule = (() => { var stream = SYSCALLS.getStreamFromFD(fd); return SYSCALLS.doStat(FS.stat, stream.path, buf); } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3250,7 +3245,7 @@ var sqlite3InitModule = (() => { FS.ftruncate(fd, length); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3264,7 +3259,7 @@ var sqlite3InitModule = (() => { stringToUTF8(cwd, buf, size); return cwdLengthInBytes; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3314,7 +3309,7 @@ var sqlite3InitModule = (() => { return -28; } } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3324,7 +3319,7 @@ var sqlite3InitModule = (() => { path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.lstat, path, buf); } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3335,12 +3330,12 @@ var sqlite3InitModule = (() => { path = SYSCALLS.calculateAt(dirfd, path); path = PATH.normalize(path); - if (path[path.length - 1] === '/') + if (path[path.length - 1] === "/") path = path.substr(0, path.length - 1); FS.mkdir(path, mode, 0); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3354,7 +3349,7 @@ var sqlite3InitModule = (() => { path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3367,7 +3362,7 @@ var sqlite3InitModule = (() => { var mode = varargs ? SYSCALLS.get() : 0; return FS.open(path, flags, mode).fd; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3386,7 +3381,7 @@ var sqlite3InitModule = (() => { HEAP8[buf + len] = endChar; return len; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3397,7 +3392,7 @@ var sqlite3InitModule = (() => { FS.rmdir(path); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3407,7 +3402,7 @@ var sqlite3InitModule = (() => { path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.stat, path, buf); } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3421,11 +3416,11 @@ var sqlite3InitModule = (() => { } else if (flags === 512) { FS.rmdir(path); } else { - abort('Invalid flags passed to unlinkat'); + abort("Invalid flags passed to unlinkat"); } return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3453,7 +3448,7 @@ var sqlite3InitModule = (() => { FS.utime(path, atime, mtime); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3515,7 +3510,7 @@ var sqlite3InitModule = (() => { HEAPU32[addr >> 2] = ptr; return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3528,7 +3523,7 @@ var sqlite3InitModule = (() => { } FS.munmap(stream); } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3554,7 +3549,7 @@ var sqlite3InitModule = (() => { function extractZone(date) { var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/); - return match ? match[1] : 'GMT'; + return match ? match[1] : "GMT"; } var winterName = extractZone(winter); var summerName = extractZone(summer); @@ -3604,12 +3599,12 @@ var sqlite3InitModule = (() => { overGrownHeapSize = Math.min( overGrownHeapSize, - requestedSize + 100663296, + requestedSize + 100663296 ); var newSize = Math.min( maxHeapSize, - alignUp(Math.max(requestedSize, overGrownHeapSize), 65536), + alignUp(Math.max(requestedSize, overGrownHeapSize), 65536) ); var replacement = emscripten_realloc_buffer(newSize); @@ -3623,23 +3618,23 @@ var sqlite3InitModule = (() => { var ENV = {}; function getExecutableName() { - return thisProgram || './this.program'; + return thisProgram || "./this.program"; } function getEnvStrings() { if (!getEnvStrings.strings) { var lang = ( - (typeof navigator == 'object' && + (typeof navigator == "object" && navigator.languages && navigator.languages[0]) || - 'C' - ).replace('-', '_') + '.UTF-8'; + "C" + ).replace("-", "_") + ".UTF-8"; var env = { - USER: 'web_user', - LOGNAME: 'web_user', - PATH: '/', - PWD: '/', - HOME: '/home/web_user', + USER: "web_user", + LOGNAME: "web_user", + PATH: "/", + PWD: "/", + HOME: "/home/web_user", LANG: lang, _: getExecutableName(), }; @@ -3650,7 +3645,7 @@ var sqlite3InitModule = (() => { } var strings = []; for (var x in env) { - strings.push(x + '=' + env[x]); + strings.push(x + "=" + env[x]); } getEnvStrings.strings = strings; } @@ -3693,7 +3688,7 @@ var sqlite3InitModule = (() => { FS.close(stream); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3705,15 +3700,15 @@ var sqlite3InitModule = (() => { var type = stream.tty ? 2 : FS.isDir(stream.mode) - ? 3 - : FS.isLink(stream.mode) - ? 7 - : 4; + ? 3 + : FS.isLink(stream.mode) + ? 7 + : 4; HEAP8[pbuf >> 0] = type; return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3739,7 +3734,7 @@ var sqlite3InitModule = (() => { HEAPU32[pnum >> 2] = num; return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3757,12 +3752,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0, + 4294967295.0 ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 ) >>> 0 : 0), ]), @@ -3772,7 +3767,7 @@ var sqlite3InitModule = (() => { stream.getdents = null; return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3785,7 +3780,7 @@ var sqlite3InitModule = (() => { } return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3810,7 +3805,7 @@ var sqlite3InitModule = (() => { HEAPU32[pnum >> 2] = num; return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3901,1588 +3896,1281 @@ var sqlite3InitModule = (() => { }; createWasm(); - (Module['___wasm_call_ctors'] = function () { - return (Module['___wasm_call_ctors'] = - Module['asm']['__wasm_call_ctors']).apply(null, arguments); - }); + Module["___wasm_call_ctors"] = function () { + return (Module["___wasm_call_ctors"] = + Module["asm"]["__wasm_call_ctors"]).apply(null, arguments); + }; - (Module['_sqlite3_status64'] = function () { - return (Module['_sqlite3_status64'] = - Module['asm']['sqlite3_status64']).apply(null, arguments); - }); + Module["_sqlite3_status64"] = function () { + return (Module["_sqlite3_status64"] = + Module["asm"]["sqlite3_status64"]).apply(null, arguments); + }; - (Module['_sqlite3_status'] = function () { - return (Module['_sqlite3_status'] = - Module['asm']['sqlite3_status']).apply(null, arguments); - }); + Module["_sqlite3_status"] = function () { + return (Module["_sqlite3_status"] = + Module["asm"]["sqlite3_status"]).apply(null, arguments); + }; - (Module['_sqlite3_db_status'] = function () { - return (Module['_sqlite3_db_status'] = - Module['asm']['sqlite3_db_status']).apply(null, arguments); - }); + Module["_sqlite3_db_status"] = function () { + return (Module["_sqlite3_db_status"] = + Module["asm"]["sqlite3_db_status"]).apply(null, arguments); + }; - (Module['_sqlite3_msize'] = function () { - return (Module['_sqlite3_msize'] = - Module['asm']['sqlite3_msize']).apply(null, arguments); - }); + Module["_sqlite3_msize"] = function () { + return (Module["_sqlite3_msize"] = Module["asm"]["sqlite3_msize"]).apply( + null, + arguments + ); + }; - (Module['_sqlite3_vfs_find'] = function () { - return (Module['_sqlite3_vfs_find'] = - Module['asm']['sqlite3_vfs_find']).apply(null, arguments); - }); + Module["_sqlite3_vfs_find"] = function () { + return (Module["_sqlite3_vfs_find"] = + Module["asm"]["sqlite3_vfs_find"]).apply(null, arguments); + }; - (Module['_sqlite3_initialize'] = function () { - return (Module['_sqlite3_initialize'] = - Module['asm']['sqlite3_initialize']).apply(null, arguments); - }); + Module["_sqlite3_initialize"] = function () { + return (Module["_sqlite3_initialize"] = + Module["asm"]["sqlite3_initialize"]).apply(null, arguments); + }; - (Module['_sqlite3_malloc'] = function () { - return (Module['_sqlite3_malloc'] = - Module['asm']['sqlite3_malloc']).apply(null, arguments); - }); + Module["_sqlite3_malloc"] = function () { + return (Module["_sqlite3_malloc"] = + Module["asm"]["sqlite3_malloc"]).apply(null, arguments); + }; - (Module['_sqlite3_free'] = function () { - return (Module['_sqlite3_free'] = - Module['asm']['sqlite3_free']).apply(null, arguments); - }); + Module["_sqlite3_free"] = function () { + return (Module["_sqlite3_free"] = Module["asm"]["sqlite3_free"]).apply( + null, + arguments + ); + }; - (Module['_sqlite3_vfs_register'] = function () { - return (Module['_sqlite3_vfs_register'] = - Module['asm']['sqlite3_vfs_register']).apply(null, arguments); - }); + Module["_sqlite3_vfs_register"] = function () { + return (Module["_sqlite3_vfs_register"] = + Module["asm"]["sqlite3_vfs_register"]).apply(null, arguments); + }; - (Module['_sqlite3_vfs_unregister'] = - function () { - return (Module['_sqlite3_vfs_unregister'] = - Module['asm']['sqlite3_vfs_unregister']).apply(null, arguments); - }); + Module["_sqlite3_vfs_unregister"] = function () { + return (Module["_sqlite3_vfs_unregister"] = + Module["asm"]["sqlite3_vfs_unregister"]).apply(null, arguments); + }; - (Module['_sqlite3_malloc64'] = function () { - return (Module['_sqlite3_malloc64'] = - Module['asm']['sqlite3_malloc64']).apply(null, arguments); - }); + Module["_sqlite3_malloc64"] = function () { + return (Module["_sqlite3_malloc64"] = + Module["asm"]["sqlite3_malloc64"]).apply(null, arguments); + }; - (Module['_sqlite3_realloc'] = function () { - return (Module['_sqlite3_realloc'] = - Module['asm']['sqlite3_realloc']).apply(null, arguments); - }); + Module["_sqlite3_realloc"] = function () { + return (Module["_sqlite3_realloc"] = + Module["asm"]["sqlite3_realloc"]).apply(null, arguments); + }; - (Module['_sqlite3_realloc64'] = function () { - return (Module['_sqlite3_realloc64'] = - Module['asm']['sqlite3_realloc64']).apply(null, arguments); - }); + Module["_sqlite3_realloc64"] = function () { + return (Module["_sqlite3_realloc64"] = + Module["asm"]["sqlite3_realloc64"]).apply(null, arguments); + }; - (Module['_sqlite3_value_text'] = function () { - return (Module['_sqlite3_value_text'] = - Module['asm']['sqlite3_value_text']).apply(null, arguments); - }); + Module["_sqlite3_value_text"] = function () { + return (Module["_sqlite3_value_text"] = + Module["asm"]["sqlite3_value_text"]).apply(null, arguments); + }; - (Module['_sqlite3_randomness'] = function () { - return (Module['_sqlite3_randomness'] = - Module['asm']['sqlite3_randomness']).apply(null, arguments); - }); + Module["_sqlite3_randomness"] = function () { + return (Module["_sqlite3_randomness"] = + Module["asm"]["sqlite3_randomness"]).apply(null, arguments); + }; - (Module['_sqlite3_stricmp'] = function () { - return (Module['_sqlite3_stricmp'] = - Module['asm']['sqlite3_stricmp']).apply(null, arguments); - }); + Module["_sqlite3_stricmp"] = function () { + return (Module["_sqlite3_stricmp"] = + Module["asm"]["sqlite3_stricmp"]).apply(null, arguments); + }; - (Module['_sqlite3_strnicmp'] = function () { - return (Module['_sqlite3_strnicmp'] = - Module['asm']['sqlite3_strnicmp']).apply(null, arguments); - }); + Module["_sqlite3_strnicmp"] = function () { + return (Module["_sqlite3_strnicmp"] = + Module["asm"]["sqlite3_strnicmp"]).apply(null, arguments); + }; - (Module['_sqlite3_uri_parameter'] = - function () { - return (Module['_sqlite3_uri_parameter'] = - Module['asm']['sqlite3_uri_parameter']).apply(null, arguments); - }); + Module["_sqlite3_uri_parameter"] = function () { + return (Module["_sqlite3_uri_parameter"] = + Module["asm"]["sqlite3_uri_parameter"]).apply(null, arguments); + }; - var ___errno_location = (Module['___errno_location'] = function () { - return (___errno_location = Module['___errno_location'] = - Module['asm']['__errno_location']).apply(null, arguments); + var ___errno_location = (Module["___errno_location"] = function () { + return (___errno_location = Module["___errno_location"] = + Module["asm"]["__errno_location"]).apply(null, arguments); }); - (Module['_sqlite3_uri_boolean'] = function () { - return (Module['_sqlite3_uri_boolean'] = - Module['asm']['sqlite3_uri_boolean']).apply(null, arguments); - }); + Module["_sqlite3_uri_boolean"] = function () { + return (Module["_sqlite3_uri_boolean"] = + Module["asm"]["sqlite3_uri_boolean"]).apply(null, arguments); + }; - (Module['_sqlite3_serialize'] = function () { - return (Module['_sqlite3_serialize'] = - Module['asm']['sqlite3_serialize']).apply(null, arguments); - }); + Module["_sqlite3_serialize"] = function () { + return (Module["_sqlite3_serialize"] = + Module["asm"]["sqlite3_serialize"]).apply(null, arguments); + }; - (Module['_sqlite3_prepare_v2'] = function () { - return (Module['_sqlite3_prepare_v2'] = - Module['asm']['sqlite3_prepare_v2']).apply(null, arguments); - }); + Module["_sqlite3_prepare_v2"] = function () { + return (Module["_sqlite3_prepare_v2"] = + Module["asm"]["sqlite3_prepare_v2"]).apply(null, arguments); + }; - (Module['_sqlite3_step'] = function () { - return (Module['_sqlite3_step'] = - Module['asm']['sqlite3_step']).apply(null, arguments); - }); + Module["_sqlite3_step"] = function () { + return (Module["_sqlite3_step"] = Module["asm"]["sqlite3_step"]).apply( + null, + arguments + ); + }; - (Module['_sqlite3_column_int64'] = function () { - return (Module['_sqlite3_column_int64'] = - Module['asm']['sqlite3_column_int64']).apply(null, arguments); - }); + Module["_sqlite3_column_int64"] = function () { + return (Module["_sqlite3_column_int64"] = + Module["asm"]["sqlite3_column_int64"]).apply(null, arguments); + }; - (Module['_sqlite3_reset'] = function () { - return (Module['_sqlite3_reset'] = - Module['asm']['sqlite3_reset']).apply(null, arguments); - }); + Module["_sqlite3_reset"] = function () { + return (Module["_sqlite3_reset"] = Module["asm"]["sqlite3_reset"]).apply( + null, + arguments + ); + }; - (Module['_sqlite3_exec'] = function () { - return (Module['_sqlite3_exec'] = - Module['asm']['sqlite3_exec']).apply(null, arguments); - }); + Module["_sqlite3_exec"] = function () { + return (Module["_sqlite3_exec"] = Module["asm"]["sqlite3_exec"]).apply( + null, + arguments + ); + }; - (Module['_sqlite3_column_int'] = function () { - return (Module['_sqlite3_column_int'] = - Module['asm']['sqlite3_column_int']).apply(null, arguments); - }); + Module["_sqlite3_column_int"] = function () { + return (Module["_sqlite3_column_int"] = + Module["asm"]["sqlite3_column_int"]).apply(null, arguments); + }; - (Module['_sqlite3_finalize'] = function () { - return (Module['_sqlite3_finalize'] = - Module['asm']['sqlite3_finalize']).apply(null, arguments); - }); + Module["_sqlite3_finalize"] = function () { + return (Module["_sqlite3_finalize"] = + Module["asm"]["sqlite3_finalize"]).apply(null, arguments); + }; - (Module['_sqlite3_file_control'] = function () { - return (Module['_sqlite3_file_control'] = - Module['asm']['sqlite3_file_control']).apply(null, arguments); - }); + Module["_sqlite3_file_control"] = function () { + return (Module["_sqlite3_file_control"] = + Module["asm"]["sqlite3_file_control"]).apply(null, arguments); + }; - (Module['_sqlite3_column_name'] = function () { - return (Module['_sqlite3_column_name'] = - Module['asm']['sqlite3_column_name']).apply(null, arguments); - }); + Module["_sqlite3_column_name"] = function () { + return (Module["_sqlite3_column_name"] = + Module["asm"]["sqlite3_column_name"]).apply(null, arguments); + }; - (Module['_sqlite3_column_text'] = function () { - return (Module['_sqlite3_column_text'] = - Module['asm']['sqlite3_column_text']).apply(null, arguments); - }); + Module["_sqlite3_column_text"] = function () { + return (Module["_sqlite3_column_text"] = + Module["asm"]["sqlite3_column_text"]).apply(null, arguments); + }; - (Module['_sqlite3_column_type'] = function () { - return (Module['_sqlite3_column_type'] = - Module['asm']['sqlite3_column_type']).apply(null, arguments); - }); + Module["_sqlite3_column_type"] = function () { + return (Module["_sqlite3_column_type"] = + Module["asm"]["sqlite3_column_type"]).apply(null, arguments); + }; - (Module['_sqlite3_errmsg'] = function () { - return (Module['_sqlite3_errmsg'] = - Module['asm']['sqlite3_errmsg']).apply(null, arguments); - }); + Module["_sqlite3_errmsg"] = function () { + return (Module["_sqlite3_errmsg"] = + Module["asm"]["sqlite3_errmsg"]).apply(null, arguments); + }; - (Module['_sqlite3_deserialize'] = function () { - return (Module['_sqlite3_deserialize'] = - Module['asm']['sqlite3_deserialize']).apply(null, arguments); - }); + Module["_sqlite3_deserialize"] = function () { + return (Module["_sqlite3_deserialize"] = + Module["asm"]["sqlite3_deserialize"]).apply(null, arguments); + }; - (Module['_sqlite3_clear_bindings'] = - function () { - return (Module['_sqlite3_clear_bindings'] = - Module['asm']['sqlite3_clear_bindings']).apply(null, arguments); - }); + Module["_sqlite3_clear_bindings"] = function () { + return (Module["_sqlite3_clear_bindings"] = + Module["asm"]["sqlite3_clear_bindings"]).apply(null, arguments); + }; - (Module['_sqlite3_value_blob'] = function () { - return (Module['_sqlite3_value_blob'] = - Module['asm']['sqlite3_value_blob']).apply(null, arguments); - }); + Module["_sqlite3_value_blob"] = function () { + return (Module["_sqlite3_value_blob"] = + Module["asm"]["sqlite3_value_blob"]).apply(null, arguments); + }; - (Module['_sqlite3_value_bytes'] = function () { - return (Module['_sqlite3_value_bytes'] = - Module['asm']['sqlite3_value_bytes']).apply(null, arguments); - }); + Module["_sqlite3_value_bytes"] = function () { + return (Module["_sqlite3_value_bytes"] = + Module["asm"]["sqlite3_value_bytes"]).apply(null, arguments); + }; - (Module['_sqlite3_value_double'] = function () { - return (Module['_sqlite3_value_double'] = - Module['asm']['sqlite3_value_double']).apply(null, arguments); - }); + Module["_sqlite3_value_double"] = function () { + return (Module["_sqlite3_value_double"] = + Module["asm"]["sqlite3_value_double"]).apply(null, arguments); + }; - (Module['_sqlite3_value_int'] = function () { - return (Module['_sqlite3_value_int'] = - Module['asm']['sqlite3_value_int']).apply(null, arguments); - }); + Module["_sqlite3_value_int"] = function () { + return (Module["_sqlite3_value_int"] = + Module["asm"]["sqlite3_value_int"]).apply(null, arguments); + }; - (Module['_sqlite3_value_int64'] = function () { - return (Module['_sqlite3_value_int64'] = - Module['asm']['sqlite3_value_int64']).apply(null, arguments); - }); + Module["_sqlite3_value_int64"] = function () { + return (Module["_sqlite3_value_int64"] = + Module["asm"]["sqlite3_value_int64"]).apply(null, arguments); + }; - (Module['_sqlite3_value_subtype'] = - function () { - return (Module['_sqlite3_value_subtype'] = - Module['asm']['sqlite3_value_subtype']).apply(null, arguments); - }); + Module["_sqlite3_value_subtype"] = function () { + return (Module["_sqlite3_value_subtype"] = + Module["asm"]["sqlite3_value_subtype"]).apply(null, arguments); + }; - (Module['_sqlite3_value_pointer'] = - function () { - return (Module['_sqlite3_value_pointer'] = - Module['asm']['sqlite3_value_pointer']).apply(null, arguments); - }); + Module["_sqlite3_value_pointer"] = function () { + return (Module["_sqlite3_value_pointer"] = + Module["asm"]["sqlite3_value_pointer"]).apply(null, arguments); + }; - (Module['_sqlite3_value_type'] = function () { - return (Module['_sqlite3_value_type'] = - Module['asm']['sqlite3_value_type']).apply(null, arguments); - }); + Module["_sqlite3_value_type"] = function () { + return (Module["_sqlite3_value_type"] = + Module["asm"]["sqlite3_value_type"]).apply(null, arguments); + }; - (Module['_sqlite3_value_nochange'] = - function () { - return (Module['_sqlite3_value_nochange'] = - Module['asm']['sqlite3_value_nochange']).apply(null, arguments); - }); + Module["_sqlite3_value_nochange"] = function () { + return (Module["_sqlite3_value_nochange"] = + Module["asm"]["sqlite3_value_nochange"]).apply(null, arguments); + }; - (Module['_sqlite3_value_frombind'] = - function () { - return (Module['_sqlite3_value_frombind'] = - Module['asm']['sqlite3_value_frombind']).apply(null, arguments); - }); + Module["_sqlite3_value_frombind"] = function () { + return (Module["_sqlite3_value_frombind"] = + Module["asm"]["sqlite3_value_frombind"]).apply(null, arguments); + }; - (Module['_sqlite3_value_dup'] = function () { - return (Module['_sqlite3_value_dup'] = - Module['asm']['sqlite3_value_dup']).apply(null, arguments); - }); + Module["_sqlite3_value_dup"] = function () { + return (Module["_sqlite3_value_dup"] = + Module["asm"]["sqlite3_value_dup"]).apply(null, arguments); + }; - (Module['_sqlite3_value_free'] = function () { - return (Module['_sqlite3_value_free'] = - Module['asm']['sqlite3_value_free']).apply(null, arguments); - }); + Module["_sqlite3_value_free"] = function () { + return (Module["_sqlite3_value_free"] = + Module["asm"]["sqlite3_value_free"]).apply(null, arguments); + }; - (Module['_sqlite3_result_blob'] = function () { - return (Module['_sqlite3_result_blob'] = - Module['asm']['sqlite3_result_blob']).apply(null, arguments); - }); + Module["_sqlite3_result_blob"] = function () { + return (Module["_sqlite3_result_blob"] = + Module["asm"]["sqlite3_result_blob"]).apply(null, arguments); + }; - (Module['_sqlite3_result_error_toobig'] = - function () { - return (Module[ - '_sqlite3_result_error_toobig' - ] = - Module['asm']['sqlite3_result_error_toobig']).apply(null, arguments); - }); + Module["_sqlite3_result_error_toobig"] = function () { + return (Module["_sqlite3_result_error_toobig"] = + Module["asm"]["sqlite3_result_error_toobig"]).apply(null, arguments); + }; - (Module['_sqlite3_result_error_nomem'] = - function () { - return (Module[ - '_sqlite3_result_error_nomem' - ] = - Module['asm']['sqlite3_result_error_nomem']).apply(null, arguments); - }); + Module["_sqlite3_result_error_nomem"] = function () { + return (Module["_sqlite3_result_error_nomem"] = + Module["asm"]["sqlite3_result_error_nomem"]).apply(null, arguments); + }; - (Module['_sqlite3_result_double'] = - function () { - return (Module['_sqlite3_result_double'] = - Module['asm']['sqlite3_result_double']).apply(null, arguments); - }); + Module["_sqlite3_result_double"] = function () { + return (Module["_sqlite3_result_double"] = + Module["asm"]["sqlite3_result_double"]).apply(null, arguments); + }; - (Module['_sqlite3_result_error'] = function () { - return (Module['_sqlite3_result_error'] = - Module['asm']['sqlite3_result_error']).apply(null, arguments); - }); + Module["_sqlite3_result_error"] = function () { + return (Module["_sqlite3_result_error"] = + Module["asm"]["sqlite3_result_error"]).apply(null, arguments); + }; - (Module['_sqlite3_result_int'] = function () { - return (Module['_sqlite3_result_int'] = - Module['asm']['sqlite3_result_int']).apply(null, arguments); - }); + Module["_sqlite3_result_int"] = function () { + return (Module["_sqlite3_result_int"] = + Module["asm"]["sqlite3_result_int"]).apply(null, arguments); + }; - (Module['_sqlite3_result_int64'] = function () { - return (Module['_sqlite3_result_int64'] = - Module['asm']['sqlite3_result_int64']).apply(null, arguments); - }); + Module["_sqlite3_result_int64"] = function () { + return (Module["_sqlite3_result_int64"] = + Module["asm"]["sqlite3_result_int64"]).apply(null, arguments); + }; - (Module['_sqlite3_result_null'] = function () { - return (Module['_sqlite3_result_null'] = - Module['asm']['sqlite3_result_null']).apply(null, arguments); - }); + Module["_sqlite3_result_null"] = function () { + return (Module["_sqlite3_result_null"] = + Module["asm"]["sqlite3_result_null"]).apply(null, arguments); + }; - (Module['_sqlite3_result_pointer'] = - function () { - return (Module['_sqlite3_result_pointer'] = - Module['asm']['sqlite3_result_pointer']).apply(null, arguments); - }); + Module["_sqlite3_result_pointer"] = function () { + return (Module["_sqlite3_result_pointer"] = + Module["asm"]["sqlite3_result_pointer"]).apply(null, arguments); + }; - (Module['_sqlite3_result_subtype'] = - function () { - return (Module['_sqlite3_result_subtype'] = - Module['asm']['sqlite3_result_subtype']).apply(null, arguments); - }); + Module["_sqlite3_result_subtype"] = function () { + return (Module["_sqlite3_result_subtype"] = + Module["asm"]["sqlite3_result_subtype"]).apply(null, arguments); + }; - (Module['_sqlite3_result_text'] = function () { - return (Module['_sqlite3_result_text'] = - Module['asm']['sqlite3_result_text']).apply(null, arguments); - }); + Module["_sqlite3_result_text"] = function () { + return (Module["_sqlite3_result_text"] = + Module["asm"]["sqlite3_result_text"]).apply(null, arguments); + }; - (Module['_sqlite3_result_zeroblob'] = - function () { - return (Module['_sqlite3_result_zeroblob'] = - Module['asm']['sqlite3_result_zeroblob']).apply(null, arguments); - }); + Module["_sqlite3_result_zeroblob"] = function () { + return (Module["_sqlite3_result_zeroblob"] = + Module["asm"]["sqlite3_result_zeroblob"]).apply(null, arguments); + }; - (Module['_sqlite3_result_zeroblob64'] = - function () { - return (Module[ - '_sqlite3_result_zeroblob64' - ] = - Module['asm']['sqlite3_result_zeroblob64']).apply(null, arguments); - }); + Module["_sqlite3_result_zeroblob64"] = function () { + return (Module["_sqlite3_result_zeroblob64"] = + Module["asm"]["sqlite3_result_zeroblob64"]).apply(null, arguments); + }; - (Module['_sqlite3_result_error_code'] = - function () { - return (Module[ - '_sqlite3_result_error_code' - ] = - Module['asm']['sqlite3_result_error_code']).apply(null, arguments); - }); + Module["_sqlite3_result_error_code"] = function () { + return (Module["_sqlite3_result_error_code"] = + Module["asm"]["sqlite3_result_error_code"]).apply(null, arguments); + }; - (Module['_sqlite3_user_data'] = function () { - return (Module['_sqlite3_user_data'] = - Module['asm']['sqlite3_user_data']).apply(null, arguments); - }); + Module["_sqlite3_user_data"] = function () { + return (Module["_sqlite3_user_data"] = + Module["asm"]["sqlite3_user_data"]).apply(null, arguments); + }; - (Module['_sqlite3_context_db_handle'] = - function () { - return (Module[ - '_sqlite3_context_db_handle' - ] = - Module['asm']['sqlite3_context_db_handle']).apply(null, arguments); - }); + Module["_sqlite3_context_db_handle"] = function () { + return (Module["_sqlite3_context_db_handle"] = + Module["asm"]["sqlite3_context_db_handle"]).apply(null, arguments); + }; - (Module['_sqlite3_vtab_nochange'] = - function () { - return (Module['_sqlite3_vtab_nochange'] = - Module['asm']['sqlite3_vtab_nochange']).apply(null, arguments); - }); + Module["_sqlite3_vtab_nochange"] = function () { + return (Module["_sqlite3_vtab_nochange"] = + Module["asm"]["sqlite3_vtab_nochange"]).apply(null, arguments); + }; - (Module['_sqlite3_vtab_in_first'] = - function () { - return (Module['_sqlite3_vtab_in_first'] = - Module['asm']['sqlite3_vtab_in_first']).apply(null, arguments); - }); + Module["_sqlite3_vtab_in_first"] = function () { + return (Module["_sqlite3_vtab_in_first"] = + Module["asm"]["sqlite3_vtab_in_first"]).apply(null, arguments); + }; - (Module['_sqlite3_vtab_in_next'] = function () { - return (Module['_sqlite3_vtab_in_next'] = - Module['asm']['sqlite3_vtab_in_next']).apply(null, arguments); - }); + Module["_sqlite3_vtab_in_next"] = function () { + return (Module["_sqlite3_vtab_in_next"] = + Module["asm"]["sqlite3_vtab_in_next"]).apply(null, arguments); + }; - (Module['_sqlite3_aggregate_context'] = - function () { - return (Module[ - '_sqlite3_aggregate_context' - ] = - Module['asm']['sqlite3_aggregate_context']).apply(null, arguments); - }); + Module["_sqlite3_aggregate_context"] = function () { + return (Module["_sqlite3_aggregate_context"] = + Module["asm"]["sqlite3_aggregate_context"]).apply(null, arguments); + }; - (Module['_sqlite3_get_auxdata'] = function () { - return (Module['_sqlite3_get_auxdata'] = - Module['asm']['sqlite3_get_auxdata']).apply(null, arguments); - }); + Module["_sqlite3_get_auxdata"] = function () { + return (Module["_sqlite3_get_auxdata"] = + Module["asm"]["sqlite3_get_auxdata"]).apply(null, arguments); + }; - (Module['_sqlite3_set_auxdata'] = function () { - return (Module['_sqlite3_set_auxdata'] = - Module['asm']['sqlite3_set_auxdata']).apply(null, arguments); - }); + Module["_sqlite3_set_auxdata"] = function () { + return (Module["_sqlite3_set_auxdata"] = + Module["asm"]["sqlite3_set_auxdata"]).apply(null, arguments); + }; - (Module['_sqlite3_column_count'] = function () { - return (Module['_sqlite3_column_count'] = - Module['asm']['sqlite3_column_count']).apply(null, arguments); - }); + Module["_sqlite3_column_count"] = function () { + return (Module["_sqlite3_column_count"] = + Module["asm"]["sqlite3_column_count"]).apply(null, arguments); + }; - (Module['_sqlite3_data_count'] = function () { - return (Module['_sqlite3_data_count'] = - Module['asm']['sqlite3_data_count']).apply(null, arguments); - }); + Module["_sqlite3_data_count"] = function () { + return (Module["_sqlite3_data_count"] = + Module["asm"]["sqlite3_data_count"]).apply(null, arguments); + }; - (Module['_sqlite3_column_blob'] = function () { - return (Module['_sqlite3_column_blob'] = - Module['asm']['sqlite3_column_blob']).apply(null, arguments); - }); + Module["_sqlite3_column_blob"] = function () { + return (Module["_sqlite3_column_blob"] = + Module["asm"]["sqlite3_column_blob"]).apply(null, arguments); + }; - (Module['_sqlite3_column_bytes'] = function () { - return (Module['_sqlite3_column_bytes'] = - Module['asm']['sqlite3_column_bytes']).apply(null, arguments); - }); + Module["_sqlite3_column_bytes"] = function () { + return (Module["_sqlite3_column_bytes"] = + Module["asm"]["sqlite3_column_bytes"]).apply(null, arguments); + }; - (Module['_sqlite3_column_double'] = - function () { - return (Module['_sqlite3_column_double'] = - Module['asm']['sqlite3_column_double']).apply(null, arguments); - }); + Module["_sqlite3_column_double"] = function () { + return (Module["_sqlite3_column_double"] = + Module["asm"]["sqlite3_column_double"]).apply(null, arguments); + }; - (Module['_sqlite3_column_value'] = function () { - return (Module['_sqlite3_column_value'] = - Module['asm']['sqlite3_column_value']).apply(null, arguments); - }); + Module["_sqlite3_column_value"] = function () { + return (Module["_sqlite3_column_value"] = + Module["asm"]["sqlite3_column_value"]).apply(null, arguments); + }; - (Module['_sqlite3_bind_blob'] = function () { - return (Module['_sqlite3_bind_blob'] = - Module['asm']['sqlite3_bind_blob']).apply(null, arguments); - }); + Module["_sqlite3_bind_blob"] = function () { + return (Module["_sqlite3_bind_blob"] = + Module["asm"]["sqlite3_bind_blob"]).apply(null, arguments); + }; - (Module['_sqlite3_bind_double'] = function () { - return (Module['_sqlite3_bind_double'] = - Module['asm']['sqlite3_bind_double']).apply(null, arguments); - }); + Module["_sqlite3_bind_double"] = function () { + return (Module["_sqlite3_bind_double"] = + Module["asm"]["sqlite3_bind_double"]).apply(null, arguments); + }; - (Module['_sqlite3_bind_int'] = function () { - return (Module['_sqlite3_bind_int'] = - Module['asm']['sqlite3_bind_int']).apply(null, arguments); - }); + Module["_sqlite3_bind_int"] = function () { + return (Module["_sqlite3_bind_int"] = + Module["asm"]["sqlite3_bind_int"]).apply(null, arguments); + }; - (Module['_sqlite3_bind_int64'] = function () { - return (Module['_sqlite3_bind_int64'] = - Module['asm']['sqlite3_bind_int64']).apply(null, arguments); - }); + Module["_sqlite3_bind_int64"] = function () { + return (Module["_sqlite3_bind_int64"] = + Module["asm"]["sqlite3_bind_int64"]).apply(null, arguments); + }; - (Module['_sqlite3_bind_null'] = function () { - return (Module['_sqlite3_bind_null'] = - Module['asm']['sqlite3_bind_null']).apply(null, arguments); - }); + Module["_sqlite3_bind_null"] = function () { + return (Module["_sqlite3_bind_null"] = + Module["asm"]["sqlite3_bind_null"]).apply(null, arguments); + }; - (Module['_sqlite3_bind_pointer'] = function () { - return (Module['_sqlite3_bind_pointer'] = - Module['asm']['sqlite3_bind_pointer']).apply(null, arguments); - }); + Module["_sqlite3_bind_pointer"] = function () { + return (Module["_sqlite3_bind_pointer"] = + Module["asm"]["sqlite3_bind_pointer"]).apply(null, arguments); + }; - (Module['_sqlite3_bind_text'] = function () { - return (Module['_sqlite3_bind_text'] = - Module['asm']['sqlite3_bind_text']).apply(null, arguments); - }); + Module["_sqlite3_bind_text"] = function () { + return (Module["_sqlite3_bind_text"] = + Module["asm"]["sqlite3_bind_text"]).apply(null, arguments); + }; - (Module[ - '_sqlite3_bind_parameter_count' - ] = function () { - return (Module[ - '_sqlite3_bind_parameter_count' - ] = - Module['asm']['sqlite3_bind_parameter_count']).apply(null, arguments); - }); + Module["_sqlite3_bind_parameter_count"] = function () { + return (Module["_sqlite3_bind_parameter_count"] = + Module["asm"]["sqlite3_bind_parameter_count"]).apply(null, arguments); + }; - (Module[ - '_sqlite3_bind_parameter_index' - ] = function () { - return (Module[ - '_sqlite3_bind_parameter_index' - ] = - Module['asm']['sqlite3_bind_parameter_index']).apply(null, arguments); - }); + Module["_sqlite3_bind_parameter_index"] = function () { + return (Module["_sqlite3_bind_parameter_index"] = + Module["asm"]["sqlite3_bind_parameter_index"]).apply(null, arguments); + }; - (Module['_sqlite3_db_handle'] = function () { - return (Module['_sqlite3_db_handle'] = - Module['asm']['sqlite3_db_handle']).apply(null, arguments); - }); + Module["_sqlite3_db_handle"] = function () { + return (Module["_sqlite3_db_handle"] = + Module["asm"]["sqlite3_db_handle"]).apply(null, arguments); + }; - (Module['_sqlite3_stmt_readonly'] = - function () { - return (Module['_sqlite3_stmt_readonly'] = - Module['asm']['sqlite3_stmt_readonly']).apply(null, arguments); - }); + Module["_sqlite3_stmt_readonly"] = function () { + return (Module["_sqlite3_stmt_readonly"] = + Module["asm"]["sqlite3_stmt_readonly"]).apply(null, arguments); + }; - (Module['_sqlite3_stmt_isexplain'] = - function () { - return (Module['_sqlite3_stmt_isexplain'] = - Module['asm']['sqlite3_stmt_isexplain']).apply(null, arguments); - }); + Module["_sqlite3_stmt_isexplain"] = function () { + return (Module["_sqlite3_stmt_isexplain"] = + Module["asm"]["sqlite3_stmt_isexplain"]).apply(null, arguments); + }; - (Module['_sqlite3_stmt_status'] = function () { - return (Module['_sqlite3_stmt_status'] = - Module['asm']['sqlite3_stmt_status']).apply(null, arguments); - }); + Module["_sqlite3_stmt_status"] = function () { + return (Module["_sqlite3_stmt_status"] = + Module["asm"]["sqlite3_stmt_status"]).apply(null, arguments); + }; - (Module['_sqlite3_sql'] = function () { - return (Module['_sqlite3_sql'] = - Module['asm']['sqlite3_sql']).apply(null, arguments); - }); + Module["_sqlite3_sql"] = function () { + return (Module["_sqlite3_sql"] = Module["asm"]["sqlite3_sql"]).apply( + null, + arguments + ); + }; - (Module['_sqlite3_expanded_sql'] = function () { - return (Module['_sqlite3_expanded_sql'] = - Module['asm']['sqlite3_expanded_sql']).apply(null, arguments); - }); + Module["_sqlite3_expanded_sql"] = function () { + return (Module["_sqlite3_expanded_sql"] = + Module["asm"]["sqlite3_expanded_sql"]).apply(null, arguments); + }; - (Module['_sqlite3_preupdate_old'] = - function () { - return (Module['_sqlite3_preupdate_old'] = - Module['asm']['sqlite3_preupdate_old']).apply(null, arguments); - }); + Module["_sqlite3_preupdate_old"] = function () { + return (Module["_sqlite3_preupdate_old"] = + Module["asm"]["sqlite3_preupdate_old"]).apply(null, arguments); + }; - (Module['_sqlite3_preupdate_count'] = - function () { - return (Module['_sqlite3_preupdate_count'] = - Module['asm']['sqlite3_preupdate_count']).apply(null, arguments); - }); + Module["_sqlite3_preupdate_count"] = function () { + return (Module["_sqlite3_preupdate_count"] = + Module["asm"]["sqlite3_preupdate_count"]).apply(null, arguments); + }; - (Module['_sqlite3_preupdate_depth'] = - function () { - return (Module['_sqlite3_preupdate_depth'] = - Module['asm']['sqlite3_preupdate_depth']).apply(null, arguments); - }); + Module["_sqlite3_preupdate_depth"] = function () { + return (Module["_sqlite3_preupdate_depth"] = + Module["asm"]["sqlite3_preupdate_depth"]).apply(null, arguments); + }; - (Module['_sqlite3_preupdate_blobwrite'] = - function () { - return (Module[ - '_sqlite3_preupdate_blobwrite' - ] = - Module['asm']['sqlite3_preupdate_blobwrite']).apply(null, arguments); - }); + Module["_sqlite3_preupdate_blobwrite"] = function () { + return (Module["_sqlite3_preupdate_blobwrite"] = + Module["asm"]["sqlite3_preupdate_blobwrite"]).apply(null, arguments); + }; - (Module['_sqlite3_preupdate_new'] = - function () { - return (Module['_sqlite3_preupdate_new'] = - Module['asm']['sqlite3_preupdate_new']).apply(null, arguments); - }); + Module["_sqlite3_preupdate_new"] = function () { + return (Module["_sqlite3_preupdate_new"] = + Module["asm"]["sqlite3_preupdate_new"]).apply(null, arguments); + }; - (Module['_sqlite3_value_numeric_type'] = - function () { - return (Module[ - '_sqlite3_value_numeric_type' - ] = - Module['asm']['sqlite3_value_numeric_type']).apply(null, arguments); - }); + Module["_sqlite3_value_numeric_type"] = function () { + return (Module["_sqlite3_value_numeric_type"] = + Module["asm"]["sqlite3_value_numeric_type"]).apply(null, arguments); + }; - (Module['_sqlite3_set_authorizer'] = - function () { - return (Module['_sqlite3_set_authorizer'] = - Module['asm']['sqlite3_set_authorizer']).apply(null, arguments); - }); + Module["_sqlite3_set_authorizer"] = function () { + return (Module["_sqlite3_set_authorizer"] = + Module["asm"]["sqlite3_set_authorizer"]).apply(null, arguments); + }; - (Module['_sqlite3_strglob'] = function () { - return (Module['_sqlite3_strglob'] = - Module['asm']['sqlite3_strglob']).apply(null, arguments); - }); + Module["_sqlite3_strglob"] = function () { + return (Module["_sqlite3_strglob"] = + Module["asm"]["sqlite3_strglob"]).apply(null, arguments); + }; - (Module['_sqlite3_strlike'] = function () { - return (Module['_sqlite3_strlike'] = - Module['asm']['sqlite3_strlike']).apply(null, arguments); - }); + Module["_sqlite3_strlike"] = function () { + return (Module["_sqlite3_strlike"] = + Module["asm"]["sqlite3_strlike"]).apply(null, arguments); + }; - (Module['_sqlite3_auto_extension'] = - function () { - return (Module['_sqlite3_auto_extension'] = - Module['asm']['sqlite3_auto_extension']).apply(null, arguments); - }); + Module["_sqlite3_auto_extension"] = function () { + return (Module["_sqlite3_auto_extension"] = + Module["asm"]["sqlite3_auto_extension"]).apply(null, arguments); + }; - (Module[ - '_sqlite3_cancel_auto_extension' - ] = function () { - return (Module[ - '_sqlite3_cancel_auto_extension' - ] = - Module['asm']['sqlite3_cancel_auto_extension']).apply(null, arguments); - }); + Module["_sqlite3_cancel_auto_extension"] = function () { + return (Module["_sqlite3_cancel_auto_extension"] = + Module["asm"]["sqlite3_cancel_auto_extension"]).apply(null, arguments); + }; - (Module[ - '_sqlite3_reset_auto_extension' - ] = function () { - return (Module[ - '_sqlite3_reset_auto_extension' - ] = - Module['asm']['sqlite3_reset_auto_extension']).apply(null, arguments); - }); + Module["_sqlite3_reset_auto_extension"] = function () { + return (Module["_sqlite3_reset_auto_extension"] = + Module["asm"]["sqlite3_reset_auto_extension"]).apply(null, arguments); + }; - (Module['_sqlite3_prepare_v3'] = function () { - return (Module['_sqlite3_prepare_v3'] = - Module['asm']['sqlite3_prepare_v3']).apply(null, arguments); - }); + Module["_sqlite3_prepare_v3"] = function () { + return (Module["_sqlite3_prepare_v3"] = + Module["asm"]["sqlite3_prepare_v3"]).apply(null, arguments); + }; - (Module['_sqlite3_create_module'] = - function () { - return (Module['_sqlite3_create_module'] = - Module['asm']['sqlite3_create_module']).apply(null, arguments); - }); + Module["_sqlite3_create_module"] = function () { + return (Module["_sqlite3_create_module"] = + Module["asm"]["sqlite3_create_module"]).apply(null, arguments); + }; - (Module['_sqlite3_create_module_v2'] = - function () { - return (Module[ - '_sqlite3_create_module_v2' - ] = - Module['asm']['sqlite3_create_module_v2']).apply(null, arguments); - }); + Module["_sqlite3_create_module_v2"] = function () { + return (Module["_sqlite3_create_module_v2"] = + Module["asm"]["sqlite3_create_module_v2"]).apply(null, arguments); + }; - (Module['_sqlite3_drop_modules'] = function () { - return (Module['_sqlite3_drop_modules'] = - Module['asm']['sqlite3_drop_modules']).apply(null, arguments); - }); + Module["_sqlite3_drop_modules"] = function () { + return (Module["_sqlite3_drop_modules"] = + Module["asm"]["sqlite3_drop_modules"]).apply(null, arguments); + }; - (Module['_sqlite3_declare_vtab'] = function () { - return (Module['_sqlite3_declare_vtab'] = - Module['asm']['sqlite3_declare_vtab']).apply(null, arguments); - }); + Module["_sqlite3_declare_vtab"] = function () { + return (Module["_sqlite3_declare_vtab"] = + Module["asm"]["sqlite3_declare_vtab"]).apply(null, arguments); + }; - (Module['_sqlite3_vtab_on_conflict'] = - function () { - return (Module[ - '_sqlite3_vtab_on_conflict' - ] = - Module['asm']['sqlite3_vtab_on_conflict']).apply(null, arguments); - }); + Module["_sqlite3_vtab_on_conflict"] = function () { + return (Module["_sqlite3_vtab_on_conflict"] = + Module["asm"]["sqlite3_vtab_on_conflict"]).apply(null, arguments); + }; - (Module['_sqlite3_vtab_collation'] = - function () { - return (Module['_sqlite3_vtab_collation'] = - Module['asm']['sqlite3_vtab_collation']).apply(null, arguments); - }); + Module["_sqlite3_vtab_collation"] = function () { + return (Module["_sqlite3_vtab_collation"] = + Module["asm"]["sqlite3_vtab_collation"]).apply(null, arguments); + }; - (Module['_sqlite3_vtab_in'] = function () { - return (Module['_sqlite3_vtab_in'] = - Module['asm']['sqlite3_vtab_in']).apply(null, arguments); - }); + Module["_sqlite3_vtab_in"] = function () { + return (Module["_sqlite3_vtab_in"] = + Module["asm"]["sqlite3_vtab_in"]).apply(null, arguments); + }; - (Module['_sqlite3_vtab_rhs_value'] = - function () { - return (Module['_sqlite3_vtab_rhs_value'] = - Module['asm']['sqlite3_vtab_rhs_value']).apply(null, arguments); - }); + Module["_sqlite3_vtab_rhs_value"] = function () { + return (Module["_sqlite3_vtab_rhs_value"] = + Module["asm"]["sqlite3_vtab_rhs_value"]).apply(null, arguments); + }; - (Module['_sqlite3_vtab_distinct'] = - function () { - return (Module['_sqlite3_vtab_distinct'] = - Module['asm']['sqlite3_vtab_distinct']).apply(null, arguments); - }); + Module["_sqlite3_vtab_distinct"] = function () { + return (Module["_sqlite3_vtab_distinct"] = + Module["asm"]["sqlite3_vtab_distinct"]).apply(null, arguments); + }; - (Module['_sqlite3_keyword_name'] = function () { - return (Module['_sqlite3_keyword_name'] = - Module['asm']['sqlite3_keyword_name']).apply(null, arguments); - }); + Module["_sqlite3_keyword_name"] = function () { + return (Module["_sqlite3_keyword_name"] = + Module["asm"]["sqlite3_keyword_name"]).apply(null, arguments); + }; - (Module['_sqlite3_keyword_count'] = - function () { - return (Module['_sqlite3_keyword_count'] = - Module['asm']['sqlite3_keyword_count']).apply(null, arguments); - }); + Module["_sqlite3_keyword_count"] = function () { + return (Module["_sqlite3_keyword_count"] = + Module["asm"]["sqlite3_keyword_count"]).apply(null, arguments); + }; - (Module['_sqlite3_keyword_check'] = - function () { - return (Module['_sqlite3_keyword_check'] = - Module['asm']['sqlite3_keyword_check']).apply(null, arguments); - }); + Module["_sqlite3_keyword_check"] = function () { + return (Module["_sqlite3_keyword_check"] = + Module["asm"]["sqlite3_keyword_check"]).apply(null, arguments); + }; - (Module['_sqlite3_complete'] = function () { - return (Module['_sqlite3_complete'] = - Module['asm']['sqlite3_complete']).apply(null, arguments); - }); + Module["_sqlite3_complete"] = function () { + return (Module["_sqlite3_complete"] = + Module["asm"]["sqlite3_complete"]).apply(null, arguments); + }; - (Module['_sqlite3_libversion'] = function () { - return (Module['_sqlite3_libversion'] = - Module['asm']['sqlite3_libversion']).apply(null, arguments); - }); + Module["_sqlite3_libversion"] = function () { + return (Module["_sqlite3_libversion"] = + Module["asm"]["sqlite3_libversion"]).apply(null, arguments); + }; - (Module['_sqlite3_libversion_number'] = - function () { - return (Module[ - '_sqlite3_libversion_number' - ] = - Module['asm']['sqlite3_libversion_number']).apply(null, arguments); - }); + Module["_sqlite3_libversion_number"] = function () { + return (Module["_sqlite3_libversion_number"] = + Module["asm"]["sqlite3_libversion_number"]).apply(null, arguments); + }; - (Module['_sqlite3_shutdown'] = function () { - return (Module['_sqlite3_shutdown'] = - Module['asm']['sqlite3_shutdown']).apply(null, arguments); - }); + Module["_sqlite3_shutdown"] = function () { + return (Module["_sqlite3_shutdown"] = + Module["asm"]["sqlite3_shutdown"]).apply(null, arguments); + }; - (Module['_sqlite3_last_insert_rowid'] = - function () { - return (Module[ - '_sqlite3_last_insert_rowid' - ] = - Module['asm']['sqlite3_last_insert_rowid']).apply(null, arguments); - }); + Module["_sqlite3_last_insert_rowid"] = function () { + return (Module["_sqlite3_last_insert_rowid"] = + Module["asm"]["sqlite3_last_insert_rowid"]).apply(null, arguments); + }; - (Module[ - '_sqlite3_set_last_insert_rowid' - ] = function () { - return (Module[ - '_sqlite3_set_last_insert_rowid' - ] = - Module['asm']['sqlite3_set_last_insert_rowid']).apply(null, arguments); - }); + Module["_sqlite3_set_last_insert_rowid"] = function () { + return (Module["_sqlite3_set_last_insert_rowid"] = + Module["asm"]["sqlite3_set_last_insert_rowid"]).apply(null, arguments); + }; - (Module['_sqlite3_changes64'] = function () { - return (Module['_sqlite3_changes64'] = - Module['asm']['sqlite3_changes64']).apply(null, arguments); - }); + Module["_sqlite3_changes64"] = function () { + return (Module["_sqlite3_changes64"] = + Module["asm"]["sqlite3_changes64"]).apply(null, arguments); + }; - (Module['_sqlite3_changes'] = function () { - return (Module['_sqlite3_changes'] = - Module['asm']['sqlite3_changes']).apply(null, arguments); - }); + Module["_sqlite3_changes"] = function () { + return (Module["_sqlite3_changes"] = + Module["asm"]["sqlite3_changes"]).apply(null, arguments); + }; - (Module['_sqlite3_total_changes64'] = - function () { - return (Module['_sqlite3_total_changes64'] = - Module['asm']['sqlite3_total_changes64']).apply(null, arguments); - }); + Module["_sqlite3_total_changes64"] = function () { + return (Module["_sqlite3_total_changes64"] = + Module["asm"]["sqlite3_total_changes64"]).apply(null, arguments); + }; - (Module['_sqlite3_total_changes'] = - function () { - return (Module['_sqlite3_total_changes'] = - Module['asm']['sqlite3_total_changes']).apply(null, arguments); - }); + Module["_sqlite3_total_changes"] = function () { + return (Module["_sqlite3_total_changes"] = + Module["asm"]["sqlite3_total_changes"]).apply(null, arguments); + }; - (Module['_sqlite3_txn_state'] = function () { - return (Module['_sqlite3_txn_state'] = - Module['asm']['sqlite3_txn_state']).apply(null, arguments); - }); + Module["_sqlite3_txn_state"] = function () { + return (Module["_sqlite3_txn_state"] = + Module["asm"]["sqlite3_txn_state"]).apply(null, arguments); + }; - (Module['_sqlite3_close_v2'] = function () { - return (Module['_sqlite3_close_v2'] = - Module['asm']['sqlite3_close_v2']).apply(null, arguments); - }); + Module["_sqlite3_close_v2"] = function () { + return (Module["_sqlite3_close_v2"] = + Module["asm"]["sqlite3_close_v2"]).apply(null, arguments); + }; - (Module['_sqlite3_busy_handler'] = function () { - return (Module['_sqlite3_busy_handler'] = - Module['asm']['sqlite3_busy_handler']).apply(null, arguments); - }); + Module["_sqlite3_busy_handler"] = function () { + return (Module["_sqlite3_busy_handler"] = + Module["asm"]["sqlite3_busy_handler"]).apply(null, arguments); + }; - (Module['_sqlite3_progress_handler'] = - function () { - return (Module[ - '_sqlite3_progress_handler' - ] = - Module['asm']['sqlite3_progress_handler']).apply(null, arguments); - }); + Module["_sqlite3_progress_handler"] = function () { + return (Module["_sqlite3_progress_handler"] = + Module["asm"]["sqlite3_progress_handler"]).apply(null, arguments); + }; - (Module['_sqlite3_busy_timeout'] = function () { - return (Module['_sqlite3_busy_timeout'] = - Module['asm']['sqlite3_busy_timeout']).apply(null, arguments); - }); + Module["_sqlite3_busy_timeout"] = function () { + return (Module["_sqlite3_busy_timeout"] = + Module["asm"]["sqlite3_busy_timeout"]).apply(null, arguments); + }; - (Module['_sqlite3_create_function'] = - function () { - return (Module['_sqlite3_create_function'] = - Module['asm']['sqlite3_create_function']).apply(null, arguments); - }); + Module["_sqlite3_create_function"] = function () { + return (Module["_sqlite3_create_function"] = + Module["asm"]["sqlite3_create_function"]).apply(null, arguments); + }; - (Module['_sqlite3_create_function_v2'] = - function () { - return (Module[ - '_sqlite3_create_function_v2' - ] = - Module['asm']['sqlite3_create_function_v2']).apply(null, arguments); - }); + Module["_sqlite3_create_function_v2"] = function () { + return (Module["_sqlite3_create_function_v2"] = + Module["asm"]["sqlite3_create_function_v2"]).apply(null, arguments); + }; - (Module[ - '_sqlite3_create_window_function' - ] = function () { - return (Module[ - '_sqlite3_create_window_function' - ] = - Module['asm']['sqlite3_create_window_function']).apply(null, arguments); - }); + Module["_sqlite3_create_window_function"] = function () { + return (Module["_sqlite3_create_window_function"] = + Module["asm"]["sqlite3_create_window_function"]).apply(null, arguments); + }; - (Module['_sqlite3_overload_function'] = - function () { - return (Module[ - '_sqlite3_overload_function' - ] = - Module['asm']['sqlite3_overload_function']).apply(null, arguments); - }); + Module["_sqlite3_overload_function"] = function () { + return (Module["_sqlite3_overload_function"] = + Module["asm"]["sqlite3_overload_function"]).apply(null, arguments); + }; - (Module['_sqlite3_trace_v2'] = function () { - return (Module['_sqlite3_trace_v2'] = - Module['asm']['sqlite3_trace_v2']).apply(null, arguments); - }); + Module["_sqlite3_trace_v2"] = function () { + return (Module["_sqlite3_trace_v2"] = + Module["asm"]["sqlite3_trace_v2"]).apply(null, arguments); + }; - (Module['_sqlite3_commit_hook'] = function () { - return (Module['_sqlite3_commit_hook'] = - Module['asm']['sqlite3_commit_hook']).apply(null, arguments); - }); + Module["_sqlite3_commit_hook"] = function () { + return (Module["_sqlite3_commit_hook"] = + Module["asm"]["sqlite3_commit_hook"]).apply(null, arguments); + }; - (Module['_sqlite3_update_hook'] = function () { - return (Module['_sqlite3_update_hook'] = - Module['asm']['sqlite3_update_hook']).apply(null, arguments); - }); + Module["_sqlite3_update_hook"] = function () { + return (Module["_sqlite3_update_hook"] = + Module["asm"]["sqlite3_update_hook"]).apply(null, arguments); + }; - (Module['_sqlite3_rollback_hook'] = - function () { - return (Module['_sqlite3_rollback_hook'] = - Module['asm']['sqlite3_rollback_hook']).apply(null, arguments); - }); + Module["_sqlite3_rollback_hook"] = function () { + return (Module["_sqlite3_rollback_hook"] = + Module["asm"]["sqlite3_rollback_hook"]).apply(null, arguments); + }; - (Module['_sqlite3_preupdate_hook'] = - function () { - return (Module['_sqlite3_preupdate_hook'] = - Module['asm']['sqlite3_preupdate_hook']).apply(null, arguments); - }); + Module["_sqlite3_preupdate_hook"] = function () { + return (Module["_sqlite3_preupdate_hook"] = + Module["asm"]["sqlite3_preupdate_hook"]).apply(null, arguments); + }; - (Module['_sqlite3_error_offset'] = function () { - return (Module['_sqlite3_error_offset'] = - Module['asm']['sqlite3_error_offset']).apply(null, arguments); - }); + Module["_sqlite3_error_offset"] = function () { + return (Module["_sqlite3_error_offset"] = + Module["asm"]["sqlite3_error_offset"]).apply(null, arguments); + }; - (Module['_sqlite3_errcode'] = function () { - return (Module['_sqlite3_errcode'] = - Module['asm']['sqlite3_errcode']).apply(null, arguments); - }); + Module["_sqlite3_errcode"] = function () { + return (Module["_sqlite3_errcode"] = + Module["asm"]["sqlite3_errcode"]).apply(null, arguments); + }; - (Module['_sqlite3_extended_errcode'] = - function () { - return (Module[ - '_sqlite3_extended_errcode' - ] = - Module['asm']['sqlite3_extended_errcode']).apply(null, arguments); - }); + Module["_sqlite3_extended_errcode"] = function () { + return (Module["_sqlite3_extended_errcode"] = + Module["asm"]["sqlite3_extended_errcode"]).apply(null, arguments); + }; - (Module['_sqlite3_errstr'] = function () { - return (Module['_sqlite3_errstr'] = - Module['asm']['sqlite3_errstr']).apply(null, arguments); - }); + Module["_sqlite3_errstr"] = function () { + return (Module["_sqlite3_errstr"] = + Module["asm"]["sqlite3_errstr"]).apply(null, arguments); + }; - (Module['_sqlite3_limit'] = function () { - return (Module['_sqlite3_limit'] = - Module['asm']['sqlite3_limit']).apply(null, arguments); - }); + Module["_sqlite3_limit"] = function () { + return (Module["_sqlite3_limit"] = Module["asm"]["sqlite3_limit"]).apply( + null, + arguments + ); + }; - (Module['_sqlite3_open'] = function () { - return (Module['_sqlite3_open'] = - Module['asm']['sqlite3_open']).apply(null, arguments); - }); + Module["_sqlite3_open"] = function () { + return (Module["_sqlite3_open"] = Module["asm"]["sqlite3_open"]).apply( + null, + arguments + ); + }; - (Module['_sqlite3_open_v2'] = function () { - return (Module['_sqlite3_open_v2'] = - Module['asm']['sqlite3_open_v2']).apply(null, arguments); - }); + Module["_sqlite3_open_v2"] = function () { + return (Module["_sqlite3_open_v2"] = + Module["asm"]["sqlite3_open_v2"]).apply(null, arguments); + }; - (Module['_sqlite3_create_collation'] = - function () { - return (Module[ - '_sqlite3_create_collation' - ] = - Module['asm']['sqlite3_create_collation']).apply(null, arguments); - }); + Module["_sqlite3_create_collation"] = function () { + return (Module["_sqlite3_create_collation"] = + Module["asm"]["sqlite3_create_collation"]).apply(null, arguments); + }; - (Module['_sqlite3_create_collation_v2'] = - function () { - return (Module[ - '_sqlite3_create_collation_v2' - ] = - Module['asm']['sqlite3_create_collation_v2']).apply(null, arguments); - }); + Module["_sqlite3_create_collation_v2"] = function () { + return (Module["_sqlite3_create_collation_v2"] = + Module["asm"]["sqlite3_create_collation_v2"]).apply(null, arguments); + }; - (Module['_sqlite3_collation_needed'] = - function () { - return (Module[ - '_sqlite3_collation_needed' - ] = - Module['asm']['sqlite3_collation_needed']).apply(null, arguments); - }); + Module["_sqlite3_collation_needed"] = function () { + return (Module["_sqlite3_collation_needed"] = + Module["asm"]["sqlite3_collation_needed"]).apply(null, arguments); + }; - (Module['_sqlite3_get_autocommit'] = - function () { - return (Module['_sqlite3_get_autocommit'] = - Module['asm']['sqlite3_get_autocommit']).apply(null, arguments); - }); + Module["_sqlite3_get_autocommit"] = function () { + return (Module["_sqlite3_get_autocommit"] = + Module["asm"]["sqlite3_get_autocommit"]).apply(null, arguments); + }; - (Module[ - '_sqlite3_table_column_metadata' - ] = function () { - return (Module[ - '_sqlite3_table_column_metadata' - ] = - Module['asm']['sqlite3_table_column_metadata']).apply(null, arguments); - }); + Module["_sqlite3_table_column_metadata"] = function () { + return (Module["_sqlite3_table_column_metadata"] = + Module["asm"]["sqlite3_table_column_metadata"]).apply(null, arguments); + }; - (Module[ - '_sqlite3_extended_result_codes' - ] = function () { - return (Module[ - '_sqlite3_extended_result_codes' - ] = - Module['asm']['sqlite3_extended_result_codes']).apply(null, arguments); - }); + Module["_sqlite3_extended_result_codes"] = function () { + return (Module["_sqlite3_extended_result_codes"] = + Module["asm"]["sqlite3_extended_result_codes"]).apply(null, arguments); + }; - (Module['_sqlite3_uri_key'] = function () { - return (Module['_sqlite3_uri_key'] = - Module['asm']['sqlite3_uri_key']).apply(null, arguments); - }); + Module["_sqlite3_uri_key"] = function () { + return (Module["_sqlite3_uri_key"] = + Module["asm"]["sqlite3_uri_key"]).apply(null, arguments); + }; - (Module['_sqlite3_uri_int64'] = function () { - return (Module['_sqlite3_uri_int64'] = - Module['asm']['sqlite3_uri_int64']).apply(null, arguments); - }); + Module["_sqlite3_uri_int64"] = function () { + return (Module["_sqlite3_uri_int64"] = + Module["asm"]["sqlite3_uri_int64"]).apply(null, arguments); + }; - (Module['_sqlite3_db_name'] = function () { - return (Module['_sqlite3_db_name'] = - Module['asm']['sqlite3_db_name']).apply(null, arguments); - }); + Module["_sqlite3_db_name"] = function () { + return (Module["_sqlite3_db_name"] = + Module["asm"]["sqlite3_db_name"]).apply(null, arguments); + }; - (Module['_sqlite3_db_filename'] = function () { - return (Module['_sqlite3_db_filename'] = - Module['asm']['sqlite3_db_filename']).apply(null, arguments); - }); + Module["_sqlite3_db_filename"] = function () { + return (Module["_sqlite3_db_filename"] = + Module["asm"]["sqlite3_db_filename"]).apply(null, arguments); + }; - (Module['_sqlite3_compileoption_used'] = - function () { - return (Module[ - '_sqlite3_compileoption_used' - ] = - Module['asm']['sqlite3_compileoption_used']).apply(null, arguments); - }); + Module["_sqlite3_compileoption_used"] = function () { + return (Module["_sqlite3_compileoption_used"] = + Module["asm"]["sqlite3_compileoption_used"]).apply(null, arguments); + }; - (Module['_sqlite3_compileoption_get'] = - function () { - return (Module[ - '_sqlite3_compileoption_get' - ] = - Module['asm']['sqlite3_compileoption_get']).apply(null, arguments); - }); + Module["_sqlite3_compileoption_get"] = function () { + return (Module["_sqlite3_compileoption_get"] = + Module["asm"]["sqlite3_compileoption_get"]).apply(null, arguments); + }; - (Module['_sqlite3session_diff'] = function () { - return (Module['_sqlite3session_diff'] = - Module['asm']['sqlite3session_diff']).apply(null, arguments); - }); + Module["_sqlite3session_diff"] = function () { + return (Module["_sqlite3session_diff"] = + Module["asm"]["sqlite3session_diff"]).apply(null, arguments); + }; - (Module['_sqlite3session_attach'] = - function () { - return (Module['_sqlite3session_attach'] = - Module['asm']['sqlite3session_attach']).apply(null, arguments); - }); + Module["_sqlite3session_attach"] = function () { + return (Module["_sqlite3session_attach"] = + Module["asm"]["sqlite3session_attach"]).apply(null, arguments); + }; - (Module['_sqlite3session_create'] = - function () { - return (Module['_sqlite3session_create'] = - Module['asm']['sqlite3session_create']).apply(null, arguments); - }); + Module["_sqlite3session_create"] = function () { + return (Module["_sqlite3session_create"] = + Module["asm"]["sqlite3session_create"]).apply(null, arguments); + }; - (Module['_sqlite3session_delete'] = - function () { - return (Module['_sqlite3session_delete'] = - Module['asm']['sqlite3session_delete']).apply(null, arguments); - }); + Module["_sqlite3session_delete"] = function () { + return (Module["_sqlite3session_delete"] = + Module["asm"]["sqlite3session_delete"]).apply(null, arguments); + }; - (Module['_sqlite3session_table_filter'] = - function () { - return (Module[ - '_sqlite3session_table_filter' - ] = - Module['asm']['sqlite3session_table_filter']).apply(null, arguments); - }); + Module["_sqlite3session_table_filter"] = function () { + return (Module["_sqlite3session_table_filter"] = + Module["asm"]["sqlite3session_table_filter"]).apply(null, arguments); + }; - (Module['_sqlite3session_changeset'] = - function () { - return (Module[ - '_sqlite3session_changeset' - ] = - Module['asm']['sqlite3session_changeset']).apply(null, arguments); - }); + Module["_sqlite3session_changeset"] = function () { + return (Module["_sqlite3session_changeset"] = + Module["asm"]["sqlite3session_changeset"]).apply(null, arguments); + }; - (Module[ - '_sqlite3session_changeset_strm' - ] = function () { - return (Module[ - '_sqlite3session_changeset_strm' - ] = - Module['asm']['sqlite3session_changeset_strm']).apply(null, arguments); - }); + Module["_sqlite3session_changeset_strm"] = function () { + return (Module["_sqlite3session_changeset_strm"] = + Module["asm"]["sqlite3session_changeset_strm"]).apply(null, arguments); + }; - (Module[ - '_sqlite3session_patchset_strm' - ] = function () { - return (Module[ - '_sqlite3session_patchset_strm' - ] = - Module['asm']['sqlite3session_patchset_strm']).apply(null, arguments); - }); + Module["_sqlite3session_patchset_strm"] = function () { + return (Module["_sqlite3session_patchset_strm"] = + Module["asm"]["sqlite3session_patchset_strm"]).apply(null, arguments); + }; - (Module['_sqlite3session_patchset'] = - function () { - return (Module['_sqlite3session_patchset'] = - Module['asm']['sqlite3session_patchset']).apply(null, arguments); - }); + Module["_sqlite3session_patchset"] = function () { + return (Module["_sqlite3session_patchset"] = + Module["asm"]["sqlite3session_patchset"]).apply(null, arguments); + }; - (Module['_sqlite3session_enable'] = - function () { - return (Module['_sqlite3session_enable'] = - Module['asm']['sqlite3session_enable']).apply(null, arguments); - }); + Module["_sqlite3session_enable"] = function () { + return (Module["_sqlite3session_enable"] = + Module["asm"]["sqlite3session_enable"]).apply(null, arguments); + }; - (Module['_sqlite3session_indirect'] = - function () { - return (Module['_sqlite3session_indirect'] = - Module['asm']['sqlite3session_indirect']).apply(null, arguments); - }); + Module["_sqlite3session_indirect"] = function () { + return (Module["_sqlite3session_indirect"] = + Module["asm"]["sqlite3session_indirect"]).apply(null, arguments); + }; - (Module['_sqlite3session_isempty'] = - function () { - return (Module['_sqlite3session_isempty'] = - Module['asm']['sqlite3session_isempty']).apply(null, arguments); - }); + Module["_sqlite3session_isempty"] = function () { + return (Module["_sqlite3session_isempty"] = + Module["asm"]["sqlite3session_isempty"]).apply(null, arguments); + }; - (Module['_sqlite3session_memory_used'] = - function () { - return (Module[ - '_sqlite3session_memory_used' - ] = - Module['asm']['sqlite3session_memory_used']).apply(null, arguments); - }); + Module["_sqlite3session_memory_used"] = function () { + return (Module["_sqlite3session_memory_used"] = + Module["asm"]["sqlite3session_memory_used"]).apply(null, arguments); + }; - (Module[ - '_sqlite3session_object_config' - ] = function () { - return (Module[ - '_sqlite3session_object_config' - ] = - Module['asm']['sqlite3session_object_config']).apply(null, arguments); - }); + Module["_sqlite3session_object_config"] = function () { + return (Module["_sqlite3session_object_config"] = + Module["asm"]["sqlite3session_object_config"]).apply(null, arguments); + }; - (Module[ - '_sqlite3session_changeset_size' - ] = function () { - return (Module[ - '_sqlite3session_changeset_size' - ] = - Module['asm']['sqlite3session_changeset_size']).apply(null, arguments); - }); + Module["_sqlite3session_changeset_size"] = function () { + return (Module["_sqlite3session_changeset_size"] = + Module["asm"]["sqlite3session_changeset_size"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_start'] = - function () { - return (Module['_sqlite3changeset_start'] = - Module['asm']['sqlite3changeset_start']).apply(null, arguments); - }); + Module["_sqlite3changeset_start"] = function () { + return (Module["_sqlite3changeset_start"] = + Module["asm"]["sqlite3changeset_start"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_start_v2'] = - function () { - return (Module[ - '_sqlite3changeset_start_v2' - ] = - Module['asm']['sqlite3changeset_start_v2']).apply(null, arguments); - }); + Module["_sqlite3changeset_start_v2"] = function () { + return (Module["_sqlite3changeset_start_v2"] = + Module["asm"]["sqlite3changeset_start_v2"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_start_strm'] = - function () { - return (Module[ - '_sqlite3changeset_start_strm' - ] = - Module['asm']['sqlite3changeset_start_strm']).apply(null, arguments); - }); + Module["_sqlite3changeset_start_strm"] = function () { + return (Module["_sqlite3changeset_start_strm"] = + Module["asm"]["sqlite3changeset_start_strm"]).apply(null, arguments); + }; - (Module[ - '_sqlite3changeset_start_v2_strm' - ] = function () { - return (Module[ - '_sqlite3changeset_start_v2_strm' - ] = - Module['asm']['sqlite3changeset_start_v2_strm']).apply(null, arguments); - }); + Module["_sqlite3changeset_start_v2_strm"] = function () { + return (Module["_sqlite3changeset_start_v2_strm"] = + Module["asm"]["sqlite3changeset_start_v2_strm"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_next'] = - function () { - return (Module['_sqlite3changeset_next'] = - Module['asm']['sqlite3changeset_next']).apply(null, arguments); - }); + Module["_sqlite3changeset_next"] = function () { + return (Module["_sqlite3changeset_next"] = + Module["asm"]["sqlite3changeset_next"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_op'] = function () { - return (Module['_sqlite3changeset_op'] = - Module['asm']['sqlite3changeset_op']).apply(null, arguments); - }); + Module["_sqlite3changeset_op"] = function () { + return (Module["_sqlite3changeset_op"] = + Module["asm"]["sqlite3changeset_op"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_pk'] = function () { - return (Module['_sqlite3changeset_pk'] = - Module['asm']['sqlite3changeset_pk']).apply(null, arguments); - }); + Module["_sqlite3changeset_pk"] = function () { + return (Module["_sqlite3changeset_pk"] = + Module["asm"]["sqlite3changeset_pk"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_old'] = function () { - return (Module['_sqlite3changeset_old'] = - Module['asm']['sqlite3changeset_old']).apply(null, arguments); - }); + Module["_sqlite3changeset_old"] = function () { + return (Module["_sqlite3changeset_old"] = + Module["asm"]["sqlite3changeset_old"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_new'] = function () { - return (Module['_sqlite3changeset_new'] = - Module['asm']['sqlite3changeset_new']).apply(null, arguments); - }); + Module["_sqlite3changeset_new"] = function () { + return (Module["_sqlite3changeset_new"] = + Module["asm"]["sqlite3changeset_new"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_conflict'] = - function () { - return (Module[ - '_sqlite3changeset_conflict' - ] = - Module['asm']['sqlite3changeset_conflict']).apply(null, arguments); - }); + Module["_sqlite3changeset_conflict"] = function () { + return (Module["_sqlite3changeset_conflict"] = + Module["asm"]["sqlite3changeset_conflict"]).apply(null, arguments); + }; - (Module[ - '_sqlite3changeset_fk_conflicts' - ] = function () { - return (Module[ - '_sqlite3changeset_fk_conflicts' - ] = - Module['asm']['sqlite3changeset_fk_conflicts']).apply(null, arguments); - }); + Module["_sqlite3changeset_fk_conflicts"] = function () { + return (Module["_sqlite3changeset_fk_conflicts"] = + Module["asm"]["sqlite3changeset_fk_conflicts"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_finalize'] = - function () { - return (Module[ - '_sqlite3changeset_finalize' - ] = - Module['asm']['sqlite3changeset_finalize']).apply(null, arguments); - }); + Module["_sqlite3changeset_finalize"] = function () { + return (Module["_sqlite3changeset_finalize"] = + Module["asm"]["sqlite3changeset_finalize"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_invert'] = - function () { - return (Module['_sqlite3changeset_invert'] = - Module['asm']['sqlite3changeset_invert']).apply(null, arguments); - }); + Module["_sqlite3changeset_invert"] = function () { + return (Module["_sqlite3changeset_invert"] = + Module["asm"]["sqlite3changeset_invert"]).apply(null, arguments); + }; - (Module[ - '_sqlite3changeset_invert_strm' - ] = function () { - return (Module[ - '_sqlite3changeset_invert_strm' - ] = - Module['asm']['sqlite3changeset_invert_strm']).apply(null, arguments); - }); + Module["_sqlite3changeset_invert_strm"] = function () { + return (Module["_sqlite3changeset_invert_strm"] = + Module["asm"]["sqlite3changeset_invert_strm"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_apply_v2'] = - function () { - return (Module[ - '_sqlite3changeset_apply_v2' - ] = - Module['asm']['sqlite3changeset_apply_v2']).apply(null, arguments); - }); + Module["_sqlite3changeset_apply_v2"] = function () { + return (Module["_sqlite3changeset_apply_v2"] = + Module["asm"]["sqlite3changeset_apply_v2"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_apply'] = - function () { - return (Module['_sqlite3changeset_apply'] = - Module['asm']['sqlite3changeset_apply']).apply(null, arguments); - }); + Module["_sqlite3changeset_apply"] = function () { + return (Module["_sqlite3changeset_apply"] = + Module["asm"]["sqlite3changeset_apply"]).apply(null, arguments); + }; - (Module[ - '_sqlite3changeset_apply_v2_strm' - ] = function () { - return (Module[ - '_sqlite3changeset_apply_v2_strm' - ] = - Module['asm']['sqlite3changeset_apply_v2_strm']).apply(null, arguments); - }); + Module["_sqlite3changeset_apply_v2_strm"] = function () { + return (Module["_sqlite3changeset_apply_v2_strm"] = + Module["asm"]["sqlite3changeset_apply_v2_strm"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_apply_strm'] = - function () { - return (Module[ - '_sqlite3changeset_apply_strm' - ] = - Module['asm']['sqlite3changeset_apply_strm']).apply(null, arguments); - }); + Module["_sqlite3changeset_apply_strm"] = function () { + return (Module["_sqlite3changeset_apply_strm"] = + Module["asm"]["sqlite3changeset_apply_strm"]).apply(null, arguments); + }; - (Module['_sqlite3changegroup_new'] = - function () { - return (Module['_sqlite3changegroup_new'] = - Module['asm']['sqlite3changegroup_new']).apply(null, arguments); - }); + Module["_sqlite3changegroup_new"] = function () { + return (Module["_sqlite3changegroup_new"] = + Module["asm"]["sqlite3changegroup_new"]).apply(null, arguments); + }; - (Module['_sqlite3changegroup_add'] = - function () { - return (Module['_sqlite3changegroup_add'] = - Module['asm']['sqlite3changegroup_add']).apply(null, arguments); - }); + Module["_sqlite3changegroup_add"] = function () { + return (Module["_sqlite3changegroup_add"] = + Module["asm"]["sqlite3changegroup_add"]).apply(null, arguments); + }; - (Module['_sqlite3changegroup_output'] = - function () { - return (Module[ - '_sqlite3changegroup_output' - ] = - Module['asm']['sqlite3changegroup_output']).apply(null, arguments); - }); + Module["_sqlite3changegroup_output"] = function () { + return (Module["_sqlite3changegroup_output"] = + Module["asm"]["sqlite3changegroup_output"]).apply(null, arguments); + }; - (Module['_sqlite3changegroup_add_strm'] = - function () { - return (Module[ - '_sqlite3changegroup_add_strm' - ] = - Module['asm']['sqlite3changegroup_add_strm']).apply(null, arguments); - }); + Module["_sqlite3changegroup_add_strm"] = function () { + return (Module["_sqlite3changegroup_add_strm"] = + Module["asm"]["sqlite3changegroup_add_strm"]).apply(null, arguments); + }; - (Module[ - '_sqlite3changegroup_output_strm' - ] = function () { - return (Module[ - '_sqlite3changegroup_output_strm' - ] = - Module['asm']['sqlite3changegroup_output_strm']).apply(null, arguments); - }); + Module["_sqlite3changegroup_output_strm"] = function () { + return (Module["_sqlite3changegroup_output_strm"] = + Module["asm"]["sqlite3changegroup_output_strm"]).apply(null, arguments); + }; - (Module['_sqlite3changegroup_delete'] = - function () { - return (Module[ - '_sqlite3changegroup_delete' - ] = - Module['asm']['sqlite3changegroup_delete']).apply(null, arguments); - }); + Module["_sqlite3changegroup_delete"] = function () { + return (Module["_sqlite3changegroup_delete"] = + Module["asm"]["sqlite3changegroup_delete"]).apply(null, arguments); + }; - (Module['_sqlite3changeset_concat'] = - function () { - return (Module['_sqlite3changeset_concat'] = - Module['asm']['sqlite3changeset_concat']).apply(null, arguments); - }); + Module["_sqlite3changeset_concat"] = function () { + return (Module["_sqlite3changeset_concat"] = + Module["asm"]["sqlite3changeset_concat"]).apply(null, arguments); + }; - (Module[ - '_sqlite3changeset_concat_strm' - ] = function () { - return (Module[ - '_sqlite3changeset_concat_strm' - ] = - Module['asm']['sqlite3changeset_concat_strm']).apply(null, arguments); - }); + Module["_sqlite3changeset_concat_strm"] = function () { + return (Module["_sqlite3changeset_concat_strm"] = + Module["asm"]["sqlite3changeset_concat_strm"]).apply(null, arguments); + }; - (Module['_sqlite3session_config'] = - function () { - return (Module['_sqlite3session_config'] = - Module['asm']['sqlite3session_config']).apply(null, arguments); - }); + Module["_sqlite3session_config"] = function () { + return (Module["_sqlite3session_config"] = + Module["asm"]["sqlite3session_config"]).apply(null, arguments); + }; - (Module['_sqlite3_sourceid'] = function () { - return (Module['_sqlite3_sourceid'] = - Module['asm']['sqlite3_sourceid']).apply(null, arguments); - }); + Module["_sqlite3_sourceid"] = function () { + return (Module["_sqlite3_sourceid"] = + Module["asm"]["sqlite3_sourceid"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_pstack_ptr'] = - function () { - return (Module[ - '_sqlite3__wasm_pstack_ptr' - ] = - Module['asm']['sqlite3__wasm_pstack_ptr']).apply(null, arguments); - }); + Module["_sqlite3__wasm_pstack_ptr"] = function () { + return (Module["_sqlite3__wasm_pstack_ptr"] = + Module["asm"]["sqlite3__wasm_pstack_ptr"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_pstack_restore' - ] = function () { - return (Module[ - '_sqlite3__wasm_pstack_restore' - ] = - Module['asm']['sqlite3__wasm_pstack_restore']).apply(null, arguments); - }); + Module["_sqlite3__wasm_pstack_restore"] = function () { + return (Module["_sqlite3__wasm_pstack_restore"] = + Module["asm"]["sqlite3__wasm_pstack_restore"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_pstack_alloc'] = - function () { - return (Module[ - '_sqlite3__wasm_pstack_alloc' - ] = - Module['asm']['sqlite3__wasm_pstack_alloc']).apply(null, arguments); - }); + Module["_sqlite3__wasm_pstack_alloc"] = function () { + return (Module["_sqlite3__wasm_pstack_alloc"] = + Module["asm"]["sqlite3__wasm_pstack_alloc"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_pstack_remaining' - ] = function () { - return (Module[ - '_sqlite3__wasm_pstack_remaining' - ] = - Module['asm']['sqlite3__wasm_pstack_remaining']).apply(null, arguments); - }); + Module["_sqlite3__wasm_pstack_remaining"] = function () { + return (Module["_sqlite3__wasm_pstack_remaining"] = + Module["asm"]["sqlite3__wasm_pstack_remaining"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_pstack_quota'] = - function () { - return (Module[ - '_sqlite3__wasm_pstack_quota' - ] = - Module['asm']['sqlite3__wasm_pstack_quota']).apply(null, arguments); - }); + Module["_sqlite3__wasm_pstack_quota"] = function () { + return (Module["_sqlite3__wasm_pstack_quota"] = + Module["asm"]["sqlite3__wasm_pstack_quota"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_db_error'] = - function () { - return (Module['_sqlite3__wasm_db_error'] = - Module['asm']['sqlite3__wasm_db_error']).apply(null, arguments); - }); + Module["_sqlite3__wasm_db_error"] = function () { + return (Module["_sqlite3__wasm_db_error"] = + Module["asm"]["sqlite3__wasm_db_error"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_test_struct'] = - function () { - return (Module[ - '_sqlite3__wasm_test_struct' - ] = - Module['asm']['sqlite3__wasm_test_struct']).apply(null, arguments); - }); + Module["_sqlite3__wasm_test_struct"] = function () { + return (Module["_sqlite3__wasm_test_struct"] = + Module["asm"]["sqlite3__wasm_test_struct"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_enum_json'] = - function () { - return (Module['_sqlite3__wasm_enum_json'] = - Module['asm']['sqlite3__wasm_enum_json']).apply(null, arguments); - }); + Module["_sqlite3__wasm_enum_json"] = function () { + return (Module["_sqlite3__wasm_enum_json"] = + Module["asm"]["sqlite3__wasm_enum_json"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_vfs_unlink'] = - function () { - return (Module[ - '_sqlite3__wasm_vfs_unlink' - ] = - Module['asm']['sqlite3__wasm_vfs_unlink']).apply(null, arguments); - }); + Module["_sqlite3__wasm_vfs_unlink"] = function () { + return (Module["_sqlite3__wasm_vfs_unlink"] = + Module["asm"]["sqlite3__wasm_vfs_unlink"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_db_vfs'] = function () { - return (Module['_sqlite3__wasm_db_vfs'] = - Module['asm']['sqlite3__wasm_db_vfs']).apply(null, arguments); - }); + Module["_sqlite3__wasm_db_vfs"] = function () { + return (Module["_sqlite3__wasm_db_vfs"] = + Module["asm"]["sqlite3__wasm_db_vfs"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_db_reset'] = - function () { - return (Module['_sqlite3__wasm_db_reset'] = - Module['asm']['sqlite3__wasm_db_reset']).apply(null, arguments); - }); + Module["_sqlite3__wasm_db_reset"] = function () { + return (Module["_sqlite3__wasm_db_reset"] = + Module["asm"]["sqlite3__wasm_db_reset"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_db_export_chunked' - ] = function () { - return (Module[ - '_sqlite3__wasm_db_export_chunked' - ] = - Module['asm']['sqlite3__wasm_db_export_chunked']).apply( + Module["_sqlite3__wasm_db_export_chunked"] = function () { + return (Module["_sqlite3__wasm_db_export_chunked"] = + Module["asm"]["sqlite3__wasm_db_export_chunked"]).apply( null, - arguments, + arguments ); - }); + }; - (Module['_sqlite3__wasm_db_serialize'] = - function () { - return (Module[ - '_sqlite3__wasm_db_serialize' - ] = - Module['asm']['sqlite3__wasm_db_serialize']).apply(null, arguments); - }); + Module["_sqlite3__wasm_db_serialize"] = function () { + return (Module["_sqlite3__wasm_db_serialize"] = + Module["asm"]["sqlite3__wasm_db_serialize"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_vfs_create_file' - ] = function () { - return (Module[ - '_sqlite3__wasm_vfs_create_file' - ] = - Module['asm']['sqlite3__wasm_vfs_create_file']).apply(null, arguments); - }); + Module["_sqlite3__wasm_vfs_create_file"] = function () { + return (Module["_sqlite3__wasm_vfs_create_file"] = + Module["asm"]["sqlite3__wasm_vfs_create_file"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_posix_create_file' - ] = function () { - return (Module[ - '_sqlite3__wasm_posix_create_file' - ] = - Module['asm']['sqlite3__wasm_posix_create_file']).apply( + Module["_sqlite3__wasm_posix_create_file"] = function () { + return (Module["_sqlite3__wasm_posix_create_file"] = + Module["asm"]["sqlite3__wasm_posix_create_file"]).apply( null, - arguments, + arguments ); - }); + }; - (Module[ - '_sqlite3__wasm_kvvfsMakeKeyOnPstack' - ] = function () { - return (Module[ - '_sqlite3__wasm_kvvfsMakeKeyOnPstack' - ] = - Module['asm']['sqlite3__wasm_kvvfsMakeKeyOnPstack']).apply( + Module["_sqlite3__wasm_kvvfsMakeKeyOnPstack"] = function () { + return (Module["_sqlite3__wasm_kvvfsMakeKeyOnPstack"] = + Module["asm"]["sqlite3__wasm_kvvfsMakeKeyOnPstack"]).apply( null, - arguments, + arguments ); - }); + }; - (Module['_sqlite3__wasm_kvvfs_methods'] = - function () { - return (Module[ - '_sqlite3__wasm_kvvfs_methods' - ] = - Module['asm']['sqlite3__wasm_kvvfs_methods']).apply(null, arguments); - }); + Module["_sqlite3__wasm_kvvfs_methods"] = function () { + return (Module["_sqlite3__wasm_kvvfs_methods"] = + Module["asm"]["sqlite3__wasm_kvvfs_methods"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_vtab_config'] = - function () { - return (Module[ - '_sqlite3__wasm_vtab_config' - ] = - Module['asm']['sqlite3__wasm_vtab_config']).apply(null, arguments); - }); + Module["_sqlite3__wasm_vtab_config"] = function () { + return (Module["_sqlite3__wasm_vtab_config"] = + Module["asm"]["sqlite3__wasm_vtab_config"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_db_config_ip'] = - function () { - return (Module[ - '_sqlite3__wasm_db_config_ip' - ] = - Module['asm']['sqlite3__wasm_db_config_ip']).apply(null, arguments); - }); + Module["_sqlite3__wasm_db_config_ip"] = function () { + return (Module["_sqlite3__wasm_db_config_ip"] = + Module["asm"]["sqlite3__wasm_db_config_ip"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_db_config_pii'] = - function () { - return (Module[ - '_sqlite3__wasm_db_config_pii' - ] = - Module['asm']['sqlite3__wasm_db_config_pii']).apply(null, arguments); - }); + Module["_sqlite3__wasm_db_config_pii"] = function () { + return (Module["_sqlite3__wasm_db_config_pii"] = + Module["asm"]["sqlite3__wasm_db_config_pii"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_db_config_s'] = - function () { - return (Module[ - '_sqlite3__wasm_db_config_s' - ] = - Module['asm']['sqlite3__wasm_db_config_s']).apply(null, arguments); - }); + Module["_sqlite3__wasm_db_config_s"] = function () { + return (Module["_sqlite3__wasm_db_config_s"] = + Module["asm"]["sqlite3__wasm_db_config_s"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_config_i'] = - function () { - return (Module['_sqlite3__wasm_config_i'] = - Module['asm']['sqlite3__wasm_config_i']).apply(null, arguments); - }); + Module["_sqlite3__wasm_config_i"] = function () { + return (Module["_sqlite3__wasm_config_i"] = + Module["asm"]["sqlite3__wasm_config_i"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_config_ii'] = - function () { - return (Module['_sqlite3__wasm_config_ii'] = - Module['asm']['sqlite3__wasm_config_ii']).apply(null, arguments); - }); + Module["_sqlite3__wasm_config_ii"] = function () { + return (Module["_sqlite3__wasm_config_ii"] = + Module["asm"]["sqlite3__wasm_config_ii"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_config_j'] = - function () { - return (Module['_sqlite3__wasm_config_j'] = - Module['asm']['sqlite3__wasm_config_j']).apply(null, arguments); - }); + Module["_sqlite3__wasm_config_j"] = function () { + return (Module["_sqlite3__wasm_config_j"] = + Module["asm"]["sqlite3__wasm_config_j"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_qfmt_token'] = - function () { - return (Module[ - '_sqlite3__wasm_qfmt_token' - ] = - Module['asm']['sqlite3__wasm_qfmt_token']).apply(null, arguments); - }); + Module["_sqlite3__wasm_qfmt_token"] = function () { + return (Module["_sqlite3__wasm_qfmt_token"] = + Module["asm"]["sqlite3__wasm_qfmt_token"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_init_wasmfs'] = - function () { - return (Module[ - '_sqlite3__wasm_init_wasmfs' - ] = - Module['asm']['sqlite3__wasm_init_wasmfs']).apply(null, arguments); - }); + Module["_sqlite3__wasm_init_wasmfs"] = function () { + return (Module["_sqlite3__wasm_init_wasmfs"] = + Module["asm"]["sqlite3__wasm_init_wasmfs"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_test_intptr'] = - function () { - return (Module[ - '_sqlite3__wasm_test_intptr' - ] = - Module['asm']['sqlite3__wasm_test_intptr']).apply(null, arguments); - }); + Module["_sqlite3__wasm_test_intptr"] = function () { + return (Module["_sqlite3__wasm_test_intptr"] = + Module["asm"]["sqlite3__wasm_test_intptr"]).apply(null, arguments); + }; - (Module['_sqlite3__wasm_test_voidptr'] = - function () { - return (Module[ - '_sqlite3__wasm_test_voidptr' - ] = - Module['asm']['sqlite3__wasm_test_voidptr']).apply(null, arguments); - }); + Module["_sqlite3__wasm_test_voidptr"] = function () { + return (Module["_sqlite3__wasm_test_voidptr"] = + Module["asm"]["sqlite3__wasm_test_voidptr"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_test_int64_max' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_int64_max' - ] = - Module['asm']['sqlite3__wasm_test_int64_max']).apply(null, arguments); - }); + Module["_sqlite3__wasm_test_int64_max"] = function () { + return (Module["_sqlite3__wasm_test_int64_max"] = + Module["asm"]["sqlite3__wasm_test_int64_max"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_test_int64_min' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_int64_min' - ] = - Module['asm']['sqlite3__wasm_test_int64_min']).apply(null, arguments); - }); + Module["_sqlite3__wasm_test_int64_min"] = function () { + return (Module["_sqlite3__wasm_test_int64_min"] = + Module["asm"]["sqlite3__wasm_test_int64_min"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_test_int64_times2' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_int64_times2' - ] = - Module['asm']['sqlite3__wasm_test_int64_times2']).apply( + Module["_sqlite3__wasm_test_int64_times2"] = function () { + return (Module["_sqlite3__wasm_test_int64_times2"] = + Module["asm"]["sqlite3__wasm_test_int64_times2"]).apply( null, - arguments, + arguments ); - }); + }; - (Module[ - '_sqlite3__wasm_test_int64_minmax' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_int64_minmax' - ] = - Module['asm']['sqlite3__wasm_test_int64_minmax']).apply( + Module["_sqlite3__wasm_test_int64_minmax"] = function () { + return (Module["_sqlite3__wasm_test_int64_minmax"] = + Module["asm"]["sqlite3__wasm_test_int64_minmax"]).apply( null, - arguments, + arguments ); - }); + }; - (Module['_sqlite3__wasm_test_int64ptr'] = - function () { - return (Module[ - '_sqlite3__wasm_test_int64ptr' - ] = - Module['asm']['sqlite3__wasm_test_int64ptr']).apply(null, arguments); - }); + Module["_sqlite3__wasm_test_int64ptr"] = function () { + return (Module["_sqlite3__wasm_test_int64ptr"] = + Module["asm"]["sqlite3__wasm_test_int64ptr"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_test_stack_overflow' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_stack_overflow' - ] = - Module['asm']['sqlite3__wasm_test_stack_overflow']).apply( + Module["_sqlite3__wasm_test_stack_overflow"] = function () { + return (Module["_sqlite3__wasm_test_stack_overflow"] = + Module["asm"]["sqlite3__wasm_test_stack_overflow"]).apply( null, - arguments, + arguments ); - }); + }; - (Module[ - '_sqlite3__wasm_test_str_hello' - ] = function () { - return (Module[ - '_sqlite3__wasm_test_str_hello' - ] = - Module['asm']['sqlite3__wasm_test_str_hello']).apply(null, arguments); - }); + Module["_sqlite3__wasm_test_str_hello"] = function () { + return (Module["_sqlite3__wasm_test_str_hello"] = + Module["asm"]["sqlite3__wasm_test_str_hello"]).apply(null, arguments); + }; - (Module[ - '_sqlite3__wasm_SQLTester_strglob' - ] = function () { - return (Module[ - '_sqlite3__wasm_SQLTester_strglob' - ] = - Module['asm']['sqlite3__wasm_SQLTester_strglob']).apply( + Module["_sqlite3__wasm_SQLTester_strglob"] = function () { + return (Module["_sqlite3__wasm_SQLTester_strglob"] = + Module["asm"]["sqlite3__wasm_SQLTester_strglob"]).apply( null, - arguments, + arguments ); - }); + }; - var _malloc = (Module['_malloc'] = function () { - return (_malloc = Module['_malloc'] = Module['asm']['malloc']).apply( + var _malloc = (Module["_malloc"] = function () { + return (_malloc = Module["_malloc"] = Module["asm"]["malloc"]).apply( null, - arguments, + arguments ); }); - (Module['_free'] = function () { - return (Module['_free'] = Module['asm']['free']).apply( - null, - arguments, - ); - }); + Module["_free"] = function () { + return (Module["_free"] = Module["asm"]["free"]).apply(null, arguments); + }; - (Module['_realloc'] = function () { - return (Module['_realloc'] = Module['asm']['realloc']).apply( + Module["_realloc"] = function () { + return (Module["_realloc"] = Module["asm"]["realloc"]).apply( null, - arguments, + arguments ); - }); + }; - var _emscripten_builtin_memalign = (Module['_emscripten_builtin_memalign'] = + var _emscripten_builtin_memalign = (Module["_emscripten_builtin_memalign"] = function () { return (_emscripten_builtin_memalign = Module[ - '_emscripten_builtin_memalign' + "_emscripten_builtin_memalign" ] = - Module['asm']['emscripten_builtin_memalign']).apply(null, arguments); + Module["asm"]["emscripten_builtin_memalign"]).apply(null, arguments); }); - (Module['stackSave'] = function () { - return (Module['stackSave'] = - Module['asm']['stackSave']).apply(null, arguments); - }); + Module["stackSave"] = function () { + return (Module["stackSave"] = Module["asm"]["stackSave"]).apply( + null, + arguments + ); + }; - (Module['stackRestore'] = function () { - return (Module['stackRestore'] = - Module['asm']['stackRestore']).apply(null, arguments); - }); + Module["stackRestore"] = function () { + return (Module["stackRestore"] = Module["asm"]["stackRestore"]).apply( + null, + arguments + ); + }; - (Module['stackAlloc'] = function () { - return (Module['stackAlloc'] = - Module['asm']['stackAlloc']).apply(null, arguments); - }); + Module["stackAlloc"] = function () { + return (Module["stackAlloc"] = Module["asm"]["stackAlloc"]).apply( + null, + arguments + ); + }; - Module['wasmMemory'] = wasmMemory; + Module["wasmMemory"] = wasmMemory; var calledRun; @@ -5492,7 +5180,6 @@ var sqlite3InitModule = (() => { }; function run(args) { - if (runDependencies > 0) { return; } @@ -5506,23 +5193,23 @@ var sqlite3InitModule = (() => { function doRun() { if (calledRun) return; calledRun = true; - Module['calledRun'] = true; + Module["calledRun"] = true; if (ABORT) return; initRuntime(); readyPromiseResolve(Module); - if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); + if (Module["onRuntimeInitialized"]) Module["onRuntimeInitialized"](); postRun(); } - if (Module['setStatus']) { - Module['setStatus']('Running...'); + if (Module["setStatus"]) { + Module["setStatus"]("Running..."); setTimeout(function () { setTimeout(function () { - Module['setStatus'](''); + Module["setStatus"](""); }, 1); doRun(); }, 1); @@ -5531,11 +5218,11 @@ var sqlite3InitModule = (() => { } } - if (Module['preInit']) { - if (typeof Module['preInit'] == 'function') - Module['preInit'] = [Module['preInit']]; - while (Module['preInit'].length > 0) { - Module['preInit'].pop()(); + if (Module["preInit"]) { + if (typeof Module["preInit"] == "function") + Module["preInit"] = [Module["preInit"]]; + while (Module["preInit"].length > 0) { + Module["preInit"].pop()(); } } @@ -5545,12 +5232,12 @@ var sqlite3InitModule = (() => { Module.postRun.push(function (Module) { globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( apiConfig = globalThis.sqlite3ApiConfig || - sqlite3ApiBootstrap.defaultConfig, + sqlite3ApiBootstrap.defaultConfig ) { if (sqlite3ApiBootstrap.sqlite3) { (sqlite3ApiBootstrap.sqlite3.config || console).warn( - 'sqlite3ApiBootstrap() called multiple times.', - 'Config and external initializers are ignored on calls after the first.', + "sqlite3ApiBootstrap() called multiple times.", + "Config and external initializers are ignored on calls after the first." ); return sqlite3ApiBootstrap.sqlite3; } @@ -5560,7 +5247,7 @@ var sqlite3InitModule = (() => { exports: undefined, memory: undefined, bigIntEnabled: (() => { - if ('undefined' !== typeof Module) { + if ("undefined" !== typeof Module) { if (!!Module.HEAPU64) return true; } return !!globalThis.BigInt64Array; @@ -5569,27 +5256,27 @@ var sqlite3InitModule = (() => { warn: console.warn.bind(console), error: console.error.bind(console), log: console.log.bind(console), - wasmfsOpfsDir: '/opfs', + wasmfsOpfsDir: "/opfs", useStdAlloc: false, }, - apiConfig || {}, + apiConfig || {} ); Object.assign( config, { - allocExportName: config.useStdAlloc ? 'malloc' : 'sqlite3_malloc', - deallocExportName: config.useStdAlloc ? 'free' : 'sqlite3_free', + allocExportName: config.useStdAlloc ? "malloc" : "sqlite3_malloc", + deallocExportName: config.useStdAlloc ? "free" : "sqlite3_free", reallocExportName: config.useStdAlloc - ? 'realloc' - : 'sqlite3_realloc', + ? "realloc" + : "sqlite3_realloc", }, - config, + config ); - ['exports', 'memory', 'wasmfsOpfsDir'].forEach((k) => { - if ('function' === typeof config[k]) { + ["exports", "memory", "wasmfsOpfsDir"].forEach((k) => { + if ("function" === typeof config[k]) { config[k] = config[k](); } }); @@ -5604,11 +5291,11 @@ var sqlite3InitModule = (() => { const __rcStr = (rc) => { return ( (capi.sqlite3_js_rc_str && capi.sqlite3_js_rc_str(rc)) || - 'Unknown result code #' + rc + "Unknown result code #" + rc ); }; - const __isInt = (n) => 'number' === typeof n && n === (n | 0); + const __isInt = (n) => "number" === typeof n && n === (n | 0); class SQLite3Error extends Error { constructor(...args) { @@ -5620,23 +5307,23 @@ var sqlite3InitModule = (() => { super(__rcStr(args[0])); } else { const rcStr = __rcStr(rc); - if ('object' === typeof args[1]) { + if ("object" === typeof args[1]) { super(rcStr, args[1]); } else { - args[0] = rcStr + ':'; - super(args.join(' ')); + args[0] = rcStr + ":"; + super(args.join(" ")); } } } else { - if (2 === args.length && 'object' === typeof args[1]) { + if (2 === args.length && "object" === typeof args[1]) { super(...args); } else { - super(args.join(' ')); + super(args.join(" ")); } } } this.resultCode = rc || capi.SQLITE_ERROR; - this.name = 'SQLite3Error'; + this.name = "SQLite3Error"; } } @@ -5647,20 +5334,20 @@ var sqlite3InitModule = (() => { if (config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)) { toss3( - "config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.", + "config.wasmfsOpfsDir must be falsy or in the form '/dir-name'." ); } const isInt32 = (n) => { return ( - 'bigint' !== typeof n && + "bigint" !== typeof n && !!(n === (n | 0) && n <= 2147483647 && n >= -2147483648) ); }; const bigIntFits64 = function f(b) { if (!f._max) { - f._max = BigInt('0x7fffffffffffffff'); + f._max = BigInt("0x7fffffffffffffff"); f._min = ~f._max; } return b >= f._min && b <= f._max; @@ -5683,7 +5370,7 @@ var sqlite3InitModule = (() => { }; const __SAB = - 'undefined' === typeof SharedArrayBuffer + "undefined" === typeof SharedArrayBuffer ? function () {} : SharedArrayBuffer; @@ -5717,11 +5404,11 @@ var sqlite3InitModule = (() => { const affirmBindableTypedArray = (v) => { return ( isBindableTypedArray(v) || - toss3('Value is not of a supported TypedArray type.') + toss3("Value is not of a supported TypedArray type.") ); }; - const utf8Decoder = new TextDecoder('utf-8'); + const utf8Decoder = new TextDecoder("utf-8"); const typedArrayToString = function (typedArray, begin, end) { return utf8Decoder.decode(typedArrayPart(typedArray, begin, end)); @@ -5730,24 +5417,24 @@ var sqlite3InitModule = (() => { const flexibleString = function (v) { if (isSQLableTypedArray(v)) { return typedArrayToString( - v instanceof ArrayBuffer ? new Uint8Array(v) : v, + v instanceof ArrayBuffer ? new Uint8Array(v) : v ); - } else if (Array.isArray(v)) return v.join(''); + } else if (Array.isArray(v)) return v.join(""); else if (wasm.isPtr(v)) v = wasm.cstrToJs(v); return v; }; class WasmAllocError extends Error { constructor(...args) { - if (2 === args.length && 'object' === typeof args[1]) { + if (2 === args.length && "object" === typeof args[1]) { super(...args); } else if (args.length) { - super(args.join(' ')); + super(args.join(" ")); } else { - super('Allocation failed.'); + super("Allocation failed."); } this.resultCode = capi.SQLITE_NOMEM; - this.name = 'WasmAllocError'; + this.name = "WasmAllocError"; } } @@ -5769,7 +5456,7 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - xDestroy, + xDestroy ) => {}, sqlite3_create_function: ( @@ -5780,7 +5467,7 @@ var sqlite3InitModule = (() => { pApp, xFunc, xStep, - xFinal, + xFinal ) => {}, sqlite3_create_window_function: ( @@ -5793,7 +5480,7 @@ var sqlite3InitModule = (() => { xFinal, xValue, xInverse, - xDestroy, + xDestroy ) => {}, sqlite3_prepare_v3: ( @@ -5802,7 +5489,7 @@ var sqlite3InitModule = (() => { sqlByteLen, prepFlags, stmtPtrPtr, - strPtrPtr, + strPtrPtr ) => {}, sqlite3_prepare_v2: ( @@ -5810,7 +5497,7 @@ var sqlite3InitModule = (() => { sql, sqlByteLen, stmtPtrPtr, - strPtrPtr, + strPtrPtr ) => {}, sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg) => {}, @@ -5834,20 +5521,20 @@ var sqlite3InitModule = (() => { isSharedTypedArray, toss: function (...args) { - throw new Error(args.join(' ')); + throw new Error(args.join(" ")); }, toss3, typedArrayPart, affirmDbHeader: function (bytes) { if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); - const header = 'SQLite format 3'; + const header = "SQLite format 3"; if (header.length > bytes.byteLength) { - toss3('Input does not contain an SQLite3 database header.'); + toss3("Input does not contain an SQLite3 database header."); } for (let i = 0; i < header.length; ++i) { if (header.charCodeAt(i) !== bytes[i]) { - toss3('Input does not contain an SQLite3 database header.'); + toss3("Input does not contain an SQLite3 database header."); } } }, @@ -5856,7 +5543,7 @@ var sqlite3InitModule = (() => { if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); const n = bytes.byteLength; if (n < 512 || n % 512 !== 0) { - toss3('Byte array size', n, 'is invalid for an SQLite3 db.'); + toss3("Byte array size", n, "is invalid for an SQLite3 db."); } util.affirmDbHeader(bytes); }, @@ -5865,21 +5552,21 @@ var sqlite3InitModule = (() => { Object.assign(wasm, { ptrSizeof: config.wasmPtrSizeof || 4, - ptrIR: config.wasmPtrIR || 'i32', + ptrIR: config.wasmPtrIR || "i32", bigIntEnabled: !!config.bigIntEnabled, exports: config.exports || - toss3('Missing API config.exports (WASM module exports).'), + toss3("Missing API config.exports (WASM module exports)."), memory: config.memory || - config.exports['memory'] || + config.exports["memory"] || toss3( - 'API config object requires a WebAssembly.Memory object', - 'in either config.exports.memory (exported)', - 'or config.memory (imported).', + "API config object requires a WebAssembly.Memory object", + "in either config.exports.memory (exported)", + "or config.memory (imported)." ), alloc: undefined, @@ -5908,20 +5595,20 @@ var sqlite3InitModule = (() => { for (const key of [keyAlloc, keyDealloc, keyRealloc]) { const f = wasm.exports[key]; if (!(f instanceof Function)) - toss3('Missing required exports[', key, '] function.'); + toss3("Missing required exports[", key, "] function."); } wasm.alloc = function f(n) { return ( f.impl(n) || - WasmAllocError.toss('Failed to allocate', n, ' bytes.') + WasmAllocError.toss("Failed to allocate", n, " bytes.") ); }; wasm.alloc.impl = wasm.exports[keyAlloc]; wasm.realloc = function f(m, n) { const m2 = f.impl(m, n); return n - ? m2 || WasmAllocError.toss('Failed to reallocate', n, ' bytes.') + ? m2 || WasmAllocError.toss("Failed to reallocate", n, " bytes.") : 0; }; wasm.realloc.impl = wasm.exports[keyRealloc]; @@ -5955,13 +5642,13 @@ var sqlite3InitModule = (() => { rc[v] = capi.sqlite3_compileoption_used(v); }); return rc; - } else if ('object' === typeof optName) { + } else if ("object" === typeof optName) { Object.keys(optName).forEach((k) => { optName[k] = capi.sqlite3_compileoption_used(k); }); return optName; } - return 'string' === typeof optName + return "string" === typeof optName ? !!capi.sqlite3_compileoption_used(optName) : false; }; @@ -5970,29 +5657,29 @@ var sqlite3InitModule = (() => { restore: wasm.exports.sqlite3__wasm_pstack_restore, alloc: function (n) { - if ('string' === typeof n && !(n = wasm.sizeofIR(n))) { + if ("string" === typeof n && !(n = wasm.sizeofIR(n))) { WasmAllocError.toss( - 'Invalid value for pstack.alloc(', + "Invalid value for pstack.alloc(", arguments[0], - ')', + ")" ); } return ( wasm.exports.sqlite3__wasm_pstack_alloc(n) || WasmAllocError.toss( - 'Could not allocate', + "Could not allocate", n, - 'bytes from the pstack.', + "bytes from the pstack." ) ); }, allocChunks: function (n, sz) { - if ('string' === typeof sz && !(sz = wasm.sizeofIR(sz))) { + if ("string" === typeof sz && !(sz = wasm.sizeofIR(sz))) { WasmAllocError.toss( - 'Invalid size value for allocChunks(', + "Invalid size value for allocChunks(", arguments[1], - ')', + ")" ); } const mem = wasm.pstack.alloc(n * sz); @@ -6069,9 +5756,9 @@ var sqlite3InitModule = (() => { } while (n > 0); } catch (e) { console.error( - 'Highly unexpected (and ignored!) ' + - 'exception in sqlite3_randomness():', - e, + "Highly unexpected (and ignored!) " + + "exception in sqlite3_randomness():", + e ); } finally { wasm.pstack.restore(stack); @@ -6093,31 +5780,31 @@ var sqlite3InitModule = (() => { !globalThis.FileSystemDirectoryHandle || !globalThis.FileSystemFileHandle ) { - return (__wasmfsOpfsDir = ''); + return (__wasmfsOpfsDir = ""); } try { if ( pdir && 0 === wasm.xCallWrapped( - 'sqlite3__wasm_init_wasmfs', - 'i32', - ['string'], - pdir, + "sqlite3__wasm_init_wasmfs", + "i32", + ["string"], + pdir ) ) { return (__wasmfsOpfsDir = pdir); } else { - return (__wasmfsOpfsDir = ''); + return (__wasmfsOpfsDir = ""); } } catch (e) { - return (__wasmfsOpfsDir = ''); + return (__wasmfsOpfsDir = ""); } }; capi.sqlite3_wasmfs_filename_is_persistent = function (name) { const p = capi.sqlite3_wasmfs_opfs_dir(); - return p && name ? name.startsWith(p + '/') : false; + return p && name ? name.startsWith(p + "/") : false; }; capi.sqlite3_js_db_uses_vfs = function (pDb, vfsName, dbName = 0) { @@ -6147,9 +5834,9 @@ var sqlite3InitModule = (() => { }; capi.sqlite3_js_db_export = function (pDb, schema = 0) { - pDb = wasm.xWrap.testConvertArg('sqlite3*', pDb); - if (!pDb) toss3('Invalid sqlite3* argument.'); - if (!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.'); + pDb = wasm.xWrap.testConvertArg("sqlite3*", pDb); + if (!pDb) toss3("Invalid sqlite3* argument."); + if (!wasm.bigIntEnabled) toss3("BigInt64 support is not enabled."); const scope = wasm.scopedAllocPush(); let pOut; try { @@ -6159,23 +5846,23 @@ var sqlite3InitModule = (() => { const zSchema = schema ? wasm.isPtr(schema) ? schema - : wasm.scopedAllocCString('' + schema) + : wasm.scopedAllocCString("" + schema) : 0; let rc = wasm.exports.sqlite3__wasm_db_serialize( pDb, zSchema, ppOut, pSize, - 0, + 0 ); if (rc) { toss3( - 'Database serialization failed with code', - sqlite3.capi.sqlite3_js_rc_str(rc), + "Database serialization failed with code", + sqlite3.capi.sqlite3_js_rc_str(rc) ); } pOut = wasm.peekPtr(ppOut); - const nOut = wasm.peek(pSize, 'i64'); + const nOut = wasm.peek(pSize, "i64"); rc = nOut ? wasm.heap8u().slice(pOut, pOut + Number(nOut)) : new Uint8Array(); @@ -6194,9 +5881,9 @@ var sqlite3InitModule = (() => { capi.sqlite3_aggregate_context(pCtx, n) || (n ? WasmAllocError.toss( - 'Cannot allocate', + "Cannot allocate", n, - 'bytes for sqlite3_aggregate_context()', + "bytes for sqlite3_aggregate_context()" ) : 0) ); @@ -6216,24 +5903,24 @@ var sqlite3InitModule = (() => { } } else { SQLite3Error.toss( - 'Invalid 2nd argument for sqlite3_js_posix_create_file().', + "Invalid 2nd argument for sqlite3_js_posix_create_file()." ); } try { if (!util.isInt32(dataLen) || dataLen < 0) { SQLite3Error.toss( - 'Invalid 3rd argument for sqlite3_js_posix_create_file().', + "Invalid 3rd argument for sqlite3_js_posix_create_file()." ); } const rc = util.sqlite3__wasm_posix_create_file( filename, pData, - dataLen, + dataLen ); if (rc) SQLite3Error.toss( - 'Creation of file failed with sqlite3 result code', - capi.sqlite3_js_rc_str(rc), + "Creation of file failed with sqlite3 result code", + capi.sqlite3_js_rc_str(rc) ); } finally { wasm.dealloc(pData); @@ -6244,12 +5931,12 @@ var sqlite3InitModule = (() => { vfs, filename, data, - dataLen, + dataLen ) { config.warn( - 'sqlite3_js_vfs_create_file() is deprecated and', - 'should be avoided because it can lead to C-level crashes.', - 'See its documentation for alternative options.', + "sqlite3_js_vfs_create_file() is deprecated and", + "should be avoided because it can lead to C-level crashes.", + "See its documentation for alternative options." ); let pData; if (data) { @@ -6269,7 +5956,7 @@ var sqlite3InitModule = (() => { } } else { SQLite3Error.toss( - 'Invalid 3rd argument type for sqlite3_js_vfs_create_file().', + "Invalid 3rd argument type for sqlite3_js_vfs_create_file()." ); } } else { @@ -6278,7 +5965,7 @@ var sqlite3InitModule = (() => { if (!util.isInt32(dataLen) || dataLen < 0) { wasm.dealloc(pData); SQLite3Error.toss( - 'Invalid 4th argument for sqlite3_js_vfs_create_file().', + "Invalid 4th argument for sqlite3_js_vfs_create_file()." ); } try { @@ -6286,12 +5973,12 @@ var sqlite3InitModule = (() => { vfs, filename, pData, - dataLen, + dataLen ); if (rc) SQLite3Error.toss( - 'Creation of file failed with sqlite3 result code', - capi.sqlite3_js_rc_str(rc), + "Creation of file failed with sqlite3 result code", + capi.sqlite3_js_rc_str(rc) ); } finally { wasm.dealloc(pData); @@ -6299,7 +5986,7 @@ var sqlite3InitModule = (() => { }; capi.sqlite3_js_sql_to_string = (sql) => { - if ('string' === typeof sql) { + if ("string" === typeof sql) { return sql; } const x = flexibleString(v); @@ -6309,16 +5996,16 @@ var sqlite3InitModule = (() => { if (util.isUIThread()) { const __kvvfsInfo = function (which) { const rc = Object.create(null); - rc.prefix = 'kvvfs-' + which; + rc.prefix = "kvvfs-" + which; rc.stores = []; - if ('session' === which || '' === which) + if ("session" === which || "" === which) rc.stores.push(globalThis.sessionStorage); - if ('local' === which || '' === which) + if ("local" === which || "" === which) rc.stores.push(globalThis.localStorage); return rc; }; - capi.sqlite3_js_kvvfs_clear = function (which = '') { + capi.sqlite3_js_kvvfs_clear = function (which = "") { let rc = 0; const kvinfo = __kvvfsInfo(which); kvinfo.stores.forEach((s) => { @@ -6334,7 +6021,7 @@ var sqlite3InitModule = (() => { return rc; }; - capi.sqlite3_js_kvvfs_size = function (which = '') { + capi.sqlite3_js_kvvfs_size = function (which = "") { let sz = 0; const kvinfo = __kvvfsInfo(which); kvinfo.stores.forEach((s) => { @@ -6353,23 +6040,23 @@ var sqlite3InitModule = (() => { capi.sqlite3_db_config = function (pDb, op, ...args) { if (!this.s) { - this.s = wasm.xWrap('sqlite3__wasm_db_config_s', 'int', [ - 'sqlite3*', - 'int', - 'string:static', + this.s = wasm.xWrap("sqlite3__wasm_db_config_s", "int", [ + "sqlite3*", + "int", + "string:static", ]); - this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int', [ - 'sqlite3*', - 'int', - '*', - 'int', - 'int', + this.pii = wasm.xWrap("sqlite3__wasm_db_config_pii", "int", [ + "sqlite3*", + "int", + "*", + "int", + "int", ]); - this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip', 'int', [ - 'sqlite3*', - 'int', - 'int', - '*', + this.ip = wasm.xWrap("sqlite3__wasm_db_config_ip", "int", [ + "sqlite3*", + "int", + "int", + "*", ]); } switch (op) { @@ -6403,7 +6090,7 @@ var sqlite3InitModule = (() => { capi.sqlite3_value_to_js = function ( pVal, - throwIfCannotConvert = true, + throwIfCannotConvert = true ) { let arg; const valType = capi.sqlite3_value_type(pVal); @@ -6425,9 +6112,9 @@ var sqlite3InitModule = (() => { const pBlob = capi.sqlite3_value_blob(pVal); if (n && !pBlob) sqlite3.WasmAllocError.toss( - 'Cannot allocate memory for blob argument of', + "Cannot allocate memory for blob argument of", n, - 'byte(s)', + "byte(s)" ); arg = n ? wasm.heap8u().slice(pBlob, pBlob + Number(n)) : null; break; @@ -6439,8 +6126,8 @@ var sqlite3InitModule = (() => { if (throwIfCannotConvert) { toss3( capi.SQLITE_MISMATCH, - 'Unhandled sqlite3_value_type():', - valType, + "Unhandled sqlite3_value_type():", + valType ); } arg = undefined; @@ -6451,7 +6138,7 @@ var sqlite3InitModule = (() => { capi.sqlite3_values_to_js = function ( argc, pArgv, - throwIfCannotConvert = true, + throwIfCannotConvert = true ) { let i; const tgt = []; @@ -6459,8 +6146,8 @@ var sqlite3InitModule = (() => { tgt.push( capi.sqlite3_value_to_js( wasm.peekPtr(pArgv + wasm.ptrSizeof * i), - throwIfCannotConvert, - ), + throwIfCannotConvert + ) ); } return tgt; @@ -6470,7 +6157,7 @@ var sqlite3InitModule = (() => { if (e instanceof WasmAllocError) { capi.sqlite3_result_error_nomem(pCtx); } else { - capi.sqlite3_result_error(pCtx, '' + e, -1); + capi.sqlite3_result_error(pCtx, "" + e, -1); } }; @@ -6481,12 +6168,12 @@ var sqlite3InitModule = (() => { } try { switch (typeof val) { - case 'undefined': + case "undefined": break; - case 'boolean': + case "boolean": capi.sqlite3_result_int(pCtx, val ? 1 : 0); break; - case 'bigint': + case "bigint": if (util.bigIntFits32(val)) { capi.sqlite3_result_int(pCtx, Number(val)); } else if (util.bigIntFitsDouble(val)) { @@ -6496,15 +6183,15 @@ var sqlite3InitModule = (() => { capi.sqlite3_result_int64(pCtx, val); else toss3( - 'BigInt value', + "BigInt value", val.toString(), - 'is too BigInt for int64.', + "is too BigInt for int64." ); } else { - toss3('BigInt value', val.toString(), 'is too BigInt.'); + toss3("BigInt value", val.toString(), "is too BigInt."); } break; - case 'number': { + case "number": { let f; if (util.isInt32(val)) { f = capi.sqlite3_result_int; @@ -6520,12 +6207,12 @@ var sqlite3InitModule = (() => { f(pCtx, val); break; } - case 'string': { + case "string": { const [p, n] = wasm.allocCString(val, true); capi.sqlite3_result_text(pCtx, p, n, capi.SQLITE_WASM_DEALLOC); break; } - case 'object': + case "object": if (null === val) { capi.sqlite3_result_null(pCtx); break; @@ -6535,7 +6222,7 @@ var sqlite3InitModule = (() => { pCtx, pBlob, val.byteLength, - capi.SQLITE_WASM_DEALLOC, + capi.SQLITE_WASM_DEALLOC ); break; } @@ -6544,7 +6231,7 @@ var sqlite3InitModule = (() => { toss3( "Don't not how to handle this UDF result value:", typeof val, - val, + val ); } } catch (e) { @@ -6555,7 +6242,7 @@ var sqlite3InitModule = (() => { capi.sqlite3_column_js = function ( pStmt, iCol, - throwIfCannotConvert = true, + throwIfCannotConvert = true ) { const v = capi.sqlite3_column_value(pStmt, iCol); return 0 === v @@ -6571,23 +6258,23 @@ var sqlite3InitModule = (() => { if (rc) return SQLite3Error.toss( rc, - arguments[2] + '() failed with code ' + rc, + arguments[2] + "() failed with code " + rc ); const pv = wasm.peekPtr(this.ptr); return pv ? capi.sqlite3_value_to_js(pv, true) : undefined; }.bind(Object.create(null)); capi.sqlite3_preupdate_new_js = (pDb, iCol) => - __newOldValue(pDb, iCol, 'sqlite3_preupdate_new'); + __newOldValue(pDb, iCol, "sqlite3_preupdate_new"); capi.sqlite3_preupdate_old_js = (pDb, iCol) => - __newOldValue(pDb, iCol, 'sqlite3_preupdate_old'); + __newOldValue(pDb, iCol, "sqlite3_preupdate_old"); capi.sqlite3changeset_new_js = (pChangesetIter, iCol) => - __newOldValue(pChangesetIter, iCol, 'sqlite3changeset_new'); + __newOldValue(pChangesetIter, iCol, "sqlite3changeset_new"); capi.sqlite3changeset_old_js = (pChangesetIter, iCol) => - __newOldValue(pChangesetIter, iCol, 'sqlite3changeset_old'); + __newOldValue(pChangesetIter, iCol, "sqlite3changeset_old"); const sqlite3 = { WasmAllocError: WasmAllocError, @@ -6614,7 +6301,7 @@ var sqlite3InitModule = (() => { return sqlite3; }; const catcher = (e) => { - config.error('an async sqlite3 initializer failed:', e); + config.error("an async sqlite3 initializer failed:", e); throw e; }; if (!lia || !lia.length) { @@ -6636,7 +6323,7 @@ var sqlite3InitModule = (() => { f(sqlite3); }); } catch (e) { - console.error('sqlite3 bootstrap initializer threw:', e); + console.error("sqlite3 bootstrap initializer threw:", e); throw e; } delete sqlite3ApiBootstrap.initializers; @@ -6654,28 +6341,28 @@ var sqlite3InitModule = (() => { globalThis.WhWasmUtilInstaller = function (target) { if (undefined === target.bigIntEnabled) { - target.bigIntEnabled = !!globalThis['BigInt64Array']; + target.bigIntEnabled = !!globalThis["BigInt64Array"]; } const toss = (...args) => { - throw new Error(args.join(' ')); + throw new Error(args.join(" ")); }; if (!target.exports) { - Object.defineProperty(target, 'exports', { + Object.defineProperty(target, "exports", { enumerable: true, configurable: true, get: () => target.instance && target.instance.exports, }); } - const ptrIR = target.pointerIR || 'i32'; + const ptrIR = target.pointerIR || "i32"; const ptrSizeof = (target.ptrSizeof = - 'i32' === ptrIR + "i32" === ptrIR ? 4 - : 'i64' === ptrIR - ? 8 - : toss('Unhandled ptrSizeof:', ptrIR)); + : "i64" === ptrIR + ? 8 + : toss("Unhandled ptrSizeof:", ptrIR)); const cache = Object.create(null); @@ -6688,26 +6375,26 @@ var sqlite3InitModule = (() => { cache.scopedAlloc = []; cache.utf8Decoder = new TextDecoder(); - cache.utf8Encoder = new TextEncoder('utf-8'); + cache.utf8Encoder = new TextEncoder("utf-8"); target.sizeofIR = (n) => { switch (n) { - case 'i8': + case "i8": return 1; - case 'i16': + case "i16": return 2; - case 'i32': - case 'f32': - case 'float': + case "i32": + case "f32": + case "float": return 4; - case 'i64': - case 'f64': - case 'double': + case "i64": + case "f64": + case "double": return 8; - case '*': + case "*": return ptrSizeof; default: - return ('' + n).endsWith('*') ? ptrSizeof : undefined; + return ("" + n).endsWith("*") ? ptrSizeof : undefined; } }; @@ -6779,14 +6466,14 @@ var sqlite3InitModule = (() => { break; default: if (target.bigIntEnabled) { - if (n === globalThis['BigUint64Array']) return c.HEAP64U; - else if (n === globalThis['BigInt64Array']) return c.HEAP64; + if (n === globalThis["BigUint64Array"]) return c.HEAP64U; + else if (n === globalThis["BigInt64Array"]) return c.HEAP64; break; } } toss( - 'Invalid heapForSize() size: expecting 8, 16, 32,', - 'or (if BigInt is enabled) 64.', + "Invalid heapForSize() size: expecting 8, 16, 32,", + "or (if BigInt is enabled) 64." ); }; @@ -6803,13 +6490,13 @@ var sqlite3InitModule = (() => { if (!f._) { f._ = { sigTypes: Object.assign(Object.create(null), { - i: 'i32', - p: 'i32', - P: 'i32', - s: 'i32', - j: 'i64', - f: 'f32', - d: 'f64', + i: "i32", + p: "i32", + P: "i32", + s: "i32", + j: "i64", + f: "f32", + d: "f64", }), typeCodes: Object.assign(Object.create(null), { @@ -6832,27 +6519,27 @@ var sqlite3InitModule = (() => { }, letterType: (x) => - f._.sigTypes[x] || toss('Invalid signature letter:', x), + f._.sigTypes[x] || toss("Invalid signature letter:", x), pushSigType: (dest, letter) => dest.push(f._.typeCodes[f._.letterType(letter)]), }; } - if ('string' === typeof func) { + if ("string" === typeof func) { const x = sig; sig = func; func = x; } const sigParams = f._.sigParams(sig); const wasmCode = [0x01, 0x60]; - f._.uleb128Encode(wasmCode, 'push', sigParams.length); + f._.uleb128Encode(wasmCode, "push", sigParams.length); for (const x of sigParams) f._.pushSigType(wasmCode, x); - if ('v' === sig[0]) wasmCode.push(0); + if ("v" === sig[0]) wasmCode.push(0); else { wasmCode.push(1); f._.pushSigType(wasmCode, sig[0]); } - f._.uleb128Encode(wasmCode, 'unshift', wasmCode.length); + f._.uleb128Encode(wasmCode, "unshift", wasmCode.length); wasmCode.unshift( 0x00, 0x61, @@ -6862,7 +6549,7 @@ var sqlite3InitModule = (() => { 0x00, 0x00, 0x00, - 0x01, + 0x01 ); wasmCode.push( 0x02, @@ -6882,29 +6569,29 @@ var sqlite3InitModule = (() => { 0x01, 0x66, 0x00, - 0x00, + 0x00 ); return new WebAssembly.Instance( new WebAssembly.Module(new Uint8Array(wasmCode)), { e: { f: func }, - }, - ).exports['f']; + } + ).exports["f"]; }; const __installFunction = function f(func, sig, scoped) { if (scoped && !cache.scopedAlloc.length) { - toss('No scopedAllocPush() scope is active.'); + toss("No scopedAllocPush() scope is active."); } - if ('string' === typeof func) { + if ("string" === typeof func) { const x = sig; sig = func; func = x; } - if ('string' !== typeof sig || !(func instanceof Function)) { + if ("string" !== typeof sig || !(func instanceof Function)) { toss( - 'Invalid arguments: expecting (function,signature) ' + - 'or (signature,function).', + "Invalid arguments: expecting (function,signature) " + + "or (signature,function)." ); } const ft = target.functionTable(); @@ -6965,8 +6652,8 @@ var sqlite3InitModule = (() => { return rc; }; - target.peek = function f(ptr, type = 'i8') { - if (type.endsWith('*')) type = ptrIR; + target.peek = function f(ptr, type = "i8") { + if (type.endsWith("*")) type = ptrIR; const c = cache.memory && cache.heapSize === cache.memory.buffer.byteLength ? cache @@ -6976,72 +6663,72 @@ var sqlite3InitModule = (() => { do { if (list) ptr = arguments[0].shift(); switch (type) { - case 'i1': - case 'i8': + case "i1": + case "i8": rc = c.HEAP8[ptr >> 0]; break; - case 'i16': + case "i16": rc = c.HEAP16[ptr >> 1]; break; - case 'i32': + case "i32": rc = c.HEAP32[ptr >> 2]; break; - case 'float': - case 'f32': + case "float": + case "f32": rc = c.HEAP32F[ptr >> 2]; break; - case 'double': - case 'f64': + case "double": + case "f64": rc = Number(c.HEAP64F[ptr >> 3]); break; - case 'i64': + case "i64": if (target.bigIntEnabled) { rc = BigInt(c.HEAP64[ptr >> 3]); break; } default: - toss('Invalid type for peek():', type); + toss("Invalid type for peek():", type); } if (list) list.push(rc); } while (list && arguments[0].length); return list || rc; }; - target.poke = function (ptr, value, type = 'i8') { - if (type.endsWith('*')) type = ptrIR; + target.poke = function (ptr, value, type = "i8") { + if (type.endsWith("*")) type = ptrIR; const c = cache.memory && cache.heapSize === cache.memory.buffer.byteLength ? cache : heapWrappers(); for (const p of Array.isArray(ptr) ? ptr : [ptr]) { switch (type) { - case 'i1': - case 'i8': + case "i1": + case "i8": c.HEAP8[p >> 0] = value; continue; - case 'i16': + case "i16": c.HEAP16[p >> 1] = value; continue; - case 'i32': + case "i32": c.HEAP32[p >> 2] = value; continue; - case 'float': - case 'f32': + case "float": + case "f32": c.HEAP32F[p >> 2] = value; continue; - case 'double': - case 'f64': + case "double": + case "f64": c.HEAP64F[p >> 3] = value; continue; - case 'i64': + case "i64": if (c.HEAP64) { c.HEAP64[p >> 3] = BigInt(value); continue; } default: - toss('Invalid type for poke(): ' + type); + toss("Invalid type for poke(): " + type); } } return this; @@ -7053,34 +6740,34 @@ var sqlite3InitModule = (() => { target.pokePtr = (ptr, value = 0) => target.poke(ptr, value, ptrIR); target.peek8 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'i8'); + target.peek(1 === ptr.length ? ptr[0] : ptr, "i8"); - target.poke8 = (ptr, value) => target.poke(ptr, value, 'i8'); + target.poke8 = (ptr, value) => target.poke(ptr, value, "i8"); target.peek16 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'i16'); + target.peek(1 === ptr.length ? ptr[0] : ptr, "i16"); - target.poke16 = (ptr, value) => target.poke(ptr, value, 'i16'); + target.poke16 = (ptr, value) => target.poke(ptr, value, "i16"); target.peek32 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'i32'); + target.peek(1 === ptr.length ? ptr[0] : ptr, "i32"); - target.poke32 = (ptr, value) => target.poke(ptr, value, 'i32'); + target.poke32 = (ptr, value) => target.poke(ptr, value, "i32"); target.peek64 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'i64'); + target.peek(1 === ptr.length ? ptr[0] : ptr, "i64"); - target.poke64 = (ptr, value) => target.poke(ptr, value, 'i64'); + target.poke64 = (ptr, value) => target.poke(ptr, value, "i64"); target.peek32f = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'f32'); + target.peek(1 === ptr.length ? ptr[0] : ptr, "f32"); - target.poke32f = (ptr, value) => target.poke(ptr, value, 'f32'); + target.poke32f = (ptr, value) => target.poke(ptr, value, "f32"); target.peek64f = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, 'f64'); + target.peek(1 === ptr.length ? ptr[0] : ptr, "f64"); - target.poke64f = (ptr, value) => target.poke(ptr, value, 'f64'); + target.poke64f = (ptr, value) => target.poke(ptr, value, "f64"); target.getMemValue = target.peek; @@ -7091,7 +6778,7 @@ var sqlite3InitModule = (() => { target.setPtrValue = target.pokePtr; target.isPtr32 = (ptr) => - 'number' === typeof ptr && ptr === (ptr | 0) && ptr >= 0; + "number" === typeof ptr && ptr === (ptr | 0) && ptr >= 0; target.isPtr = target.isPtr32; @@ -7104,14 +6791,14 @@ var sqlite3InitModule = (() => { }; const __SAB = - 'undefined' === typeof SharedArrayBuffer + "undefined" === typeof SharedArrayBuffer ? function () {} : SharedArrayBuffer; const __utf8Decode = function (arrayBuffer, begin, end) { return cache.utf8Decoder.decode( arrayBuffer.buffer instanceof __SAB ? arrayBuffer.slice(begin, end) - : arrayBuffer.subarray(begin, end), + : arrayBuffer.subarray(begin, end) ); }; @@ -7120,12 +6807,12 @@ var sqlite3InitModule = (() => { return n ? __utf8Decode(heapWrappers().HEAP8U, ptr, ptr + n) : null === n - ? n - : ''; + ? n + : ""; }; target.jstrlen = function (str) { - if ('string' !== typeof str) return null; + if ("string" !== typeof str) return null; const n = str.length; let len = 0; for (let i = 0; i < n; ++i) { @@ -7147,13 +6834,13 @@ var sqlite3InitModule = (() => { tgt, offset = 0, maxBytes = -1, - addNul = true, + addNul = true ) { if ( !tgt || (!(tgt instanceof Int8Array) && !(tgt instanceof Uint8Array)) ) { - toss('jstrcpy() target must be an Int8Array or Uint8Array.'); + toss("jstrcpy() target must be an Int8Array or Uint8Array."); } if (maxBytes < 0) maxBytes = tgt.length - offset; if (!(maxBytes > 0) || !(offset >= 0)) return 0; @@ -7194,7 +6881,7 @@ var sqlite3InitModule = (() => { target.cstrncpy = function (tgtPtr, srcPtr, n) { if (!tgtPtr || !srcPtr) - toss('cstrncpy() does not accept NULL strings.'); + toss("cstrncpy() does not accept NULL strings."); if (n < 0) n = target.cstrlen(strPtr) + 1; else if (!(n > 0)) return 0; const heap = target.heap8u(); @@ -7208,7 +6895,7 @@ var sqlite3InitModule = (() => { }; target.jstrToUintArray = (str, addNul = false) => { - return cache.utf8Encoder.encode(addNul ? str + '\0' : str); + return cache.utf8Encoder.encode(addNul ? str + "\0" : str); }; const __affirmAlloc = (obj, funcName) => { @@ -7217,9 +6904,9 @@ var sqlite3InitModule = (() => { !(obj.dealloc instanceof Function) ) { toss( - 'Object is missing alloc() and/or dealloc() function(s)', - 'required by', - funcName + '().', + "Object is missing alloc() and/or dealloc() function(s)", + "required by", + funcName + "()." ); } }; @@ -7228,10 +6915,10 @@ var sqlite3InitModule = (() => { jstr, returnWithLength, allocator, - funcName, + funcName ) { __affirmAlloc(target, funcName); - if ('string' !== typeof jstr) return null; + if ("string" !== typeof jstr) return null; { const u = cache.utf8Encoder.encode(jstr), ptr = allocator(u.length + 1), @@ -7243,21 +6930,21 @@ var sqlite3InitModule = (() => { }; target.allocCString = (jstr, returnWithLength = false) => - __allocCStr(jstr, returnWithLength, target.alloc, 'allocCString()'); + __allocCStr(jstr, returnWithLength, target.alloc, "allocCString()"); target.scopedAllocPush = function () { - __affirmAlloc(target, 'scopedAllocPush'); + __affirmAlloc(target, "scopedAllocPush"); const a = []; cache.scopedAlloc.push(a); return a; }; target.scopedAllocPop = function (state) { - __affirmAlloc(target, 'scopedAllocPop'); + __affirmAlloc(target, "scopedAllocPop"); const n = arguments.length ? cache.scopedAlloc.indexOf(state) : cache.scopedAlloc.length - 1; - if (n < 0) toss('Invalid state object for scopedAllocPop().'); + if (n < 0) toss("Invalid state object for scopedAllocPop()."); if (0 === arguments.length) state = cache.scopedAlloc[n]; cache.scopedAlloc.splice(n, 1); for (let p; (p = state.pop()); ) { @@ -7269,14 +6956,14 @@ var sqlite3InitModule = (() => { target.scopedAlloc = function (n) { if (!cache.scopedAlloc.length) { - toss('No scopedAllocPush() scope is active.'); + toss("No scopedAllocPush() scope is active."); } const p = target.alloc(n); cache.scopedAlloc[cache.scopedAlloc.length - 1].push(p); return p; }; - Object.defineProperty(target.scopedAlloc, 'level', { + Object.defineProperty(target.scopedAlloc, "level", { configurable: false, enumerable: false, get: () => cache.scopedAlloc.length, @@ -7288,18 +6975,18 @@ var sqlite3InitModule = (() => { jstr, returnWithLength, target.scopedAlloc, - 'scopedAllocCString()', + "scopedAllocCString()" ); const __allocMainArgv = function (isScoped, list) { - const pList = target[isScoped ? 'scopedAlloc' : 'alloc']( - (list.length + 1) * target.ptrSizeof, + const pList = target[isScoped ? "scopedAlloc" : "alloc"]( + (list.length + 1) * target.ptrSizeof ); let i = 0; list.forEach((e) => { target.pokePtr( pList + target.ptrSizeof * i++, - target[isScoped ? 'scopedAllocCString' : 'allocCString']('' + e), + target[isScoped ? "scopedAllocCString" : "allocCString"]("" + e) ); }); target.pokePtr(pList + target.ptrSizeof * i, 0); @@ -7330,7 +7017,7 @@ var sqlite3InitModule = (() => { const __allocPtr = function (howMany, safePtrSize, method) { __affirmAlloc(target, method); - const pIr = safePtrSize ? 'i64' : ptrIR; + const pIr = safePtrSize ? "i64" : ptrIR; let m = target[method](howMany * (safePtrSize ? 8 : ptrSizeof)); target.poke(m, 0, pIr); if (1 === howMany) { @@ -7346,24 +7033,24 @@ var sqlite3InitModule = (() => { }; target.allocPtr = (howMany = 1, safePtrSize = true) => - __allocPtr(howMany, safePtrSize, 'alloc'); + __allocPtr(howMany, safePtrSize, "alloc"); target.scopedAllocPtr = (howMany = 1, safePtrSize = true) => - __allocPtr(howMany, safePtrSize, 'scopedAlloc'); + __allocPtr(howMany, safePtrSize, "scopedAlloc"); target.xGet = function (name) { return ( - target.exports[name] || toss('Cannot find exported symbol:', name) + target.exports[name] || toss("Cannot find exported symbol:", name) ); }; const __argcMismatch = (f, n) => - toss(f + '() requires', n, 'argument(s).'); + toss(f + "() requires", n, "argument(s)."); target.xCall = function (fname, ...args) { const f = fname instanceof Function ? fname : target.xGet(fname); if (!(f instanceof Function)) - toss('Exported symbol', fname, 'is not a function.'); + toss("Exported symbol", fname, "is not a function."); if (f.length !== args.length) __argcMismatch(f === fname ? f.name : fname, f.length); return 2 === arguments.length && Array.isArray(arguments[1]) @@ -7381,73 +7068,73 @@ var sqlite3InitModule = (() => { xResult = cache.xWrap.convert.result; if (target.bigIntEnabled) { - xArg.set('i64', (i) => BigInt(i)); + xArg.set("i64", (i) => BigInt(i)); } const __xArgPtr = - 'i32' === ptrIR ? (i) => i | 0 : (i) => BigInt(i) | BigInt(0); + "i32" === ptrIR ? (i) => i | 0 : (i) => BigInt(i) | BigInt(0); xArg - .set('i32', __xArgPtr) - .set('i16', (i) => (i | 0) & 0xffff) - .set('i8', (i) => (i | 0) & 0xff) - .set('f32', (i) => Number(i).valueOf()) - .set('float', xArg.get('f32')) - .set('f64', xArg.get('f32')) - .set('double', xArg.get('f64')) - .set('int', xArg.get('i32')) - .set('null', (i) => i) - .set(null, xArg.get('null')) - .set('**', __xArgPtr) - .set('*', __xArgPtr); + .set("i32", __xArgPtr) + .set("i16", (i) => (i | 0) & 0xffff) + .set("i8", (i) => (i | 0) & 0xff) + .set("f32", (i) => Number(i).valueOf()) + .set("float", xArg.get("f32")) + .set("f64", xArg.get("f32")) + .set("double", xArg.get("f64")) + .set("int", xArg.get("i32")) + .set("null", (i) => i) + .set(null, xArg.get("null")) + .set("**", __xArgPtr) + .set("*", __xArgPtr); xResult - .set('*', __xArgPtr) - .set('pointer', __xArgPtr) - .set('number', (v) => Number(v)) - .set('void', (v) => undefined) - .set('null', (v) => v) - .set(null, xResult.get('null')); + .set("*", __xArgPtr) + .set("pointer", __xArgPtr) + .set("number", (v) => Number(v)) + .set("void", (v) => undefined) + .set("null", (v) => v) + .set(null, xResult.get("null")); { const copyToResult = [ - 'i8', - 'i16', - 'i32', - 'int', - 'f32', - 'float', - 'f64', - 'double', + "i8", + "i16", + "i32", + "int", + "f32", + "float", + "f64", + "double", ]; - if (target.bigIntEnabled) copyToResult.push('i64'); + if (target.bigIntEnabled) copyToResult.push("i64"); const adaptPtr = xArg.get(ptrIR); for (const t of copyToResult) { - xArg.set(t + '*', adaptPtr); - xResult.set(t + '*', adaptPtr); - xResult.set(t, xArg.get(t) || toss('Missing arg converter:', t)); + xArg.set(t + "*", adaptPtr); + xResult.set(t + "*", adaptPtr); + xResult.set(t, xArg.get(t) || toss("Missing arg converter:", t)); } } const __xArgString = function (v) { - if ('string' === typeof v) return target.scopedAllocCString(v); + if ("string" === typeof v) return target.scopedAllocCString(v); return v ? __xArgPtr(v) : null; }; xArg - .set('string', __xArgString) - .set('utf8', __xArgString) - .set('pointer', __xArgString); + .set("string", __xArgString) + .set("utf8", __xArgString) + .set("pointer", __xArgString); xResult - .set('string', (i) => target.cstrToJs(i)) - .set('utf8', xResult.get('string')) - .set('string:dealloc', (i) => { + .set("string", (i) => target.cstrToJs(i)) + .set("utf8", xResult.get("string")) + .set("string:dealloc", (i) => { try { return i ? target.cstrToJs(i) : null; } finally { target.dealloc(i); } }) - .set('utf8:dealloc', xResult.get('string:dealloc')) - .set('json', (i) => JSON.parse(target.cstrToJs(i))) - .set('json:dealloc', (i) => { + .set("utf8:dealloc", xResult.get("string:dealloc")) + .set("json", (i) => JSON.parse(target.cstrToJs(i))) + .set("json:dealloc", (i) => { try { return i ? JSON.parse(target.cstrToJs(i)) : null; } finally { @@ -7457,11 +7144,11 @@ var sqlite3InitModule = (() => { const AbstractArgAdapter = class { constructor(opt) { - this.name = opt.name || 'unnamed adapter'; + this.name = opt.name || "unnamed adapter"; } convertArg(v, argv, argIndex) { - toss('AbstractArgAdapter must be subclassed.'); + toss("AbstractArgAdapter must be subclassed."); } }; @@ -7470,37 +7157,37 @@ var sqlite3InitModule = (() => { super(opt); if (xArg.FuncPtrAdapter.warnOnUse) { console.warn( - 'xArg.FuncPtrAdapter is an internal-only API', - 'and is not intended to be invoked from', - 'client-level code. Invoked with:', - opt, + "xArg.FuncPtrAdapter is an internal-only API", + "and is not intended to be invoked from", + "client-level code. Invoked with:", + opt ); } - this.name = opt.name || 'unnamed'; + this.name = opt.name || "unnamed"; this.signature = opt.signature; if (opt.contextKey instanceof Function) { this.contextKey = opt.contextKey; - if (!opt.bindScope) opt.bindScope = 'context'; + if (!opt.bindScope) opt.bindScope = "context"; } this.bindScope = opt.bindScope || toss( - 'FuncPtrAdapter options requires a bindScope (explicit or implied).', + "FuncPtrAdapter options requires a bindScope (explicit or implied)." ); if (FuncPtrAdapter.bindScopes.indexOf(opt.bindScope) < 0) { toss( - 'Invalid options.bindScope (' + + "Invalid options.bindScope (" + opt.bindMod + - ') for FuncPtrAdapter. ' + - 'Expecting one of: (' + - FuncPtrAdapter.bindScopes.join(', ') + - ')', + ") for FuncPtrAdapter. " + + "Expecting one of: (" + + FuncPtrAdapter.bindScopes.join(", ") + + ")" ); } - this.isTransient = 'transient' === this.bindScope; - this.isContext = 'context' === this.bindScope; - this.isPermanent = 'permanent' === this.bindScope; - this.singleton = 'singleton' === this.bindScope ? [] : undefined; + this.isTransient = "transient" === this.bindScope; + this.isContext = "context" === this.bindScope; + this.isPermanent = "permanent" === this.bindScope; + this.singleton = "singleton" === this.bindScope ? [] : undefined; this.callProxy = opt.callProxy instanceof Function ? opt.callProxy : undefined; @@ -7528,27 +7215,27 @@ var sqlite3InitModule = (() => { const fp = __installFunction(v, this.signature, this.isTransient); if (FuncPtrAdapter.debugFuncInstall) { FuncPtrAdapter.debugOut( - 'FuncPtrAdapter installed', + "FuncPtrAdapter installed", this, this.contextKey(argv, argIndex), - '@' + fp, - v, + "@" + fp, + v ); } if (pair) { if (pair[1]) { if (FuncPtrAdapter.debugFuncInstall) { FuncPtrAdapter.debugOut( - 'FuncPtrAdapter uninstalling', + "FuncPtrAdapter uninstalling", this, this.contextKey(argv, argIndex), - '@' + pair[1], - v, + "@" + pair[1], + v ); } try { cache.scopedAlloc[cache.scopedAlloc.length - 1].push( - pair[1], + pair[1] ); } catch (e) {} } @@ -7560,11 +7247,11 @@ var sqlite3InitModule = (() => { if (pair && pair[1] && pair[1] !== v) { if (FuncPtrAdapter.debugFuncInstall) { FuncPtrAdapter.debugOut( - 'FuncPtrAdapter uninstalling', + "FuncPtrAdapter uninstalling", this, this.contextKey(argv, argIndex), - '@' + pair[1], - v, + "@" + pair[1], + v ); } try { @@ -7575,12 +7262,12 @@ var sqlite3InitModule = (() => { return v || 0; } else { throw new TypeError( - 'Invalid FuncPtrAdapter argument type. ' + - 'Expecting a function pointer or a ' + - (this.name ? this.name + ' ' : '') + - 'function matching signature ' + + "Invalid FuncPtrAdapter argument type. " + + "Expecting a function pointer or a " + + (this.name ? this.name + " " : "") + + "function matching signature " + this.signature + - '.', + "." ); } } @@ -7593,17 +7280,17 @@ var sqlite3InitModule = (() => { xArg.FuncPtrAdapter.debugOut = console.debug.bind(console); xArg.FuncPtrAdapter.bindScopes = [ - 'transient', - 'context', - 'singleton', - 'permanent', + "transient", + "context", + "singleton", + "permanent", ]; const __xArgAdapterCheck = (t) => - xArg.get(t) || toss('Argument adapter not found:', t); + xArg.get(t) || toss("Argument adapter not found:", t); const __xResultAdapterCheck = (t) => - xResult.get(t) || toss('Result adapter not found:', t); + xResult.get(t) || toss("Result adapter not found:", t); cache.xWrap.convertArg = (t, ...args) => __xArgAdapterCheck(t)(...args); @@ -7622,11 +7309,11 @@ var sqlite3InitModule = (() => { if (target.isPtr(fArg)) { fArg = target.functionEntry(fArg) || - toss('Function pointer not found in WASM function table.'); + toss("Function pointer not found in WASM function table."); } const fIsFunc = fArg instanceof Function; const xf = fIsFunc ? fArg : target.xGet(fArg); - if (fIsFunc) fArg = xf.name || 'unnamed function'; + if (fIsFunc) fArg = xf.name || "unnamed function"; if (argTypes.length !== xf.length) __argcMismatch(fArg, xf.length); if (null === resultType && 0 === xf.length) { return xf; @@ -7665,22 +7352,22 @@ var sqlite3InitModule = (() => { typeName, adapter, modeName, - xcvPart, + xcvPart ) { - if ('string' === typeof typeName) { + if ("string" === typeof typeName) { if (1 === argc) return xcvPart.get(typeName); else if (2 === argc) { if (!adapter) { delete xcvPart.get(typeName); return func; } else if (!(adapter instanceof Function)) { - toss(modeName, 'requires a function argument.'); + toss(modeName, "requires a function argument."); } xcvPart.set(typeName, adapter); return func; } } - toss('Invalid arguments to', modeName); + toss("Invalid arguments to", modeName); }; target.xWrap.resultAdapter = function f(typeName, adapter) { @@ -7689,8 +7376,8 @@ var sqlite3InitModule = (() => { arguments.length, typeName, adapter, - 'resultAdapter()', - xResult, + "resultAdapter()", + xResult ); }; @@ -7700,8 +7387,8 @@ var sqlite3InitModule = (() => { arguments.length, typeName, adapter, - 'argAdapter()', - xArg, + "argAdapter()", + xArg ); }; @@ -7722,12 +7409,12 @@ var sqlite3InitModule = (() => { }; globalThis.WhWasmUtilInstaller.yawl = function (config) { - const wfetch = () => fetch(config.uri, { credentials: 'same-origin' }); + const wfetch = () => fetch(config.uri, { credentials: "same-origin" }); const wui = this; const finalThen = function (arg) { if (config.wasmUtilTarget) { const toss = (...args) => { - throw new Error(args.join(' ')); + throw new Error(args.join(" ")); }; const tgt = config.wasmUtilTarget; tgt.module = arg.module; @@ -7744,7 +7431,7 @@ var sqlite3InitModule = (() => { const exports = arg.instance.exports; tgt.alloc = function (n) { return ( - exports.malloc(n) || toss('Allocation of', n, 'bytes failed.') + exports.malloc(n) || toss("Allocation of", n, "bytes failed.") ); }; tgt.dealloc = function (m) { @@ -7760,14 +7447,14 @@ var sqlite3InitModule = (() => { ? function loadWasmStreaming() { return WebAssembly.instantiateStreaming( wfetch(), - config.imports || {}, + config.imports || {} ).then(finalThen); } : function loadWasmOldSchool() { return wfetch() .then((response) => response.arrayBuffer()) .then((bytes) => - WebAssembly.instantiate(bytes, config.imports || {}), + WebAssembly.instantiate(bytes, config.imports || {}) ) .then(finalThen); }; @@ -7775,7 +7462,7 @@ var sqlite3InitModule = (() => { }.bind(globalThis.WhWasmUtilInstaller); globalThis.Jaccwabyt = function StructBinderFactory(config) { const toss = (...args) => { - throw new Error(args.join(' ')); + throw new Error(args.join(" ")); }; if ( @@ -7783,10 +7470,10 @@ var sqlite3InitModule = (() => { !(config.heap instanceof Function) ) { toss( - 'config.heap must be WebAssembly.Memory instance or a function.', + "config.heap must be WebAssembly.Memory instance or a function." ); } - ['alloc', 'dealloc'].forEach(function (k) { + ["alloc", "dealloc"].forEach(function (k) { config[k] instanceof Function || toss("Config option '" + k + "' must be a function."); }); @@ -7798,16 +7485,16 @@ var sqlite3InitModule = (() => { alloc = config.alloc, dealloc = config.dealloc, log = config.log || console.log.bind(console), - memberPrefix = config.memberPrefix || '', - memberSuffix = config.memberSuffix || '', + memberPrefix = config.memberPrefix || "", + memberSuffix = config.memberSuffix || "", bigIntEnabled = undefined === config.bigIntEnabled - ? !!globalThis['BigInt64Array'] + ? !!globalThis["BigInt64Array"] : !!config.bigIntEnabled, - BigInt = globalThis['BigInt'], - BigInt64Array = globalThis['BigInt64Array'], + BigInt = globalThis["BigInt"], + BigInt64Array = globalThis["BigInt64Array"], ptrSizeof = config.ptrSizeof || 4, - ptrIR = config.ptrIR || 'i32'; + ptrIR = config.ptrIR || "i32"; if (!SBF.debugFlags) { SBF.__makeDebugFlags = function (deriveFrom = null) { if (deriveFrom && deriveFrom.__flags) @@ -7829,7 +7516,7 @@ var sqlite3InitModule = (() => { } return f._flags; }; - Object.defineProperty(f, '__flags', { + Object.defineProperty(f, "__flags", { iterable: false, writable: false, value: Object.create(deriveFrom), @@ -7847,106 +7534,106 @@ var sqlite3InitModule = (() => { return new Int16Array(buffer)[0] === 256; })(); - const isFuncSig = (s) => '(' === s[1]; - const isAutoPtrSig = (s) => 'P' === s; - const sigLetter = (s) => (isFuncSig(s) ? 'p' : s[0]); + const isFuncSig = (s) => "(" === s[1]; + const isAutoPtrSig = (s) => "P" === s; + const sigLetter = (s) => (isFuncSig(s) ? "p" : s[0]); const sigIR = function (s) { switch (sigLetter(s)) { - case 'c': - case 'C': - return 'i8'; - case 'i': - return 'i32'; - case 'p': - case 'P': - case 's': + case "c": + case "C": + return "i8"; + case "i": + return "i32"; + case "p": + case "P": + case "s": return ptrIR; - case 'j': - return 'i64'; - case 'f': - return 'float'; - case 'd': - return 'double'; + case "j": + return "i64"; + case "f": + return "float"; + case "d": + return "double"; } - toss('Unhandled signature IR:', s); + toss("Unhandled signature IR:", s); }; const affirmBigIntArray = BigInt64Array ? () => true - : () => toss('BigInt64Array is not available.'); + : () => toss("BigInt64Array is not available."); const sigDVGetter = function (s) { switch (sigLetter(s)) { - case 'p': - case 'P': - case 's': { + case "p": + case "P": + case "s": { switch (ptrSizeof) { case 4: - return 'getInt32'; + return "getInt32"; case 8: - return affirmBigIntArray() && 'getBigInt64'; + return affirmBigIntArray() && "getBigInt64"; } break; } - case 'i': - return 'getInt32'; - case 'c': - return 'getInt8'; - case 'C': - return 'getUint8'; - case 'j': - return affirmBigIntArray() && 'getBigInt64'; - case 'f': - return 'getFloat32'; - case 'd': - return 'getFloat64'; + case "i": + return "getInt32"; + case "c": + return "getInt8"; + case "C": + return "getUint8"; + case "j": + return affirmBigIntArray() && "getBigInt64"; + case "f": + return "getFloat32"; + case "d": + return "getFloat64"; } - toss('Unhandled DataView getter for signature:', s); + toss("Unhandled DataView getter for signature:", s); }; const sigDVSetter = function (s) { switch (sigLetter(s)) { - case 'p': - case 'P': - case 's': { + case "p": + case "P": + case "s": { switch (ptrSizeof) { case 4: - return 'setInt32'; + return "setInt32"; case 8: - return affirmBigIntArray() && 'setBigInt64'; + return affirmBigIntArray() && "setBigInt64"; } break; } - case 'i': - return 'setInt32'; - case 'c': - return 'setInt8'; - case 'C': - return 'setUint8'; - case 'j': - return affirmBigIntArray() && 'setBigInt64'; - case 'f': - return 'setFloat32'; - case 'd': - return 'setFloat64'; + case "i": + return "setInt32"; + case "c": + return "setInt8"; + case "C": + return "setUint8"; + case "j": + return affirmBigIntArray() && "setBigInt64"; + case "f": + return "setFloat32"; + case "d": + return "setFloat64"; } - toss('Unhandled DataView setter for signature:', s); + toss("Unhandled DataView setter for signature:", s); }; const sigDVSetWrapper = function (s) { switch (sigLetter(s)) { - case 'i': - case 'f': - case 'c': - case 'C': - case 'd': + case "i": + case "f": + case "c": + case "C": + case "d": return Number; - case 'j': + case "j": return affirmBigIntArray() && BigInt; - case 'p': - case 'P': - case 's': + case "p": + case "P": + case "s": switch (ptrSizeof) { case 4: return Number; @@ -7955,18 +7642,18 @@ var sqlite3InitModule = (() => { } break; } - toss('Unhandled DataView set wrapper for signature:', s); + toss("Unhandled DataView set wrapper for signature:", s); }; - const sPropName = (s, k) => s + '::' + k; + const sPropName = (s, k) => s + "::" + k; const __propThrowOnSet = function (structName, propName) { - return () => toss(sPropName(structName, propName), 'is read-only.'); + return () => toss(sPropName(structName, propName), "is read-only."); }; const __instancePointerMap = new WeakMap(); - const xPtrPropName = '(pointer-is-external)'; + const xPtrPropName = "(pointer-is-external)"; const __freeStruct = function (ctor, obj, m) { if (!m) m = __instancePointerMap.get(obj); @@ -7978,15 +7665,15 @@ var sqlite3InitModule = (() => { try { if (x instanceof Function) x.call(obj); else if (x instanceof StructType) x.dispose(); - else if ('number' === typeof x) dealloc(x); + else if ("number" === typeof x) dealloc(x); } catch (e) { console.warn( - 'ondispose() for', + "ondispose() for", ctor.structName, - '@', + "@", m, - 'threw. NOT propagating it.', - e, + "threw. NOT propagating it.", + e ); } } @@ -7995,24 +7682,24 @@ var sqlite3InitModule = (() => { obj.ondispose(); } catch (e) { console.warn( - 'ondispose() for', + "ondispose() for", ctor.structName, - '@', + "@", m, - 'threw. NOT propagating it.', - e, + "threw. NOT propagating it.", + e ); } } delete obj.ondispose; if (ctor.debugFlags.__flags.dealloc) { log( - 'debug.dealloc:', - obj[xPtrPropName] ? 'EXTERNAL' : '', + "debug.dealloc:", + obj[xPtrPropName] ? "EXTERNAL" : "", ctor.structName, - 'instance:', + "instance:", ctor.structInfo.sizeof, - 'bytes @' + m, + "bytes @" + m ); } if (!obj[xPtrPropName]) dealloc(m); @@ -8033,17 +7720,17 @@ var sqlite3InitModule = (() => { if (m) Object.defineProperty(obj, xPtrPropName, rop(m)); else { m = alloc(ctor.structInfo.sizeof); - if (!m) toss('Allocation of', ctor.structName, 'structure failed.'); + if (!m) toss("Allocation of", ctor.structName, "structure failed."); } try { if (ctor.debugFlags.__flags.alloc) { log( - 'debug.alloc:', - fill ? '' : 'EXTERNAL', + "debug.alloc:", + fill ? "" : "EXTERNAL", ctor.structName, - 'instance:', + "instance:", ctor.structInfo.sizeof, - 'bytes @' + m, + "bytes @" + m ); } if (fill) heap().fill(0, m, m + ctor.structInfo.sizeof); @@ -8067,7 +7754,7 @@ var sqlite3InitModule = (() => { const __lookupMember = function ( structInfo, memberName, - tossIfNotFound = true, + tossIfNotFound = true ) { let m = structInfo.members[memberName]; if (!m && (memberPrefix || memberSuffix)) { @@ -8080,7 +7767,7 @@ var sqlite3InitModule = (() => { if (!m && tossIfNotFound) { toss( sPropName(structInfo.name, memberName), - 'is not a mapped struct member.', + "is not a mapped struct member." ); } } @@ -8090,11 +7777,11 @@ var sqlite3InitModule = (() => { const __memberSignature = function f( obj, memberName, - emscriptenFormat = false, + emscriptenFormat = false ) { if (!f._) f._ = (x) => - x.replace(/[^vipPsjrdcC]/g, '').replace(/[pPscC]/g, 'i'); + x.replace(/[^vipPsjrdcC]/g, "").replace(/[pPscC]/g, "i"); const m = __lookupMember(obj.structInfo, memberName, true); return emscriptenFormat ? f._(m.signature) : m.signature; }; @@ -8116,37 +7803,37 @@ var sqlite3InitModule = (() => { return a; }); - const __utf8Decoder = new TextDecoder('utf-8'); + const __utf8Decoder = new TextDecoder("utf-8"); const __utf8Encoder = new TextEncoder(); const __SAB = - 'undefined' === typeof SharedArrayBuffer + "undefined" === typeof SharedArrayBuffer ? function () {} : SharedArrayBuffer; const __utf8Decode = function (arrayBuffer, begin, end) { return __utf8Decoder.decode( arrayBuffer.buffer instanceof __SAB ? arrayBuffer.slice(begin, end) - : arrayBuffer.subarray(begin, end), + : arrayBuffer.subarray(begin, end) ); }; const __memberIsString = function ( obj, memberName, - tossIfNotFound = false, + tossIfNotFound = false ) { const m = __lookupMember(obj.structInfo, memberName, tossIfNotFound); - return m && 1 === m.signature.length && 's' === m.signature[0] + return m && 1 === m.signature.length && "s" === m.signature[0] ? m : false; }; const __affirmCStringSignature = function (member) { - if ('s' === member.signature) return; + if ("s" === member.signature) return; toss( - 'Invalid member type signature for C-string value:', - JSON.stringify(member), + "Invalid member type signature for C-string value:", + JSON.stringify(member) ); }; @@ -8160,7 +7847,7 @@ var sqlite3InitModule = (() => { const mem = heap(); for (; mem[pos] !== 0; ++pos) {} - return addr === pos ? '' : __utf8Decode(mem, addr, pos); + return addr === pos ? "" : __utf8Decode(mem, addr, pos); }; const __addOnDispose = function (obj, ...v) { @@ -8177,7 +7864,7 @@ var sqlite3InitModule = (() => { const __allocCString = function (str) { const u = __utf8Encoder.encode(str); const mem = alloc(u.length + 1); - if (!mem) toss('Allocation error while duplicating string:', str); + if (!mem) toss("Allocation error while duplicating string:", str); const h = heap(); h.set(u, mem); @@ -8199,8 +7886,8 @@ var sqlite3InitModule = (() => { const StructType = function ctor(structName, structInfo) { if (arguments[2] !== rop) { toss( - 'Do not call the StructType constructor', - 'from client-level code.', + "Do not call the StructType constructor", + "from client-level code." ); } Object.defineProperties(this, { @@ -8245,7 +7932,7 @@ var sqlite3InitModule = (() => { allocCString: rop(__allocCString), isA: rop((v) => v instanceof StructType), hasExternalPointer: rop( - (v) => v instanceof StructType && !!v[xPtrPropName], + (v) => v instanceof StructType && !!v[xPtrPropName] ), memberKey: __memberKeyProp, }); @@ -8256,8 +7943,8 @@ var sqlite3InitModule = (() => { const makeMemberWrapper = function f(ctor, name, descr) { if (!f._) { f._ = { getters: {}, setters: {}, sw: {} }; - const a = ['i', 'c', 'C', 'p', 'P', 's', 'f', 'd', 'v()']; - if (bigIntEnabled) a.push('j'); + const a = ["i", "c", "C", "p", "P", "s", "f", "d", "v()"]; + if (bigIntEnabled) a.push("j"); a.forEach(function (v) { f._.getters[v] = sigDVGetter(v); f._.setters[v] = sigDVSetter(v); @@ -8267,14 +7954,14 @@ var sqlite3InitModule = (() => { rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/; f.sigCheck = function (obj, name, key, sig) { if (Object.prototype.hasOwnProperty.call(obj, key)) { - toss(obj.structName, 'already has a property named', key + '.'); + toss(obj.structName, "already has a property named", key + "."); } rxSig1.test(sig) || rxSig2.test(sig) || toss( - 'Malformed signature for', - sPropName(obj.structName, name) + ':', - sig, + "Malformed signature for", + sPropName(obj.structName, name) + ":", + sig ); }; } @@ -8292,25 +7979,25 @@ var sqlite3InitModule = (() => { prop.get = function () { if (dbg.getter) { log( - 'debug.getter:', + "debug.getter:", f._.getters[sigGlyph], - 'for', + "for", sigIR(sigGlyph), xPropName, - '@', + "@", this.pointer, - '+', + "+", descr.offset, - 'sz', - descr.sizeof, + "sz", + descr.sizeof ); } let rc = new DataView( heap().buffer, this.pointer + descr.offset, - descr.sizeof, + descr.sizeof )[f._.getters[sigGlyph]](0, isLittleEndian); - if (dbg.getter) log('debug.getter:', xPropName, 'result =', rc); + if (dbg.getter) log("debug.getter:", xPropName, "result =", rc); return rc; }; if (descr.readOnly) { @@ -8319,22 +8006,22 @@ var sqlite3InitModule = (() => { prop.set = function (v) { if (dbg.setter) { log( - 'debug.setter:', + "debug.setter:", f._.setters[sigGlyph], - 'for', + "for", sigIR(sigGlyph), xPropName, - '@', + "@", this.pointer, - '+', + "+", descr.offset, - 'sz', + "sz", descr.sizeof, - v, + v ); } if (!this.pointer) { - toss('Cannot set struct property on disposed instance.'); + toss("Cannot set struct property on disposed instance."); } if (null === v) v = 0; else @@ -8345,15 +8032,15 @@ var sqlite3InitModule = (() => { ) { v = v.pointer || 0; if (dbg.setter) - log('debug.setter:', xPropName, 'resolved to', v); + log("debug.setter:", xPropName, "resolved to", v); break; } - toss('Invalid value for pointer-type', xPropName + '.'); + toss("Invalid value for pointer-type", xPropName + "."); } new DataView( heap().buffer, this.pointer + descr.offset, - descr.sizeof, + descr.sizeof )[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian); }; } @@ -8367,59 +8054,59 @@ var sqlite3InitModule = (() => { } else if (!structInfo.name) { structInfo.name = structName; } - if (!structName) toss('Struct name is required.'); + if (!structName) toss("Struct name is required."); let lastMember = false; Object.keys(structInfo.members).forEach((k) => { const m = structInfo.members[k]; - if (!m.sizeof) toss(structName, 'member', k, 'is missing sizeof.'); + if (!m.sizeof) toss(structName, "member", k, "is missing sizeof."); else if (m.sizeof === 1) { - m.signature === 'c' || - m.signature === 'C' || + m.signature === "c" || + m.signature === "C" || toss( - 'Unexpected sizeof==1 member', + "Unexpected sizeof==1 member", sPropName(structInfo.name, k), - 'with signature', - m.signature, + "with signature", + m.signature ); } else { if (0 !== m.sizeof % 4) { console.warn( - 'Invalid struct member description =', + "Invalid struct member description =", m, - 'from', - structInfo, + "from", + structInfo ); toss( structName, - 'member', + "member", k, - 'sizeof is not aligned. sizeof=' + m.sizeof, + "sizeof is not aligned. sizeof=" + m.sizeof ); } if (0 !== m.offset % 4) { console.warn( - 'Invalid struct member description =', + "Invalid struct member description =", m, - 'from', - structInfo, + "from", + structInfo ); toss( structName, - 'member', + "member", k, - 'offset is not aligned. offset=' + m.offset, + "offset is not aligned. offset=" + m.offset ); } } if (!lastMember || lastMember.offset < m.offset) lastMember = m; }); - if (!lastMember) toss('No member property descriptions found.'); + if (!lastMember) toss("No member property descriptions found."); else if (structInfo.sizeof < lastMember.offset + lastMember.sizeof) { toss( - 'Invalid struct config:', + "Invalid struct config:", structName, - 'max member offset (' + lastMember.offset + ') ', - 'extends past end of struct (sizeof=' + structInfo.sizeof + ').', + "max member offset (" + lastMember.offset + ") ", + "extends past end of struct (sizeof=" + structInfo.sizeof + ")." ); } const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags)); @@ -8427,16 +8114,16 @@ var sqlite3InitModule = (() => { const StructCtor = function StructCtor(externalMemory) { if (!(this instanceof StructCtor)) { toss( - 'The', + "The", structName, - "constructor may only be called via 'new'.", + "constructor may only be called via 'new'." ); } else if (arguments.length) { if ( externalMemory !== (externalMemory | 0) || externalMemory <= 0 ) { - toss('Invalid pointer value for', structName, 'constructor.'); + toss("Invalid pointer value for", structName, "constructor."); } __allocStruct(StructCtor, this, externalMemory); } else { @@ -8458,7 +8145,7 @@ var sqlite3InitModule = (() => { constructor: rop(StructCtor), }); Object.keys(structInfo.members).forEach((name) => - makeMemberWrapper(StructCtor, name, structInfo.members[name]), + makeMemberWrapper(StructCtor, name, structInfo.members[name]) ); return StructCtor; }; @@ -8473,7 +8160,7 @@ var sqlite3InitModule = (() => { globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { const toss = (...args) => { - throw new Error(args.join(' ')); + throw new Error(args.join(" ")); }; sqlite3.SQLite3Error.toss; const capi = sqlite3.capi, @@ -8483,84 +8170,84 @@ var sqlite3InitModule = (() => { delete globalThis.WhWasmUtilInstaller; wasm.bindingSignatures = [ - ['sqlite3_aggregate_context', 'void*', 'sqlite3_context*', 'int'], + ["sqlite3_aggregate_context", "void*", "sqlite3_context*", "int"], - ['sqlite3_bind_double', 'int', 'sqlite3_stmt*', 'int', 'f64'], - ['sqlite3_bind_int', 'int', 'sqlite3_stmt*', 'int', 'int'], - ['sqlite3_bind_null', undefined, 'sqlite3_stmt*', 'int'], - ['sqlite3_bind_parameter_count', 'int', 'sqlite3_stmt*'], - ['sqlite3_bind_parameter_index', 'int', 'sqlite3_stmt*', 'string'], + ["sqlite3_bind_double", "int", "sqlite3_stmt*", "int", "f64"], + ["sqlite3_bind_int", "int", "sqlite3_stmt*", "int", "int"], + ["sqlite3_bind_null", undefined, "sqlite3_stmt*", "int"], + ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], + ["sqlite3_bind_parameter_index", "int", "sqlite3_stmt*", "string"], [ - 'sqlite3_bind_pointer', - 'int', - 'sqlite3_stmt*', - 'int', - '*', - 'string:static', - '*', + "sqlite3_bind_pointer", + "int", + "sqlite3_stmt*", + "int", + "*", + "string:static", + "*", ], [ - 'sqlite3_busy_handler', - 'int', + "sqlite3_busy_handler", + "int", [ - 'sqlite3*', + "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ - signature: 'i(pi)', + signature: "i(pi)", contextKey: (argv, argIndex) => argv[0], }), - '*', + "*", ], ], - ['sqlite3_busy_timeout', 'int', 'sqlite3*', 'int'], - - ['sqlite3_changes', 'int', 'sqlite3*'], - ['sqlite3_clear_bindings', 'int', 'sqlite3_stmt*'], - ['sqlite3_collation_needed', 'int', 'sqlite3*', '*', '*'], - ['sqlite3_column_blob', '*', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_bytes', 'int', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_count', 'int', 'sqlite3_stmt*'], - ['sqlite3_column_double', 'f64', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_int', 'int', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_name', 'string', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_text', 'string', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_type', 'int', 'sqlite3_stmt*', 'int'], - ['sqlite3_column_value', 'sqlite3_value*', 'sqlite3_stmt*', 'int'], + ["sqlite3_busy_timeout", "int", "sqlite3*", "int"], + + ["sqlite3_changes", "int", "sqlite3*"], + ["sqlite3_clear_bindings", "int", "sqlite3_stmt*"], + ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"], + ["sqlite3_column_blob", "*", "sqlite3_stmt*", "int"], + ["sqlite3_column_bytes", "int", "sqlite3_stmt*", "int"], + ["sqlite3_column_count", "int", "sqlite3_stmt*"], + ["sqlite3_column_double", "f64", "sqlite3_stmt*", "int"], + ["sqlite3_column_int", "int", "sqlite3_stmt*", "int"], + ["sqlite3_column_name", "string", "sqlite3_stmt*", "int"], + ["sqlite3_column_text", "string", "sqlite3_stmt*", "int"], + ["sqlite3_column_type", "int", "sqlite3_stmt*", "int"], + ["sqlite3_column_value", "sqlite3_value*", "sqlite3_stmt*", "int"], [ - 'sqlite3_commit_hook', - 'void*', + "sqlite3_commit_hook", + "void*", [ - 'sqlite3*', + "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_commit_hook', - signature: 'i(p)', + name: "sqlite3_commit_hook", + signature: "i(p)", contextKey: (argv) => argv[0], }), - '*', + "*", ], ], - ['sqlite3_compileoption_get', 'string', 'int'], - ['sqlite3_compileoption_used', 'int', 'string'], - ['sqlite3_complete', 'int', 'string:flexible'], - ['sqlite3_context_db_handle', 'sqlite3*', 'sqlite3_context*'], - - ['sqlite3_data_count', 'int', 'sqlite3_stmt*'], - ['sqlite3_db_filename', 'string', 'sqlite3*', 'string'], - ['sqlite3_db_handle', 'sqlite3*', 'sqlite3_stmt*'], - ['sqlite3_db_name', 'string', 'sqlite3*', 'int'], - ['sqlite3_db_status', 'int', 'sqlite3*', 'int', '*', '*', 'int'], - ['sqlite3_errcode', 'int', 'sqlite3*'], - ['sqlite3_errmsg', 'string', 'sqlite3*'], - ['sqlite3_error_offset', 'int', 'sqlite3*'], - ['sqlite3_errstr', 'string', 'int'], + ["sqlite3_compileoption_get", "string", "int"], + ["sqlite3_compileoption_used", "int", "string"], + ["sqlite3_complete", "int", "string:flexible"], + ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"], + + ["sqlite3_data_count", "int", "sqlite3_stmt*"], + ["sqlite3_db_filename", "string", "sqlite3*", "string"], + ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], + ["sqlite3_db_name", "string", "sqlite3*", "int"], + ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"], + ["sqlite3_errcode", "int", "sqlite3*"], + ["sqlite3_errmsg", "string", "sqlite3*"], + ["sqlite3_error_offset", "int", "sqlite3*"], + ["sqlite3_errstr", "string", "int"], [ - 'sqlite3_exec', - 'int', + "sqlite3_exec", + "int", [ - 'sqlite3*', - 'string:flexible', + "sqlite3*", + "string:flexible", new wasm.xWrap.FuncPtrAdapter({ - signature: 'i(pipp)', - bindScope: 'transient', + signature: "i(pipp)", + bindScope: "transient", callProxy: (callback) => { let aNames; return (pVoid, nCols, pColVals, pColNames) => { @@ -8574,108 +8261,108 @@ var sqlite3InitModule = (() => { }; }, }), - '*', - '**', + "*", + "**", ], ], - ['sqlite3_expanded_sql', 'string', 'sqlite3_stmt*'], - ['sqlite3_extended_errcode', 'int', 'sqlite3*'], - ['sqlite3_extended_result_codes', 'int', 'sqlite3*', 'int'], - ['sqlite3_file_control', 'int', 'sqlite3*', 'string', 'int', '*'], - ['sqlite3_finalize', 'int', 'sqlite3_stmt*'], - ['sqlite3_free', undefined, '*'], - ['sqlite3_get_autocommit', 'int', 'sqlite3*'], - ['sqlite3_get_auxdata', '*', 'sqlite3_context*', 'int'], - ['sqlite3_initialize', undefined], - - ['sqlite3_keyword_count', 'int'], - ['sqlite3_keyword_name', 'int', ['int', '**', '*']], - ['sqlite3_keyword_check', 'int', ['string', 'int']], - ['sqlite3_libversion', 'string'], - ['sqlite3_libversion_number', 'int'], - ['sqlite3_limit', 'int', ['sqlite3*', 'int', 'int']], - ['sqlite3_malloc', '*', 'int'], - ['sqlite3_open', 'int', 'string', '*'], - ['sqlite3_open_v2', 'int', 'string', '*', 'int', 'string'], + ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], + ["sqlite3_extended_errcode", "int", "sqlite3*"], + ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], + ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"], + ["sqlite3_finalize", "int", "sqlite3_stmt*"], + ["sqlite3_free", undefined, "*"], + ["sqlite3_get_autocommit", "int", "sqlite3*"], + ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"], + ["sqlite3_initialize", undefined], + + ["sqlite3_keyword_count", "int"], + ["sqlite3_keyword_name", "int", ["int", "**", "*"]], + ["sqlite3_keyword_check", "int", ["string", "int"]], + ["sqlite3_libversion", "string"], + ["sqlite3_libversion_number", "int"], + ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]], + ["sqlite3_malloc", "*", "int"], + ["sqlite3_open", "int", "string", "*"], + ["sqlite3_open_v2", "int", "string", "*", "int", "string"], [ - 'sqlite3_progress_handler', + "sqlite3_progress_handler", undefined, [ - 'sqlite3*', - 'int', + "sqlite3*", + "int", new wasm.xWrap.FuncPtrAdapter({ - name: 'xProgressHandler', - signature: 'i(p)', - bindScope: 'context', + name: "xProgressHandler", + signature: "i(p)", + bindScope: "context", contextKey: (argv, argIndex) => argv[0], }), - '*', + "*", ], ], - ['sqlite3_realloc', '*', '*', 'int'], - ['sqlite3_reset', 'int', 'sqlite3_stmt*'], + ["sqlite3_realloc", "*", "*", "int"], + ["sqlite3_reset", "int", "sqlite3_stmt*"], [ - 'sqlite3_result_blob', + "sqlite3_result_blob", undefined, - 'sqlite3_context*', - '*', - 'int', - '*', + "sqlite3_context*", + "*", + "int", + "*", ], - ['sqlite3_result_double', undefined, 'sqlite3_context*', 'f64'], + ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"], [ - 'sqlite3_result_error', + "sqlite3_result_error", undefined, - 'sqlite3_context*', - 'string', - 'int', + "sqlite3_context*", + "string", + "int", ], - ['sqlite3_result_error_code', undefined, 'sqlite3_context*', 'int'], - ['sqlite3_result_error_nomem', undefined, 'sqlite3_context*'], - ['sqlite3_result_error_toobig', undefined, 'sqlite3_context*'], - ['sqlite3_result_int', undefined, 'sqlite3_context*', 'int'], - ['sqlite3_result_null', undefined, 'sqlite3_context*'], + ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"], + ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"], + ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"], + ["sqlite3_result_int", undefined, "sqlite3_context*", "int"], + ["sqlite3_result_null", undefined, "sqlite3_context*"], [ - 'sqlite3_result_pointer', + "sqlite3_result_pointer", undefined, - 'sqlite3_context*', - '*', - 'string:static', - '*', + "sqlite3_context*", + "*", + "string:static", + "*", ], - ['sqlite3_result_subtype', undefined, 'sqlite3_value*', 'int'], + ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"], [ - 'sqlite3_result_text', + "sqlite3_result_text", undefined, - 'sqlite3_context*', - 'string', - 'int', - '*', + "sqlite3_context*", + "string", + "int", + "*", ], - ['sqlite3_result_zeroblob', undefined, 'sqlite3_context*', 'int'], + ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"], [ - 'sqlite3_rollback_hook', - 'void*', + "sqlite3_rollback_hook", + "void*", [ - 'sqlite3*', + "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_rollback_hook', - signature: 'v(p)', + name: "sqlite3_rollback_hook", + signature: "v(p)", contextKey: (argv) => argv[0], }), - '*', + "*", ], ], [ - 'sqlite3_set_authorizer', - 'int', + "sqlite3_set_authorizer", + "int", [ - 'sqlite3*', + "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_set_authorizer::xAuth', - signature: 'i(pi' + 'ssss)', + name: "sqlite3_set_authorizer::xAuth", + signature: "i(pi" + "ssss)", contextKey: (argv, argIndex) => argv[0], callProxy: (callback) => { return (pV, iCode, s0, s1, s2, s3) => { @@ -8691,128 +8378,128 @@ var sqlite3InitModule = (() => { }; }, }), - '*', + "*", ], ], [ - 'sqlite3_set_auxdata', + "sqlite3_set_auxdata", undefined, [ - 'sqlite3_context*', - 'int', - '*', + "sqlite3_context*", + "int", + "*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xDestroyAuxData', - signature: 'v(*)', + name: "xDestroyAuxData", + signature: "v(*)", contextKey: (argv, argIndex) => argv[0], }), ], ], - ['sqlite3_shutdown', undefined], - ['sqlite3_sourceid', 'string'], - ['sqlite3_sql', 'string', 'sqlite3_stmt*'], - ['sqlite3_status', 'int', 'int', '*', '*', 'int'], - ['sqlite3_step', 'int', 'sqlite3_stmt*'], - ['sqlite3_stmt_isexplain', 'int', ['sqlite3_stmt*']], - ['sqlite3_stmt_readonly', 'int', ['sqlite3_stmt*']], - ['sqlite3_stmt_status', 'int', 'sqlite3_stmt*', 'int', 'int'], - ['sqlite3_strglob', 'int', 'string', 'string'], - ['sqlite3_stricmp', 'int', 'string', 'string'], - ['sqlite3_strlike', 'int', 'string', 'string', 'int'], - ['sqlite3_strnicmp', 'int', 'string', 'string', 'int'], + ["sqlite3_shutdown", undefined], + ["sqlite3_sourceid", "string"], + ["sqlite3_sql", "string", "sqlite3_stmt*"], + ["sqlite3_status", "int", "int", "*", "*", "int"], + ["sqlite3_step", "int", "sqlite3_stmt*"], + ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]], + ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]], + ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"], + ["sqlite3_strglob", "int", "string", "string"], + ["sqlite3_stricmp", "int", "string", "string"], + ["sqlite3_strlike", "int", "string", "string", "int"], + ["sqlite3_strnicmp", "int", "string", "string", "int"], [ - 'sqlite3_table_column_metadata', - 'int', - 'sqlite3*', - 'string', - 'string', - 'string', - '**', - '**', - '*', - '*', - '*', + "sqlite3_table_column_metadata", + "int", + "sqlite3*", + "string", + "string", + "string", + "**", + "**", + "*", + "*", + "*", ], - ['sqlite3_total_changes', 'int', 'sqlite3*'], + ["sqlite3_total_changes", "int", "sqlite3*"], [ - 'sqlite3_trace_v2', - 'int', + "sqlite3_trace_v2", + "int", [ - 'sqlite3*', - 'int', + "sqlite3*", + "int", new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_trace_v2::callback', - signature: 'i(ippp)', + name: "sqlite3_trace_v2::callback", + signature: "i(ippp)", contextKey: (argv, argIndex) => argv[0], }), - '*', + "*", ], ], - ['sqlite3_txn_state', 'int', ['sqlite3*', 'string']], - - ['sqlite3_uri_boolean', 'int', 'sqlite3_filename', 'string', 'int'], - ['sqlite3_uri_key', 'string', 'sqlite3_filename', 'int'], - ['sqlite3_uri_parameter', 'string', 'sqlite3_filename', 'string'], - ['sqlite3_user_data', 'void*', 'sqlite3_context*'], - ['sqlite3_value_blob', '*', 'sqlite3_value*'], - ['sqlite3_value_bytes', 'int', 'sqlite3_value*'], - ['sqlite3_value_double', 'f64', 'sqlite3_value*'], - ['sqlite3_value_dup', 'sqlite3_value*', 'sqlite3_value*'], - ['sqlite3_value_free', undefined, 'sqlite3_value*'], - ['sqlite3_value_frombind', 'int', 'sqlite3_value*'], - ['sqlite3_value_int', 'int', 'sqlite3_value*'], - ['sqlite3_value_nochange', 'int', 'sqlite3_value*'], - ['sqlite3_value_numeric_type', 'int', 'sqlite3_value*'], - ['sqlite3_value_pointer', '*', 'sqlite3_value*', 'string:static'], - ['sqlite3_value_subtype', 'int', 'sqlite3_value*'], - ['sqlite3_value_text', 'string', 'sqlite3_value*'], - ['sqlite3_value_type', 'int', 'sqlite3_value*'], - ['sqlite3_vfs_find', '*', 'string'], - ['sqlite3_vfs_register', 'int', 'sqlite3_vfs*', 'int'], - ['sqlite3_vfs_unregister', 'int', 'sqlite3_vfs*'], + ["sqlite3_txn_state", "int", ["sqlite3*", "string"]], + + ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], + ["sqlite3_uri_key", "string", "sqlite3_filename", "int"], + ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], + ["sqlite3_user_data", "void*", "sqlite3_context*"], + ["sqlite3_value_blob", "*", "sqlite3_value*"], + ["sqlite3_value_bytes", "int", "sqlite3_value*"], + ["sqlite3_value_double", "f64", "sqlite3_value*"], + ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"], + ["sqlite3_value_free", undefined, "sqlite3_value*"], + ["sqlite3_value_frombind", "int", "sqlite3_value*"], + ["sqlite3_value_int", "int", "sqlite3_value*"], + ["sqlite3_value_nochange", "int", "sqlite3_value*"], + ["sqlite3_value_numeric_type", "int", "sqlite3_value*"], + ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], + ["sqlite3_value_subtype", "int", "sqlite3_value*"], + ["sqlite3_value_text", "string", "sqlite3_value*"], + ["sqlite3_value_type", "int", "sqlite3_value*"], + ["sqlite3_vfs_find", "*", "string"], + ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], + ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"], ]; wasm.bindingSignatures.int64 = [ - ['sqlite3_bind_int64', 'int', ['sqlite3_stmt*', 'int', 'i64']], - ['sqlite3_changes64', 'i64', ['sqlite3*']], - ['sqlite3_column_int64', 'i64', ['sqlite3_stmt*', 'int']], + ["sqlite3_bind_int64", "int", ["sqlite3_stmt*", "int", "i64"]], + ["sqlite3_changes64", "i64", ["sqlite3*"]], + ["sqlite3_column_int64", "i64", ["sqlite3_stmt*", "int"]], [ - 'sqlite3_create_module', - 'int', - ['sqlite3*', 'string', 'sqlite3_module*', '*'], + "sqlite3_create_module", + "int", + ["sqlite3*", "string", "sqlite3_module*", "*"], ], [ - 'sqlite3_create_module_v2', - 'int', - ['sqlite3*', 'string', 'sqlite3_module*', '*', '*'], + "sqlite3_create_module_v2", + "int", + ["sqlite3*", "string", "sqlite3_module*", "*", "*"], ], - ['sqlite3_declare_vtab', 'int', ['sqlite3*', 'string:flexible']], + ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]], [ - 'sqlite3_deserialize', - 'int', - 'sqlite3*', - 'string', - '*', - 'i64', - 'i64', - 'int', + "sqlite3_deserialize", + "int", + "sqlite3*", + "string", + "*", + "i64", + "i64", + "int", ], - ['sqlite3_drop_modules', 'int', ['sqlite3*', '**']], - ['sqlite3_last_insert_rowid', 'i64', ['sqlite3*']], - ['sqlite3_malloc64', '*', 'i64'], - ['sqlite3_msize', 'i64', '*'], - ['sqlite3_overload_function', 'int', ['sqlite3*', 'string', 'int']], - ['sqlite3_preupdate_blobwrite', 'int', 'sqlite3*'], - ['sqlite3_preupdate_count', 'int', 'sqlite3*'], - ['sqlite3_preupdate_depth', 'int', 'sqlite3*'], + ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]], + ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]], + ["sqlite3_malloc64", "*", "i64"], + ["sqlite3_msize", "i64", "*"], + ["sqlite3_overload_function", "int", ["sqlite3*", "string", "int"]], + ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"], + ["sqlite3_preupdate_count", "int", "sqlite3*"], + ["sqlite3_preupdate_depth", "int", "sqlite3*"], [ - 'sqlite3_preupdate_hook', - '*', + "sqlite3_preupdate_hook", + "*", [ - 'sqlite3*', + "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_preupdate_hook', - signature: 'v(ppippjj)', + name: "sqlite3_preupdate_hook", + signature: "v(ppippjj)", contextKey: (argv) => argv[0], callProxy: (callback) => { return (p, db, op, zDb, zTbl, iKey1, iKey2) => { @@ -8823,31 +8510,31 @@ var sqlite3InitModule = (() => { wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl), iKey1, - iKey2, + iKey2 ); }; }, }), - '*', + "*", ], ], - ['sqlite3_preupdate_new', 'int', ['sqlite3*', 'int', '**']], - ['sqlite3_preupdate_old', 'int', ['sqlite3*', 'int', '**']], - ['sqlite3_realloc64', '*', '*', 'i64'], - ['sqlite3_result_int64', undefined, '*', 'i64'], - ['sqlite3_result_zeroblob64', 'int', '*', 'i64'], - ['sqlite3_serialize', '*', 'sqlite3*', 'string', '*', 'int'], - ['sqlite3_set_last_insert_rowid', undefined, ['sqlite3*', 'i64']], - ['sqlite3_status64', 'int', 'int', '*', '*', 'int'], - ['sqlite3_total_changes64', 'i64', ['sqlite3*']], + ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]], + ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]], + ["sqlite3_realloc64", "*", "*", "i64"], + ["sqlite3_result_int64", undefined, "*", "i64"], + ["sqlite3_result_zeroblob64", "int", "*", "i64"], + ["sqlite3_serialize", "*", "sqlite3*", "string", "*", "int"], + ["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]], + ["sqlite3_status64", "int", "int", "*", "*", "int"], + ["sqlite3_total_changes64", "i64", ["sqlite3*"]], [ - 'sqlite3_update_hook', - '*', + "sqlite3_update_hook", + "*", [ - 'sqlite3*', + "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ - name: 'sqlite3_update_hook', - signature: 'v(iippj)', + name: "sqlite3_update_hook", + signature: "v(iippj)", contextKey: (argv) => argv[0], callProxy: (callback) => { return (p, op, z0, z1, rowid) => { @@ -8856,30 +8543,30 @@ var sqlite3InitModule = (() => { op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), - rowid, + rowid ); }; }, }), - '*', + "*", ], ], - ['sqlite3_uri_int64', 'i64', ['sqlite3_filename', 'string', 'i64']], - ['sqlite3_value_int64', 'i64', 'sqlite3_value*'], - ['sqlite3_vtab_collation', 'string', 'sqlite3_index_info*', 'int'], - ['sqlite3_vtab_distinct', 'int', 'sqlite3_index_info*'], - ['sqlite3_vtab_in', 'int', 'sqlite3_index_info*', 'int', 'int'], - ['sqlite3_vtab_in_first', 'int', 'sqlite3_value*', '**'], - ['sqlite3_vtab_in_next', 'int', 'sqlite3_value*', '**'], - - ['sqlite3_vtab_nochange', 'int', 'sqlite3_context*'], - ['sqlite3_vtab_on_conflict', 'int', 'sqlite3*'], - ['sqlite3_vtab_rhs_value', 'int', 'sqlite3_index_info*', 'int', '**'], + ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], + ["sqlite3_value_int64", "i64", "sqlite3_value*"], + ["sqlite3_vtab_collation", "string", "sqlite3_index_info*", "int"], + ["sqlite3_vtab_distinct", "int", "sqlite3_index_info*"], + ["sqlite3_vtab_in", "int", "sqlite3_index_info*", "int", "int"], + ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"], + ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"], + + ["sqlite3_vtab_nochange", "int", "sqlite3_context*"], + ["sqlite3_vtab_on_conflict", "int", "sqlite3*"], + ["sqlite3_vtab_rhs_value", "int", "sqlite3_index_info*", "int", "**"], ]; if (wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add) { const __ipsProxy = { - signature: 'i(ps)', + signature: "i(ps)", callProxy: (callback) => { return (p, s) => { try { @@ -8894,340 +8581,340 @@ var sqlite3InitModule = (() => { wasm.bindingSignatures.int64.push( ...[ [ - 'sqlite3changegroup_add', - 'int', - ['sqlite3_changegroup*', 'int', 'void*'], + "sqlite3changegroup_add", + "int", + ["sqlite3_changegroup*", "int", "void*"], ], [ - 'sqlite3changegroup_add_strm', - 'int', + "sqlite3changegroup_add_strm", + "int", [ - 'sqlite3_changegroup*', + "sqlite3_changegroup*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xInput", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", ], ], [ - 'sqlite3changegroup_delete', + "sqlite3changegroup_delete", undefined, - ['sqlite3_changegroup*'], + ["sqlite3_changegroup*"], ], - ['sqlite3changegroup_new', 'int', ['**']], + ["sqlite3changegroup_new", "int", ["**"]], [ - 'sqlite3changegroup_output', - 'int', - ['sqlite3_changegroup*', 'int*', '**'], + "sqlite3changegroup_output", + "int", + ["sqlite3_changegroup*", "int*", "**"], ], [ - 'sqlite3changegroup_output_strm', - 'int', + "sqlite3changegroup_output_strm", + "int", [ - 'sqlite3_changegroup*', + "sqlite3_changegroup*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppi)', - bindScope: 'transient', + name: "xOutput", + signature: "i(ppi)", + bindScope: "transient", }), - 'void*', + "void*", ], ], [ - 'sqlite3changeset_apply', - 'int', + "sqlite3changeset_apply", + "int", [ - 'sqlite3*', - 'int', - 'void*', + "sqlite3*", + "int", + "void*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - bindScope: 'transient', + name: "xFilter", + bindScope: "transient", ...__ipsProxy, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xConflict', - signature: 'i(pip)', - bindScope: 'transient', + name: "xConflict", + signature: "i(pip)", + bindScope: "transient", }), - 'void*', + "void*", ], ], [ - 'sqlite3changeset_apply_strm', - 'int', + "sqlite3changeset_apply_strm", + "int", [ - 'sqlite3*', + "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xInput", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - bindScope: 'transient', + name: "xFilter", + bindScope: "transient", ...__ipsProxy, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xConflict', - signature: 'i(pip)', - bindScope: 'transient', + name: "xConflict", + signature: "i(pip)", + bindScope: "transient", }), - 'void*', + "void*", ], ], [ - 'sqlite3changeset_apply_v2', - 'int', + "sqlite3changeset_apply_v2", + "int", [ - 'sqlite3*', - 'int', - 'void*', + "sqlite3*", + "int", + "void*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - bindScope: 'transient', + name: "xFilter", + bindScope: "transient", ...__ipsProxy, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xConflict', - signature: 'i(pip)', - bindScope: 'transient', + name: "xConflict", + signature: "i(pip)", + bindScope: "transient", }), - 'void*', - '**', - 'int*', - 'int', + "void*", + "**", + "int*", + "int", ], ], [ - 'sqlite3changeset_apply_v2_strm', - 'int', + "sqlite3changeset_apply_v2_strm", + "int", [ - 'sqlite3*', + "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xInput", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', - bindScope: 'transient', + name: "xFilter", + bindScope: "transient", ...__ipsProxy, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xConflict', - signature: 'i(pip)', - bindScope: 'transient', + name: "xConflict", + signature: "i(pip)", + bindScope: "transient", }), - 'void*', - '**', - 'int*', - 'int', + "void*", + "**", + "int*", + "int", ], ], [ - 'sqlite3changeset_concat', - 'int', - ['int', 'void*', 'int', 'void*', 'int*', '**'], + "sqlite3changeset_concat", + "int", + ["int", "void*", "int", "void*", "int*", "**"], ], [ - 'sqlite3changeset_concat_strm', - 'int', + "sqlite3changeset_concat_strm", + "int", [ new wasm.xWrap.FuncPtrAdapter({ - name: 'xInputA', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xInputA", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xInputB', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xInputB", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppi)', - bindScope: 'transient', + name: "xOutput", + signature: "i(ppi)", + bindScope: "transient", }), - 'void*', + "void*", ], ], [ - 'sqlite3changeset_conflict', - 'int', - ['sqlite3_changeset_iter*', 'int', '**'], + "sqlite3changeset_conflict", + "int", + ["sqlite3_changeset_iter*", "int", "**"], ], - ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']], + ["sqlite3changeset_finalize", "int", ["sqlite3_changeset_iter*"]], [ - 'sqlite3changeset_fk_conflicts', - 'int', - ['sqlite3_changeset_iter*', 'int*'], + "sqlite3changeset_fk_conflicts", + "int", + ["sqlite3_changeset_iter*", "int*"], ], [ - 'sqlite3changeset_invert', - 'int', - ['int', 'void*', 'int*', '**'], + "sqlite3changeset_invert", + "int", + ["int", "void*", "int*", "**"], ], [ - 'sqlite3changeset_invert_strm', - 'int', + "sqlite3changeset_invert_strm", + "int", [ new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xInput", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppi)', - bindScope: 'transient', + name: "xOutput", + signature: "i(ppi)", + bindScope: "transient", }), - 'void*', + "void*", ], ], [ - 'sqlite3changeset_new', - 'int', - ['sqlite3_changeset_iter*', 'int', '**'], + "sqlite3changeset_new", + "int", + ["sqlite3_changeset_iter*", "int", "**"], ], - ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']], + ["sqlite3changeset_next", "int", ["sqlite3_changeset_iter*"]], [ - 'sqlite3changeset_old', - 'int', - ['sqlite3_changeset_iter*', 'int', '**'], + "sqlite3changeset_old", + "int", + ["sqlite3_changeset_iter*", "int", "**"], ], [ - 'sqlite3changeset_op', - 'int', - ['sqlite3_changeset_iter*', '**', 'int*', 'int*', 'int*'], + "sqlite3changeset_op", + "int", + ["sqlite3_changeset_iter*", "**", "int*", "int*", "int*"], ], [ - 'sqlite3changeset_pk', - 'int', - ['sqlite3_changeset_iter*', '**', 'int*'], + "sqlite3changeset_pk", + "int", + ["sqlite3_changeset_iter*", "**", "int*"], ], - ['sqlite3changeset_start', 'int', ['**', 'int', '*']], + ["sqlite3changeset_start", "int", ["**", "int", "*"]], [ - 'sqlite3changeset_start_strm', - 'int', + "sqlite3changeset_start_strm", + "int", [ - '**', + "**", new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xInput", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", ], ], - ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']], + ["sqlite3changeset_start_v2", "int", ["**", "int", "*", "int"]], [ - 'sqlite3changeset_start_v2_strm', - 'int', + "sqlite3changeset_start_v2_strm", + "int", [ - '**', + "**", new wasm.xWrap.FuncPtrAdapter({ - name: 'xInput', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xInput", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', - 'int', + "void*", + "int", ], ], - ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']], + ["sqlite3session_attach", "int", ["sqlite3_session*", "string"]], [ - 'sqlite3session_changeset', - 'int', - ['sqlite3_session*', 'int*', '**'], + "sqlite3session_changeset", + "int", + ["sqlite3_session*", "int*", "**"], ], - ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']], + ["sqlite3session_changeset_size", "i64", ["sqlite3_session*"]], [ - 'sqlite3session_changeset_strm', - 'int', + "sqlite3session_changeset_strm", + "int", [ - 'sqlite3_session*', + "sqlite3_session*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xOutput", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", ], ], - ['sqlite3session_config', 'int', ['int', 'void*']], - ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']], + ["sqlite3session_config", "int", ["int", "void*"]], + ["sqlite3session_create", "int", ["sqlite3*", "string", "**"]], [ - 'sqlite3session_diff', - 'int', - ['sqlite3_session*', 'string', 'string', '**'], + "sqlite3session_diff", + "int", + ["sqlite3_session*", "string", "string", "**"], ], - ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']], - ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']], - ['sqlite3session_isempty', 'int', ['sqlite3_session*']], - ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']], + ["sqlite3session_enable", "int", ["sqlite3_session*", "int"]], + ["sqlite3session_indirect", "int", ["sqlite3_session*", "int"]], + ["sqlite3session_isempty", "int", ["sqlite3_session*"]], + ["sqlite3session_memory_used", "i64", ["sqlite3_session*"]], [ - 'sqlite3session_object_config', - 'int', - ['sqlite3_session*', 'int', 'void*'], + "sqlite3session_object_config", + "int", + ["sqlite3_session*", "int", "void*"], ], [ - 'sqlite3session_patchset', - 'int', - ['sqlite3_session*', '*', '**'], + "sqlite3session_patchset", + "int", + ["sqlite3_session*", "*", "**"], ], [ - 'sqlite3session_patchset_strm', - 'int', + "sqlite3session_patchset_strm", + "int", [ - 'sqlite3_session*', + "sqlite3_session*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xOutput', - signature: 'i(ppp)', - bindScope: 'transient', + name: "xOutput", + signature: "i(ppp)", + bindScope: "transient", }), - 'void*', + "void*", ], ], [ - 'sqlite3session_table_filter', + "sqlite3session_table_filter", undefined, [ - 'sqlite3_session*', + "sqlite3_session*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xFilter', + name: "xFilter", ...__ipsProxy, contextKey: (argv, argIndex) => argv[0], }), - '*', + "*", ], ], - ], + ] ); } wasm.bindingSignatures.wasmInternal = [ - ['sqlite3__wasm_db_reset', 'int', 'sqlite3*'], - ['sqlite3__wasm_db_vfs', 'sqlite3_vfs*', 'sqlite3*', 'string'], + ["sqlite3__wasm_db_reset", "int", "sqlite3*"], + ["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*", "string"], [ - 'sqlite3__wasm_vfs_create_file', - 'int', - 'sqlite3_vfs*', - 'string', - '*', - 'int', + "sqlite3__wasm_vfs_create_file", + "int", + "sqlite3_vfs*", + "string", + "*", + "int", ], - ['sqlite3__wasm_posix_create_file', 'int', 'string', '*', 'int'], - ['sqlite3__wasm_vfs_unlink', 'int', 'sqlite3_vfs*', 'string'], - ['sqlite3__wasm_qfmt_token', 'string:dealloc', 'string', 'int'], + ["sqlite3__wasm_posix_create_file", "int", "string", "*", "int"], + ["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*", "string"], + ["sqlite3__wasm_qfmt_token", "string:dealloc", "string", "int"], ]; sqlite3.StructBinder = globalThis.Jaccwabyt({ @@ -9235,82 +8922,82 @@ var sqlite3InitModule = (() => { alloc: wasm.alloc, dealloc: wasm.dealloc, bigIntEnabled: wasm.bigIntEnabled, - memberPrefix: '$', + memberPrefix: "$", }); delete globalThis.Jaccwabyt; { - const __xString = wasm.xWrap.argAdapter('string'); - wasm.xWrap.argAdapter('string:flexible', (v) => - __xString(util.flexibleString(v)), + const __xString = wasm.xWrap.argAdapter("string"); + wasm.xWrap.argAdapter("string:flexible", (v) => + __xString(util.flexibleString(v)) ); wasm.xWrap.argAdapter( - 'string:static', + "string:static", function (v) { if (wasm.isPtr(v)) return v; - v = '' + v; + v = "" + v; let rc = this[v]; return rc || (this[v] = wasm.allocCString(v)); - }.bind(Object.create(null)), + }.bind(Object.create(null)) ); - const __xArgPtr = wasm.xWrap.argAdapter('*'); + const __xArgPtr = wasm.xWrap.argAdapter("*"); const nilType = function () {}; - wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)( - 'sqlite3_context*', - __xArgPtr, - )('sqlite3_value*', __xArgPtr)('void*', __xArgPtr)( - 'sqlite3_changegroup*', - __xArgPtr, - )('sqlite3_changeset_iter*', __xArgPtr)( - 'sqlite3_session*', - __xArgPtr, - )('sqlite3_stmt*', (v) => + wasm.xWrap.argAdapter("sqlite3_filename", __xArgPtr)( + "sqlite3_context*", + __xArgPtr + )("sqlite3_value*", __xArgPtr)("void*", __xArgPtr)( + "sqlite3_changegroup*", + __xArgPtr + )("sqlite3_changeset_iter*", __xArgPtr)( + "sqlite3_session*", + __xArgPtr + )("sqlite3_stmt*", (v) => __xArgPtr( - v instanceof (sqlite3?.oo1?.Stmt || nilType) ? v.pointer : v, - ), - )('sqlite3*', (v) => + v instanceof (sqlite3?.oo1?.Stmt || nilType) ? v.pointer : v + ) + )("sqlite3*", (v) => __xArgPtr( - v instanceof (sqlite3?.oo1?.DB || nilType) ? v.pointer : v, - ), - )('sqlite3_index_info*', (v) => + v instanceof (sqlite3?.oo1?.DB || nilType) ? v.pointer : v + ) + )("sqlite3_index_info*", (v) => __xArgPtr( - v instanceof (capi.sqlite3_index_info || nilType) ? v.pointer : v, - ), - )('sqlite3_module*', (v) => + v instanceof (capi.sqlite3_index_info || nilType) ? v.pointer : v + ) + )("sqlite3_module*", (v) => __xArgPtr( - v instanceof (capi.sqlite3_module || nilType) ? v.pointer : v, - ), - )('sqlite3_vfs*', (v) => { - if ('string' === typeof v) { + v instanceof (capi.sqlite3_module || nilType) ? v.pointer : v + ) + )("sqlite3_vfs*", (v) => { + if ("string" === typeof v) { return ( capi.sqlite3_vfs_find(v) || sqlite3.SQLite3Error.toss( capi.SQLITE_NOTFOUND, - 'Unknown sqlite3_vfs name:', - v, + "Unknown sqlite3_vfs name:", + v ) ); } return __xArgPtr( - v instanceof (capi.sqlite3_vfs || nilType) ? v.pointer : v, + v instanceof (capi.sqlite3_vfs || nilType) ? v.pointer : v ); }); - const __xRcPtr = wasm.xWrap.resultAdapter('*'); - wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)( - 'sqlite3_context*', - __xRcPtr, - )('sqlite3_stmt*', __xRcPtr)('sqlite3_value*', __xRcPtr)( - 'sqlite3_vfs*', - __xRcPtr, - )('void*', __xRcPtr); + const __xRcPtr = wasm.xWrap.resultAdapter("*"); + wasm.xWrap.resultAdapter("sqlite3*", __xRcPtr)( + "sqlite3_context*", + __xRcPtr + )("sqlite3_stmt*", __xRcPtr)("sqlite3_value*", __xRcPtr)( + "sqlite3_vfs*", + __xRcPtr + )("void*", __xRcPtr); if (0 === wasm.exports.sqlite3_step.length) { wasm.xWrap.doArgcCheck = false; sqlite3.config.warn( - 'Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks.', + "Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks." ); } for (const e of wasm.bindingSignatures) { @@ -9323,8 +9010,8 @@ var sqlite3InitModule = (() => { const fI64Disabled = function (fname) { return () => toss( - fname + '() is unavailable due to lack', - 'of BigInt support in this build.', + fname + "() is unavailable due to lack", + "of BigInt support in this build." ); }; for (const e of wasm.bindingSignatures.int64) { @@ -9337,11 +9024,11 @@ var sqlite3InitModule = (() => { if (wasm.exports.sqlite3__wasm_db_error) { const __db_err = wasm.xWrap( - 'sqlite3__wasm_db_error', - 'int', - 'sqlite3*', - 'int', - 'string', + "sqlite3__wasm_db_error", + "int", + "sqlite3*", + "int", + "string" ); util.sqlite3__wasm_db_error = function (pDb, resultCode, message) { @@ -9349,7 +9036,7 @@ var sqlite3InitModule = (() => { resultCode = capi.SQLITE_NOMEM; message = 0; } else if (resultCode instanceof Error) { - message = message || '' + resultCode; + message = message || "" + resultCode; resultCode = resultCode.resultCode || capi.SQLITE_ERROR; } return pDb ? __db_err(pDb, resultCode, message) : resultCode; @@ -9357,8 +9044,8 @@ var sqlite3InitModule = (() => { } else { util.sqlite3__wasm_db_error = function (pDb, errCode, msg) { console.warn( - 'sqlite3__wasm_db_error() is not exported.', - arguments, + "sqlite3__wasm_db_error() is not exported.", + arguments ); return errCode; }; @@ -9366,43 +9053,43 @@ var sqlite3InitModule = (() => { } { - const cJson = wasm.xCall('sqlite3__wasm_enum_json'); + const cJson = wasm.xCall("sqlite3__wasm_enum_json"); if (!cJson) { toss( "Maintenance required: increase sqlite3__wasm_enum_json()'s", - 'static buffer size!', + "static buffer size!" ); } wasm.ctype = JSON.parse(wasm.cstrToJs(cJson)); const defineGroups = [ - 'access', - 'authorizer', - 'blobFinalizers', - 'changeset', - 'config', - 'dataTypes', - 'dbConfig', - 'dbStatus', - 'encodings', - 'fcntl', - 'flock', - 'ioCap', - 'limits', - 'openFlags', - 'prepareFlags', - 'resultCodes', - 'sqlite3Status', - 'stmtStatus', - 'syncFlags', - 'trace', - 'txnState', - 'udfFlags', - 'version', + "access", + "authorizer", + "blobFinalizers", + "changeset", + "config", + "dataTypes", + "dbConfig", + "dbStatus", + "encodings", + "fcntl", + "flock", + "ioCap", + "limits", + "openFlags", + "prepareFlags", + "resultCodes", + "sqlite3Status", + "stmtStatus", + "syncFlags", + "trace", + "txnState", + "udfFlags", + "version", ]; if (wasm.bigIntEnabled) { - defineGroups.push('serialize', 'session', 'vtab'); + defineGroups.push("serialize", "session", "vtab"); } for (const t of defineGroups) { for (const e of Object.entries(wasm.ctype[t])) { @@ -9411,12 +9098,12 @@ var sqlite3InitModule = (() => { } if (!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)) { toss( - 'Internal error: cannot resolve exported function', - 'entry SQLITE_WASM_DEALLOC (==' + capi.SQLITE_WASM_DEALLOC + ').', + "Internal error: cannot resolve exported function", + "entry SQLITE_WASM_DEALLOC (==" + capi.SQLITE_WASM_DEALLOC + ")." ); } const __rcMap = Object.create(null); - for (const t of ['resultCodes']) { + for (const t of ["resultCodes"]) { for (const e of Object.entries(wasm.ctype[t])) { __rcMap[e[1]] = e[0]; } @@ -9441,17 +9128,17 @@ var sqlite3InitModule = (() => { } if (capi.sqlite3_index_info) { for (const k of [ - 'sqlite3_index_constraint', - 'sqlite3_index_orderby', - 'sqlite3_index_constraint_usage', + "sqlite3_index_constraint", + "sqlite3_index_orderby", + "sqlite3_index_constraint_usage", ]) { capi.sqlite3_index_info[k] = capi[k]; delete capi[k]; } capi.sqlite3_vtab_config = wasm.xWrap( - 'sqlite3__wasm_vtab_config', - 'int', - ['sqlite3*', 'int', 'int'], + "sqlite3__wasm_vtab_config", + "int", + ["sqlite3*", "int", "int"] ); } } @@ -9460,7 +9147,7 @@ var sqlite3InitModule = (() => { return util.sqlite3__wasm_db_error( pDb, capi.SQLITE_MISUSE, - f + '() requires ' + n + ' argument' + (1 === n ? '' : 's') + '.', + f + "() requires " + n + " argument" + (1 === n ? "" : "s") + "." ); }; @@ -9468,11 +9155,11 @@ var sqlite3InitModule = (() => { return util.sqlite3__wasm_db_error( pDb, capi.SQLITE_FORMAT, - 'SQLITE_UTF8 is the only supported encoding.', + "SQLITE_UTF8 is the only supported encoding." ); }; - const __argPDb = (pDb) => wasm.xWrap.argAdapter('sqlite3*')(pDb); + const __argPDb = (pDb) => wasm.xWrap.argAdapter("sqlite3*")(pDb); const __argStr = (str) => (wasm.isPtr(str) ? wasm.cstrToJs(str) : str); const __dbCleanupMap = function (pDb, mode) { pDb = __argPDb(pDb); @@ -9487,7 +9174,7 @@ var sqlite3InitModule = (() => { }.bind( Object.assign(Object.create(null), { dbMap: new Map(), - }), + }) ); __dbCleanupMap.addCollation = function (pDb, name) { @@ -9520,14 +9207,14 @@ var sqlite3InitModule = (() => { const closeArgs = [pDb]; for (const name of [ - 'sqlite3_busy_handler', - 'sqlite3_commit_hook', - 'sqlite3_preupdate_hook', - 'sqlite3_progress_handler', - 'sqlite3_rollback_hook', - 'sqlite3_set_authorizer', - 'sqlite3_trace_v2', - 'sqlite3_update_hook', + "sqlite3_busy_handler", + "sqlite3_commit_hook", + "sqlite3_preupdate_hook", + "sqlite3_progress_handler", + "sqlite3_rollback_hook", + "sqlite3_set_authorizer", + "sqlite3_trace_v2", + "sqlite3_update_hook", ]) { const x = wasm.exports[name]; closeArgs.length = x.length; @@ -9535,11 +9222,11 @@ var sqlite3InitModule = (() => { capi[name](...closeArgs); } catch (e) { console.warn( - 'close-time call of', - name + '(', + "close-time call of", + name + "(", closeArgs, - ') threw:', - e, + ") threw:", + e ); } } @@ -9554,7 +9241,7 @@ var sqlite3InitModule = (() => { capi.SQLITE_UTF8, 0, 0, - 0, + 0 ); } catch (e) {} } @@ -9588,13 +9275,13 @@ var sqlite3InitModule = (() => { { const __sqlite3CloseV2 = wasm.xWrap( - 'sqlite3_close_v2', - 'int', - 'sqlite3*', + "sqlite3_close_v2", + "int", + "sqlite3*" ); capi.sqlite3_close_v2 = function (pDb) { if (1 !== arguments.length) - return __dbArgcMismatch(pDb, 'sqlite3_close_v2', 1); + return __dbArgcMismatch(pDb, "sqlite3_close_v2", 1); if (pDb) { try { __dbCleanupMap.cleanup(pDb); @@ -9606,13 +9293,13 @@ var sqlite3InitModule = (() => { if (capi.sqlite3session_table_filter) { const __sqlite3SessionDelete = wasm.xWrap( - 'sqlite3session_delete', + "sqlite3session_delete", undefined, - ['sqlite3_session*'], + ["sqlite3_session*"] ); capi.sqlite3session_delete = function (pSession) { if (1 !== arguments.length) { - return __dbArgcMismatch(pDb, 'sqlite3session_delete', 1); + return __dbArgcMismatch(pDb, "sqlite3session_delete", 1); } else if (pSession) { capi.sqlite3session_table_filter(pSession, 0, 0); } @@ -9623,33 +9310,33 @@ var sqlite3InitModule = (() => { { const contextKey = (argv, argIndex) => { return ( - 'argv[' + + "argv[" + argIndex + - ']:' + + "]:" + argv[0] + - ':' + + ":" + wasm.cstrToJs(argv[1]).toLowerCase() ); }; const __sqlite3CreateCollationV2 = wasm.xWrap( - 'sqlite3_create_collation_v2', - 'int', + "sqlite3_create_collation_v2", + "int", [ - 'sqlite3*', - 'string', - 'int', - '*', + "sqlite3*", + "string", + "int", + "*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xCompare', - signature: 'i(pipip)', + name: "xCompare", + signature: "i(pipip)", contextKey, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xDestroy', - signature: 'v(p)', + name: "xDestroy", + signature: "v(p)", contextKey, }), - ], + ] ); capi.sqlite3_create_collation_v2 = function ( @@ -9658,10 +9345,10 @@ var sqlite3InitModule = (() => { eTextRep, pArg, xCompare, - xDestroy, + xDestroy ) { if (6 !== arguments.length) - return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6); + return __dbArgcMismatch(pDb, "sqlite3_create_collation_v2", 6); else if (0 === (eTextRep & 0xf)) { eTextRep |= capi.SQLITE_UTF8; } else if (capi.SQLITE_UTF8 !== (eTextRep & 0xf)) { @@ -9674,7 +9361,7 @@ var sqlite3InitModule = (() => { eTextRep, pArg, xCompare, - xDestroy, + xDestroy ); if (0 === rc && xCompare instanceof Function) { __dbCleanupMap.addCollation(pDb, zName); @@ -9690,7 +9377,7 @@ var sqlite3InitModule = (() => { zName, eTextRep, pArg, - xCompare, + xCompare ) => { return 5 === arguments.length ? capi.sqlite3_create_collation_v2( @@ -9699,9 +9386,9 @@ var sqlite3InitModule = (() => { eTextRep, pArg, xCompare, - 0, + 0 ) - : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5); + : __dbArgcMismatch(pDb, "sqlite3_create_collation", 5); }; } @@ -9709,18 +9396,18 @@ var sqlite3InitModule = (() => { const contextKey = function (argv, argIndex) { return ( argv[0] + - ':' + + ":" + (argv[2] < 0 ? -1 : argv[2]) + - ':' + + ":" + argIndex + - ':' + + ":" + wasm.cstrToJs(argv[1]).toLowerCase() ); }; const __cfProxy = Object.assign(Object.create(null), { xInverseAndStep: { - signature: 'v(pip)', + signature: "v(pip)", contextKey, callProxy: (callback) => { return (pCtx, argc, pArgv) => { @@ -9733,7 +9420,7 @@ var sqlite3InitModule = (() => { }, }, xFinalAndValue: { - signature: 'v(p)', + signature: "v(p)", contextKey, callProxy: (callback) => { return (pCtx) => { @@ -9746,14 +9433,14 @@ var sqlite3InitModule = (() => { }, }, xFunc: { - signature: 'v(pip)', + signature: "v(pip)", contextKey, callProxy: (callback) => { return (pCtx, argc, pArgv) => { try { capi.sqlite3_result_js( pCtx, - callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)), + callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) ); } catch (e) { capi.sqlite3_result_error_js(pCtx, e); @@ -9762,7 +9449,7 @@ var sqlite3InitModule = (() => { }, }, xDestroy: { - signature: 'v(p)', + signature: "v(p)", contextKey, callProxy: (callback) => { @@ -9770,7 +9457,7 @@ var sqlite3InitModule = (() => { try { callback(pVoid); } catch (e) { - console.error('UDF xDestroy method threw:', e); + console.error("UDF xDestroy method threw:", e); } }; }, @@ -9778,63 +9465,63 @@ var sqlite3InitModule = (() => { }); const __sqlite3CreateFunction = wasm.xWrap( - 'sqlite3_create_function_v2', - 'int', + "sqlite3_create_function_v2", + "int", [ - 'sqlite3*', - 'string', - 'int', - 'int', - '*', + "sqlite3*", + "string", + "int", + "int", + "*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xFunc', + name: "xFunc", ...__cfProxy.xFunc, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xStep', + name: "xStep", ...__cfProxy.xInverseAndStep, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xFinal', + name: "xFinal", ...__cfProxy.xFinalAndValue, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xDestroy', + name: "xDestroy", ...__cfProxy.xDestroy, }), - ], + ] ); const __sqlite3CreateWindowFunction = wasm.xWrap( - 'sqlite3_create_window_function', - 'int', + "sqlite3_create_window_function", + "int", [ - 'sqlite3*', - 'string', - 'int', - 'int', - '*', + "sqlite3*", + "string", + "int", + "int", + "*", new wasm.xWrap.FuncPtrAdapter({ - name: 'xStep', + name: "xStep", ...__cfProxy.xInverseAndStep, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xFinal', + name: "xFinal", ...__cfProxy.xFinalAndValue, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xValue', + name: "xValue", ...__cfProxy.xFinalAndValue, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xInverse', + name: "xInverse", ...__cfProxy.xInverseAndStep, }), new wasm.xWrap.FuncPtrAdapter({ - name: 'xDestroy', + name: "xDestroy", ...__cfProxy.xDestroy, }), - ], + ] ); capi.sqlite3_create_function_v2 = function f( @@ -9846,13 +9533,13 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - xDestroy, + xDestroy ) { if (f.length !== arguments.length) { return __dbArgcMismatch( pDb, - 'sqlite3_create_function_v2', - f.length, + "sqlite3_create_function_v2", + f.length ); } else if (0 === (eTextRep & 0xf)) { eTextRep |= capi.SQLITE_UTF8; @@ -9869,7 +9556,7 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - xDestroy, + xDestroy ); if ( 0 === rc && @@ -9882,11 +9569,11 @@ var sqlite3InitModule = (() => { } return rc; } catch (e) { - console.error('sqlite3_create_function_v2() setup threw:', e); + console.error("sqlite3_create_function_v2() setup threw:", e); return util.sqlite3__wasm_db_error( pDb, e, - 'Creation of UDF threw: ' + e, + "Creation of UDF threw: " + e ); } }; @@ -9899,7 +9586,7 @@ var sqlite3InitModule = (() => { pApp, xFunc, xStep, - xFinal, + xFinal ) { return f.length === arguments.length ? capi.sqlite3_create_function_v2( @@ -9911,9 +9598,9 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - 0, + 0 ) - : __dbArgcMismatch(pDb, 'sqlite3_create_function', f.length); + : __dbArgcMismatch(pDb, "sqlite3_create_function", f.length); }; capi.sqlite3_create_window_function = function f( @@ -9926,13 +9613,13 @@ var sqlite3InitModule = (() => { xFinal, xValue, xInverse, - xDestroy, + xDestroy ) { if (f.length !== arguments.length) { return __dbArgcMismatch( pDb, - 'sqlite3_create_window_function', - f.length, + "sqlite3_create_window_function", + f.length ); } else if (0 === (eTextRep & 0xf)) { eTextRep |= capi.SQLITE_UTF8; @@ -9950,7 +9637,7 @@ var sqlite3InitModule = (() => { xFinal, xValue, xInverse, - xDestroy, + xDestroy ); if ( 0 === rc && @@ -9964,11 +9651,11 @@ var sqlite3InitModule = (() => { } return rc; } catch (e) { - console.error('sqlite3_create_window_function() setup threw:', e); + console.error("sqlite3_create_window_function() setup threw:", e); return util.sqlite3__wasm_db_error( pDb, e, - 'Creation of UDF threw: ' + e, + "Creation of UDF threw: " + e ); } }; @@ -9991,37 +9678,37 @@ var sqlite3InitModule = (() => { { const __flexiString = (v, n) => { - if ('string' === typeof v) { + if ("string" === typeof v) { n = -1; } else if (util.isSQLableTypedArray(v)) { n = v.byteLength; v = util.typedArrayToString( - v instanceof ArrayBuffer ? new Uint8Array(v) : v, + v instanceof ArrayBuffer ? new Uint8Array(v) : v ); } else if (Array.isArray(v)) { - v = v.join(''); + v = v.join(""); n = -1; } return [v, n]; }; const __prepare = { - basic: wasm.xWrap('sqlite3_prepare_v3', 'int', [ - 'sqlite3*', - 'string', - 'int', - 'int', - '**', - '**', + basic: wasm.xWrap("sqlite3_prepare_v3", "int", [ + "sqlite3*", + "string", + "int", + "int", + "**", + "**", ]), - full: wasm.xWrap('sqlite3_prepare_v3', 'int', [ - 'sqlite3*', - '*', - 'int', - 'int', - '**', - '**', + full: wasm.xWrap("sqlite3_prepare_v3", "int", [ + "sqlite3*", + "*", + "int", + "int", + "**", + "**", ]), }; @@ -10031,36 +9718,36 @@ var sqlite3InitModule = (() => { sqlLen, prepFlags, ppStmt, - pzTail, + pzTail ) { if (f.length !== arguments.length) { - return __dbArgcMismatch(pDb, 'sqlite3_prepare_v3', f.length); + return __dbArgcMismatch(pDb, "sqlite3_prepare_v3", f.length); } const [xSql, xSqlLen] = __flexiString(sql, sqlLen); switch (typeof xSql) { - case 'string': + case "string": return __prepare.basic( pDb, xSql, xSqlLen, prepFlags, ppStmt, - null, + null ); - case 'number': + case "number": return __prepare.full( pDb, xSql, xSqlLen, prepFlags, ppStmt, - pzTail, + pzTail ); default: return util.sqlite3__wasm_db_error( pDb, capi.SQLITE_MISUSE, - 'Invalid SQL argument type for sqlite3_prepare_v2/v3().', + "Invalid SQL argument type for sqlite3_prepare_v2/v3()." ); } }; @@ -10070,28 +9757,28 @@ var sqlite3InitModule = (() => { sql, sqlLen, ppStmt, - pzTail, + pzTail ) { return f.length === arguments.length ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) - : __dbArgcMismatch(pDb, 'sqlite3_prepare_v2', f.length); + : __dbArgcMismatch(pDb, "sqlite3_prepare_v2", f.length); }; } { - const __bindText = wasm.xWrap('sqlite3_bind_text', 'int', [ - 'sqlite3_stmt*', - 'int', - 'string', - 'int', - '*', + const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [ + "sqlite3_stmt*", + "int", + "string", + "int", + "*", ]); - const __bindBlob = wasm.xWrap('sqlite3_bind_blob', 'int', [ - 'sqlite3_stmt*', - 'int', - '*', - 'int', - '*', + const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [ + "sqlite3_stmt*", + "int", + "*", + "int", + "*", ]); capi.sqlite3_bind_text = function f( @@ -10099,33 +9786,33 @@ var sqlite3InitModule = (() => { iCol, text, nText, - xDestroy, + xDestroy ) { if (f.length !== arguments.length) { return __dbArgcMismatch( capi.sqlite3_db_handle(pStmt), - 'sqlite3_bind_text', - f.length, + "sqlite3_bind_text", + f.length ); } else if (wasm.isPtr(text) || null === text) { return __bindText(pStmt, iCol, text, nText, xDestroy); } else if (text instanceof ArrayBuffer) { text = new Uint8Array(text); } else if (Array.isArray(pMem)) { - text = pMem.join(''); + text = pMem.join(""); } let p, n; try { if (util.isSQLableTypedArray(text)) { p = wasm.allocFromTypedArray(text); n = text.byteLength; - } else if ('string' === typeof text) { + } else if ("string" === typeof text) { [p, n] = wasm.allocCString(text); } else { return util.sqlite3__wasm_db_error( capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE, - 'Invalid 3rd argument type for sqlite3_bind_text().', + "Invalid 3rd argument type for sqlite3_bind_text()." ); } return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); @@ -10133,7 +9820,7 @@ var sqlite3InitModule = (() => { wasm.dealloc(p); return util.sqlite3__wasm_db_error( capi.sqlite3_db_handle(pStmt), - e, + e ); } }; @@ -10143,33 +9830,33 @@ var sqlite3InitModule = (() => { iCol, pMem, nMem, - xDestroy, + xDestroy ) { if (f.length !== arguments.length) { return __dbArgcMismatch( capi.sqlite3_db_handle(pStmt), - 'sqlite3_bind_blob', - f.length, + "sqlite3_bind_blob", + f.length ); } else if (wasm.isPtr(pMem) || null === pMem) { return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy); } else if (pMem instanceof ArrayBuffer) { pMem = new Uint8Array(pMem); } else if (Array.isArray(pMem)) { - pMem = pMem.join(''); + pMem = pMem.join(""); } let p, n; try { if (util.isBindableTypedArray(pMem)) { p = wasm.allocFromTypedArray(pMem); n = nMem >= 0 ? nMem : pMem.byteLength; - } else if ('string' === typeof pMem) { + } else if ("string" === typeof pMem) { [p, n] = wasm.allocCString(pMem); } else { return util.sqlite3__wasm_db_error( capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE, - 'Invalid 3rd argument type for sqlite3_bind_blob().', + "Invalid 3rd argument type for sqlite3_bind_blob()." ); } return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); @@ -10177,7 +9864,7 @@ var sqlite3InitModule = (() => { wasm.dealloc(p); return util.sqlite3__wasm_db_error( capi.sqlite3_db_handle(pStmt), - e, + e ); } }; @@ -10198,7 +9885,7 @@ var sqlite3InitModule = (() => { return wasm.exports.sqlite3__wasm_config_ii( op, args[0], - args[1], + args[1] ); case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: return wasm.exports.sqlite3__wasm_config_j(op, args[0]); @@ -10232,7 +9919,7 @@ var sqlite3InitModule = (() => { capi.sqlite3_auto_extension = function (fPtr) { if (fPtr instanceof Function) { - fPtr = wasm.installFunction('i(ppp)', fPtr); + fPtr = wasm.installFunction("i(ppp)", fPtr); } else if (1 !== arguments.length || !wasm.isPtr(fPtr)) { return capi.SQLITE_MISUSE; } @@ -10256,11 +9943,11 @@ var sqlite3InitModule = (() => { }; } - const pKvvfs = capi.sqlite3_vfs_find('kvvfs'); + const pKvvfs = capi.sqlite3_vfs_find("kvvfs"); if (pKvvfs) { if (util.isUIThread()) { const kvvfsMethods = new capi.sqlite3_kvvfs_methods( - wasm.exports.sqlite3__wasm_kvvfs_methods(), + wasm.exports.sqlite3__wasm_kvvfs_methods() ); delete capi.sqlite3_kvvfs_methods; @@ -10293,7 +9980,7 @@ var sqlite3InitModule = (() => { wasm.poke(zBuf + nBuf - 1, 0); return nBuf - 1; } catch (e) { - console.error('kvstorageRead()', e); + console.error("kvstorageRead()", e); return -2; } finally { pstack.restore(stack); @@ -10309,7 +9996,7 @@ var sqlite3InitModule = (() => { kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData)); return 0; } catch (e) { - console.error('kvstorageWrite()', e); + console.error("kvstorageWrite()", e); return capi.SQLITE_IOERR; } finally { pstack.restore(stack); @@ -10323,7 +10010,7 @@ var sqlite3InitModule = (() => { kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey)); return 0; } catch (e) { - console.error('kvstorageDelete()', e); + console.error("kvstorageDelete()", e); return capi.SQLITE_IOERR; } finally { pstack.restore(stack); @@ -10333,7 +10020,7 @@ var sqlite3InitModule = (() => { for (const k of Object.keys(kvvfsImpls)) { kvvfsMethods[kvvfsMethods.memberKey(k)] = wasm.installFunction( kvvfsMethods.memberSignature(k), - kvvfsImpls[k], + kvvfsImpls[k] ); } } else { @@ -10348,12 +10035,12 @@ var sqlite3InitModule = (() => { tgt, name, func, - applyArgcCheck = callee.installMethodArgcCheck, + applyArgcCheck = callee.installMethodArgcCheck ) { if (!(tgt instanceof StructBinder.StructType)) { - toss('Usage error: target object is-not-a StructType.'); + toss("Usage error: target object is-not-a StructType."); } else if (!(func instanceof Function) && !wasm.isPtr(func)) { - toss('Usage errror: expecting a Function or WASM pointer to one.'); + toss("Usage errror: expecting a Function or WASM pointer to one."); } if (1 === arguments.length) { return (n, f) => callee(tgt, n, f, applyArgcCheck); @@ -10363,12 +10050,12 @@ var sqlite3InitModule = (() => { return function (...args) { if (func.length !== arguments.length) { toss( - 'Argument mismatch for', + "Argument mismatch for", tgt.structInfo.name + - '::' + + "::" + funcName + - ': Native signature is:', - sig, + ": Native signature is:", + sig ); } return func.apply(this, args); @@ -10378,7 +10065,7 @@ var sqlite3InitModule = (() => { callee.removeFuncList = function () { if (this.ondispose.__removeFuncList) { this.ondispose.__removeFuncList.forEach((v, ndx) => { - if ('number' === typeof v) { + if ("number" === typeof v) { try { wasm.uninstallFunction(v); } catch (e) {} @@ -10391,10 +10078,10 @@ var sqlite3InitModule = (() => { const sigN = tgt.memberSignature(name); if (sigN.length < 2) { toss( - 'Member', + "Member", name, - 'does not have a function pointer signature:', - sigN, + "does not have a function pointer signature:", + sigN ); } const memKey = tgt.memberKey(name); @@ -10404,19 +10091,19 @@ var sqlite3InitModule = (() => { : func; if (wasm.isPtr(fProxy)) { if (fProxy && !wasm.functionEntry(fProxy)) { - toss('Pointer', fProxy, 'is not a WASM function table entry.'); + toss("Pointer", fProxy, "is not a WASM function table entry."); } tgt[memKey] = fProxy; } else { const pFunc = wasm.installFunction( fProxy, - tgt.memberSignature(name, true), + tgt.memberSignature(name, true) ); tgt[memKey] = pFunc; if (!tgt.ondispose || !tgt.ondispose.__removeFuncList) { tgt.addOnDispose( - 'ondispose.__removeFuncList handler', - callee.removeFuncList, + "ondispose.__removeFuncList handler", + callee.removeFuncList ); tgt.ondispose.__removeFuncList = []; } @@ -10429,7 +10116,7 @@ var sqlite3InitModule = (() => { const installMethods = function ( structInstance, methods, - applyArgcCheck = installMethod.installMethodArgcCheck, + applyArgcCheck = installMethod.installMethodArgcCheck ) { const seen = new Map(); for (const k of Object.keys(methods)) { @@ -10450,16 +10137,16 @@ var sqlite3InitModule = (() => { StructBinder.StructType.prototype.installMethod = function callee( name, func, - applyArgcCheck = installMethod.installMethodArgcCheck, + applyArgcCheck = installMethod.installMethodArgcCheck ) { - return arguments.length < 3 && name && 'object' === typeof name + return arguments.length < 3 && name && "object" === typeof name ? installMethods(this, ...arguments) : installMethod(this, ...arguments); }; StructBinder.StructType.prototype.installMethods = function ( methods, - applyArgcCheck = installMethod.installMethodArgcCheck, + applyArgcCheck = installMethod.installMethodArgcCheck ) { return installMethods(this, methods, applyArgcCheck); }; @@ -10467,10 +10154,10 @@ var sqlite3InitModule = (() => { globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { sqlite3.version = { - libVersion: '3.46.1', + libVersion: "3.46.1", libVersionNumber: 3046001, sourceId: - '2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33', + "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33", downloadVersion: 3460100, }; }); @@ -10498,26 +10185,26 @@ var sqlite3InitModule = (() => { if (dbPtr instanceof DB) dbPtr = dbPtr.pointer; toss3( sqliteResultCode, - 'sqlite3 result code', - sqliteResultCode + ':', + "sqlite3 result code", + sqliteResultCode + ":", dbPtr ? capi.sqlite3_errmsg(dbPtr) - : capi.sqlite3_errstr(sqliteResultCode), + : capi.sqlite3_errstr(sqliteResultCode) ); } return arguments[0]; }; const __dbTraceToConsole = wasm.installFunction( - 'i(ippp)', + "i(ippp)", function (t, c, p, x) { if (capi.SQLITE_TRACE_STMT === t) { console.log( - 'SQL TRACE #' + ++this.counter + ' via sqlite3@' + c + ':', - wasm.cstrToJs(x), + "SQL TRACE #" + ++this.counter + " via sqlite3@" + c + ":", + wasm.cstrToJs(x) ); } - }.bind({ counter: 0 }), + }.bind({ counter: 0 }) ); const __vfsPostOpenSql = Object.create(null); @@ -10526,21 +10213,21 @@ var sqlite3InitModule = (() => { if (!ctor._name2vfs) { ctor._name2vfs = Object.create(null); const isWorkerThread = - 'function' === typeof importScripts + "function" === typeof importScripts ? (n) => toss3( - 'The VFS for', + "The VFS for", n, - 'is only available in the main window thread.', + "is only available in the main window thread." ) : false; - ctor._name2vfs[':localStorage:'] = { - vfs: 'kvvfs', - filename: isWorkerThread || (() => 'local'), + ctor._name2vfs[":localStorage:"] = { + vfs: "kvvfs", + filename: isWorkerThread || (() => "local"), }; - ctor._name2vfs[':sessionStorage:'] = { - vfs: 'kvvfs', - filename: isWorkerThread || (() => 'session'), + ctor._name2vfs[":sessionStorage:"] = { + vfs: "kvvfs", + filename: isWorkerThread || (() => "session"), }; } const opt = ctor.normalizeArgs(...args); @@ -10548,16 +10235,16 @@ var sqlite3InitModule = (() => { vfsName = opt.vfs, flagsStr = opt.flags; if ( - ('string' !== typeof fn && 'number' !== typeof fn) || - 'string' !== typeof flagsStr || + ("string" !== typeof fn && "number" !== typeof fn) || + "string" !== typeof flagsStr || (vfsName && - 'string' !== typeof vfsName && - 'number' !== typeof vfsName) + "string" !== typeof vfsName && + "number" !== typeof vfsName) ) { - sqlite3.config.error('Invalid DB ctor args', opt, arguments); - toss3('Invalid arguments for DB constructor.'); + sqlite3.config.error("Invalid DB ctor args", opt, arguments); + toss3("Invalid arguments for DB constructor."); } - let fnJs = 'number' === typeof fn ? wasm.cstrToJs(fn) : fn; + let fnJs = "number" === typeof fn ? wasm.cstrToJs(fn) : fn; const vfsCheck = ctor._name2vfs[fnJs]; if (vfsCheck) { vfsName = vfsCheck.vfs; @@ -10565,10 +10252,10 @@ var sqlite3InitModule = (() => { } let pDb, oflags = 0; - if (flagsStr.indexOf('c') >= 0) { + if (flagsStr.indexOf("c") >= 0) { oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; } - if (flagsStr.indexOf('w') >= 0) oflags |= capi.SQLITE_OPEN_READWRITE; + if (flagsStr.indexOf("w") >= 0) oflags |= capi.SQLITE_OPEN_READWRITE; if (0 === oflags) oflags |= capi.SQLITE_OPEN_READONLY; oflags |= capi.SQLITE_OPEN_EXRESCODE; const stack = wasm.pstack.pointer; @@ -10578,12 +10265,12 @@ var sqlite3InitModule = (() => { pDb = wasm.peekPtr(pPtr); checkSqlite3Rc(pDb, rc); capi.sqlite3_extended_result_codes(pDb, 1); - if (flagsStr.indexOf('t') >= 0) { + if (flagsStr.indexOf("t") >= 0) { capi.sqlite3_trace_v2( pDb, capi.SQLITE_TRACE_STMT, __dbTraceToConsole, - pDb, + pDb ); } } catch (e) { @@ -10598,7 +10285,7 @@ var sqlite3InitModule = (() => { try { const pVfs = capi.sqlite3_js_db_vfs(pDb) || - toss3('Internal error: cannot get VFS for new db handle.'); + toss3("Internal error: cannot get VFS for new db handle."); const postInitSql = __vfsPostOpenSql[pVfs]; if (postInitSql) { if (postInitSql instanceof Function) { @@ -10606,7 +10293,7 @@ var sqlite3InitModule = (() => { } else { checkSqlite3Rc( pDb, - capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0), + capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0) ); } } @@ -10621,20 +10308,20 @@ var sqlite3InitModule = (() => { }; dbCtorHelper.normalizeArgs = function ( - filename = ':memory:', - flags = 'c', - vfs = null, + filename = ":memory:", + flags = "c", + vfs = null ) { const arg = {}; if ( 1 === arguments.length && arguments[0] && - 'object' === typeof arguments[0] + "object" === typeof arguments[0] ) { Object.assign(arg, arguments[0]); - if (undefined === arg.flags) arg.flags = 'c'; + if (undefined === arg.flags) arg.flags = "c"; if (undefined === arg.vfs) arg.vfs = null; - if (undefined === arg.filename) arg.filename = ':memory:'; + if (undefined === arg.filename) arg.filename = ":memory:"; } else { arg.filename = filename; arg.flags = flags; @@ -10655,7 +10342,7 @@ var sqlite3InitModule = (() => { boolean: 4, blob: 5, }; - BindTypes['undefined'] == BindTypes.null; + BindTypes["undefined"] == BindTypes.null; if (wasm.bigIntEnabled) { BindTypes.bigint = BindTypes.number; } @@ -10664,7 +10351,7 @@ var sqlite3InitModule = (() => { if (BindTypes !== arguments[2]) { toss3( capi.SQLITE_MISUSE, - 'Do not call the Stmt constructor directly. Use DB.prepare().', + "Do not call the Stmt constructor directly. Use DB.prepare()." ); } this.db = arguments[0]; @@ -10673,13 +10360,13 @@ var sqlite3InitModule = (() => { }; const affirmDbOpen = function (db) { - if (!db.pointer) toss3('DB has been closed.'); + if (!db.pointer) toss3("DB has been closed."); return db; }; const affirmColIndex = function (stmt, ndx) { if (ndx !== (ndx | 0) || ndx < 0 || ndx >= stmt.columnCount) { - toss3('Column index', ndx, 'is out of range.'); + toss3("Column index", ndx, "is out of range."); } return stmt; }; @@ -10690,13 +10377,13 @@ var sqlite3InitModule = (() => { switch (args.length) { case 1: if ( - 'string' === typeof args[0] || + "string" === typeof args[0] || util.isSQLableTypedArray(args[0]) ) { out.sql = args[0]; } else if (Array.isArray(args[0])) { out.sql = args[0]; - } else if (args[0] && 'object' === typeof args[0]) { + } else if (args[0] && "object" === typeof args[0]) { out.opt = args[0]; out.sql = out.opt.sql; } @@ -10706,36 +10393,36 @@ var sqlite3InitModule = (() => { out.opt = args[1]; break; default: - toss3('Invalid argument count for exec().'); + toss3("Invalid argument count for exec()."); } out.sql = util.flexibleString(out.sql); - if ('string' !== typeof out.sql) { - toss3('Missing SQL argument or unsupported SQL value type.'); + if ("string" !== typeof out.sql) { + toss3("Missing SQL argument or unsupported SQL value type."); } const opt = out.opt; switch (opt.returnValue) { - case 'resultRows': + case "resultRows": if (!opt.resultRows) opt.resultRows = []; out.returnVal = () => opt.resultRows; break; - case 'saveSql': + case "saveSql": if (!opt.saveSql) opt.saveSql = []; out.returnVal = () => opt.saveSql; break; case undefined: - case 'this': + case "this": out.returnVal = () => db; break; default: - toss3('Invalid returnValue value:', opt.returnValue); + toss3("Invalid returnValue value:", opt.returnValue); } if (!opt.callback && !opt.returnValue && undefined !== opt.rowMode) { if (!opt.resultRows) opt.resultRows = []; out.returnVal = () => opt.resultRows; } if (opt.callback || opt.resultRows) { - switch (undefined === opt.rowMode ? 'array' : opt.rowMode) { - case 'object': + switch (undefined === opt.rowMode ? "array" : opt.rowMode) { + case "object": out.cbArg = (stmt, cache) => { if (!cache.columnNames) cache.columnNames = stmt.getColumnNames([]); @@ -10747,15 +10434,15 @@ var sqlite3InitModule = (() => { return rv; }; break; - case 'array': + case "array": out.cbArg = (stmt) => stmt.get([]); break; - case 'stmt': + case "stmt": if (Array.isArray(opt.resultRows)) { toss3( - 'exec(): invalid rowMode for a resultRows array: must', + "exec(): invalid rowMode for a resultRows array: must", "be one of 'array', 'object',", - 'a result column number, or column name reference.', + "a result column number, or column name reference." ); } out.cbArg = (stmt) => stmt; @@ -10765,9 +10452,9 @@ var sqlite3InitModule = (() => { out.cbArg = (stmt) => stmt.get(opt.rowMode); break; } else if ( - 'string' === typeof opt.rowMode && + "string" === typeof opt.rowMode && opt.rowMode.length > 1 && - '$' === opt.rowMode[0] + "$" === opt.rowMode[0] ) { const $colName = opt.rowMode.substr(1); out.cbArg = (stmt) => { @@ -10775,14 +10462,14 @@ var sqlite3InitModule = (() => { return undefined === rc ? toss3( capi.SQLITE_NOTFOUND, - 'exec(): unknown result column:', - $colName, + "exec(): unknown result column:", + $colName ) : rc; }; break; } - toss3('Invalid rowMode:', opt.rowMode); + toss3("Invalid rowMode:", opt.rowMode); } } return out; @@ -10806,7 +10493,7 @@ var sqlite3InitModule = (() => { sql, bind, rowMode, - returnValue: 'resultRows', + returnValue: "resultRows", }); DB.checkRc = (db, resultCode) => checkSqlite3Rc(db, resultCode); @@ -10860,7 +10547,7 @@ var sqlite3InitModule = (() => { } }, - dbFilename: function (dbName = 'main') { + dbFilename: function (dbName = "main") { return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName); }, @@ -10872,7 +10559,7 @@ var sqlite3InitModule = (() => { let rc; const pVfs = capi.sqlite3_js_db_vfs( affirmDbOpen(this).pointer, - dbName, + dbName ); if (pVfs) { const v = new capi.sqlite3_vfs(pVfs); @@ -10893,13 +10580,13 @@ var sqlite3InitModule = (() => { ppStmt = wasm.pstack.alloc(8); DB.checkRc( this, - capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null), + capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null) ); pStmt = wasm.peekPtr(ppStmt); } finally { wasm.pstack.restore(stack); } - if (!pStmt) toss3('Cannot prepare empty SQL.'); + if (!pStmt) toss3("Cannot prepare empty SQL."); const stmt = new Stmt(this, pStmt, BindTypes); __stmtMap.get(this)[pStmt] = stmt; return stmt; @@ -10909,7 +10596,7 @@ var sqlite3InitModule = (() => { affirmDbOpen(this); const arg = parseExecArgs(this, arguments); if (!arg.sql) { - return toss3('exec() requires an SQL string.'); + return toss3("exec() requires an SQL string."); } const opt = arg.opt; const callback = opt.callback; @@ -10933,7 +10620,7 @@ var sqlite3InitModule = (() => { ? arg.sql.byteLength : wasm.jstrlen(arg.sql); const ppStmt = wasm.scopedAlloc( - 2 * wasm.ptrSizeof + (sqlByteLen + 1), + 2 * wasm.ptrSizeof + (sqlByteLen + 1) ); const pzTail = ppStmt + wasm.ptrSizeof; let pSql = pzTail + wasm.ptrSizeof; @@ -10941,7 +10628,7 @@ var sqlite3InitModule = (() => { if (isTA) wasm.heap8().set(arg.sql, pSql); else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false); wasm.poke(pSql + sqlByteLen, 0); - while (pSql && wasm.peek(pSql, 'i8')) { + while (pSql && wasm.peek(pSql, "i8")) { wasm.pokePtr([ppStmt, pzTail], 0); DB.checkRc( this, @@ -10951,8 +10638,8 @@ var sqlite3InitModule = (() => { sqlByteLen, 0, ppStmt, - pzTail, - ), + pzTail + ) ); const pStmt = wasm.peekPtr(ppStmt); pSql = wasm.peekPtr(pzTail); @@ -10972,7 +10659,7 @@ var sqlite3InitModule = (() => { for (; stmt.step(); stmt._lockedByExec = false) { if (0 === gotColNames++) { stmt.getColumnNames( - (cbArgCache.columnNames = opt.columnNames || []), + (cbArgCache.columnNames = opt.columnNames || []) ); } stmt._lockedByExec = true; @@ -11019,8 +10706,8 @@ var sqlite3InitModule = (() => { break; } if (!opt) opt = {}; - if ('string' !== typeof name) { - toss3('Invalid arguments: missing function name.'); + if ("string" !== typeof name) { + toss3("Invalid arguments: missing function name."); } let xStep = opt.xStep || 0; let xFinal = opt.xFinal || 0; @@ -11030,62 +10717,62 @@ var sqlite3InitModule = (() => { if (isFunc(xFunc)) { isWindow = false; if (isFunc(xStep) || isFunc(xFinal)) { - toss3('Ambiguous arguments: scalar or aggregate?'); + toss3("Ambiguous arguments: scalar or aggregate?"); } xStep = xFinal = null; } else if (isFunc(xStep)) { if (!isFunc(xFinal)) { - toss3('Missing xFinal() callback for aggregate or window UDF.'); + toss3("Missing xFinal() callback for aggregate or window UDF."); } xFunc = null; } else if (isFunc(xFinal)) { - toss3('Missing xStep() callback for aggregate or window UDF.'); + toss3("Missing xStep() callback for aggregate or window UDF."); } else { - toss3('Missing function-type properties.'); + toss3("Missing function-type properties."); } if (false === isWindow) { if (isFunc(xValue) || isFunc(xInverse)) { toss3( - 'xValue and xInverse are not permitted for non-window UDFs.', + "xValue and xInverse are not permitted for non-window UDFs." ); } } else if (isFunc(xValue)) { if (!isFunc(xInverse)) { - toss3('xInverse must be provided if xValue is.'); + toss3("xInverse must be provided if xValue is."); } isWindow = true; } else if (isFunc(xInverse)) { - toss3('xValue must be provided if xInverse is.'); + toss3("xValue must be provided if xInverse is."); } const pApp = opt.pApp; if ( undefined !== pApp && null !== pApp && - ('number' !== typeof pApp || !util.isInt32(pApp)) + ("number" !== typeof pApp || !util.isInt32(pApp)) ) { toss3( - 'Invalid value for pApp property. Must be a legal WASM pointer value.', + "Invalid value for pApp property. Must be a legal WASM pointer value." ); } const xDestroy = opt.xDestroy || 0; if (xDestroy && !isFunc(xDestroy)) { - toss3('xDestroy property must be a function.'); + toss3("xDestroy property must be a function."); } let fFlags = 0; - if (getOwnOption(opt, 'deterministic')) + if (getOwnOption(opt, "deterministic")) fFlags |= capi.SQLITE_DETERMINISTIC; - if (getOwnOption(opt, 'directOnly')) + if (getOwnOption(opt, "directOnly")) fFlags |= capi.SQLITE_DIRECTONLY; - if (getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS; + if (getOwnOption(opt, "innocuous")) fFlags |= capi.SQLITE_INNOCUOUS; name = name.toLowerCase(); const xArity = xFunc || xStep; - const arity = getOwnOption(opt, 'arity'); + const arity = getOwnOption(opt, "arity"); const arityArg = - 'number' === typeof arity + "number" === typeof arity ? arity : xArity.length - ? xArity.length - 1 - : 0; + ? xArity.length - 1 + : 0; let rc; if (isWindow) { rc = capi.sqlite3_create_window_function( @@ -11098,7 +10785,7 @@ var sqlite3InitModule = (() => { xFinal, xValue, xInverse, - xDestroy, + xDestroy ); } else { rc = capi.sqlite3_create_function_v2( @@ -11110,7 +10797,7 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - xDestroy, + xDestroy ); } DB.checkRc(this, rc); @@ -11143,11 +10830,11 @@ var sqlite3InitModule = (() => { }, selectArrays: function (sql, bind) { - return __selectAll(this, sql, bind, 'array'); + return __selectAll(this, sql, bind, "array"); }, selectObjects: function (sql, bind) { - return __selectAll(this, sql, bind, 'object'); + return __selectAll(this, sql, bind, "object"); }, openStatementCount: function () { @@ -11155,36 +10842,36 @@ var sqlite3InitModule = (() => { }, transaction: function (callback) { - let opener = 'BEGIN'; + let opener = "BEGIN"; if (arguments.length > 1) { if (/[^a-zA-Z]/.test(arguments[0])) { toss3( capi.SQLITE_MISUSE, - 'Invalid argument for BEGIN qualifier.', + "Invalid argument for BEGIN qualifier." ); } - opener += ' ' + arguments[0]; + opener += " " + arguments[0]; callback = arguments[1]; } affirmDbOpen(this).exec(opener); try { const rc = callback(this); - this.exec('COMMIT'); + this.exec("COMMIT"); return rc; } catch (e) { - this.exec('ROLLBACK'); + this.exec("ROLLBACK"); throw e; } }, savepoint: function (callback) { - affirmDbOpen(this).exec('SAVEPOINT oo1'); + affirmDbOpen(this).exec("SAVEPOINT oo1"); try { const rc = callback(this); - this.exec('RELEASE oo1'); + this.exec("RELEASE oo1"); return rc; } catch (e) { - this.exec('ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1'); + this.exec("ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1"); throw e; } }, @@ -11195,12 +10882,12 @@ var sqlite3InitModule = (() => { }; const affirmStmtOpen = function (stmt) { - if (!stmt.pointer) toss3('Stmt has been closed.'); + if (!stmt.pointer) toss3("Stmt has been closed."); return stmt; }; const isSupportedBindType = function (v) { - let t = BindTypes[null === v || undefined === v ? 'null' : typeof v]; + let t = BindTypes[null === v || undefined === v ? "null" : typeof v]; switch (t) { case BindTypes.boolean: case BindTypes.null: @@ -11218,39 +10905,39 @@ var sqlite3InitModule = (() => { const affirmSupportedBindType = function (v) { return ( isSupportedBindType(v) || - toss3('Unsupported bind() argument type:', typeof v) + toss3("Unsupported bind() argument type:", typeof v) ); }; const affirmParamIndex = function (stmt, key) { const n = - 'number' === typeof key + "number" === typeof key ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key); if (0 === n || !util.isInt32(n)) { - toss3('Invalid bind() parameter name: ' + key); + toss3("Invalid bind() parameter name: " + key); } else if (n < 1 || n > stmt.parameterCount) - toss3('Bind index', key, 'is out of range.'); + toss3("Bind index", key, "is out of range."); return n; }; const affirmNotLockedByExec = function (stmt, currentOpName) { if (stmt._lockedByExec) { toss3( - 'Operation is illegal when statement is locked:', - currentOpName, + "Operation is illegal when statement is locked:", + currentOpName ); } return stmt; }; const bindOne = function f(stmt, ndx, bindType, val) { - affirmNotLockedByExec(affirmStmtOpen(stmt), 'bind()'); + affirmNotLockedByExec(affirmStmtOpen(stmt), "bind()"); if (!f._) { f._tooBigInt = (v) => toss3( - 'BigInt value is too big to store without precision loss:', - v, + "BigInt value is too big to store without precision loss:", + v ); f._ = { string: function (stmt, ndx, val, asBlob) { @@ -11277,7 +10964,7 @@ var sqlite3InitModule = (() => { case BindTypes.number: { let m; if (util.isInt32(val)) m = capi.sqlite3_bind_int; - else if ('bigint' === typeof val) { + else if ("bigint" === typeof val) { if (!util.bigIntFits64(val)) { f._tooBigInt(val); } else if (wasm.bigIntEnabled) { @@ -11303,15 +10990,15 @@ var sqlite3InitModule = (() => { rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0); break; case BindTypes.blob: { - if ('string' === typeof val) { + if ("string" === typeof val) { rc = f._.string(stmt, ndx, val, true); break; } else if (val instanceof ArrayBuffer) { val = new Uint8Array(val); } else if (!util.isBindableTypedArray(val)) { toss3( - 'Binding a value as a blob requires', - 'that it be a string, Uint8Array, Int8Array, or ArrayBuffer.', + "Binding a value as a blob requires", + "that it be a string, Uint8Array, Int8Array, or ArrayBuffer." ); } const pBlob = wasm.alloc(val.byteLength || 1); @@ -11321,13 +11008,13 @@ var sqlite3InitModule = (() => { ndx, pBlob, val.byteLength, - capi.SQLITE_WASM_DEALLOC, + capi.SQLITE_WASM_DEALLOC ); break; } default: - sqlite3.config.warn('Unsupported bind() argument type:', val); - toss3('Unsupported bind() argument type: ' + typeof val); + sqlite3.config.warn("Unsupported bind() argument type:", val); + toss3("Unsupported bind() argument type: " + typeof val); } if (rc) DB.checkRc(stmt.db.pointer, rc); stmt._mayGet = false; @@ -11337,7 +11024,7 @@ var sqlite3InitModule = (() => { Stmt.prototype = { finalize: function () { if (this.pointer) { - affirmNotLockedByExec(this, 'finalize()'); + affirmNotLockedByExec(this, "finalize()"); const rc = capi.sqlite3_finalize(this.pointer); delete __stmtMap.get(this.db)[this.pointer]; __ptrMap.delete(this); @@ -11350,14 +11037,14 @@ var sqlite3InitModule = (() => { }, clearBindings: function () { - affirmNotLockedByExec(affirmStmtOpen(this), 'clearBindings()'); + affirmNotLockedByExec(affirmStmtOpen(this), "clearBindings()"); capi.sqlite3_clear_bindings(this.pointer); this._mayGet = false; return this; }, reset: function (alsoClearBinds) { - affirmNotLockedByExec(this, 'reset()'); + affirmNotLockedByExec(this, "reset()"); if (alsoClearBinds) this.clearBindings(); const rc = capi.sqlite3_reset(affirmStmtOpen(this).pointer); this._mayGet = false; @@ -11378,12 +11065,12 @@ var sqlite3InitModule = (() => { arg = arguments[1]; break; default: - toss3('Invalid bind() arguments.'); + toss3("Invalid bind() arguments."); } if (undefined === arg) { return this; } else if (!this.parameterCount) { - toss3('This statement has no bindable parameters.'); + toss3("This statement has no bindable parameters."); } this._mayGet = false; if (null === arg) { @@ -11391,24 +11078,24 @@ var sqlite3InitModule = (() => { } else if (Array.isArray(arg)) { if (1 !== arguments.length) { toss3( - 'When binding an array, an index argument is not permitted.', + "When binding an array, an index argument is not permitted." ); } arg.forEach((v, i) => - bindOne(this, i + 1, affirmSupportedBindType(v), v), + bindOne(this, i + 1, affirmSupportedBindType(v), v) ); return this; } else if (arg instanceof ArrayBuffer) { arg = new Uint8Array(arg); } - if ('object' === typeof arg && !util.isBindableTypedArray(arg)) { + if ("object" === typeof arg && !util.isBindableTypedArray(arg)) { if (1 !== arguments.length) { toss3( - 'When binding an object, an index argument is not permitted.', + "When binding an object, an index argument is not permitted." ); } Object.keys(arg).forEach((k) => - bindOne(this, k, affirmSupportedBindType(arg[k]), arg[k]), + bindOne(this, k, affirmSupportedBindType(arg[k]), arg[k]) ); return this; } else { @@ -11428,13 +11115,13 @@ var sqlite3InitModule = (() => { BindTypes.blob !== t && BindTypes.null !== t ) { - toss3('Invalid value type for bindAsBlob()'); + toss3("Invalid value type for bindAsBlob()"); } return bindOne(this, ndx, BindTypes.blob, arg); }, step: function () { - affirmNotLockedByExec(this, 'step()'); + affirmNotLockedByExec(this, "step()"); const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer); switch (rc) { case capi.SQLITE_DONE: @@ -11444,11 +11131,11 @@ var sqlite3InitModule = (() => { default: this._mayGet = false; sqlite3.config.warn( - 'sqlite3_step() rc=', + "sqlite3_step() rc=", rc, capi.sqlite3_js_rc_str(rc), - 'SQL =', - capi.sqlite3_sql(this.pointer), + "SQL =", + capi.sqlite3_sql(this.pointer) ); DB.checkRc(this.db.pointer, rc); } @@ -11473,7 +11160,7 @@ var sqlite3InitModule = (() => { get: function (ndx, asType) { if (!affirmStmtOpen(this)._mayGet) { - toss3('Stmt.step() has not (recently) returned true.'); + toss3("Stmt.step() has not (recently) returned true."); } if (Array.isArray(ndx)) { let i = 0; @@ -11482,7 +11169,7 @@ var sqlite3InitModule = (() => { ndx[i] = this.get(i++); } return ndx; - } else if (ndx && 'object' === typeof ndx) { + } else if (ndx && "object" === typeof ndx) { let i = 0; const n = this.columnCount; while (i < n) { @@ -11515,7 +11202,7 @@ var sqlite3InitModule = (() => { rc < Number.MIN_SAFE_INTEGER ) { toss3( - 'Integer is out of range for JS integer range: ' + rc, + "Integer is out of range for JS integer range: " + rc ); } @@ -11541,10 +11228,10 @@ var sqlite3InitModule = (() => { default: toss3( "Don't know how to translate", - 'type of result column #' + ndx + '.', + "type of result column #" + ndx + "." ); } - toss3('Not reached.'); + toss3("Not reached."); }, getInt: function (ndx) { @@ -11571,7 +11258,7 @@ var sqlite3InitModule = (() => { getColumnName: function (ndx) { return capi.sqlite3_column_name( affirmColIndex(affirmStmtOpen(this), ndx).pointer, - ndx, + ndx ); }, @@ -11597,18 +11284,18 @@ var sqlite3InitModule = (() => { get: function () { return __ptrMap.get(this); }, - set: () => toss3('The pointer property is read-only.'), + set: () => toss3("The pointer property is read-only."), }; - Object.defineProperty(Stmt.prototype, 'pointer', prop); - Object.defineProperty(DB.prototype, 'pointer', prop); + Object.defineProperty(Stmt.prototype, "pointer", prop); + Object.defineProperty(DB.prototype, "pointer", prop); } - Object.defineProperty(Stmt.prototype, 'columnCount', { + Object.defineProperty(Stmt.prototype, "columnCount", { enumerable: false, get: function () { return capi.sqlite3_column_count(this.pointer); }, - set: () => toss3('The columnCount property is read-only.'), + set: () => toss3("The columnCount property is read-only."), }); sqlite3.oo1 = { @@ -11617,13 +11304,13 @@ var sqlite3InitModule = (() => { }; if (util.isUIThread()) { - sqlite3.oo1.JsStorageDb = function (storageName = 'session') { + sqlite3.oo1.JsStorageDb = function (storageName = "session") { const opt = dbCtorHelper.normalizeArgs(...arguments); storageName = opt.filename; - if ('session' !== storageName && 'local' !== storageName) { + if ("session" !== storageName && "local" !== storageName) { toss3("JsStorageDb db name must be one of 'session' or 'local'."); } - opt.vfs = 'kvvfs'; + opt.vfs = "kvvfs"; dbCtorHelper.call(this, opt); }; const jdb = sqlite3.oo1.JsStorageDb; @@ -11647,18 +11334,18 @@ var sqlite3InitModule = (() => { const util = sqlite3.util; sqlite3.initWorker1API = function () { const toss = (...args) => { - throw new Error(args.join(' ')); + throw new Error(args.join(" ")); }; if (!(globalThis.WorkerGlobalScope instanceof Function)) { - toss('initWorker1API() must be run from a Worker thread.'); + toss("initWorker1API() must be run from a Worker thread."); } - const sqlite3 = this.sqlite3 || toss('Missing this.sqlite3 object.'); + const sqlite3 = this.sqlite3 || toss("Missing this.sqlite3 object."); const DB = sqlite3.oo1.DB; const getDbId = function (db) { let id = wState.idMap.get(db); if (id) return id; - id = 'db#' + ++wState.idSeq + '@' + db.pointer; + id = "db#" + ++wState.idSeq + "@" + db.pointer; wState.idMap.set(db, id); return id; @@ -11706,13 +11393,13 @@ var sqlite3InitModule = (() => { getDb: function (id, require = true) { return ( this.dbs[id] || - (require ? toss('Unknown (or closed) DB ID:', id) : undefined) + (require ? toss("Unknown (or closed) DB ID:", id) : undefined) ); }, }; const affirmDbOpen = function (db = wState.dbList[0]) { - return db && db.pointer ? db : toss('DB is not opened.'); + return db && db.pointer ? db : toss("DB is not opened."); }; const getMsgDb = function (msgData, affirmExists = true) { @@ -11729,16 +11416,16 @@ var sqlite3InitModule = (() => { const oargs = Object.create(null), args = ev.args || Object.create(null); if (args.simulateError) { - toss('Throwing because of simulateError flag.'); + toss("Throwing because of simulateError flag."); } const rc = Object.create(null); oargs.vfs = args.vfs; - oargs.filename = args.filename || ''; + oargs.filename = args.filename || ""; const db = wState.open(oargs); rc.filename = db.filename; rc.persistent = !!sqlite3.capi.sqlite3_js_db_uses_vfs( db.pointer, - 'opfs', + "opfs" ); rc.dbId = getDbId(db); rc.vfs = db.dbVfsName(); @@ -11752,7 +11439,7 @@ var sqlite3InitModule = (() => { }; if (db) { const doUnlink = - ev.args && 'object' === typeof ev.args + ev.args && "object" === typeof ev.args ? !!ev.args.unlink : false; wState.close(db, doUnlink); @@ -11762,13 +11449,13 @@ var sqlite3InitModule = (() => { exec: function (ev) { const rc = - 'string' === typeof ev.args + "string" === typeof ev.args ? { sql: ev.args } : ev.args || Object.create(null); - if ('stmt' === rc.rowMode) { + if ("stmt" === rc.rowMode) { toss( "Invalid rowMode for 'exec': stmt mode", - 'does not work in the Worker API.', + "does not work in the Worker API." ); } else if (!rc.sql) { toss("'exec' requires input SQL."); @@ -11780,7 +11467,7 @@ var sqlite3InitModule = (() => { const theCallback = rc.callback; let rowNumber = 0; const hadColNames = !!rc.columnNames; - if ('string' === typeof theCallback) { + if ("string" === typeof theCallback) { if (!hadColNames) rc.columnNames = []; rc.callback = function (row, stmt) { @@ -11791,7 +11478,7 @@ var sqlite3InitModule = (() => { rowNumber: ++rowNumber, row: row, }, - wState.xfer, + wState.xfer ); }; } @@ -11821,10 +11508,10 @@ var sqlite3InitModule = (() => { return rc; }, - 'config-get': function () { + "config-get": function () { const rc = Object.create(null), src = sqlite3.config; - ['bigIntEnabled'].forEach(function (k) { + ["bigIntEnabled"].forEach(function (k) { if (Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k]; }); rc.version = sqlite3.version; @@ -11838,18 +11525,18 @@ var sqlite3InitModule = (() => { const response = { byteArray: sqlite3.capi.sqlite3_js_db_export(db.pointer), filename: db.filename, - mimetype: 'application/x-sqlite3', + mimetype: "application/x-sqlite3", }; wState.xfer.push(response.byteArray.buffer); return response; }, toss: function (ev) { - toss('Testing worker exception'); + toss("Testing worker exception"); }, - 'opfs-tree': async function (ev) { - if (!sqlite3.opfs) toss('OPFS support is unavailable.'); + "opfs-tree": async function (ev) { + if (!sqlite3.opfs) toss("OPFS support is unavailable."); const response = await sqlite3.opfs.treeList(); return response; }, @@ -11868,10 +11555,10 @@ var sqlite3InitModule = (() => { ) { result = await wMsgHandler[evType](ev); } else { - toss('Unknown db worker message type:', ev.type); + toss("Unknown db worker message type:", ev.type); } } catch (err) { - evType = 'error'; + evType = "error"; result = { operation: ev.type, message: err.message, @@ -11880,7 +11567,7 @@ var sqlite3InitModule = (() => { }; if (err.stack) { result.stack = - 'string' === typeof err.stack + "string" === typeof err.stack ? err.stack.split(/\n\s*/) : err.stack; } @@ -11900,12 +11587,12 @@ var sqlite3InitModule = (() => { result: result, }, - wState.xfer, + wState.xfer ); }; globalThis.postMessage({ - type: 'sqlite3-api', - result: 'worker1-ready', + type: "sqlite3-api", + result: "worker1-ready", }); }.bind({ sqlite3 }); }); @@ -11918,16 +11605,16 @@ var sqlite3InitModule = (() => { capi.sqlite3_vfs.prototype.registerVfs = function (asDefault = false) { if (!(this instanceof sqlite3.capi.sqlite3_vfs)) { - toss('Expecting a sqlite3_vfs-type argument.'); + toss("Expecting a sqlite3_vfs-type argument."); } const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0); if (rc) { - toss('sqlite3_vfs_register(', this, ') failed with rc', rc); + toss("sqlite3_vfs_register(", this, ") failed with rc", rc); } if (this.pointer !== capi.sqlite3_vfs_find(this.$zName)) { toss( - 'BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS', - this, + "BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS", + this ); } return this; @@ -11935,16 +11622,16 @@ var sqlite3InitModule = (() => { vfs.installVfs = function (opt) { let count = 0; - const propList = ['io', 'vfs']; + const propList = ["io", "vfs"]; for (const key of propList) { const o = opt[key]; if (o) { ++count; o.struct.installMethods(o.methods, !!o.applyArgcCheck); - if ('vfs' === key) { - if (!o.struct.$zName && 'string' === typeof o.name) { + if ("vfs" === key) { + if (!o.struct.$zName && "string" === typeof o.name) { o.struct.addOnDispose( - (o.struct.$zName = wasm.allocCString(o.name)), + (o.struct.$zName = wasm.allocCString(o.name)) ); } o.struct.registerVfs(!!o.asDefault); @@ -11953,9 +11640,9 @@ var sqlite3InitModule = (() => { } if (!count) toss( - 'Misuse: installVfs() options object requires at least', - 'one of:', - propList, + "Misuse: installVfs() options object requires at least", + "one of:", + propList ); return this; }; @@ -12000,8 +11687,8 @@ var sqlite3InitModule = (() => { return ptr; } else if (!wasm.isPtr(ptr)) { sqlite3.SQLite3Error.toss( - 'Invalid argument to', - methodName + '()', + "Invalid argument to", + methodName + "()" ); } let rc = this.get(ptr); @@ -12033,9 +11720,9 @@ var sqlite3InitModule = (() => { }); }; - vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab); + vtab.xVtab = StructPtrMapper("xVtab", capi.sqlite3_vtab); - vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor); + vtab.xCursor = StructPtrMapper("xCursor", capi.sqlite3_vtab_cursor); vtab.xIndexInfo = (pIdxInfo) => new capi.sqlite3_index_info(pIdxInfo); @@ -12043,7 +11730,7 @@ var sqlite3InitModule = (() => { if (f.errorReporter instanceof Function) { try { f.errorReporter( - 'sqlite3_module::' + methodName + '(): ' + err.message, + "sqlite3_module::" + methodName + "(): " + err.message ); } catch (e) {} } @@ -12053,9 +11740,9 @@ var sqlite3InitModule = (() => { else if (err instanceof sqlite3.SQLite3Error) rc = err.resultCode; return rc || capi.SQLITE_ERROR; }; - vtab.xError.errorReporter = console.error.bind(console) ; + vtab.xError.errorReporter = console.error.bind(console); - vtab.xRowid = (ppRowid64, value) => wasm.poke(ppRowid64, value, 'i64'); + vtab.xRowid = (ppRowid64, value) => wasm.poke(ppRowid64, value, "i64"); vtab.setupModule = function (opt) { let createdMod = false; @@ -12066,8 +11753,8 @@ var sqlite3InitModule = (() => { try { const methods = opt.methods || toss("Missing 'methods' object."); for (const e of Object.entries({ - xConnect: 'xCreate', - xDisconnect: 'xDestroy', + xConnect: "xCreate", + xDisconnect: "xDestroy", })) { const k = e[0], v = e[1]; @@ -12076,7 +11763,7 @@ var sqlite3InitModule = (() => { } if (opt.catchExceptions) { const fwrap = function (methodName, func) { - if (['xConnect', 'xCreate'].indexOf(methodName) >= 0) { + if (["xConnect", "xCreate"].indexOf(methodName) >= 0) { return function (pDb, pAux, argc, argv, ppVtab, pzErr) { try { return func(...arguments) || 0; @@ -12099,37 +11786,37 @@ var sqlite3InitModule = (() => { } }; const mnames = [ - 'xCreate', - 'xConnect', - 'xBestIndex', - 'xDisconnect', - 'xDestroy', - 'xOpen', - 'xClose', - 'xFilter', - 'xNext', - 'xEof', - 'xColumn', - 'xRowid', - 'xUpdate', - 'xBegin', - 'xSync', - 'xCommit', - 'xRollback', - 'xFindFunction', - 'xRename', - 'xSavepoint', - 'xRelease', - 'xRollbackTo', - 'xShadowName', + "xCreate", + "xConnect", + "xBestIndex", + "xDisconnect", + "xDestroy", + "xOpen", + "xClose", + "xFilter", + "xNext", + "xEof", + "xColumn", + "xRowid", + "xUpdate", + "xBegin", + "xSync", + "xCommit", + "xRollback", + "xFindFunction", + "xRename", + "xSavepoint", + "xRelease", + "xRollbackTo", + "xShadowName", ]; const remethods = Object.create(null); for (const k of mnames) { const m = methods[k]; if (!(m instanceof Function)) continue; - else if ('xConnect' === k && methods.xCreate === m) { + else if ("xConnect" === k && methods.xCreate === m) { remethods[k] = methods.xCreate; - } else if ('xCreate' === k && methods.xConnect === m) { + } else if ("xCreate" === k && methods.xConnect === m) { remethods[k] = methods.xConnect; } else { remethods[k] = fwrap(k, m); @@ -12141,7 +11828,7 @@ var sqlite3InitModule = (() => { } if (0 === mod.$iVersion) { let v; - if ('number' === typeof opt.iVersion) v = opt.iVersion; + if ("number" === typeof opt.iVersion) v = opt.iVersion; else if (mod.$xShadowName) v = 3; else if (mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) v = 2; @@ -12164,17 +11851,17 @@ var sqlite3InitModule = (() => { if (!globalThis.SharedArrayBuffer || !globalThis.Atomics) { return Promise.reject( new Error( - 'Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. ' + - 'The server must emit the COOP/COEP response headers to enable those. ' + - 'See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep', - ), + "Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. " + + "The server must emit the COOP/COEP response headers to enable those. " + + "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep" + ) ); - } else if ('undefined' === typeof WorkerGlobalScope) { + } else if ("undefined" === typeof WorkerGlobalScope) { return Promise.reject( new Error( - 'The OPFS sqlite3_vfs cannot run in the main thread ' + - 'because it requires Atomics.wait().', - ), + "The OPFS sqlite3_vfs cannot run in the main thread " + + "because it requires Atomics.wait()." + ) ); } else if ( !globalThis.FileSystemHandle || @@ -12183,33 +11870,33 @@ var sqlite3InitModule = (() => { !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || !navigator?.storage?.getDirectory ) { - return Promise.reject(new Error('Missing required OPFS APIs.')); + return Promise.reject(new Error("Missing required OPFS APIs.")); } - if (!options || 'object' !== typeof options) { + if (!options || "object" !== typeof options) { options = Object.create(null); } const urlParams = new URL(globalThis.location.href).searchParams; - if (urlParams.has('opfs-disable')) { + if (urlParams.has("opfs-disable")) { return Promise.resolve(sqlite3); } if (undefined === options.verbose) { - options.verbose = urlParams.has('opfs-verbose') - ? +urlParams.get('opfs-verbose') || 2 + options.verbose = urlParams.has("opfs-verbose") + ? +urlParams.get("opfs-verbose") || 2 : 1; } if (undefined === options.sanityChecks) { - options.sanityChecks = urlParams.has('opfs-sanity-check'); + options.sanityChecks = urlParams.has("opfs-sanity-check"); } if (undefined === options.proxyUri) { options.proxyUri = callee.defaultProxyUri; } - if ('function' === typeof options.proxyUri) { + if ("function" === typeof options.proxyUri) { options.proxyUri = options.proxyUri(); } const thePromise = new Promise(function ( promiseResolve_, - promiseReject_, + promiseReject_ ) { const loggers = [ sqlite3.config.error, @@ -12218,7 +11905,7 @@ var sqlite3InitModule = (() => { ]; const logImpl = (level, ...args) => { if (options.verbose > level) - loggers[level]('OPFS syncer:', ...args); + loggers[level]("OPFS syncer:", ...args); }; const log = (...args) => logImpl(2, ...args); const warn = (...args) => logImpl(1, ...args); @@ -12260,18 +11947,18 @@ var sqlite3InitModule = (() => { } sqlite3.config.log( globalThis.location.href, - 'metrics for', + "metrics for", globalThis.location.href, - ':', + ":", metrics, - '\nTotal of', + "\nTotal of", n, - 'op(s) for', + "op(s) for", t, - 'ms (incl. ' + w + ' ms of waiting on the async side)', + "ms (incl. " + w + " ms of waiting on the async side)" ); - sqlite3.config.log('Serialization metrics:', metrics.s11n); - W.postMessage({ type: 'opfs-async-metrics' }); + sqlite3.config.log("Serialization metrics:", metrics.s11n); + W.postMessage({ type: "opfs-async-metrics" }); }, reset: function () { let k; @@ -12288,7 +11975,7 @@ var sqlite3InitModule = (() => { }; const opfsIoMethods = new sqlite3_io_methods(); const opfsVfs = new sqlite3_vfs().addOnDispose(() => - opfsIoMethods.dispose(), + opfsIoMethods.dispose() ); let promiseWasRejected = undefined; const promiseReject = (err) => { @@ -12301,24 +11988,24 @@ var sqlite3InitModule = (() => { return promiseResolve_(sqlite3); }; const W = new Worker( - new URL('sqlite3-opfs-async-proxy.js', import.meta.url), + new URL("sqlite3-opfs-async-proxy.js", import.meta.url) ); setTimeout(() => { if (undefined === promiseWasRejected) { promiseReject( new Error( - 'Timeout while waiting for OPFS async proxy worker.', - ), + "Timeout while waiting for OPFS async proxy worker." + ) ); } }, 4000); W._originalOnError = W.onerror; W.onerror = function (err) { - error('Error initializing OPFS asyncer:', err); + error("Error initializing OPFS asyncer:", err); promiseReject( new Error( - 'Loading OPFS async Worker failed for unknown reasons.', - ), + "Loading OPFS async Worker failed for unknown reasons." + ) ); }; const pDVfs = capi.sqlite3_vfs_find(null); @@ -12327,7 +12014,7 @@ var sqlite3InitModule = (() => { opfsVfs.$iVersion = 2; opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; opfsVfs.$mxPathname = 1024; - opfsVfs.$zName = wasm.allocCString('opfs'); + opfsVfs.$zName = wasm.allocCString("opfs"); opfsVfs.$xDlOpen = opfsVfs.$xDlError = @@ -12335,10 +12022,10 @@ var sqlite3InitModule = (() => { opfsVfs.$xDlClose = null; opfsVfs.addOnDispose( - '$zName', + "$zName", opfsVfs.$zName, - 'cleanup default VFS wrapper', - () => (dVfs ? dVfs.dispose() : null), + "cleanup default VFS wrapper", + () => (dVfs ? dVfs.dispose() : null) ); const state = Object.create(null); @@ -12360,7 +12047,7 @@ var sqlite3InitModule = (() => { state.sabS11nSize = opfsVfs.$mxPathname * 2; state.sabIO = new SharedArrayBuffer( - state.fileBufferSize + state.sabS11nSize, + state.fileBufferSize + state.sabS11nSize ); state.opIds = Object.create(null); const metrics = Object.create(null); @@ -12385,8 +12072,8 @@ var sqlite3InitModule = (() => { state.opIds.xUnlock = i++; state.opIds.xWrite = i++; state.opIds.mkdir = i++; - state.opIds['opfs-async-metrics'] = i++; - state.opIds['opfs-async-shutdown'] = i++; + state.opIds["opfs-async-metrics"] = i++; + state.opIds["opfs-async-shutdown"] = i++; state.opIds.retry = i++; state.sabOP = new SharedArrayBuffer(i * 4); @@ -12395,37 +12082,37 @@ var sqlite3InitModule = (() => { state.sq3Codes = Object.create(null); [ - 'SQLITE_ACCESS_EXISTS', - 'SQLITE_ACCESS_READWRITE', - 'SQLITE_BUSY', - 'SQLITE_CANTOPEN', - 'SQLITE_ERROR', - 'SQLITE_IOERR', - 'SQLITE_IOERR_ACCESS', - 'SQLITE_IOERR_CLOSE', - 'SQLITE_IOERR_DELETE', - 'SQLITE_IOERR_FSYNC', - 'SQLITE_IOERR_LOCK', - 'SQLITE_IOERR_READ', - 'SQLITE_IOERR_SHORT_READ', - 'SQLITE_IOERR_TRUNCATE', - 'SQLITE_IOERR_UNLOCK', - 'SQLITE_IOERR_WRITE', - 'SQLITE_LOCK_EXCLUSIVE', - 'SQLITE_LOCK_NONE', - 'SQLITE_LOCK_PENDING', - 'SQLITE_LOCK_RESERVED', - 'SQLITE_LOCK_SHARED', - 'SQLITE_LOCKED', - 'SQLITE_MISUSE', - 'SQLITE_NOTFOUND', - 'SQLITE_OPEN_CREATE', - 'SQLITE_OPEN_DELETEONCLOSE', - 'SQLITE_OPEN_MAIN_DB', - 'SQLITE_OPEN_READONLY', + "SQLITE_ACCESS_EXISTS", + "SQLITE_ACCESS_READWRITE", + "SQLITE_BUSY", + "SQLITE_CANTOPEN", + "SQLITE_ERROR", + "SQLITE_IOERR", + "SQLITE_IOERR_ACCESS", + "SQLITE_IOERR_CLOSE", + "SQLITE_IOERR_DELETE", + "SQLITE_IOERR_FSYNC", + "SQLITE_IOERR_LOCK", + "SQLITE_IOERR_READ", + "SQLITE_IOERR_SHORT_READ", + "SQLITE_IOERR_TRUNCATE", + "SQLITE_IOERR_UNLOCK", + "SQLITE_IOERR_WRITE", + "SQLITE_LOCK_EXCLUSIVE", + "SQLITE_LOCK_NONE", + "SQLITE_LOCK_PENDING", + "SQLITE_LOCK_RESERVED", + "SQLITE_LOCK_SHARED", + "SQLITE_LOCKED", + "SQLITE_MISUSE", + "SQLITE_NOTFOUND", + "SQLITE_OPEN_CREATE", + "SQLITE_OPEN_DELETEONCLOSE", + "SQLITE_OPEN_MAIN_DB", + "SQLITE_OPEN_READONLY", ].forEach((k) => { if (undefined === (state.sq3Codes[k] = capi[k])) { - toss('Maintenance required: not found:', k); + toss("Maintenance required: not found:", k); } }); state.opfsFlags = Object.assign(Object.create(null), { @@ -12437,14 +12124,14 @@ var sqlite3InitModule = (() => { }); const opRun = (op, ...args) => { - const opNdx = state.opIds[op] || toss('Invalid op ID:', op); + const opNdx = state.opIds[op] || toss("Invalid op ID:", op); state.s11n.serialize(...args); Atomics.store(state.sabOPView, state.opIds.rc, -1); Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); Atomics.notify(state.sabOPView, state.opIds.whichOp); const t = performance.now(); while ( - 'not-equal' !== + "not-equal" !== Atomics.wait(state.sabOPView, state.opIds.rc, -1) ) {} @@ -12452,7 +12139,7 @@ var sqlite3InitModule = (() => { metrics[op].wait += performance.now() - t; if (rc && state.asyncS11nExceptions) { const err = state.s11n.deserialize(); - if (err) error(op + '() async error:', ...err); + if (err) error(op + "() async error:", ...err); } return rc; }; @@ -12460,31 +12147,31 @@ var sqlite3InitModule = (() => { opfsUtil.debug = { asyncShutdown: () => { warn( - 'Shutting down OPFS async listener. The OPFS VFS will no longer work.', + "Shutting down OPFS async listener. The OPFS VFS will no longer work." ); - opRun('opfs-async-shutdown'); + opRun("opfs-async-shutdown"); }, asyncRestart: () => { warn( - 'Attempting to restart OPFS VFS async listener. Might work, might not.', + "Attempting to restart OPFS VFS async listener. Might work, might not." ); - W.postMessage({ type: 'opfs-async-restart' }); + W.postMessage({ type: "opfs-async-restart" }); }, }; const initS11n = () => { if (state.s11n) return state.s11n; const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder('utf-8'), + textEncoder = new TextEncoder("utf-8"), viewU8 = new Uint8Array( state.sabIO, state.sabS11nOffset, - state.sabS11nSize, + state.sabS11nSize ), viewDV = new DataView( state.sabIO, state.sabS11nOffset, - state.sabS11nSize, + state.sabS11nSize ); state.s11n = Object.create(null); @@ -12492,28 +12179,28 @@ var sqlite3InitModule = (() => { TypeIds.number = { id: 1, size: 8, - getter: 'getFloat64', - setter: 'setFloat64', + getter: "getFloat64", + setter: "setFloat64", }; TypeIds.bigint = { id: 2, size: 8, - getter: 'getBigInt64', - setter: 'setBigInt64', + getter: "getBigInt64", + setter: "setBigInt64", }; TypeIds.boolean = { id: 3, size: 4, - getter: 'getInt32', - setter: 'setInt32', + getter: "getInt32", + setter: "setInt32", }; TypeIds.string = { id: 4 }; const getTypeId = (v) => TypeIds[typeof v] || toss( - 'Maintenance required: this value type cannot be serialized.', - v, + "Maintenance required: this value type cannot be serialized.", + v ); const getTypeIdById = (tid) => { switch (tid) { @@ -12526,7 +12213,7 @@ var sqlite3InitModule = (() => { case TypeIds.string.id: return TypeIds.string; default: - toss('Invalid type ID:', tid); + toss("Invalid type ID:", tid); } }; @@ -12600,9 +12287,9 @@ var sqlite3InitModule = (() => { const randomFilename = function f(len = 16) { if (!f._chars) { f._chars = - 'abcdefghijklmnopqrstuvwxyz' + - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + - '012346789'; + "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "012346789"; f._n = f._chars.length; } const a = []; @@ -12611,7 +12298,7 @@ var sqlite3InitModule = (() => { const ndx = (Math.random() * (f._n * 64)) % f._n | 0; a[i] = f._chars[ndx]; } - return a.join(''); + return a.join(""); }; const __openFiles = Object.create(null); @@ -12630,17 +12317,17 @@ var sqlite3InitModule = (() => { const ioSyncWrappers = { xCheckReservedLock: function (pFile, pOut) { { - wasm.poke(pOut, 0, 'i32'); + wasm.poke(pOut, 0, "i32"); } return 0; }, xClose: function (pFile) { - mTimeStart('xClose'); + mTimeStart("xClose"); let rc = 0; const f = __openFiles[pFile]; if (f) { delete __openFiles[pFile]; - rc = opRun('xClose', pFile); + rc = opRun("xClose", pFile); if (f.sq3File) f.sq3File.dispose(); } mTimeEnd(); @@ -12653,14 +12340,14 @@ var sqlite3InitModule = (() => { return capi.SQLITE_NOTFOUND; }, xFileSize: function (pFile, pSz64) { - mTimeStart('xFileSize'); - let rc = opRun('xFileSize', pFile); + mTimeStart("xFileSize"); + let rc = opRun("xFileSize", pFile); if (0 == rc) { try { const sz = state.s11n.deserialize()[0]; - wasm.poke(pSz64, sz, 'i64'); + wasm.poke(pSz64, sz, "i64"); } catch (e) { - error('Unexpected error reading xFileSize() result:', e); + error("Unexpected error reading xFileSize() result:", e); rc = state.sq3Codes.SQLITE_IOERR; } } @@ -12668,12 +12355,12 @@ var sqlite3InitModule = (() => { return rc; }, xLock: function (pFile, lockType) { - mTimeStart('xLock'); + mTimeStart("xLock"); const f = __openFiles[pFile]; let rc = 0; if (!f.lockType) { - rc = opRun('xLock', pFile, lockType); + rc = opRun("xLock", pFile, lockType); if (0 === rc) f.lockType = lockType; } else { f.lockType = lockType; @@ -12682,54 +12369,54 @@ var sqlite3InitModule = (() => { return rc; }, xRead: function (pFile, pDest, n, offset64) { - mTimeStart('xRead'); + mTimeStart("xRead"); const f = __openFiles[pFile]; let rc; try { - rc = opRun('xRead', pFile, n, Number(offset64)); + rc = opRun("xRead", pFile, n, Number(offset64)); if (0 === rc || capi.SQLITE_IOERR_SHORT_READ === rc) { wasm.heap8u().set(f.sabView.subarray(0, n), pDest); } } catch (e) { - error('xRead(', arguments, ') failed:', e, f); + error("xRead(", arguments, ") failed:", e, f); rc = capi.SQLITE_IOERR_READ; } mTimeEnd(); return rc; }, xSync: function (pFile, flags) { - mTimeStart('xSync'); + mTimeStart("xSync"); ++metrics.xSync.count; - const rc = opRun('xSync', pFile, flags); + const rc = opRun("xSync", pFile, flags); mTimeEnd(); return rc; }, xTruncate: function (pFile, sz64) { - mTimeStart('xTruncate'); - const rc = opRun('xTruncate', pFile, Number(sz64)); + mTimeStart("xTruncate"); + const rc = opRun("xTruncate", pFile, Number(sz64)); mTimeEnd(); return rc; }, xUnlock: function (pFile, lockType) { - mTimeStart('xUnlock'); + mTimeStart("xUnlock"); const f = __openFiles[pFile]; let rc = 0; if (capi.SQLITE_LOCK_NONE === lockType && f.lockType) { - rc = opRun('xUnlock', pFile, lockType); + rc = opRun("xUnlock", pFile, lockType); } if (0 === rc) f.lockType = lockType; mTimeEnd(); return rc; }, xWrite: function (pFile, pSrc, n, offset64) { - mTimeStart('xWrite'); + mTimeStart("xWrite"); const f = __openFiles[pFile]; let rc; try { f.sabView.set(wasm.heap8u().subarray(pSrc, pSrc + n)); - rc = opRun('xWrite', pFile, n, Number(offset64)); + rc = opRun("xWrite", pFile, n, Number(offset64)); } catch (e) { - error('xWrite(', arguments, ') failed:', e, f); + error("xWrite(", arguments, ") failed:", e, f); rc = capi.SQLITE_IOERR_WRITE; } mTimeEnd(); @@ -12739,9 +12426,9 @@ var sqlite3InitModule = (() => { const vfsSyncWrappers = { xAccess: function (pVfs, zName, flags, pOut) { - mTimeStart('xAccess'); - const rc = opRun('xAccess', wasm.cstrToJs(zName)); - wasm.poke(pOut, rc ? 0 : 1, 'i32'); + mTimeStart("xAccess"); + const rc = opRun("xAccess", wasm.cstrToJs(zName)); + wasm.poke(pOut, rc ? 0 : 1, "i32"); mTimeEnd(); return 0; }, @@ -12749,7 +12436,7 @@ var sqlite3InitModule = (() => { wasm.poke( pOut, 2440587.5 + new Date().getTime() / 86400000, - 'double', + "double" ); return 0; }, @@ -12757,17 +12444,17 @@ var sqlite3InitModule = (() => { wasm.poke( pOut, 2440587.5 * 86400000 + new Date().getTime(), - 'i64', + "i64" ); return 0; }, xDelete: function (pVfs, zName, doSyncDir) { - mTimeStart('xDelete'); + mTimeStart("xDelete"); const rc = opRun( - 'xDelete', + "xDelete", wasm.cstrToJs(zName), doSyncDir, - false, + false ); mTimeEnd(); return rc; @@ -12777,21 +12464,21 @@ var sqlite3InitModule = (() => { return i < nOut ? 0 : capi.SQLITE_CANTOPEN; }, xGetLastError: function (pVfs, nOut, pOut) { - warn('OPFS xGetLastError() has nothing sensible to return.'); + warn("OPFS xGetLastError() has nothing sensible to return."); return 0; }, xOpen: function f(pVfs, zName, pFile, flags, pOutFlags) { - mTimeStart('xOpen'); + mTimeStart("xOpen"); let opfsFlags = 0; if (0 === zName) { zName = randomFilename(); } else if (wasm.isPtr(zName)) { - if (capi.sqlite3_uri_boolean(zName, 'opfs-unlock-asap', 0)) { + if (capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)) { opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP; } if ( - capi.sqlite3_uri_boolean(zName, 'delete-before-open', 0) + capi.sqlite3_uri_boolean(zName, "delete-before-open", 0) ) { opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN; } @@ -12802,10 +12489,10 @@ var sqlite3InitModule = (() => { fh.filename = zName; fh.sab = new SharedArrayBuffer(state.fileBufferSize); fh.flags = flags; - const rc = opRun('xOpen', pFile, zName, flags, opfsFlags); + const rc = opRun("xOpen", pFile, zName, flags, opfsFlags); if (!rc) { if (fh.readOnly) { - wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, 'i32'); + wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, "i32"); } __openFiles[pFile] = fh; fh.sabView = state.sabFileBufView; @@ -12839,13 +12526,13 @@ var sqlite3InitModule = (() => { } opfsUtil.getResolvedPath = function (filename, splitIt) { - const p = new URL(filename, 'file://irrelevant').pathname; - return splitIt ? p.split('/').filter((v) => !!v) : p; + const p = new URL(filename, "file://irrelevant").pathname; + return splitIt ? p.split("/").filter((v) => !!v) : p; }; opfsUtil.getDirForFilename = async function f( absFilename, - createDirs = false, + createDirs = false ) { const path = opfsUtil.getResolvedPath(absFilename, true); const filename = path.pop(); @@ -12863,8 +12550,8 @@ var sqlite3InitModule = (() => { opfsUtil.mkdir = async function (absDirName) { try { await opfsUtil.getDirForFilename( - absDirName + '/filepart', - true, + absDirName + "/filepart", + true ); return true; } catch (e) { @@ -12890,7 +12577,7 @@ var sqlite3InitModule = (() => { tgt.dirs = []; tgt.files = []; for await (const handle of dirHandle.values()) { - if ('directory' === handle.kind) { + if ("directory" === handle.kind) { const subDir = Object.create(null); tgt.dirs.push(subDir); await callee(handle, subDir); @@ -12915,24 +12602,24 @@ var sqlite3InitModule = (() => { opfsUtil.unlink = async function ( fsEntryName, recursive = false, - throwOnError = false, + throwOnError = false ) { try { const [hDir, filenamePart] = await opfsUtil.getDirForFilename( fsEntryName, - false, + false ); await hDir.removeEntry(filenamePart, { recursive }); return true; } catch (e) { if (throwOnError) { throw new Error( - 'unlink(', + "unlink(", arguments[0], - ') failed: ' + e.message, + ") failed: " + e.message, { cause: e, - }, + } ); } return false; @@ -12944,7 +12631,7 @@ var sqlite3InitModule = (() => { recursive: true, directory: opfsUtil.rootDirectory, }; - if ('function' === typeof opt) { + if ("function" === typeof opt) { opt = { callback: opt }; } opt = Object.assign(defaultOpt, opt || {}); @@ -12952,7 +12639,7 @@ var sqlite3InitModule = (() => { for await (const handle of dirHandle.values()) { if (false === opt.callback(handle, dirHandle, depth)) return false; - else if (opt.recursive && 'directory' === handle.kind) { + else if (opt.recursive && "directory" === handle.kind) { if (false === (await callee(handle, depth + 1))) break; } } @@ -12963,7 +12650,7 @@ var sqlite3InitModule = (() => { const importDbChunked = async function (filename, callback) { const [hDir, fnamePart] = await opfsUtil.getDirForFilename( filename, - true, + true ); const hFile = await hDir.getFileHandle(fnamePart, { create: true, @@ -12986,9 +12673,9 @@ var sqlite3InitModule = (() => { } if (nWrote < 512 || 0 !== nWrote % 512) { toss( - 'Input size', + "Input size", nWrote, - 'is not correct for an SQLite database.', + "is not correct for an SQLite database." ); } if (!checkedHeader) { @@ -13017,7 +12704,7 @@ var sqlite3InitModule = (() => { const n = bytes.byteLength; const [hDir, fnamePart] = await opfsUtil.getDirForFilename( filename, - true, + true ); let sah, nWrote = 0; @@ -13030,11 +12717,11 @@ var sqlite3InitModule = (() => { nWrote = sah.write(bytes, { at: 0 }); if (nWrote != n) { toss( - 'Expected to write ' + + "Expected to write " + n + - ' bytes but wrote ' + + " bytes but wrote " + nWrote + - '.', + "." ); } sah.write(new Uint8Array([1, 1]), { at: 18 }); @@ -13067,15 +12754,15 @@ var sqlite3InitModule = (() => { sqlite3.capi.sqlite3_exec( oo1Db, [ - 'pragma journal_mode=DELETE;', + "pragma journal_mode=DELETE;", - 'pragma cache_size=-16384;', + "pragma cache_size=-16384;", ], 0, 0, - 0, + 0 ); - }, + } ); } @@ -13089,70 +12776,70 @@ var sqlite3InitModule = (() => { capi.SQLITE_OPEN_READWRITE | capi.SQLITE_OPEN_MAIN_DB; const pOut = wasm.scopedAlloc(8); - const dbFile = '/sanity/check/file' + randomFilename(8); + const dbFile = "/sanity/check/file" + randomFilename(8); const zDbFile = wasm.scopedAllocCString(dbFile); let rc; - state.s11n.serialize('This is ä string.'); + state.s11n.serialize("This is ä string."); rc = state.s11n.deserialize(); - log('deserialize() says:', rc); - if ('This is ä string.' !== rc[0]) toss('String d13n error.'); + log("deserialize() says:", rc); + if ("This is ä string." !== rc[0]) toss("String d13n error."); vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, 'i32'); - log('xAccess(', dbFile, ') exists ?=', rc); + rc = wasm.peek(pOut, "i32"); + log("xAccess(", dbFile, ") exists ?=", rc); rc = vfsSyncWrappers.xOpen( opfsVfs.pointer, zDbFile, fid, openFlags, - pOut, + pOut ); log( - 'open rc =', + "open rc =", rc, - 'state.sabOPView[xOpen] =', - state.sabOPView[state.opIds.xOpen], + "state.sabOPView[xOpen] =", + state.sabOPView[state.opIds.xOpen] ); if (0 !== rc) { - error('open failed with code', rc); + error("open failed with code", rc); return; } vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, 'i32'); - if (!rc) toss('xAccess() failed to detect file.'); + rc = wasm.peek(pOut, "i32"); + if (!rc) toss("xAccess() failed to detect file."); rc = ioSyncWrappers.xSync(sq3File.pointer, 0); - if (rc) toss('sync failed w/ rc', rc); + if (rc) toss("sync failed w/ rc", rc); rc = ioSyncWrappers.xTruncate(sq3File.pointer, 1024); - if (rc) toss('truncate failed w/ rc', rc); - wasm.poke(pOut, 0, 'i64'); + if (rc) toss("truncate failed w/ rc", rc); + wasm.poke(pOut, 0, "i64"); rc = ioSyncWrappers.xFileSize(sq3File.pointer, pOut); - if (rc) toss('xFileSize failed w/ rc', rc); - log('xFileSize says:', wasm.peek(pOut, 'i64')); + if (rc) toss("xFileSize failed w/ rc", rc); + log("xFileSize says:", wasm.peek(pOut, "i64")); rc = ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1); - if (rc) toss('xWrite() failed!'); + if (rc) toss("xWrite() failed!"); const readBuf = wasm.scopedAlloc(16); rc = ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); wasm.poke(readBuf + 6, 0); let jRead = wasm.cstrToJs(readBuf); - log('xRead() got:', jRead); - if ('sanity' !== jRead) toss('Unexpected xRead() value.'); + log("xRead() got:", jRead); + if ("sanity" !== jRead) toss("Unexpected xRead() value."); if (vfsSyncWrappers.xSleep) { - log('xSleep()ing before close()ing...'); + log("xSleep()ing before close()ing..."); vfsSyncWrappers.xSleep(opfsVfs.pointer, 2000); - log('waking up from xSleep()'); + log("waking up from xSleep()"); } rc = ioSyncWrappers.xClose(fid); - log('xClose rc =', rc, 'sabOPView =', state.sabOPView); - log('Deleting file:', dbFile); + log("xClose rc =", rc, "sabOPView =", state.sabOPView); + log("Deleting file:", dbFile); vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234); vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, 'i32'); + rc = wasm.peek(pOut, "i32"); if (rc) toss( - 'Expecting 0 from xAccess(', + "Expecting 0 from xAccess(", dbFile, - ') after xDelete().', + ") after xDelete()." ); - warn('End of OPFS sanity checks.'); + warn("End of OPFS sanity checks."); } finally { sq3File.dispose(); wasm.scopedAllocPop(scope); @@ -13161,13 +12848,13 @@ var sqlite3InitModule = (() => { W.onmessage = function ({ data }) { switch (data.type) { - case 'opfs-unavailable': - promiseReject(new Error(data.payload.join(' '))); + case "opfs-unavailable": + promiseReject(new Error(data.payload.join(" "))); break; - case 'opfs-async-loaded': - W.postMessage({ type: 'opfs-async-init', args: state }); + case "opfs-async-loaded": + W.postMessage({ type: "opfs-async-init", args: state }); break; - case 'opfs-async-inited': { + case "opfs-async-inited": { if (true === promiseWasRejected) { break; } @@ -13180,17 +12867,17 @@ var sqlite3InitModule = (() => { state.sabFileBufView = new Uint8Array( state.sabIO, 0, - state.fileBufferSize, + state.fileBufferSize ); state.sabS11nView = new Uint8Array( state.sabIO, state.sabS11nOffset, - state.sabS11nSize, + state.sabS11nSize ); initS11n(); if (options.sanityChecks) { warn( - 'Running sanity checks because of opfs-sanity-check URL arg...', + "Running sanity checks because of opfs-sanity-check URL arg..." ); sanityCheck(); } @@ -13202,7 +12889,7 @@ var sqlite3InitModule = (() => { delete W._originalOnError; sqlite3.opfs = opfsUtil; opfsUtil.rootDirectory = d; - log('End of OPFS sqlite3_vfs setup.', opfsVfs); + log("End of OPFS sqlite3_vfs setup.", opfsVfs); promiseResolve(); }) .catch(promiseReject); @@ -13217,7 +12904,7 @@ var sqlite3InitModule = (() => { } default: { const errMsg = - 'Unexpected message from the OPFS async worker: ' + + "Unexpected message from the OPFS async worker: " + JSON.stringify(data); error(errMsg); promiseReject(new Error(errMsg)); @@ -13228,7 +12915,7 @@ var sqlite3InitModule = (() => { }); return thePromise; }; - installOpfsVfs.defaultProxyUri = 'sqlite3-opfs-async-proxy.js'; + installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; globalThis.sqlite3ApiBootstrap.initializersAsync.push( async (sqlite3) => { try { @@ -13239,15 +12926,15 @@ var sqlite3InitModule = (() => { } return installOpfsVfs().catch((e) => { sqlite3.config.warn( - 'Ignoring inability to install OPFS sqlite3_vfs:', - e.message, + "Ignoring inability to install OPFS sqlite3_vfs:", + e.message ); }); } catch (e) { - sqlite3.config.error('installOpfsVfs() exception:', e); + sqlite3.config.error("installOpfsVfs() exception:", e); return Promise.reject(e); } - }, + } ); }); @@ -13274,7 +12961,7 @@ var sqlite3InitModule = (() => { capi.SQLITE_OPEN_SUPER_JOURNAL | capi.SQLITE_OPEN_WAL; - const OPAQUE_DIR_NAME = '.opaque'; + const OPAQUE_DIR_NAME = ".opaque"; const getRandomName = () => Math.random().toString(36).slice(2); @@ -13282,7 +12969,7 @@ var sqlite3InitModule = (() => { const textEncoder = new TextEncoder(); const optionDefaults = Object.assign(Object.create(null), { - name: 'opfs-sahpool', + name: "opfs-sahpool", directory: undefined, initialCapacity: 6, clearOnInit: false, @@ -13316,7 +13003,7 @@ var sqlite3InitModule = (() => { const ioMethods = { xCheckReservedLock: function (pFile, pOut) { const pool = getPoolForPFile(pFile); - pool.log('xCheckReservedLock'); + pool.log("xCheckReservedLock"); pool.storeErr(); wasm.poke32(pOut, 1); return 0; @@ -13370,7 +13057,7 @@ var sqlite3InitModule = (() => { try { const nRead = file.sah.read( wasm.heap8u().subarray(pDest, pDest + n), - { at: HEADER_OFFSET_DATA + Number(offset64) }, + { at: HEADER_OFFSET_DATA + Number(offset64) } ); if (nRead < n) { wasm.heap8u().fill(0, pDest + nRead, pDest + n); @@ -13412,7 +13099,7 @@ var sqlite3InitModule = (() => { }, xUnlock: function (pFile, lockType) { const pool = getPoolForPFile(pFile); - pool.log('xUnlock'); + pool.log("xUnlock"); const file = pool.getOFileForS3File(pFile); file.lockType = lockType; return 0; @@ -13425,9 +13112,9 @@ var sqlite3InitModule = (() => { try { const nBytes = file.sah.write( wasm.heap8u().subarray(pSrc, pSrc + n), - { at: HEADER_OFFSET_DATA + Number(offset64) }, + { at: HEADER_OFFSET_DATA + Number(offset64) } ); - return n === nBytes ? 0 : toss('Unknown write() failure.'); + return n === nBytes ? 0 : toss("Unknown write() failure."); } catch (e) { return pool.storeErr(e, capi.SQLITE_IOERR); } @@ -13456,12 +13143,12 @@ var sqlite3InitModule = (() => { wasm.poke( pOut, 2440587.5 + new Date().getTime() / 86400000, - 'double', + "double" ); return 0; }, xCurrentTimeInt64: function (pVfs, pOut) { - wasm.poke(pOut, 2440587.5 * 86400000 + new Date().getTime(), 'i64'); + wasm.poke(pOut, 2440587.5 * 86400000 + new Date().getTime(), "i64"); return 0; }, xDelete: function (pVfs, zName, doSyncDir) { @@ -13514,11 +13201,11 @@ var sqlite3InitModule = (() => { sah = pool.nextAvailableSAH(); pool.setAssociatedPath(sah, path, flags); } else { - toss('SAH pool is full. Cannot create file', path); + toss("SAH pool is full. Cannot create file", path); } } if (!sah) { - toss('file not found:', path); + toss("file not found:", path); } const file = { path, flags, sah }; @@ -13538,7 +13225,7 @@ var sqlite3InitModule = (() => { const createOpfsVfs = function (vfsName) { if (sqlite3.capi.sqlite3_vfs_find(vfsName)) { - toss3('VFS name is already registered:', vfsName); + toss3("VFS name is already registered:", vfsName); } const opfsVfs = new capi.sqlite3_vfs(); @@ -13549,7 +13236,7 @@ var sqlite3InitModule = (() => { opfsVfs.$mxPathname = HEADER_MAX_PATH_SIZE; opfsVfs.addOnDispose( (opfsVfs.$zName = wasm.allocCString(vfsName)), - () => setPoolForVfs(opfsVfs.pointer, 0), + () => setPoolForVfs(opfsVfs.pointer, 0) ); if (dVfs) { @@ -13605,26 +13292,26 @@ var sqlite3InitModule = (() => { this.vfsName = options.name || optionDefaults.name; this.#cVfs = createOpfsVfs(this.vfsName); setPoolForVfs(this.#cVfs.pointer, this); - this.vfsDir = options.directory || '.' + this.vfsName; + this.vfsDir = options.directory || "." + this.vfsName; this.#dvBody = new DataView( this.#apBody.buffer, - this.#apBody.byteOffset, + this.#apBody.byteOffset ); this.isReady = this.reset( - !!(options.clearOnInit ?? optionDefaults.clearOnInit), + !!(options.clearOnInit ?? optionDefaults.clearOnInit) ).then(() => { if (this.$error) throw this.$error; return this.getCapacity() ? Promise.resolve(undefined) : this.addCapacity( - options.initialCapacity || optionDefaults.initialCapacity, + options.initialCapacity || optionDefaults.initialCapacity ); }); } #logImpl(level, ...args) { if (this.#verbosity > level) - loggers[level](this.vfsName + ':', ...args); + loggers[level](this.vfsName + ":", ...args); } log(...args) { this.#logImpl(2, ...args); @@ -13663,7 +13350,7 @@ var sqlite3InitModule = (() => { }); const ah = await h.createSyncAccessHandle(); this.#mapSAHToName.set(ah, name); - this.setAssociatedPath(ah, '', 0); + this.setAssociatedPath(ah, "", 0); } return this.getCapacity(); } @@ -13695,7 +13382,7 @@ var sqlite3InitModule = (() => { async acquireAccessHandles(clearFiles) { const files = []; for await (const [name, h] of this.#dhOpaque) { - if ('file' === h.kind) { + if ("file" === h.kind) { files.push([name, h]); } } @@ -13706,7 +13393,7 @@ var sqlite3InitModule = (() => { this.#mapSAHToName.set(ah, name); if (clearFiles) { ah.truncate(HEADER_OFFSET_DATA); - this.setAssociatedPath(ah, '', 0); + this.setAssociatedPath(ah, "", 0); } else { const path = this.getAssociatedPath(ah); if (path) { @@ -13720,7 +13407,7 @@ var sqlite3InitModule = (() => { this.releaseAccessHandles(); throw e; } - }), + }) ); } @@ -13735,10 +13422,10 @@ var sqlite3InitModule = (() => { ) { warn( `Removing file with unexpected flags ${flags.toString(16)}`, - this.#apBody, + this.#apBody ); - this.setAssociatedPath(sah, '', 0); - return ''; + this.setAssociatedPath(sah, "", 0); + return ""; } const fileDigest = new Uint32Array(HEADER_DIGEST_SIZE / 4); @@ -13751,18 +13438,18 @@ var sqlite3InitModule = (() => { } return pathBytes ? textDecoder.decode(this.#apBody.subarray(0, pathBytes)) - : ''; + : ""; } else { - warn('Disassociating file with bad digest.'); - this.setAssociatedPath(sah, '', 0); - return ''; + warn("Disassociating file with bad digest."); + this.setAssociatedPath(sah, "", 0); + return ""; } } setAssociatedPath(sah, path, flags) { const enc = textEncoder.encodeInto(path, this.#apBody); if (HEADER_MAX_PATH_SIZE <= enc.written + 1) { - toss('Path too long:', path); + toss("Path too long:", path); } this.#apBody.fill(0, enc.written, HEADER_MAX_PATH_SIZE); this.#dvBody.setUint32(HEADER_OFFSET_FLAGS, flags); @@ -13795,7 +13482,7 @@ var sqlite3InitModule = (() => { await this.isReady; let h = await navigator.storage.getDirectory(); let prev; - for (const d of this.vfsDir.split('/')) { + for (const d of this.vfsDir.split("/")) { if (d) { prev = h; h = await h.getDirectoryHandle(d, { create: true }); @@ -13805,7 +13492,7 @@ var sqlite3InitModule = (() => { this.#dhVfsParent = prev; this.#dhOpaque = await this.#dhVfsRoot.getDirectoryHandle( OPAQUE_DIR_NAME, - { create: true }, + { create: true } ); this.releaseAccessHandles(); return this.acquireAccessHandles(clearFiles); @@ -13814,7 +13501,7 @@ var sqlite3InitModule = (() => { getPath(arg) { if (wasm.isPtr(arg)) arg = wasm.cstrToJs(arg); return ( - arg instanceof URL ? arg : new URL(arg, 'file://localhost/') + arg instanceof URL ? arg : new URL(arg, "file://localhost/") ).pathname; } @@ -13822,7 +13509,7 @@ var sqlite3InitModule = (() => { const sah = this.#mapFilenameToSAH.get(path); if (sah) { this.#mapFilenameToSAH.delete(path); - this.setAssociatedPath(sah, '', 0); + this.setAssociatedPath(sah, "", 0); } return !!sah; } @@ -13884,21 +13571,21 @@ var sqlite3InitModule = (() => { }); this.#dhVfsRoot = this.#dhVfsParent = undefined; } catch (e) { - sqlite3.config.error(this.vfsName, 'removeVfs() failed:', e); + sqlite3.config.error(this.vfsName, "removeVfs() failed:", e); } return true; } exportFile(name) { const sah = - this.#mapFilenameToSAH.get(name) || toss('File not found:', name); + this.#mapFilenameToSAH.get(name) || toss("File not found:", name); const n = sah.getSize() - HEADER_OFFSET_DATA; const b = new Uint8Array(n > 0 ? n : 0); if (n > 0) { const nRead = sah.read(b, { at: HEADER_OFFSET_DATA }); if (nRead != n) { toss( - 'Expected to read ' + n + ' bytes but read ' + nRead + '.', + "Expected to read " + n + " bytes but read " + nRead + "." ); } } @@ -13909,7 +13596,7 @@ var sqlite3InitModule = (() => { const sah = this.#mapFilenameToSAH.get(name) || this.nextAvailableSAH() || - toss('No available handles to import to.'); + toss("No available handles to import to."); sah.truncate(0); let nWrote = 0, chunk, @@ -13926,9 +13613,9 @@ var sqlite3InitModule = (() => { } if (nWrote < 512 || 0 !== nWrote % 512) { toss( - 'Input size', + "Input size", nWrote, - 'is not correct for an SQLite database.', + "is not correct for an SQLite database." ); } if (!checkedHeader) { @@ -13940,7 +13627,7 @@ var sqlite3InitModule = (() => { at: HEADER_OFFSET_DATA + 18, }); } catch (e) { - this.setAssociatedPath(sah, '', 0); + this.setAssociatedPath(sah, "", 0); throw e; } this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB); @@ -13954,22 +13641,22 @@ var sqlite3InitModule = (() => { const sah = this.#mapFilenameToSAH.get(name) || this.nextAvailableSAH() || - toss('No available handles to import to.'); + toss("No available handles to import to."); const n = bytes.byteLength; if (n < 512 || n % 512 != 0) { - toss('Byte array size is invalid for an SQLite db.'); + toss("Byte array size is invalid for an SQLite db."); } - const header = 'SQLite format 3'; + const header = "SQLite format 3"; for (let i = 0; i < header.length; ++i) { if (header.charCodeAt(i) !== bytes[i]) { - toss('Input does not contain an SQLite database header.'); + toss("Input does not contain an SQLite database header."); } } const nWrote = sah.write(bytes, { at: HEADER_OFFSET_DATA }); if (nWrote != n) { - this.setAssociatedPath(sah, '', 0); + this.setAssociatedPath(sah, "", 0); toss( - 'Expected to write ' + n + ' bytes but wrote ' + nWrote + '.', + "Expected to write " + n + " bytes but wrote " + nWrote + "." ); } else { sah.write(new Uint8Array([1, 1]), { @@ -14036,7 +13723,7 @@ var sqlite3InitModule = (() => { const apiVersionCheck = async () => { const dh = await navigator.storage.getDirectory(); - const fn = '.opfs-sahpool-sync-check-' + getRandomName(); + const fn = ".opfs-sahpool-sync-check-" + getRandomName(); const fh = await dh.getFileHandle(fn, { create: true }); const ah = await fh.createSyncAccessHandle(); const close = ah.close(); @@ -14044,15 +13731,15 @@ var sqlite3InitModule = (() => { await dh.removeEntry(fn); if (close?.then) { toss( - 'The local OPFS API is too old for opfs-sahpool:', - 'it has an async FileSystemSyncAccessHandle.close() method.', + "The local OPFS API is too old for opfs-sahpool:", + "it has an async FileSystemSyncAccessHandle.close() method." ); } return true; }; sqlite3.installOpfsSAHPoolVfs = async function ( - options = Object.create(null), + options = Object.create(null) ) { const vfsName = options.name || optionDefaults.name; if (initPromises[vfsName]) { @@ -14066,7 +13753,7 @@ var sqlite3InitModule = (() => { !navigator?.storage?.getDirectory ) { return (initPromises[vfsName] = Promise.reject( - new Error('Missing required OPFS APIs.'), + new Error("Missing required OPFS APIs.") )); } @@ -14096,17 +13783,17 @@ var sqlite3InitModule = (() => { sqlite3.capi.sqlite3_exec( oo1Db, [ - 'pragma journal_mode=DELETE;', - 'pragma cache_size=-16384;', + "pragma journal_mode=DELETE;", + "pragma cache_size=-16384;", ], 0, 0, - 0, + 0 ); - }, + } ); } - thePool.log('VFS initialized.'); + thePool.log("VFS initialized."); return poolUtil; }) .catch(async (e) => { @@ -14119,15 +13806,15 @@ var sqlite3InitModule = (() => { })); }; }); - if ('undefined' !== typeof Module) { + if ("undefined" !== typeof Module) { const SABC = Object.assign( Object.create(null), { exports: - 'undefined' === typeof wasmExports ? Module['asm'] : wasmExports, + "undefined" === typeof wasmExports ? Module["asm"] : wasmExports, memory: Module.wasmMemory, }, - globalThis.sqlite3ApiConfig || {}, + globalThis.sqlite3ApiConfig || {} ); globalThis.sqlite3ApiConfig = SABC; @@ -14135,7 +13822,7 @@ var sqlite3InitModule = (() => { try { sqlite3 = globalThis.sqlite3ApiBootstrap(); } catch (e) { - console.error('sqlite3ApiBootstrap() error:', e); + console.error("sqlite3ApiBootstrap() error:", e); throw e; } finally { delete globalThis.sqlite3ApiBootstrap; @@ -14145,10 +13832,10 @@ var sqlite3InitModule = (() => { Module.sqlite3 = sqlite3; } else { console.warn( - 'This is not running in an Emscripten module context, so', - 'globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack', - 'of config info for the WASM environment.', - 'It must be called manually.', + "This is not running in an Emscripten module context, so", + "globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack", + "of config info for the WASM environment.", + "It must be called manually." ); } }); @@ -14161,7 +13848,7 @@ const toExportForESM = (function () { const originalInit = sqlite3InitModule; if (!originalInit) { throw new Error( - 'Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build.', + "Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build." ); } @@ -14169,26 +13856,26 @@ const toExportForESM = (function () { Object.create(null), { moduleScript: globalThis?.document?.currentScript, - isWorker: 'undefined' !== typeof WorkerGlobalScope, + isWorker: "undefined" !== typeof WorkerGlobalScope, location: globalThis.location, urlParams: globalThis?.location?.href ? new URL(globalThis.location.href).searchParams : new URLSearchParams(), - }, + } )); initModuleState.debugModule = initModuleState.urlParams.has( - 'sqlite3.debugModule', + "sqlite3.debugModule" ) - ? (...args) => console.warn('sqlite3.debugModule:', ...args) + ? (...args) => console.warn("sqlite3.debugModule:", ...args) : () => {}; - if (initModuleState.urlParams.has('sqlite3.dir')) { + if (initModuleState.urlParams.has("sqlite3.dir")) { initModuleState.sqlite3Dir = - initModuleState.urlParams.get('sqlite3.dir') + '/'; + initModuleState.urlParams.get("sqlite3.dir") + "/"; } else if (initModuleState.moduleScript) { - const li = initModuleState.moduleScript.src.split('/'); + const li = initModuleState.moduleScript.src.split("/"); li.pop(); - initModuleState.sqlite3Dir = li.join('/') + '/'; + initModuleState.sqlite3Dir = li.join("/") + "/"; } globalThis.sqlite3InitModule = function ff(...args) { @@ -14203,7 +13890,7 @@ const toExportForESM = (function () { return f(); }) .catch((e) => { - console.error('Exception loading sqlite3 module:', e); + console.error("Exception loading sqlite3 module:", e); throw e; }); }; @@ -14211,11 +13898,11 @@ const toExportForESM = (function () { if (globalThis.sqlite3InitModuleState.moduleScript) { const sim = globalThis.sqlite3InitModuleState; - let src = sim.moduleScript.src.split('/'); + let src = sim.moduleScript.src.split("/"); src.pop(); - sim.scriptDir = src.join('/') + '/'; + sim.scriptDir = src.join("/") + "/"; } - initModuleState.debugModule('sqlite3InitModuleState =', initModuleState); + initModuleState.debugModule("sqlite3InitModuleState =", initModuleState); return globalThis.sqlite3InitModule; })(); sqlite3InitModule = toExportForESM; @@ -14246,9 +13933,9 @@ var sqlite3InitModule$1 = sqlite3InitModule; */ globalThis.sqlite3Worker1Promiser = function callee( - config = callee.defaultConfig, + config = callee.defaultConfig ) { - if (1 === arguments.length && 'function' === typeof arguments[0]) { + if (1 === arguments.length && "function" === typeof arguments[0]) { const f = config; config = Object.assign(Object.create(null), callee.defaultConfig); config.onready = f; @@ -14264,22 +13951,22 @@ globalThis.sqlite3Worker1Promiser = function callee( config.generateMessageId || function (msg) { return ( - msg.type + '#' + (idTypeMap[msg.type] = (idTypeMap[msg.type] || 0) + 1) + msg.type + "#" + (idTypeMap[msg.type] = (idTypeMap[msg.type] || 0) + 1) ); }; const toss = (...args) => { - throw new Error(args.join(' ')); + throw new Error(args.join(" ")); }; if (!config.worker) config.worker = callee.defaultConfig.worker; - if ('function' === typeof config.worker) config.worker = config.worker(); + if ("function" === typeof config.worker) config.worker = config.worker(); let dbId; let promiserFunc; config.worker.onmessage = function (ev) { ev = ev.data; - debug('worker1.onmessage', ev); + debug("worker1.onmessage", ev); let msgHandler = handlerMap[ev.messageId]; if (!msgHandler) { - if (ev && 'sqlite3-api' === ev.type && 'worker1-ready' === ev.result) { + if (ev && "sqlite3-api" === ev.type && "worker1-ready" === ev.result) { if (config.onready) config.onready(promiserFunc); return; } @@ -14289,18 +13976,18 @@ globalThis.sqlite3Worker1Promiser = function callee( return; } if (config.onunhandled) config.onunhandled(arguments[0]); - else err('sqlite3Worker1Promiser() unhandled worker message:', ev); + else err("sqlite3Worker1Promiser() unhandled worker message:", ev); return; } delete handlerMap[ev.messageId]; switch (ev.type) { - case 'error': + case "error": msgHandler.reject(ev); return; - case 'open': + case "open": if (!dbId) dbId = ev.dbId; break; - case 'close': + case "close": if (ev.dbId === dbId) dbId = undefined; break; } @@ -14320,23 +14007,23 @@ globalThis.sqlite3Worker1Promiser = function callee( msg.args = arguments[1]; msg.dbId = msg.args.dbId; } else { - toss('Invalid arguments for sqlite3Worker1Promiser()-created factory.'); + toss("Invalid arguments for sqlite3Worker1Promiser()-created factory."); } - if (!msg.dbId && msg.type !== 'open') msg.dbId = dbId; + if (!msg.dbId && msg.type !== "open") msg.dbId = dbId; msg.messageId = genMsgId(msg); msg.departureTime = performance.now(); const proxy = Object.create(null); proxy.message = msg; let rowCallbackId; - if ('exec' === msg.type && msg.args) { - if ('function' === typeof msg.args.callback) { - rowCallbackId = msg.messageId + ':row'; + if ("exec" === msg.type && msg.args) { + if ("function" === typeof msg.args.callback) { + rowCallbackId = msg.messageId + ":row"; proxy.onrow = msg.args.callback; msg.args.callback = rowCallbackId; handlerMap[rowCallbackId] = proxy; - } else if ('string' === typeof msg.args.callback) { + } else if ("string" === typeof msg.args.callback) { toss( - 'exec callback may not be a string when using the Promise interface.', + "exec callback may not be a string when using the Promise interface." ); } } @@ -14346,10 +14033,10 @@ globalThis.sqlite3Worker1Promiser = function callee( proxy.reject = reject; handlerMap[msg.messageId] = proxy; debug( - 'Posting', + "Posting", msg.type, - 'message to Worker dbId=' + (dbId || 'default') + ':', - msg, + "message to Worker dbId=" + (dbId || "default") + ":", + msg ); config.worker.postMessage(msg); }); @@ -14361,21 +14048,21 @@ globalThis.sqlite3Worker1Promiser = function callee( globalThis.sqlite3Worker1Promiser.defaultConfig = { worker: function () { return new Worker( - new URL('sqlite3-worker1-bundler-friendly.mjs', import.meta.url), + new URL("sqlite3-worker1-bundler-friendly.mjs", import.meta.url), { - type: 'module', - }, + type: "module", + } ); }, - onerror: (...args) => console.error('worker1 promiser error', ...args), + onerror: (...args) => console.error("worker1 promiser error", ...args), }; sqlite3Worker1Promiser.v2 = function (config) { let oldFunc; - if ('function' == typeof config) { + if ("function" == typeof config) { oldFunc = config; config = {}; - } else if ('function' === typeof config?.onready) { + } else if ("function" === typeof config?.onready) { oldFunc = config.onready; delete config.onready; } @@ -14422,7 +14109,7 @@ class SQLite { constructor(sqlite3) { if (typeof sqlite3 === "undefined") { throw new Error( - "`sqliteObject` must be defined before calling constructor", + "`sqliteObject` must be defined before calling constructor" ); } this.sqlite3 = sqlite3; @@ -14608,7 +14295,7 @@ class SQLite { nByte, prepFlags, ppStmt, - pzTail, + pzTail ); } @@ -14652,7 +14339,7 @@ class SQLite { pApp, xFunc, xStep, - xFinal, + xFinal ) { try { this.sqlite3.capi.sqlite3_create_function( @@ -14663,7 +14350,7 @@ class SQLite { pApp, // pApp is ignored xFunc, xStep, - xFinal, + xFinal ); console.log("create function"); } catch (error) { @@ -14703,9 +14390,9 @@ class SQLite { log(`Created trigger for ${table_name}`); log(row); log(`------------------------------------`); - }, + } ); - }, + } ); } catch (error) { console.log("error creating diesel trigger"); From c7f4b0a5af000d5403ffc09f60e74b18d2f7478b Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Fri, 13 Sep 2024 17:56:45 -0400 Subject: [PATCH 32/97] passing tests --- .../src/connection/serialized_database.rs | 2 -- .../src/js/wa-sqlite-diesel-bundle.js | 24 +++++++++++++++---- diesel-wasm-sqlite/tests/test/web.rs | 9 ++++++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/diesel-wasm-sqlite/src/connection/serialized_database.rs b/diesel-wasm-sqlite/src/connection/serialized_database.rs index 491abf9b1..16584945f 100644 --- a/diesel-wasm-sqlite/src/connection/serialized_database.rs +++ b/diesel-wasm-sqlite/src/connection/serialized_database.rs @@ -1,5 +1,3 @@ -use crate::ffi; - /// `SerializedDatabase` is a wrapper for a serialized database that is dynamically allocated by calling `sqlite3_serialize`. /// This RAII wrapper is necessary to deallocate the memory when it goes out of scope with `sqlite3_free`. #[derive(Debug)] diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js index 824fef44e..6b8085551 100644 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js @@ -14404,11 +14404,27 @@ class SQLite { return this.sqlite3.capi.sqlite3_value_free(value); } - /* - serialize(database, zSchema, size, flags) { - return this.module._sqlite3_serialize(database, zSchema, size, flags); + sqlite3_serialize(database, zSchema, size, flags) { + return this.sqlite3.capi.sqlite3_serialize(database, zSchema, size, flags); + } + + sqlite3_deserialize( + database, + z_schema, + p_data, + sz_database, + sz_buffer, + m_flags + ) { + return this.sqlite3.capi.sqlite3_deserialize( + database, + z_schema, + p_data, + sz_database, + sz_buffer, + m_flags + ); } - */ } export { SQLite, SQLiteError }; diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index 8440e7577..d68992e38 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -262,5 +262,12 @@ async fn serializing() { let loaded_books = schema::books::dsl::books .select(StoredBook::as_select()) .load(&mut conn); - assert_eq!(loaded_books.unwrap().len(), 1); + assert_eq!( + loaded_books.unwrap(), + vec![StoredBook { + id: 1, + title: "Game of Thrones".into(), + author: Some("George R.R".into()), + },] + ); } From 4541a21d21802e3273b6054d2c64394546918bd3 Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Fri, 13 Sep 2024 18:13:10 -0400 Subject: [PATCH 33/97] working on freeing the value --- diesel-wasm-sqlite/package.js | 4 ++-- diesel-wasm-sqlite/src/connection/raw.rs | 10 ++-------- .../src/connection/serialized_database.rs | 14 ++++++++++---- diesel-wasm-sqlite/src/ffi.rs | 11 +++-------- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index ccd06dad3..6212022ba 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -308,7 +308,7 @@ export class SQLite { } value_free(value) { - return this.sqlite3.capi.sqlite3_value_free(value); + return this.sqlite3.capi.value_free(value); } sqlite3_serialize(database, z_schema, p_size, m_flags) { @@ -348,7 +348,7 @@ export class SQLite { } } - sqlite3_free(database, arg1) { + sqlite3_free(_database, arg1) { try { this.sqlite3.capi.sqlite3_free(arg1); } catch (error) { diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs index 3a4dc5550..d4839122a 100755 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -101,14 +101,8 @@ impl RawConnection { panic!("Serialization failed"); } - let len = p_size.as_f64().unwrap() as usize; - let mut data = vec![0; len as usize]; - - unsafe { - ffi::raw_copy_from_sqlite(data_ptr, len as u32, data.as_mut_slice()); - } - - SerializedDatabase { data } + let len = p_size.as_f64().unwrap() as u32; + unsafe { SerializedDatabase::new(data_ptr, len) } } /// Deserializes the database from the data slice given to be loaded diff --git a/diesel-wasm-sqlite/src/connection/serialized_database.rs b/diesel-wasm-sqlite/src/connection/serialized_database.rs index 16584945f..2ad82b1b1 100644 --- a/diesel-wasm-sqlite/src/connection/serialized_database.rs +++ b/diesel-wasm-sqlite/src/connection/serialized_database.rs @@ -1,3 +1,5 @@ +use crate::ffi; + /// `SerializedDatabase` is a wrapper for a serialized database that is dynamically allocated by calling `sqlite3_serialize`. /// This RAII wrapper is necessary to deallocate the memory when it goes out of scope with `sqlite3_free`. #[derive(Debug)] @@ -5,9 +7,13 @@ pub struct SerializedDatabase { pub data: Vec, } -impl Drop for SerializedDatabase { - /// Deallocates the memory of the serialized database when it goes out of scope. - fn drop(&mut self) { - // ffi::sqlite3_free(self.data as _); +impl SerializedDatabase { + pub(crate) unsafe fn new(data_ptr: *mut u8, len: u32) -> Self { + let mut data = vec![0; len as usize]; + ffi::raw_copy_from_sqlite(data_ptr, len, data.as_mut_slice()); + + crate::get_sqlite_unchecked().value_free(data_ptr); + + Self { data } } } diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index ea8940eec..a55967930 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -251,6 +251,9 @@ extern "C" { #[wasm_bindgen(method)] pub fn value_double(this: &SQLite, pValue: *mut u8) -> f64; + #[wasm_bindgen(method)] + pub fn value_free(this: &SQLite, pValue: *mut u8); + #[wasm_bindgen(method)] pub fn value_int(this: &SQLite, pValue: *mut u8) -> i32; @@ -327,9 +330,6 @@ extern "C" { #[wasm_bindgen(method, catch)] pub fn register_diesel_sql_functions(this: &SQLite, database: &JsValue) -> Result<(), JsValue>; - #[wasm_bindgen(method)] - pub fn value_free(this: &SQLite, value: *mut u8); - #[wasm_bindgen(method)] pub fn sqlite3_serialize( this: &SQLite, @@ -350,8 +350,3 @@ extern "C" { m_flags: u32, ) -> i32; } - -#[wasm_bindgen] -extern "C" { - pub fn sqlite3_free(arg1: *mut u8); -} From b2403e5f4dc7a678fb8677d0503cff048125665c Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Mon, 16 Sep 2024 09:14:53 -0400 Subject: [PATCH 34/97] cleanup --- diesel-wasm-sqlite/src/connection/raw.rs | 2 -- diesel-wasm-sqlite/src/connection/serialized_database.rs | 2 -- diesel-wasm-sqlite/src/ffi.rs | 5 ----- diesel-wasm-sqlite/tests/test/web.rs | 3 --- 4 files changed, 12 deletions(-) diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs index d4839122a..4e614a586 100755 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ b/diesel-wasm-sqlite/src/connection/raw.rs @@ -3,8 +3,6 @@ use crate::{ffi, WasmSqlite, WasmSqliteError}; use diesel::{result::*, sql_types::HasSqlType}; -use js_sys::Uint8Array; -use serde::Serialize; use wasm_bindgen::{closure::Closure, JsValue}; use super::serialized_database::SerializedDatabase; diff --git a/diesel-wasm-sqlite/src/connection/serialized_database.rs b/diesel-wasm-sqlite/src/connection/serialized_database.rs index 2ad82b1b1..e9914a702 100644 --- a/diesel-wasm-sqlite/src/connection/serialized_database.rs +++ b/diesel-wasm-sqlite/src/connection/serialized_database.rs @@ -12,8 +12,6 @@ impl SerializedDatabase { let mut data = vec![0; len as usize]; ffi::raw_copy_from_sqlite(data_ptr, len, data.as_mut_slice()); - crate::get_sqlite_unchecked().value_free(data_ptr); - Self { data } } } diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index a55967930..86382e428 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -84,11 +84,6 @@ pub unsafe fn raw_copy_from_sqlite(src: *mut u8, len: u32, buf: &mut [u8]) { let mem = wasm.heap8u(); mem.slice(src as u32, src as u32 + len) .raw_copy_to_ptr(buf.as_mut_ptr()); - //let offset = (src as u32) / std::mem::size_of::() as u32; - //// this is safe because we view the slice and immediately copy it into - //// our memory. - //let view = Uint8Array::new_with_byte_offset_and_length(&mem, offset, len); - //view.raw_copy_to_ptr(buf.as_mut_ptr()) } pub async fn init_sqlite() { diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index d68992e38..29ccfa4f0 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -227,14 +227,11 @@ async fn can_insert_or_ignore() { #[wasm_bindgen_test] async fn serializing() { - use schema::test_table::dsl::*; - init().await; let mut conn = establish_connection().await; let new_books = vec![BookForm { title: "Game of Thrones".into(), author: Some("George R.R".into()), - // published_year: NaiveDate::from_ymd_opt(2015, 5, 3).unwrap(), }]; let rows_changed = insert_books(&mut conn, new_books).unwrap(); assert_eq!(rows_changed, 1); From a11e1865e3c0f89a92b8d662f7bf4306fb1e2d30 Mon Sep 17 00:00:00 2001 From: Dakota Brink Date: Mon, 16 Sep 2024 09:55:46 -0400 Subject: [PATCH 35/97] free memory after serialization --- .../src/connection/serialized_database.rs | 2 ++ diesel-wasm-sqlite/src/connection/sqlite_value.rs | 11 ++++------- diesel-wasm-sqlite/src/ffi.rs | 3 +++ diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js | 4 ++++ diesel-wasm-sqlite/tests/test/web.rs | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/diesel-wasm-sqlite/src/connection/serialized_database.rs b/diesel-wasm-sqlite/src/connection/serialized_database.rs index e9914a702..876b37ebc 100644 --- a/diesel-wasm-sqlite/src/connection/serialized_database.rs +++ b/diesel-wasm-sqlite/src/connection/serialized_database.rs @@ -12,6 +12,8 @@ impl SerializedDatabase { let mut data = vec![0; len as usize]; ffi::raw_copy_from_sqlite(data_ptr, len, data.as_mut_slice()); + crate::get_sqlite_unchecked().sqlite3_free(data_ptr); + Self { data } } } diff --git a/diesel-wasm-sqlite/src/connection/sqlite_value.rs b/diesel-wasm-sqlite/src/connection/sqlite_value.rs index 2772d954d..9ecfc131f 100644 --- a/diesel-wasm-sqlite/src/connection/sqlite_value.rs +++ b/diesel-wasm-sqlite/src/connection/sqlite_value.rs @@ -56,10 +56,9 @@ impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { ) -> Option> { let value = match &*row { PrivateSqliteRow::Direct(stmt) => stmt.column_value(col_idx), - PrivateSqliteRow::Duplicated { values, .. } => values - .get(col_idx as usize) - .and_then(|v| v.as_ref())? - .value + PrivateSqliteRow::Duplicated { values, .. } => { + values.get(col_idx as usize).and_then(|v| v.as_ref())?.value + } }; let ret = Self { @@ -177,8 +176,6 @@ impl OwnedSqliteValue { pub(super) fn duplicate(&self) -> OwnedSqliteValue { let sqlite3 = crate::get_sqlite_unchecked(); let value = sqlite3.value_dup(self.value); - OwnedSqliteValue { - value - } + OwnedSqliteValue { value } } } diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 86382e428..db00076c1 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -249,6 +249,9 @@ extern "C" { #[wasm_bindgen(method)] pub fn value_free(this: &SQLite, pValue: *mut u8); + #[wasm_bindgen(method)] + pub fn sqlite3_free(this: &SQLite, pValue: *mut u8); + #[wasm_bindgen(method)] pub fn value_int(this: &SQLite, pValue: *mut u8) -> i32; diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js index 6b8085551..349b332bc 100644 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js @@ -14404,6 +14404,10 @@ class SQLite { return this.sqlite3.capi.sqlite3_value_free(value); } + sqlite3_free(value) { + return this.sqlite3.capi.sqlite3_free(value); + } + sqlite3_serialize(database, zSchema, size, flags) { return this.sqlite3.capi.sqlite3_serialize(database, zSchema, size, flags); } diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index 29ccfa4f0..8d469027d 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -47,7 +47,7 @@ pub struct StoredBook { // published_year: NaiveDateTime, } -pub async fn establish_connection() -> WasmSqliteConnection { +async fn establish_connection() -> WasmSqliteConnection { diesel_wasm_sqlite::init_sqlite().await; let rng: u16 = rand::random(); From 9a5cd7a5667147d23ecf7973ebf18365ba863092 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 20 Sep 2024 16:39:09 -0400 Subject: [PATCH 36/97] Dont use r2d2 for WebAssembly (#1065) * create interface for native/wasm EncryptedMessageStore * create interface for spawning tasks onto the global executor in native/wasm * fix some bugs with diesel backend --- Cargo.lock | 2 + Cargo.toml | 2 + bindings_ffi/Cargo.lock | 2 + bindings_ffi/src/mls.rs | 99 +- bindings_node/Cargo.lock | 2 + bindings_node/build.rs | 2 +- bindings_node/rustfmt.toml | 2 - bindings_node/src/conversations.rs | 378 +- bindings_node/src/encoded_content.rs | 84 +- bindings_node/src/groups.rs | 1141 +-- bindings_node/src/lib.rs | 22 +- bindings_node/src/messages.rs | 118 +- bindings_node/src/mls_client.rs | 495 +- bindings_node/src/permissions.rs | 238 +- bindings_node/src/streams.rs | 103 +- bindings_wasm/src/mls_client.rs | 3 + bindings_wasm/tests/web.rs | 2 +- dev/bench | 2 +- dev/flamegraph | 8 +- dev/lint | 5 +- dev/lint-rust | 10 +- dev/up | 6 +- diesel-wasm-sqlite/package.js | 37 +- diesel-wasm-sqlite/src/connection/mod.rs | 2 +- diesel-wasm-sqlite/src/connection/stmt.rs | 20 +- .../src/js/sqlite3-opfs-async-proxy.js | 200 +- .../src/js/wa-sqlite-diesel-bundle.js | 6578 +++++++++-------- diesel-wasm-sqlite/tests/test/row.rs | 72 - diesel-wasm-sqlite/tests/test/web.rs | 9 - examples/cli/cli-client.rs | 8 +- xmtp_api_http/src/lib.rs | 4 + xmtp_id/Cargo.toml | 2 +- xmtp_id/src/associations/association_log.rs | 2 - xmtp_id/src/associations/mod.rs | 2 +- xmtp_id/src/associations/signature.rs | 1 - xmtp_id/src/lib.rs | 3 +- xmtp_mls/Cargo.toml | 3 +- xmtp_mls/src/api/test_utils.rs | 2 +- xmtp_mls/src/bin/update-schema.rs | 8 +- xmtp_mls/src/builder.rs | 22 +- xmtp_mls/src/client.rs | 6 +- xmtp_mls/src/groups/mod.rs | 60 +- xmtp_mls/src/groups/subscriptions.rs | 20 +- xmtp_mls/src/groups/sync.rs | 4 +- xmtp_mls/src/identity.rs | 2 +- xmtp_mls/src/lib.rs | 27 +- xmtp_mls/src/retry.rs | 20 +- .../encrypted_store/association_state.rs | 5 +- .../storage/encrypted_store/consent_record.rs | 13 +- .../storage/encrypted_store/db_connection.rs | 56 +- xmtp_mls/src/storage/encrypted_store/group.rs | 37 +- .../storage/encrypted_store/group_intent.rs | 35 +- .../storage/encrypted_store/group_message.rs | 30 +- .../src/storage/encrypted_store/identity.rs | 5 +- .../encrypted_store/identity_update.rs | 24 +- xmtp_mls/src/storage/encrypted_store/mod.rs | 566 +- .../src/storage/encrypted_store/native.rs | 190 + .../storage/encrypted_store/refresh_state.rs | 25 +- .../encrypted_store/sqlcipher_connection.rs | 17 +- xmtp_mls/src/storage/encrypted_store/wasm.rs | 68 + xmtp_mls/src/storage/sql_key_store.rs | 29 +- xmtp_mls/src/stream_handles.rs | 255 + xmtp_mls/src/subscriptions.rs | 74 +- xmtp_mls/src/utils/hash.rs | 5 - xmtp_mls/src/utils/id.rs | 21 - xmtp_mls/src/utils/mod.rs | 44 +- xmtp_mls/src/utils/test.rs | 11 +- xmtp_mls/src/utils/time.rs | 11 - xmtp_mls/src/xmtp_openmls_provider.rs | 28 +- 69 files changed, 6067 insertions(+), 5322 deletions(-) delete mode 100644 bindings_node/rustfmt.toml create mode 100644 xmtp_mls/src/storage/encrypted_store/native.rs create mode 100644 xmtp_mls/src/storage/encrypted_store/wasm.rs create mode 100644 xmtp_mls/src/stream_handles.rs delete mode 100644 xmtp_mls/src/utils/hash.rs delete mode 100644 xmtp_mls/src/utils/id.rs delete mode 100644 xmtp_mls/src/utils/time.rs diff --git a/Cargo.lock b/Cargo.lock index 387cba172..90ea51282 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6497,7 +6497,9 @@ dependencies = [ "tracing-test", "tracing-wasm", "trait-variant", + "wasm-bindgen-futures", "wasm-bindgen-test", + "wasm-timer", "xmtp_api_grpc", "xmtp_api_http", "xmtp_cryptography", diff --git a/Cargo.toml b/Cargo.toml index b5ef439af..b5cb763b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ async-stream = "0.3" async-trait = "0.1.77" trait-variant = "0.1.2" chrono = "0.4.38" +wasm-timer = "0.2" ctor = "0.2" ed25519 = "2.2.3" ed25519-dalek = "2.1.1" @@ -66,6 +67,7 @@ diesel = { version = "2.2", default-features = false } diesel-wasm-sqlite = "0.0.1" diesel_migrations = { version = "2.2", default-features = false } wasm-bindgen-test = "0.3.42" +wasm-bindgen-futures = "0.4" gloo-timers = "0.3" # Internal Crate Dependencies diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 661420c93..6c73f6999 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -5920,6 +5920,8 @@ dependencies = [ "tokio-stream", "tracing", "trait-variant", + "wasm-bindgen-futures", + "wasm-timer", "xmtp_api_grpc", "xmtp_cryptography", "xmtp_id", diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 9402de395..b7a0003e4 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -5,7 +5,7 @@ use crate::GenericError; use std::collections::HashMap; use std::convert::TryInto; use std::sync::Arc; -use tokio::{sync::Mutex, task::AbortHandle}; +use tokio::sync::Mutex; use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_id::associations::unverified::UnverifiedSignature; use xmtp_id::associations::AccountId; @@ -16,28 +16,21 @@ use xmtp_id::{ associations::{builder::SignatureRequest, generate_inbox_id as xmtp_id_generate_inbox_id}, InboxId, }; -use xmtp_mls::groups::group_mutable_metadata::MetadataField; -use xmtp_mls::groups::group_permissions::BasePolicies; -use xmtp_mls::groups::group_permissions::GroupMutablePermissionsError; -use xmtp_mls::groups::group_permissions::MembershipPolicies; -use xmtp_mls::groups::group_permissions::MetadataBasePolicies; -use xmtp_mls::groups::group_permissions::MetadataPolicies; -use xmtp_mls::groups::group_permissions::PermissionsBasePolicies; -use xmtp_mls::groups::group_permissions::PermissionsPolicies; -use xmtp_mls::groups::group_permissions::PolicySet; -use xmtp_mls::groups::intents::PermissionPolicyOption; -use xmtp_mls::groups::intents::PermissionUpdateType; -use xmtp_mls::groups::GroupMetadataOptions; use xmtp_mls::{ api::ApiClientWrapper, builder::ClientBuilder, - client::Client as MlsClient, - client::ClientError, + client::{Client as MlsClient, ClientError}, groups::{ group_metadata::{ConversationType, GroupMetadata}, - group_permissions::GroupMutablePermissions, + group_mutable_metadata::MetadataField, + group_permissions::{ + BasePolicies, GroupMutablePermissions, GroupMutablePermissionsError, + MembershipPolicies, MetadataBasePolicies, MetadataPolicies, PermissionsBasePolicies, + PermissionsPolicies, PolicySet, + }, + intents::{PermissionPolicyOption, PermissionUpdateType}, members::PermissionLevel, - MlsGroup, PreconfiguredPolicies, UpdateAdminListType, + GroupMetadataOptions, MlsGroup, PreconfiguredPolicies, UpdateAdminListType, }, identity::IdentityStrategy, retry::Retry, @@ -45,7 +38,7 @@ use xmtp_mls::{ group_message::{DeliveryStatus, GroupMessageKind, StoredGroupMessage}, EncryptedMessageStore, EncryptionKey, StorageOption, }, - subscriptions::StreamHandle, + AbortHandle, GenericStreamHandle, StreamHandle, }; pub type RustXmtpClient = MlsClient; @@ -108,9 +101,9 @@ pub async fn create_client( let key: EncryptionKey = key .try_into() .map_err(|_| "Malformed 32 byte encryption key".to_string())?; - EncryptedMessageStore::new(storage_option, key)? + EncryptedMessageStore::new(storage_option, key).await? } - None => EncryptedMessageStore::new_unencrypted(storage_option)?, + None => EncryptedMessageStore::new_unencrypted(storage_option).await?, }; log::info!("Creating XMTP client"); let identity_strategy = IdentityStrategy::CreateIfNotFound( @@ -1431,27 +1424,22 @@ impl From for FfiMessage { } } -#[derive(uniffi::Object, Clone, Debug)] +type FfiHandle = Box>>; + +#[derive(uniffi::Object, Clone)] pub struct FfiStreamCloser { - #[allow(clippy::type_complexity)] - stream_handle: Arc>>>>, + stream_handle: Arc>>, // for convenience, does not require locking mutex. - abort_handle: Arc, + abort_handle: Arc>, } impl FfiStreamCloser { - pub fn new(stream_handle: StreamHandle>) -> Self { + pub fn new( + stream_handle: impl StreamHandle> + Send + Sync + 'static, + ) -> Self { Self { - abort_handle: Arc::new(stream_handle.handle.abort_handle()), - stream_handle: Arc::new(Mutex::new(Some(stream_handle))), - } - } - - #[cfg(test)] - pub async fn wait_for_ready(&self) { - let mut handle = self.stream_handle.lock().await; - if let Some(ref mut h) = &mut *handle { - h.wait_for_ready().await; + abort_handle: Arc::new(stream_handle.abort_handle()), + stream_handle: Arc::new(Mutex::new(Some(Box::new(stream_handle)))), } } } @@ -1461,28 +1449,28 @@ impl FfiStreamCloser { /// Signal the stream to end /// Does not wait for the stream to end. pub fn end(&self) { - self.abort_handle.abort(); + self.abort_handle.end(); } /// End the stream and asyncronously wait for it to shutdown pub async fn end_and_wait(&self) -> Result<(), GenericError> { + use xmtp_mls::StreamHandleError::*; + use GenericError::Generic; + if self.abort_handle.is_finished() { return Ok(()); } let mut stream_handle = self.stream_handle.lock().await; let stream_handle = stream_handle.take(); - if let Some(h) = stream_handle { - h.handle.abort(); - match h.handle.await { - Err(e) if !e.is_cancelled() => Err(GenericError::Generic { - err: format!("subscription event loop join error {}", e), - }), - Err(e) if e.is_cancelled() => Ok(()), - Ok(t) => t.map_err(|e| GenericError::Generic { err: e.to_string() }), - Err(e) => Err(GenericError::Generic { + if let Some(mut h) = stream_handle { + match h.end_and_wait().await { + Err(Cancelled) => Ok(()), + Err(Panicked(msg)) => Err(Generic { err: msg }), + Err(e) => Err(Generic { err: format!("error joining task {}", e), }), + Ok(t) => t.map_err(|e| Generic { err: e.to_string() }), } } else { log::warn!("subscription already closed"); @@ -1493,6 +1481,13 @@ impl FfiStreamCloser { pub fn is_closed(&self) -> bool { self.abort_handle.is_finished() } + + pub async fn wait_for_ready(&self) { + let mut stream_handle = self.stream_handle.lock().await; + if let Some(ref mut h) = *stream_handle { + h.wait_for_ready().await; + } + } } #[uniffi::export(callback_interface)] @@ -1577,12 +1572,10 @@ mod tests { FfiPermissionUpdateType, }; use ethers::utils::hex; - use std:: - sync::{ - atomic::{AtomicU32, Ordering}, - Arc, Mutex, - } - ; + use std::sync::{ + atomic::{AtomicU32, Ordering}, + Arc, Mutex, + }; use tokio::{sync::Notify, time::error::Elapsed}; use xmtp_cryptography::{signature::RecoverableSignature, utils::rng}; use xmtp_id::associations::{ @@ -1649,7 +1642,7 @@ mod tests { } pub async fn wait_for_delivery(&self) -> Result<(), Elapsed> { - tokio::time::timeout(std::time::Duration::from_secs(60), async { + tokio::time::timeout(core::time::Duration::from_secs(60), async { self.notify.notified().await }) .await?; @@ -1679,7 +1672,7 @@ mod tests { self.notify.notify_one(); } } - + fn static_enc_key() -> EncryptionKey { [2u8; 32] } diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index 92bf17c13..b20dd466a 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -5425,6 +5425,8 @@ dependencies = [ "tokio-stream", "tracing", "trait-variant", + "wasm-bindgen-futures", + "wasm-timer", "xmtp_cryptography", "xmtp_id", "xmtp_proto", diff --git a/bindings_node/build.rs b/bindings_node/build.rs index 1f866b6a3..9fc236788 100644 --- a/bindings_node/build.rs +++ b/bindings_node/build.rs @@ -1,5 +1,5 @@ extern crate napi_build; fn main() { - napi_build::setup(); + napi_build::setup(); } diff --git a/bindings_node/rustfmt.toml b/bindings_node/rustfmt.toml deleted file mode 100644 index cab5731ed..000000000 --- a/bindings_node/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -tab_spaces = 2 -edition = "2021" diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index 3928c36f0..6ec253d79 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -14,214 +14,212 @@ use crate::{groups::NapiGroup, mls_client::RustXmtpClient, streams::NapiStreamCl #[napi(object)] pub struct NapiListConversationsOptions { - pub created_after_ns: Option, - pub created_before_ns: Option, - pub limit: Option, + pub created_after_ns: Option, + pub created_before_ns: Option, + pub limit: Option, } #[napi(object)] #[derive(Clone)] pub struct NapiCreateGroupOptions { - pub permissions: Option, - pub group_name: Option, - pub group_image_url_square: Option, - pub group_description: Option, - pub group_pinned_frame_url: Option, + pub permissions: Option, + pub group_name: Option, + pub group_image_url_square: Option, + pub group_description: Option, + pub group_pinned_frame_url: Option, } impl NapiCreateGroupOptions { - pub fn into_group_metadata_options(self) -> GroupMetadataOptions { - GroupMetadataOptions { - name: self.group_name, - image_url_square: self.group_image_url_square, - description: self.group_description, - pinned_frame_url: self.group_pinned_frame_url, + pub fn into_group_metadata_options(self) -> GroupMetadataOptions { + GroupMetadataOptions { + name: self.group_name, + image_url_square: self.group_image_url_square, + description: self.group_description, + pinned_frame_url: self.group_pinned_frame_url, + } } - } } #[napi] pub struct NapiConversations { - inner_client: Arc, + inner_client: Arc, } #[napi] impl NapiConversations { - pub fn new(inner_client: Arc) -> Self { - Self { inner_client } - } - - #[napi] - pub async fn create_group( - &self, - account_addresses: Vec, - options: Option, - ) -> Result { - let options = match options { - Some(options) => options, - None => NapiCreateGroupOptions { - permissions: None, - group_name: None, - group_image_url_square: None, - group_description: None, - group_pinned_frame_url: None, - }, - }; - - let group_permissions = match options.permissions { - Some(NapiGroupPermissionsOptions::AllMembers) => { - Some(PreconfiguredPolicies::AllMembers.to_policy_set()) - } - Some(NapiGroupPermissionsOptions::AdminOnly) => { - Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()) - } - _ => None, - }; - - let metadata_options = options.clone().into_group_metadata_options(); - - let convo = if account_addresses.is_empty() { - self - .inner_client - .create_group(group_permissions, metadata_options) - .map_err(|e| Error::from_reason(format!("ClientError: {}", e)))? - } else { - self - .inner_client - .create_group_with_members(account_addresses, group_permissions, metadata_options) - .await - .map_err(|e| Error::from_reason(format!("ClientError: {}", e)))? - }; - - let out = NapiGroup::new( - self.inner_client.clone(), - convo.group_id, - convo.created_at_ns, - ); - - Ok(out) - } - - #[napi] - pub fn find_group_by_id(&self, group_id: String) -> Result { - let group_id = hex::decode(group_id).map_err(|e| Error::from_reason(format!("{}", e)))?; - - let group = self - .inner_client - .group(group_id) - .map_err(|e| Error::from_reason(format!("{}", e)))?; - - Ok(NapiGroup::new( - self.inner_client.clone(), - group.group_id, - group.created_at_ns, - )) - } - - #[napi] - pub fn find_message_by_id(&self, message_id: String) -> Result { - let message_id = hex::decode(message_id).map_err(|e| Error::from_reason(format!("{}", e)))?; - - let message = self - .inner_client - .message(message_id) - .map_err(|e| Error::from_reason(format!("{}", e)))?; - - Ok(NapiMessage::from(message)) - } - - #[napi] - pub async fn process_streamed_welcome_message( - &self, - envelope_bytes: Uint8Array, - ) -> Result { - let envelope_bytes = envelope_bytes.deref().to_vec(); - let group = self - .inner_client - .process_streamed_welcome_message(envelope_bytes) - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?; - let out = NapiGroup::new( - self.inner_client.clone(), - group.group_id, - group.created_at_ns, - ); - Ok(out) - } - - #[napi] - pub async fn sync(&self) -> Result<()> { - self - .inner_client - .sync_welcomes() - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?; - Ok(()) - } - - #[napi] - pub async fn list(&self, opts: Option) -> Result> { - let opts = match opts { - Some(options) => options, - None => NapiListConversationsOptions { - created_after_ns: None, - created_before_ns: None, - limit: None, - }, - }; - let convo_list: Vec = self - .inner_client - .find_groups( - None, - opts.created_after_ns, - opts.created_before_ns, - opts.limit, - ) - .map_err(|e| Error::from_reason(format!("{}", e)))? - .into_iter() - .map(|group| { - NapiGroup::new( - self.inner_client.clone(), - group.group_id, - group.created_at_ns, - ) - }) - .collect(); - - Ok(convo_list) - } - - #[napi(ts_args_type = "callback: (err: null | Error, result: NapiGroup) => void")] - pub fn stream(&self, callback: JsFunction) -> Result { - let tsfn: ThreadsafeFunction = - callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?; - let client = self.inner_client.clone(); - let stream_closer = - RustXmtpClient::stream_conversations_with_callback(client.clone(), move |convo| { - tsfn.call( - Ok(NapiGroup::new( - client.clone(), + pub fn new(inner_client: Arc) -> Self { + Self { inner_client } + } + + #[napi] + pub async fn create_group( + &self, + account_addresses: Vec, + options: Option, + ) -> Result { + let options = match options { + Some(options) => options, + None => NapiCreateGroupOptions { + permissions: None, + group_name: None, + group_image_url_square: None, + group_description: None, + group_pinned_frame_url: None, + }, + }; + + let group_permissions = match options.permissions { + Some(NapiGroupPermissionsOptions::AllMembers) => { + Some(PreconfiguredPolicies::AllMembers.to_policy_set()) + } + Some(NapiGroupPermissionsOptions::AdminOnly) => { + Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()) + } + _ => None, + }; + + let metadata_options = options.clone().into_group_metadata_options(); + + let convo = if account_addresses.is_empty() { + self.inner_client + .create_group(group_permissions, metadata_options) + .map_err(|e| Error::from_reason(format!("ClientError: {}", e)))? + } else { + self.inner_client + .create_group_with_members(account_addresses, group_permissions, metadata_options) + .await + .map_err(|e| Error::from_reason(format!("ClientError: {}", e)))? + }; + + let out = NapiGroup::new( + self.inner_client.clone(), convo.group_id, convo.created_at_ns, - )), - ThreadsafeFunctionCallMode::Blocking, ); - }); - - Ok(NapiStreamCloser::new(stream_closer)) - } - - #[napi(ts_args_type = "callback: (err: null | Error, result: NapiMessage) => void")] - pub fn stream_all_messages(&self, callback: JsFunction) -> Result { - let tsfn: ThreadsafeFunction = - callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?; - let stream_closer = RustXmtpClient::stream_all_messages_with_callback( - self.inner_client.clone(), - move |message| { - tsfn.call(Ok(message.into()), ThreadsafeFunctionCallMode::Blocking); - }, - ); - - Ok(NapiStreamCloser::new(stream_closer)) - } + + Ok(out) + } + + #[napi] + pub fn find_group_by_id(&self, group_id: String) -> Result { + let group_id = hex::decode(group_id).map_err(|e| Error::from_reason(format!("{}", e)))?; + + let group = self + .inner_client + .group(group_id) + .map_err(|e| Error::from_reason(format!("{}", e)))?; + + Ok(NapiGroup::new( + self.inner_client.clone(), + group.group_id, + group.created_at_ns, + )) + } + + #[napi] + pub fn find_message_by_id(&self, message_id: String) -> Result { + let message_id = + hex::decode(message_id).map_err(|e| Error::from_reason(format!("{}", e)))?; + + let message = self + .inner_client + .message(message_id) + .map_err(|e| Error::from_reason(format!("{}", e)))?; + + Ok(NapiMessage::from(message)) + } + + #[napi] + pub async fn process_streamed_welcome_message( + &self, + envelope_bytes: Uint8Array, + ) -> Result { + let envelope_bytes = envelope_bytes.deref().to_vec(); + let group = self + .inner_client + .process_streamed_welcome_message(envelope_bytes) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; + let out = NapiGroup::new( + self.inner_client.clone(), + group.group_id, + group.created_at_ns, + ); + Ok(out) + } + + #[napi] + pub async fn sync(&self) -> Result<()> { + self.inner_client + .sync_welcomes() + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; + Ok(()) + } + + #[napi] + pub async fn list(&self, opts: Option) -> Result> { + let opts = match opts { + Some(options) => options, + None => NapiListConversationsOptions { + created_after_ns: None, + created_before_ns: None, + limit: None, + }, + }; + let convo_list: Vec = self + .inner_client + .find_groups( + None, + opts.created_after_ns, + opts.created_before_ns, + opts.limit, + ) + .map_err(|e| Error::from_reason(format!("{}", e)))? + .into_iter() + .map(|group| { + NapiGroup::new( + self.inner_client.clone(), + group.group_id, + group.created_at_ns, + ) + }) + .collect(); + + Ok(convo_list) + } + + #[napi(ts_args_type = "callback: (err: null | Error, result: NapiGroup) => void")] + pub fn stream(&self, callback: JsFunction) -> Result { + let tsfn: ThreadsafeFunction = + callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?; + let client = self.inner_client.clone(); + let stream_closer = + RustXmtpClient::stream_conversations_with_callback(client.clone(), move |convo| { + tsfn.call( + Ok(NapiGroup::new( + client.clone(), + convo.group_id, + convo.created_at_ns, + )), + ThreadsafeFunctionCallMode::Blocking, + ); + }); + + Ok(NapiStreamCloser::new(stream_closer)) + } + + #[napi(ts_args_type = "callback: (err: null | Error, result: NapiMessage) => void")] + pub fn stream_all_messages(&self, callback: JsFunction) -> Result { + let tsfn: ThreadsafeFunction = + callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?; + let stream_closer = RustXmtpClient::stream_all_messages_with_callback( + self.inner_client.clone(), + move |message| { + tsfn.call(Ok(message.into()), ThreadsafeFunctionCallMode::Blocking); + }, + ); + + Ok(NapiStreamCloser::new(stream_closer)) + } } diff --git a/bindings_node/src/encoded_content.rs b/bindings_node/src/encoded_content.rs index c0bba36b9..7961bee20 100644 --- a/bindings_node/src/encoded_content.rs +++ b/bindings_node/src/encoded_content.rs @@ -6,69 +6,69 @@ use xmtp_proto::xmtp::mls::message_contents::{ContentTypeId, EncodedContent}; #[derive(Clone)] #[napi(object)] pub struct NapiContentTypeId { - pub authority_id: String, - pub type_id: String, - pub version_major: u32, - pub version_minor: u32, + pub authority_id: String, + pub type_id: String, + pub version_major: u32, + pub version_minor: u32, } impl From for NapiContentTypeId { - fn from(content_type_id: ContentTypeId) -> NapiContentTypeId { - NapiContentTypeId { - authority_id: content_type_id.authority_id, - type_id: content_type_id.type_id, - version_major: content_type_id.version_major, - version_minor: content_type_id.version_minor, + fn from(content_type_id: ContentTypeId) -> NapiContentTypeId { + NapiContentTypeId { + authority_id: content_type_id.authority_id, + type_id: content_type_id.type_id, + version_major: content_type_id.version_major, + version_minor: content_type_id.version_minor, + } } - } } impl From for ContentTypeId { - fn from(content_type_id: NapiContentTypeId) -> Self { - ContentTypeId { - authority_id: content_type_id.authority_id, - type_id: content_type_id.type_id, - version_major: content_type_id.version_major, - version_minor: content_type_id.version_minor, + fn from(content_type_id: NapiContentTypeId) -> Self { + ContentTypeId { + authority_id: content_type_id.authority_id, + type_id: content_type_id.type_id, + version_major: content_type_id.version_major, + version_minor: content_type_id.version_minor, + } } - } } #[derive(Clone)] #[napi(object)] pub struct NapiEncodedContent { - pub r#type: Option, - pub parameters: HashMap, - pub fallback: Option, - pub compression: Option, - pub content: Uint8Array, + pub r#type: Option, + pub parameters: HashMap, + pub fallback: Option, + pub compression: Option, + pub content: Uint8Array, } impl From for NapiEncodedContent { - fn from(content: EncodedContent) -> NapiEncodedContent { - let r#type = content.r#type.map(|v| v.into()); + fn from(content: EncodedContent) -> NapiEncodedContent { + let r#type = content.r#type.map(|v| v.into()); - NapiEncodedContent { - r#type, - parameters: content.parameters, - fallback: content.fallback, - compression: content.compression, - content: content.content.into(), + NapiEncodedContent { + r#type, + parameters: content.parameters, + fallback: content.fallback, + compression: content.compression, + content: content.content.into(), + } } - } } impl From for EncodedContent { - fn from(content: NapiEncodedContent) -> Self { - let r#type = content.r#type.map(|v| v.into()); - let content_bytes: Vec = content.content.deref().to_vec(); + fn from(content: NapiEncodedContent) -> Self { + let r#type = content.r#type.map(|v| v.into()); + let content_bytes: Vec = content.content.deref().to_vec(); - EncodedContent { - r#type, - parameters: content.parameters, - fallback: content.fallback, - compression: content.compression, - content: content_bytes, + EncodedContent { + r#type, + parameters: content.parameters, + fallback: content.fallback, + compression: content.compression, + content: content_bytes, + } } - } } diff --git a/bindings_node/src/groups.rs b/bindings_node/src/groups.rs index a652ed2eb..4755e8a13 100644 --- a/bindings_node/src/groups.rs +++ b/bindings_node/src/groups.rs @@ -1,25 +1,25 @@ use std::{ops::Deref, sync::Arc}; use napi::{ - bindgen_prelude::{Error, Result, Uint8Array}, - threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode}, - JsFunction, + bindgen_prelude::{Error, Result, Uint8Array}, + threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode}, + JsFunction, }; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_mls::groups::{ - group_metadata::{ConversationType, GroupMetadata}, - members::PermissionLevel, - MlsGroup, UpdateAdminListType, + group_metadata::{ConversationType, GroupMetadata}, + members::PermissionLevel, + MlsGroup, UpdateAdminListType, }; use xmtp_proto::xmtp::mls::message_contents::EncodedContent; use crate::{ - encoded_content::NapiEncodedContent, - messages::{NapiListMessagesOptions, NapiMessage}, - mls_client::RustXmtpClient, - permissions::NapiGroupPermissions, - streams::NapiStreamCloser, - ErrorWrapper, + encoded_content::NapiEncodedContent, + messages::{NapiListMessagesOptions, NapiMessage}, + mls_client::RustXmtpClient, + permissions::NapiGroupPermissions, + streams::NapiStreamCloser, + ErrorWrapper, }; use prost::Message; @@ -28,583 +28,584 @@ use napi_derive::napi; #[napi] pub struct NapiGroupMetadata { - inner: GroupMetadata, + inner: GroupMetadata, } #[napi] impl NapiGroupMetadata { - #[napi] - pub fn creator_inbox_id(&self) -> String { - self.inner.creator_inbox_id.clone() - } - - #[napi] - pub fn conversation_type(&self) -> String { - match self.inner.conversation_type { - ConversationType::Group => "group".to_string(), - ConversationType::Dm => "dm".to_string(), - ConversationType::Sync => "sync".to_string(), - } - } + #[napi] + pub fn creator_inbox_id(&self) -> String { + self.inner.creator_inbox_id.clone() + } + + #[napi] + pub fn conversation_type(&self) -> String { + match self.inner.conversation_type { + ConversationType::Group => "group".to_string(), + ConversationType::Dm => "dm".to_string(), + ConversationType::Sync => "sync".to_string(), + } + } } #[napi] pub enum NapiPermissionLevel { - Member, - Admin, - SuperAdmin, + Member, + Admin, + SuperAdmin, } #[napi] pub struct NapiGroupMember { - pub inbox_id: String, - pub account_addresses: Vec, - pub installation_ids: Vec, - pub permission_level: NapiPermissionLevel, + pub inbox_id: String, + pub account_addresses: Vec, + pub installation_ids: Vec, + pub permission_level: NapiPermissionLevel, } #[derive(Debug)] #[napi] pub struct NapiGroup { - inner_client: Arc, - group_id: Vec, - created_at_ns: i64, + inner_client: Arc, + group_id: Vec, + created_at_ns: i64, } #[napi] impl NapiGroup { - pub fn new(inner_client: Arc, group_id: Vec, created_at_ns: i64) -> Self { - Self { - inner_client, - group_id, - created_at_ns, - } - } - - #[napi] - pub fn id(&self) -> String { - hex::encode(self.group_id.clone()) - } - - #[napi] - pub async fn send(&self, encoded_content: NapiEncodedContent) -> Result { - let encoded_content: EncodedContent = encoded_content.into(); - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let message_id = group - .send_message( - encoded_content.encode_to_vec().as_slice(), - &self.inner_client, - ) - .await - .map_err(ErrorWrapper::from)?; - Ok(hex::encode(message_id.clone())) - } - - /// send a message without immediately publishing to the delivery service. - #[napi] - pub fn send_optimistic(&self, encoded_content: NapiEncodedContent) -> Result> { - let encoded_content: EncodedContent = encoded_content.into(); - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let id = group - .send_message_optimistic(encoded_content.encode_to_vec().as_slice()) - .map_err(ErrorWrapper::from)?; - - Ok(id) - } - - /// Publish all unpublished messages - #[napi] - pub async fn publish_messages(&self) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - group - .publish_messages(&self.inner_client) - .await - .map_err(ErrorWrapper::from)?; - Ok(()) - } - - #[napi] - pub async fn sync(&self) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .sync(&self.inner_client) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub fn find_messages(&self, opts: Option) -> Result> { - let opts = match opts { - Some(options) => options, - None => NapiListMessagesOptions { - sent_before_ns: None, - sent_after_ns: None, - limit: None, - delivery_status: None, - }, - }; - - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let delivery_status = opts.delivery_status.map(|status| status.into()); - - let messages: Vec = group - .find_messages( - None, - opts.sent_before_ns, - opts.sent_after_ns, - delivery_status, - opts.limit, - ) - .map_err(ErrorWrapper::from)? - .into_iter() - .map(|msg| msg.into()) - .collect(); - - Ok(messages) - } - - #[napi] - pub async fn process_streamed_group_message( - &self, - envelope_bytes: Uint8Array, - ) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - let envelope_bytes: Vec = envelope_bytes.deref().to_vec(); - let message = group - .process_streamed_group_message(envelope_bytes, &self.inner_client) - .await - .map_err(ErrorWrapper::from)?; - - Ok(message.into()) - } - - #[napi] - pub fn list_members(&self) -> Result> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let members: Vec = group - .members() - .map_err(ErrorWrapper::from)? - .into_iter() - .map(|member| NapiGroupMember { - inbox_id: member.inbox_id, - account_addresses: member.account_addresses, - installation_ids: member - .installation_ids - .into_iter() - .map(|id| ed25519_public_key_to_address(id.as_slice())) - .collect(), - permission_level: match member.permission_level { - PermissionLevel::Member => NapiPermissionLevel::Member, - PermissionLevel::Admin => NapiPermissionLevel::Admin, - PermissionLevel::SuperAdmin => NapiPermissionLevel::SuperAdmin, - }, - }) - .collect(); - - Ok(members) - } - - #[napi] - pub fn admin_list(&self) -> Result> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let admin_list = group - .admin_list(group.mls_provider().map_err(ErrorWrapper::from)?) - .map_err(ErrorWrapper::from)?; - - Ok(admin_list) - } - - #[napi] - pub fn super_admin_list(&self) -> Result> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let super_admin_list = group - .super_admin_list(group.mls_provider().map_err(ErrorWrapper::from)?) - .map_err(ErrorWrapper::from)?; - - Ok(super_admin_list) - } - - #[napi] - pub fn is_admin(&self, inbox_id: String) -> Result { - let admin_list = self.admin_list().map_err(ErrorWrapper::from)?; - Ok(admin_list.contains(&inbox_id)) - } - - #[napi] - pub fn is_super_admin(&self, inbox_id: String) -> Result { - let super_admin_list = self.super_admin_list().map_err(ErrorWrapper::from)?; - Ok(super_admin_list.contains(&inbox_id)) - } - - #[napi] - pub async fn add_members(&self, account_addresses: Vec) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .add_members(&self.inner_client, account_addresses) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub async fn add_admin(&self, inbox_id: String) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - group - .update_admin_list(&self.inner_client, UpdateAdminListType::Add, inbox_id) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub async fn remove_admin(&self, inbox_id: String) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - group - .update_admin_list(&self.inner_client, UpdateAdminListType::Remove, inbox_id) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub async fn add_super_admin(&self, inbox_id: String) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - group - .update_admin_list(&self.inner_client, UpdateAdminListType::AddSuper, inbox_id) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub async fn remove_super_admin(&self, inbox_id: String) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - group - .update_admin_list( - &self.inner_client, - UpdateAdminListType::RemoveSuper, - inbox_id, - ) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub fn group_permissions(&self) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let permissions = group.permissions().map_err(ErrorWrapper::from)?; - - Ok(NapiGroupPermissions::new(permissions)) - } - - #[napi] - pub async fn add_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .add_members_by_inbox_id(&self.inner_client, inbox_ids) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub async fn remove_members(&self, account_addresses: Vec) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .remove_members(&self.inner_client, account_addresses) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub async fn remove_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .remove_members_by_inbox_id(&self.inner_client, inbox_ids) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub async fn update_group_name(&self, group_name: String) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .update_group_name(&self.inner_client, group_name) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub fn group_name(&self) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let group_name = group - .group_name(group.mls_provider().map_err(ErrorWrapper::from)?) - .map_err(ErrorWrapper::from)?; - - Ok(group_name) - } - - #[napi] - pub async fn update_group_image_url_square(&self, group_image_url_square: String) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .update_group_image_url_square(&self.inner_client, group_image_url_square) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub fn group_image_url_square(&self) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let group_image_url_square = group - .group_image_url_square(group.mls_provider().map_err(ErrorWrapper::from)?) - .map_err(ErrorWrapper::from)?; - - Ok(group_image_url_square) - } - - #[napi] - pub async fn update_group_description(&self, group_description: String) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .update_group_description(&self.inner_client, group_description) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub fn group_description(&self) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let group_description = group - .group_description(group.mls_provider().map_err(ErrorWrapper::from)?) - .map_err(ErrorWrapper::from)?; - - Ok(group_description) - } - - #[napi] - pub async fn update_group_pinned_frame_url(&self, pinned_frame_url: String) -> Result<()> { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - group - .update_group_pinned_frame_url(&self.inner_client, pinned_frame_url) - .await - .map_err(ErrorWrapper::from)?; - - Ok(()) - } - - #[napi] - pub fn group_pinned_frame_url(&self) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let group_pinned_frame_url = group - .group_pinned_frame_url(group.mls_provider().map_err(ErrorWrapper::from)?) - .map_err(|e| Error::from_reason(format!("{}", e)))?; - - Ok(group_pinned_frame_url) - } - - #[napi(ts_args_type = "callback: (err: null | Error, result: NapiMessage) => void")] - pub fn stream(&self, callback: JsFunction) -> Result { - let tsfn: ThreadsafeFunction = - callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?; - let stream_closer = MlsGroup::stream_with_callback( - self.inner_client.clone(), - self.group_id.clone(), - self.created_at_ns, - move |message| { - tsfn.call(Ok(message.into()), ThreadsafeFunctionCallMode::Blocking); - }, - ); - - Ok(stream_closer.into()) - } - - #[napi] - pub fn created_at_ns(&self) -> i64 { - self.created_at_ns - } - - #[napi] - pub fn is_active(&self) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - Ok( - group - .is_active(group.mls_provider().map_err(ErrorWrapper::from)?) - .map_err(ErrorWrapper::from)?, - ) - } - - #[napi] - pub fn added_by_inbox_id(&self) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - Ok(group.added_by_inbox_id().map_err(ErrorWrapper::from)?) - } - - #[napi] - pub fn group_metadata(&self) -> Result { - let group = MlsGroup::new( - self.inner_client.context().clone(), - self.group_id.clone(), - self.created_at_ns, - ); - - let metadata = group - .metadata(group.mls_provider().map_err(ErrorWrapper::from)?) - .map_err(ErrorWrapper::from)?; - - Ok(NapiGroupMetadata { inner: metadata }) - } + pub fn new(inner_client: Arc, group_id: Vec, created_at_ns: i64) -> Self { + Self { + inner_client, + group_id, + created_at_ns, + } + } + + #[napi] + pub fn id(&self) -> String { + hex::encode(self.group_id.clone()) + } + + #[napi] + pub async fn send(&self, encoded_content: NapiEncodedContent) -> Result { + let encoded_content: EncodedContent = encoded_content.into(); + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let message_id = group + .send_message( + encoded_content.encode_to_vec().as_slice(), + &self.inner_client, + ) + .await + .map_err(ErrorWrapper::from)?; + Ok(hex::encode(message_id.clone())) + } + + /// send a message without immediately publishing to the delivery service. + #[napi] + pub fn send_optimistic(&self, encoded_content: NapiEncodedContent) -> Result> { + let encoded_content: EncodedContent = encoded_content.into(); + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let id = group + .send_message_optimistic(encoded_content.encode_to_vec().as_slice()) + .map_err(ErrorWrapper::from)?; + + Ok(id) + } + + /// Publish all unpublished messages + #[napi] + pub async fn publish_messages(&self) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .publish_messages(&self.inner_client) + .await + .map_err(ErrorWrapper::from)?; + Ok(()) + } + + #[napi] + pub async fn sync(&self) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .sync(&self.inner_client) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub fn find_messages(&self, opts: Option) -> Result> { + let opts = match opts { + Some(options) => options, + None => NapiListMessagesOptions { + sent_before_ns: None, + sent_after_ns: None, + limit: None, + delivery_status: None, + }, + }; + + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let delivery_status = opts.delivery_status.map(|status| status.into()); + + let messages: Vec = group + .find_messages( + None, + opts.sent_before_ns, + opts.sent_after_ns, + delivery_status, + opts.limit, + ) + .map_err(ErrorWrapper::from)? + .into_iter() + .map(|msg| msg.into()) + .collect(); + + Ok(messages) + } + + #[napi] + pub async fn process_streamed_group_message( + &self, + envelope_bytes: Uint8Array, + ) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + let envelope_bytes: Vec = envelope_bytes.deref().to_vec(); + let message = group + .process_streamed_group_message(envelope_bytes, &self.inner_client) + .await + .map_err(ErrorWrapper::from)?; + + Ok(message.into()) + } + + #[napi] + pub fn list_members(&self) -> Result> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let members: Vec = group + .members() + .map_err(ErrorWrapper::from)? + .into_iter() + .map(|member| NapiGroupMember { + inbox_id: member.inbox_id, + account_addresses: member.account_addresses, + installation_ids: member + .installation_ids + .into_iter() + .map(|id| ed25519_public_key_to_address(id.as_slice())) + .collect(), + permission_level: match member.permission_level { + PermissionLevel::Member => NapiPermissionLevel::Member, + PermissionLevel::Admin => NapiPermissionLevel::Admin, + PermissionLevel::SuperAdmin => NapiPermissionLevel::SuperAdmin, + }, + }) + .collect(); + + Ok(members) + } + + #[napi] + pub fn admin_list(&self) -> Result> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let admin_list = group + .admin_list(group.mls_provider().map_err(ErrorWrapper::from)?) + .map_err(ErrorWrapper::from)?; + + Ok(admin_list) + } + + #[napi] + pub fn super_admin_list(&self) -> Result> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let super_admin_list = group + .super_admin_list(group.mls_provider().map_err(ErrorWrapper::from)?) + .map_err(ErrorWrapper::from)?; + + Ok(super_admin_list) + } + + #[napi] + pub fn is_admin(&self, inbox_id: String) -> Result { + let admin_list = self.admin_list().map_err(ErrorWrapper::from)?; + Ok(admin_list.contains(&inbox_id)) + } + + #[napi] + pub fn is_super_admin(&self, inbox_id: String) -> Result { + let super_admin_list = self.super_admin_list().map_err(ErrorWrapper::from)?; + Ok(super_admin_list.contains(&inbox_id)) + } + + #[napi] + pub async fn add_members(&self, account_addresses: Vec) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .add_members(&self.inner_client, account_addresses) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub async fn add_admin(&self, inbox_id: String) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .update_admin_list(&self.inner_client, UpdateAdminListType::Add, inbox_id) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub async fn remove_admin(&self, inbox_id: String) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .update_admin_list(&self.inner_client, UpdateAdminListType::Remove, inbox_id) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub async fn add_super_admin(&self, inbox_id: String) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .update_admin_list(&self.inner_client, UpdateAdminListType::AddSuper, inbox_id) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub async fn remove_super_admin(&self, inbox_id: String) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + group + .update_admin_list( + &self.inner_client, + UpdateAdminListType::RemoveSuper, + inbox_id, + ) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub fn group_permissions(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let permissions = group.permissions().map_err(ErrorWrapper::from)?; + + Ok(NapiGroupPermissions::new(permissions)) + } + + #[napi] + pub async fn add_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .add_members_by_inbox_id(&self.inner_client, inbox_ids) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub async fn remove_members(&self, account_addresses: Vec) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .remove_members(&self.inner_client, account_addresses) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub async fn remove_members_by_inbox_id(&self, inbox_ids: Vec) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .remove_members_by_inbox_id(&self.inner_client, inbox_ids) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub async fn update_group_name(&self, group_name: String) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_group_name(&self.inner_client, group_name) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub fn group_name(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let group_name = group + .group_name(group.mls_provider().map_err(ErrorWrapper::from)?) + .map_err(ErrorWrapper::from)?; + + Ok(group_name) + } + + #[napi] + pub async fn update_group_image_url_square( + &self, + group_image_url_square: String, + ) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_group_image_url_square(&self.inner_client, group_image_url_square) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub fn group_image_url_square(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let group_image_url_square = group + .group_image_url_square(group.mls_provider().map_err(ErrorWrapper::from)?) + .map_err(ErrorWrapper::from)?; + + Ok(group_image_url_square) + } + + #[napi] + pub async fn update_group_description(&self, group_description: String) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_group_description(&self.inner_client, group_description) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub fn group_description(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let group_description = group + .group_description(group.mls_provider().map_err(ErrorWrapper::from)?) + .map_err(ErrorWrapper::from)?; + + Ok(group_description) + } + + #[napi] + pub async fn update_group_pinned_frame_url(&self, pinned_frame_url: String) -> Result<()> { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + group + .update_group_pinned_frame_url(&self.inner_client, pinned_frame_url) + .await + .map_err(ErrorWrapper::from)?; + + Ok(()) + } + + #[napi] + pub fn group_pinned_frame_url(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let group_pinned_frame_url = group + .group_pinned_frame_url(group.mls_provider().map_err(ErrorWrapper::from)?) + .map_err(|e| Error::from_reason(format!("{}", e)))?; + + Ok(group_pinned_frame_url) + } + + #[napi(ts_args_type = "callback: (err: null | Error, result: NapiMessage) => void")] + pub fn stream(&self, callback: JsFunction) -> Result { + let tsfn: ThreadsafeFunction = + callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?; + let stream_closer = MlsGroup::stream_with_callback( + self.inner_client.clone(), + self.group_id.clone(), + self.created_at_ns, + move |message| { + tsfn.call(Ok(message.into()), ThreadsafeFunctionCallMode::Blocking); + }, + ); + + Ok(NapiStreamCloser::new(stream_closer)) + } + + #[napi] + pub fn created_at_ns(&self) -> i64 { + self.created_at_ns + } + + #[napi] + pub fn is_active(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + Ok(group + .is_active(group.mls_provider().map_err(ErrorWrapper::from)?) + .map_err(ErrorWrapper::from)?) + } + + #[napi] + pub fn added_by_inbox_id(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + Ok(group.added_by_inbox_id().map_err(ErrorWrapper::from)?) + } + + #[napi] + pub fn group_metadata(&self) -> Result { + let group = MlsGroup::new( + self.inner_client.context().clone(), + self.group_id.clone(), + self.created_at_ns, + ); + + let metadata = group + .metadata(group.mls_provider().map_err(ErrorWrapper::from)?) + .map_err(ErrorWrapper::from)?; + + Ok(NapiGroupMetadata { inner: metadata }) + } } diff --git a/bindings_node/src/lib.rs b/bindings_node/src/lib.rs index 0dea07153..132e667df 100755 --- a/bindings_node/src/lib.rs +++ b/bindings_node/src/lib.rs @@ -16,25 +16,25 @@ use napi::bindgen_prelude::Error; #[derive(Debug)] pub struct ErrorWrapper(E) where - E: std::error::Error; + E: std::error::Error; impl std::fmt::Display for ErrorWrapper { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!(f, "{}", self.0) - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{}", self.0) + } } impl From for ErrorWrapper where - T: std::error::Error, + T: std::error::Error, { - fn from(err: T) -> ErrorWrapper { - ErrorWrapper(err) - } + fn from(err: T) -> ErrorWrapper { + ErrorWrapper(err) + } } impl From> for napi::bindgen_prelude::Error { - fn from(e: ErrorWrapper) -> napi::bindgen_prelude::Error { - Error::from_reason(e.to_string()) - } + fn from(e: ErrorWrapper) -> napi::bindgen_prelude::Error { + Error::from_reason(e.to_string()) + } } diff --git a/bindings_node/src/messages.rs b/bindings_node/src/messages.rs index eb207b78c..44ff7e537 100644 --- a/bindings_node/src/messages.rs +++ b/bindings_node/src/messages.rs @@ -9,92 +9,92 @@ use crate::encoded_content::NapiEncodedContent; #[napi] pub enum NapiGroupMessageKind { - Application, - MembershipChange, + Application, + MembershipChange, } impl From for NapiGroupMessageKind { - fn from(kind: GroupMessageKind) -> Self { - match kind { - GroupMessageKind::Application => NapiGroupMessageKind::Application, - GroupMessageKind::MembershipChange => NapiGroupMessageKind::MembershipChange, + fn from(kind: GroupMessageKind) -> Self { + match kind { + GroupMessageKind::Application => NapiGroupMessageKind::Application, + GroupMessageKind::MembershipChange => NapiGroupMessageKind::MembershipChange, + } } - } } #[napi] pub enum NapiDeliveryStatus { - Unpublished, - Published, - Failed, + Unpublished, + Published, + Failed, } impl From for NapiDeliveryStatus { - fn from(status: DeliveryStatus) -> Self { - match status { - DeliveryStatus::Unpublished => NapiDeliveryStatus::Unpublished, - DeliveryStatus::Published => NapiDeliveryStatus::Published, - DeliveryStatus::Failed => NapiDeliveryStatus::Failed, + fn from(status: DeliveryStatus) -> Self { + match status { + DeliveryStatus::Unpublished => NapiDeliveryStatus::Unpublished, + DeliveryStatus::Published => NapiDeliveryStatus::Published, + DeliveryStatus::Failed => NapiDeliveryStatus::Failed, + } } - } } impl From for DeliveryStatus { - fn from(status: NapiDeliveryStatus) -> Self { - match status { - NapiDeliveryStatus::Unpublished => DeliveryStatus::Unpublished, - NapiDeliveryStatus::Published => DeliveryStatus::Published, - NapiDeliveryStatus::Failed => DeliveryStatus::Failed, + fn from(status: NapiDeliveryStatus) -> Self { + match status { + NapiDeliveryStatus::Unpublished => DeliveryStatus::Unpublished, + NapiDeliveryStatus::Published => DeliveryStatus::Published, + NapiDeliveryStatus::Failed => DeliveryStatus::Failed, + } } - } } #[napi(object)] pub struct NapiListMessagesOptions { - pub sent_before_ns: Option, - pub sent_after_ns: Option, - pub limit: Option, - pub delivery_status: Option, + pub sent_before_ns: Option, + pub sent_after_ns: Option, + pub limit: Option, + pub delivery_status: Option, } #[napi] pub struct NapiMessage { - pub id: String, - pub sent_at_ns: i64, - pub convo_id: String, - pub sender_inbox_id: String, - pub content: NapiEncodedContent, - pub kind: NapiGroupMessageKind, - pub delivery_status: NapiDeliveryStatus, + pub id: String, + pub sent_at_ns: i64, + pub convo_id: String, + pub sender_inbox_id: String, + pub content: NapiEncodedContent, + pub kind: NapiGroupMessageKind, + pub delivery_status: NapiDeliveryStatus, } impl From for NapiMessage { - fn from(msg: StoredGroupMessage) -> Self { - let id = hex::encode(msg.id.clone()); - let convo_id = hex::encode(msg.group_id.clone()); - let contents = msg.decrypted_message_bytes.clone(); - let content: NapiEncodedContent = match EncodedContent::decode(contents.as_slice()) { - Ok(value) => value.into(), - Err(e) => { - println!("Error decoding content: {:?}", e); - NapiEncodedContent { - r#type: None, - parameters: Default::default(), - fallback: None, - compression: None, - content: Uint8Array::new(vec![]), - } - } - }; + fn from(msg: StoredGroupMessage) -> Self { + let id = hex::encode(msg.id.clone()); + let convo_id = hex::encode(msg.group_id.clone()); + let contents = msg.decrypted_message_bytes.clone(); + let content: NapiEncodedContent = match EncodedContent::decode(contents.as_slice()) { + Ok(value) => value.into(), + Err(e) => { + println!("Error decoding content: {:?}", e); + NapiEncodedContent { + r#type: None, + parameters: Default::default(), + fallback: None, + compression: None, + content: Uint8Array::new(vec![]), + } + } + }; - Self { - id, - sent_at_ns: msg.sent_at_ns, - convo_id, - sender_inbox_id: msg.sender_inbox_id, - content, - kind: msg.kind.into(), - delivery_status: msg.delivery_status.into(), + Self { + id, + sent_at_ns: msg.sent_at_ns, + convo_id, + sender_inbox_id: msg.sender_inbox_id, + content, + kind: msg.kind.into(), + delivery_status: msg.delivery_status.into(), + } } - } } diff --git a/bindings_node/src/mls_client.rs b/bindings_node/src/mls_client.rs index 236f5c494..7ddd214fb 100644 --- a/bindings_node/src/mls_client.rs +++ b/bindings_node/src/mls_client.rs @@ -20,296 +20,299 @@ pub type RustXmtpClient = MlsClient; #[napi(object)] pub struct NapiInboxState { - pub inbox_id: String, - pub recovery_address: String, - pub installation_ids: Vec, - pub account_addresses: Vec, + pub inbox_id: String, + pub recovery_address: String, + pub installation_ids: Vec, + pub account_addresses: Vec, } impl From for NapiInboxState { - fn from(state: AssociationState) -> Self { - Self { - inbox_id: state.inbox_id().to_string(), - recovery_address: state.recovery_address().to_string(), - installation_ids: state - .installation_ids() - .into_iter() - .map(|id| ed25519_public_key_to_address(id.as_slice())) - .collect(), - account_addresses: state.account_addresses(), + fn from(state: AssociationState) -> Self { + Self { + inbox_id: state.inbox_id().to_string(), + recovery_address: state.recovery_address().to_string(), + installation_ids: state + .installation_ids() + .into_iter() + .map(|id| ed25519_public_key_to_address(id.as_slice())) + .collect(), + account_addresses: state.account_addresses(), + } } - } } #[napi] pub struct NapiClient { - inner_client: Arc, - signatures: HashMap, - pub account_address: String, + inner_client: Arc, + signatures: HashMap, + pub account_address: String, } #[napi] pub async fn create_client( - host: String, - is_secure: bool, - db_path: String, - inbox_id: String, - account_address: String, - encryption_key: Option, - history_sync_url: Option, + host: String, + is_secure: bool, + db_path: String, + inbox_id: String, + account_address: String, + encryption_key: Option, + history_sync_url: Option, ) -> Result { - let api_client = TonicApiClient::create(host.clone(), is_secure) - .await - .map_err(|_| Error::from_reason("Error creating Tonic API client"))?; - - let storage_option = StorageOption::Persistent(db_path); - - let store = match encryption_key { - Some(key) => { - let key: Vec = key.deref().into(); - let key: EncryptionKey = key - .try_into() - .map_err(|_| Error::from_reason("Malformed 32 byte encryption key".to_string()))?; - EncryptedMessageStore::new(storage_option, key) - .map_err(|_| Error::from_reason("Error creating encrypted message store"))? - } - None => EncryptedMessageStore::new_unencrypted(storage_option) - .map_err(|_| Error::from_reason("Error creating unencrypted message store"))?, - }; - - let identity_strategy = IdentityStrategy::CreateIfNotFound( - inbox_id.clone(), - account_address.clone().to_lowercase(), - // this is a temporary solution - 1, - None, - ); - - let xmtp_client = match history_sync_url { - Some(url) => ClientBuilder::new(identity_strategy) - .api_client(api_client) - .store(store) - .history_sync_url(&url) - .build() - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?, - None => ClientBuilder::new(identity_strategy) - .api_client(api_client) - .store(store) - .build() - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?, - }; - - Ok(NapiClient { - inner_client: Arc::new(xmtp_client), - account_address, - signatures: HashMap::new(), - }) + let api_client = TonicApiClient::create(host.clone(), is_secure) + .await + .map_err(|_| Error::from_reason("Error creating Tonic API client"))?; + + let storage_option = StorageOption::Persistent(db_path); + + let store = match encryption_key { + Some(key) => { + let key: Vec = key.deref().into(); + let key: EncryptionKey = key + .try_into() + .map_err(|_| Error::from_reason("Malformed 32 byte encryption key".to_string()))?; + EncryptedMessageStore::new(storage_option, key) + .await + .map_err(|_| Error::from_reason("Error creating encrypted message store"))? + } + None => EncryptedMessageStore::new_unencrypted(storage_option) + .await + .map_err(|_| Error::from_reason("Error creating unencrypted message store"))?, + }; + + let identity_strategy = IdentityStrategy::CreateIfNotFound( + inbox_id.clone(), + account_address.clone().to_lowercase(), + // this is a temporary solution + 1, + None, + ); + + let xmtp_client = match history_sync_url { + Some(url) => ClientBuilder::new(identity_strategy) + .api_client(api_client) + .store(store) + .history_sync_url(&url) + .build() + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?, + None => ClientBuilder::new(identity_strategy) + .api_client(api_client) + .store(store) + .build() + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?, + }; + + Ok(NapiClient { + inner_client: Arc::new(xmtp_client), + account_address, + signatures: HashMap::new(), + }) } #[napi] pub async fn get_inbox_id_for_address( - host: String, - is_secure: bool, - account_address: String, + host: String, + is_secure: bool, + account_address: String, ) -> Result> { - let account_address = account_address.to_lowercase(); - let api_client = ApiClientWrapper::new( - TonicApiClient::create(host.clone(), is_secure) - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?, - Retry::default(), - ); - - let results = api_client - .get_inbox_ids(vec![account_address.clone()]) - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?; - - Ok(results.get(&account_address).cloned()) + let account_address = account_address.to_lowercase(); + let api_client = ApiClientWrapper::new( + TonicApiClient::create(host.clone(), is_secure) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?, + Retry::default(), + ); + + let results = api_client + .get_inbox_ids(vec![account_address.clone()]) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; + + Ok(results.get(&account_address).cloned()) } #[napi] pub fn generate_inbox_id(account_address: String) -> String { - let account_address = account_address.to_lowercase(); - // ensure that the nonce is always 1 for now since this will only be used for the - // create_client function above, which also has a hard-coded nonce of 1 - xmtp_id_generate_inbox_id(&account_address, &1) + let account_address = account_address.to_lowercase(); + // ensure that the nonce is always 1 for now since this will only be used for the + // create_client function above, which also has a hard-coded nonce of 1 + xmtp_id_generate_inbox_id(&account_address, &1) } #[napi] impl NapiClient { - #[napi] - pub fn inbox_id(&self) -> String { - self.inner_client.inbox_id() - } - - #[napi] - pub fn is_registered(&self) -> bool { - self.inner_client.identity().signature_request().is_none() - } - - #[napi] - pub fn installation_id(&self) -> String { - ed25519_public_key_to_address(self.inner_client.installation_public_key().as_slice()) - } - - #[napi] - pub async fn can_message(&self, account_addresses: Vec) -> Result> { - let results: HashMap = self - .inner_client - .can_message(account_addresses) - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?; - - Ok(results) - } - - #[napi] - pub fn add_ecdsa_signature(&mut self, signature_bytes: Uint8Array) -> Result<()> { - if self.is_registered() { - return Err(Error::from_reason( - "An identity is already registered with this client", - )); + #[napi] + pub fn inbox_id(&self) -> String { + self.inner_client.inbox_id() } - let signature = UnverifiedSignature::new_recoverable_ecdsa(signature_bytes.deref().to_vec()); + #[napi] + pub fn is_registered(&self) -> bool { + self.inner_client.identity().signature_request().is_none() + } - self.signatures.insert( - MemberIdentifier::Address(self.account_address.clone().to_lowercase()), - signature, - ); + #[napi] + pub fn installation_id(&self) -> String { + ed25519_public_key_to_address(self.inner_client.installation_public_key().as_slice()) + } - Ok(()) - } + #[napi] + pub async fn can_message( + &self, + account_addresses: Vec, + ) -> Result> { + let results: HashMap = self + .inner_client + .can_message(account_addresses) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; - #[napi] - pub fn add_scw_signature( - &mut self, - signature_bytes: Uint8Array, - chain_id: BigInt, - account_address: String, - // TODO:nm remove this - _chain_rpc_url: String, - block_number: BigInt, - ) -> Result<()> { - if self.is_registered() { - return Err(Error::from_reason( - "An identity is already registered with this client", - )); + Ok(results) } - let (_, chain_id_u64, _) = chain_id.get_u64(); + #[napi] + pub fn add_ecdsa_signature(&mut self, signature_bytes: Uint8Array) -> Result<()> { + if self.is_registered() { + return Err(Error::from_reason( + "An identity is already registered with this client", + )); + } - let account_id = AccountId::new_evm(chain_id_u64, account_address.clone()); + let signature = + UnverifiedSignature::new_recoverable_ecdsa(signature_bytes.deref().to_vec()); - let signature = UnverifiedSignature::new_smart_contract_wallet( - signature_bytes.deref().to_vec(), - account_id, - block_number.get_u64().1, - ); + self.signatures.insert( + MemberIdentifier::Address(self.account_address.clone().to_lowercase()), + signature, + ); - self.signatures.insert( - MemberIdentifier::Address(account_address.clone().to_lowercase()), - signature, - ); + Ok(()) + } - Ok(()) - } + #[napi] + pub fn add_scw_signature( + &mut self, + signature_bytes: Uint8Array, + chain_id: BigInt, + account_address: String, + // TODO:nm remove this + _chain_rpc_url: String, + block_number: BigInt, + ) -> Result<()> { + if self.is_registered() { + return Err(Error::from_reason( + "An identity is already registered with this client", + )); + } + + let (_, chain_id_u64, _) = chain_id.get_u64(); + + let account_id = AccountId::new_evm(chain_id_u64, account_address.clone()); + + let signature = UnverifiedSignature::new_smart_contract_wallet( + signature_bytes.deref().to_vec(), + account_id, + block_number.get_u64().1, + ); + + self.signatures.insert( + MemberIdentifier::Address(account_address.clone().to_lowercase()), + signature, + ); + + Ok(()) + } - #[napi] - pub async fn register_identity(&self) -> Result<()> { - if self.is_registered() { - return Err(Error::from_reason( - "An identity is already registered with this client", - )); + #[napi] + pub async fn register_identity(&self) -> Result<()> { + if self.is_registered() { + return Err(Error::from_reason( + "An identity is already registered with this client", + )); + } + + if self.signatures.is_empty() { + return Err(Error::from_reason( + "No client signatures found, add at least 1 before registering", + )); + } + + let mut signature_request = match self.inner_client.identity().signature_request() { + Some(signature_req) => signature_req, + // this should never happen since we're checking for it above in is_registered + None => return Err(Error::from_reason("No signature request found")), + }; + + // apply added signatures to the signature request + for signature in self.signatures.values() { + signature_request + .add_signature( + signature.clone(), + self.inner_client + .smart_contract_signature_verifier() + .as_ref(), + ) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; + } + + self.inner_client + .register_identity(signature_request) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; + + Ok(()) } - if self.signatures.is_empty() { - return Err(Error::from_reason( - "No client signatures found, add at least 1 before registering", - )); + #[napi] + pub fn signature_text(&self) -> Option { + self.inner_client + .identity() + .signature_request() + .map(|signature_req| signature_req.signature_text()) } - let mut signature_request = match self.inner_client.identity().signature_request() { - Some(signature_req) => signature_req, - // this should never happen since we're checking for it above in is_registered - None => return Err(Error::from_reason("No signature request found")), - }; + #[napi] + pub fn conversations(&self) -> NapiConversations { + NapiConversations::new(self.inner_client.clone()) + } - // apply added signatures to the signature request - for signature in self.signatures.values() { - signature_request - .add_signature( - signature.clone(), - self + #[napi] + pub async fn request_history_sync(&self) -> Result<()> { + let _ = self .inner_client - .smart_contract_signature_verifier() - .as_ref(), - ) - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?; + .send_history_request() + .await + .map_err(|e| Error::from_reason(format!("{}", e))); + + Ok(()) + } + + #[napi] + pub async fn find_inbox_id_by_address(&self, address: String) -> Result> { + let inbox_id = self + .inner_client + .find_inbox_id_from_address(address) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; + + Ok(inbox_id) } - self - .inner_client - .register_identity(signature_request) - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?; - - Ok(()) - } - - #[napi] - pub fn signature_text(&self) -> Option { - self - .inner_client - .identity() - .signature_request() - .map(|signature_req| signature_req.signature_text()) - } - - #[napi] - pub fn conversations(&self) -> NapiConversations { - NapiConversations::new(self.inner_client.clone()) - } - - #[napi] - pub async fn request_history_sync(&self) -> Result<()> { - let _ = self - .inner_client - .send_history_request() - .await - .map_err(|e| Error::from_reason(format!("{}", e))); - - Ok(()) - } - - #[napi] - pub async fn find_inbox_id_by_address(&self, address: String) -> Result> { - let inbox_id = self - .inner_client - .find_inbox_id_from_address(address) - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?; - - Ok(inbox_id) - } - - /** - * Get the client's inbox state. - * - * If `refresh_from_network` is true, the client will go to the network first to refresh the state. - * Otherwise, the state will be read from the local database. - */ - #[napi] - pub async fn inbox_state(&self, refresh_from_network: bool) -> Result { - let state = self - .inner_client - .inbox_state(refresh_from_network) - .await - .map_err(|e| Error::from_reason(format!("{}", e)))?; - Ok(state.into()) - } + /** + * Get the client's inbox state. + * + * If `refresh_from_network` is true, the client will go to the network first to refresh the state. + * Otherwise, the state will be read from the local database. + */ + #[napi] + pub async fn inbox_state(&self, refresh_from_network: bool) -> Result { + let state = self + .inner_client + .inbox_state(refresh_from_network) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; + Ok(state.into()) + } } diff --git a/bindings_node/src/permissions.rs b/bindings_node/src/permissions.rs index 45c2f12d0..71b8edb90 100644 --- a/bindings_node/src/permissions.rs +++ b/bindings_node/src/permissions.rs @@ -1,172 +1,178 @@ use napi::bindgen_prelude::{Error, Result}; use napi_derive::napi; use xmtp_mls::groups::{ - group_mutable_metadata::MetadataField, - group_permissions::{ - BasePolicies, GroupMutablePermissions, MembershipPolicies, MetadataBasePolicies, - MetadataPolicies, PermissionsBasePolicies, PermissionsPolicies, - }, - intents::{PermissionPolicyOption, PermissionUpdateType}, - PreconfiguredPolicies, + group_mutable_metadata::MetadataField, + group_permissions::{ + BasePolicies, GroupMutablePermissions, MembershipPolicies, MetadataBasePolicies, + MetadataPolicies, PermissionsBasePolicies, PermissionsPolicies, + }, + intents::{PermissionPolicyOption, PermissionUpdateType}, + PreconfiguredPolicies, }; #[napi] pub enum NapiGroupPermissionsOptions { - AllMembers, - AdminOnly, - CustomPolicy, + AllMembers, + AdminOnly, + CustomPolicy, } #[napi] pub enum NapiPermissionUpdateType { - AddMember, - RemoveMember, - AddAdmin, - RemoveAdmin, - UpdateMetadata, + AddMember, + RemoveMember, + AddAdmin, + RemoveAdmin, + UpdateMetadata, } impl From<&NapiPermissionUpdateType> for PermissionUpdateType { - fn from(update_type: &NapiPermissionUpdateType) -> Self { - match update_type { - NapiPermissionUpdateType::AddMember => PermissionUpdateType::AddMember, - NapiPermissionUpdateType::RemoveMember => PermissionUpdateType::RemoveMember, - NapiPermissionUpdateType::AddAdmin => PermissionUpdateType::AddAdmin, - NapiPermissionUpdateType::RemoveAdmin => PermissionUpdateType::RemoveAdmin, - NapiPermissionUpdateType::UpdateMetadata => PermissionUpdateType::UpdateMetadata, + fn from(update_type: &NapiPermissionUpdateType) -> Self { + match update_type { + NapiPermissionUpdateType::AddMember => PermissionUpdateType::AddMember, + NapiPermissionUpdateType::RemoveMember => PermissionUpdateType::RemoveMember, + NapiPermissionUpdateType::AddAdmin => PermissionUpdateType::AddAdmin, + NapiPermissionUpdateType::RemoveAdmin => PermissionUpdateType::RemoveAdmin, + NapiPermissionUpdateType::UpdateMetadata => PermissionUpdateType::UpdateMetadata, + } } - } } #[napi] pub enum NapiPermissionPolicy { - Allow, - Deny, - Admin, - SuperAdmin, - DoesNotExist, - Other, + Allow, + Deny, + Admin, + SuperAdmin, + DoesNotExist, + Other, } impl TryInto for NapiPermissionPolicy { - type Error = Error; + type Error = Error; - fn try_into(self) -> Result { - match self { - NapiPermissionPolicy::Allow => Ok(PermissionPolicyOption::Allow), - NapiPermissionPolicy::Deny => Ok(PermissionPolicyOption::Deny), - NapiPermissionPolicy::Admin => Ok(PermissionPolicyOption::AdminOnly), - NapiPermissionPolicy::SuperAdmin => Ok(PermissionPolicyOption::SuperAdminOnly), - _ => Err(Error::from_reason("InvalidPermissionPolicyOption")), + fn try_into(self) -> Result { + match self { + NapiPermissionPolicy::Allow => Ok(PermissionPolicyOption::Allow), + NapiPermissionPolicy::Deny => Ok(PermissionPolicyOption::Deny), + NapiPermissionPolicy::Admin => Ok(PermissionPolicyOption::AdminOnly), + NapiPermissionPolicy::SuperAdmin => Ok(PermissionPolicyOption::SuperAdminOnly), + _ => Err(Error::from_reason("InvalidPermissionPolicyOption")), + } } - } } impl From<&MembershipPolicies> for NapiPermissionPolicy { - fn from(policies: &MembershipPolicies) -> Self { - if let MembershipPolicies::Standard(base_policy) = policies { - match base_policy { - BasePolicies::Allow => NapiPermissionPolicy::Allow, - BasePolicies::Deny => NapiPermissionPolicy::Deny, - BasePolicies::AllowSameMember => NapiPermissionPolicy::Other, - BasePolicies::AllowIfAdminOrSuperAdmin => NapiPermissionPolicy::Admin, - BasePolicies::AllowIfSuperAdmin => NapiPermissionPolicy::SuperAdmin, - } - } else { - NapiPermissionPolicy::Other + fn from(policies: &MembershipPolicies) -> Self { + if let MembershipPolicies::Standard(base_policy) = policies { + match base_policy { + BasePolicies::Allow => NapiPermissionPolicy::Allow, + BasePolicies::Deny => NapiPermissionPolicy::Deny, + BasePolicies::AllowSameMember => NapiPermissionPolicy::Other, + BasePolicies::AllowIfAdminOrSuperAdmin => NapiPermissionPolicy::Admin, + BasePolicies::AllowIfSuperAdmin => NapiPermissionPolicy::SuperAdmin, + } + } else { + NapiPermissionPolicy::Other + } } - } } impl From<&MetadataPolicies> for NapiPermissionPolicy { - fn from(policies: &MetadataPolicies) -> Self { - if let MetadataPolicies::Standard(base_policy) = policies { - match base_policy { - MetadataBasePolicies::Allow => NapiPermissionPolicy::Allow, - MetadataBasePolicies::Deny => NapiPermissionPolicy::Deny, - MetadataBasePolicies::AllowIfActorAdminOrSuperAdmin => NapiPermissionPolicy::Admin, - MetadataBasePolicies::AllowIfActorSuperAdmin => NapiPermissionPolicy::SuperAdmin, - } - } else { - NapiPermissionPolicy::Other + fn from(policies: &MetadataPolicies) -> Self { + if let MetadataPolicies::Standard(base_policy) = policies { + match base_policy { + MetadataBasePolicies::Allow => NapiPermissionPolicy::Allow, + MetadataBasePolicies::Deny => NapiPermissionPolicy::Deny, + MetadataBasePolicies::AllowIfActorAdminOrSuperAdmin => NapiPermissionPolicy::Admin, + MetadataBasePolicies::AllowIfActorSuperAdmin => NapiPermissionPolicy::SuperAdmin, + } + } else { + NapiPermissionPolicy::Other + } } - } } impl From<&PermissionsPolicies> for NapiPermissionPolicy { - fn from(policies: &PermissionsPolicies) -> Self { - if let PermissionsPolicies::Standard(base_policy) = policies { - match base_policy { - PermissionsBasePolicies::Deny => NapiPermissionPolicy::Deny, - PermissionsBasePolicies::AllowIfActorAdminOrSuperAdmin => NapiPermissionPolicy::Admin, - PermissionsBasePolicies::AllowIfActorSuperAdmin => NapiPermissionPolicy::SuperAdmin, - } - } else { - NapiPermissionPolicy::Other + fn from(policies: &PermissionsPolicies) -> Self { + if let PermissionsPolicies::Standard(base_policy) = policies { + match base_policy { + PermissionsBasePolicies::Deny => NapiPermissionPolicy::Deny, + PermissionsBasePolicies::AllowIfActorAdminOrSuperAdmin => { + NapiPermissionPolicy::Admin + } + PermissionsBasePolicies::AllowIfActorSuperAdmin => NapiPermissionPolicy::SuperAdmin, + } + } else { + NapiPermissionPolicy::Other + } } - } } #[napi(object)] pub struct NapiPermissionPolicySet { - pub add_member_policy: NapiPermissionPolicy, - pub remove_member_policy: NapiPermissionPolicy, - pub add_admin_policy: NapiPermissionPolicy, - pub remove_admin_policy: NapiPermissionPolicy, - pub update_group_name_policy: NapiPermissionPolicy, - pub update_group_description_policy: NapiPermissionPolicy, - pub update_group_image_url_square_policy: NapiPermissionPolicy, - pub update_group_pinned_frame_url_policy: NapiPermissionPolicy, + pub add_member_policy: NapiPermissionPolicy, + pub remove_member_policy: NapiPermissionPolicy, + pub add_admin_policy: NapiPermissionPolicy, + pub remove_admin_policy: NapiPermissionPolicy, + pub update_group_name_policy: NapiPermissionPolicy, + pub update_group_description_policy: NapiPermissionPolicy, + pub update_group_image_url_square_policy: NapiPermissionPolicy, + pub update_group_pinned_frame_url_policy: NapiPermissionPolicy, } impl From for NapiGroupPermissionsOptions { - fn from(policy: PreconfiguredPolicies) -> Self { - match policy { - PreconfiguredPolicies::AllMembers => NapiGroupPermissionsOptions::AllMembers, - PreconfiguredPolicies::AdminsOnly => NapiGroupPermissionsOptions::AdminOnly, + fn from(policy: PreconfiguredPolicies) -> Self { + match policy { + PreconfiguredPolicies::AllMembers => NapiGroupPermissionsOptions::AllMembers, + PreconfiguredPolicies::AdminsOnly => NapiGroupPermissionsOptions::AdminOnly, + } } - } } #[napi] pub struct NapiGroupPermissions { - inner: GroupMutablePermissions, + inner: GroupMutablePermissions, } #[napi] impl NapiGroupPermissions { - pub fn new(permissions: GroupMutablePermissions) -> Self { - Self { inner: permissions } - } + pub fn new(permissions: GroupMutablePermissions) -> Self { + Self { inner: permissions } + } - #[napi] - pub fn policy_type(&self) -> Result { - if let Ok(preconfigured_policy) = self.inner.preconfigured_policy() { - Ok(preconfigured_policy.into()) - } else { - Ok(NapiGroupPermissionsOptions::CustomPolicy) + #[napi] + pub fn policy_type(&self) -> Result { + if let Ok(preconfigured_policy) = self.inner.preconfigured_policy() { + Ok(preconfigured_policy.into()) + } else { + Ok(NapiGroupPermissionsOptions::CustomPolicy) + } } - } - #[napi] - pub fn policy_set(&self) -> Result { - let policy_set = &self.inner.policies; - let metadata_policy_map = &policy_set.update_metadata_policy; - let get_policy = |field: &str| { - metadata_policy_map - .get(field) - .map(NapiPermissionPolicy::from) - .unwrap_or(NapiPermissionPolicy::DoesNotExist) - }; - Ok(NapiPermissionPolicySet { - add_member_policy: NapiPermissionPolicy::from(&policy_set.add_member_policy), - remove_member_policy: NapiPermissionPolicy::from(&policy_set.remove_member_policy), - add_admin_policy: NapiPermissionPolicy::from(&policy_set.add_admin_policy), - remove_admin_policy: NapiPermissionPolicy::from(&policy_set.remove_admin_policy), - update_group_name_policy: get_policy(MetadataField::GroupName.as_str()), - update_group_description_policy: get_policy(MetadataField::Description.as_str()), - update_group_image_url_square_policy: get_policy(MetadataField::GroupImageUrlSquare.as_str()), - update_group_pinned_frame_url_policy: get_policy(MetadataField::GroupPinnedFrameUrl.as_str()), - }) - } + #[napi] + pub fn policy_set(&self) -> Result { + let policy_set = &self.inner.policies; + let metadata_policy_map = &policy_set.update_metadata_policy; + let get_policy = |field: &str| { + metadata_policy_map + .get(field) + .map(NapiPermissionPolicy::from) + .unwrap_or(NapiPermissionPolicy::DoesNotExist) + }; + Ok(NapiPermissionPolicySet { + add_member_policy: NapiPermissionPolicy::from(&policy_set.add_member_policy), + remove_member_policy: NapiPermissionPolicy::from(&policy_set.remove_member_policy), + add_admin_policy: NapiPermissionPolicy::from(&policy_set.add_admin_policy), + remove_admin_policy: NapiPermissionPolicy::from(&policy_set.remove_admin_policy), + update_group_name_policy: get_policy(MetadataField::GroupName.as_str()), + update_group_description_policy: get_policy(MetadataField::Description.as_str()), + update_group_image_url_square_policy: get_policy( + MetadataField::GroupImageUrlSquare.as_str(), + ), + update_group_pinned_frame_url_policy: get_policy( + MetadataField::GroupPinnedFrameUrl.as_str(), + ), + }) + } } diff --git a/bindings_node/src/streams.rs b/bindings_node/src/streams.rs index c12301239..3f9af02f6 100644 --- a/bindings_node/src/streams.rs +++ b/bindings_node/src/streams.rs @@ -1,73 +1,70 @@ use napi::bindgen_prelude::Error; use std::sync::Arc; -use tokio::{sync::Mutex, task::AbortHandle}; -use xmtp_mls::{client::ClientError, subscriptions::StreamHandle}; +use tokio::sync::Mutex; +use xmtp_mls::{ + client::ClientError, AbortHandle, GenericStreamHandle, StreamHandle, StreamHandleError, +}; use napi_derive::napi; +type NapiHandle = Box>>; + #[napi] pub struct NapiStreamCloser { - #[allow(clippy::type_complexity)] - handle: Arc>>>>, - // for convenience, does not require locking mutex. - abort_handle: Arc, + handle: Arc>>, + abort: Arc>, } impl NapiStreamCloser { - pub fn new(handle: StreamHandle>) -> Self { - Self { - abort_handle: Arc::new(handle.handle.abort_handle()), - handle: Arc::new(Mutex::new(Some(handle))), + pub fn new( + handle: impl StreamHandle> + Send + Sync + 'static, + ) -> Self { + let abort = handle.abort_handle(); + Self { + handle: Arc::new(Mutex::new(Some(Box::new(handle)))), + abort: Arc::new(abort), + } } - } -} - -impl From>> for NapiStreamCloser { - fn from(handle: StreamHandle>) -> Self { - NapiStreamCloser::new(handle) - } } #[napi] impl NapiStreamCloser { - /// Signal the stream to end - /// Does not wait for the stream to end. - #[napi] - pub fn end(&self) { - self.abort_handle.abort(); - } - - /// End the stream and `await` for it to shutdown - /// Returns the `Result` of the task. - #[napi] - /// End the stream and asyncronously wait for it to shutdown - pub async fn end_and_wait(&self) -> Result<(), Error> { - if self.abort_handle.is_finished() { - return Ok(()); + /// Signal the stream to end + /// Does not wait for the stream to end. + #[napi] + pub fn end(&self) { + self.abort.end(); } - let mut stream_handle = self.handle.lock().await; - let stream_handle = stream_handle.take(); - if let Some(h) = stream_handle { - h.handle.abort(); - match h.handle.await { - Err(e) if !e.is_cancelled() => Err(Error::from_reason(format!( - "subscription event loop join error {}", - e - ))), - Err(e) if e.is_cancelled() => Ok(()), - Ok(t) => t.map_err(|e| Error::from_reason(e.to_string())), - Err(e) => Err(Error::from_reason(format!("error joining task {}", e))), - } - } else { - log::warn!("subscription already closed"); - Ok(()) + /// End the stream and `await` for it to shutdown + /// Returns the `Result` of the task. + /// End the stream and asyncronously wait for it to shutdown + #[napi] + pub async fn end_and_wait(&self) -> Result<(), Error> { + use StreamHandleError::*; + if self.abort.is_finished() { + return Ok(()); + } + + let mut stream_handle = self.handle.lock().await; + let stream_handle = stream_handle.take(); + + if let Some(mut h) = stream_handle { + match h.end_and_wait().await { + Err(Cancelled) => Ok(()), + Err(Panicked(msg)) => Err(Error::from_reason(msg)), + Ok(t) => t.map_err(|e| Error::from_reason(e.to_string())), + Err(e) => Err(Error::from_reason(format!("error joining task {}", e))), + } + } else { + log::warn!("subscription already closed"); + Ok(()) + } } - } - /// Checks if this stream is closed - #[napi] - pub fn is_closed(&self) -> bool { - self.abort_handle.is_finished() - } + /// Checks if this stream is closed + #[napi] + pub fn is_closed(&self) -> bool { + self.abort.is_finished() + } } diff --git a/bindings_wasm/src/mls_client.rs b/bindings_wasm/src/mls_client.rs index c84ac166b..68b005c0f 100644 --- a/bindings_wasm/src/mls_client.rs +++ b/bindings_wasm/src/mls_client.rs @@ -43,9 +43,12 @@ pub async fn create_client( .try_into() .map_err(|_| JsError::new("Malformed 32 byte encryption key"))?; EncryptedMessageStore::new(storage_option, key) + .await .map_err(|_| JsError::new("Error creating encrypted message store"))? + } None => EncryptedMessageStore::new_unencrypted(storage_option) + .await .map_err(|_| JsError::new("Error creating unencrypted message store"))?, }; diff --git a/bindings_wasm/tests/web.rs b/bindings_wasm/tests/web.rs index 2b678accb..fb95ee39c 100644 --- a/bindings_wasm/tests/web.rs +++ b/bindings_wasm/tests/web.rs @@ -21,7 +21,7 @@ pub async fn test_create_client() { let host = ApiUrls::LOCAL_ADDRESS.to_string(); let inbox_id = get_inbox_id_for_address(host.clone(), account_address.clone()) .await - .unwrap_or_else(|e| panic!("Error getting inbox ID")); + .unwrap_or_else(|_| panic!("Error getting inbox ID")); let client = create_client( host.clone(), inbox_id.unwrap(), diff --git a/dev/bench b/dev/bench index 5f15c8ff6..c4ec1e38e 100755 --- a/dev/bench +++ b/dev/bench @@ -4,5 +4,5 @@ set -eou pipefail if [[ -z "${1-}" ]]; then cargo bench --no-fail-fast --features bench else - cargo bench --no-fail-fast --features bench -- $1 + cargo bench --no-fail-fast --features bench -- "$1" fi diff --git a/dev/flamegraph b/dev/flamegraph index 1cf35918c..9dbedbc26 100755 --- a/dev/flamegraph +++ b/dev/flamegraph @@ -2,14 +2,14 @@ set -eou pipefail -if [[ "${OSTYPE}" == "darwin"* ]]; then +if [[ "${OSTYPE}" == "darwin"* ]]; then if ! which inferno-flamegraph &>/dev/null; then cargo install inferno; fi fi -if [[ -z "${1-}" ]]; then +if [[ -z "${1-}" ]]; then XMTP_FLAMEGRAPH=trace cargo bench --no-fail-fast --features bench else - XMTP_FLAMEGRAPH=trace cargo bench --no-fail-fast --features bench -- $1 + XMTP_FLAMEGRAPH=trace cargo bench --no-fail-fast --features bench -- "$1" fi -cat xmtp_mls/tracing.folded | inferno-flamegraph > tracing-flamegraph.svg +inferno-flamegraph > tracing-flamegraph.svg diff --git a/dev/lint b/dev/lint index 3ca797b71..df5e5fc0d 100755 --- a/dev/lint +++ b/dev/lint @@ -1,9 +1,8 @@ #!/bin/bash set -eou pipefail -rustup component add clippy +if ! cargo-clippy &>/dev/null; then rustup component add clippy; fi dev/lint-shellcheck dev/lint-markdown - -cargo clippy +dev/lint-rust diff --git a/dev/lint-rust b/dev/lint-rust index 46e16edfd..9ab5fbbd8 100755 --- a/dev/lint-rust +++ b/dev/lint-rust @@ -1,4 +1,12 @@ #!/bin/bash set -eou pipefail -cargo fmt +if ! cargo-clippy &>/dev/null; then rustup component add clippy; fi + +cargo fmt & +cargo clippy --manifest-path "bindings_ffi/Cargo.toml" --all-features --all-targets --no-deps -- -Dwarnings & +cargo clippy --manifest-path "bindings_node/Cargo.toml" --all-features --all-targets --no-deps -- -Dwarnings & +cargo clippy --manifest-path "bindings_wasm/Cargo.toml" --all-features --all-targets --no-deps -- -Dwarnings & +cargo clippy --all-features --all-targets --no-deps -- -Dwarnings & + +wait diff --git a/dev/up b/dev/up index 076811ed3..4bbb91644 100755 --- a/dev/up +++ b/dev/up @@ -12,11 +12,11 @@ if [[ "${OSTYPE}" == "darwin"* ]]; then fi if ! kotlinc -version &>/dev/null; then brew install kotlin; fi if ! swiftformat -version &>/dev/null; then brew install swiftformat; fi - if ! which foundryup &>/dev/null; then + if ! which foundryup &>/dev/null; then # install foundry for tests that require mocking blockchain curl -L https://foundry.paradigm.xyz | bash - # you may need to adjust this depending on which $SHELL you use - source $HOME/.zshenv + # you may need to adjust this depending on which $SHELL you use + source "$HOME"/.zshenv foundryup fi if ! wasm-pack --version &>/dev/null; then cargo install wasm-pack; fi diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index 6212022ba..d51990cf7 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -16,7 +16,7 @@ export class SQLite { constructor(sqlite3) { if (typeof sqlite3 === "undefined") { throw new Error( - "`sqliteObject` must be defined before calling constructor" + "`sqliteObject` must be defined before calling constructor", ); } this.sqlite3 = sqlite3; @@ -146,15 +146,7 @@ export class SQLite { open(database_url, iflags) { try { - let db; - if (database_url === ":memory:") { - db = new this.sqlite3.oo1.DB("transient_in_memory_db:"); - console.log(`Created in-memory database`); - } else { - db = new this.sqlite3.oo1.OpfsDb(database_url); - console.log(`Created persistent database at ${db.filename}`); - } - return db; + return new this.sqlite3.oo1.OpfsDb(database_url); } catch (error) { console.log("OPFS open error", error); throw error; @@ -202,7 +194,7 @@ export class SQLite { nByte, prepFlags, ppStmt, - pzTail + pzTail, ); } @@ -246,7 +238,7 @@ export class SQLite { pApp, xFunc, xStep, - xFinal + xFinal, ) { try { this.sqlite3.capi.sqlite3_create_function( @@ -257,7 +249,7 @@ export class SQLite { pApp, // pApp is ignored xFunc, xStep, - xFinal + xFinal, ); console.log("create function"); } catch (error) { @@ -297,9 +289,9 @@ export class SQLite { log(`Created trigger for ${table_name}`); log(row); log(`------------------------------------`); - } + }, ); - } + }, ); } catch (error) { console.log("error creating diesel trigger"); @@ -308,7 +300,7 @@ export class SQLite { } value_free(value) { - return this.sqlite3.capi.value_free(value); + return this.sqlite3.capi.sqlite3_value_free(value); } sqlite3_serialize(database, z_schema, p_size, m_flags) { @@ -317,7 +309,7 @@ export class SQLite { database, z_schema, p_size, - m_flags + m_flags, ); } catch (error) { console.log("error serializing"); @@ -331,7 +323,7 @@ export class SQLite { p_data, sz_database, sz_buffer, - m_flags + m_flags, ) { try { return this.sqlite3.capi.sqlite3_deserialize( @@ -340,7 +332,7 @@ export class SQLite { p_data, sz_database, sz_buffer, - m_flags + m_flags, ); } catch (error) { console.log("error deserializing"); @@ -349,11 +341,6 @@ export class SQLite { } sqlite3_free(_database, arg1) { - try { - this.sqlite3.capi.sqlite3_free(arg1); - } catch (error) { - console.log("error freeing value"); - throw error; - } + return this.sqlite3.capi.sqlite3_free(arg1); } } diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index 76ace8b6a..b8492f450 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -38,7 +38,7 @@ use diesel::{ }; use serialized_database::SerializedDatabase; -use crate::{ffi, get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; +use crate::{get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; // This relies on the invariant that RawConnection or Statement are never // leaked. If a reference to one of those was held on a different thread, this diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 5a7d876e1..b5dc418f0 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -182,18 +182,9 @@ impl Statement { } } - fn reset(&self) -> QueryResult<()> { + fn reset(&self) { let sqlite3 = crate::get_sqlite_unchecked(); - let rc = sqlite3.reset(&self.inner_statement); - ensure_sqlite_ok(rc, &self.raw_connection())?; - Ok(()) - } - - fn clear_bindings(&self) -> QueryResult<()> { - let sqlite3 = crate::get_sqlite_unchecked(); - let rc = sqlite3.clear_bindings(&self.inner_statement); - ensure_sqlite_ok(rc, &self.raw_connection())?; - Ok(()) + let _ = sqlite3.reset(&self.inner_statement); } fn raw_connection(&self) -> JsValue { @@ -327,8 +318,8 @@ impl<'stmt, 'query> BoundStatement<'stmt, 'query> { // we have to free the wawsm memory here not C memory so this will change significantly impl<'stmt, 'query> Drop for BoundStatement<'stmt, 'query> { fn drop(&mut self) { - self.statement.reset().unwrap(); - self.statement.clear_bindings().unwrap(); + self.statement.reset(); + // self.statement.clear_bindings().unwrap(); let wasm = ffi::get_sqlite_unchecked().inner().wasm(); for (idx, buffer) in std::mem::take(&mut self.binds_to_free) { // It's always safe to bind null values, as there is no buffer that needs to outlife something @@ -345,6 +336,9 @@ impl<'stmt, 'query> Drop for BoundStatement<'stmt, 'query> { wasm.dealloc(buffer); } } + if let Some(query) = self.query.take() { + std::mem::drop(query); + } } } diff --git a/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js b/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js index 6fe506ea1..07d4ac1f8 100644 --- a/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js +++ b/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js @@ -52,15 +52,15 @@ const wPost = (type, ...args) => postMessage({ type, payload: args }); const installAsyncProxy = function () { const toss = function (...args) { - throw new Error(args.join(" ")); + throw new Error(args.join(' ')); }; if (globalThis.window === globalThis) { toss( - "This code cannot run from the main thread.", - "Load it as a Worker from a separate Worker." + 'This code cannot run from the main thread.', + 'Load it as a Worker from a separate Worker.', ); } else if (!navigator?.storage?.getDirectory) { - toss("This API requires navigator.storage.getDirectory."); + toss('This API requires navigator.storage.getDirectory.'); } const state = Object.create(null); @@ -73,7 +73,7 @@ const installAsyncProxy = function () { 2: console.log.bind(console), }; const logImpl = (level, ...args) => { - if (state.verbose > level) loggers[level]("OPFS asyncer:", ...args); + if (state.verbose > level) loggers[level]('OPFS asyncer:', ...args); }; const log = (...args) => logImpl(2, ...args); const warn = (...args) => logImpl(1, ...args); @@ -84,8 +84,8 @@ const installAsyncProxy = function () { const __implicitLocks = new Set(); const getResolvedPath = function (filename, splitIt) { - const p = new URL(filename, "file://irrelevant").pathname; - return splitIt ? p.split("/").filter((v) => !!v) : p; + const p = new URL(filename, 'file://irrelevant').pathname; + return splitIt ? p.split('/').filter((v) => !!v) : p; }; const getDirForFilename = async function f(absFilename, createDirs = false) { @@ -102,7 +102,7 @@ const installAsyncProxy = function () { const closeSyncHandle = async (fh) => { if (fh.syncHandle) { - log("Closing sync handle for", fh.filenameAbs); + log('Closing sync handle for', fh.filenameAbs); const h = fh.syncHandle; delete fh.syncHandle; delete fh.xLock; @@ -115,7 +115,7 @@ const installAsyncProxy = function () { try { await closeSyncHandle(fh); } catch (e) { - warn("closeSyncHandleNoThrow() ignoring:", e, fh); + warn('closeSyncHandleNoThrow() ignoring:', e, fh); } }; @@ -124,7 +124,7 @@ const installAsyncProxy = function () { for (const fid of __implicitLocks) { const fh = __openFiles[fid]; await closeSyncHandleNoThrow(fh); - log("Auto-unlocked", fid, fh.filenameAbs); + log('Auto-unlocked', fid, fh.filenameAbs); } } }; @@ -138,27 +138,27 @@ const installAsyncProxy = function () { class GetSyncHandleError extends Error { constructor(errorObject, ...msg) { super( - [...msg, ": " + errorObject.name + ":", errorObject.message].join(" "), + [...msg, ': ' + errorObject.name + ':', errorObject.message].join(' '), { cause: errorObject, - } + }, ); - this.name = "GetSyncHandleError"; + this.name = 'GetSyncHandleError'; } } GetSyncHandleError.convertRc = (e, rc) => { if (e instanceof GetSyncHandleError) { if ( - e.cause.name === "NoModificationAllowedError" || - (e.cause.name === "DOMException" && - 0 === e.cause.message.indexOf("Access Handles cannot")) + e.cause.name === 'NoModificationAllowedError' || + (e.cause.name === 'DOMException' && + 0 === e.cause.message.indexOf('Access Handles cannot')) ) { return state.sq3Codes.SQLITE_BUSY; - } else if ("NotFoundError" === e.cause.name) { + } else if ('NotFoundError' === e.cause.name) { return state.sq3Codes.SQLITE_CANTOPEN; } - } else if ("NotFoundError" === e?.name) { + } else if ('NotFoundError' === e?.name) { return state.sq3Codes.SQLITE_CANTOPEN; } return rc; @@ -167,7 +167,7 @@ const installAsyncProxy = function () { const getSyncHandle = async (fh, opName) => { if (!fh.syncHandle) { const t = performance.now(); - log("Acquiring sync handle for", fh.filenameAbs); + log('Acquiring sync handle for', fh.filenameAbs); const maxTries = 6, msBase = state.asyncIdleWaitTime * 2; let i = 1, @@ -180,39 +180,39 @@ const installAsyncProxy = function () { if (i === maxTries) { throw new GetSyncHandleError( e, - "Error getting sync handle for", - opName + "().", + 'Error getting sync handle for', + opName + '().', maxTries, - "attempts failed.", - fh.filenameAbs + 'attempts failed.', + fh.filenameAbs, ); } warn( - "Error getting sync handle for", - opName + "(). Waiting", + 'Error getting sync handle for', + opName + '(). Waiting', ms, - "ms and trying again.", + 'ms and trying again.', fh.filenameAbs, - e + e, ); Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms); } } log( - "Got", - opName + "() sync handle for", + 'Got', + opName + '() sync handle for', fh.filenameAbs, - "in", + 'in', performance.now() - t, - "ms" + 'ms', ); if (!fh.xLock) { __implicitLocks.add(fh.fid); log( - "Acquired implicit lock for", - opName + "()", + 'Acquired implicit lock for', + opName + '()', fh.fid, - fh.filenameAbs + fh.filenameAbs, ); } } @@ -220,31 +220,31 @@ const installAsyncProxy = function () { }; const storeAndNotify = (opName, value) => { - log(opName + "() => notify(", value, ")"); + log(opName + '() => notify(', value, ')'); Atomics.store(state.sabOPView, state.opIds.rc, value); Atomics.notify(state.sabOPView, state.opIds.rc); }; const affirmNotRO = function (opName, fh) { - if (fh.readOnly) toss(opName + "(): File is read-only: " + fh.filenameAbs); + if (fh.readOnly) toss(opName + '(): File is read-only: ' + fh.filenameAbs); }; let flagAsyncShutdown = false; const vfsAsyncImpls = { - "opfs-async-shutdown": async () => { + 'opfs-async-shutdown': async () => { flagAsyncShutdown = true; - storeAndNotify("opfs-async-shutdown", 0); + storeAndNotify('opfs-async-shutdown', 0); }, mkdir: async (dirname) => { let rc = 0; try { - await getDirForFilename(dirname + "/filepart", true); + await getDirForFilename(dirname + '/filepart', true); } catch (e) { state.s11n.storeException(2, e); rc = state.sq3Codes.SQLITE_IOERR; } - storeAndNotify("mkdir", rc); + storeAndNotify('mkdir', rc); }, xAccess: async (filename) => { let rc = 0; @@ -255,10 +255,10 @@ const installAsyncProxy = function () { state.s11n.storeException(2, e); rc = state.sq3Codes.SQLITE_IOERR; } - storeAndNotify("xAccess", rc); + storeAndNotify('xAccess', rc); }, xClose: async function (fid) { - const opName = "xClose"; + const opName = 'xClose'; __implicitLocks.delete(fid); const fh = __openFiles[fid]; let rc = 0; @@ -269,7 +269,7 @@ const installAsyncProxy = function () { try { await fh.dirHandle.removeEntry(fh.filenamePart); } catch (e) { - warn("Ignoring dirHandle.removeEntry() failure of", fh, e); + warn('Ignoring dirHandle.removeEntry() failure of', fh, e); } } } else { @@ -280,7 +280,7 @@ const installAsyncProxy = function () { }, xDelete: async function (...args) { const rc = await vfsAsyncImpls.xDeleteNoWait(...args); - storeAndNotify("xDelete", rc); + storeAndNotify('xDelete', rc); }, xDeleteNoWait: async function (filename, syncDir = 0, recursive = false) { let rc = 0; @@ -293,7 +293,7 @@ const installAsyncProxy = function () { recursive = false; filename = getResolvedPath(filename, true); filename.pop(); - filename = filename.join("/"); + filename = filename.join('/'); } } catch (e) { state.s11n.storeException(2, e); @@ -305,14 +305,14 @@ const installAsyncProxy = function () { const fh = __openFiles[fid]; let rc = 0; try { - const sz = await (await getSyncHandle(fh, "xFileSize")).getSize(); + const sz = await (await getSyncHandle(fh, 'xFileSize')).getSize(); state.s11n.serialize(Number(sz)); } catch (e) { state.s11n.storeException(1, e); rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR); } await releaseImplicitLock(fh); - storeAndNotify("xFileSize", rc); + storeAndNotify('xFileSize', rc); }, xLock: async function (fid, lockType) { const fh = __openFiles[fid]; @@ -321,21 +321,21 @@ const installAsyncProxy = function () { fh.xLock = lockType; if (!fh.syncHandle) { try { - await getSyncHandle(fh, "xLock"); + await getSyncHandle(fh, 'xLock'); __implicitLocks.delete(fid); } catch (e) { state.s11n.storeException(1, e); rc = GetSyncHandleError.convertRc( e, - state.sq3Codes.SQLITE_IOERR_LOCK + state.sq3Codes.SQLITE_IOERR_LOCK, ); fh.xLock = oldLockType; } } - storeAndNotify("xLock", rc); + storeAndNotify('xLock', rc); }, xOpen: async function (fid, filename, flags, opfsFlags) { - const opName = "xOpen"; + const opName = 'xOpen'; const create = state.sq3Codes.SQLITE_OPEN_CREATE & flags; try { let hDir, filenamePart; @@ -380,21 +380,21 @@ const installAsyncProxy = function () { nRead; const fh = __openFiles[fid]; try { - nRead = (await getSyncHandle(fh, "xRead")).read( + nRead = (await getSyncHandle(fh, 'xRead')).read( fh.sabView.subarray(0, n), - { at: Number(offset64) } + { at: Number(offset64) }, ); if (nRead < n) { fh.sabView.fill(0, nRead, n); rc = state.sq3Codes.SQLITE_IOERR_SHORT_READ; } } catch (e) { - error("xRead() failed", e, fh); + error('xRead() failed', e, fh); state.s11n.storeException(1, e); rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_READ); } await releaseImplicitLock(fh); - storeAndNotify("xRead", rc); + storeAndNotify('xRead', rc); }, xSync: async function (fid, flags) { const fh = __openFiles[fid]; @@ -407,24 +407,24 @@ const installAsyncProxy = function () { rc = state.sq3Codes.SQLITE_IOERR_FSYNC; } } - storeAndNotify("xSync", rc); + storeAndNotify('xSync', rc); }, xTruncate: async function (fid, size) { let rc = 0; const fh = __openFiles[fid]; try { - affirmNotRO("xTruncate", fh); - await (await getSyncHandle(fh, "xTruncate")).truncate(size); + affirmNotRO('xTruncate', fh); + await (await getSyncHandle(fh, 'xTruncate')).truncate(size); } catch (e) { - error("xTruncate():", e, fh); + error('xTruncate():', e, fh); state.s11n.storeException(2, e); rc = GetSyncHandleError.convertRc( e, - state.sq3Codes.SQLITE_IOERR_TRUNCATE + state.sq3Codes.SQLITE_IOERR_TRUNCATE, ); } await releaseImplicitLock(fh); - storeAndNotify("xTruncate", rc); + storeAndNotify('xTruncate', rc); }, xUnlock: async function (fid, lockType) { let rc = 0; @@ -437,68 +437,68 @@ const installAsyncProxy = function () { rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; } } - storeAndNotify("xUnlock", rc); + storeAndNotify('xUnlock', rc); }, xWrite: async function (fid, n, offset64) { let rc; const fh = __openFiles[fid]; try { - affirmNotRO("xWrite", fh); + affirmNotRO('xWrite', fh); rc = n === - (await getSyncHandle(fh, "xWrite")).write(fh.sabView.subarray(0, n), { + (await getSyncHandle(fh, 'xWrite')).write(fh.sabView.subarray(0, n), { at: Number(offset64), }) ? 0 : state.sq3Codes.SQLITE_IOERR_WRITE; } catch (e) { - error("xWrite():", e, fh); + error('xWrite():', e, fh); state.s11n.storeException(1, e); rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_WRITE); } await releaseImplicitLock(fh); - storeAndNotify("xWrite", rc); + storeAndNotify('xWrite', rc); }, }; const initS11n = () => { if (state.s11n) return state.s11n; const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder("utf-8"), + textEncoder = new TextEncoder('utf-8'), viewU8 = new Uint8Array( state.sabIO, state.sabS11nOffset, - state.sabS11nSize + state.sabS11nSize, ), viewDV = new DataView( state.sabIO, state.sabS11nOffset, - state.sabS11nSize + state.sabS11nSize, ); state.s11n = Object.create(null); const TypeIds = Object.create(null); TypeIds.number = { id: 1, size: 8, - getter: "getFloat64", - setter: "setFloat64", + getter: 'getFloat64', + setter: 'setFloat64', }; TypeIds.bigint = { id: 2, size: 8, - getter: "getBigInt64", - setter: "setBigInt64", + getter: 'getBigInt64', + setter: 'setBigInt64', }; TypeIds.boolean = { id: 3, size: 4, - getter: "getInt32", - setter: "setInt32", + getter: 'getInt32', + setter: 'setInt32', }; TypeIds.string = { id: 4 }; const getTypeId = (v) => TypeIds[typeof v] || - toss("Maintenance required: this value type cannot be serialized.", v); + toss('Maintenance required: this value type cannot be serialized.', v); const getTypeIdById = (tid) => { switch (tid) { case TypeIds.number.id: @@ -510,7 +510,7 @@ const installAsyncProxy = function () { case TypeIds.string.id: return TypeIds.string; default: - toss("Invalid type ID:", tid); + toss('Invalid type ID:', tid); } }; state.s11n.deserialize = function (clear = false) { @@ -574,7 +574,7 @@ const installAsyncProxy = function () { state.s11n.storeException = state.asyncS11nExceptions ? (priority, e) => { if (priority <= state.asyncS11nExceptions) { - state.s11n.serialize([e.name, ": ", e.message].join("")); + state.s11n.serialize([e.name, ': ', e.message].join('')); } } : () => {}; @@ -595,12 +595,12 @@ const installAsyncProxy = function () { while (!flagAsyncShutdown) { try { if ( - "not-equal" !== + 'not-equal' !== Atomics.wait( state.sabOPView, state.opIds.whichOp, 0, - state.asyncIdleWaitTime + state.asyncIdleWaitTime, ) ) { await releaseImplicitLocks(); @@ -609,13 +609,13 @@ const installAsyncProxy = function () { const opId = Atomics.load(state.sabOPView, state.opIds.whichOp); Atomics.store(state.sabOPView, state.opIds.whichOp, 0); const hnd = - opHandlers[opId] ?? toss("No waitLoop handler for whichOp #", opId); + opHandlers[opId] ?? toss('No waitLoop handler for whichOp #', opId); const args = state.s11n.deserialize(true) || []; if (hnd.f) await hnd.f(...args); - else error("Missing callback for opId", opId); + else error('Missing callback for opId', opId); } catch (e) { - error("in waitLoop():", e); + error('in waitLoop():', e); } } }; @@ -626,7 +626,7 @@ const installAsyncProxy = function () { state.rootDir = d; globalThis.onmessage = function ({ data }) { switch (data.type) { - case "opfs-async-init": { + case 'opfs-async-init': { const opt = data.args; for (const k in opt) state[k] = opt[k]; state.verbose = opt.verbose ?? 1; @@ -634,28 +634,28 @@ const installAsyncProxy = function () { state.sabFileBufView = new Uint8Array( state.sabIO, 0, - state.fileBufferSize + state.fileBufferSize, ); state.sabS11nView = new Uint8Array( state.sabIO, state.sabS11nOffset, - state.sabS11nSize + state.sabS11nSize, ); Object.keys(vfsAsyncImpls).forEach((k) => { if (!Number.isFinite(state.opIds[k])) { - toss("Maintenance required: missing state.opIds[", k, "]"); + toss('Maintenance required: missing state.opIds[', k, ']'); } }); initS11n(); - log("init state", state); - wPost("opfs-async-inited"); + log('init state', state); + wPost('opfs-async-inited'); waitLoop(); break; } - case "opfs-async-restart": + case 'opfs-async-restart': if (flagAsyncShutdown) { warn( - "Restarting after opfs-async-shutdown. Might or might not work." + 'Restarting after opfs-async-shutdown. Might or might not work.', ); flagAsyncShutdown = false; waitLoop(); @@ -663,21 +663,21 @@ const installAsyncProxy = function () { break; } }; - wPost("opfs-async-loaded"); + wPost('opfs-async-loaded'); }) - .catch((e) => error("error initializing OPFS asyncer:", e)); + .catch((e) => error('error initializing OPFS asyncer:', e)); }; if (!globalThis.SharedArrayBuffer) { wPost( - "opfs-unavailable", - "Missing SharedArrayBuffer API.", - "The server must emit the COOP/COEP response headers to enable that." + 'opfs-unavailable', + 'Missing SharedArrayBuffer API.', + 'The server must emit the COOP/COEP response headers to enable that.', ); } else if (!globalThis.Atomics) { wPost( - "opfs-unavailable", - "Missing Atomics API.", - "The server must emit the COOP/COEP response headers to enable that." + 'opfs-unavailable', + 'Missing Atomics API.', + 'The server must emit the COOP/COEP response headers to enable that.', ); } else if ( !globalThis.FileSystemHandle || @@ -686,7 +686,7 @@ if (!globalThis.SharedArrayBuffer) { !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || !navigator?.storage?.getDirectory ) { - wPost("opfs-unavailable", "Missing required OPFS APIs."); + wPost('opfs-unavailable', 'Missing required OPFS APIs.'); } else { installAsyncProxy(); } diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js index 349b332bc..cd5904897 100644 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js @@ -40,10 +40,10 @@ var sqlite3InitModule = (() => { var sqlite3InitModule = config || {}; var Module = - typeof sqlite3InitModule != "undefined" ? sqlite3InitModule : {}; + typeof sqlite3InitModule != 'undefined' ? sqlite3InitModule : {}; var readyPromiseResolve, readyPromiseReject; - Module["ready"] = new Promise(function (resolve, reject) { + Module['ready'] = new Promise(function (resolve, reject) { readyPromiseResolve = resolve; readyPromiseReject = reject; }); @@ -55,23 +55,23 @@ var sqlite3InitModule = (() => { }); delete globalThis.sqlite3InitModuleState; sqlite3InitModuleState.debugModule( - "globalThis.location =", - globalThis.location + 'globalThis.location =', + globalThis.location, ); - const xNameOfInstantiateWasm = "emscripten-bug-17951"; + const xNameOfInstantiateWasm = 'emscripten-bug-17951'; Module[xNameOfInstantiateWasm] = function callee(imports, onSuccess) { imports.env.foo = function () {}; const uri = Module.locateFile( callee.uri, - "undefined" === typeof scriptDirectory ? "" : scriptDirectory + 'undefined' === typeof scriptDirectory ? '' : scriptDirectory, ); - sqlite3InitModuleState.debugModule("instantiateWasm() uri =", uri); - const wfetch = () => fetch(uri, { credentials: "same-origin" }); + sqlite3InitModuleState.debugModule('instantiateWasm() uri =', uri); + const wfetch = () => fetch(uri, { credentials: 'same-origin' }); const loadWasm = WebAssembly.instantiateStreaming ? async () => { return WebAssembly.instantiateStreaming(wfetch(), imports).then( - (arg) => onSuccess(arg.instance, arg.module) + (arg) => onSuccess(arg.instance, arg.module), ); } : async () => { @@ -84,22 +84,22 @@ var sqlite3InitModule = (() => { return {}; }; - Module[xNameOfInstantiateWasm].uri = "sqlite3.wasm"; + Module[xNameOfInstantiateWasm].uri = 'sqlite3.wasm'; var moduleOverrides = Object.assign({}, Module); - var thisProgram = "./this.program"; + var thisProgram = './this.program'; - var ENVIRONMENT_IS_WEB = typeof window == "object"; - var ENVIRONMENT_IS_WORKER = typeof importScripts == "function"; + var ENVIRONMENT_IS_WEB = typeof window == 'object'; + var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'; - typeof process == "object" && - typeof process.versions == "object" && - typeof process.versions.node == "string"; + typeof process == 'object' && + typeof process.versions == 'object' && + typeof process.versions.node == 'string'; - var scriptDirectory = ""; + var scriptDirectory = ''; function locateFile(path) { - if (Module["locateFile"]) { - return Module["locateFile"](path, scriptDirectory); + if (Module['locateFile']) { + return Module['locateFile'](path, scriptDirectory); } return scriptDirectory + path; } @@ -109,7 +109,7 @@ var sqlite3InitModule = (() => { if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { if (ENVIRONMENT_IS_WORKER) { scriptDirectory = self.location.href; - } else if (typeof document != "undefined" && document.currentScript) { + } else if (typeof document != 'undefined' && document.currentScript) { scriptDirectory = document.currentScript.src; } @@ -117,19 +117,19 @@ var sqlite3InitModule = (() => { scriptDirectory = _scriptDir; } - if (scriptDirectory.indexOf("blob:") !== 0) { + if (scriptDirectory.indexOf('blob:') !== 0) { scriptDirectory = scriptDirectory.substr( 0, - scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1 + scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1, ); } else { - scriptDirectory = ""; + scriptDirectory = ''; } { read_ = (url) => { var xhr = new XMLHttpRequest(); - xhr.open("GET", url, false); + xhr.open('GET', url, false); xhr.send(null); return xhr.responseText; }; @@ -137,8 +137,8 @@ var sqlite3InitModule = (() => { if (ENVIRONMENT_IS_WORKER) { readBinary = (url) => { var xhr = new XMLHttpRequest(); - xhr.open("GET", url, false); - xhr.responseType = "arraybuffer"; + xhr.open('GET', url, false); + xhr.responseType = 'arraybuffer'; xhr.send(null); return new Uint8Array(xhr.response); }; @@ -146,8 +146,8 @@ var sqlite3InitModule = (() => { readAsync = (url, onload, onerror) => { var xhr = new XMLHttpRequest(); - xhr.open("GET", url, true); - xhr.responseType = "arraybuffer"; + xhr.open('GET', url, true); + xhr.responseType = 'arraybuffer'; xhr.onload = () => { if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { onload(xhr.response); @@ -161,25 +161,25 @@ var sqlite3InitModule = (() => { } } - var out = Module["print"] || console.log.bind(console); - var err = Module["printErr"] || console.warn.bind(console); + var out = Module['print'] || console.log.bind(console); + var err = Module['printErr'] || console.warn.bind(console); Object.assign(Module, moduleOverrides); moduleOverrides = null; - if (Module["arguments"]) Module["arguments"]; + if (Module['arguments']) Module['arguments']; - if (Module["thisProgram"]) thisProgram = Module["thisProgram"]; + if (Module['thisProgram']) thisProgram = Module['thisProgram']; - if (Module["quit"]) Module["quit"]; + if (Module['quit']) Module['quit']; var wasmBinary; - if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"]; - Module["noExitRuntime"] || true; + if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; + Module['noExitRuntime'] || true; - if (typeof WebAssembly != "object") { - abort("no native wasm support detected"); + if (typeof WebAssembly != 'object') { + abort('no native wasm support detected'); } var wasmMemory; @@ -193,7 +193,7 @@ var sqlite3InitModule = (() => { } var UTF8Decoder = - typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : undefined; + typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) { var endIdx = idx + maxBytesToRead; @@ -204,7 +204,7 @@ var sqlite3InitModule = (() => { if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); } - var str = ""; + var str = ''; while (idx < endPtr) { var u0 = heapOrArray[idx++]; @@ -234,7 +234,7 @@ var sqlite3InitModule = (() => { var ch = u0 - 0x10000; str += String.fromCharCode( 0xd800 | (ch >> 10), - 0xdc00 | (ch & 0x3ff) + 0xdc00 | (ch & 0x3ff), ); } } @@ -242,7 +242,7 @@ var sqlite3InitModule = (() => { } function UTF8ToString(ptr, maxBytesToRead) { - return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ""; + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; } function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { @@ -303,26 +303,30 @@ var sqlite3InitModule = (() => { return len; } - var HEAP8, HEAPU8, HEAP16, HEAP32, HEAPU32; + var HEAP8, + HEAPU8, + HEAP16, + HEAP32, + HEAPU32; function updateMemoryViews() { var b = wasmMemory.buffer; - Module["HEAP8"] = HEAP8 = new Int8Array(b); - Module["HEAP16"] = HEAP16 = new Int16Array(b); - Module["HEAP32"] = HEAP32 = new Int32Array(b); - Module["HEAPU8"] = HEAPU8 = new Uint8Array(b); - Module["HEAPU16"] = new Uint16Array(b); - Module["HEAPU32"] = HEAPU32 = new Uint32Array(b); - Module["HEAPF32"] = new Float32Array(b); - Module["HEAPF64"] = new Float64Array(b); - Module["HEAP64"] = new BigInt64Array(b); - Module["HEAPU64"] = new BigUint64Array(b); + Module['HEAP8'] = HEAP8 = new Int8Array(b); + Module['HEAP16'] = HEAP16 = new Int16Array(b); + Module['HEAP32'] = HEAP32 = new Int32Array(b); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); + Module['HEAPU16'] = new Uint16Array(b); + Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); + Module['HEAPF32'] = new Float32Array(b); + Module['HEAPF64'] = new Float64Array(b); + Module['HEAP64'] = new BigInt64Array(b); + Module['HEAPU64'] = new BigUint64Array(b); } - var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 16777216; + var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216; - if (Module["wasmMemory"]) { - wasmMemory = Module["wasmMemory"]; + if (Module['wasmMemory']) { + wasmMemory = Module['wasmMemory']; } else { wasmMemory = new WebAssembly.Memory({ initial: INITIAL_MEMORY / 65536, @@ -340,11 +344,11 @@ var sqlite3InitModule = (() => { var __ATPOSTRUN__ = []; function preRun() { - if (Module["preRun"]) { - if (typeof Module["preRun"] == "function") - Module["preRun"] = [Module["preRun"]]; - while (Module["preRun"].length) { - addOnPreRun(Module["preRun"].shift()); + if (Module['preRun']) { + if (typeof Module['preRun'] == 'function') + Module['preRun'] = [Module['preRun']]; + while (Module['preRun'].length) { + addOnPreRun(Module['preRun'].shift()); } } @@ -352,17 +356,18 @@ var sqlite3InitModule = (() => { } function initRuntime() { - if (!Module["noFSInit"] && !FS.init.initialized) FS.init(); + + if (!Module['noFSInit'] && !FS.init.initialized) FS.init(); FS.ignorePermissions = false; callRuntimeCallbacks(__ATINIT__); } function postRun() { - if (Module["postRun"]) { - if (typeof Module["postRun"] == "function") - Module["postRun"] = [Module["postRun"]]; - while (Module["postRun"].length) { - addOnPostRun(Module["postRun"].shift()); + if (Module['postRun']) { + if (typeof Module['postRun'] == 'function') + Module['postRun'] = [Module['postRun']]; + while (Module['postRun'].length) { + addOnPostRun(Module['postRun'].shift()); } } @@ -391,16 +396,16 @@ var sqlite3InitModule = (() => { function addRunDependency(id) { runDependencies++; - if (Module["monitorRunDependencies"]) { - Module["monitorRunDependencies"](runDependencies); + if (Module['monitorRunDependencies']) { + Module['monitorRunDependencies'](runDependencies); } } function removeRunDependency(id) { runDependencies--; - if (Module["monitorRunDependencies"]) { - Module["monitorRunDependencies"](runDependencies); + if (Module['monitorRunDependencies']) { + Module['monitorRunDependencies'](runDependencies); } if (runDependencies == 0) { @@ -413,17 +418,17 @@ var sqlite3InitModule = (() => { } function abort(what) { - if (Module["onAbort"]) { - Module["onAbort"](what); + if (Module['onAbort']) { + Module['onAbort'](what); } - what = "Aborted(" + what + ")"; + what = 'Aborted(' + what + ')'; err(what); ABORT = true; - what += ". Build with -sASSERTIONS for more info."; + what += '. Build with -sASSERTIONS for more info.'; var e = new WebAssembly.RuntimeError(what); @@ -432,20 +437,20 @@ var sqlite3InitModule = (() => { throw e; } - var dataURIPrefix = "data:application/octet-stream;base64,"; + var dataURIPrefix = 'data:application/octet-stream;base64,'; function isDataURI(filename) { return filename.startsWith(dataURIPrefix); } var wasmBinaryFile; - if (Module["locateFile"]) { - wasmBinaryFile = "sqlite3.wasm"; + if (Module['locateFile']) { + wasmBinaryFile = 'sqlite3.wasm'; if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(wasmBinaryFile); } } else { - wasmBinaryFile = new URL("sqlite3.wasm", import.meta.url).href; + wasmBinaryFile = new URL('sqlite3.wasm', import.meta.url).href; } function getBinary(file) { @@ -456,7 +461,7 @@ var sqlite3InitModule = (() => { if (readBinary) { return readBinary(file); } - throw "both async and sync fetching of the wasm failed"; + throw 'both async and sync fetching of the wasm failed'; } catch (err) { abort(err); } @@ -464,15 +469,15 @@ var sqlite3InitModule = (() => { function getBinaryPromise() { if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { - if (typeof fetch == "function") { - return fetch(wasmBinaryFile, { credentials: "same-origin" }) + if (typeof fetch == 'function') { + return fetch(wasmBinaryFile, { credentials: 'same-origin' }) .then(function (response) { - if (!response["ok"]) { + if (!response['ok']) { throw ( "failed to load wasm binary file at '" + wasmBinaryFile + "'" ); } - return response["arrayBuffer"](); + return response['arrayBuffer'](); }) .catch(function () { return getBinary(wasmBinaryFile); @@ -494,11 +499,11 @@ var sqlite3InitModule = (() => { function receiveInstance(instance, module) { var exports = instance.exports; - Module["asm"] = exports; + Module['asm'] = exports; - Module["asm"]["__indirect_function_table"]; + Module['asm']['__indirect_function_table']; - addOnInit(Module["asm"]["__wasm_call_ctors"]); + addOnInit(Module['asm']['__wasm_call_ctors']); removeRunDependency(); } @@ -506,7 +511,7 @@ var sqlite3InitModule = (() => { addRunDependency(); function receiveInstantiationResult(result) { - receiveInstance(result["instance"]); + receiveInstance(result['instance']); } function instantiateArrayBuffer(receiver) { @@ -518,7 +523,7 @@ var sqlite3InitModule = (() => { return instance; }) .then(receiver, function (reason) { - err("failed to asynchronously prepare wasm: " + reason); + err('failed to asynchronously prepare wasm: ' + reason); abort(reason); }); @@ -527,32 +532,32 @@ var sqlite3InitModule = (() => { function instantiateAsync() { if ( !wasmBinary && - typeof WebAssembly.instantiateStreaming == "function" && + typeof WebAssembly.instantiateStreaming == 'function' && !isDataURI(wasmBinaryFile) && - typeof fetch == "function" + typeof fetch == 'function' ) { - return fetch(wasmBinaryFile, { credentials: "same-origin" }).then( + return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then( function (response) { var result = WebAssembly.instantiateStreaming(response, info); return result.then(receiveInstantiationResult, function (reason) { - err("wasm streaming compile failed: " + reason); - err("falling back to ArrayBuffer instantiation"); + err('wasm streaming compile failed: ' + reason); + err('falling back to ArrayBuffer instantiation'); return instantiateArrayBuffer(receiveInstantiationResult); }); - } + }, ); } else { return instantiateArrayBuffer(receiveInstantiationResult); } } - if (Module["instantiateWasm"]) { + if (Module['instantiateWasm']) { try { - var exports = Module["instantiateWasm"](info, receiveInstance); + var exports = Module['instantiateWasm'](info, receiveInstance); return exports; } catch (e) { - err("Module.instantiateWasm callback failed with error: " + e); + err('Module.instantiateWasm callback failed with error: ' + e); readyPromiseReject(e); } @@ -572,7 +577,7 @@ var sqlite3InitModule = (() => { } var PATH = { - isAbs: (path) => path.charAt(0) === "/", + isAbs: (path) => path.charAt(0) === '/', splitPath: (filename) => { var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; @@ -582,9 +587,9 @@ var sqlite3InitModule = (() => { var up = 0; for (var i = parts.length - 1; i >= 0; i--) { var last = parts[i]; - if (last === ".") { + if (last === '.') { parts.splice(i, 1); - } else if (last === "..") { + } else if (last === '..') { parts.splice(i, 1); up++; } else if (up) { @@ -595,33 +600,33 @@ var sqlite3InitModule = (() => { if (allowAboveRoot) { for (; up; up--) { - parts.unshift(".."); + parts.unshift('..'); } } return parts; }, normalize: (path) => { var isAbsolute = PATH.isAbs(path), - trailingSlash = path.substr(-1) === "/"; + trailingSlash = path.substr(-1) === '/'; path = PATH.normalizeArray( - path.split("/").filter((p) => !!p), - !isAbsolute - ).join("/"); + path.split('/').filter((p) => !!p), + !isAbsolute, + ).join('/'); if (!path && !isAbsolute) { - path = "."; + path = '.'; } if (path && trailingSlash) { - path += "/"; + path += '/'; } - return (isAbsolute ? "/" : "") + path; + return (isAbsolute ? '/' : '') + path; }, dirname: (path) => { var result = PATH.splitPath(path), root = result[0], dir = result[1]; if (!root && !dir) { - return "."; + return '.'; } if (dir) { dir = dir.substr(0, dir.length - 1); @@ -629,56 +634,56 @@ var sqlite3InitModule = (() => { return root + dir; }, basename: (path) => { - if (path === "/") return "/"; + if (path === '/') return '/'; path = PATH.normalize(path); - path = path.replace(/\/$/, ""); - var lastSlash = path.lastIndexOf("/"); + path = path.replace(/\/$/, ''); + var lastSlash = path.lastIndexOf('/'); if (lastSlash === -1) return path; return path.substr(lastSlash + 1); }, join: function () { var paths = Array.prototype.slice.call(arguments); - return PATH.normalize(paths.join("/")); + return PATH.normalize(paths.join('/')); }, join2: (l, r) => { - return PATH.normalize(l + "/" + r); + return PATH.normalize(l + '/' + r); }, }; function getRandomDevice() { if ( - typeof crypto == "object" && - typeof crypto["getRandomValues"] == "function" + typeof crypto == 'object' && + typeof crypto['getRandomValues'] == 'function' ) { var randomBuffer = new Uint8Array(1); return () => { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; }; - } else return () => abort("randomDevice"); + } else return () => abort('randomDevice'); } var PATH_FS = { resolve: function () { - var resolvedPath = "", + var resolvedPath = '', resolvedAbsolute = false; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { var path = i >= 0 ? arguments[i] : FS.cwd(); - if (typeof path != "string") { - throw new TypeError("Arguments to path.resolve must be strings"); + if (typeof path != 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); } else if (!path) { - return ""; + return ''; } - resolvedPath = path + "/" + resolvedPath; + resolvedPath = path + '/' + resolvedPath; resolvedAbsolute = PATH.isAbs(path); } resolvedPath = PATH.normalizeArray( - resolvedPath.split("/").filter((p) => !!p), - !resolvedAbsolute - ).join("/"); - return (resolvedAbsolute ? "/" : "") + resolvedPath || "."; + resolvedPath.split('/').filter((p) => !!p), + !resolvedAbsolute, + ).join('/'); + return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'; }, relative: (from, to) => { from = PATH_FS.resolve(from).substr(1); @@ -686,17 +691,17 @@ var sqlite3InitModule = (() => { function trim(arr) { var start = 0; for (; start < arr.length; start++) { - if (arr[start] !== "") break; + if (arr[start] !== '') break; } var end = arr.length - 1; for (; end >= 0; end--) { - if (arr[end] !== "") break; + if (arr[end] !== '') break; } if (start > end) return []; return arr.slice(start, end - start + 1); } - var fromParts = trim(from.split("/")); - var toParts = trim(to.split("/")); + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); var length = Math.min(fromParts.length, toParts.length); var samePartsLength = length; for (var i = 0; i < length; i++) { @@ -707,10 +712,10 @@ var sqlite3InitModule = (() => { } var outputParts = []; for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push(".."); + outputParts.push('..'); } outputParts = outputParts.concat(toParts.slice(samePartsLength)); - return outputParts.join("/"); + return outputParts.join('/'); }, }; @@ -721,7 +726,7 @@ var sqlite3InitModule = (() => { stringy, u8array, 0, - u8array.length + u8array.length, ); u8array.length = numBytesWritten; return u8array; @@ -795,17 +800,17 @@ var sqlite3InitModule = (() => { if (!tty.input.length) { var result = null; if ( - typeof window != "undefined" && - typeof window.prompt == "function" + typeof window != 'undefined' && + typeof window.prompt == 'function' ) { - result = window.prompt("Input: "); + result = window.prompt('Input: '); if (result !== null) { - result += "\n"; + result += '\n'; } - } else if (typeof readline == "function") { + } else if (typeof readline == 'function') { result = readline(); if (result !== null) { - result += "\n"; + result += '\n'; } } if (!result) { @@ -865,7 +870,7 @@ var sqlite3InitModule = (() => { var MEMFS = { ops_table: null, mount: function (mount) { - return MEMFS.createNode(null, "/", 16384 | 511, 0); + return MEMFS.createNode(null, '/', 16384 | 511, 0); }, createNode: function (parent, name, mode, dev) { if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { @@ -961,7 +966,7 @@ var sqlite3InitModule = (() => { newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> - 0 + 0, ); if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); var oldContents = node.contents; @@ -979,7 +984,7 @@ var sqlite3InitModule = (() => { node.contents = new Uint8Array(newSize); if (oldContents) { node.contents.set( - oldContents.subarray(0, Math.min(newSize, node.usedBytes)) + oldContents.subarray(0, Math.min(newSize, node.usedBytes)), ); } node.usedBytes = newSize; @@ -1063,7 +1068,7 @@ var sqlite3InitModule = (() => { parent.timestamp = Date.now(); }, readdir: function (node) { - var entries = [".", ".."]; + var entries = ['.', '..']; for (var key in node.contents) { if (!node.contents.hasOwnProperty(key)) { continue; @@ -1118,7 +1123,7 @@ var sqlite3InitModule = (() => { } else if (position + length <= node.usedBytes) { node.contents.set( buffer.subarray(offset, offset + length), - position + position, ); return length; } @@ -1128,7 +1133,7 @@ var sqlite3InitModule = (() => { if (node.contents.subarray && buffer.subarray) { node.contents.set( buffer.subarray(offset, offset + length), - position + position, ); } else { for (var i = 0; i < length; i++) { @@ -1156,7 +1161,7 @@ var sqlite3InitModule = (() => { MEMFS.expandFileStorage(stream.node, offset + length); stream.node.usedBytes = Math.max( stream.node.usedBytes, - offset + length + offset + length, ); }, mmap: function (stream, length, position, prot, flags) { @@ -1178,7 +1183,7 @@ var sqlite3InitModule = (() => { contents = Array.prototype.slice.call( contents, position, - position + length + position + length, ); } } @@ -1200,13 +1205,13 @@ var sqlite3InitModule = (() => { }; function asyncLoad(url, onload, onerror, noRunDep) { - var dep = getUniqueRunDependency("al " + url); + var dep = getUniqueRunDependency('al ' + url) ; readAsync( url, (arrayBuffer) => { assert( arrayBuffer, - 'Loading data file "' + url + '" failed (no arrayBuffer).' + 'Loading data file "' + url + '" failed (no arrayBuffer).', ); onload(new Uint8Array(arrayBuffer)); if (dep) removeRunDependency(); @@ -1217,7 +1222,7 @@ var sqlite3InitModule = (() => { } else { throw 'Loading data file "' + url + '" failed.'; } - } + }, ); if (dep) addRunDependency(); } @@ -1229,7 +1234,7 @@ var sqlite3InitModule = (() => { streams: [], nextInode: 1, nameTable: null, - currentPath: "/", + currentPath: '/', initialized: false, ignorePermissions: true, ErrnoError: null, @@ -1239,7 +1244,7 @@ var sqlite3InitModule = (() => { lookupPath: (path, opts = {}) => { path = PATH_FS.resolve(path); - if (!path) return { path: "", node: null }; + if (!path) return { path: '', node: null }; var defaults = { follow_mount: true, @@ -1251,10 +1256,10 @@ var sqlite3InitModule = (() => { throw new FS.ErrnoError(32); } - var parts = path.split("/").filter((p) => !!p); + var parts = path.split('/').filter((p) => !!p); var current = FS.root; - var current_path = "/"; + var current_path = '/'; for (var i = 0; i < parts.length; i++) { var islast = i === parts.length - 1; @@ -1297,11 +1302,11 @@ var sqlite3InitModule = (() => { if (FS.isRoot(node)) { var mount = node.mount.mountpoint; if (!path) return mount; - return mount[mount.length - 1] !== "/" - ? mount + "/" + path + return mount[mount.length - 1] !== '/' + ? mount + '/' + path : mount + path; } - path = path ? node.name + "/" + path : node.name; + path = path ? node.name + '/' + path : node.name; node = node.parent; } }, @@ -1385,18 +1390,18 @@ var sqlite3InitModule = (() => { isSocket: (mode) => { return (mode & 49152) === 49152; }, - flagModes: { r: 0, "r+": 2, w: 577, "w+": 578, a: 1089, "a+": 1090 }, + flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 }, modeStringToFlags: (str) => { var flags = FS.flagModes[str]; - if (typeof flags == "undefined") { - throw new Error("Unknown file open mode: " + str); + if (typeof flags == 'undefined') { + throw new Error('Unknown file open mode: ' + str); } return flags; }, flagsToPermissionString: (flag) => { - var perms = ["r", "w", "rw"][flag & 3]; + var perms = ['r', 'w', 'rw'][flag & 3]; if (flag & 512) { - perms += "w"; + perms += 'w'; } return perms; }, @@ -1405,17 +1410,17 @@ var sqlite3InitModule = (() => { return 0; } - if (perms.includes("r") && !(node.mode & 292)) { + if (perms.includes('r') && !(node.mode & 292)) { return 2; - } else if (perms.includes("w") && !(node.mode & 146)) { + } else if (perms.includes('w') && !(node.mode & 146)) { return 2; - } else if (perms.includes("x") && !(node.mode & 73)) { + } else if (perms.includes('x') && !(node.mode & 73)) { return 2; } return 0; }, mayLookup: (dir) => { - var errCode = FS.nodePermissions(dir, "x"); + var errCode = FS.nodePermissions(dir, 'x'); if (errCode) return errCode; if (!dir.node_ops.lookup) return 2; return 0; @@ -1425,7 +1430,7 @@ var sqlite3InitModule = (() => { var node = FS.lookupNode(dir, name); return 20; } catch (e) {} - return FS.nodePermissions(dir, "wx"); + return FS.nodePermissions(dir, 'wx'); }, mayDelete: (dir, name, isdir) => { var node; @@ -1434,7 +1439,7 @@ var sqlite3InitModule = (() => { } catch (e) { return e.errno; } - var errCode = FS.nodePermissions(dir, "wx"); + var errCode = FS.nodePermissions(dir, 'wx'); if (errCode) { return errCode; } @@ -1459,7 +1464,7 @@ var sqlite3InitModule = (() => { if (FS.isLink(node.mode)) { return 32; } else if (FS.isDir(node.mode)) { - if (FS.flagsToPermissionString(flags) !== "r" || flags & 512) { + if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) { return 31; } } @@ -1572,7 +1577,7 @@ var sqlite3InitModule = (() => { return mounts; }, syncfs: (populate, callback) => { - if (typeof populate == "function") { + if (typeof populate == 'function') { callback = populate; populate = false; } @@ -1581,9 +1586,9 @@ var sqlite3InitModule = (() => { if (FS.syncFSRequests > 1) { err( - "warning: " + + 'warning: ' + FS.syncFSRequests + - " FS.syncfs operations in flight at once, probably just doing extra work" + ' FS.syncfs operations in flight at once, probably just doing extra work', ); } @@ -1616,7 +1621,7 @@ var sqlite3InitModule = (() => { }); }, mount: (type, opts, mountpoint) => { - var root = mountpoint === "/"; + var root = mountpoint === '/'; var pseudo = !mountpoint; var node; @@ -1697,7 +1702,7 @@ var sqlite3InitModule = (() => { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; var name = PATH.basename(path); - if (!name || name === "." || name === "..") { + if (!name || name === '.' || name === '..') { throw new FS.ErrnoError(28); } var errCode = FS.mayCreate(parent, name); @@ -1722,11 +1727,11 @@ var sqlite3InitModule = (() => { return FS.mknod(path, mode, 0); }, mkdirTree: (path, mode) => { - var dirs = path.split("/"); - var d = ""; + var dirs = path.split('/'); + var d = ''; for (var i = 0; i < dirs.length; ++i) { if (!dirs[i]) continue; - d += "/" + dirs[i]; + d += '/' + dirs[i]; try { FS.mkdir(d, mode); } catch (e) { @@ -1735,7 +1740,7 @@ var sqlite3InitModule = (() => { } }, mkdev: (path, mode, dev) => { - if (typeof dev == "undefined") { + if (typeof dev == 'undefined') { dev = mode; mode = 438; } @@ -1783,12 +1788,12 @@ var sqlite3InitModule = (() => { var old_node = FS.lookupNode(old_dir, old_name); var relative = PATH_FS.relative(old_path, new_dirname); - if (relative.charAt(0) !== ".") { + if (relative.charAt(0) !== '.') { throw new FS.ErrnoError(28); } relative = PATH_FS.relative(new_path, old_dirname); - if (relative.charAt(0) !== ".") { + if (relative.charAt(0) !== '.') { throw new FS.ErrnoError(55); } @@ -1824,7 +1829,7 @@ var sqlite3InitModule = (() => { } if (new_dir !== old_dir) { - errCode = FS.nodePermissions(old_dir, "w"); + errCode = FS.nodePermissions(old_dir, 'w'); if (errCode) { throw new FS.ErrnoError(errCode); } @@ -1898,7 +1903,7 @@ var sqlite3InitModule = (() => { } return PATH_FS.resolve( FS.getPath(link.parent), - link.node_ops.readlink(link) + link.node_ops.readlink(link), ); }, stat: (path, dontFollow) => { @@ -1917,7 +1922,7 @@ var sqlite3InitModule = (() => { }, chmod: (path, mode, dontFollow) => { var node; - if (typeof path == "string") { + if (typeof path == 'string') { var lookup = FS.lookupPath(path, { follow: !dontFollow }); node = lookup.node; } else { @@ -1943,7 +1948,7 @@ var sqlite3InitModule = (() => { }, chown: (path, uid, gid, dontFollow) => { var node; - if (typeof path == "string") { + if (typeof path == 'string') { var lookup = FS.lookupPath(path, { follow: !dontFollow }); node = lookup.node; } else { @@ -1971,7 +1976,7 @@ var sqlite3InitModule = (() => { throw new FS.ErrnoError(28); } var node; - if (typeof path == "string") { + if (typeof path == 'string') { var lookup = FS.lookupPath(path, { follow: true }); node = lookup.node; } else { @@ -1986,7 +1991,7 @@ var sqlite3InitModule = (() => { if (!FS.isFile(node.mode)) { throw new FS.ErrnoError(28); } - var errCode = FS.nodePermissions(node, "w"); + var errCode = FS.nodePermissions(node, 'w'); if (errCode) { throw new FS.ErrnoError(errCode); } @@ -2013,18 +2018,18 @@ var sqlite3InitModule = (() => { }); }, open: (path, flags, mode) => { - if (path === "") { + if (path === '') { throw new FS.ErrnoError(44); } - flags = typeof flags == "string" ? FS.modeStringToFlags(flags) : flags; - mode = typeof mode == "undefined" ? 438 : mode; + flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; + mode = typeof mode == 'undefined' ? 438 : mode; if (flags & 64) { mode = (mode & 4095) | 32768; } else { mode = 0; } var node; - if (typeof path == "object") { + if (typeof path == 'object') { node = path; } else { path = PATH.normalize(path); @@ -2087,7 +2092,7 @@ var sqlite3InitModule = (() => { if (stream.stream_ops.open) { stream.stream_ops.open(stream); } - if (Module["logReadFiles"] && !(flags & 1)) { + if (Module['logReadFiles'] && !(flags & 1)) { if (!FS.readFiles) FS.readFiles = {}; if (!(path in FS.readFiles)) { FS.readFiles[path] = 1; @@ -2144,7 +2149,7 @@ var sqlite3InitModule = (() => { if (!stream.stream_ops.read) { throw new FS.ErrnoError(28); } - var seeking = typeof position != "undefined"; + var seeking = typeof position != 'undefined'; if (!seeking) { position = stream.position; } else if (!stream.seekable) { @@ -2155,7 +2160,7 @@ var sqlite3InitModule = (() => { buffer, offset, length, - position + position, ); if (!seeking) stream.position += bytesRead; return bytesRead; @@ -2179,7 +2184,7 @@ var sqlite3InitModule = (() => { if (stream.seekable && stream.flags & 1024) { FS.llseek(stream, 0, 2); } - var seeking = typeof position != "undefined"; + var seeking = typeof position != 'undefined'; if (!seeking) { position = stream.position; } else if (!stream.seekable) { @@ -2191,7 +2196,7 @@ var sqlite3InitModule = (() => { offset, length, position, - canOwn + canOwn, ); if (!seeking) stream.position += bytesWritten; return bytesWritten; @@ -2239,7 +2244,7 @@ var sqlite3InitModule = (() => { buffer, offset, length, - mmapFlags + mmapFlags, ); }, munmap: (stream) => 0, @@ -2251,8 +2256,8 @@ var sqlite3InitModule = (() => { }, readFile: (path, opts = {}) => { opts.flags = opts.flags || 0; - opts.encoding = opts.encoding || "binary"; - if (opts.encoding !== "utf8" && opts.encoding !== "binary") { + opts.encoding = opts.encoding || 'binary'; + if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { throw new Error('Invalid encoding type "' + opts.encoding + '"'); } var ret; @@ -2261,9 +2266,9 @@ var sqlite3InitModule = (() => { var length = stat.size; var buf = new Uint8Array(length); FS.read(stream, buf, 0, length, 0); - if (opts.encoding === "utf8") { + if (opts.encoding === 'utf8') { ret = UTF8ArrayToString(buf, 0); - } else if (opts.encoding === "binary") { + } else if (opts.encoding === 'binary') { ret = buf; } FS.close(stream); @@ -2272,14 +2277,14 @@ var sqlite3InitModule = (() => { writeFile: (path, data, opts = {}) => { opts.flags = opts.flags || 577; var stream = FS.open(path, opts.flags, opts.mode); - if (typeof data == "string") { + if (typeof data == 'string') { var buf = new Uint8Array(lengthBytesUTF8(data) + 1); var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn); } else if (ArrayBuffer.isView(data)) { FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); } else { - throw new Error("Unsupported data type"); + throw new Error('Unsupported data type'); } FS.close(stream); }, @@ -2292,46 +2297,46 @@ var sqlite3InitModule = (() => { if (!FS.isDir(lookup.node.mode)) { throw new FS.ErrnoError(54); } - var errCode = FS.nodePermissions(lookup.node, "x"); + var errCode = FS.nodePermissions(lookup.node, 'x'); if (errCode) { throw new FS.ErrnoError(errCode); } FS.currentPath = lookup.path; }, createDefaultDirectories: () => { - FS.mkdir("/tmp"); - FS.mkdir("/home"); - FS.mkdir("/home/web_user"); + FS.mkdir('/tmp'); + FS.mkdir('/home'); + FS.mkdir('/home/web_user'); }, createDefaultDevices: () => { - FS.mkdir("/dev"); + FS.mkdir('/dev'); FS.registerDevice(FS.makedev(1, 3), { read: () => 0, write: (stream, buffer, offset, length, pos) => length, }); - FS.mkdev("/dev/null", FS.makedev(1, 3)); + FS.mkdev('/dev/null', FS.makedev(1, 3)); TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); - FS.mkdev("/dev/tty", FS.makedev(5, 0)); - FS.mkdev("/dev/tty1", FS.makedev(6, 0)); + FS.mkdev('/dev/tty', FS.makedev(5, 0)); + FS.mkdev('/dev/tty1', FS.makedev(6, 0)); var random_device = getRandomDevice(); - FS.createDevice("/dev", "random", random_device); - FS.createDevice("/dev", "urandom", random_device); + FS.createDevice('/dev', 'random', random_device); + FS.createDevice('/dev', 'urandom', random_device); - FS.mkdir("/dev/shm"); - FS.mkdir("/dev/shm/tmp"); + FS.mkdir('/dev/shm'); + FS.mkdir('/dev/shm/tmp'); }, createSpecialDirectories: () => { - FS.mkdir("/proc"); - var proc_self = FS.mkdir("/proc/self"); - FS.mkdir("/proc/self/fd"); + FS.mkdir('/proc'); + var proc_self = FS.mkdir('/proc/self'); + FS.mkdir('/proc/self/fd'); FS.mount( { mount: () => { - var node = FS.createNode(proc_self, "fd", 16384 | 511, 73); + var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73); node.node_ops = { lookup: (parent, name) => { var fd = +name; @@ -2339,7 +2344,7 @@ var sqlite3InitModule = (() => { if (!stream) throw new FS.ErrnoError(8); var ret = { parent: null, - mount: { mountpoint: "fake" }, + mount: { mountpoint: 'fake' }, node_ops: { readlink: () => stream.path }, }; ret.parent = ret; @@ -2350,29 +2355,29 @@ var sqlite3InitModule = (() => { }, }, {}, - "/proc/self/fd" + '/proc/self/fd', ); }, createStandardStreams: () => { - if (Module["stdin"]) { - FS.createDevice("/dev", "stdin", Module["stdin"]); + if (Module['stdin']) { + FS.createDevice('/dev', 'stdin', Module['stdin']); } else { - FS.symlink("/dev/tty", "/dev/stdin"); + FS.symlink('/dev/tty', '/dev/stdin'); } - if (Module["stdout"]) { - FS.createDevice("/dev", "stdout", null, Module["stdout"]); + if (Module['stdout']) { + FS.createDevice('/dev', 'stdout', null, Module['stdout']); } else { - FS.symlink("/dev/tty", "/dev/stdout"); + FS.symlink('/dev/tty', '/dev/stdout'); } - if (Module["stderr"]) { - FS.createDevice("/dev", "stderr", null, Module["stderr"]); + if (Module['stderr']) { + FS.createDevice('/dev', 'stderr', null, Module['stderr']); } else { - FS.symlink("/dev/tty1", "/dev/stderr"); + FS.symlink('/dev/tty1', '/dev/stderr'); } - FS.open("/dev/stdin", 0); - FS.open("/dev/stdout", 1); - FS.open("/dev/stderr", 1); + FS.open('/dev/stdin', 0); + FS.open('/dev/stdout', 1); + FS.open('/dev/stderr', 1); }, ensureErrnoError: () => { if (FS.ErrnoError) return; @@ -2382,14 +2387,14 @@ var sqlite3InitModule = (() => { this.errno = errno; }; this.setErrno(errno); - this.message = "FS error"; + this.message = 'FS error'; }; FS.ErrnoError.prototype = new Error(); FS.ErrnoError.prototype.constructor = FS.ErrnoError; [44].forEach((code) => { FS.genericErrors[code] = new FS.ErrnoError(code); - FS.genericErrors[code].stack = ""; + FS.genericErrors[code].stack = ''; }); }, staticInit: () => { @@ -2397,7 +2402,7 @@ var sqlite3InitModule = (() => { FS.nameTable = new Array(4096); - FS.mount(MEMFS, {}, "/"); + FS.mount(MEMFS, {}, '/'); FS.createDefaultDirectories(); FS.createDefaultDevices(); @@ -2412,9 +2417,9 @@ var sqlite3InitModule = (() => { FS.ensureErrnoError(); - Module["stdin"] = input || Module["stdin"]; - Module["stdout"] = output || Module["stdout"]; - Module["stderr"] = error || Module["stderr"]; + Module['stdin'] = input || Module['stdin']; + Module['stdout'] = output || Module['stdout']; + Module['stderr'] = error || Module['stderr']; FS.createStandardStreams(); }, @@ -2469,15 +2474,15 @@ var sqlite3InitModule = (() => { ret.path = lookup.path; ret.object = lookup.node; ret.name = lookup.node.name; - ret.isRoot = lookup.path === "/"; + ret.isRoot = lookup.path === '/'; } catch (e) { ret.error = e.errno; } return ret; }, createPath: (parent, path, canRead, canWrite) => { - parent = typeof parent == "string" ? parent : FS.getPath(parent); - var parts = path.split("/").reverse(); + parent = typeof parent == 'string' ? parent : FS.getPath(parent); + var parts = path.split('/').reverse(); while (parts.length) { var part = parts.pop(); if (!part) continue; @@ -2491,8 +2496,8 @@ var sqlite3InitModule = (() => { }, createFile: (parent, name, properties, canRead, canWrite) => { var path = PATH.join2( - typeof parent == "string" ? parent : FS.getPath(parent), - name + typeof parent == 'string' ? parent : FS.getPath(parent), + name, ); var mode = FS.getMode(canRead, canWrite); return FS.create(path, mode); @@ -2500,13 +2505,13 @@ var sqlite3InitModule = (() => { createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { var path = name; if (parent) { - parent = typeof parent == "string" ? parent : FS.getPath(parent); + parent = typeof parent == 'string' ? parent : FS.getPath(parent); path = name ? PATH.join2(parent, name) : parent; } var mode = FS.getMode(canRead, canWrite); var node = FS.create(path, mode); if (data) { - if (typeof data == "string") { + if (typeof data == 'string') { var arr = new Array(data.length); for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); @@ -2523,8 +2528,8 @@ var sqlite3InitModule = (() => { }, createDevice: (parent, name, input, output) => { var path = PATH.join2( - typeof parent == "string" ? parent : FS.getPath(parent), - name + typeof parent == 'string' ? parent : FS.getPath(parent), + name, ); var mode = FS.getMode(!!input, !!output); if (!FS.createDevice.major) FS.createDevice.major = 64; @@ -2579,9 +2584,9 @@ var sqlite3InitModule = (() => { forceLoadFile: (obj) => { if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; - if (typeof XMLHttpRequest != "undefined") { + if (typeof XMLHttpRequest != 'undefined') { throw new Error( - "Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread." + 'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.', ); } else if (read_) { try { @@ -2591,7 +2596,7 @@ var sqlite3InitModule = (() => { throw new FS.ErrnoError(29); } } else { - throw new Error("Cannot load without read() or XMLHttpRequest."); + throw new Error('Cannot load without read() or XMLHttpRequest.'); } }, createLazyFile: (parent, name, url, canRead, canWrite) => { @@ -2614,22 +2619,22 @@ var sqlite3InitModule = (() => { LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() { var xhr = new XMLHttpRequest(); - xhr.open("HEAD", url, false); + xhr.open('HEAD', url, false); xhr.send(null); if ( !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) ) throw new Error( - "Couldn't load " + url + ". Status: " + xhr.status + "Couldn't load " + url + '. Status: ' + xhr.status, ); - var datalength = Number(xhr.getResponseHeader("Content-length")); + var datalength = Number(xhr.getResponseHeader('Content-length')); var header; var hasByteServing = - (header = xhr.getResponseHeader("Accept-Ranges")) && - header === "bytes"; + (header = xhr.getResponseHeader('Accept-Ranges')) && + header === 'bytes'; var usesGzip = - (header = xhr.getResponseHeader("Content-Encoding")) && - header === "gzip"; + (header = xhr.getResponseHeader('Content-Encoding')) && + header === 'gzip'; var chunkSize = 1024 * 1024; @@ -2638,25 +2643,25 @@ var sqlite3InitModule = (() => { var doXHR = (from, to) => { if (from > to) throw new Error( - "invalid range (" + + 'invalid range (' + from + - ", " + + ', ' + to + - ") or no bytes requested!" + ') or no bytes requested!', ); if (to > datalength - 1) throw new Error( - "only " + datalength + " bytes available! programmer error!" + 'only ' + datalength + ' bytes available! programmer error!', ); var xhr = new XMLHttpRequest(); - xhr.open("GET", url, false); + xhr.open('GET', url, false); if (datalength !== chunkSize) - xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); + xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to); - xhr.responseType = "arraybuffer"; + xhr.responseType = 'arraybuffer'; if (xhr.overrideMimeType) { - xhr.overrideMimeType("text/plain; charset=x-user-defined"); + xhr.overrideMimeType('text/plain; charset=x-user-defined'); } xhr.send(null); @@ -2664,23 +2669,23 @@ var sqlite3InitModule = (() => { !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) ) throw new Error( - "Couldn't load " + url + ". Status: " + xhr.status + "Couldn't load " + url + '. Status: ' + xhr.status, ); if (xhr.response !== undefined) { return new Uint8Array(xhr.response || []); } - return intArrayFromString(xhr.responseText || ""); + return intArrayFromString(xhr.responseText || ''); }; var lazyArray = this; lazyArray.setDataGetter((chunkNum) => { var start = chunkNum * chunkSize; var end = (chunkNum + 1) * chunkSize - 1; end = Math.min(end, datalength - 1); - if (typeof lazyArray.chunks[chunkNum] == "undefined") { + if (typeof lazyArray.chunks[chunkNum] == 'undefined') { lazyArray.chunks[chunkNum] = doXHR(start, end); } - if (typeof lazyArray.chunks[chunkNum] == "undefined") - throw new Error("doXHR failed!"); + if (typeof lazyArray.chunks[chunkNum] == 'undefined') + throw new Error('doXHR failed!'); return lazyArray.chunks[chunkNum]; }); @@ -2689,7 +2694,7 @@ var sqlite3InitModule = (() => { datalength = this.getter(0).length; chunkSize = datalength; out( - "LazyFiles on gzip forces download of the whole file when length is accessed" + 'LazyFiles on gzip forces download of the whole file when length is accessed', ); } @@ -2697,9 +2702,9 @@ var sqlite3InitModule = (() => { this._chunkSize = chunkSize; this.lengthKnown = true; }; - if (typeof XMLHttpRequest != "undefined") { + if (typeof XMLHttpRequest != 'undefined') { if (!ENVIRONMENT_IS_WORKER) - throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc"; + throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; var lazyArray = new LazyUint8Array(); Object.defineProperties(lazyArray, { length: { @@ -2794,7 +2799,7 @@ var sqlite3InitModule = (() => { onerror, dontCreateFile, canOwn, - preFinish + preFinish, ) => { var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) @@ -2809,7 +2814,7 @@ var sqlite3InitModule = (() => { byteArray, canRead, canWrite, - canOwn + canOwn, ); } if (onload) onload(); @@ -2826,7 +2831,7 @@ var sqlite3InitModule = (() => { finish(byteArray); } addRunDependency(); - if (typeof url == "string") { + if (typeof url == 'string') { asyncLoad(url, (byteArray) => processData(byteArray), onerror); } else { processData(url); @@ -2841,10 +2846,10 @@ var sqlite3InitModule = (() => { ); }, DB_NAME: () => { - return "EM_FS_" + window.location.pathname; + return 'EM_FS_' + window.location.pathname; }, DB_VERSION: 20, - DB_STORE_NAME: "FILE_DATA", + DB_STORE_NAME: 'FILE_DATA', saveFilesToDB: (paths, onload, onerror) => { onload = onload || (() => {}); onerror = onerror || (() => {}); @@ -2855,13 +2860,13 @@ var sqlite3InitModule = (() => { return onerror(e); } openRequest.onupgradeneeded = () => { - out("creating db"); + out('creating db'); var db = openRequest.result; db.createObjectStore(FS.DB_STORE_NAME); }; openRequest.onsuccess = () => { var db = openRequest.result; - var transaction = db.transaction([FS.DB_STORE_NAME], "readwrite"); + var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite'); var files = transaction.objectStore(FS.DB_STORE_NAME); var ok = 0, fail = 0, @@ -2873,7 +2878,7 @@ var sqlite3InitModule = (() => { paths.forEach((path) => { var putRequest = files.put( FS.analyzePath(path).object.contents, - path + path, ); putRequest.onsuccess = () => { ok++; @@ -2901,7 +2906,7 @@ var sqlite3InitModule = (() => { openRequest.onsuccess = () => { var db = openRequest.result; try { - var transaction = db.transaction([FS.DB_STORE_NAME], "readonly"); + var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly'); } catch (e) { onerror(e); return; @@ -2926,7 +2931,7 @@ var sqlite3InitModule = (() => { getRequest.result, true, true, - true + true, ); ok++; if (ok + fail == total) finish(); @@ -2990,12 +2995,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0 + 4294967295.0, ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, ) >>> 0 : 0), ]), @@ -3013,12 +3018,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0 + 4294967295.0, ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, ) >>> 0 : 0), ]), @@ -3032,12 +3037,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0 + 4294967295.0, ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, ) >>> 0 : 0), ]), @@ -3051,12 +3056,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0 + 4294967295.0, ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, ) >>> 0 : 0), ]), @@ -3070,12 +3075,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0 + 4294967295.0, ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, ) >>> 0 : 0), ]), @@ -3115,7 +3120,7 @@ var sqlite3InitModule = (() => { FS.chmod(path, mode); return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3132,16 +3137,16 @@ var sqlite3InitModule = (() => { if (!node) { return -44; } - var perms = ""; - if (amode & 4) perms += "r"; - if (amode & 2) perms += "w"; - if (amode & 1) perms += "x"; + var perms = ''; + if (amode & 4) perms += 'r'; + if (amode & 2) perms += 'w'; + if (amode & 1) perms += 'x'; if (perms && FS.nodePermissions(node, perms)) { return -2; } return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3151,7 +3156,7 @@ var sqlite3InitModule = (() => { FS.fchmod(fd, mode); return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3161,7 +3166,7 @@ var sqlite3InitModule = (() => { FS.fchown(fd, owner, group); return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3216,7 +3221,7 @@ var sqlite3InitModule = (() => { } } } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3226,7 +3231,7 @@ var sqlite3InitModule = (() => { var stream = SYSCALLS.getStreamFromFD(fd); return SYSCALLS.doStat(FS.stat, stream.path, buf); } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3245,7 +3250,7 @@ var sqlite3InitModule = (() => { FS.ftruncate(fd, length); return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3259,7 +3264,7 @@ var sqlite3InitModule = (() => { stringToUTF8(cwd, buf, size); return cwdLengthInBytes; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3309,7 +3314,7 @@ var sqlite3InitModule = (() => { return -28; } } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3319,7 +3324,7 @@ var sqlite3InitModule = (() => { path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.lstat, path, buf); } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3330,12 +3335,12 @@ var sqlite3InitModule = (() => { path = SYSCALLS.calculateAt(dirfd, path); path = PATH.normalize(path); - if (path[path.length - 1] === "/") + if (path[path.length - 1] === '/') path = path.substr(0, path.length - 1); FS.mkdir(path, mode, 0); return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3349,7 +3354,7 @@ var sqlite3InitModule = (() => { path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3362,7 +3367,7 @@ var sqlite3InitModule = (() => { var mode = varargs ? SYSCALLS.get() : 0; return FS.open(path, flags, mode).fd; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3381,7 +3386,7 @@ var sqlite3InitModule = (() => { HEAP8[buf + len] = endChar; return len; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3392,7 +3397,7 @@ var sqlite3InitModule = (() => { FS.rmdir(path); return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3402,7 +3407,7 @@ var sqlite3InitModule = (() => { path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.stat, path, buf); } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3416,11 +3421,11 @@ var sqlite3InitModule = (() => { } else if (flags === 512) { FS.rmdir(path); } else { - abort("Invalid flags passed to unlinkat"); + abort('Invalid flags passed to unlinkat'); } return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3448,7 +3453,7 @@ var sqlite3InitModule = (() => { FS.utime(path, atime, mtime); return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3510,7 +3515,7 @@ var sqlite3InitModule = (() => { HEAPU32[addr >> 2] = ptr; return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3523,7 +3528,7 @@ var sqlite3InitModule = (() => { } FS.munmap(stream); } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3549,7 +3554,7 @@ var sqlite3InitModule = (() => { function extractZone(date) { var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/); - return match ? match[1] : "GMT"; + return match ? match[1] : 'GMT'; } var winterName = extractZone(winter); var summerName = extractZone(summer); @@ -3599,12 +3604,12 @@ var sqlite3InitModule = (() => { overGrownHeapSize = Math.min( overGrownHeapSize, - requestedSize + 100663296 + requestedSize + 100663296, ); var newSize = Math.min( maxHeapSize, - alignUp(Math.max(requestedSize, overGrownHeapSize), 65536) + alignUp(Math.max(requestedSize, overGrownHeapSize), 65536), ); var replacement = emscripten_realloc_buffer(newSize); @@ -3618,23 +3623,23 @@ var sqlite3InitModule = (() => { var ENV = {}; function getExecutableName() { - return thisProgram || "./this.program"; + return thisProgram || './this.program'; } function getEnvStrings() { if (!getEnvStrings.strings) { var lang = ( - (typeof navigator == "object" && + (typeof navigator == 'object' && navigator.languages && navigator.languages[0]) || - "C" - ).replace("-", "_") + ".UTF-8"; + 'C' + ).replace('-', '_') + '.UTF-8'; var env = { - USER: "web_user", - LOGNAME: "web_user", - PATH: "/", - PWD: "/", - HOME: "/home/web_user", + USER: 'web_user', + LOGNAME: 'web_user', + PATH: '/', + PWD: '/', + HOME: '/home/web_user', LANG: lang, _: getExecutableName(), }; @@ -3645,7 +3650,7 @@ var sqlite3InitModule = (() => { } var strings = []; for (var x in env) { - strings.push(x + "=" + env[x]); + strings.push(x + '=' + env[x]); } getEnvStrings.strings = strings; } @@ -3688,7 +3693,7 @@ var sqlite3InitModule = (() => { FS.close(stream); return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3700,15 +3705,15 @@ var sqlite3InitModule = (() => { var type = stream.tty ? 2 : FS.isDir(stream.mode) - ? 3 - : FS.isLink(stream.mode) - ? 7 - : 4; + ? 3 + : FS.isLink(stream.mode) + ? 7 + : 4; HEAP8[pbuf >> 0] = type; return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3734,7 +3739,7 @@ var sqlite3InitModule = (() => { HEAPU32[pnum >> 2] = num; return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3752,12 +3757,12 @@ var sqlite3InitModule = (() => { ? tempDouble > 0.0 ? (Math.min( +Math.floor(tempDouble / 4294967296.0), - 4294967295.0 + 4294967295.0, ) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0 + (tempDouble - +(~~tempDouble >>> 0)) / 4294967296.0, ) >>> 0 : 0), ]), @@ -3767,7 +3772,7 @@ var sqlite3InitModule = (() => { stream.getdents = null; return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3780,7 +3785,7 @@ var sqlite3InitModule = (() => { } return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3805,7 +3810,7 @@ var sqlite3InitModule = (() => { HEAPU32[pnum >> 2] = num; return 0; } catch (e) { - if (typeof FS == "undefined" || !(e instanceof FS.ErrnoError)) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } @@ -3896,1281 +3901,1588 @@ var sqlite3InitModule = (() => { }; createWasm(); - Module["___wasm_call_ctors"] = function () { - return (Module["___wasm_call_ctors"] = - Module["asm"]["__wasm_call_ctors"]).apply(null, arguments); - }; + (Module['___wasm_call_ctors'] = function () { + return (Module['___wasm_call_ctors'] = + Module['asm']['__wasm_call_ctors']).apply(null, arguments); + }); - Module["_sqlite3_status64"] = function () { - return (Module["_sqlite3_status64"] = - Module["asm"]["sqlite3_status64"]).apply(null, arguments); - }; + (Module['_sqlite3_status64'] = function () { + return (Module['_sqlite3_status64'] = + Module['asm']['sqlite3_status64']).apply(null, arguments); + }); - Module["_sqlite3_status"] = function () { - return (Module["_sqlite3_status"] = - Module["asm"]["sqlite3_status"]).apply(null, arguments); - }; + (Module['_sqlite3_status'] = function () { + return (Module['_sqlite3_status'] = + Module['asm']['sqlite3_status']).apply(null, arguments); + }); - Module["_sqlite3_db_status"] = function () { - return (Module["_sqlite3_db_status"] = - Module["asm"]["sqlite3_db_status"]).apply(null, arguments); - }; + (Module['_sqlite3_db_status'] = function () { + return (Module['_sqlite3_db_status'] = + Module['asm']['sqlite3_db_status']).apply(null, arguments); + }); - Module["_sqlite3_msize"] = function () { - return (Module["_sqlite3_msize"] = Module["asm"]["sqlite3_msize"]).apply( - null, - arguments - ); - }; + (Module['_sqlite3_msize'] = function () { + return (Module['_sqlite3_msize'] = + Module['asm']['sqlite3_msize']).apply(null, arguments); + }); - Module["_sqlite3_vfs_find"] = function () { - return (Module["_sqlite3_vfs_find"] = - Module["asm"]["sqlite3_vfs_find"]).apply(null, arguments); - }; + (Module['_sqlite3_vfs_find'] = function () { + return (Module['_sqlite3_vfs_find'] = + Module['asm']['sqlite3_vfs_find']).apply(null, arguments); + }); - Module["_sqlite3_initialize"] = function () { - return (Module["_sqlite3_initialize"] = - Module["asm"]["sqlite3_initialize"]).apply(null, arguments); - }; + (Module['_sqlite3_initialize'] = function () { + return (Module['_sqlite3_initialize'] = + Module['asm']['sqlite3_initialize']).apply(null, arguments); + }); - Module["_sqlite3_malloc"] = function () { - return (Module["_sqlite3_malloc"] = - Module["asm"]["sqlite3_malloc"]).apply(null, arguments); - }; + (Module['_sqlite3_malloc'] = function () { + return (Module['_sqlite3_malloc'] = + Module['asm']['sqlite3_malloc']).apply(null, arguments); + }); - Module["_sqlite3_free"] = function () { - return (Module["_sqlite3_free"] = Module["asm"]["sqlite3_free"]).apply( - null, - arguments - ); - }; + (Module['_sqlite3_free'] = function () { + return (Module['_sqlite3_free'] = + Module['asm']['sqlite3_free']).apply(null, arguments); + }); - Module["_sqlite3_vfs_register"] = function () { - return (Module["_sqlite3_vfs_register"] = - Module["asm"]["sqlite3_vfs_register"]).apply(null, arguments); - }; + (Module['_sqlite3_vfs_register'] = function () { + return (Module['_sqlite3_vfs_register'] = + Module['asm']['sqlite3_vfs_register']).apply(null, arguments); + }); - Module["_sqlite3_vfs_unregister"] = function () { - return (Module["_sqlite3_vfs_unregister"] = - Module["asm"]["sqlite3_vfs_unregister"]).apply(null, arguments); - }; + (Module['_sqlite3_vfs_unregister'] = + function () { + return (Module['_sqlite3_vfs_unregister'] = + Module['asm']['sqlite3_vfs_unregister']).apply(null, arguments); + }); - Module["_sqlite3_malloc64"] = function () { - return (Module["_sqlite3_malloc64"] = - Module["asm"]["sqlite3_malloc64"]).apply(null, arguments); - }; + (Module['_sqlite3_malloc64'] = function () { + return (Module['_sqlite3_malloc64'] = + Module['asm']['sqlite3_malloc64']).apply(null, arguments); + }); - Module["_sqlite3_realloc"] = function () { - return (Module["_sqlite3_realloc"] = - Module["asm"]["sqlite3_realloc"]).apply(null, arguments); - }; + (Module['_sqlite3_realloc'] = function () { + return (Module['_sqlite3_realloc'] = + Module['asm']['sqlite3_realloc']).apply(null, arguments); + }); - Module["_sqlite3_realloc64"] = function () { - return (Module["_sqlite3_realloc64"] = - Module["asm"]["sqlite3_realloc64"]).apply(null, arguments); - }; + (Module['_sqlite3_realloc64'] = function () { + return (Module['_sqlite3_realloc64'] = + Module['asm']['sqlite3_realloc64']).apply(null, arguments); + }); - Module["_sqlite3_value_text"] = function () { - return (Module["_sqlite3_value_text"] = - Module["asm"]["sqlite3_value_text"]).apply(null, arguments); - }; + (Module['_sqlite3_value_text'] = function () { + return (Module['_sqlite3_value_text'] = + Module['asm']['sqlite3_value_text']).apply(null, arguments); + }); - Module["_sqlite3_randomness"] = function () { - return (Module["_sqlite3_randomness"] = - Module["asm"]["sqlite3_randomness"]).apply(null, arguments); - }; + (Module['_sqlite3_randomness'] = function () { + return (Module['_sqlite3_randomness'] = + Module['asm']['sqlite3_randomness']).apply(null, arguments); + }); - Module["_sqlite3_stricmp"] = function () { - return (Module["_sqlite3_stricmp"] = - Module["asm"]["sqlite3_stricmp"]).apply(null, arguments); - }; + (Module['_sqlite3_stricmp'] = function () { + return (Module['_sqlite3_stricmp'] = + Module['asm']['sqlite3_stricmp']).apply(null, arguments); + }); - Module["_sqlite3_strnicmp"] = function () { - return (Module["_sqlite3_strnicmp"] = - Module["asm"]["sqlite3_strnicmp"]).apply(null, arguments); - }; + (Module['_sqlite3_strnicmp'] = function () { + return (Module['_sqlite3_strnicmp'] = + Module['asm']['sqlite3_strnicmp']).apply(null, arguments); + }); - Module["_sqlite3_uri_parameter"] = function () { - return (Module["_sqlite3_uri_parameter"] = - Module["asm"]["sqlite3_uri_parameter"]).apply(null, arguments); - }; + (Module['_sqlite3_uri_parameter'] = + function () { + return (Module['_sqlite3_uri_parameter'] = + Module['asm']['sqlite3_uri_parameter']).apply(null, arguments); + }); - var ___errno_location = (Module["___errno_location"] = function () { - return (___errno_location = Module["___errno_location"] = - Module["asm"]["__errno_location"]).apply(null, arguments); + var ___errno_location = (Module['___errno_location'] = function () { + return (___errno_location = Module['___errno_location'] = + Module['asm']['__errno_location']).apply(null, arguments); }); - Module["_sqlite3_uri_boolean"] = function () { - return (Module["_sqlite3_uri_boolean"] = - Module["asm"]["sqlite3_uri_boolean"]).apply(null, arguments); - }; + (Module['_sqlite3_uri_boolean'] = function () { + return (Module['_sqlite3_uri_boolean'] = + Module['asm']['sqlite3_uri_boolean']).apply(null, arguments); + }); - Module["_sqlite3_serialize"] = function () { - return (Module["_sqlite3_serialize"] = - Module["asm"]["sqlite3_serialize"]).apply(null, arguments); - }; + (Module['_sqlite3_serialize'] = function () { + return (Module['_sqlite3_serialize'] = + Module['asm']['sqlite3_serialize']).apply(null, arguments); + }); - Module["_sqlite3_prepare_v2"] = function () { - return (Module["_sqlite3_prepare_v2"] = - Module["asm"]["sqlite3_prepare_v2"]).apply(null, arguments); - }; + (Module['_sqlite3_prepare_v2'] = function () { + return (Module['_sqlite3_prepare_v2'] = + Module['asm']['sqlite3_prepare_v2']).apply(null, arguments); + }); - Module["_sqlite3_step"] = function () { - return (Module["_sqlite3_step"] = Module["asm"]["sqlite3_step"]).apply( - null, - arguments - ); - }; + (Module['_sqlite3_step'] = function () { + return (Module['_sqlite3_step'] = + Module['asm']['sqlite3_step']).apply(null, arguments); + }); - Module["_sqlite3_column_int64"] = function () { - return (Module["_sqlite3_column_int64"] = - Module["asm"]["sqlite3_column_int64"]).apply(null, arguments); - }; + (Module['_sqlite3_column_int64'] = function () { + return (Module['_sqlite3_column_int64'] = + Module['asm']['sqlite3_column_int64']).apply(null, arguments); + }); - Module["_sqlite3_reset"] = function () { - return (Module["_sqlite3_reset"] = Module["asm"]["sqlite3_reset"]).apply( - null, - arguments - ); - }; + (Module['_sqlite3_reset'] = function () { + return (Module['_sqlite3_reset'] = + Module['asm']['sqlite3_reset']).apply(null, arguments); + }); - Module["_sqlite3_exec"] = function () { - return (Module["_sqlite3_exec"] = Module["asm"]["sqlite3_exec"]).apply( - null, - arguments - ); - }; + (Module['_sqlite3_exec'] = function () { + return (Module['_sqlite3_exec'] = + Module['asm']['sqlite3_exec']).apply(null, arguments); + }); - Module["_sqlite3_column_int"] = function () { - return (Module["_sqlite3_column_int"] = - Module["asm"]["sqlite3_column_int"]).apply(null, arguments); - }; + (Module['_sqlite3_column_int'] = function () { + return (Module['_sqlite3_column_int'] = + Module['asm']['sqlite3_column_int']).apply(null, arguments); + }); - Module["_sqlite3_finalize"] = function () { - return (Module["_sqlite3_finalize"] = - Module["asm"]["sqlite3_finalize"]).apply(null, arguments); - }; + (Module['_sqlite3_finalize'] = function () { + return (Module['_sqlite3_finalize'] = + Module['asm']['sqlite3_finalize']).apply(null, arguments); + }); - Module["_sqlite3_file_control"] = function () { - return (Module["_sqlite3_file_control"] = - Module["asm"]["sqlite3_file_control"]).apply(null, arguments); - }; + (Module['_sqlite3_file_control'] = function () { + return (Module['_sqlite3_file_control'] = + Module['asm']['sqlite3_file_control']).apply(null, arguments); + }); - Module["_sqlite3_column_name"] = function () { - return (Module["_sqlite3_column_name"] = - Module["asm"]["sqlite3_column_name"]).apply(null, arguments); - }; + (Module['_sqlite3_column_name'] = function () { + return (Module['_sqlite3_column_name'] = + Module['asm']['sqlite3_column_name']).apply(null, arguments); + }); - Module["_sqlite3_column_text"] = function () { - return (Module["_sqlite3_column_text"] = - Module["asm"]["sqlite3_column_text"]).apply(null, arguments); - }; + (Module['_sqlite3_column_text'] = function () { + return (Module['_sqlite3_column_text'] = + Module['asm']['sqlite3_column_text']).apply(null, arguments); + }); - Module["_sqlite3_column_type"] = function () { - return (Module["_sqlite3_column_type"] = - Module["asm"]["sqlite3_column_type"]).apply(null, arguments); - }; + (Module['_sqlite3_column_type'] = function () { + return (Module['_sqlite3_column_type'] = + Module['asm']['sqlite3_column_type']).apply(null, arguments); + }); - Module["_sqlite3_errmsg"] = function () { - return (Module["_sqlite3_errmsg"] = - Module["asm"]["sqlite3_errmsg"]).apply(null, arguments); - }; + (Module['_sqlite3_errmsg'] = function () { + return (Module['_sqlite3_errmsg'] = + Module['asm']['sqlite3_errmsg']).apply(null, arguments); + }); - Module["_sqlite3_deserialize"] = function () { - return (Module["_sqlite3_deserialize"] = - Module["asm"]["sqlite3_deserialize"]).apply(null, arguments); - }; + (Module['_sqlite3_deserialize'] = function () { + return (Module['_sqlite3_deserialize'] = + Module['asm']['sqlite3_deserialize']).apply(null, arguments); + }); - Module["_sqlite3_clear_bindings"] = function () { - return (Module["_sqlite3_clear_bindings"] = - Module["asm"]["sqlite3_clear_bindings"]).apply(null, arguments); - }; + (Module['_sqlite3_clear_bindings'] = + function () { + return (Module['_sqlite3_clear_bindings'] = + Module['asm']['sqlite3_clear_bindings']).apply(null, arguments); + }); - Module["_sqlite3_value_blob"] = function () { - return (Module["_sqlite3_value_blob"] = - Module["asm"]["sqlite3_value_blob"]).apply(null, arguments); - }; + (Module['_sqlite3_value_blob'] = function () { + return (Module['_sqlite3_value_blob'] = + Module['asm']['sqlite3_value_blob']).apply(null, arguments); + }); - Module["_sqlite3_value_bytes"] = function () { - return (Module["_sqlite3_value_bytes"] = - Module["asm"]["sqlite3_value_bytes"]).apply(null, arguments); - }; + (Module['_sqlite3_value_bytes'] = function () { + return (Module['_sqlite3_value_bytes'] = + Module['asm']['sqlite3_value_bytes']).apply(null, arguments); + }); - Module["_sqlite3_value_double"] = function () { - return (Module["_sqlite3_value_double"] = - Module["asm"]["sqlite3_value_double"]).apply(null, arguments); - }; + (Module['_sqlite3_value_double'] = function () { + return (Module['_sqlite3_value_double'] = + Module['asm']['sqlite3_value_double']).apply(null, arguments); + }); - Module["_sqlite3_value_int"] = function () { - return (Module["_sqlite3_value_int"] = - Module["asm"]["sqlite3_value_int"]).apply(null, arguments); - }; + (Module['_sqlite3_value_int'] = function () { + return (Module['_sqlite3_value_int'] = + Module['asm']['sqlite3_value_int']).apply(null, arguments); + }); - Module["_sqlite3_value_int64"] = function () { - return (Module["_sqlite3_value_int64"] = - Module["asm"]["sqlite3_value_int64"]).apply(null, arguments); - }; + (Module['_sqlite3_value_int64'] = function () { + return (Module['_sqlite3_value_int64'] = + Module['asm']['sqlite3_value_int64']).apply(null, arguments); + }); - Module["_sqlite3_value_subtype"] = function () { - return (Module["_sqlite3_value_subtype"] = - Module["asm"]["sqlite3_value_subtype"]).apply(null, arguments); - }; + (Module['_sqlite3_value_subtype'] = + function () { + return (Module['_sqlite3_value_subtype'] = + Module['asm']['sqlite3_value_subtype']).apply(null, arguments); + }); - Module["_sqlite3_value_pointer"] = function () { - return (Module["_sqlite3_value_pointer"] = - Module["asm"]["sqlite3_value_pointer"]).apply(null, arguments); - }; + (Module['_sqlite3_value_pointer'] = + function () { + return (Module['_sqlite3_value_pointer'] = + Module['asm']['sqlite3_value_pointer']).apply(null, arguments); + }); - Module["_sqlite3_value_type"] = function () { - return (Module["_sqlite3_value_type"] = - Module["asm"]["sqlite3_value_type"]).apply(null, arguments); - }; + (Module['_sqlite3_value_type'] = function () { + return (Module['_sqlite3_value_type'] = + Module['asm']['sqlite3_value_type']).apply(null, arguments); + }); - Module["_sqlite3_value_nochange"] = function () { - return (Module["_sqlite3_value_nochange"] = - Module["asm"]["sqlite3_value_nochange"]).apply(null, arguments); - }; + (Module['_sqlite3_value_nochange'] = + function () { + return (Module['_sqlite3_value_nochange'] = + Module['asm']['sqlite3_value_nochange']).apply(null, arguments); + }); - Module["_sqlite3_value_frombind"] = function () { - return (Module["_sqlite3_value_frombind"] = - Module["asm"]["sqlite3_value_frombind"]).apply(null, arguments); - }; + (Module['_sqlite3_value_frombind'] = + function () { + return (Module['_sqlite3_value_frombind'] = + Module['asm']['sqlite3_value_frombind']).apply(null, arguments); + }); - Module["_sqlite3_value_dup"] = function () { - return (Module["_sqlite3_value_dup"] = - Module["asm"]["sqlite3_value_dup"]).apply(null, arguments); - }; + (Module['_sqlite3_value_dup'] = function () { + return (Module['_sqlite3_value_dup'] = + Module['asm']['sqlite3_value_dup']).apply(null, arguments); + }); - Module["_sqlite3_value_free"] = function () { - return (Module["_sqlite3_value_free"] = - Module["asm"]["sqlite3_value_free"]).apply(null, arguments); - }; + (Module['_sqlite3_value_free'] = function () { + return (Module['_sqlite3_value_free'] = + Module['asm']['sqlite3_value_free']).apply(null, arguments); + }); - Module["_sqlite3_result_blob"] = function () { - return (Module["_sqlite3_result_blob"] = - Module["asm"]["sqlite3_result_blob"]).apply(null, arguments); - }; + (Module['_sqlite3_result_blob'] = function () { + return (Module['_sqlite3_result_blob'] = + Module['asm']['sqlite3_result_blob']).apply(null, arguments); + }); - Module["_sqlite3_result_error_toobig"] = function () { - return (Module["_sqlite3_result_error_toobig"] = - Module["asm"]["sqlite3_result_error_toobig"]).apply(null, arguments); - }; + (Module['_sqlite3_result_error_toobig'] = + function () { + return (Module[ + '_sqlite3_result_error_toobig' + ] = + Module['asm']['sqlite3_result_error_toobig']).apply(null, arguments); + }); - Module["_sqlite3_result_error_nomem"] = function () { - return (Module["_sqlite3_result_error_nomem"] = - Module["asm"]["sqlite3_result_error_nomem"]).apply(null, arguments); - }; + (Module['_sqlite3_result_error_nomem'] = + function () { + return (Module[ + '_sqlite3_result_error_nomem' + ] = + Module['asm']['sqlite3_result_error_nomem']).apply(null, arguments); + }); - Module["_sqlite3_result_double"] = function () { - return (Module["_sqlite3_result_double"] = - Module["asm"]["sqlite3_result_double"]).apply(null, arguments); - }; + (Module['_sqlite3_result_double'] = + function () { + return (Module['_sqlite3_result_double'] = + Module['asm']['sqlite3_result_double']).apply(null, arguments); + }); - Module["_sqlite3_result_error"] = function () { - return (Module["_sqlite3_result_error"] = - Module["asm"]["sqlite3_result_error"]).apply(null, arguments); - }; + (Module['_sqlite3_result_error'] = function () { + return (Module['_sqlite3_result_error'] = + Module['asm']['sqlite3_result_error']).apply(null, arguments); + }); - Module["_sqlite3_result_int"] = function () { - return (Module["_sqlite3_result_int"] = - Module["asm"]["sqlite3_result_int"]).apply(null, arguments); - }; + (Module['_sqlite3_result_int'] = function () { + return (Module['_sqlite3_result_int'] = + Module['asm']['sqlite3_result_int']).apply(null, arguments); + }); - Module["_sqlite3_result_int64"] = function () { - return (Module["_sqlite3_result_int64"] = - Module["asm"]["sqlite3_result_int64"]).apply(null, arguments); - }; + (Module['_sqlite3_result_int64'] = function () { + return (Module['_sqlite3_result_int64'] = + Module['asm']['sqlite3_result_int64']).apply(null, arguments); + }); - Module["_sqlite3_result_null"] = function () { - return (Module["_sqlite3_result_null"] = - Module["asm"]["sqlite3_result_null"]).apply(null, arguments); - }; + (Module['_sqlite3_result_null'] = function () { + return (Module['_sqlite3_result_null'] = + Module['asm']['sqlite3_result_null']).apply(null, arguments); + }); - Module["_sqlite3_result_pointer"] = function () { - return (Module["_sqlite3_result_pointer"] = - Module["asm"]["sqlite3_result_pointer"]).apply(null, arguments); - }; + (Module['_sqlite3_result_pointer'] = + function () { + return (Module['_sqlite3_result_pointer'] = + Module['asm']['sqlite3_result_pointer']).apply(null, arguments); + }); - Module["_sqlite3_result_subtype"] = function () { - return (Module["_sqlite3_result_subtype"] = - Module["asm"]["sqlite3_result_subtype"]).apply(null, arguments); - }; + (Module['_sqlite3_result_subtype'] = + function () { + return (Module['_sqlite3_result_subtype'] = + Module['asm']['sqlite3_result_subtype']).apply(null, arguments); + }); - Module["_sqlite3_result_text"] = function () { - return (Module["_sqlite3_result_text"] = - Module["asm"]["sqlite3_result_text"]).apply(null, arguments); - }; + (Module['_sqlite3_result_text'] = function () { + return (Module['_sqlite3_result_text'] = + Module['asm']['sqlite3_result_text']).apply(null, arguments); + }); - Module["_sqlite3_result_zeroblob"] = function () { - return (Module["_sqlite3_result_zeroblob"] = - Module["asm"]["sqlite3_result_zeroblob"]).apply(null, arguments); - }; + (Module['_sqlite3_result_zeroblob'] = + function () { + return (Module['_sqlite3_result_zeroblob'] = + Module['asm']['sqlite3_result_zeroblob']).apply(null, arguments); + }); - Module["_sqlite3_result_zeroblob64"] = function () { - return (Module["_sqlite3_result_zeroblob64"] = - Module["asm"]["sqlite3_result_zeroblob64"]).apply(null, arguments); - }; + (Module['_sqlite3_result_zeroblob64'] = + function () { + return (Module[ + '_sqlite3_result_zeroblob64' + ] = + Module['asm']['sqlite3_result_zeroblob64']).apply(null, arguments); + }); - Module["_sqlite3_result_error_code"] = function () { - return (Module["_sqlite3_result_error_code"] = - Module["asm"]["sqlite3_result_error_code"]).apply(null, arguments); - }; + (Module['_sqlite3_result_error_code'] = + function () { + return (Module[ + '_sqlite3_result_error_code' + ] = + Module['asm']['sqlite3_result_error_code']).apply(null, arguments); + }); - Module["_sqlite3_user_data"] = function () { - return (Module["_sqlite3_user_data"] = - Module["asm"]["sqlite3_user_data"]).apply(null, arguments); - }; + (Module['_sqlite3_user_data'] = function () { + return (Module['_sqlite3_user_data'] = + Module['asm']['sqlite3_user_data']).apply(null, arguments); + }); - Module["_sqlite3_context_db_handle"] = function () { - return (Module["_sqlite3_context_db_handle"] = - Module["asm"]["sqlite3_context_db_handle"]).apply(null, arguments); - }; + (Module['_sqlite3_context_db_handle'] = + function () { + return (Module[ + '_sqlite3_context_db_handle' + ] = + Module['asm']['sqlite3_context_db_handle']).apply(null, arguments); + }); - Module["_sqlite3_vtab_nochange"] = function () { - return (Module["_sqlite3_vtab_nochange"] = - Module["asm"]["sqlite3_vtab_nochange"]).apply(null, arguments); - }; + (Module['_sqlite3_vtab_nochange'] = + function () { + return (Module['_sqlite3_vtab_nochange'] = + Module['asm']['sqlite3_vtab_nochange']).apply(null, arguments); + }); - Module["_sqlite3_vtab_in_first"] = function () { - return (Module["_sqlite3_vtab_in_first"] = - Module["asm"]["sqlite3_vtab_in_first"]).apply(null, arguments); - }; + (Module['_sqlite3_vtab_in_first'] = + function () { + return (Module['_sqlite3_vtab_in_first'] = + Module['asm']['sqlite3_vtab_in_first']).apply(null, arguments); + }); - Module["_sqlite3_vtab_in_next"] = function () { - return (Module["_sqlite3_vtab_in_next"] = - Module["asm"]["sqlite3_vtab_in_next"]).apply(null, arguments); - }; + (Module['_sqlite3_vtab_in_next'] = function () { + return (Module['_sqlite3_vtab_in_next'] = + Module['asm']['sqlite3_vtab_in_next']).apply(null, arguments); + }); - Module["_sqlite3_aggregate_context"] = function () { - return (Module["_sqlite3_aggregate_context"] = - Module["asm"]["sqlite3_aggregate_context"]).apply(null, arguments); - }; + (Module['_sqlite3_aggregate_context'] = + function () { + return (Module[ + '_sqlite3_aggregate_context' + ] = + Module['asm']['sqlite3_aggregate_context']).apply(null, arguments); + }); - Module["_sqlite3_get_auxdata"] = function () { - return (Module["_sqlite3_get_auxdata"] = - Module["asm"]["sqlite3_get_auxdata"]).apply(null, arguments); - }; + (Module['_sqlite3_get_auxdata'] = function () { + return (Module['_sqlite3_get_auxdata'] = + Module['asm']['sqlite3_get_auxdata']).apply(null, arguments); + }); - Module["_sqlite3_set_auxdata"] = function () { - return (Module["_sqlite3_set_auxdata"] = - Module["asm"]["sqlite3_set_auxdata"]).apply(null, arguments); - }; + (Module['_sqlite3_set_auxdata'] = function () { + return (Module['_sqlite3_set_auxdata'] = + Module['asm']['sqlite3_set_auxdata']).apply(null, arguments); + }); - Module["_sqlite3_column_count"] = function () { - return (Module["_sqlite3_column_count"] = - Module["asm"]["sqlite3_column_count"]).apply(null, arguments); - }; + (Module['_sqlite3_column_count'] = function () { + return (Module['_sqlite3_column_count'] = + Module['asm']['sqlite3_column_count']).apply(null, arguments); + }); - Module["_sqlite3_data_count"] = function () { - return (Module["_sqlite3_data_count"] = - Module["asm"]["sqlite3_data_count"]).apply(null, arguments); - }; + (Module['_sqlite3_data_count'] = function () { + return (Module['_sqlite3_data_count'] = + Module['asm']['sqlite3_data_count']).apply(null, arguments); + }); - Module["_sqlite3_column_blob"] = function () { - return (Module["_sqlite3_column_blob"] = - Module["asm"]["sqlite3_column_blob"]).apply(null, arguments); - }; + (Module['_sqlite3_column_blob'] = function () { + return (Module['_sqlite3_column_blob'] = + Module['asm']['sqlite3_column_blob']).apply(null, arguments); + }); - Module["_sqlite3_column_bytes"] = function () { - return (Module["_sqlite3_column_bytes"] = - Module["asm"]["sqlite3_column_bytes"]).apply(null, arguments); - }; + (Module['_sqlite3_column_bytes'] = function () { + return (Module['_sqlite3_column_bytes'] = + Module['asm']['sqlite3_column_bytes']).apply(null, arguments); + }); - Module["_sqlite3_column_double"] = function () { - return (Module["_sqlite3_column_double"] = - Module["asm"]["sqlite3_column_double"]).apply(null, arguments); - }; + (Module['_sqlite3_column_double'] = + function () { + return (Module['_sqlite3_column_double'] = + Module['asm']['sqlite3_column_double']).apply(null, arguments); + }); - Module["_sqlite3_column_value"] = function () { - return (Module["_sqlite3_column_value"] = - Module["asm"]["sqlite3_column_value"]).apply(null, arguments); - }; + (Module['_sqlite3_column_value'] = function () { + return (Module['_sqlite3_column_value'] = + Module['asm']['sqlite3_column_value']).apply(null, arguments); + }); - Module["_sqlite3_bind_blob"] = function () { - return (Module["_sqlite3_bind_blob"] = - Module["asm"]["sqlite3_bind_blob"]).apply(null, arguments); - }; + (Module['_sqlite3_bind_blob'] = function () { + return (Module['_sqlite3_bind_blob'] = + Module['asm']['sqlite3_bind_blob']).apply(null, arguments); + }); - Module["_sqlite3_bind_double"] = function () { - return (Module["_sqlite3_bind_double"] = - Module["asm"]["sqlite3_bind_double"]).apply(null, arguments); - }; + (Module['_sqlite3_bind_double'] = function () { + return (Module['_sqlite3_bind_double'] = + Module['asm']['sqlite3_bind_double']).apply(null, arguments); + }); - Module["_sqlite3_bind_int"] = function () { - return (Module["_sqlite3_bind_int"] = - Module["asm"]["sqlite3_bind_int"]).apply(null, arguments); - }; + (Module['_sqlite3_bind_int'] = function () { + return (Module['_sqlite3_bind_int'] = + Module['asm']['sqlite3_bind_int']).apply(null, arguments); + }); - Module["_sqlite3_bind_int64"] = function () { - return (Module["_sqlite3_bind_int64"] = - Module["asm"]["sqlite3_bind_int64"]).apply(null, arguments); - }; + (Module['_sqlite3_bind_int64'] = function () { + return (Module['_sqlite3_bind_int64'] = + Module['asm']['sqlite3_bind_int64']).apply(null, arguments); + }); - Module["_sqlite3_bind_null"] = function () { - return (Module["_sqlite3_bind_null"] = - Module["asm"]["sqlite3_bind_null"]).apply(null, arguments); - }; + (Module['_sqlite3_bind_null'] = function () { + return (Module['_sqlite3_bind_null'] = + Module['asm']['sqlite3_bind_null']).apply(null, arguments); + }); - Module["_sqlite3_bind_pointer"] = function () { - return (Module["_sqlite3_bind_pointer"] = - Module["asm"]["sqlite3_bind_pointer"]).apply(null, arguments); - }; + (Module['_sqlite3_bind_pointer'] = function () { + return (Module['_sqlite3_bind_pointer'] = + Module['asm']['sqlite3_bind_pointer']).apply(null, arguments); + }); - Module["_sqlite3_bind_text"] = function () { - return (Module["_sqlite3_bind_text"] = - Module["asm"]["sqlite3_bind_text"]).apply(null, arguments); - }; + (Module['_sqlite3_bind_text'] = function () { + return (Module['_sqlite3_bind_text'] = + Module['asm']['sqlite3_bind_text']).apply(null, arguments); + }); - Module["_sqlite3_bind_parameter_count"] = function () { - return (Module["_sqlite3_bind_parameter_count"] = - Module["asm"]["sqlite3_bind_parameter_count"]).apply(null, arguments); - }; + (Module[ + '_sqlite3_bind_parameter_count' + ] = function () { + return (Module[ + '_sqlite3_bind_parameter_count' + ] = + Module['asm']['sqlite3_bind_parameter_count']).apply(null, arguments); + }); - Module["_sqlite3_bind_parameter_index"] = function () { - return (Module["_sqlite3_bind_parameter_index"] = - Module["asm"]["sqlite3_bind_parameter_index"]).apply(null, arguments); - }; + (Module[ + '_sqlite3_bind_parameter_index' + ] = function () { + return (Module[ + '_sqlite3_bind_parameter_index' + ] = + Module['asm']['sqlite3_bind_parameter_index']).apply(null, arguments); + }); - Module["_sqlite3_db_handle"] = function () { - return (Module["_sqlite3_db_handle"] = - Module["asm"]["sqlite3_db_handle"]).apply(null, arguments); - }; + (Module['_sqlite3_db_handle'] = function () { + return (Module['_sqlite3_db_handle'] = + Module['asm']['sqlite3_db_handle']).apply(null, arguments); + }); - Module["_sqlite3_stmt_readonly"] = function () { - return (Module["_sqlite3_stmt_readonly"] = - Module["asm"]["sqlite3_stmt_readonly"]).apply(null, arguments); - }; + (Module['_sqlite3_stmt_readonly'] = + function () { + return (Module['_sqlite3_stmt_readonly'] = + Module['asm']['sqlite3_stmt_readonly']).apply(null, arguments); + }); - Module["_sqlite3_stmt_isexplain"] = function () { - return (Module["_sqlite3_stmt_isexplain"] = - Module["asm"]["sqlite3_stmt_isexplain"]).apply(null, arguments); - }; + (Module['_sqlite3_stmt_isexplain'] = + function () { + return (Module['_sqlite3_stmt_isexplain'] = + Module['asm']['sqlite3_stmt_isexplain']).apply(null, arguments); + }); - Module["_sqlite3_stmt_status"] = function () { - return (Module["_sqlite3_stmt_status"] = - Module["asm"]["sqlite3_stmt_status"]).apply(null, arguments); - }; + (Module['_sqlite3_stmt_status'] = function () { + return (Module['_sqlite3_stmt_status'] = + Module['asm']['sqlite3_stmt_status']).apply(null, arguments); + }); - Module["_sqlite3_sql"] = function () { - return (Module["_sqlite3_sql"] = Module["asm"]["sqlite3_sql"]).apply( - null, - arguments - ); - }; + (Module['_sqlite3_sql'] = function () { + return (Module['_sqlite3_sql'] = + Module['asm']['sqlite3_sql']).apply(null, arguments); + }); - Module["_sqlite3_expanded_sql"] = function () { - return (Module["_sqlite3_expanded_sql"] = - Module["asm"]["sqlite3_expanded_sql"]).apply(null, arguments); - }; + (Module['_sqlite3_expanded_sql'] = function () { + return (Module['_sqlite3_expanded_sql'] = + Module['asm']['sqlite3_expanded_sql']).apply(null, arguments); + }); - Module["_sqlite3_preupdate_old"] = function () { - return (Module["_sqlite3_preupdate_old"] = - Module["asm"]["sqlite3_preupdate_old"]).apply(null, arguments); - }; + (Module['_sqlite3_preupdate_old'] = + function () { + return (Module['_sqlite3_preupdate_old'] = + Module['asm']['sqlite3_preupdate_old']).apply(null, arguments); + }); - Module["_sqlite3_preupdate_count"] = function () { - return (Module["_sqlite3_preupdate_count"] = - Module["asm"]["sqlite3_preupdate_count"]).apply(null, arguments); - }; + (Module['_sqlite3_preupdate_count'] = + function () { + return (Module['_sqlite3_preupdate_count'] = + Module['asm']['sqlite3_preupdate_count']).apply(null, arguments); + }); - Module["_sqlite3_preupdate_depth"] = function () { - return (Module["_sqlite3_preupdate_depth"] = - Module["asm"]["sqlite3_preupdate_depth"]).apply(null, arguments); - }; + (Module['_sqlite3_preupdate_depth'] = + function () { + return (Module['_sqlite3_preupdate_depth'] = + Module['asm']['sqlite3_preupdate_depth']).apply(null, arguments); + }); - Module["_sqlite3_preupdate_blobwrite"] = function () { - return (Module["_sqlite3_preupdate_blobwrite"] = - Module["asm"]["sqlite3_preupdate_blobwrite"]).apply(null, arguments); - }; + (Module['_sqlite3_preupdate_blobwrite'] = + function () { + return (Module[ + '_sqlite3_preupdate_blobwrite' + ] = + Module['asm']['sqlite3_preupdate_blobwrite']).apply(null, arguments); + }); - Module["_sqlite3_preupdate_new"] = function () { - return (Module["_sqlite3_preupdate_new"] = - Module["asm"]["sqlite3_preupdate_new"]).apply(null, arguments); - }; + (Module['_sqlite3_preupdate_new'] = + function () { + return (Module['_sqlite3_preupdate_new'] = + Module['asm']['sqlite3_preupdate_new']).apply(null, arguments); + }); - Module["_sqlite3_value_numeric_type"] = function () { - return (Module["_sqlite3_value_numeric_type"] = - Module["asm"]["sqlite3_value_numeric_type"]).apply(null, arguments); - }; + (Module['_sqlite3_value_numeric_type'] = + function () { + return (Module[ + '_sqlite3_value_numeric_type' + ] = + Module['asm']['sqlite3_value_numeric_type']).apply(null, arguments); + }); - Module["_sqlite3_set_authorizer"] = function () { - return (Module["_sqlite3_set_authorizer"] = - Module["asm"]["sqlite3_set_authorizer"]).apply(null, arguments); - }; + (Module['_sqlite3_set_authorizer'] = + function () { + return (Module['_sqlite3_set_authorizer'] = + Module['asm']['sqlite3_set_authorizer']).apply(null, arguments); + }); - Module["_sqlite3_strglob"] = function () { - return (Module["_sqlite3_strglob"] = - Module["asm"]["sqlite3_strglob"]).apply(null, arguments); - }; + (Module['_sqlite3_strglob'] = function () { + return (Module['_sqlite3_strglob'] = + Module['asm']['sqlite3_strglob']).apply(null, arguments); + }); - Module["_sqlite3_strlike"] = function () { - return (Module["_sqlite3_strlike"] = - Module["asm"]["sqlite3_strlike"]).apply(null, arguments); - }; + (Module['_sqlite3_strlike'] = function () { + return (Module['_sqlite3_strlike'] = + Module['asm']['sqlite3_strlike']).apply(null, arguments); + }); - Module["_sqlite3_auto_extension"] = function () { - return (Module["_sqlite3_auto_extension"] = - Module["asm"]["sqlite3_auto_extension"]).apply(null, arguments); - }; + (Module['_sqlite3_auto_extension'] = + function () { + return (Module['_sqlite3_auto_extension'] = + Module['asm']['sqlite3_auto_extension']).apply(null, arguments); + }); - Module["_sqlite3_cancel_auto_extension"] = function () { - return (Module["_sqlite3_cancel_auto_extension"] = - Module["asm"]["sqlite3_cancel_auto_extension"]).apply(null, arguments); - }; + (Module[ + '_sqlite3_cancel_auto_extension' + ] = function () { + return (Module[ + '_sqlite3_cancel_auto_extension' + ] = + Module['asm']['sqlite3_cancel_auto_extension']).apply(null, arguments); + }); - Module["_sqlite3_reset_auto_extension"] = function () { - return (Module["_sqlite3_reset_auto_extension"] = - Module["asm"]["sqlite3_reset_auto_extension"]).apply(null, arguments); - }; + (Module[ + '_sqlite3_reset_auto_extension' + ] = function () { + return (Module[ + '_sqlite3_reset_auto_extension' + ] = + Module['asm']['sqlite3_reset_auto_extension']).apply(null, arguments); + }); - Module["_sqlite3_prepare_v3"] = function () { - return (Module["_sqlite3_prepare_v3"] = - Module["asm"]["sqlite3_prepare_v3"]).apply(null, arguments); - }; + (Module['_sqlite3_prepare_v3'] = function () { + return (Module['_sqlite3_prepare_v3'] = + Module['asm']['sqlite3_prepare_v3']).apply(null, arguments); + }); - Module["_sqlite3_create_module"] = function () { - return (Module["_sqlite3_create_module"] = - Module["asm"]["sqlite3_create_module"]).apply(null, arguments); - }; + (Module['_sqlite3_create_module'] = + function () { + return (Module['_sqlite3_create_module'] = + Module['asm']['sqlite3_create_module']).apply(null, arguments); + }); - Module["_sqlite3_create_module_v2"] = function () { - return (Module["_sqlite3_create_module_v2"] = - Module["asm"]["sqlite3_create_module_v2"]).apply(null, arguments); - }; + (Module['_sqlite3_create_module_v2'] = + function () { + return (Module[ + '_sqlite3_create_module_v2' + ] = + Module['asm']['sqlite3_create_module_v2']).apply(null, arguments); + }); - Module["_sqlite3_drop_modules"] = function () { - return (Module["_sqlite3_drop_modules"] = - Module["asm"]["sqlite3_drop_modules"]).apply(null, arguments); - }; + (Module['_sqlite3_drop_modules'] = function () { + return (Module['_sqlite3_drop_modules'] = + Module['asm']['sqlite3_drop_modules']).apply(null, arguments); + }); - Module["_sqlite3_declare_vtab"] = function () { - return (Module["_sqlite3_declare_vtab"] = - Module["asm"]["sqlite3_declare_vtab"]).apply(null, arguments); - }; + (Module['_sqlite3_declare_vtab'] = function () { + return (Module['_sqlite3_declare_vtab'] = + Module['asm']['sqlite3_declare_vtab']).apply(null, arguments); + }); - Module["_sqlite3_vtab_on_conflict"] = function () { - return (Module["_sqlite3_vtab_on_conflict"] = - Module["asm"]["sqlite3_vtab_on_conflict"]).apply(null, arguments); - }; + (Module['_sqlite3_vtab_on_conflict'] = + function () { + return (Module[ + '_sqlite3_vtab_on_conflict' + ] = + Module['asm']['sqlite3_vtab_on_conflict']).apply(null, arguments); + }); - Module["_sqlite3_vtab_collation"] = function () { - return (Module["_sqlite3_vtab_collation"] = - Module["asm"]["sqlite3_vtab_collation"]).apply(null, arguments); - }; + (Module['_sqlite3_vtab_collation'] = + function () { + return (Module['_sqlite3_vtab_collation'] = + Module['asm']['sqlite3_vtab_collation']).apply(null, arguments); + }); - Module["_sqlite3_vtab_in"] = function () { - return (Module["_sqlite3_vtab_in"] = - Module["asm"]["sqlite3_vtab_in"]).apply(null, arguments); - }; + (Module['_sqlite3_vtab_in'] = function () { + return (Module['_sqlite3_vtab_in'] = + Module['asm']['sqlite3_vtab_in']).apply(null, arguments); + }); - Module["_sqlite3_vtab_rhs_value"] = function () { - return (Module["_sqlite3_vtab_rhs_value"] = - Module["asm"]["sqlite3_vtab_rhs_value"]).apply(null, arguments); - }; + (Module['_sqlite3_vtab_rhs_value'] = + function () { + return (Module['_sqlite3_vtab_rhs_value'] = + Module['asm']['sqlite3_vtab_rhs_value']).apply(null, arguments); + }); - Module["_sqlite3_vtab_distinct"] = function () { - return (Module["_sqlite3_vtab_distinct"] = - Module["asm"]["sqlite3_vtab_distinct"]).apply(null, arguments); - }; + (Module['_sqlite3_vtab_distinct'] = + function () { + return (Module['_sqlite3_vtab_distinct'] = + Module['asm']['sqlite3_vtab_distinct']).apply(null, arguments); + }); - Module["_sqlite3_keyword_name"] = function () { - return (Module["_sqlite3_keyword_name"] = - Module["asm"]["sqlite3_keyword_name"]).apply(null, arguments); - }; + (Module['_sqlite3_keyword_name'] = function () { + return (Module['_sqlite3_keyword_name'] = + Module['asm']['sqlite3_keyword_name']).apply(null, arguments); + }); - Module["_sqlite3_keyword_count"] = function () { - return (Module["_sqlite3_keyword_count"] = - Module["asm"]["sqlite3_keyword_count"]).apply(null, arguments); - }; + (Module['_sqlite3_keyword_count'] = + function () { + return (Module['_sqlite3_keyword_count'] = + Module['asm']['sqlite3_keyword_count']).apply(null, arguments); + }); - Module["_sqlite3_keyword_check"] = function () { - return (Module["_sqlite3_keyword_check"] = - Module["asm"]["sqlite3_keyword_check"]).apply(null, arguments); - }; + (Module['_sqlite3_keyword_check'] = + function () { + return (Module['_sqlite3_keyword_check'] = + Module['asm']['sqlite3_keyword_check']).apply(null, arguments); + }); - Module["_sqlite3_complete"] = function () { - return (Module["_sqlite3_complete"] = - Module["asm"]["sqlite3_complete"]).apply(null, arguments); - }; + (Module['_sqlite3_complete'] = function () { + return (Module['_sqlite3_complete'] = + Module['asm']['sqlite3_complete']).apply(null, arguments); + }); - Module["_sqlite3_libversion"] = function () { - return (Module["_sqlite3_libversion"] = - Module["asm"]["sqlite3_libversion"]).apply(null, arguments); - }; + (Module['_sqlite3_libversion'] = function () { + return (Module['_sqlite3_libversion'] = + Module['asm']['sqlite3_libversion']).apply(null, arguments); + }); - Module["_sqlite3_libversion_number"] = function () { - return (Module["_sqlite3_libversion_number"] = - Module["asm"]["sqlite3_libversion_number"]).apply(null, arguments); - }; + (Module['_sqlite3_libversion_number'] = + function () { + return (Module[ + '_sqlite3_libversion_number' + ] = + Module['asm']['sqlite3_libversion_number']).apply(null, arguments); + }); - Module["_sqlite3_shutdown"] = function () { - return (Module["_sqlite3_shutdown"] = - Module["asm"]["sqlite3_shutdown"]).apply(null, arguments); - }; + (Module['_sqlite3_shutdown'] = function () { + return (Module['_sqlite3_shutdown'] = + Module['asm']['sqlite3_shutdown']).apply(null, arguments); + }); - Module["_sqlite3_last_insert_rowid"] = function () { - return (Module["_sqlite3_last_insert_rowid"] = - Module["asm"]["sqlite3_last_insert_rowid"]).apply(null, arguments); - }; + (Module['_sqlite3_last_insert_rowid'] = + function () { + return (Module[ + '_sqlite3_last_insert_rowid' + ] = + Module['asm']['sqlite3_last_insert_rowid']).apply(null, arguments); + }); - Module["_sqlite3_set_last_insert_rowid"] = function () { - return (Module["_sqlite3_set_last_insert_rowid"] = - Module["asm"]["sqlite3_set_last_insert_rowid"]).apply(null, arguments); - }; + (Module[ + '_sqlite3_set_last_insert_rowid' + ] = function () { + return (Module[ + '_sqlite3_set_last_insert_rowid' + ] = + Module['asm']['sqlite3_set_last_insert_rowid']).apply(null, arguments); + }); - Module["_sqlite3_changes64"] = function () { - return (Module["_sqlite3_changes64"] = - Module["asm"]["sqlite3_changes64"]).apply(null, arguments); - }; + (Module['_sqlite3_changes64'] = function () { + return (Module['_sqlite3_changes64'] = + Module['asm']['sqlite3_changes64']).apply(null, arguments); + }); - Module["_sqlite3_changes"] = function () { - return (Module["_sqlite3_changes"] = - Module["asm"]["sqlite3_changes"]).apply(null, arguments); - }; + (Module['_sqlite3_changes'] = function () { + return (Module['_sqlite3_changes'] = + Module['asm']['sqlite3_changes']).apply(null, arguments); + }); - Module["_sqlite3_total_changes64"] = function () { - return (Module["_sqlite3_total_changes64"] = - Module["asm"]["sqlite3_total_changes64"]).apply(null, arguments); - }; + (Module['_sqlite3_total_changes64'] = + function () { + return (Module['_sqlite3_total_changes64'] = + Module['asm']['sqlite3_total_changes64']).apply(null, arguments); + }); - Module["_sqlite3_total_changes"] = function () { - return (Module["_sqlite3_total_changes"] = - Module["asm"]["sqlite3_total_changes"]).apply(null, arguments); - }; + (Module['_sqlite3_total_changes'] = + function () { + return (Module['_sqlite3_total_changes'] = + Module['asm']['sqlite3_total_changes']).apply(null, arguments); + }); - Module["_sqlite3_txn_state"] = function () { - return (Module["_sqlite3_txn_state"] = - Module["asm"]["sqlite3_txn_state"]).apply(null, arguments); - }; + (Module['_sqlite3_txn_state'] = function () { + return (Module['_sqlite3_txn_state'] = + Module['asm']['sqlite3_txn_state']).apply(null, arguments); + }); - Module["_sqlite3_close_v2"] = function () { - return (Module["_sqlite3_close_v2"] = - Module["asm"]["sqlite3_close_v2"]).apply(null, arguments); - }; + (Module['_sqlite3_close_v2'] = function () { + return (Module['_sqlite3_close_v2'] = + Module['asm']['sqlite3_close_v2']).apply(null, arguments); + }); - Module["_sqlite3_busy_handler"] = function () { - return (Module["_sqlite3_busy_handler"] = - Module["asm"]["sqlite3_busy_handler"]).apply(null, arguments); - }; + (Module['_sqlite3_busy_handler'] = function () { + return (Module['_sqlite3_busy_handler'] = + Module['asm']['sqlite3_busy_handler']).apply(null, arguments); + }); - Module["_sqlite3_progress_handler"] = function () { - return (Module["_sqlite3_progress_handler"] = - Module["asm"]["sqlite3_progress_handler"]).apply(null, arguments); - }; + (Module['_sqlite3_progress_handler'] = + function () { + return (Module[ + '_sqlite3_progress_handler' + ] = + Module['asm']['sqlite3_progress_handler']).apply(null, arguments); + }); - Module["_sqlite3_busy_timeout"] = function () { - return (Module["_sqlite3_busy_timeout"] = - Module["asm"]["sqlite3_busy_timeout"]).apply(null, arguments); - }; + (Module['_sqlite3_busy_timeout'] = function () { + return (Module['_sqlite3_busy_timeout'] = + Module['asm']['sqlite3_busy_timeout']).apply(null, arguments); + }); - Module["_sqlite3_create_function"] = function () { - return (Module["_sqlite3_create_function"] = - Module["asm"]["sqlite3_create_function"]).apply(null, arguments); - }; + (Module['_sqlite3_create_function'] = + function () { + return (Module['_sqlite3_create_function'] = + Module['asm']['sqlite3_create_function']).apply(null, arguments); + }); - Module["_sqlite3_create_function_v2"] = function () { - return (Module["_sqlite3_create_function_v2"] = - Module["asm"]["sqlite3_create_function_v2"]).apply(null, arguments); - }; + (Module['_sqlite3_create_function_v2'] = + function () { + return (Module[ + '_sqlite3_create_function_v2' + ] = + Module['asm']['sqlite3_create_function_v2']).apply(null, arguments); + }); - Module["_sqlite3_create_window_function"] = function () { - return (Module["_sqlite3_create_window_function"] = - Module["asm"]["sqlite3_create_window_function"]).apply(null, arguments); - }; + (Module[ + '_sqlite3_create_window_function' + ] = function () { + return (Module[ + '_sqlite3_create_window_function' + ] = + Module['asm']['sqlite3_create_window_function']).apply(null, arguments); + }); - Module["_sqlite3_overload_function"] = function () { - return (Module["_sqlite3_overload_function"] = - Module["asm"]["sqlite3_overload_function"]).apply(null, arguments); - }; + (Module['_sqlite3_overload_function'] = + function () { + return (Module[ + '_sqlite3_overload_function' + ] = + Module['asm']['sqlite3_overload_function']).apply(null, arguments); + }); - Module["_sqlite3_trace_v2"] = function () { - return (Module["_sqlite3_trace_v2"] = - Module["asm"]["sqlite3_trace_v2"]).apply(null, arguments); - }; + (Module['_sqlite3_trace_v2'] = function () { + return (Module['_sqlite3_trace_v2'] = + Module['asm']['sqlite3_trace_v2']).apply(null, arguments); + }); - Module["_sqlite3_commit_hook"] = function () { - return (Module["_sqlite3_commit_hook"] = - Module["asm"]["sqlite3_commit_hook"]).apply(null, arguments); - }; + (Module['_sqlite3_commit_hook'] = function () { + return (Module['_sqlite3_commit_hook'] = + Module['asm']['sqlite3_commit_hook']).apply(null, arguments); + }); - Module["_sqlite3_update_hook"] = function () { - return (Module["_sqlite3_update_hook"] = - Module["asm"]["sqlite3_update_hook"]).apply(null, arguments); - }; + (Module['_sqlite3_update_hook'] = function () { + return (Module['_sqlite3_update_hook'] = + Module['asm']['sqlite3_update_hook']).apply(null, arguments); + }); - Module["_sqlite3_rollback_hook"] = function () { - return (Module["_sqlite3_rollback_hook"] = - Module["asm"]["sqlite3_rollback_hook"]).apply(null, arguments); - }; + (Module['_sqlite3_rollback_hook'] = + function () { + return (Module['_sqlite3_rollback_hook'] = + Module['asm']['sqlite3_rollback_hook']).apply(null, arguments); + }); - Module["_sqlite3_preupdate_hook"] = function () { - return (Module["_sqlite3_preupdate_hook"] = - Module["asm"]["sqlite3_preupdate_hook"]).apply(null, arguments); - }; + (Module['_sqlite3_preupdate_hook'] = + function () { + return (Module['_sqlite3_preupdate_hook'] = + Module['asm']['sqlite3_preupdate_hook']).apply(null, arguments); + }); - Module["_sqlite3_error_offset"] = function () { - return (Module["_sqlite3_error_offset"] = - Module["asm"]["sqlite3_error_offset"]).apply(null, arguments); - }; + (Module['_sqlite3_error_offset'] = function () { + return (Module['_sqlite3_error_offset'] = + Module['asm']['sqlite3_error_offset']).apply(null, arguments); + }); - Module["_sqlite3_errcode"] = function () { - return (Module["_sqlite3_errcode"] = - Module["asm"]["sqlite3_errcode"]).apply(null, arguments); - }; + (Module['_sqlite3_errcode'] = function () { + return (Module['_sqlite3_errcode'] = + Module['asm']['sqlite3_errcode']).apply(null, arguments); + }); - Module["_sqlite3_extended_errcode"] = function () { - return (Module["_sqlite3_extended_errcode"] = - Module["asm"]["sqlite3_extended_errcode"]).apply(null, arguments); - }; + (Module['_sqlite3_extended_errcode'] = + function () { + return (Module[ + '_sqlite3_extended_errcode' + ] = + Module['asm']['sqlite3_extended_errcode']).apply(null, arguments); + }); - Module["_sqlite3_errstr"] = function () { - return (Module["_sqlite3_errstr"] = - Module["asm"]["sqlite3_errstr"]).apply(null, arguments); - }; + (Module['_sqlite3_errstr'] = function () { + return (Module['_sqlite3_errstr'] = + Module['asm']['sqlite3_errstr']).apply(null, arguments); + }); - Module["_sqlite3_limit"] = function () { - return (Module["_sqlite3_limit"] = Module["asm"]["sqlite3_limit"]).apply( - null, - arguments - ); - }; + (Module['_sqlite3_limit'] = function () { + return (Module['_sqlite3_limit'] = + Module['asm']['sqlite3_limit']).apply(null, arguments); + }); - Module["_sqlite3_open"] = function () { - return (Module["_sqlite3_open"] = Module["asm"]["sqlite3_open"]).apply( - null, - arguments - ); - }; + (Module['_sqlite3_open'] = function () { + return (Module['_sqlite3_open'] = + Module['asm']['sqlite3_open']).apply(null, arguments); + }); - Module["_sqlite3_open_v2"] = function () { - return (Module["_sqlite3_open_v2"] = - Module["asm"]["sqlite3_open_v2"]).apply(null, arguments); - }; + (Module['_sqlite3_open_v2'] = function () { + return (Module['_sqlite3_open_v2'] = + Module['asm']['sqlite3_open_v2']).apply(null, arguments); + }); - Module["_sqlite3_create_collation"] = function () { - return (Module["_sqlite3_create_collation"] = - Module["asm"]["sqlite3_create_collation"]).apply(null, arguments); - }; + (Module['_sqlite3_create_collation'] = + function () { + return (Module[ + '_sqlite3_create_collation' + ] = + Module['asm']['sqlite3_create_collation']).apply(null, arguments); + }); - Module["_sqlite3_create_collation_v2"] = function () { - return (Module["_sqlite3_create_collation_v2"] = - Module["asm"]["sqlite3_create_collation_v2"]).apply(null, arguments); - }; + (Module['_sqlite3_create_collation_v2'] = + function () { + return (Module[ + '_sqlite3_create_collation_v2' + ] = + Module['asm']['sqlite3_create_collation_v2']).apply(null, arguments); + }); - Module["_sqlite3_collation_needed"] = function () { - return (Module["_sqlite3_collation_needed"] = - Module["asm"]["sqlite3_collation_needed"]).apply(null, arguments); - }; + (Module['_sqlite3_collation_needed'] = + function () { + return (Module[ + '_sqlite3_collation_needed' + ] = + Module['asm']['sqlite3_collation_needed']).apply(null, arguments); + }); - Module["_sqlite3_get_autocommit"] = function () { - return (Module["_sqlite3_get_autocommit"] = - Module["asm"]["sqlite3_get_autocommit"]).apply(null, arguments); - }; + (Module['_sqlite3_get_autocommit'] = + function () { + return (Module['_sqlite3_get_autocommit'] = + Module['asm']['sqlite3_get_autocommit']).apply(null, arguments); + }); - Module["_sqlite3_table_column_metadata"] = function () { - return (Module["_sqlite3_table_column_metadata"] = - Module["asm"]["sqlite3_table_column_metadata"]).apply(null, arguments); - }; + (Module[ + '_sqlite3_table_column_metadata' + ] = function () { + return (Module[ + '_sqlite3_table_column_metadata' + ] = + Module['asm']['sqlite3_table_column_metadata']).apply(null, arguments); + }); - Module["_sqlite3_extended_result_codes"] = function () { - return (Module["_sqlite3_extended_result_codes"] = - Module["asm"]["sqlite3_extended_result_codes"]).apply(null, arguments); - }; + (Module[ + '_sqlite3_extended_result_codes' + ] = function () { + return (Module[ + '_sqlite3_extended_result_codes' + ] = + Module['asm']['sqlite3_extended_result_codes']).apply(null, arguments); + }); - Module["_sqlite3_uri_key"] = function () { - return (Module["_sqlite3_uri_key"] = - Module["asm"]["sqlite3_uri_key"]).apply(null, arguments); - }; + (Module['_sqlite3_uri_key'] = function () { + return (Module['_sqlite3_uri_key'] = + Module['asm']['sqlite3_uri_key']).apply(null, arguments); + }); - Module["_sqlite3_uri_int64"] = function () { - return (Module["_sqlite3_uri_int64"] = - Module["asm"]["sqlite3_uri_int64"]).apply(null, arguments); - }; + (Module['_sqlite3_uri_int64'] = function () { + return (Module['_sqlite3_uri_int64'] = + Module['asm']['sqlite3_uri_int64']).apply(null, arguments); + }); - Module["_sqlite3_db_name"] = function () { - return (Module["_sqlite3_db_name"] = - Module["asm"]["sqlite3_db_name"]).apply(null, arguments); - }; + (Module['_sqlite3_db_name'] = function () { + return (Module['_sqlite3_db_name'] = + Module['asm']['sqlite3_db_name']).apply(null, arguments); + }); - Module["_sqlite3_db_filename"] = function () { - return (Module["_sqlite3_db_filename"] = - Module["asm"]["sqlite3_db_filename"]).apply(null, arguments); - }; + (Module['_sqlite3_db_filename'] = function () { + return (Module['_sqlite3_db_filename'] = + Module['asm']['sqlite3_db_filename']).apply(null, arguments); + }); - Module["_sqlite3_compileoption_used"] = function () { - return (Module["_sqlite3_compileoption_used"] = - Module["asm"]["sqlite3_compileoption_used"]).apply(null, arguments); - }; + (Module['_sqlite3_compileoption_used'] = + function () { + return (Module[ + '_sqlite3_compileoption_used' + ] = + Module['asm']['sqlite3_compileoption_used']).apply(null, arguments); + }); - Module["_sqlite3_compileoption_get"] = function () { - return (Module["_sqlite3_compileoption_get"] = - Module["asm"]["sqlite3_compileoption_get"]).apply(null, arguments); - }; + (Module['_sqlite3_compileoption_get'] = + function () { + return (Module[ + '_sqlite3_compileoption_get' + ] = + Module['asm']['sqlite3_compileoption_get']).apply(null, arguments); + }); - Module["_sqlite3session_diff"] = function () { - return (Module["_sqlite3session_diff"] = - Module["asm"]["sqlite3session_diff"]).apply(null, arguments); - }; + (Module['_sqlite3session_diff'] = function () { + return (Module['_sqlite3session_diff'] = + Module['asm']['sqlite3session_diff']).apply(null, arguments); + }); - Module["_sqlite3session_attach"] = function () { - return (Module["_sqlite3session_attach"] = - Module["asm"]["sqlite3session_attach"]).apply(null, arguments); - }; + (Module['_sqlite3session_attach'] = + function () { + return (Module['_sqlite3session_attach'] = + Module['asm']['sqlite3session_attach']).apply(null, arguments); + }); - Module["_sqlite3session_create"] = function () { - return (Module["_sqlite3session_create"] = - Module["asm"]["sqlite3session_create"]).apply(null, arguments); - }; + (Module['_sqlite3session_create'] = + function () { + return (Module['_sqlite3session_create'] = + Module['asm']['sqlite3session_create']).apply(null, arguments); + }); - Module["_sqlite3session_delete"] = function () { - return (Module["_sqlite3session_delete"] = - Module["asm"]["sqlite3session_delete"]).apply(null, arguments); - }; + (Module['_sqlite3session_delete'] = + function () { + return (Module['_sqlite3session_delete'] = + Module['asm']['sqlite3session_delete']).apply(null, arguments); + }); - Module["_sqlite3session_table_filter"] = function () { - return (Module["_sqlite3session_table_filter"] = - Module["asm"]["sqlite3session_table_filter"]).apply(null, arguments); - }; + (Module['_sqlite3session_table_filter'] = + function () { + return (Module[ + '_sqlite3session_table_filter' + ] = + Module['asm']['sqlite3session_table_filter']).apply(null, arguments); + }); - Module["_sqlite3session_changeset"] = function () { - return (Module["_sqlite3session_changeset"] = - Module["asm"]["sqlite3session_changeset"]).apply(null, arguments); - }; + (Module['_sqlite3session_changeset'] = + function () { + return (Module[ + '_sqlite3session_changeset' + ] = + Module['asm']['sqlite3session_changeset']).apply(null, arguments); + }); - Module["_sqlite3session_changeset_strm"] = function () { - return (Module["_sqlite3session_changeset_strm"] = - Module["asm"]["sqlite3session_changeset_strm"]).apply(null, arguments); - }; + (Module[ + '_sqlite3session_changeset_strm' + ] = function () { + return (Module[ + '_sqlite3session_changeset_strm' + ] = + Module['asm']['sqlite3session_changeset_strm']).apply(null, arguments); + }); - Module["_sqlite3session_patchset_strm"] = function () { - return (Module["_sqlite3session_patchset_strm"] = - Module["asm"]["sqlite3session_patchset_strm"]).apply(null, arguments); - }; + (Module[ + '_sqlite3session_patchset_strm' + ] = function () { + return (Module[ + '_sqlite3session_patchset_strm' + ] = + Module['asm']['sqlite3session_patchset_strm']).apply(null, arguments); + }); - Module["_sqlite3session_patchset"] = function () { - return (Module["_sqlite3session_patchset"] = - Module["asm"]["sqlite3session_patchset"]).apply(null, arguments); - }; + (Module['_sqlite3session_patchset'] = + function () { + return (Module['_sqlite3session_patchset'] = + Module['asm']['sqlite3session_patchset']).apply(null, arguments); + }); - Module["_sqlite3session_enable"] = function () { - return (Module["_sqlite3session_enable"] = - Module["asm"]["sqlite3session_enable"]).apply(null, arguments); - }; + (Module['_sqlite3session_enable'] = + function () { + return (Module['_sqlite3session_enable'] = + Module['asm']['sqlite3session_enable']).apply(null, arguments); + }); - Module["_sqlite3session_indirect"] = function () { - return (Module["_sqlite3session_indirect"] = - Module["asm"]["sqlite3session_indirect"]).apply(null, arguments); - }; + (Module['_sqlite3session_indirect'] = + function () { + return (Module['_sqlite3session_indirect'] = + Module['asm']['sqlite3session_indirect']).apply(null, arguments); + }); - Module["_sqlite3session_isempty"] = function () { - return (Module["_sqlite3session_isempty"] = - Module["asm"]["sqlite3session_isempty"]).apply(null, arguments); - }; + (Module['_sqlite3session_isempty'] = + function () { + return (Module['_sqlite3session_isempty'] = + Module['asm']['sqlite3session_isempty']).apply(null, arguments); + }); - Module["_sqlite3session_memory_used"] = function () { - return (Module["_sqlite3session_memory_used"] = - Module["asm"]["sqlite3session_memory_used"]).apply(null, arguments); - }; + (Module['_sqlite3session_memory_used'] = + function () { + return (Module[ + '_sqlite3session_memory_used' + ] = + Module['asm']['sqlite3session_memory_used']).apply(null, arguments); + }); - Module["_sqlite3session_object_config"] = function () { - return (Module["_sqlite3session_object_config"] = - Module["asm"]["sqlite3session_object_config"]).apply(null, arguments); - }; + (Module[ + '_sqlite3session_object_config' + ] = function () { + return (Module[ + '_sqlite3session_object_config' + ] = + Module['asm']['sqlite3session_object_config']).apply(null, arguments); + }); - Module["_sqlite3session_changeset_size"] = function () { - return (Module["_sqlite3session_changeset_size"] = - Module["asm"]["sqlite3session_changeset_size"]).apply(null, arguments); - }; + (Module[ + '_sqlite3session_changeset_size' + ] = function () { + return (Module[ + '_sqlite3session_changeset_size' + ] = + Module['asm']['sqlite3session_changeset_size']).apply(null, arguments); + }); - Module["_sqlite3changeset_start"] = function () { - return (Module["_sqlite3changeset_start"] = - Module["asm"]["sqlite3changeset_start"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_start'] = + function () { + return (Module['_sqlite3changeset_start'] = + Module['asm']['sqlite3changeset_start']).apply(null, arguments); + }); - Module["_sqlite3changeset_start_v2"] = function () { - return (Module["_sqlite3changeset_start_v2"] = - Module["asm"]["sqlite3changeset_start_v2"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_start_v2'] = + function () { + return (Module[ + '_sqlite3changeset_start_v2' + ] = + Module['asm']['sqlite3changeset_start_v2']).apply(null, arguments); + }); - Module["_sqlite3changeset_start_strm"] = function () { - return (Module["_sqlite3changeset_start_strm"] = - Module["asm"]["sqlite3changeset_start_strm"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_start_strm'] = + function () { + return (Module[ + '_sqlite3changeset_start_strm' + ] = + Module['asm']['sqlite3changeset_start_strm']).apply(null, arguments); + }); - Module["_sqlite3changeset_start_v2_strm"] = function () { - return (Module["_sqlite3changeset_start_v2_strm"] = - Module["asm"]["sqlite3changeset_start_v2_strm"]).apply(null, arguments); - }; + (Module[ + '_sqlite3changeset_start_v2_strm' + ] = function () { + return (Module[ + '_sqlite3changeset_start_v2_strm' + ] = + Module['asm']['sqlite3changeset_start_v2_strm']).apply(null, arguments); + }); - Module["_sqlite3changeset_next"] = function () { - return (Module["_sqlite3changeset_next"] = - Module["asm"]["sqlite3changeset_next"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_next'] = + function () { + return (Module['_sqlite3changeset_next'] = + Module['asm']['sqlite3changeset_next']).apply(null, arguments); + }); - Module["_sqlite3changeset_op"] = function () { - return (Module["_sqlite3changeset_op"] = - Module["asm"]["sqlite3changeset_op"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_op'] = function () { + return (Module['_sqlite3changeset_op'] = + Module['asm']['sqlite3changeset_op']).apply(null, arguments); + }); - Module["_sqlite3changeset_pk"] = function () { - return (Module["_sqlite3changeset_pk"] = - Module["asm"]["sqlite3changeset_pk"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_pk'] = function () { + return (Module['_sqlite3changeset_pk'] = + Module['asm']['sqlite3changeset_pk']).apply(null, arguments); + }); - Module["_sqlite3changeset_old"] = function () { - return (Module["_sqlite3changeset_old"] = - Module["asm"]["sqlite3changeset_old"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_old'] = function () { + return (Module['_sqlite3changeset_old'] = + Module['asm']['sqlite3changeset_old']).apply(null, arguments); + }); - Module["_sqlite3changeset_new"] = function () { - return (Module["_sqlite3changeset_new"] = - Module["asm"]["sqlite3changeset_new"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_new'] = function () { + return (Module['_sqlite3changeset_new'] = + Module['asm']['sqlite3changeset_new']).apply(null, arguments); + }); - Module["_sqlite3changeset_conflict"] = function () { - return (Module["_sqlite3changeset_conflict"] = - Module["asm"]["sqlite3changeset_conflict"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_conflict'] = + function () { + return (Module[ + '_sqlite3changeset_conflict' + ] = + Module['asm']['sqlite3changeset_conflict']).apply(null, arguments); + }); - Module["_sqlite3changeset_fk_conflicts"] = function () { - return (Module["_sqlite3changeset_fk_conflicts"] = - Module["asm"]["sqlite3changeset_fk_conflicts"]).apply(null, arguments); - }; + (Module[ + '_sqlite3changeset_fk_conflicts' + ] = function () { + return (Module[ + '_sqlite3changeset_fk_conflicts' + ] = + Module['asm']['sqlite3changeset_fk_conflicts']).apply(null, arguments); + }); - Module["_sqlite3changeset_finalize"] = function () { - return (Module["_sqlite3changeset_finalize"] = - Module["asm"]["sqlite3changeset_finalize"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_finalize'] = + function () { + return (Module[ + '_sqlite3changeset_finalize' + ] = + Module['asm']['sqlite3changeset_finalize']).apply(null, arguments); + }); - Module["_sqlite3changeset_invert"] = function () { - return (Module["_sqlite3changeset_invert"] = - Module["asm"]["sqlite3changeset_invert"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_invert'] = + function () { + return (Module['_sqlite3changeset_invert'] = + Module['asm']['sqlite3changeset_invert']).apply(null, arguments); + }); - Module["_sqlite3changeset_invert_strm"] = function () { - return (Module["_sqlite3changeset_invert_strm"] = - Module["asm"]["sqlite3changeset_invert_strm"]).apply(null, arguments); - }; + (Module[ + '_sqlite3changeset_invert_strm' + ] = function () { + return (Module[ + '_sqlite3changeset_invert_strm' + ] = + Module['asm']['sqlite3changeset_invert_strm']).apply(null, arguments); + }); - Module["_sqlite3changeset_apply_v2"] = function () { - return (Module["_sqlite3changeset_apply_v2"] = - Module["asm"]["sqlite3changeset_apply_v2"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_apply_v2'] = + function () { + return (Module[ + '_sqlite3changeset_apply_v2' + ] = + Module['asm']['sqlite3changeset_apply_v2']).apply(null, arguments); + }); - Module["_sqlite3changeset_apply"] = function () { - return (Module["_sqlite3changeset_apply"] = - Module["asm"]["sqlite3changeset_apply"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_apply'] = + function () { + return (Module['_sqlite3changeset_apply'] = + Module['asm']['sqlite3changeset_apply']).apply(null, arguments); + }); - Module["_sqlite3changeset_apply_v2_strm"] = function () { - return (Module["_sqlite3changeset_apply_v2_strm"] = - Module["asm"]["sqlite3changeset_apply_v2_strm"]).apply(null, arguments); - }; + (Module[ + '_sqlite3changeset_apply_v2_strm' + ] = function () { + return (Module[ + '_sqlite3changeset_apply_v2_strm' + ] = + Module['asm']['sqlite3changeset_apply_v2_strm']).apply(null, arguments); + }); - Module["_sqlite3changeset_apply_strm"] = function () { - return (Module["_sqlite3changeset_apply_strm"] = - Module["asm"]["sqlite3changeset_apply_strm"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_apply_strm'] = + function () { + return (Module[ + '_sqlite3changeset_apply_strm' + ] = + Module['asm']['sqlite3changeset_apply_strm']).apply(null, arguments); + }); - Module["_sqlite3changegroup_new"] = function () { - return (Module["_sqlite3changegroup_new"] = - Module["asm"]["sqlite3changegroup_new"]).apply(null, arguments); - }; + (Module['_sqlite3changegroup_new'] = + function () { + return (Module['_sqlite3changegroup_new'] = + Module['asm']['sqlite3changegroup_new']).apply(null, arguments); + }); - Module["_sqlite3changegroup_add"] = function () { - return (Module["_sqlite3changegroup_add"] = - Module["asm"]["sqlite3changegroup_add"]).apply(null, arguments); - }; + (Module['_sqlite3changegroup_add'] = + function () { + return (Module['_sqlite3changegroup_add'] = + Module['asm']['sqlite3changegroup_add']).apply(null, arguments); + }); - Module["_sqlite3changegroup_output"] = function () { - return (Module["_sqlite3changegroup_output"] = - Module["asm"]["sqlite3changegroup_output"]).apply(null, arguments); - }; + (Module['_sqlite3changegroup_output'] = + function () { + return (Module[ + '_sqlite3changegroup_output' + ] = + Module['asm']['sqlite3changegroup_output']).apply(null, arguments); + }); - Module["_sqlite3changegroup_add_strm"] = function () { - return (Module["_sqlite3changegroup_add_strm"] = - Module["asm"]["sqlite3changegroup_add_strm"]).apply(null, arguments); - }; + (Module['_sqlite3changegroup_add_strm'] = + function () { + return (Module[ + '_sqlite3changegroup_add_strm' + ] = + Module['asm']['sqlite3changegroup_add_strm']).apply(null, arguments); + }); - Module["_sqlite3changegroup_output_strm"] = function () { - return (Module["_sqlite3changegroup_output_strm"] = - Module["asm"]["sqlite3changegroup_output_strm"]).apply(null, arguments); - }; + (Module[ + '_sqlite3changegroup_output_strm' + ] = function () { + return (Module[ + '_sqlite3changegroup_output_strm' + ] = + Module['asm']['sqlite3changegroup_output_strm']).apply(null, arguments); + }); - Module["_sqlite3changegroup_delete"] = function () { - return (Module["_sqlite3changegroup_delete"] = - Module["asm"]["sqlite3changegroup_delete"]).apply(null, arguments); - }; + (Module['_sqlite3changegroup_delete'] = + function () { + return (Module[ + '_sqlite3changegroup_delete' + ] = + Module['asm']['sqlite3changegroup_delete']).apply(null, arguments); + }); - Module["_sqlite3changeset_concat"] = function () { - return (Module["_sqlite3changeset_concat"] = - Module["asm"]["sqlite3changeset_concat"]).apply(null, arguments); - }; + (Module['_sqlite3changeset_concat'] = + function () { + return (Module['_sqlite3changeset_concat'] = + Module['asm']['sqlite3changeset_concat']).apply(null, arguments); + }); - Module["_sqlite3changeset_concat_strm"] = function () { - return (Module["_sqlite3changeset_concat_strm"] = - Module["asm"]["sqlite3changeset_concat_strm"]).apply(null, arguments); - }; + (Module[ + '_sqlite3changeset_concat_strm' + ] = function () { + return (Module[ + '_sqlite3changeset_concat_strm' + ] = + Module['asm']['sqlite3changeset_concat_strm']).apply(null, arguments); + }); - Module["_sqlite3session_config"] = function () { - return (Module["_sqlite3session_config"] = - Module["asm"]["sqlite3session_config"]).apply(null, arguments); - }; + (Module['_sqlite3session_config'] = + function () { + return (Module['_sqlite3session_config'] = + Module['asm']['sqlite3session_config']).apply(null, arguments); + }); - Module["_sqlite3_sourceid"] = function () { - return (Module["_sqlite3_sourceid"] = - Module["asm"]["sqlite3_sourceid"]).apply(null, arguments); - }; + (Module['_sqlite3_sourceid'] = function () { + return (Module['_sqlite3_sourceid'] = + Module['asm']['sqlite3_sourceid']).apply(null, arguments); + }); - Module["_sqlite3__wasm_pstack_ptr"] = function () { - return (Module["_sqlite3__wasm_pstack_ptr"] = - Module["asm"]["sqlite3__wasm_pstack_ptr"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_pstack_ptr'] = + function () { + return (Module[ + '_sqlite3__wasm_pstack_ptr' + ] = + Module['asm']['sqlite3__wasm_pstack_ptr']).apply(null, arguments); + }); - Module["_sqlite3__wasm_pstack_restore"] = function () { - return (Module["_sqlite3__wasm_pstack_restore"] = - Module["asm"]["sqlite3__wasm_pstack_restore"]).apply(null, arguments); - }; + (Module[ + '_sqlite3__wasm_pstack_restore' + ] = function () { + return (Module[ + '_sqlite3__wasm_pstack_restore' + ] = + Module['asm']['sqlite3__wasm_pstack_restore']).apply(null, arguments); + }); - Module["_sqlite3__wasm_pstack_alloc"] = function () { - return (Module["_sqlite3__wasm_pstack_alloc"] = - Module["asm"]["sqlite3__wasm_pstack_alloc"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_pstack_alloc'] = + function () { + return (Module[ + '_sqlite3__wasm_pstack_alloc' + ] = + Module['asm']['sqlite3__wasm_pstack_alloc']).apply(null, arguments); + }); - Module["_sqlite3__wasm_pstack_remaining"] = function () { - return (Module["_sqlite3__wasm_pstack_remaining"] = - Module["asm"]["sqlite3__wasm_pstack_remaining"]).apply(null, arguments); - }; + (Module[ + '_sqlite3__wasm_pstack_remaining' + ] = function () { + return (Module[ + '_sqlite3__wasm_pstack_remaining' + ] = + Module['asm']['sqlite3__wasm_pstack_remaining']).apply(null, arguments); + }); - Module["_sqlite3__wasm_pstack_quota"] = function () { - return (Module["_sqlite3__wasm_pstack_quota"] = - Module["asm"]["sqlite3__wasm_pstack_quota"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_pstack_quota'] = + function () { + return (Module[ + '_sqlite3__wasm_pstack_quota' + ] = + Module['asm']['sqlite3__wasm_pstack_quota']).apply(null, arguments); + }); - Module["_sqlite3__wasm_db_error"] = function () { - return (Module["_sqlite3__wasm_db_error"] = - Module["asm"]["sqlite3__wasm_db_error"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_db_error'] = + function () { + return (Module['_sqlite3__wasm_db_error'] = + Module['asm']['sqlite3__wasm_db_error']).apply(null, arguments); + }); - Module["_sqlite3__wasm_test_struct"] = function () { - return (Module["_sqlite3__wasm_test_struct"] = - Module["asm"]["sqlite3__wasm_test_struct"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_test_struct'] = + function () { + return (Module[ + '_sqlite3__wasm_test_struct' + ] = + Module['asm']['sqlite3__wasm_test_struct']).apply(null, arguments); + }); - Module["_sqlite3__wasm_enum_json"] = function () { - return (Module["_sqlite3__wasm_enum_json"] = - Module["asm"]["sqlite3__wasm_enum_json"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_enum_json'] = + function () { + return (Module['_sqlite3__wasm_enum_json'] = + Module['asm']['sqlite3__wasm_enum_json']).apply(null, arguments); + }); - Module["_sqlite3__wasm_vfs_unlink"] = function () { - return (Module["_sqlite3__wasm_vfs_unlink"] = - Module["asm"]["sqlite3__wasm_vfs_unlink"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_vfs_unlink'] = + function () { + return (Module[ + '_sqlite3__wasm_vfs_unlink' + ] = + Module['asm']['sqlite3__wasm_vfs_unlink']).apply(null, arguments); + }); - Module["_sqlite3__wasm_db_vfs"] = function () { - return (Module["_sqlite3__wasm_db_vfs"] = - Module["asm"]["sqlite3__wasm_db_vfs"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_db_vfs'] = function () { + return (Module['_sqlite3__wasm_db_vfs'] = + Module['asm']['sqlite3__wasm_db_vfs']).apply(null, arguments); + }); - Module["_sqlite3__wasm_db_reset"] = function () { - return (Module["_sqlite3__wasm_db_reset"] = - Module["asm"]["sqlite3__wasm_db_reset"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_db_reset'] = + function () { + return (Module['_sqlite3__wasm_db_reset'] = + Module['asm']['sqlite3__wasm_db_reset']).apply(null, arguments); + }); - Module["_sqlite3__wasm_db_export_chunked"] = function () { - return (Module["_sqlite3__wasm_db_export_chunked"] = - Module["asm"]["sqlite3__wasm_db_export_chunked"]).apply( + (Module[ + '_sqlite3__wasm_db_export_chunked' + ] = function () { + return (Module[ + '_sqlite3__wasm_db_export_chunked' + ] = + Module['asm']['sqlite3__wasm_db_export_chunked']).apply( null, - arguments + arguments, ); - }; + }); - Module["_sqlite3__wasm_db_serialize"] = function () { - return (Module["_sqlite3__wasm_db_serialize"] = - Module["asm"]["sqlite3__wasm_db_serialize"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_db_serialize'] = + function () { + return (Module[ + '_sqlite3__wasm_db_serialize' + ] = + Module['asm']['sqlite3__wasm_db_serialize']).apply(null, arguments); + }); - Module["_sqlite3__wasm_vfs_create_file"] = function () { - return (Module["_sqlite3__wasm_vfs_create_file"] = - Module["asm"]["sqlite3__wasm_vfs_create_file"]).apply(null, arguments); - }; + (Module[ + '_sqlite3__wasm_vfs_create_file' + ] = function () { + return (Module[ + '_sqlite3__wasm_vfs_create_file' + ] = + Module['asm']['sqlite3__wasm_vfs_create_file']).apply(null, arguments); + }); - Module["_sqlite3__wasm_posix_create_file"] = function () { - return (Module["_sqlite3__wasm_posix_create_file"] = - Module["asm"]["sqlite3__wasm_posix_create_file"]).apply( + (Module[ + '_sqlite3__wasm_posix_create_file' + ] = function () { + return (Module[ + '_sqlite3__wasm_posix_create_file' + ] = + Module['asm']['sqlite3__wasm_posix_create_file']).apply( null, - arguments + arguments, ); - }; + }); - Module["_sqlite3__wasm_kvvfsMakeKeyOnPstack"] = function () { - return (Module["_sqlite3__wasm_kvvfsMakeKeyOnPstack"] = - Module["asm"]["sqlite3__wasm_kvvfsMakeKeyOnPstack"]).apply( + (Module[ + '_sqlite3__wasm_kvvfsMakeKeyOnPstack' + ] = function () { + return (Module[ + '_sqlite3__wasm_kvvfsMakeKeyOnPstack' + ] = + Module['asm']['sqlite3__wasm_kvvfsMakeKeyOnPstack']).apply( null, - arguments + arguments, ); - }; + }); - Module["_sqlite3__wasm_kvvfs_methods"] = function () { - return (Module["_sqlite3__wasm_kvvfs_methods"] = - Module["asm"]["sqlite3__wasm_kvvfs_methods"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_kvvfs_methods'] = + function () { + return (Module[ + '_sqlite3__wasm_kvvfs_methods' + ] = + Module['asm']['sqlite3__wasm_kvvfs_methods']).apply(null, arguments); + }); - Module["_sqlite3__wasm_vtab_config"] = function () { - return (Module["_sqlite3__wasm_vtab_config"] = - Module["asm"]["sqlite3__wasm_vtab_config"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_vtab_config'] = + function () { + return (Module[ + '_sqlite3__wasm_vtab_config' + ] = + Module['asm']['sqlite3__wasm_vtab_config']).apply(null, arguments); + }); - Module["_sqlite3__wasm_db_config_ip"] = function () { - return (Module["_sqlite3__wasm_db_config_ip"] = - Module["asm"]["sqlite3__wasm_db_config_ip"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_db_config_ip'] = + function () { + return (Module[ + '_sqlite3__wasm_db_config_ip' + ] = + Module['asm']['sqlite3__wasm_db_config_ip']).apply(null, arguments); + }); - Module["_sqlite3__wasm_db_config_pii"] = function () { - return (Module["_sqlite3__wasm_db_config_pii"] = - Module["asm"]["sqlite3__wasm_db_config_pii"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_db_config_pii'] = + function () { + return (Module[ + '_sqlite3__wasm_db_config_pii' + ] = + Module['asm']['sqlite3__wasm_db_config_pii']).apply(null, arguments); + }); - Module["_sqlite3__wasm_db_config_s"] = function () { - return (Module["_sqlite3__wasm_db_config_s"] = - Module["asm"]["sqlite3__wasm_db_config_s"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_db_config_s'] = + function () { + return (Module[ + '_sqlite3__wasm_db_config_s' + ] = + Module['asm']['sqlite3__wasm_db_config_s']).apply(null, arguments); + }); - Module["_sqlite3__wasm_config_i"] = function () { - return (Module["_sqlite3__wasm_config_i"] = - Module["asm"]["sqlite3__wasm_config_i"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_config_i'] = + function () { + return (Module['_sqlite3__wasm_config_i'] = + Module['asm']['sqlite3__wasm_config_i']).apply(null, arguments); + }); - Module["_sqlite3__wasm_config_ii"] = function () { - return (Module["_sqlite3__wasm_config_ii"] = - Module["asm"]["sqlite3__wasm_config_ii"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_config_ii'] = + function () { + return (Module['_sqlite3__wasm_config_ii'] = + Module['asm']['sqlite3__wasm_config_ii']).apply(null, arguments); + }); - Module["_sqlite3__wasm_config_j"] = function () { - return (Module["_sqlite3__wasm_config_j"] = - Module["asm"]["sqlite3__wasm_config_j"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_config_j'] = + function () { + return (Module['_sqlite3__wasm_config_j'] = + Module['asm']['sqlite3__wasm_config_j']).apply(null, arguments); + }); - Module["_sqlite3__wasm_qfmt_token"] = function () { - return (Module["_sqlite3__wasm_qfmt_token"] = - Module["asm"]["sqlite3__wasm_qfmt_token"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_qfmt_token'] = + function () { + return (Module[ + '_sqlite3__wasm_qfmt_token' + ] = + Module['asm']['sqlite3__wasm_qfmt_token']).apply(null, arguments); + }); - Module["_sqlite3__wasm_init_wasmfs"] = function () { - return (Module["_sqlite3__wasm_init_wasmfs"] = - Module["asm"]["sqlite3__wasm_init_wasmfs"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_init_wasmfs'] = + function () { + return (Module[ + '_sqlite3__wasm_init_wasmfs' + ] = + Module['asm']['sqlite3__wasm_init_wasmfs']).apply(null, arguments); + }); - Module["_sqlite3__wasm_test_intptr"] = function () { - return (Module["_sqlite3__wasm_test_intptr"] = - Module["asm"]["sqlite3__wasm_test_intptr"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_test_intptr'] = + function () { + return (Module[ + '_sqlite3__wasm_test_intptr' + ] = + Module['asm']['sqlite3__wasm_test_intptr']).apply(null, arguments); + }); - Module["_sqlite3__wasm_test_voidptr"] = function () { - return (Module["_sqlite3__wasm_test_voidptr"] = - Module["asm"]["sqlite3__wasm_test_voidptr"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_test_voidptr'] = + function () { + return (Module[ + '_sqlite3__wasm_test_voidptr' + ] = + Module['asm']['sqlite3__wasm_test_voidptr']).apply(null, arguments); + }); - Module["_sqlite3__wasm_test_int64_max"] = function () { - return (Module["_sqlite3__wasm_test_int64_max"] = - Module["asm"]["sqlite3__wasm_test_int64_max"]).apply(null, arguments); - }; + (Module[ + '_sqlite3__wasm_test_int64_max' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_int64_max' + ] = + Module['asm']['sqlite3__wasm_test_int64_max']).apply(null, arguments); + }); - Module["_sqlite3__wasm_test_int64_min"] = function () { - return (Module["_sqlite3__wasm_test_int64_min"] = - Module["asm"]["sqlite3__wasm_test_int64_min"]).apply(null, arguments); - }; + (Module[ + '_sqlite3__wasm_test_int64_min' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_int64_min' + ] = + Module['asm']['sqlite3__wasm_test_int64_min']).apply(null, arguments); + }); - Module["_sqlite3__wasm_test_int64_times2"] = function () { - return (Module["_sqlite3__wasm_test_int64_times2"] = - Module["asm"]["sqlite3__wasm_test_int64_times2"]).apply( + (Module[ + '_sqlite3__wasm_test_int64_times2' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_int64_times2' + ] = + Module['asm']['sqlite3__wasm_test_int64_times2']).apply( null, - arguments + arguments, ); - }; + }); - Module["_sqlite3__wasm_test_int64_minmax"] = function () { - return (Module["_sqlite3__wasm_test_int64_minmax"] = - Module["asm"]["sqlite3__wasm_test_int64_minmax"]).apply( + (Module[ + '_sqlite3__wasm_test_int64_minmax' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_int64_minmax' + ] = + Module['asm']['sqlite3__wasm_test_int64_minmax']).apply( null, - arguments + arguments, ); - }; + }); - Module["_sqlite3__wasm_test_int64ptr"] = function () { - return (Module["_sqlite3__wasm_test_int64ptr"] = - Module["asm"]["sqlite3__wasm_test_int64ptr"]).apply(null, arguments); - }; + (Module['_sqlite3__wasm_test_int64ptr'] = + function () { + return (Module[ + '_sqlite3__wasm_test_int64ptr' + ] = + Module['asm']['sqlite3__wasm_test_int64ptr']).apply(null, arguments); + }); - Module["_sqlite3__wasm_test_stack_overflow"] = function () { - return (Module["_sqlite3__wasm_test_stack_overflow"] = - Module["asm"]["sqlite3__wasm_test_stack_overflow"]).apply( + (Module[ + '_sqlite3__wasm_test_stack_overflow' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_stack_overflow' + ] = + Module['asm']['sqlite3__wasm_test_stack_overflow']).apply( null, - arguments + arguments, ); - }; + }); - Module["_sqlite3__wasm_test_str_hello"] = function () { - return (Module["_sqlite3__wasm_test_str_hello"] = - Module["asm"]["sqlite3__wasm_test_str_hello"]).apply(null, arguments); - }; + (Module[ + '_sqlite3__wasm_test_str_hello' + ] = function () { + return (Module[ + '_sqlite3__wasm_test_str_hello' + ] = + Module['asm']['sqlite3__wasm_test_str_hello']).apply(null, arguments); + }); - Module["_sqlite3__wasm_SQLTester_strglob"] = function () { - return (Module["_sqlite3__wasm_SQLTester_strglob"] = - Module["asm"]["sqlite3__wasm_SQLTester_strglob"]).apply( + (Module[ + '_sqlite3__wasm_SQLTester_strglob' + ] = function () { + return (Module[ + '_sqlite3__wasm_SQLTester_strglob' + ] = + Module['asm']['sqlite3__wasm_SQLTester_strglob']).apply( null, - arguments + arguments, ); - }; + }); - var _malloc = (Module["_malloc"] = function () { - return (_malloc = Module["_malloc"] = Module["asm"]["malloc"]).apply( + var _malloc = (Module['_malloc'] = function () { + return (_malloc = Module['_malloc'] = Module['asm']['malloc']).apply( null, - arguments + arguments, ); }); - Module["_free"] = function () { - return (Module["_free"] = Module["asm"]["free"]).apply(null, arguments); - }; + (Module['_free'] = function () { + return (Module['_free'] = Module['asm']['free']).apply( + null, + arguments, + ); + }); - Module["_realloc"] = function () { - return (Module["_realloc"] = Module["asm"]["realloc"]).apply( + (Module['_realloc'] = function () { + return (Module['_realloc'] = Module['asm']['realloc']).apply( null, - arguments + arguments, ); - }; + }); - var _emscripten_builtin_memalign = (Module["_emscripten_builtin_memalign"] = + var _emscripten_builtin_memalign = (Module['_emscripten_builtin_memalign'] = function () { return (_emscripten_builtin_memalign = Module[ - "_emscripten_builtin_memalign" + '_emscripten_builtin_memalign' ] = - Module["asm"]["emscripten_builtin_memalign"]).apply(null, arguments); + Module['asm']['emscripten_builtin_memalign']).apply(null, arguments); }); - Module["stackSave"] = function () { - return (Module["stackSave"] = Module["asm"]["stackSave"]).apply( - null, - arguments - ); - }; + (Module['stackSave'] = function () { + return (Module['stackSave'] = + Module['asm']['stackSave']).apply(null, arguments); + }); - Module["stackRestore"] = function () { - return (Module["stackRestore"] = Module["asm"]["stackRestore"]).apply( - null, - arguments - ); - }; + (Module['stackRestore'] = function () { + return (Module['stackRestore'] = + Module['asm']['stackRestore']).apply(null, arguments); + }); - Module["stackAlloc"] = function () { - return (Module["stackAlloc"] = Module["asm"]["stackAlloc"]).apply( - null, - arguments - ); - }; + (Module['stackAlloc'] = function () { + return (Module['stackAlloc'] = + Module['asm']['stackAlloc']).apply(null, arguments); + }); - Module["wasmMemory"] = wasmMemory; + Module['wasmMemory'] = wasmMemory; var calledRun; @@ -5180,6 +5492,7 @@ var sqlite3InitModule = (() => { }; function run(args) { + if (runDependencies > 0) { return; } @@ -5193,23 +5506,23 @@ var sqlite3InitModule = (() => { function doRun() { if (calledRun) return; calledRun = true; - Module["calledRun"] = true; + Module['calledRun'] = true; if (ABORT) return; initRuntime(); readyPromiseResolve(Module); - if (Module["onRuntimeInitialized"]) Module["onRuntimeInitialized"](); + if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); postRun(); } - if (Module["setStatus"]) { - Module["setStatus"]("Running..."); + if (Module['setStatus']) { + Module['setStatus']('Running...'); setTimeout(function () { setTimeout(function () { - Module["setStatus"](""); + Module['setStatus'](''); }, 1); doRun(); }, 1); @@ -5218,11 +5531,11 @@ var sqlite3InitModule = (() => { } } - if (Module["preInit"]) { - if (typeof Module["preInit"] == "function") - Module["preInit"] = [Module["preInit"]]; - while (Module["preInit"].length > 0) { - Module["preInit"].pop()(); + if (Module['preInit']) { + if (typeof Module['preInit'] == 'function') + Module['preInit'] = [Module['preInit']]; + while (Module['preInit'].length > 0) { + Module['preInit'].pop()(); } } @@ -5232,12 +5545,12 @@ var sqlite3InitModule = (() => { Module.postRun.push(function (Module) { globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( apiConfig = globalThis.sqlite3ApiConfig || - sqlite3ApiBootstrap.defaultConfig + sqlite3ApiBootstrap.defaultConfig, ) { if (sqlite3ApiBootstrap.sqlite3) { (sqlite3ApiBootstrap.sqlite3.config || console).warn( - "sqlite3ApiBootstrap() called multiple times.", - "Config and external initializers are ignored on calls after the first." + 'sqlite3ApiBootstrap() called multiple times.', + 'Config and external initializers are ignored on calls after the first.', ); return sqlite3ApiBootstrap.sqlite3; } @@ -5247,7 +5560,7 @@ var sqlite3InitModule = (() => { exports: undefined, memory: undefined, bigIntEnabled: (() => { - if ("undefined" !== typeof Module) { + if ('undefined' !== typeof Module) { if (!!Module.HEAPU64) return true; } return !!globalThis.BigInt64Array; @@ -5256,27 +5569,27 @@ var sqlite3InitModule = (() => { warn: console.warn.bind(console), error: console.error.bind(console), log: console.log.bind(console), - wasmfsOpfsDir: "/opfs", + wasmfsOpfsDir: '/opfs', useStdAlloc: false, }, - apiConfig || {} + apiConfig || {}, ); Object.assign( config, { - allocExportName: config.useStdAlloc ? "malloc" : "sqlite3_malloc", - deallocExportName: config.useStdAlloc ? "free" : "sqlite3_free", + allocExportName: config.useStdAlloc ? 'malloc' : 'sqlite3_malloc', + deallocExportName: config.useStdAlloc ? 'free' : 'sqlite3_free', reallocExportName: config.useStdAlloc - ? "realloc" - : "sqlite3_realloc", + ? 'realloc' + : 'sqlite3_realloc', }, - config + config, ); - ["exports", "memory", "wasmfsOpfsDir"].forEach((k) => { - if ("function" === typeof config[k]) { + ['exports', 'memory', 'wasmfsOpfsDir'].forEach((k) => { + if ('function' === typeof config[k]) { config[k] = config[k](); } }); @@ -5291,11 +5604,11 @@ var sqlite3InitModule = (() => { const __rcStr = (rc) => { return ( (capi.sqlite3_js_rc_str && capi.sqlite3_js_rc_str(rc)) || - "Unknown result code #" + rc + 'Unknown result code #' + rc ); }; - const __isInt = (n) => "number" === typeof n && n === (n | 0); + const __isInt = (n) => 'number' === typeof n && n === (n | 0); class SQLite3Error extends Error { constructor(...args) { @@ -5307,23 +5620,23 @@ var sqlite3InitModule = (() => { super(__rcStr(args[0])); } else { const rcStr = __rcStr(rc); - if ("object" === typeof args[1]) { + if ('object' === typeof args[1]) { super(rcStr, args[1]); } else { - args[0] = rcStr + ":"; - super(args.join(" ")); + args[0] = rcStr + ':'; + super(args.join(' ')); } } } else { - if (2 === args.length && "object" === typeof args[1]) { + if (2 === args.length && 'object' === typeof args[1]) { super(...args); } else { - super(args.join(" ")); + super(args.join(' ')); } } } this.resultCode = rc || capi.SQLITE_ERROR; - this.name = "SQLite3Error"; + this.name = 'SQLite3Error'; } } @@ -5334,20 +5647,20 @@ var sqlite3InitModule = (() => { if (config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)) { toss3( - "config.wasmfsOpfsDir must be falsy or in the form '/dir-name'." + "config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.", ); } const isInt32 = (n) => { return ( - "bigint" !== typeof n && + 'bigint' !== typeof n && !!(n === (n | 0) && n <= 2147483647 && n >= -2147483648) ); }; const bigIntFits64 = function f(b) { if (!f._max) { - f._max = BigInt("0x7fffffffffffffff"); + f._max = BigInt('0x7fffffffffffffff'); f._min = ~f._max; } return b >= f._min && b <= f._max; @@ -5370,7 +5683,7 @@ var sqlite3InitModule = (() => { }; const __SAB = - "undefined" === typeof SharedArrayBuffer + 'undefined' === typeof SharedArrayBuffer ? function () {} : SharedArrayBuffer; @@ -5404,11 +5717,11 @@ var sqlite3InitModule = (() => { const affirmBindableTypedArray = (v) => { return ( isBindableTypedArray(v) || - toss3("Value is not of a supported TypedArray type.") + toss3('Value is not of a supported TypedArray type.') ); }; - const utf8Decoder = new TextDecoder("utf-8"); + const utf8Decoder = new TextDecoder('utf-8'); const typedArrayToString = function (typedArray, begin, end) { return utf8Decoder.decode(typedArrayPart(typedArray, begin, end)); @@ -5417,24 +5730,24 @@ var sqlite3InitModule = (() => { const flexibleString = function (v) { if (isSQLableTypedArray(v)) { return typedArrayToString( - v instanceof ArrayBuffer ? new Uint8Array(v) : v + v instanceof ArrayBuffer ? new Uint8Array(v) : v, ); - } else if (Array.isArray(v)) return v.join(""); + } else if (Array.isArray(v)) return v.join(''); else if (wasm.isPtr(v)) v = wasm.cstrToJs(v); return v; }; class WasmAllocError extends Error { constructor(...args) { - if (2 === args.length && "object" === typeof args[1]) { + if (2 === args.length && 'object' === typeof args[1]) { super(...args); } else if (args.length) { - super(args.join(" ")); + super(args.join(' ')); } else { - super("Allocation failed."); + super('Allocation failed.'); } this.resultCode = capi.SQLITE_NOMEM; - this.name = "WasmAllocError"; + this.name = 'WasmAllocError'; } } @@ -5456,7 +5769,7 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - xDestroy + xDestroy, ) => {}, sqlite3_create_function: ( @@ -5467,7 +5780,7 @@ var sqlite3InitModule = (() => { pApp, xFunc, xStep, - xFinal + xFinal, ) => {}, sqlite3_create_window_function: ( @@ -5480,7 +5793,7 @@ var sqlite3InitModule = (() => { xFinal, xValue, xInverse, - xDestroy + xDestroy, ) => {}, sqlite3_prepare_v3: ( @@ -5489,7 +5802,7 @@ var sqlite3InitModule = (() => { sqlByteLen, prepFlags, stmtPtrPtr, - strPtrPtr + strPtrPtr, ) => {}, sqlite3_prepare_v2: ( @@ -5497,7 +5810,7 @@ var sqlite3InitModule = (() => { sql, sqlByteLen, stmtPtrPtr, - strPtrPtr + strPtrPtr, ) => {}, sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg) => {}, @@ -5521,20 +5834,20 @@ var sqlite3InitModule = (() => { isSharedTypedArray, toss: function (...args) { - throw new Error(args.join(" ")); + throw new Error(args.join(' ')); }, toss3, typedArrayPart, affirmDbHeader: function (bytes) { if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); - const header = "SQLite format 3"; + const header = 'SQLite format 3'; if (header.length > bytes.byteLength) { - toss3("Input does not contain an SQLite3 database header."); + toss3('Input does not contain an SQLite3 database header.'); } for (let i = 0; i < header.length; ++i) { if (header.charCodeAt(i) !== bytes[i]) { - toss3("Input does not contain an SQLite3 database header."); + toss3('Input does not contain an SQLite3 database header.'); } } }, @@ -5543,7 +5856,7 @@ var sqlite3InitModule = (() => { if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); const n = bytes.byteLength; if (n < 512 || n % 512 !== 0) { - toss3("Byte array size", n, "is invalid for an SQLite3 db."); + toss3('Byte array size', n, 'is invalid for an SQLite3 db.'); } util.affirmDbHeader(bytes); }, @@ -5552,21 +5865,21 @@ var sqlite3InitModule = (() => { Object.assign(wasm, { ptrSizeof: config.wasmPtrSizeof || 4, - ptrIR: config.wasmPtrIR || "i32", + ptrIR: config.wasmPtrIR || 'i32', bigIntEnabled: !!config.bigIntEnabled, exports: config.exports || - toss3("Missing API config.exports (WASM module exports)."), + toss3('Missing API config.exports (WASM module exports).'), memory: config.memory || - config.exports["memory"] || + config.exports['memory'] || toss3( - "API config object requires a WebAssembly.Memory object", - "in either config.exports.memory (exported)", - "or config.memory (imported)." + 'API config object requires a WebAssembly.Memory object', + 'in either config.exports.memory (exported)', + 'or config.memory (imported).', ), alloc: undefined, @@ -5595,20 +5908,20 @@ var sqlite3InitModule = (() => { for (const key of [keyAlloc, keyDealloc, keyRealloc]) { const f = wasm.exports[key]; if (!(f instanceof Function)) - toss3("Missing required exports[", key, "] function."); + toss3('Missing required exports[', key, '] function.'); } wasm.alloc = function f(n) { return ( f.impl(n) || - WasmAllocError.toss("Failed to allocate", n, " bytes.") + WasmAllocError.toss('Failed to allocate', n, ' bytes.') ); }; wasm.alloc.impl = wasm.exports[keyAlloc]; wasm.realloc = function f(m, n) { const m2 = f.impl(m, n); return n - ? m2 || WasmAllocError.toss("Failed to reallocate", n, " bytes.") + ? m2 || WasmAllocError.toss('Failed to reallocate', n, ' bytes.') : 0; }; wasm.realloc.impl = wasm.exports[keyRealloc]; @@ -5642,13 +5955,13 @@ var sqlite3InitModule = (() => { rc[v] = capi.sqlite3_compileoption_used(v); }); return rc; - } else if ("object" === typeof optName) { + } else if ('object' === typeof optName) { Object.keys(optName).forEach((k) => { optName[k] = capi.sqlite3_compileoption_used(k); }); return optName; } - return "string" === typeof optName + return 'string' === typeof optName ? !!capi.sqlite3_compileoption_used(optName) : false; }; @@ -5657,29 +5970,29 @@ var sqlite3InitModule = (() => { restore: wasm.exports.sqlite3__wasm_pstack_restore, alloc: function (n) { - if ("string" === typeof n && !(n = wasm.sizeofIR(n))) { + if ('string' === typeof n && !(n = wasm.sizeofIR(n))) { WasmAllocError.toss( - "Invalid value for pstack.alloc(", + 'Invalid value for pstack.alloc(', arguments[0], - ")" + ')', ); } return ( wasm.exports.sqlite3__wasm_pstack_alloc(n) || WasmAllocError.toss( - "Could not allocate", + 'Could not allocate', n, - "bytes from the pstack." + 'bytes from the pstack.', ) ); }, allocChunks: function (n, sz) { - if ("string" === typeof sz && !(sz = wasm.sizeofIR(sz))) { + if ('string' === typeof sz && !(sz = wasm.sizeofIR(sz))) { WasmAllocError.toss( - "Invalid size value for allocChunks(", + 'Invalid size value for allocChunks(', arguments[1], - ")" + ')', ); } const mem = wasm.pstack.alloc(n * sz); @@ -5756,9 +6069,9 @@ var sqlite3InitModule = (() => { } while (n > 0); } catch (e) { console.error( - "Highly unexpected (and ignored!) " + - "exception in sqlite3_randomness():", - e + 'Highly unexpected (and ignored!) ' + + 'exception in sqlite3_randomness():', + e, ); } finally { wasm.pstack.restore(stack); @@ -5780,31 +6093,31 @@ var sqlite3InitModule = (() => { !globalThis.FileSystemDirectoryHandle || !globalThis.FileSystemFileHandle ) { - return (__wasmfsOpfsDir = ""); + return (__wasmfsOpfsDir = ''); } try { if ( pdir && 0 === wasm.xCallWrapped( - "sqlite3__wasm_init_wasmfs", - "i32", - ["string"], - pdir + 'sqlite3__wasm_init_wasmfs', + 'i32', + ['string'], + pdir, ) ) { return (__wasmfsOpfsDir = pdir); } else { - return (__wasmfsOpfsDir = ""); + return (__wasmfsOpfsDir = ''); } } catch (e) { - return (__wasmfsOpfsDir = ""); + return (__wasmfsOpfsDir = ''); } }; capi.sqlite3_wasmfs_filename_is_persistent = function (name) { const p = capi.sqlite3_wasmfs_opfs_dir(); - return p && name ? name.startsWith(p + "/") : false; + return p && name ? name.startsWith(p + '/') : false; }; capi.sqlite3_js_db_uses_vfs = function (pDb, vfsName, dbName = 0) { @@ -5834,9 +6147,9 @@ var sqlite3InitModule = (() => { }; capi.sqlite3_js_db_export = function (pDb, schema = 0) { - pDb = wasm.xWrap.testConvertArg("sqlite3*", pDb); - if (!pDb) toss3("Invalid sqlite3* argument."); - if (!wasm.bigIntEnabled) toss3("BigInt64 support is not enabled."); + pDb = wasm.xWrap.testConvertArg('sqlite3*', pDb); + if (!pDb) toss3('Invalid sqlite3* argument.'); + if (!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.'); const scope = wasm.scopedAllocPush(); let pOut; try { @@ -5846,23 +6159,23 @@ var sqlite3InitModule = (() => { const zSchema = schema ? wasm.isPtr(schema) ? schema - : wasm.scopedAllocCString("" + schema) + : wasm.scopedAllocCString('' + schema) : 0; let rc = wasm.exports.sqlite3__wasm_db_serialize( pDb, zSchema, ppOut, pSize, - 0 + 0, ); if (rc) { toss3( - "Database serialization failed with code", - sqlite3.capi.sqlite3_js_rc_str(rc) + 'Database serialization failed with code', + sqlite3.capi.sqlite3_js_rc_str(rc), ); } pOut = wasm.peekPtr(ppOut); - const nOut = wasm.peek(pSize, "i64"); + const nOut = wasm.peek(pSize, 'i64'); rc = nOut ? wasm.heap8u().slice(pOut, pOut + Number(nOut)) : new Uint8Array(); @@ -5881,9 +6194,9 @@ var sqlite3InitModule = (() => { capi.sqlite3_aggregate_context(pCtx, n) || (n ? WasmAllocError.toss( - "Cannot allocate", + 'Cannot allocate', n, - "bytes for sqlite3_aggregate_context()" + 'bytes for sqlite3_aggregate_context()', ) : 0) ); @@ -5903,24 +6216,24 @@ var sqlite3InitModule = (() => { } } else { SQLite3Error.toss( - "Invalid 2nd argument for sqlite3_js_posix_create_file()." + 'Invalid 2nd argument for sqlite3_js_posix_create_file().', ); } try { if (!util.isInt32(dataLen) || dataLen < 0) { SQLite3Error.toss( - "Invalid 3rd argument for sqlite3_js_posix_create_file()." + 'Invalid 3rd argument for sqlite3_js_posix_create_file().', ); } const rc = util.sqlite3__wasm_posix_create_file( filename, pData, - dataLen + dataLen, ); if (rc) SQLite3Error.toss( - "Creation of file failed with sqlite3 result code", - capi.sqlite3_js_rc_str(rc) + 'Creation of file failed with sqlite3 result code', + capi.sqlite3_js_rc_str(rc), ); } finally { wasm.dealloc(pData); @@ -5931,12 +6244,12 @@ var sqlite3InitModule = (() => { vfs, filename, data, - dataLen + dataLen, ) { config.warn( - "sqlite3_js_vfs_create_file() is deprecated and", - "should be avoided because it can lead to C-level crashes.", - "See its documentation for alternative options." + 'sqlite3_js_vfs_create_file() is deprecated and', + 'should be avoided because it can lead to C-level crashes.', + 'See its documentation for alternative options.', ); let pData; if (data) { @@ -5956,7 +6269,7 @@ var sqlite3InitModule = (() => { } } else { SQLite3Error.toss( - "Invalid 3rd argument type for sqlite3_js_vfs_create_file()." + 'Invalid 3rd argument type for sqlite3_js_vfs_create_file().', ); } } else { @@ -5965,7 +6278,7 @@ var sqlite3InitModule = (() => { if (!util.isInt32(dataLen) || dataLen < 0) { wasm.dealloc(pData); SQLite3Error.toss( - "Invalid 4th argument for sqlite3_js_vfs_create_file()." + 'Invalid 4th argument for sqlite3_js_vfs_create_file().', ); } try { @@ -5973,12 +6286,12 @@ var sqlite3InitModule = (() => { vfs, filename, pData, - dataLen + dataLen, ); if (rc) SQLite3Error.toss( - "Creation of file failed with sqlite3 result code", - capi.sqlite3_js_rc_str(rc) + 'Creation of file failed with sqlite3 result code', + capi.sqlite3_js_rc_str(rc), ); } finally { wasm.dealloc(pData); @@ -5986,7 +6299,7 @@ var sqlite3InitModule = (() => { }; capi.sqlite3_js_sql_to_string = (sql) => { - if ("string" === typeof sql) { + if ('string' === typeof sql) { return sql; } const x = flexibleString(v); @@ -5996,16 +6309,16 @@ var sqlite3InitModule = (() => { if (util.isUIThread()) { const __kvvfsInfo = function (which) { const rc = Object.create(null); - rc.prefix = "kvvfs-" + which; + rc.prefix = 'kvvfs-' + which; rc.stores = []; - if ("session" === which || "" === which) + if ('session' === which || '' === which) rc.stores.push(globalThis.sessionStorage); - if ("local" === which || "" === which) + if ('local' === which || '' === which) rc.stores.push(globalThis.localStorage); return rc; }; - capi.sqlite3_js_kvvfs_clear = function (which = "") { + capi.sqlite3_js_kvvfs_clear = function (which = '') { let rc = 0; const kvinfo = __kvvfsInfo(which); kvinfo.stores.forEach((s) => { @@ -6021,7 +6334,7 @@ var sqlite3InitModule = (() => { return rc; }; - capi.sqlite3_js_kvvfs_size = function (which = "") { + capi.sqlite3_js_kvvfs_size = function (which = '') { let sz = 0; const kvinfo = __kvvfsInfo(which); kvinfo.stores.forEach((s) => { @@ -6040,23 +6353,23 @@ var sqlite3InitModule = (() => { capi.sqlite3_db_config = function (pDb, op, ...args) { if (!this.s) { - this.s = wasm.xWrap("sqlite3__wasm_db_config_s", "int", [ - "sqlite3*", - "int", - "string:static", + this.s = wasm.xWrap('sqlite3__wasm_db_config_s', 'int', [ + 'sqlite3*', + 'int', + 'string:static', ]); - this.pii = wasm.xWrap("sqlite3__wasm_db_config_pii", "int", [ - "sqlite3*", - "int", - "*", - "int", - "int", + this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int', [ + 'sqlite3*', + 'int', + '*', + 'int', + 'int', ]); - this.ip = wasm.xWrap("sqlite3__wasm_db_config_ip", "int", [ - "sqlite3*", - "int", - "int", - "*", + this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip', 'int', [ + 'sqlite3*', + 'int', + 'int', + '*', ]); } switch (op) { @@ -6090,7 +6403,7 @@ var sqlite3InitModule = (() => { capi.sqlite3_value_to_js = function ( pVal, - throwIfCannotConvert = true + throwIfCannotConvert = true, ) { let arg; const valType = capi.sqlite3_value_type(pVal); @@ -6112,9 +6425,9 @@ var sqlite3InitModule = (() => { const pBlob = capi.sqlite3_value_blob(pVal); if (n && !pBlob) sqlite3.WasmAllocError.toss( - "Cannot allocate memory for blob argument of", + 'Cannot allocate memory for blob argument of', n, - "byte(s)" + 'byte(s)', ); arg = n ? wasm.heap8u().slice(pBlob, pBlob + Number(n)) : null; break; @@ -6126,8 +6439,8 @@ var sqlite3InitModule = (() => { if (throwIfCannotConvert) { toss3( capi.SQLITE_MISMATCH, - "Unhandled sqlite3_value_type():", - valType + 'Unhandled sqlite3_value_type():', + valType, ); } arg = undefined; @@ -6138,7 +6451,7 @@ var sqlite3InitModule = (() => { capi.sqlite3_values_to_js = function ( argc, pArgv, - throwIfCannotConvert = true + throwIfCannotConvert = true, ) { let i; const tgt = []; @@ -6146,8 +6459,8 @@ var sqlite3InitModule = (() => { tgt.push( capi.sqlite3_value_to_js( wasm.peekPtr(pArgv + wasm.ptrSizeof * i), - throwIfCannotConvert - ) + throwIfCannotConvert, + ), ); } return tgt; @@ -6157,7 +6470,7 @@ var sqlite3InitModule = (() => { if (e instanceof WasmAllocError) { capi.sqlite3_result_error_nomem(pCtx); } else { - capi.sqlite3_result_error(pCtx, "" + e, -1); + capi.sqlite3_result_error(pCtx, '' + e, -1); } }; @@ -6168,12 +6481,12 @@ var sqlite3InitModule = (() => { } try { switch (typeof val) { - case "undefined": + case 'undefined': break; - case "boolean": + case 'boolean': capi.sqlite3_result_int(pCtx, val ? 1 : 0); break; - case "bigint": + case 'bigint': if (util.bigIntFits32(val)) { capi.sqlite3_result_int(pCtx, Number(val)); } else if (util.bigIntFitsDouble(val)) { @@ -6183,15 +6496,15 @@ var sqlite3InitModule = (() => { capi.sqlite3_result_int64(pCtx, val); else toss3( - "BigInt value", + 'BigInt value', val.toString(), - "is too BigInt for int64." + 'is too BigInt for int64.', ); } else { - toss3("BigInt value", val.toString(), "is too BigInt."); + toss3('BigInt value', val.toString(), 'is too BigInt.'); } break; - case "number": { + case 'number': { let f; if (util.isInt32(val)) { f = capi.sqlite3_result_int; @@ -6207,12 +6520,12 @@ var sqlite3InitModule = (() => { f(pCtx, val); break; } - case "string": { + case 'string': { const [p, n] = wasm.allocCString(val, true); capi.sqlite3_result_text(pCtx, p, n, capi.SQLITE_WASM_DEALLOC); break; } - case "object": + case 'object': if (null === val) { capi.sqlite3_result_null(pCtx); break; @@ -6222,7 +6535,7 @@ var sqlite3InitModule = (() => { pCtx, pBlob, val.byteLength, - capi.SQLITE_WASM_DEALLOC + capi.SQLITE_WASM_DEALLOC, ); break; } @@ -6231,7 +6544,7 @@ var sqlite3InitModule = (() => { toss3( "Don't not how to handle this UDF result value:", typeof val, - val + val, ); } } catch (e) { @@ -6242,7 +6555,7 @@ var sqlite3InitModule = (() => { capi.sqlite3_column_js = function ( pStmt, iCol, - throwIfCannotConvert = true + throwIfCannotConvert = true, ) { const v = capi.sqlite3_column_value(pStmt, iCol); return 0 === v @@ -6258,23 +6571,23 @@ var sqlite3InitModule = (() => { if (rc) return SQLite3Error.toss( rc, - arguments[2] + "() failed with code " + rc + arguments[2] + '() failed with code ' + rc, ); const pv = wasm.peekPtr(this.ptr); return pv ? capi.sqlite3_value_to_js(pv, true) : undefined; }.bind(Object.create(null)); capi.sqlite3_preupdate_new_js = (pDb, iCol) => - __newOldValue(pDb, iCol, "sqlite3_preupdate_new"); + __newOldValue(pDb, iCol, 'sqlite3_preupdate_new'); capi.sqlite3_preupdate_old_js = (pDb, iCol) => - __newOldValue(pDb, iCol, "sqlite3_preupdate_old"); + __newOldValue(pDb, iCol, 'sqlite3_preupdate_old'); capi.sqlite3changeset_new_js = (pChangesetIter, iCol) => - __newOldValue(pChangesetIter, iCol, "sqlite3changeset_new"); + __newOldValue(pChangesetIter, iCol, 'sqlite3changeset_new'); capi.sqlite3changeset_old_js = (pChangesetIter, iCol) => - __newOldValue(pChangesetIter, iCol, "sqlite3changeset_old"); + __newOldValue(pChangesetIter, iCol, 'sqlite3changeset_old'); const sqlite3 = { WasmAllocError: WasmAllocError, @@ -6301,7 +6614,7 @@ var sqlite3InitModule = (() => { return sqlite3; }; const catcher = (e) => { - config.error("an async sqlite3 initializer failed:", e); + config.error('an async sqlite3 initializer failed:', e); throw e; }; if (!lia || !lia.length) { @@ -6323,7 +6636,7 @@ var sqlite3InitModule = (() => { f(sqlite3); }); } catch (e) { - console.error("sqlite3 bootstrap initializer threw:", e); + console.error('sqlite3 bootstrap initializer threw:', e); throw e; } delete sqlite3ApiBootstrap.initializers; @@ -6341,28 +6654,28 @@ var sqlite3InitModule = (() => { globalThis.WhWasmUtilInstaller = function (target) { if (undefined === target.bigIntEnabled) { - target.bigIntEnabled = !!globalThis["BigInt64Array"]; + target.bigIntEnabled = !!globalThis['BigInt64Array']; } const toss = (...args) => { - throw new Error(args.join(" ")); + throw new Error(args.join(' ')); }; if (!target.exports) { - Object.defineProperty(target, "exports", { + Object.defineProperty(target, 'exports', { enumerable: true, configurable: true, get: () => target.instance && target.instance.exports, }); } - const ptrIR = target.pointerIR || "i32"; + const ptrIR = target.pointerIR || 'i32'; const ptrSizeof = (target.ptrSizeof = - "i32" === ptrIR + 'i32' === ptrIR ? 4 - : "i64" === ptrIR - ? 8 - : toss("Unhandled ptrSizeof:", ptrIR)); + : 'i64' === ptrIR + ? 8 + : toss('Unhandled ptrSizeof:', ptrIR)); const cache = Object.create(null); @@ -6375,26 +6688,26 @@ var sqlite3InitModule = (() => { cache.scopedAlloc = []; cache.utf8Decoder = new TextDecoder(); - cache.utf8Encoder = new TextEncoder("utf-8"); + cache.utf8Encoder = new TextEncoder('utf-8'); target.sizeofIR = (n) => { switch (n) { - case "i8": + case 'i8': return 1; - case "i16": + case 'i16': return 2; - case "i32": - case "f32": - case "float": + case 'i32': + case 'f32': + case 'float': return 4; - case "i64": - case "f64": - case "double": + case 'i64': + case 'f64': + case 'double': return 8; - case "*": + case '*': return ptrSizeof; default: - return ("" + n).endsWith("*") ? ptrSizeof : undefined; + return ('' + n).endsWith('*') ? ptrSizeof : undefined; } }; @@ -6466,14 +6779,14 @@ var sqlite3InitModule = (() => { break; default: if (target.bigIntEnabled) { - if (n === globalThis["BigUint64Array"]) return c.HEAP64U; - else if (n === globalThis["BigInt64Array"]) return c.HEAP64; + if (n === globalThis['BigUint64Array']) return c.HEAP64U; + else if (n === globalThis['BigInt64Array']) return c.HEAP64; break; } } toss( - "Invalid heapForSize() size: expecting 8, 16, 32,", - "or (if BigInt is enabled) 64." + 'Invalid heapForSize() size: expecting 8, 16, 32,', + 'or (if BigInt is enabled) 64.', ); }; @@ -6490,13 +6803,13 @@ var sqlite3InitModule = (() => { if (!f._) { f._ = { sigTypes: Object.assign(Object.create(null), { - i: "i32", - p: "i32", - P: "i32", - s: "i32", - j: "i64", - f: "f32", - d: "f64", + i: 'i32', + p: 'i32', + P: 'i32', + s: 'i32', + j: 'i64', + f: 'f32', + d: 'f64', }), typeCodes: Object.assign(Object.create(null), { @@ -6519,27 +6832,27 @@ var sqlite3InitModule = (() => { }, letterType: (x) => - f._.sigTypes[x] || toss("Invalid signature letter:", x), + f._.sigTypes[x] || toss('Invalid signature letter:', x), pushSigType: (dest, letter) => dest.push(f._.typeCodes[f._.letterType(letter)]), }; } - if ("string" === typeof func) { + if ('string' === typeof func) { const x = sig; sig = func; func = x; } const sigParams = f._.sigParams(sig); const wasmCode = [0x01, 0x60]; - f._.uleb128Encode(wasmCode, "push", sigParams.length); + f._.uleb128Encode(wasmCode, 'push', sigParams.length); for (const x of sigParams) f._.pushSigType(wasmCode, x); - if ("v" === sig[0]) wasmCode.push(0); + if ('v' === sig[0]) wasmCode.push(0); else { wasmCode.push(1); f._.pushSigType(wasmCode, sig[0]); } - f._.uleb128Encode(wasmCode, "unshift", wasmCode.length); + f._.uleb128Encode(wasmCode, 'unshift', wasmCode.length); wasmCode.unshift( 0x00, 0x61, @@ -6549,7 +6862,7 @@ var sqlite3InitModule = (() => { 0x00, 0x00, 0x00, - 0x01 + 0x01, ); wasmCode.push( 0x02, @@ -6569,29 +6882,29 @@ var sqlite3InitModule = (() => { 0x01, 0x66, 0x00, - 0x00 + 0x00, ); return new WebAssembly.Instance( new WebAssembly.Module(new Uint8Array(wasmCode)), { e: { f: func }, - } - ).exports["f"]; + }, + ).exports['f']; }; const __installFunction = function f(func, sig, scoped) { if (scoped && !cache.scopedAlloc.length) { - toss("No scopedAllocPush() scope is active."); + toss('No scopedAllocPush() scope is active.'); } - if ("string" === typeof func) { + if ('string' === typeof func) { const x = sig; sig = func; func = x; } - if ("string" !== typeof sig || !(func instanceof Function)) { + if ('string' !== typeof sig || !(func instanceof Function)) { toss( - "Invalid arguments: expecting (function,signature) " + - "or (signature,function)." + 'Invalid arguments: expecting (function,signature) ' + + 'or (signature,function).', ); } const ft = target.functionTable(); @@ -6652,8 +6965,8 @@ var sqlite3InitModule = (() => { return rc; }; - target.peek = function f(ptr, type = "i8") { - if (type.endsWith("*")) type = ptrIR; + target.peek = function f(ptr, type = 'i8') { + if (type.endsWith('*')) type = ptrIR; const c = cache.memory && cache.heapSize === cache.memory.buffer.byteLength ? cache @@ -6663,72 +6976,72 @@ var sqlite3InitModule = (() => { do { if (list) ptr = arguments[0].shift(); switch (type) { - case "i1": - case "i8": + case 'i1': + case 'i8': rc = c.HEAP8[ptr >> 0]; break; - case "i16": + case 'i16': rc = c.HEAP16[ptr >> 1]; break; - case "i32": + case 'i32': rc = c.HEAP32[ptr >> 2]; break; - case "float": - case "f32": + case 'float': + case 'f32': rc = c.HEAP32F[ptr >> 2]; break; - case "double": - case "f64": + case 'double': + case 'f64': rc = Number(c.HEAP64F[ptr >> 3]); break; - case "i64": + case 'i64': if (target.bigIntEnabled) { rc = BigInt(c.HEAP64[ptr >> 3]); break; } default: - toss("Invalid type for peek():", type); + toss('Invalid type for peek():', type); } if (list) list.push(rc); } while (list && arguments[0].length); return list || rc; }; - target.poke = function (ptr, value, type = "i8") { - if (type.endsWith("*")) type = ptrIR; + target.poke = function (ptr, value, type = 'i8') { + if (type.endsWith('*')) type = ptrIR; const c = cache.memory && cache.heapSize === cache.memory.buffer.byteLength ? cache : heapWrappers(); for (const p of Array.isArray(ptr) ? ptr : [ptr]) { switch (type) { - case "i1": - case "i8": + case 'i1': + case 'i8': c.HEAP8[p >> 0] = value; continue; - case "i16": + case 'i16': c.HEAP16[p >> 1] = value; continue; - case "i32": + case 'i32': c.HEAP32[p >> 2] = value; continue; - case "float": - case "f32": + case 'float': + case 'f32': c.HEAP32F[p >> 2] = value; continue; - case "double": - case "f64": + case 'double': + case 'f64': c.HEAP64F[p >> 3] = value; continue; - case "i64": + case 'i64': if (c.HEAP64) { c.HEAP64[p >> 3] = BigInt(value); continue; } default: - toss("Invalid type for poke(): " + type); + toss('Invalid type for poke(): ' + type); } } return this; @@ -6740,34 +7053,34 @@ var sqlite3InitModule = (() => { target.pokePtr = (ptr, value = 0) => target.poke(ptr, value, ptrIR); target.peek8 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, "i8"); + target.peek(1 === ptr.length ? ptr[0] : ptr, 'i8'); - target.poke8 = (ptr, value) => target.poke(ptr, value, "i8"); + target.poke8 = (ptr, value) => target.poke(ptr, value, 'i8'); target.peek16 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, "i16"); + target.peek(1 === ptr.length ? ptr[0] : ptr, 'i16'); - target.poke16 = (ptr, value) => target.poke(ptr, value, "i16"); + target.poke16 = (ptr, value) => target.poke(ptr, value, 'i16'); target.peek32 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, "i32"); + target.peek(1 === ptr.length ? ptr[0] : ptr, 'i32'); - target.poke32 = (ptr, value) => target.poke(ptr, value, "i32"); + target.poke32 = (ptr, value) => target.poke(ptr, value, 'i32'); target.peek64 = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, "i64"); + target.peek(1 === ptr.length ? ptr[0] : ptr, 'i64'); - target.poke64 = (ptr, value) => target.poke(ptr, value, "i64"); + target.poke64 = (ptr, value) => target.poke(ptr, value, 'i64'); target.peek32f = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, "f32"); + target.peek(1 === ptr.length ? ptr[0] : ptr, 'f32'); - target.poke32f = (ptr, value) => target.poke(ptr, value, "f32"); + target.poke32f = (ptr, value) => target.poke(ptr, value, 'f32'); target.peek64f = (...ptr) => - target.peek(1 === ptr.length ? ptr[0] : ptr, "f64"); + target.peek(1 === ptr.length ? ptr[0] : ptr, 'f64'); - target.poke64f = (ptr, value) => target.poke(ptr, value, "f64"); + target.poke64f = (ptr, value) => target.poke(ptr, value, 'f64'); target.getMemValue = target.peek; @@ -6778,7 +7091,7 @@ var sqlite3InitModule = (() => { target.setPtrValue = target.pokePtr; target.isPtr32 = (ptr) => - "number" === typeof ptr && ptr === (ptr | 0) && ptr >= 0; + 'number' === typeof ptr && ptr === (ptr | 0) && ptr >= 0; target.isPtr = target.isPtr32; @@ -6791,14 +7104,14 @@ var sqlite3InitModule = (() => { }; const __SAB = - "undefined" === typeof SharedArrayBuffer + 'undefined' === typeof SharedArrayBuffer ? function () {} : SharedArrayBuffer; const __utf8Decode = function (arrayBuffer, begin, end) { return cache.utf8Decoder.decode( arrayBuffer.buffer instanceof __SAB ? arrayBuffer.slice(begin, end) - : arrayBuffer.subarray(begin, end) + : arrayBuffer.subarray(begin, end), ); }; @@ -6807,12 +7120,12 @@ var sqlite3InitModule = (() => { return n ? __utf8Decode(heapWrappers().HEAP8U, ptr, ptr + n) : null === n - ? n - : ""; + ? n + : ''; }; target.jstrlen = function (str) { - if ("string" !== typeof str) return null; + if ('string' !== typeof str) return null; const n = str.length; let len = 0; for (let i = 0; i < n; ++i) { @@ -6834,13 +7147,13 @@ var sqlite3InitModule = (() => { tgt, offset = 0, maxBytes = -1, - addNul = true + addNul = true, ) { if ( !tgt || (!(tgt instanceof Int8Array) && !(tgt instanceof Uint8Array)) ) { - toss("jstrcpy() target must be an Int8Array or Uint8Array."); + toss('jstrcpy() target must be an Int8Array or Uint8Array.'); } if (maxBytes < 0) maxBytes = tgt.length - offset; if (!(maxBytes > 0) || !(offset >= 0)) return 0; @@ -6881,7 +7194,7 @@ var sqlite3InitModule = (() => { target.cstrncpy = function (tgtPtr, srcPtr, n) { if (!tgtPtr || !srcPtr) - toss("cstrncpy() does not accept NULL strings."); + toss('cstrncpy() does not accept NULL strings.'); if (n < 0) n = target.cstrlen(strPtr) + 1; else if (!(n > 0)) return 0; const heap = target.heap8u(); @@ -6895,7 +7208,7 @@ var sqlite3InitModule = (() => { }; target.jstrToUintArray = (str, addNul = false) => { - return cache.utf8Encoder.encode(addNul ? str + "\0" : str); + return cache.utf8Encoder.encode(addNul ? str + '\0' : str); }; const __affirmAlloc = (obj, funcName) => { @@ -6904,9 +7217,9 @@ var sqlite3InitModule = (() => { !(obj.dealloc instanceof Function) ) { toss( - "Object is missing alloc() and/or dealloc() function(s)", - "required by", - funcName + "()." + 'Object is missing alloc() and/or dealloc() function(s)', + 'required by', + funcName + '().', ); } }; @@ -6915,10 +7228,10 @@ var sqlite3InitModule = (() => { jstr, returnWithLength, allocator, - funcName + funcName, ) { __affirmAlloc(target, funcName); - if ("string" !== typeof jstr) return null; + if ('string' !== typeof jstr) return null; { const u = cache.utf8Encoder.encode(jstr), ptr = allocator(u.length + 1), @@ -6930,21 +7243,21 @@ var sqlite3InitModule = (() => { }; target.allocCString = (jstr, returnWithLength = false) => - __allocCStr(jstr, returnWithLength, target.alloc, "allocCString()"); + __allocCStr(jstr, returnWithLength, target.alloc, 'allocCString()'); target.scopedAllocPush = function () { - __affirmAlloc(target, "scopedAllocPush"); + __affirmAlloc(target, 'scopedAllocPush'); const a = []; cache.scopedAlloc.push(a); return a; }; target.scopedAllocPop = function (state) { - __affirmAlloc(target, "scopedAllocPop"); + __affirmAlloc(target, 'scopedAllocPop'); const n = arguments.length ? cache.scopedAlloc.indexOf(state) : cache.scopedAlloc.length - 1; - if (n < 0) toss("Invalid state object for scopedAllocPop()."); + if (n < 0) toss('Invalid state object for scopedAllocPop().'); if (0 === arguments.length) state = cache.scopedAlloc[n]; cache.scopedAlloc.splice(n, 1); for (let p; (p = state.pop()); ) { @@ -6956,14 +7269,14 @@ var sqlite3InitModule = (() => { target.scopedAlloc = function (n) { if (!cache.scopedAlloc.length) { - toss("No scopedAllocPush() scope is active."); + toss('No scopedAllocPush() scope is active.'); } const p = target.alloc(n); cache.scopedAlloc[cache.scopedAlloc.length - 1].push(p); return p; }; - Object.defineProperty(target.scopedAlloc, "level", { + Object.defineProperty(target.scopedAlloc, 'level', { configurable: false, enumerable: false, get: () => cache.scopedAlloc.length, @@ -6975,18 +7288,18 @@ var sqlite3InitModule = (() => { jstr, returnWithLength, target.scopedAlloc, - "scopedAllocCString()" + 'scopedAllocCString()', ); const __allocMainArgv = function (isScoped, list) { - const pList = target[isScoped ? "scopedAlloc" : "alloc"]( - (list.length + 1) * target.ptrSizeof + const pList = target[isScoped ? 'scopedAlloc' : 'alloc']( + (list.length + 1) * target.ptrSizeof, ); let i = 0; list.forEach((e) => { target.pokePtr( pList + target.ptrSizeof * i++, - target[isScoped ? "scopedAllocCString" : "allocCString"]("" + e) + target[isScoped ? 'scopedAllocCString' : 'allocCString']('' + e), ); }); target.pokePtr(pList + target.ptrSizeof * i, 0); @@ -7017,7 +7330,7 @@ var sqlite3InitModule = (() => { const __allocPtr = function (howMany, safePtrSize, method) { __affirmAlloc(target, method); - const pIr = safePtrSize ? "i64" : ptrIR; + const pIr = safePtrSize ? 'i64' : ptrIR; let m = target[method](howMany * (safePtrSize ? 8 : ptrSizeof)); target.poke(m, 0, pIr); if (1 === howMany) { @@ -7033,24 +7346,24 @@ var sqlite3InitModule = (() => { }; target.allocPtr = (howMany = 1, safePtrSize = true) => - __allocPtr(howMany, safePtrSize, "alloc"); + __allocPtr(howMany, safePtrSize, 'alloc'); target.scopedAllocPtr = (howMany = 1, safePtrSize = true) => - __allocPtr(howMany, safePtrSize, "scopedAlloc"); + __allocPtr(howMany, safePtrSize, 'scopedAlloc'); target.xGet = function (name) { return ( - target.exports[name] || toss("Cannot find exported symbol:", name) + target.exports[name] || toss('Cannot find exported symbol:', name) ); }; const __argcMismatch = (f, n) => - toss(f + "() requires", n, "argument(s)."); + toss(f + '() requires', n, 'argument(s).'); target.xCall = function (fname, ...args) { const f = fname instanceof Function ? fname : target.xGet(fname); if (!(f instanceof Function)) - toss("Exported symbol", fname, "is not a function."); + toss('Exported symbol', fname, 'is not a function.'); if (f.length !== args.length) __argcMismatch(f === fname ? f.name : fname, f.length); return 2 === arguments.length && Array.isArray(arguments[1]) @@ -7068,73 +7381,73 @@ var sqlite3InitModule = (() => { xResult = cache.xWrap.convert.result; if (target.bigIntEnabled) { - xArg.set("i64", (i) => BigInt(i)); + xArg.set('i64', (i) => BigInt(i)); } const __xArgPtr = - "i32" === ptrIR ? (i) => i | 0 : (i) => BigInt(i) | BigInt(0); + 'i32' === ptrIR ? (i) => i | 0 : (i) => BigInt(i) | BigInt(0); xArg - .set("i32", __xArgPtr) - .set("i16", (i) => (i | 0) & 0xffff) - .set("i8", (i) => (i | 0) & 0xff) - .set("f32", (i) => Number(i).valueOf()) - .set("float", xArg.get("f32")) - .set("f64", xArg.get("f32")) - .set("double", xArg.get("f64")) - .set("int", xArg.get("i32")) - .set("null", (i) => i) - .set(null, xArg.get("null")) - .set("**", __xArgPtr) - .set("*", __xArgPtr); + .set('i32', __xArgPtr) + .set('i16', (i) => (i | 0) & 0xffff) + .set('i8', (i) => (i | 0) & 0xff) + .set('f32', (i) => Number(i).valueOf()) + .set('float', xArg.get('f32')) + .set('f64', xArg.get('f32')) + .set('double', xArg.get('f64')) + .set('int', xArg.get('i32')) + .set('null', (i) => i) + .set(null, xArg.get('null')) + .set('**', __xArgPtr) + .set('*', __xArgPtr); xResult - .set("*", __xArgPtr) - .set("pointer", __xArgPtr) - .set("number", (v) => Number(v)) - .set("void", (v) => undefined) - .set("null", (v) => v) - .set(null, xResult.get("null")); + .set('*', __xArgPtr) + .set('pointer', __xArgPtr) + .set('number', (v) => Number(v)) + .set('void', (v) => undefined) + .set('null', (v) => v) + .set(null, xResult.get('null')); { const copyToResult = [ - "i8", - "i16", - "i32", - "int", - "f32", - "float", - "f64", - "double", + 'i8', + 'i16', + 'i32', + 'int', + 'f32', + 'float', + 'f64', + 'double', ]; - if (target.bigIntEnabled) copyToResult.push("i64"); + if (target.bigIntEnabled) copyToResult.push('i64'); const adaptPtr = xArg.get(ptrIR); for (const t of copyToResult) { - xArg.set(t + "*", adaptPtr); - xResult.set(t + "*", adaptPtr); - xResult.set(t, xArg.get(t) || toss("Missing arg converter:", t)); + xArg.set(t + '*', adaptPtr); + xResult.set(t + '*', adaptPtr); + xResult.set(t, xArg.get(t) || toss('Missing arg converter:', t)); } } const __xArgString = function (v) { - if ("string" === typeof v) return target.scopedAllocCString(v); + if ('string' === typeof v) return target.scopedAllocCString(v); return v ? __xArgPtr(v) : null; }; xArg - .set("string", __xArgString) - .set("utf8", __xArgString) - .set("pointer", __xArgString); + .set('string', __xArgString) + .set('utf8', __xArgString) + .set('pointer', __xArgString); xResult - .set("string", (i) => target.cstrToJs(i)) - .set("utf8", xResult.get("string")) - .set("string:dealloc", (i) => { + .set('string', (i) => target.cstrToJs(i)) + .set('utf8', xResult.get('string')) + .set('string:dealloc', (i) => { try { return i ? target.cstrToJs(i) : null; } finally { target.dealloc(i); } }) - .set("utf8:dealloc", xResult.get("string:dealloc")) - .set("json", (i) => JSON.parse(target.cstrToJs(i))) - .set("json:dealloc", (i) => { + .set('utf8:dealloc', xResult.get('string:dealloc')) + .set('json', (i) => JSON.parse(target.cstrToJs(i))) + .set('json:dealloc', (i) => { try { return i ? JSON.parse(target.cstrToJs(i)) : null; } finally { @@ -7144,11 +7457,11 @@ var sqlite3InitModule = (() => { const AbstractArgAdapter = class { constructor(opt) { - this.name = opt.name || "unnamed adapter"; + this.name = opt.name || 'unnamed adapter'; } convertArg(v, argv, argIndex) { - toss("AbstractArgAdapter must be subclassed."); + toss('AbstractArgAdapter must be subclassed.'); } }; @@ -7157,37 +7470,37 @@ var sqlite3InitModule = (() => { super(opt); if (xArg.FuncPtrAdapter.warnOnUse) { console.warn( - "xArg.FuncPtrAdapter is an internal-only API", - "and is not intended to be invoked from", - "client-level code. Invoked with:", - opt + 'xArg.FuncPtrAdapter is an internal-only API', + 'and is not intended to be invoked from', + 'client-level code. Invoked with:', + opt, ); } - this.name = opt.name || "unnamed"; + this.name = opt.name || 'unnamed'; this.signature = opt.signature; if (opt.contextKey instanceof Function) { this.contextKey = opt.contextKey; - if (!opt.bindScope) opt.bindScope = "context"; + if (!opt.bindScope) opt.bindScope = 'context'; } this.bindScope = opt.bindScope || toss( - "FuncPtrAdapter options requires a bindScope (explicit or implied)." + 'FuncPtrAdapter options requires a bindScope (explicit or implied).', ); if (FuncPtrAdapter.bindScopes.indexOf(opt.bindScope) < 0) { toss( - "Invalid options.bindScope (" + + 'Invalid options.bindScope (' + opt.bindMod + - ") for FuncPtrAdapter. " + - "Expecting one of: (" + - FuncPtrAdapter.bindScopes.join(", ") + - ")" + ') for FuncPtrAdapter. ' + + 'Expecting one of: (' + + FuncPtrAdapter.bindScopes.join(', ') + + ')', ); } - this.isTransient = "transient" === this.bindScope; - this.isContext = "context" === this.bindScope; - this.isPermanent = "permanent" === this.bindScope; - this.singleton = "singleton" === this.bindScope ? [] : undefined; + this.isTransient = 'transient' === this.bindScope; + this.isContext = 'context' === this.bindScope; + this.isPermanent = 'permanent' === this.bindScope; + this.singleton = 'singleton' === this.bindScope ? [] : undefined; this.callProxy = opt.callProxy instanceof Function ? opt.callProxy : undefined; @@ -7215,27 +7528,27 @@ var sqlite3InitModule = (() => { const fp = __installFunction(v, this.signature, this.isTransient); if (FuncPtrAdapter.debugFuncInstall) { FuncPtrAdapter.debugOut( - "FuncPtrAdapter installed", + 'FuncPtrAdapter installed', this, this.contextKey(argv, argIndex), - "@" + fp, - v + '@' + fp, + v, ); } if (pair) { if (pair[1]) { if (FuncPtrAdapter.debugFuncInstall) { FuncPtrAdapter.debugOut( - "FuncPtrAdapter uninstalling", + 'FuncPtrAdapter uninstalling', this, this.contextKey(argv, argIndex), - "@" + pair[1], - v + '@' + pair[1], + v, ); } try { cache.scopedAlloc[cache.scopedAlloc.length - 1].push( - pair[1] + pair[1], ); } catch (e) {} } @@ -7247,11 +7560,11 @@ var sqlite3InitModule = (() => { if (pair && pair[1] && pair[1] !== v) { if (FuncPtrAdapter.debugFuncInstall) { FuncPtrAdapter.debugOut( - "FuncPtrAdapter uninstalling", + 'FuncPtrAdapter uninstalling', this, this.contextKey(argv, argIndex), - "@" + pair[1], - v + '@' + pair[1], + v, ); } try { @@ -7262,12 +7575,12 @@ var sqlite3InitModule = (() => { return v || 0; } else { throw new TypeError( - "Invalid FuncPtrAdapter argument type. " + - "Expecting a function pointer or a " + - (this.name ? this.name + " " : "") + - "function matching signature " + + 'Invalid FuncPtrAdapter argument type. ' + + 'Expecting a function pointer or a ' + + (this.name ? this.name + ' ' : '') + + 'function matching signature ' + this.signature + - "." + '.', ); } } @@ -7280,17 +7593,17 @@ var sqlite3InitModule = (() => { xArg.FuncPtrAdapter.debugOut = console.debug.bind(console); xArg.FuncPtrAdapter.bindScopes = [ - "transient", - "context", - "singleton", - "permanent", + 'transient', + 'context', + 'singleton', + 'permanent', ]; const __xArgAdapterCheck = (t) => - xArg.get(t) || toss("Argument adapter not found:", t); + xArg.get(t) || toss('Argument adapter not found:', t); const __xResultAdapterCheck = (t) => - xResult.get(t) || toss("Result adapter not found:", t); + xResult.get(t) || toss('Result adapter not found:', t); cache.xWrap.convertArg = (t, ...args) => __xArgAdapterCheck(t)(...args); @@ -7309,11 +7622,11 @@ var sqlite3InitModule = (() => { if (target.isPtr(fArg)) { fArg = target.functionEntry(fArg) || - toss("Function pointer not found in WASM function table."); + toss('Function pointer not found in WASM function table.'); } const fIsFunc = fArg instanceof Function; const xf = fIsFunc ? fArg : target.xGet(fArg); - if (fIsFunc) fArg = xf.name || "unnamed function"; + if (fIsFunc) fArg = xf.name || 'unnamed function'; if (argTypes.length !== xf.length) __argcMismatch(fArg, xf.length); if (null === resultType && 0 === xf.length) { return xf; @@ -7352,22 +7665,22 @@ var sqlite3InitModule = (() => { typeName, adapter, modeName, - xcvPart + xcvPart, ) { - if ("string" === typeof typeName) { + if ('string' === typeof typeName) { if (1 === argc) return xcvPart.get(typeName); else if (2 === argc) { if (!adapter) { delete xcvPart.get(typeName); return func; } else if (!(adapter instanceof Function)) { - toss(modeName, "requires a function argument."); + toss(modeName, 'requires a function argument.'); } xcvPart.set(typeName, adapter); return func; } } - toss("Invalid arguments to", modeName); + toss('Invalid arguments to', modeName); }; target.xWrap.resultAdapter = function f(typeName, adapter) { @@ -7376,8 +7689,8 @@ var sqlite3InitModule = (() => { arguments.length, typeName, adapter, - "resultAdapter()", - xResult + 'resultAdapter()', + xResult, ); }; @@ -7387,8 +7700,8 @@ var sqlite3InitModule = (() => { arguments.length, typeName, adapter, - "argAdapter()", - xArg + 'argAdapter()', + xArg, ); }; @@ -7409,12 +7722,12 @@ var sqlite3InitModule = (() => { }; globalThis.WhWasmUtilInstaller.yawl = function (config) { - const wfetch = () => fetch(config.uri, { credentials: "same-origin" }); + const wfetch = () => fetch(config.uri, { credentials: 'same-origin' }); const wui = this; const finalThen = function (arg) { if (config.wasmUtilTarget) { const toss = (...args) => { - throw new Error(args.join(" ")); + throw new Error(args.join(' ')); }; const tgt = config.wasmUtilTarget; tgt.module = arg.module; @@ -7431,7 +7744,7 @@ var sqlite3InitModule = (() => { const exports = arg.instance.exports; tgt.alloc = function (n) { return ( - exports.malloc(n) || toss("Allocation of", n, "bytes failed.") + exports.malloc(n) || toss('Allocation of', n, 'bytes failed.') ); }; tgt.dealloc = function (m) { @@ -7447,14 +7760,14 @@ var sqlite3InitModule = (() => { ? function loadWasmStreaming() { return WebAssembly.instantiateStreaming( wfetch(), - config.imports || {} + config.imports || {}, ).then(finalThen); } : function loadWasmOldSchool() { return wfetch() .then((response) => response.arrayBuffer()) .then((bytes) => - WebAssembly.instantiate(bytes, config.imports || {}) + WebAssembly.instantiate(bytes, config.imports || {}), ) .then(finalThen); }; @@ -7462,7 +7775,7 @@ var sqlite3InitModule = (() => { }.bind(globalThis.WhWasmUtilInstaller); globalThis.Jaccwabyt = function StructBinderFactory(config) { const toss = (...args) => { - throw new Error(args.join(" ")); + throw new Error(args.join(' ')); }; if ( @@ -7470,10 +7783,10 @@ var sqlite3InitModule = (() => { !(config.heap instanceof Function) ) { toss( - "config.heap must be WebAssembly.Memory instance or a function." + 'config.heap must be WebAssembly.Memory instance or a function.', ); } - ["alloc", "dealloc"].forEach(function (k) { + ['alloc', 'dealloc'].forEach(function (k) { config[k] instanceof Function || toss("Config option '" + k + "' must be a function."); }); @@ -7485,16 +7798,16 @@ var sqlite3InitModule = (() => { alloc = config.alloc, dealloc = config.dealloc, log = config.log || console.log.bind(console), - memberPrefix = config.memberPrefix || "", - memberSuffix = config.memberSuffix || "", + memberPrefix = config.memberPrefix || '', + memberSuffix = config.memberSuffix || '', bigIntEnabled = undefined === config.bigIntEnabled - ? !!globalThis["BigInt64Array"] + ? !!globalThis['BigInt64Array'] : !!config.bigIntEnabled, - BigInt = globalThis["BigInt"], - BigInt64Array = globalThis["BigInt64Array"], + BigInt = globalThis['BigInt'], + BigInt64Array = globalThis['BigInt64Array'], ptrSizeof = config.ptrSizeof || 4, - ptrIR = config.ptrIR || "i32"; + ptrIR = config.ptrIR || 'i32'; if (!SBF.debugFlags) { SBF.__makeDebugFlags = function (deriveFrom = null) { if (deriveFrom && deriveFrom.__flags) @@ -7516,7 +7829,7 @@ var sqlite3InitModule = (() => { } return f._flags; }; - Object.defineProperty(f, "__flags", { + Object.defineProperty(f, '__flags', { iterable: false, writable: false, value: Object.create(deriveFrom), @@ -7534,106 +7847,106 @@ var sqlite3InitModule = (() => { return new Int16Array(buffer)[0] === 256; })(); - const isFuncSig = (s) => "(" === s[1]; - const isAutoPtrSig = (s) => "P" === s; - const sigLetter = (s) => (isFuncSig(s) ? "p" : s[0]); + const isFuncSig = (s) => '(' === s[1]; + const isAutoPtrSig = (s) => 'P' === s; + const sigLetter = (s) => (isFuncSig(s) ? 'p' : s[0]); const sigIR = function (s) { switch (sigLetter(s)) { - case "c": - case "C": - return "i8"; - case "i": - return "i32"; - case "p": - case "P": - case "s": + case 'c': + case 'C': + return 'i8'; + case 'i': + return 'i32'; + case 'p': + case 'P': + case 's': return ptrIR; - case "j": - return "i64"; - case "f": - return "float"; - case "d": - return "double"; + case 'j': + return 'i64'; + case 'f': + return 'float'; + case 'd': + return 'double'; } - toss("Unhandled signature IR:", s); + toss('Unhandled signature IR:', s); }; const affirmBigIntArray = BigInt64Array ? () => true - : () => toss("BigInt64Array is not available."); + : () => toss('BigInt64Array is not available.'); const sigDVGetter = function (s) { switch (sigLetter(s)) { - case "p": - case "P": - case "s": { + case 'p': + case 'P': + case 's': { switch (ptrSizeof) { case 4: - return "getInt32"; + return 'getInt32'; case 8: - return affirmBigIntArray() && "getBigInt64"; + return affirmBigIntArray() && 'getBigInt64'; } break; } - case "i": - return "getInt32"; - case "c": - return "getInt8"; - case "C": - return "getUint8"; - case "j": - return affirmBigIntArray() && "getBigInt64"; - case "f": - return "getFloat32"; - case "d": - return "getFloat64"; + case 'i': + return 'getInt32'; + case 'c': + return 'getInt8'; + case 'C': + return 'getUint8'; + case 'j': + return affirmBigIntArray() && 'getBigInt64'; + case 'f': + return 'getFloat32'; + case 'd': + return 'getFloat64'; } - toss("Unhandled DataView getter for signature:", s); + toss('Unhandled DataView getter for signature:', s); }; const sigDVSetter = function (s) { switch (sigLetter(s)) { - case "p": - case "P": - case "s": { + case 'p': + case 'P': + case 's': { switch (ptrSizeof) { case 4: - return "setInt32"; + return 'setInt32'; case 8: - return affirmBigIntArray() && "setBigInt64"; + return affirmBigIntArray() && 'setBigInt64'; } break; } - case "i": - return "setInt32"; - case "c": - return "setInt8"; - case "C": - return "setUint8"; - case "j": - return affirmBigIntArray() && "setBigInt64"; - case "f": - return "setFloat32"; - case "d": - return "setFloat64"; + case 'i': + return 'setInt32'; + case 'c': + return 'setInt8'; + case 'C': + return 'setUint8'; + case 'j': + return affirmBigIntArray() && 'setBigInt64'; + case 'f': + return 'setFloat32'; + case 'd': + return 'setFloat64'; } - toss("Unhandled DataView setter for signature:", s); + toss('Unhandled DataView setter for signature:', s); }; const sigDVSetWrapper = function (s) { switch (sigLetter(s)) { - case "i": - case "f": - case "c": - case "C": - case "d": + case 'i': + case 'f': + case 'c': + case 'C': + case 'd': return Number; - case "j": + case 'j': return affirmBigIntArray() && BigInt; - case "p": - case "P": - case "s": + case 'p': + case 'P': + case 's': switch (ptrSizeof) { case 4: return Number; @@ -7642,18 +7955,18 @@ var sqlite3InitModule = (() => { } break; } - toss("Unhandled DataView set wrapper for signature:", s); + toss('Unhandled DataView set wrapper for signature:', s); }; - const sPropName = (s, k) => s + "::" + k; + const sPropName = (s, k) => s + '::' + k; const __propThrowOnSet = function (structName, propName) { - return () => toss(sPropName(structName, propName), "is read-only."); + return () => toss(sPropName(structName, propName), 'is read-only.'); }; const __instancePointerMap = new WeakMap(); - const xPtrPropName = "(pointer-is-external)"; + const xPtrPropName = '(pointer-is-external)'; const __freeStruct = function (ctor, obj, m) { if (!m) m = __instancePointerMap.get(obj); @@ -7665,15 +7978,15 @@ var sqlite3InitModule = (() => { try { if (x instanceof Function) x.call(obj); else if (x instanceof StructType) x.dispose(); - else if ("number" === typeof x) dealloc(x); + else if ('number' === typeof x) dealloc(x); } catch (e) { console.warn( - "ondispose() for", + 'ondispose() for', ctor.structName, - "@", + '@', m, - "threw. NOT propagating it.", - e + 'threw. NOT propagating it.', + e, ); } } @@ -7682,24 +7995,24 @@ var sqlite3InitModule = (() => { obj.ondispose(); } catch (e) { console.warn( - "ondispose() for", + 'ondispose() for', ctor.structName, - "@", + '@', m, - "threw. NOT propagating it.", - e + 'threw. NOT propagating it.', + e, ); } } delete obj.ondispose; if (ctor.debugFlags.__flags.dealloc) { log( - "debug.dealloc:", - obj[xPtrPropName] ? "EXTERNAL" : "", + 'debug.dealloc:', + obj[xPtrPropName] ? 'EXTERNAL' : '', ctor.structName, - "instance:", + 'instance:', ctor.structInfo.sizeof, - "bytes @" + m + 'bytes @' + m, ); } if (!obj[xPtrPropName]) dealloc(m); @@ -7720,17 +8033,17 @@ var sqlite3InitModule = (() => { if (m) Object.defineProperty(obj, xPtrPropName, rop(m)); else { m = alloc(ctor.structInfo.sizeof); - if (!m) toss("Allocation of", ctor.structName, "structure failed."); + if (!m) toss('Allocation of', ctor.structName, 'structure failed.'); } try { if (ctor.debugFlags.__flags.alloc) { log( - "debug.alloc:", - fill ? "" : "EXTERNAL", + 'debug.alloc:', + fill ? '' : 'EXTERNAL', ctor.structName, - "instance:", + 'instance:', ctor.structInfo.sizeof, - "bytes @" + m + 'bytes @' + m, ); } if (fill) heap().fill(0, m, m + ctor.structInfo.sizeof); @@ -7754,7 +8067,7 @@ var sqlite3InitModule = (() => { const __lookupMember = function ( structInfo, memberName, - tossIfNotFound = true + tossIfNotFound = true, ) { let m = structInfo.members[memberName]; if (!m && (memberPrefix || memberSuffix)) { @@ -7767,7 +8080,7 @@ var sqlite3InitModule = (() => { if (!m && tossIfNotFound) { toss( sPropName(structInfo.name, memberName), - "is not a mapped struct member." + 'is not a mapped struct member.', ); } } @@ -7777,11 +8090,11 @@ var sqlite3InitModule = (() => { const __memberSignature = function f( obj, memberName, - emscriptenFormat = false + emscriptenFormat = false, ) { if (!f._) f._ = (x) => - x.replace(/[^vipPsjrdcC]/g, "").replace(/[pPscC]/g, "i"); + x.replace(/[^vipPsjrdcC]/g, '').replace(/[pPscC]/g, 'i'); const m = __lookupMember(obj.structInfo, memberName, true); return emscriptenFormat ? f._(m.signature) : m.signature; }; @@ -7803,37 +8116,37 @@ var sqlite3InitModule = (() => { return a; }); - const __utf8Decoder = new TextDecoder("utf-8"); + const __utf8Decoder = new TextDecoder('utf-8'); const __utf8Encoder = new TextEncoder(); const __SAB = - "undefined" === typeof SharedArrayBuffer + 'undefined' === typeof SharedArrayBuffer ? function () {} : SharedArrayBuffer; const __utf8Decode = function (arrayBuffer, begin, end) { return __utf8Decoder.decode( arrayBuffer.buffer instanceof __SAB ? arrayBuffer.slice(begin, end) - : arrayBuffer.subarray(begin, end) + : arrayBuffer.subarray(begin, end), ); }; const __memberIsString = function ( obj, memberName, - tossIfNotFound = false + tossIfNotFound = false, ) { const m = __lookupMember(obj.structInfo, memberName, tossIfNotFound); - return m && 1 === m.signature.length && "s" === m.signature[0] + return m && 1 === m.signature.length && 's' === m.signature[0] ? m : false; }; const __affirmCStringSignature = function (member) { - if ("s" === member.signature) return; + if ('s' === member.signature) return; toss( - "Invalid member type signature for C-string value:", - JSON.stringify(member) + 'Invalid member type signature for C-string value:', + JSON.stringify(member), ); }; @@ -7847,7 +8160,7 @@ var sqlite3InitModule = (() => { const mem = heap(); for (; mem[pos] !== 0; ++pos) {} - return addr === pos ? "" : __utf8Decode(mem, addr, pos); + return addr === pos ? '' : __utf8Decode(mem, addr, pos); }; const __addOnDispose = function (obj, ...v) { @@ -7864,7 +8177,7 @@ var sqlite3InitModule = (() => { const __allocCString = function (str) { const u = __utf8Encoder.encode(str); const mem = alloc(u.length + 1); - if (!mem) toss("Allocation error while duplicating string:", str); + if (!mem) toss('Allocation error while duplicating string:', str); const h = heap(); h.set(u, mem); @@ -7886,8 +8199,8 @@ var sqlite3InitModule = (() => { const StructType = function ctor(structName, structInfo) { if (arguments[2] !== rop) { toss( - "Do not call the StructType constructor", - "from client-level code." + 'Do not call the StructType constructor', + 'from client-level code.', ); } Object.defineProperties(this, { @@ -7932,7 +8245,7 @@ var sqlite3InitModule = (() => { allocCString: rop(__allocCString), isA: rop((v) => v instanceof StructType), hasExternalPointer: rop( - (v) => v instanceof StructType && !!v[xPtrPropName] + (v) => v instanceof StructType && !!v[xPtrPropName], ), memberKey: __memberKeyProp, }); @@ -7943,8 +8256,8 @@ var sqlite3InitModule = (() => { const makeMemberWrapper = function f(ctor, name, descr) { if (!f._) { f._ = { getters: {}, setters: {}, sw: {} }; - const a = ["i", "c", "C", "p", "P", "s", "f", "d", "v()"]; - if (bigIntEnabled) a.push("j"); + const a = ['i', 'c', 'C', 'p', 'P', 's', 'f', 'd', 'v()']; + if (bigIntEnabled) a.push('j'); a.forEach(function (v) { f._.getters[v] = sigDVGetter(v); f._.setters[v] = sigDVSetter(v); @@ -7954,14 +8267,14 @@ var sqlite3InitModule = (() => { rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/; f.sigCheck = function (obj, name, key, sig) { if (Object.prototype.hasOwnProperty.call(obj, key)) { - toss(obj.structName, "already has a property named", key + "."); + toss(obj.structName, 'already has a property named', key + '.'); } rxSig1.test(sig) || rxSig2.test(sig) || toss( - "Malformed signature for", - sPropName(obj.structName, name) + ":", - sig + 'Malformed signature for', + sPropName(obj.structName, name) + ':', + sig, ); }; } @@ -7979,25 +8292,25 @@ var sqlite3InitModule = (() => { prop.get = function () { if (dbg.getter) { log( - "debug.getter:", + 'debug.getter:', f._.getters[sigGlyph], - "for", + 'for', sigIR(sigGlyph), xPropName, - "@", + '@', this.pointer, - "+", + '+', descr.offset, - "sz", - descr.sizeof + 'sz', + descr.sizeof, ); } let rc = new DataView( heap().buffer, this.pointer + descr.offset, - descr.sizeof + descr.sizeof, )[f._.getters[sigGlyph]](0, isLittleEndian); - if (dbg.getter) log("debug.getter:", xPropName, "result =", rc); + if (dbg.getter) log('debug.getter:', xPropName, 'result =', rc); return rc; }; if (descr.readOnly) { @@ -8006,22 +8319,22 @@ var sqlite3InitModule = (() => { prop.set = function (v) { if (dbg.setter) { log( - "debug.setter:", + 'debug.setter:', f._.setters[sigGlyph], - "for", + 'for', sigIR(sigGlyph), xPropName, - "@", + '@', this.pointer, - "+", + '+', descr.offset, - "sz", + 'sz', descr.sizeof, - v + v, ); } if (!this.pointer) { - toss("Cannot set struct property on disposed instance."); + toss('Cannot set struct property on disposed instance.'); } if (null === v) v = 0; else @@ -8032,15 +8345,15 @@ var sqlite3InitModule = (() => { ) { v = v.pointer || 0; if (dbg.setter) - log("debug.setter:", xPropName, "resolved to", v); + log('debug.setter:', xPropName, 'resolved to', v); break; } - toss("Invalid value for pointer-type", xPropName + "."); + toss('Invalid value for pointer-type', xPropName + '.'); } new DataView( heap().buffer, this.pointer + descr.offset, - descr.sizeof + descr.sizeof, )[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian); }; } @@ -8054,59 +8367,59 @@ var sqlite3InitModule = (() => { } else if (!structInfo.name) { structInfo.name = structName; } - if (!structName) toss("Struct name is required."); + if (!structName) toss('Struct name is required.'); let lastMember = false; Object.keys(structInfo.members).forEach((k) => { const m = structInfo.members[k]; - if (!m.sizeof) toss(structName, "member", k, "is missing sizeof."); + if (!m.sizeof) toss(structName, 'member', k, 'is missing sizeof.'); else if (m.sizeof === 1) { - m.signature === "c" || - m.signature === "C" || + m.signature === 'c' || + m.signature === 'C' || toss( - "Unexpected sizeof==1 member", + 'Unexpected sizeof==1 member', sPropName(structInfo.name, k), - "with signature", - m.signature + 'with signature', + m.signature, ); } else { if (0 !== m.sizeof % 4) { console.warn( - "Invalid struct member description =", + 'Invalid struct member description =', m, - "from", - structInfo + 'from', + structInfo, ); toss( structName, - "member", + 'member', k, - "sizeof is not aligned. sizeof=" + m.sizeof + 'sizeof is not aligned. sizeof=' + m.sizeof, ); } if (0 !== m.offset % 4) { console.warn( - "Invalid struct member description =", + 'Invalid struct member description =', m, - "from", - structInfo + 'from', + structInfo, ); toss( structName, - "member", + 'member', k, - "offset is not aligned. offset=" + m.offset + 'offset is not aligned. offset=' + m.offset, ); } } if (!lastMember || lastMember.offset < m.offset) lastMember = m; }); - if (!lastMember) toss("No member property descriptions found."); + if (!lastMember) toss('No member property descriptions found.'); else if (structInfo.sizeof < lastMember.offset + lastMember.sizeof) { toss( - "Invalid struct config:", + 'Invalid struct config:', structName, - "max member offset (" + lastMember.offset + ") ", - "extends past end of struct (sizeof=" + structInfo.sizeof + ")." + 'max member offset (' + lastMember.offset + ') ', + 'extends past end of struct (sizeof=' + structInfo.sizeof + ').', ); } const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags)); @@ -8114,16 +8427,16 @@ var sqlite3InitModule = (() => { const StructCtor = function StructCtor(externalMemory) { if (!(this instanceof StructCtor)) { toss( - "The", + 'The', structName, - "constructor may only be called via 'new'." + "constructor may only be called via 'new'.", ); } else if (arguments.length) { if ( externalMemory !== (externalMemory | 0) || externalMemory <= 0 ) { - toss("Invalid pointer value for", structName, "constructor."); + toss('Invalid pointer value for', structName, 'constructor.'); } __allocStruct(StructCtor, this, externalMemory); } else { @@ -8145,7 +8458,7 @@ var sqlite3InitModule = (() => { constructor: rop(StructCtor), }); Object.keys(structInfo.members).forEach((name) => - makeMemberWrapper(StructCtor, name, structInfo.members[name]) + makeMemberWrapper(StructCtor, name, structInfo.members[name]), ); return StructCtor; }; @@ -8160,7 +8473,7 @@ var sqlite3InitModule = (() => { globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { const toss = (...args) => { - throw new Error(args.join(" ")); + throw new Error(args.join(' ')); }; sqlite3.SQLite3Error.toss; const capi = sqlite3.capi, @@ -8170,84 +8483,84 @@ var sqlite3InitModule = (() => { delete globalThis.WhWasmUtilInstaller; wasm.bindingSignatures = [ - ["sqlite3_aggregate_context", "void*", "sqlite3_context*", "int"], + ['sqlite3_aggregate_context', 'void*', 'sqlite3_context*', 'int'], - ["sqlite3_bind_double", "int", "sqlite3_stmt*", "int", "f64"], - ["sqlite3_bind_int", "int", "sqlite3_stmt*", "int", "int"], - ["sqlite3_bind_null", undefined, "sqlite3_stmt*", "int"], - ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], - ["sqlite3_bind_parameter_index", "int", "sqlite3_stmt*", "string"], + ['sqlite3_bind_double', 'int', 'sqlite3_stmt*', 'int', 'f64'], + ['sqlite3_bind_int', 'int', 'sqlite3_stmt*', 'int', 'int'], + ['sqlite3_bind_null', undefined, 'sqlite3_stmt*', 'int'], + ['sqlite3_bind_parameter_count', 'int', 'sqlite3_stmt*'], + ['sqlite3_bind_parameter_index', 'int', 'sqlite3_stmt*', 'string'], [ - "sqlite3_bind_pointer", - "int", - "sqlite3_stmt*", - "int", - "*", - "string:static", - "*", + 'sqlite3_bind_pointer', + 'int', + 'sqlite3_stmt*', + 'int', + '*', + 'string:static', + '*', ], [ - "sqlite3_busy_handler", - "int", + 'sqlite3_busy_handler', + 'int', [ - "sqlite3*", + 'sqlite3*', new wasm.xWrap.FuncPtrAdapter({ - signature: "i(pi)", + signature: 'i(pi)', contextKey: (argv, argIndex) => argv[0], }), - "*", + '*', ], ], - ["sqlite3_busy_timeout", "int", "sqlite3*", "int"], - - ["sqlite3_changes", "int", "sqlite3*"], - ["sqlite3_clear_bindings", "int", "sqlite3_stmt*"], - ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"], - ["sqlite3_column_blob", "*", "sqlite3_stmt*", "int"], - ["sqlite3_column_bytes", "int", "sqlite3_stmt*", "int"], - ["sqlite3_column_count", "int", "sqlite3_stmt*"], - ["sqlite3_column_double", "f64", "sqlite3_stmt*", "int"], - ["sqlite3_column_int", "int", "sqlite3_stmt*", "int"], - ["sqlite3_column_name", "string", "sqlite3_stmt*", "int"], - ["sqlite3_column_text", "string", "sqlite3_stmt*", "int"], - ["sqlite3_column_type", "int", "sqlite3_stmt*", "int"], - ["sqlite3_column_value", "sqlite3_value*", "sqlite3_stmt*", "int"], + ['sqlite3_busy_timeout', 'int', 'sqlite3*', 'int'], + + ['sqlite3_changes', 'int', 'sqlite3*'], + ['sqlite3_clear_bindings', 'int', 'sqlite3_stmt*'], + ['sqlite3_collation_needed', 'int', 'sqlite3*', '*', '*'], + ['sqlite3_column_blob', '*', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_bytes', 'int', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_count', 'int', 'sqlite3_stmt*'], + ['sqlite3_column_double', 'f64', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_int', 'int', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_name', 'string', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_text', 'string', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_type', 'int', 'sqlite3_stmt*', 'int'], + ['sqlite3_column_value', 'sqlite3_value*', 'sqlite3_stmt*', 'int'], [ - "sqlite3_commit_hook", - "void*", + 'sqlite3_commit_hook', + 'void*', [ - "sqlite3*", + 'sqlite3*', new wasm.xWrap.FuncPtrAdapter({ - name: "sqlite3_commit_hook", - signature: "i(p)", + name: 'sqlite3_commit_hook', + signature: 'i(p)', contextKey: (argv) => argv[0], }), - "*", + '*', ], ], - ["sqlite3_compileoption_get", "string", "int"], - ["sqlite3_compileoption_used", "int", "string"], - ["sqlite3_complete", "int", "string:flexible"], - ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"], - - ["sqlite3_data_count", "int", "sqlite3_stmt*"], - ["sqlite3_db_filename", "string", "sqlite3*", "string"], - ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], - ["sqlite3_db_name", "string", "sqlite3*", "int"], - ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"], - ["sqlite3_errcode", "int", "sqlite3*"], - ["sqlite3_errmsg", "string", "sqlite3*"], - ["sqlite3_error_offset", "int", "sqlite3*"], - ["sqlite3_errstr", "string", "int"], + ['sqlite3_compileoption_get', 'string', 'int'], + ['sqlite3_compileoption_used', 'int', 'string'], + ['sqlite3_complete', 'int', 'string:flexible'], + ['sqlite3_context_db_handle', 'sqlite3*', 'sqlite3_context*'], + + ['sqlite3_data_count', 'int', 'sqlite3_stmt*'], + ['sqlite3_db_filename', 'string', 'sqlite3*', 'string'], + ['sqlite3_db_handle', 'sqlite3*', 'sqlite3_stmt*'], + ['sqlite3_db_name', 'string', 'sqlite3*', 'int'], + ['sqlite3_db_status', 'int', 'sqlite3*', 'int', '*', '*', 'int'], + ['sqlite3_errcode', 'int', 'sqlite3*'], + ['sqlite3_errmsg', 'string', 'sqlite3*'], + ['sqlite3_error_offset', 'int', 'sqlite3*'], + ['sqlite3_errstr', 'string', 'int'], [ - "sqlite3_exec", - "int", + 'sqlite3_exec', + 'int', [ - "sqlite3*", - "string:flexible", + 'sqlite3*', + 'string:flexible', new wasm.xWrap.FuncPtrAdapter({ - signature: "i(pipp)", - bindScope: "transient", + signature: 'i(pipp)', + bindScope: 'transient', callProxy: (callback) => { let aNames; return (pVoid, nCols, pColVals, pColNames) => { @@ -8261,108 +8574,108 @@ var sqlite3InitModule = (() => { }; }, }), - "*", - "**", + '*', + '**', ], ], - ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], - ["sqlite3_extended_errcode", "int", "sqlite3*"], - ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], - ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"], - ["sqlite3_finalize", "int", "sqlite3_stmt*"], - ["sqlite3_free", undefined, "*"], - ["sqlite3_get_autocommit", "int", "sqlite3*"], - ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"], - ["sqlite3_initialize", undefined], - - ["sqlite3_keyword_count", "int"], - ["sqlite3_keyword_name", "int", ["int", "**", "*"]], - ["sqlite3_keyword_check", "int", ["string", "int"]], - ["sqlite3_libversion", "string"], - ["sqlite3_libversion_number", "int"], - ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]], - ["sqlite3_malloc", "*", "int"], - ["sqlite3_open", "int", "string", "*"], - ["sqlite3_open_v2", "int", "string", "*", "int", "string"], + ['sqlite3_expanded_sql', 'string', 'sqlite3_stmt*'], + ['sqlite3_extended_errcode', 'int', 'sqlite3*'], + ['sqlite3_extended_result_codes', 'int', 'sqlite3*', 'int'], + ['sqlite3_file_control', 'int', 'sqlite3*', 'string', 'int', '*'], + ['sqlite3_finalize', 'int', 'sqlite3_stmt*'], + ['sqlite3_free', undefined, '*'], + ['sqlite3_get_autocommit', 'int', 'sqlite3*'], + ['sqlite3_get_auxdata', '*', 'sqlite3_context*', 'int'], + ['sqlite3_initialize', undefined], + + ['sqlite3_keyword_count', 'int'], + ['sqlite3_keyword_name', 'int', ['int', '**', '*']], + ['sqlite3_keyword_check', 'int', ['string', 'int']], + ['sqlite3_libversion', 'string'], + ['sqlite3_libversion_number', 'int'], + ['sqlite3_limit', 'int', ['sqlite3*', 'int', 'int']], + ['sqlite3_malloc', '*', 'int'], + ['sqlite3_open', 'int', 'string', '*'], + ['sqlite3_open_v2', 'int', 'string', '*', 'int', 'string'], [ - "sqlite3_progress_handler", + 'sqlite3_progress_handler', undefined, [ - "sqlite3*", - "int", + 'sqlite3*', + 'int', new wasm.xWrap.FuncPtrAdapter({ - name: "xProgressHandler", - signature: "i(p)", - bindScope: "context", + name: 'xProgressHandler', + signature: 'i(p)', + bindScope: 'context', contextKey: (argv, argIndex) => argv[0], }), - "*", + '*', ], ], - ["sqlite3_realloc", "*", "*", "int"], - ["sqlite3_reset", "int", "sqlite3_stmt*"], + ['sqlite3_realloc', '*', '*', 'int'], + ['sqlite3_reset', 'int', 'sqlite3_stmt*'], [ - "sqlite3_result_blob", + 'sqlite3_result_blob', undefined, - "sqlite3_context*", - "*", - "int", - "*", + 'sqlite3_context*', + '*', + 'int', + '*', ], - ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"], + ['sqlite3_result_double', undefined, 'sqlite3_context*', 'f64'], [ - "sqlite3_result_error", + 'sqlite3_result_error', undefined, - "sqlite3_context*", - "string", - "int", + 'sqlite3_context*', + 'string', + 'int', ], - ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"], - ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"], - ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"], - ["sqlite3_result_int", undefined, "sqlite3_context*", "int"], - ["sqlite3_result_null", undefined, "sqlite3_context*"], + ['sqlite3_result_error_code', undefined, 'sqlite3_context*', 'int'], + ['sqlite3_result_error_nomem', undefined, 'sqlite3_context*'], + ['sqlite3_result_error_toobig', undefined, 'sqlite3_context*'], + ['sqlite3_result_int', undefined, 'sqlite3_context*', 'int'], + ['sqlite3_result_null', undefined, 'sqlite3_context*'], [ - "sqlite3_result_pointer", + 'sqlite3_result_pointer', undefined, - "sqlite3_context*", - "*", - "string:static", - "*", + 'sqlite3_context*', + '*', + 'string:static', + '*', ], - ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"], + ['sqlite3_result_subtype', undefined, 'sqlite3_value*', 'int'], [ - "sqlite3_result_text", + 'sqlite3_result_text', undefined, - "sqlite3_context*", - "string", - "int", - "*", + 'sqlite3_context*', + 'string', + 'int', + '*', ], - ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"], + ['sqlite3_result_zeroblob', undefined, 'sqlite3_context*', 'int'], [ - "sqlite3_rollback_hook", - "void*", + 'sqlite3_rollback_hook', + 'void*', [ - "sqlite3*", + 'sqlite3*', new wasm.xWrap.FuncPtrAdapter({ - name: "sqlite3_rollback_hook", - signature: "v(p)", + name: 'sqlite3_rollback_hook', + signature: 'v(p)', contextKey: (argv) => argv[0], }), - "*", + '*', ], ], [ - "sqlite3_set_authorizer", - "int", + 'sqlite3_set_authorizer', + 'int', [ - "sqlite3*", + 'sqlite3*', new wasm.xWrap.FuncPtrAdapter({ - name: "sqlite3_set_authorizer::xAuth", - signature: "i(pi" + "ssss)", + name: 'sqlite3_set_authorizer::xAuth', + signature: 'i(pi' + 'ssss)', contextKey: (argv, argIndex) => argv[0], callProxy: (callback) => { return (pV, iCode, s0, s1, s2, s3) => { @@ -8378,128 +8691,128 @@ var sqlite3InitModule = (() => { }; }, }), - "*", + '*', ], ], [ - "sqlite3_set_auxdata", + 'sqlite3_set_auxdata', undefined, [ - "sqlite3_context*", - "int", - "*", + 'sqlite3_context*', + 'int', + '*', new wasm.xWrap.FuncPtrAdapter({ - name: "xDestroyAuxData", - signature: "v(*)", + name: 'xDestroyAuxData', + signature: 'v(*)', contextKey: (argv, argIndex) => argv[0], }), ], ], - ["sqlite3_shutdown", undefined], - ["sqlite3_sourceid", "string"], - ["sqlite3_sql", "string", "sqlite3_stmt*"], - ["sqlite3_status", "int", "int", "*", "*", "int"], - ["sqlite3_step", "int", "sqlite3_stmt*"], - ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]], - ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]], - ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"], - ["sqlite3_strglob", "int", "string", "string"], - ["sqlite3_stricmp", "int", "string", "string"], - ["sqlite3_strlike", "int", "string", "string", "int"], - ["sqlite3_strnicmp", "int", "string", "string", "int"], + ['sqlite3_shutdown', undefined], + ['sqlite3_sourceid', 'string'], + ['sqlite3_sql', 'string', 'sqlite3_stmt*'], + ['sqlite3_status', 'int', 'int', '*', '*', 'int'], + ['sqlite3_step', 'int', 'sqlite3_stmt*'], + ['sqlite3_stmt_isexplain', 'int', ['sqlite3_stmt*']], + ['sqlite3_stmt_readonly', 'int', ['sqlite3_stmt*']], + ['sqlite3_stmt_status', 'int', 'sqlite3_stmt*', 'int', 'int'], + ['sqlite3_strglob', 'int', 'string', 'string'], + ['sqlite3_stricmp', 'int', 'string', 'string'], + ['sqlite3_strlike', 'int', 'string', 'string', 'int'], + ['sqlite3_strnicmp', 'int', 'string', 'string', 'int'], [ - "sqlite3_table_column_metadata", - "int", - "sqlite3*", - "string", - "string", - "string", - "**", - "**", - "*", - "*", - "*", + 'sqlite3_table_column_metadata', + 'int', + 'sqlite3*', + 'string', + 'string', + 'string', + '**', + '**', + '*', + '*', + '*', ], - ["sqlite3_total_changes", "int", "sqlite3*"], + ['sqlite3_total_changes', 'int', 'sqlite3*'], [ - "sqlite3_trace_v2", - "int", + 'sqlite3_trace_v2', + 'int', [ - "sqlite3*", - "int", + 'sqlite3*', + 'int', new wasm.xWrap.FuncPtrAdapter({ - name: "sqlite3_trace_v2::callback", - signature: "i(ippp)", + name: 'sqlite3_trace_v2::callback', + signature: 'i(ippp)', contextKey: (argv, argIndex) => argv[0], }), - "*", + '*', ], ], - ["sqlite3_txn_state", "int", ["sqlite3*", "string"]], - - ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], - ["sqlite3_uri_key", "string", "sqlite3_filename", "int"], - ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], - ["sqlite3_user_data", "void*", "sqlite3_context*"], - ["sqlite3_value_blob", "*", "sqlite3_value*"], - ["sqlite3_value_bytes", "int", "sqlite3_value*"], - ["sqlite3_value_double", "f64", "sqlite3_value*"], - ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"], - ["sqlite3_value_free", undefined, "sqlite3_value*"], - ["sqlite3_value_frombind", "int", "sqlite3_value*"], - ["sqlite3_value_int", "int", "sqlite3_value*"], - ["sqlite3_value_nochange", "int", "sqlite3_value*"], - ["sqlite3_value_numeric_type", "int", "sqlite3_value*"], - ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], - ["sqlite3_value_subtype", "int", "sqlite3_value*"], - ["sqlite3_value_text", "string", "sqlite3_value*"], - ["sqlite3_value_type", "int", "sqlite3_value*"], - ["sqlite3_vfs_find", "*", "string"], - ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], - ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"], + ['sqlite3_txn_state', 'int', ['sqlite3*', 'string']], + + ['sqlite3_uri_boolean', 'int', 'sqlite3_filename', 'string', 'int'], + ['sqlite3_uri_key', 'string', 'sqlite3_filename', 'int'], + ['sqlite3_uri_parameter', 'string', 'sqlite3_filename', 'string'], + ['sqlite3_user_data', 'void*', 'sqlite3_context*'], + ['sqlite3_value_blob', '*', 'sqlite3_value*'], + ['sqlite3_value_bytes', 'int', 'sqlite3_value*'], + ['sqlite3_value_double', 'f64', 'sqlite3_value*'], + ['sqlite3_value_dup', 'sqlite3_value*', 'sqlite3_value*'], + ['sqlite3_value_free', undefined, 'sqlite3_value*'], + ['sqlite3_value_frombind', 'int', 'sqlite3_value*'], + ['sqlite3_value_int', 'int', 'sqlite3_value*'], + ['sqlite3_value_nochange', 'int', 'sqlite3_value*'], + ['sqlite3_value_numeric_type', 'int', 'sqlite3_value*'], + ['sqlite3_value_pointer', '*', 'sqlite3_value*', 'string:static'], + ['sqlite3_value_subtype', 'int', 'sqlite3_value*'], + ['sqlite3_value_text', 'string', 'sqlite3_value*'], + ['sqlite3_value_type', 'int', 'sqlite3_value*'], + ['sqlite3_vfs_find', '*', 'string'], + ['sqlite3_vfs_register', 'int', 'sqlite3_vfs*', 'int'], + ['sqlite3_vfs_unregister', 'int', 'sqlite3_vfs*'], ]; wasm.bindingSignatures.int64 = [ - ["sqlite3_bind_int64", "int", ["sqlite3_stmt*", "int", "i64"]], - ["sqlite3_changes64", "i64", ["sqlite3*"]], - ["sqlite3_column_int64", "i64", ["sqlite3_stmt*", "int"]], + ['sqlite3_bind_int64', 'int', ['sqlite3_stmt*', 'int', 'i64']], + ['sqlite3_changes64', 'i64', ['sqlite3*']], + ['sqlite3_column_int64', 'i64', ['sqlite3_stmt*', 'int']], [ - "sqlite3_create_module", - "int", - ["sqlite3*", "string", "sqlite3_module*", "*"], + 'sqlite3_create_module', + 'int', + ['sqlite3*', 'string', 'sqlite3_module*', '*'], ], [ - "sqlite3_create_module_v2", - "int", - ["sqlite3*", "string", "sqlite3_module*", "*", "*"], + 'sqlite3_create_module_v2', + 'int', + ['sqlite3*', 'string', 'sqlite3_module*', '*', '*'], ], - ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]], + ['sqlite3_declare_vtab', 'int', ['sqlite3*', 'string:flexible']], [ - "sqlite3_deserialize", - "int", - "sqlite3*", - "string", - "*", - "i64", - "i64", - "int", + 'sqlite3_deserialize', + 'int', + 'sqlite3*', + 'string', + '*', + 'i64', + 'i64', + 'int', ], - ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]], - ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]], - ["sqlite3_malloc64", "*", "i64"], - ["sqlite3_msize", "i64", "*"], - ["sqlite3_overload_function", "int", ["sqlite3*", "string", "int"]], - ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"], - ["sqlite3_preupdate_count", "int", "sqlite3*"], - ["sqlite3_preupdate_depth", "int", "sqlite3*"], + ['sqlite3_drop_modules', 'int', ['sqlite3*', '**']], + ['sqlite3_last_insert_rowid', 'i64', ['sqlite3*']], + ['sqlite3_malloc64', '*', 'i64'], + ['sqlite3_msize', 'i64', '*'], + ['sqlite3_overload_function', 'int', ['sqlite3*', 'string', 'int']], + ['sqlite3_preupdate_blobwrite', 'int', 'sqlite3*'], + ['sqlite3_preupdate_count', 'int', 'sqlite3*'], + ['sqlite3_preupdate_depth', 'int', 'sqlite3*'], [ - "sqlite3_preupdate_hook", - "*", + 'sqlite3_preupdate_hook', + '*', [ - "sqlite3*", + 'sqlite3*', new wasm.xWrap.FuncPtrAdapter({ - name: "sqlite3_preupdate_hook", - signature: "v(ppippjj)", + name: 'sqlite3_preupdate_hook', + signature: 'v(ppippjj)', contextKey: (argv) => argv[0], callProxy: (callback) => { return (p, db, op, zDb, zTbl, iKey1, iKey2) => { @@ -8510,31 +8823,31 @@ var sqlite3InitModule = (() => { wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl), iKey1, - iKey2 + iKey2, ); }; }, }), - "*", + '*', ], ], - ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]], - ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]], - ["sqlite3_realloc64", "*", "*", "i64"], - ["sqlite3_result_int64", undefined, "*", "i64"], - ["sqlite3_result_zeroblob64", "int", "*", "i64"], - ["sqlite3_serialize", "*", "sqlite3*", "string", "*", "int"], - ["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]], - ["sqlite3_status64", "int", "int", "*", "*", "int"], - ["sqlite3_total_changes64", "i64", ["sqlite3*"]], + ['sqlite3_preupdate_new', 'int', ['sqlite3*', 'int', '**']], + ['sqlite3_preupdate_old', 'int', ['sqlite3*', 'int', '**']], + ['sqlite3_realloc64', '*', '*', 'i64'], + ['sqlite3_result_int64', undefined, '*', 'i64'], + ['sqlite3_result_zeroblob64', 'int', '*', 'i64'], + ['sqlite3_serialize', '*', 'sqlite3*', 'string', '*', 'int'], + ['sqlite3_set_last_insert_rowid', undefined, ['sqlite3*', 'i64']], + ['sqlite3_status64', 'int', 'int', '*', '*', 'int'], + ['sqlite3_total_changes64', 'i64', ['sqlite3*']], [ - "sqlite3_update_hook", - "*", + 'sqlite3_update_hook', + '*', [ - "sqlite3*", + 'sqlite3*', new wasm.xWrap.FuncPtrAdapter({ - name: "sqlite3_update_hook", - signature: "v(iippj)", + name: 'sqlite3_update_hook', + signature: 'v(iippj)', contextKey: (argv) => argv[0], callProxy: (callback) => { return (p, op, z0, z1, rowid) => { @@ -8543,30 +8856,30 @@ var sqlite3InitModule = (() => { op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), - rowid + rowid, ); }; }, }), - "*", + '*', ], ], - ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], - ["sqlite3_value_int64", "i64", "sqlite3_value*"], - ["sqlite3_vtab_collation", "string", "sqlite3_index_info*", "int"], - ["sqlite3_vtab_distinct", "int", "sqlite3_index_info*"], - ["sqlite3_vtab_in", "int", "sqlite3_index_info*", "int", "int"], - ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"], - ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"], - - ["sqlite3_vtab_nochange", "int", "sqlite3_context*"], - ["sqlite3_vtab_on_conflict", "int", "sqlite3*"], - ["sqlite3_vtab_rhs_value", "int", "sqlite3_index_info*", "int", "**"], + ['sqlite3_uri_int64', 'i64', ['sqlite3_filename', 'string', 'i64']], + ['sqlite3_value_int64', 'i64', 'sqlite3_value*'], + ['sqlite3_vtab_collation', 'string', 'sqlite3_index_info*', 'int'], + ['sqlite3_vtab_distinct', 'int', 'sqlite3_index_info*'], + ['sqlite3_vtab_in', 'int', 'sqlite3_index_info*', 'int', 'int'], + ['sqlite3_vtab_in_first', 'int', 'sqlite3_value*', '**'], + ['sqlite3_vtab_in_next', 'int', 'sqlite3_value*', '**'], + + ['sqlite3_vtab_nochange', 'int', 'sqlite3_context*'], + ['sqlite3_vtab_on_conflict', 'int', 'sqlite3*'], + ['sqlite3_vtab_rhs_value', 'int', 'sqlite3_index_info*', 'int', '**'], ]; if (wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add) { const __ipsProxy = { - signature: "i(ps)", + signature: 'i(ps)', callProxy: (callback) => { return (p, s) => { try { @@ -8581,340 +8894,340 @@ var sqlite3InitModule = (() => { wasm.bindingSignatures.int64.push( ...[ [ - "sqlite3changegroup_add", - "int", - ["sqlite3_changegroup*", "int", "void*"], + 'sqlite3changegroup_add', + 'int', + ['sqlite3_changegroup*', 'int', 'void*'], ], [ - "sqlite3changegroup_add_strm", - "int", + 'sqlite3changegroup_add_strm', + 'int', [ - "sqlite3_changegroup*", + 'sqlite3_changegroup*', new wasm.xWrap.FuncPtrAdapter({ - name: "xInput", - signature: "i(ppp)", - bindScope: "transient", + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], [ - "sqlite3changegroup_delete", + 'sqlite3changegroup_delete', undefined, - ["sqlite3_changegroup*"], + ['sqlite3_changegroup*'], ], - ["sqlite3changegroup_new", "int", ["**"]], + ['sqlite3changegroup_new', 'int', ['**']], [ - "sqlite3changegroup_output", - "int", - ["sqlite3_changegroup*", "int*", "**"], + 'sqlite3changegroup_output', + 'int', + ['sqlite3_changegroup*', 'int*', '**'], ], [ - "sqlite3changegroup_output_strm", - "int", + 'sqlite3changegroup_output_strm', + 'int', [ - "sqlite3_changegroup*", + 'sqlite3_changegroup*', new wasm.xWrap.FuncPtrAdapter({ - name: "xOutput", - signature: "i(ppi)", - bindScope: "transient", + name: 'xOutput', + signature: 'i(ppi)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], [ - "sqlite3changeset_apply", - "int", + 'sqlite3changeset_apply', + 'int', [ - "sqlite3*", - "int", - "void*", + 'sqlite3*', + 'int', + 'void*', new wasm.xWrap.FuncPtrAdapter({ - name: "xFilter", - bindScope: "transient", + name: 'xFilter', + bindScope: 'transient', ...__ipsProxy, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xConflict", - signature: "i(pip)", - bindScope: "transient", + name: 'xConflict', + signature: 'i(pip)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], [ - "sqlite3changeset_apply_strm", - "int", + 'sqlite3changeset_apply_strm', + 'int', [ - "sqlite3*", + 'sqlite3*', new wasm.xWrap.FuncPtrAdapter({ - name: "xInput", - signature: "i(ppp)", - bindScope: "transient", + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', new wasm.xWrap.FuncPtrAdapter({ - name: "xFilter", - bindScope: "transient", + name: 'xFilter', + bindScope: 'transient', ...__ipsProxy, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xConflict", - signature: "i(pip)", - bindScope: "transient", + name: 'xConflict', + signature: 'i(pip)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], [ - "sqlite3changeset_apply_v2", - "int", + 'sqlite3changeset_apply_v2', + 'int', [ - "sqlite3*", - "int", - "void*", + 'sqlite3*', + 'int', + 'void*', new wasm.xWrap.FuncPtrAdapter({ - name: "xFilter", - bindScope: "transient", + name: 'xFilter', + bindScope: 'transient', ...__ipsProxy, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xConflict", - signature: "i(pip)", - bindScope: "transient", + name: 'xConflict', + signature: 'i(pip)', + bindScope: 'transient', }), - "void*", - "**", - "int*", - "int", + 'void*', + '**', + 'int*', + 'int', ], ], [ - "sqlite3changeset_apply_v2_strm", - "int", + 'sqlite3changeset_apply_v2_strm', + 'int', [ - "sqlite3*", + 'sqlite3*', new wasm.xWrap.FuncPtrAdapter({ - name: "xInput", - signature: "i(ppp)", - bindScope: "transient", + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', new wasm.xWrap.FuncPtrAdapter({ - name: "xFilter", - bindScope: "transient", + name: 'xFilter', + bindScope: 'transient', ...__ipsProxy, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xConflict", - signature: "i(pip)", - bindScope: "transient", + name: 'xConflict', + signature: 'i(pip)', + bindScope: 'transient', }), - "void*", - "**", - "int*", - "int", + 'void*', + '**', + 'int*', + 'int', ], ], [ - "sqlite3changeset_concat", - "int", - ["int", "void*", "int", "void*", "int*", "**"], + 'sqlite3changeset_concat', + 'int', + ['int', 'void*', 'int', 'void*', 'int*', '**'], ], [ - "sqlite3changeset_concat_strm", - "int", + 'sqlite3changeset_concat_strm', + 'int', [ new wasm.xWrap.FuncPtrAdapter({ - name: "xInputA", - signature: "i(ppp)", - bindScope: "transient", + name: 'xInputA', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', new wasm.xWrap.FuncPtrAdapter({ - name: "xInputB", - signature: "i(ppp)", - bindScope: "transient", + name: 'xInputB', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', new wasm.xWrap.FuncPtrAdapter({ - name: "xOutput", - signature: "i(ppi)", - bindScope: "transient", + name: 'xOutput', + signature: 'i(ppi)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], [ - "sqlite3changeset_conflict", - "int", - ["sqlite3_changeset_iter*", "int", "**"], + 'sqlite3changeset_conflict', + 'int', + ['sqlite3_changeset_iter*', 'int', '**'], ], - ["sqlite3changeset_finalize", "int", ["sqlite3_changeset_iter*"]], + ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']], [ - "sqlite3changeset_fk_conflicts", - "int", - ["sqlite3_changeset_iter*", "int*"], + 'sqlite3changeset_fk_conflicts', + 'int', + ['sqlite3_changeset_iter*', 'int*'], ], [ - "sqlite3changeset_invert", - "int", - ["int", "void*", "int*", "**"], + 'sqlite3changeset_invert', + 'int', + ['int', 'void*', 'int*', '**'], ], [ - "sqlite3changeset_invert_strm", - "int", + 'sqlite3changeset_invert_strm', + 'int', [ new wasm.xWrap.FuncPtrAdapter({ - name: "xInput", - signature: "i(ppp)", - bindScope: "transient", + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', new wasm.xWrap.FuncPtrAdapter({ - name: "xOutput", - signature: "i(ppi)", - bindScope: "transient", + name: 'xOutput', + signature: 'i(ppi)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], [ - "sqlite3changeset_new", - "int", - ["sqlite3_changeset_iter*", "int", "**"], + 'sqlite3changeset_new', + 'int', + ['sqlite3_changeset_iter*', 'int', '**'], ], - ["sqlite3changeset_next", "int", ["sqlite3_changeset_iter*"]], + ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']], [ - "sqlite3changeset_old", - "int", - ["sqlite3_changeset_iter*", "int", "**"], + 'sqlite3changeset_old', + 'int', + ['sqlite3_changeset_iter*', 'int', '**'], ], [ - "sqlite3changeset_op", - "int", - ["sqlite3_changeset_iter*", "**", "int*", "int*", "int*"], + 'sqlite3changeset_op', + 'int', + ['sqlite3_changeset_iter*', '**', 'int*', 'int*', 'int*'], ], [ - "sqlite3changeset_pk", - "int", - ["sqlite3_changeset_iter*", "**", "int*"], + 'sqlite3changeset_pk', + 'int', + ['sqlite3_changeset_iter*', '**', 'int*'], ], - ["sqlite3changeset_start", "int", ["**", "int", "*"]], + ['sqlite3changeset_start', 'int', ['**', 'int', '*']], [ - "sqlite3changeset_start_strm", - "int", + 'sqlite3changeset_start_strm', + 'int', [ - "**", + '**', new wasm.xWrap.FuncPtrAdapter({ - name: "xInput", - signature: "i(ppp)", - bindScope: "transient", + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], - ["sqlite3changeset_start_v2", "int", ["**", "int", "*", "int"]], + ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']], [ - "sqlite3changeset_start_v2_strm", - "int", + 'sqlite3changeset_start_v2_strm', + 'int', [ - "**", + '**', new wasm.xWrap.FuncPtrAdapter({ - name: "xInput", - signature: "i(ppp)", - bindScope: "transient", + name: 'xInput', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", - "int", + 'void*', + 'int', ], ], - ["sqlite3session_attach", "int", ["sqlite3_session*", "string"]], + ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']], [ - "sqlite3session_changeset", - "int", - ["sqlite3_session*", "int*", "**"], + 'sqlite3session_changeset', + 'int', + ['sqlite3_session*', 'int*', '**'], ], - ["sqlite3session_changeset_size", "i64", ["sqlite3_session*"]], + ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']], [ - "sqlite3session_changeset_strm", - "int", + 'sqlite3session_changeset_strm', + 'int', [ - "sqlite3_session*", + 'sqlite3_session*', new wasm.xWrap.FuncPtrAdapter({ - name: "xOutput", - signature: "i(ppp)", - bindScope: "transient", + name: 'xOutput', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], - ["sqlite3session_config", "int", ["int", "void*"]], - ["sqlite3session_create", "int", ["sqlite3*", "string", "**"]], + ['sqlite3session_config', 'int', ['int', 'void*']], + ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']], [ - "sqlite3session_diff", - "int", - ["sqlite3_session*", "string", "string", "**"], + 'sqlite3session_diff', + 'int', + ['sqlite3_session*', 'string', 'string', '**'], ], - ["sqlite3session_enable", "int", ["sqlite3_session*", "int"]], - ["sqlite3session_indirect", "int", ["sqlite3_session*", "int"]], - ["sqlite3session_isempty", "int", ["sqlite3_session*"]], - ["sqlite3session_memory_used", "i64", ["sqlite3_session*"]], + ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']], + ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']], + ['sqlite3session_isempty', 'int', ['sqlite3_session*']], + ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']], [ - "sqlite3session_object_config", - "int", - ["sqlite3_session*", "int", "void*"], + 'sqlite3session_object_config', + 'int', + ['sqlite3_session*', 'int', 'void*'], ], [ - "sqlite3session_patchset", - "int", - ["sqlite3_session*", "*", "**"], + 'sqlite3session_patchset', + 'int', + ['sqlite3_session*', '*', '**'], ], [ - "sqlite3session_patchset_strm", - "int", + 'sqlite3session_patchset_strm', + 'int', [ - "sqlite3_session*", + 'sqlite3_session*', new wasm.xWrap.FuncPtrAdapter({ - name: "xOutput", - signature: "i(ppp)", - bindScope: "transient", + name: 'xOutput', + signature: 'i(ppp)', + bindScope: 'transient', }), - "void*", + 'void*', ], ], [ - "sqlite3session_table_filter", + 'sqlite3session_table_filter', undefined, [ - "sqlite3_session*", + 'sqlite3_session*', new wasm.xWrap.FuncPtrAdapter({ - name: "xFilter", + name: 'xFilter', ...__ipsProxy, contextKey: (argv, argIndex) => argv[0], }), - "*", + '*', ], ], - ] + ], ); } wasm.bindingSignatures.wasmInternal = [ - ["sqlite3__wasm_db_reset", "int", "sqlite3*"], - ["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*", "string"], + ['sqlite3__wasm_db_reset', 'int', 'sqlite3*'], + ['sqlite3__wasm_db_vfs', 'sqlite3_vfs*', 'sqlite3*', 'string'], [ - "sqlite3__wasm_vfs_create_file", - "int", - "sqlite3_vfs*", - "string", - "*", - "int", + 'sqlite3__wasm_vfs_create_file', + 'int', + 'sqlite3_vfs*', + 'string', + '*', + 'int', ], - ["sqlite3__wasm_posix_create_file", "int", "string", "*", "int"], - ["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*", "string"], - ["sqlite3__wasm_qfmt_token", "string:dealloc", "string", "int"], + ['sqlite3__wasm_posix_create_file', 'int', 'string', '*', 'int'], + ['sqlite3__wasm_vfs_unlink', 'int', 'sqlite3_vfs*', 'string'], + ['sqlite3__wasm_qfmt_token', 'string:dealloc', 'string', 'int'], ]; sqlite3.StructBinder = globalThis.Jaccwabyt({ @@ -8922,82 +9235,82 @@ var sqlite3InitModule = (() => { alloc: wasm.alloc, dealloc: wasm.dealloc, bigIntEnabled: wasm.bigIntEnabled, - memberPrefix: "$", + memberPrefix: '$', }); delete globalThis.Jaccwabyt; { - const __xString = wasm.xWrap.argAdapter("string"); - wasm.xWrap.argAdapter("string:flexible", (v) => - __xString(util.flexibleString(v)) + const __xString = wasm.xWrap.argAdapter('string'); + wasm.xWrap.argAdapter('string:flexible', (v) => + __xString(util.flexibleString(v)), ); wasm.xWrap.argAdapter( - "string:static", + 'string:static', function (v) { if (wasm.isPtr(v)) return v; - v = "" + v; + v = '' + v; let rc = this[v]; return rc || (this[v] = wasm.allocCString(v)); - }.bind(Object.create(null)) + }.bind(Object.create(null)), ); - const __xArgPtr = wasm.xWrap.argAdapter("*"); + const __xArgPtr = wasm.xWrap.argAdapter('*'); const nilType = function () {}; - wasm.xWrap.argAdapter("sqlite3_filename", __xArgPtr)( - "sqlite3_context*", - __xArgPtr - )("sqlite3_value*", __xArgPtr)("void*", __xArgPtr)( - "sqlite3_changegroup*", - __xArgPtr - )("sqlite3_changeset_iter*", __xArgPtr)( - "sqlite3_session*", - __xArgPtr - )("sqlite3_stmt*", (v) => + wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)( + 'sqlite3_context*', + __xArgPtr, + )('sqlite3_value*', __xArgPtr)('void*', __xArgPtr)( + 'sqlite3_changegroup*', + __xArgPtr, + )('sqlite3_changeset_iter*', __xArgPtr)( + 'sqlite3_session*', + __xArgPtr, + )('sqlite3_stmt*', (v) => __xArgPtr( - v instanceof (sqlite3?.oo1?.Stmt || nilType) ? v.pointer : v - ) - )("sqlite3*", (v) => + v instanceof (sqlite3?.oo1?.Stmt || nilType) ? v.pointer : v, + ), + )('sqlite3*', (v) => __xArgPtr( - v instanceof (sqlite3?.oo1?.DB || nilType) ? v.pointer : v - ) - )("sqlite3_index_info*", (v) => + v instanceof (sqlite3?.oo1?.DB || nilType) ? v.pointer : v, + ), + )('sqlite3_index_info*', (v) => __xArgPtr( - v instanceof (capi.sqlite3_index_info || nilType) ? v.pointer : v - ) - )("sqlite3_module*", (v) => + v instanceof (capi.sqlite3_index_info || nilType) ? v.pointer : v, + ), + )('sqlite3_module*', (v) => __xArgPtr( - v instanceof (capi.sqlite3_module || nilType) ? v.pointer : v - ) - )("sqlite3_vfs*", (v) => { - if ("string" === typeof v) { + v instanceof (capi.sqlite3_module || nilType) ? v.pointer : v, + ), + )('sqlite3_vfs*', (v) => { + if ('string' === typeof v) { return ( capi.sqlite3_vfs_find(v) || sqlite3.SQLite3Error.toss( capi.SQLITE_NOTFOUND, - "Unknown sqlite3_vfs name:", - v + 'Unknown sqlite3_vfs name:', + v, ) ); } return __xArgPtr( - v instanceof (capi.sqlite3_vfs || nilType) ? v.pointer : v + v instanceof (capi.sqlite3_vfs || nilType) ? v.pointer : v, ); }); - const __xRcPtr = wasm.xWrap.resultAdapter("*"); - wasm.xWrap.resultAdapter("sqlite3*", __xRcPtr)( - "sqlite3_context*", - __xRcPtr - )("sqlite3_stmt*", __xRcPtr)("sqlite3_value*", __xRcPtr)( - "sqlite3_vfs*", - __xRcPtr - )("void*", __xRcPtr); + const __xRcPtr = wasm.xWrap.resultAdapter('*'); + wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)( + 'sqlite3_context*', + __xRcPtr, + )('sqlite3_stmt*', __xRcPtr)('sqlite3_value*', __xRcPtr)( + 'sqlite3_vfs*', + __xRcPtr, + )('void*', __xRcPtr); if (0 === wasm.exports.sqlite3_step.length) { wasm.xWrap.doArgcCheck = false; sqlite3.config.warn( - "Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks." + 'Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks.', ); } for (const e of wasm.bindingSignatures) { @@ -9010,8 +9323,8 @@ var sqlite3InitModule = (() => { const fI64Disabled = function (fname) { return () => toss( - fname + "() is unavailable due to lack", - "of BigInt support in this build." + fname + '() is unavailable due to lack', + 'of BigInt support in this build.', ); }; for (const e of wasm.bindingSignatures.int64) { @@ -9024,11 +9337,11 @@ var sqlite3InitModule = (() => { if (wasm.exports.sqlite3__wasm_db_error) { const __db_err = wasm.xWrap( - "sqlite3__wasm_db_error", - "int", - "sqlite3*", - "int", - "string" + 'sqlite3__wasm_db_error', + 'int', + 'sqlite3*', + 'int', + 'string', ); util.sqlite3__wasm_db_error = function (pDb, resultCode, message) { @@ -9036,7 +9349,7 @@ var sqlite3InitModule = (() => { resultCode = capi.SQLITE_NOMEM; message = 0; } else if (resultCode instanceof Error) { - message = message || "" + resultCode; + message = message || '' + resultCode; resultCode = resultCode.resultCode || capi.SQLITE_ERROR; } return pDb ? __db_err(pDb, resultCode, message) : resultCode; @@ -9044,8 +9357,8 @@ var sqlite3InitModule = (() => { } else { util.sqlite3__wasm_db_error = function (pDb, errCode, msg) { console.warn( - "sqlite3__wasm_db_error() is not exported.", - arguments + 'sqlite3__wasm_db_error() is not exported.', + arguments, ); return errCode; }; @@ -9053,43 +9366,43 @@ var sqlite3InitModule = (() => { } { - const cJson = wasm.xCall("sqlite3__wasm_enum_json"); + const cJson = wasm.xCall('sqlite3__wasm_enum_json'); if (!cJson) { toss( "Maintenance required: increase sqlite3__wasm_enum_json()'s", - "static buffer size!" + 'static buffer size!', ); } wasm.ctype = JSON.parse(wasm.cstrToJs(cJson)); const defineGroups = [ - "access", - "authorizer", - "blobFinalizers", - "changeset", - "config", - "dataTypes", - "dbConfig", - "dbStatus", - "encodings", - "fcntl", - "flock", - "ioCap", - "limits", - "openFlags", - "prepareFlags", - "resultCodes", - "sqlite3Status", - "stmtStatus", - "syncFlags", - "trace", - "txnState", - "udfFlags", - "version", + 'access', + 'authorizer', + 'blobFinalizers', + 'changeset', + 'config', + 'dataTypes', + 'dbConfig', + 'dbStatus', + 'encodings', + 'fcntl', + 'flock', + 'ioCap', + 'limits', + 'openFlags', + 'prepareFlags', + 'resultCodes', + 'sqlite3Status', + 'stmtStatus', + 'syncFlags', + 'trace', + 'txnState', + 'udfFlags', + 'version', ]; if (wasm.bigIntEnabled) { - defineGroups.push("serialize", "session", "vtab"); + defineGroups.push('serialize', 'session', 'vtab'); } for (const t of defineGroups) { for (const e of Object.entries(wasm.ctype[t])) { @@ -9098,12 +9411,12 @@ var sqlite3InitModule = (() => { } if (!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)) { toss( - "Internal error: cannot resolve exported function", - "entry SQLITE_WASM_DEALLOC (==" + capi.SQLITE_WASM_DEALLOC + ")." + 'Internal error: cannot resolve exported function', + 'entry SQLITE_WASM_DEALLOC (==' + capi.SQLITE_WASM_DEALLOC + ').', ); } const __rcMap = Object.create(null); - for (const t of ["resultCodes"]) { + for (const t of ['resultCodes']) { for (const e of Object.entries(wasm.ctype[t])) { __rcMap[e[1]] = e[0]; } @@ -9128,17 +9441,17 @@ var sqlite3InitModule = (() => { } if (capi.sqlite3_index_info) { for (const k of [ - "sqlite3_index_constraint", - "sqlite3_index_orderby", - "sqlite3_index_constraint_usage", + 'sqlite3_index_constraint', + 'sqlite3_index_orderby', + 'sqlite3_index_constraint_usage', ]) { capi.sqlite3_index_info[k] = capi[k]; delete capi[k]; } capi.sqlite3_vtab_config = wasm.xWrap( - "sqlite3__wasm_vtab_config", - "int", - ["sqlite3*", "int", "int"] + 'sqlite3__wasm_vtab_config', + 'int', + ['sqlite3*', 'int', 'int'], ); } } @@ -9147,7 +9460,7 @@ var sqlite3InitModule = (() => { return util.sqlite3__wasm_db_error( pDb, capi.SQLITE_MISUSE, - f + "() requires " + n + " argument" + (1 === n ? "" : "s") + "." + f + '() requires ' + n + ' argument' + (1 === n ? '' : 's') + '.', ); }; @@ -9155,11 +9468,11 @@ var sqlite3InitModule = (() => { return util.sqlite3__wasm_db_error( pDb, capi.SQLITE_FORMAT, - "SQLITE_UTF8 is the only supported encoding." + 'SQLITE_UTF8 is the only supported encoding.', ); }; - const __argPDb = (pDb) => wasm.xWrap.argAdapter("sqlite3*")(pDb); + const __argPDb = (pDb) => wasm.xWrap.argAdapter('sqlite3*')(pDb); const __argStr = (str) => (wasm.isPtr(str) ? wasm.cstrToJs(str) : str); const __dbCleanupMap = function (pDb, mode) { pDb = __argPDb(pDb); @@ -9174,7 +9487,7 @@ var sqlite3InitModule = (() => { }.bind( Object.assign(Object.create(null), { dbMap: new Map(), - }) + }), ); __dbCleanupMap.addCollation = function (pDb, name) { @@ -9207,14 +9520,14 @@ var sqlite3InitModule = (() => { const closeArgs = [pDb]; for (const name of [ - "sqlite3_busy_handler", - "sqlite3_commit_hook", - "sqlite3_preupdate_hook", - "sqlite3_progress_handler", - "sqlite3_rollback_hook", - "sqlite3_set_authorizer", - "sqlite3_trace_v2", - "sqlite3_update_hook", + 'sqlite3_busy_handler', + 'sqlite3_commit_hook', + 'sqlite3_preupdate_hook', + 'sqlite3_progress_handler', + 'sqlite3_rollback_hook', + 'sqlite3_set_authorizer', + 'sqlite3_trace_v2', + 'sqlite3_update_hook', ]) { const x = wasm.exports[name]; closeArgs.length = x.length; @@ -9222,11 +9535,11 @@ var sqlite3InitModule = (() => { capi[name](...closeArgs); } catch (e) { console.warn( - "close-time call of", - name + "(", + 'close-time call of', + name + '(', closeArgs, - ") threw:", - e + ') threw:', + e, ); } } @@ -9241,7 +9554,7 @@ var sqlite3InitModule = (() => { capi.SQLITE_UTF8, 0, 0, - 0 + 0, ); } catch (e) {} } @@ -9275,13 +9588,13 @@ var sqlite3InitModule = (() => { { const __sqlite3CloseV2 = wasm.xWrap( - "sqlite3_close_v2", - "int", - "sqlite3*" + 'sqlite3_close_v2', + 'int', + 'sqlite3*', ); capi.sqlite3_close_v2 = function (pDb) { if (1 !== arguments.length) - return __dbArgcMismatch(pDb, "sqlite3_close_v2", 1); + return __dbArgcMismatch(pDb, 'sqlite3_close_v2', 1); if (pDb) { try { __dbCleanupMap.cleanup(pDb); @@ -9293,13 +9606,13 @@ var sqlite3InitModule = (() => { if (capi.sqlite3session_table_filter) { const __sqlite3SessionDelete = wasm.xWrap( - "sqlite3session_delete", + 'sqlite3session_delete', undefined, - ["sqlite3_session*"] + ['sqlite3_session*'], ); capi.sqlite3session_delete = function (pSession) { if (1 !== arguments.length) { - return __dbArgcMismatch(pDb, "sqlite3session_delete", 1); + return __dbArgcMismatch(pDb, 'sqlite3session_delete', 1); } else if (pSession) { capi.sqlite3session_table_filter(pSession, 0, 0); } @@ -9310,33 +9623,33 @@ var sqlite3InitModule = (() => { { const contextKey = (argv, argIndex) => { return ( - "argv[" + + 'argv[' + argIndex + - "]:" + + ']:' + argv[0] + - ":" + + ':' + wasm.cstrToJs(argv[1]).toLowerCase() ); }; const __sqlite3CreateCollationV2 = wasm.xWrap( - "sqlite3_create_collation_v2", - "int", + 'sqlite3_create_collation_v2', + 'int', [ - "sqlite3*", - "string", - "int", - "*", + 'sqlite3*', + 'string', + 'int', + '*', new wasm.xWrap.FuncPtrAdapter({ - name: "xCompare", - signature: "i(pipip)", + name: 'xCompare', + signature: 'i(pipip)', contextKey, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xDestroy", - signature: "v(p)", + name: 'xDestroy', + signature: 'v(p)', contextKey, }), - ] + ], ); capi.sqlite3_create_collation_v2 = function ( @@ -9345,10 +9658,10 @@ var sqlite3InitModule = (() => { eTextRep, pArg, xCompare, - xDestroy + xDestroy, ) { if (6 !== arguments.length) - return __dbArgcMismatch(pDb, "sqlite3_create_collation_v2", 6); + return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6); else if (0 === (eTextRep & 0xf)) { eTextRep |= capi.SQLITE_UTF8; } else if (capi.SQLITE_UTF8 !== (eTextRep & 0xf)) { @@ -9361,7 +9674,7 @@ var sqlite3InitModule = (() => { eTextRep, pArg, xCompare, - xDestroy + xDestroy, ); if (0 === rc && xCompare instanceof Function) { __dbCleanupMap.addCollation(pDb, zName); @@ -9377,7 +9690,7 @@ var sqlite3InitModule = (() => { zName, eTextRep, pArg, - xCompare + xCompare, ) => { return 5 === arguments.length ? capi.sqlite3_create_collation_v2( @@ -9386,9 +9699,9 @@ var sqlite3InitModule = (() => { eTextRep, pArg, xCompare, - 0 + 0, ) - : __dbArgcMismatch(pDb, "sqlite3_create_collation", 5); + : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5); }; } @@ -9396,18 +9709,18 @@ var sqlite3InitModule = (() => { const contextKey = function (argv, argIndex) { return ( argv[0] + - ":" + + ':' + (argv[2] < 0 ? -1 : argv[2]) + - ":" + + ':' + argIndex + - ":" + + ':' + wasm.cstrToJs(argv[1]).toLowerCase() ); }; const __cfProxy = Object.assign(Object.create(null), { xInverseAndStep: { - signature: "v(pip)", + signature: 'v(pip)', contextKey, callProxy: (callback) => { return (pCtx, argc, pArgv) => { @@ -9420,7 +9733,7 @@ var sqlite3InitModule = (() => { }, }, xFinalAndValue: { - signature: "v(p)", + signature: 'v(p)', contextKey, callProxy: (callback) => { return (pCtx) => { @@ -9433,14 +9746,14 @@ var sqlite3InitModule = (() => { }, }, xFunc: { - signature: "v(pip)", + signature: 'v(pip)', contextKey, callProxy: (callback) => { return (pCtx, argc, pArgv) => { try { capi.sqlite3_result_js( pCtx, - callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) + callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)), ); } catch (e) { capi.sqlite3_result_error_js(pCtx, e); @@ -9449,7 +9762,7 @@ var sqlite3InitModule = (() => { }, }, xDestroy: { - signature: "v(p)", + signature: 'v(p)', contextKey, callProxy: (callback) => { @@ -9457,7 +9770,7 @@ var sqlite3InitModule = (() => { try { callback(pVoid); } catch (e) { - console.error("UDF xDestroy method threw:", e); + console.error('UDF xDestroy method threw:', e); } }; }, @@ -9465,63 +9778,63 @@ var sqlite3InitModule = (() => { }); const __sqlite3CreateFunction = wasm.xWrap( - "sqlite3_create_function_v2", - "int", + 'sqlite3_create_function_v2', + 'int', [ - "sqlite3*", - "string", - "int", - "int", - "*", + 'sqlite3*', + 'string', + 'int', + 'int', + '*', new wasm.xWrap.FuncPtrAdapter({ - name: "xFunc", + name: 'xFunc', ...__cfProxy.xFunc, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xStep", + name: 'xStep', ...__cfProxy.xInverseAndStep, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xFinal", + name: 'xFinal', ...__cfProxy.xFinalAndValue, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xDestroy", + name: 'xDestroy', ...__cfProxy.xDestroy, }), - ] + ], ); const __sqlite3CreateWindowFunction = wasm.xWrap( - "sqlite3_create_window_function", - "int", + 'sqlite3_create_window_function', + 'int', [ - "sqlite3*", - "string", - "int", - "int", - "*", + 'sqlite3*', + 'string', + 'int', + 'int', + '*', new wasm.xWrap.FuncPtrAdapter({ - name: "xStep", + name: 'xStep', ...__cfProxy.xInverseAndStep, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xFinal", + name: 'xFinal', ...__cfProxy.xFinalAndValue, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xValue", + name: 'xValue', ...__cfProxy.xFinalAndValue, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xInverse", + name: 'xInverse', ...__cfProxy.xInverseAndStep, }), new wasm.xWrap.FuncPtrAdapter({ - name: "xDestroy", + name: 'xDestroy', ...__cfProxy.xDestroy, }), - ] + ], ); capi.sqlite3_create_function_v2 = function f( @@ -9533,13 +9846,13 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - xDestroy + xDestroy, ) { if (f.length !== arguments.length) { return __dbArgcMismatch( pDb, - "sqlite3_create_function_v2", - f.length + 'sqlite3_create_function_v2', + f.length, ); } else if (0 === (eTextRep & 0xf)) { eTextRep |= capi.SQLITE_UTF8; @@ -9556,7 +9869,7 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - xDestroy + xDestroy, ); if ( 0 === rc && @@ -9569,11 +9882,11 @@ var sqlite3InitModule = (() => { } return rc; } catch (e) { - console.error("sqlite3_create_function_v2() setup threw:", e); + console.error('sqlite3_create_function_v2() setup threw:', e); return util.sqlite3__wasm_db_error( pDb, e, - "Creation of UDF threw: " + e + 'Creation of UDF threw: ' + e, ); } }; @@ -9586,7 +9899,7 @@ var sqlite3InitModule = (() => { pApp, xFunc, xStep, - xFinal + xFinal, ) { return f.length === arguments.length ? capi.sqlite3_create_function_v2( @@ -9598,9 +9911,9 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - 0 + 0, ) - : __dbArgcMismatch(pDb, "sqlite3_create_function", f.length); + : __dbArgcMismatch(pDb, 'sqlite3_create_function', f.length); }; capi.sqlite3_create_window_function = function f( @@ -9613,13 +9926,13 @@ var sqlite3InitModule = (() => { xFinal, xValue, xInverse, - xDestroy + xDestroy, ) { if (f.length !== arguments.length) { return __dbArgcMismatch( pDb, - "sqlite3_create_window_function", - f.length + 'sqlite3_create_window_function', + f.length, ); } else if (0 === (eTextRep & 0xf)) { eTextRep |= capi.SQLITE_UTF8; @@ -9637,7 +9950,7 @@ var sqlite3InitModule = (() => { xFinal, xValue, xInverse, - xDestroy + xDestroy, ); if ( 0 === rc && @@ -9651,11 +9964,11 @@ var sqlite3InitModule = (() => { } return rc; } catch (e) { - console.error("sqlite3_create_window_function() setup threw:", e); + console.error('sqlite3_create_window_function() setup threw:', e); return util.sqlite3__wasm_db_error( pDb, e, - "Creation of UDF threw: " + e + 'Creation of UDF threw: ' + e, ); } }; @@ -9678,37 +9991,37 @@ var sqlite3InitModule = (() => { { const __flexiString = (v, n) => { - if ("string" === typeof v) { + if ('string' === typeof v) { n = -1; } else if (util.isSQLableTypedArray(v)) { n = v.byteLength; v = util.typedArrayToString( - v instanceof ArrayBuffer ? new Uint8Array(v) : v + v instanceof ArrayBuffer ? new Uint8Array(v) : v, ); } else if (Array.isArray(v)) { - v = v.join(""); + v = v.join(''); n = -1; } return [v, n]; }; const __prepare = { - basic: wasm.xWrap("sqlite3_prepare_v3", "int", [ - "sqlite3*", - "string", - "int", - "int", - "**", - "**", + basic: wasm.xWrap('sqlite3_prepare_v3', 'int', [ + 'sqlite3*', + 'string', + 'int', + 'int', + '**', + '**', ]), - full: wasm.xWrap("sqlite3_prepare_v3", "int", [ - "sqlite3*", - "*", - "int", - "int", - "**", - "**", + full: wasm.xWrap('sqlite3_prepare_v3', 'int', [ + 'sqlite3*', + '*', + 'int', + 'int', + '**', + '**', ]), }; @@ -9718,36 +10031,36 @@ var sqlite3InitModule = (() => { sqlLen, prepFlags, ppStmt, - pzTail + pzTail, ) { if (f.length !== arguments.length) { - return __dbArgcMismatch(pDb, "sqlite3_prepare_v3", f.length); + return __dbArgcMismatch(pDb, 'sqlite3_prepare_v3', f.length); } const [xSql, xSqlLen] = __flexiString(sql, sqlLen); switch (typeof xSql) { - case "string": + case 'string': return __prepare.basic( pDb, xSql, xSqlLen, prepFlags, ppStmt, - null + null, ); - case "number": + case 'number': return __prepare.full( pDb, xSql, xSqlLen, prepFlags, ppStmt, - pzTail + pzTail, ); default: return util.sqlite3__wasm_db_error( pDb, capi.SQLITE_MISUSE, - "Invalid SQL argument type for sqlite3_prepare_v2/v3()." + 'Invalid SQL argument type for sqlite3_prepare_v2/v3().', ); } }; @@ -9757,28 +10070,28 @@ var sqlite3InitModule = (() => { sql, sqlLen, ppStmt, - pzTail + pzTail, ) { return f.length === arguments.length ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) - : __dbArgcMismatch(pDb, "sqlite3_prepare_v2", f.length); + : __dbArgcMismatch(pDb, 'sqlite3_prepare_v2', f.length); }; } { - const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [ - "sqlite3_stmt*", - "int", - "string", - "int", - "*", + const __bindText = wasm.xWrap('sqlite3_bind_text', 'int', [ + 'sqlite3_stmt*', + 'int', + 'string', + 'int', + '*', ]); - const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [ - "sqlite3_stmt*", - "int", - "*", - "int", - "*", + const __bindBlob = wasm.xWrap('sqlite3_bind_blob', 'int', [ + 'sqlite3_stmt*', + 'int', + '*', + 'int', + '*', ]); capi.sqlite3_bind_text = function f( @@ -9786,33 +10099,33 @@ var sqlite3InitModule = (() => { iCol, text, nText, - xDestroy + xDestroy, ) { if (f.length !== arguments.length) { return __dbArgcMismatch( capi.sqlite3_db_handle(pStmt), - "sqlite3_bind_text", - f.length + 'sqlite3_bind_text', + f.length, ); } else if (wasm.isPtr(text) || null === text) { return __bindText(pStmt, iCol, text, nText, xDestroy); } else if (text instanceof ArrayBuffer) { text = new Uint8Array(text); } else if (Array.isArray(pMem)) { - text = pMem.join(""); + text = pMem.join(''); } let p, n; try { if (util.isSQLableTypedArray(text)) { p = wasm.allocFromTypedArray(text); n = text.byteLength; - } else if ("string" === typeof text) { + } else if ('string' === typeof text) { [p, n] = wasm.allocCString(text); } else { return util.sqlite3__wasm_db_error( capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE, - "Invalid 3rd argument type for sqlite3_bind_text()." + 'Invalid 3rd argument type for sqlite3_bind_text().', ); } return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); @@ -9820,7 +10133,7 @@ var sqlite3InitModule = (() => { wasm.dealloc(p); return util.sqlite3__wasm_db_error( capi.sqlite3_db_handle(pStmt), - e + e, ); } }; @@ -9830,33 +10143,33 @@ var sqlite3InitModule = (() => { iCol, pMem, nMem, - xDestroy + xDestroy, ) { if (f.length !== arguments.length) { return __dbArgcMismatch( capi.sqlite3_db_handle(pStmt), - "sqlite3_bind_blob", - f.length + 'sqlite3_bind_blob', + f.length, ); } else if (wasm.isPtr(pMem) || null === pMem) { return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy); } else if (pMem instanceof ArrayBuffer) { pMem = new Uint8Array(pMem); } else if (Array.isArray(pMem)) { - pMem = pMem.join(""); + pMem = pMem.join(''); } let p, n; try { if (util.isBindableTypedArray(pMem)) { p = wasm.allocFromTypedArray(pMem); n = nMem >= 0 ? nMem : pMem.byteLength; - } else if ("string" === typeof pMem) { + } else if ('string' === typeof pMem) { [p, n] = wasm.allocCString(pMem); } else { return util.sqlite3__wasm_db_error( capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE, - "Invalid 3rd argument type for sqlite3_bind_blob()." + 'Invalid 3rd argument type for sqlite3_bind_blob().', ); } return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); @@ -9864,7 +10177,7 @@ var sqlite3InitModule = (() => { wasm.dealloc(p); return util.sqlite3__wasm_db_error( capi.sqlite3_db_handle(pStmt), - e + e, ); } }; @@ -9885,7 +10198,7 @@ var sqlite3InitModule = (() => { return wasm.exports.sqlite3__wasm_config_ii( op, args[0], - args[1] + args[1], ); case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: return wasm.exports.sqlite3__wasm_config_j(op, args[0]); @@ -9919,7 +10232,7 @@ var sqlite3InitModule = (() => { capi.sqlite3_auto_extension = function (fPtr) { if (fPtr instanceof Function) { - fPtr = wasm.installFunction("i(ppp)", fPtr); + fPtr = wasm.installFunction('i(ppp)', fPtr); } else if (1 !== arguments.length || !wasm.isPtr(fPtr)) { return capi.SQLITE_MISUSE; } @@ -9943,11 +10256,11 @@ var sqlite3InitModule = (() => { }; } - const pKvvfs = capi.sqlite3_vfs_find("kvvfs"); + const pKvvfs = capi.sqlite3_vfs_find('kvvfs'); if (pKvvfs) { if (util.isUIThread()) { const kvvfsMethods = new capi.sqlite3_kvvfs_methods( - wasm.exports.sqlite3__wasm_kvvfs_methods() + wasm.exports.sqlite3__wasm_kvvfs_methods(), ); delete capi.sqlite3_kvvfs_methods; @@ -9980,7 +10293,7 @@ var sqlite3InitModule = (() => { wasm.poke(zBuf + nBuf - 1, 0); return nBuf - 1; } catch (e) { - console.error("kvstorageRead()", e); + console.error('kvstorageRead()', e); return -2; } finally { pstack.restore(stack); @@ -9996,7 +10309,7 @@ var sqlite3InitModule = (() => { kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData)); return 0; } catch (e) { - console.error("kvstorageWrite()", e); + console.error('kvstorageWrite()', e); return capi.SQLITE_IOERR; } finally { pstack.restore(stack); @@ -10010,7 +10323,7 @@ var sqlite3InitModule = (() => { kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey)); return 0; } catch (e) { - console.error("kvstorageDelete()", e); + console.error('kvstorageDelete()', e); return capi.SQLITE_IOERR; } finally { pstack.restore(stack); @@ -10020,7 +10333,7 @@ var sqlite3InitModule = (() => { for (const k of Object.keys(kvvfsImpls)) { kvvfsMethods[kvvfsMethods.memberKey(k)] = wasm.installFunction( kvvfsMethods.memberSignature(k), - kvvfsImpls[k] + kvvfsImpls[k], ); } } else { @@ -10035,12 +10348,12 @@ var sqlite3InitModule = (() => { tgt, name, func, - applyArgcCheck = callee.installMethodArgcCheck + applyArgcCheck = callee.installMethodArgcCheck, ) { if (!(tgt instanceof StructBinder.StructType)) { - toss("Usage error: target object is-not-a StructType."); + toss('Usage error: target object is-not-a StructType.'); } else if (!(func instanceof Function) && !wasm.isPtr(func)) { - toss("Usage errror: expecting a Function or WASM pointer to one."); + toss('Usage errror: expecting a Function or WASM pointer to one.'); } if (1 === arguments.length) { return (n, f) => callee(tgt, n, f, applyArgcCheck); @@ -10050,12 +10363,12 @@ var sqlite3InitModule = (() => { return function (...args) { if (func.length !== arguments.length) { toss( - "Argument mismatch for", + 'Argument mismatch for', tgt.structInfo.name + - "::" + + '::' + funcName + - ": Native signature is:", - sig + ': Native signature is:', + sig, ); } return func.apply(this, args); @@ -10065,7 +10378,7 @@ var sqlite3InitModule = (() => { callee.removeFuncList = function () { if (this.ondispose.__removeFuncList) { this.ondispose.__removeFuncList.forEach((v, ndx) => { - if ("number" === typeof v) { + if ('number' === typeof v) { try { wasm.uninstallFunction(v); } catch (e) {} @@ -10078,10 +10391,10 @@ var sqlite3InitModule = (() => { const sigN = tgt.memberSignature(name); if (sigN.length < 2) { toss( - "Member", + 'Member', name, - "does not have a function pointer signature:", - sigN + 'does not have a function pointer signature:', + sigN, ); } const memKey = tgt.memberKey(name); @@ -10091,19 +10404,19 @@ var sqlite3InitModule = (() => { : func; if (wasm.isPtr(fProxy)) { if (fProxy && !wasm.functionEntry(fProxy)) { - toss("Pointer", fProxy, "is not a WASM function table entry."); + toss('Pointer', fProxy, 'is not a WASM function table entry.'); } tgt[memKey] = fProxy; } else { const pFunc = wasm.installFunction( fProxy, - tgt.memberSignature(name, true) + tgt.memberSignature(name, true), ); tgt[memKey] = pFunc; if (!tgt.ondispose || !tgt.ondispose.__removeFuncList) { tgt.addOnDispose( - "ondispose.__removeFuncList handler", - callee.removeFuncList + 'ondispose.__removeFuncList handler', + callee.removeFuncList, ); tgt.ondispose.__removeFuncList = []; } @@ -10116,7 +10429,7 @@ var sqlite3InitModule = (() => { const installMethods = function ( structInstance, methods, - applyArgcCheck = installMethod.installMethodArgcCheck + applyArgcCheck = installMethod.installMethodArgcCheck, ) { const seen = new Map(); for (const k of Object.keys(methods)) { @@ -10137,16 +10450,16 @@ var sqlite3InitModule = (() => { StructBinder.StructType.prototype.installMethod = function callee( name, func, - applyArgcCheck = installMethod.installMethodArgcCheck + applyArgcCheck = installMethod.installMethodArgcCheck, ) { - return arguments.length < 3 && name && "object" === typeof name + return arguments.length < 3 && name && 'object' === typeof name ? installMethods(this, ...arguments) : installMethod(this, ...arguments); }; StructBinder.StructType.prototype.installMethods = function ( methods, - applyArgcCheck = installMethod.installMethodArgcCheck + applyArgcCheck = installMethod.installMethodArgcCheck, ) { return installMethods(this, methods, applyArgcCheck); }; @@ -10154,10 +10467,10 @@ var sqlite3InitModule = (() => { globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) { sqlite3.version = { - libVersion: "3.46.1", + libVersion: '3.46.1', libVersionNumber: 3046001, sourceId: - "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33", + '2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33', downloadVersion: 3460100, }; }); @@ -10185,26 +10498,26 @@ var sqlite3InitModule = (() => { if (dbPtr instanceof DB) dbPtr = dbPtr.pointer; toss3( sqliteResultCode, - "sqlite3 result code", - sqliteResultCode + ":", + 'sqlite3 result code', + sqliteResultCode + ':', dbPtr ? capi.sqlite3_errmsg(dbPtr) - : capi.sqlite3_errstr(sqliteResultCode) + : capi.sqlite3_errstr(sqliteResultCode), ); } return arguments[0]; }; const __dbTraceToConsole = wasm.installFunction( - "i(ippp)", + 'i(ippp)', function (t, c, p, x) { if (capi.SQLITE_TRACE_STMT === t) { console.log( - "SQL TRACE #" + ++this.counter + " via sqlite3@" + c + ":", - wasm.cstrToJs(x) + 'SQL TRACE #' + ++this.counter + ' via sqlite3@' + c + ':', + wasm.cstrToJs(x), ); } - }.bind({ counter: 0 }) + }.bind({ counter: 0 }), ); const __vfsPostOpenSql = Object.create(null); @@ -10213,21 +10526,21 @@ var sqlite3InitModule = (() => { if (!ctor._name2vfs) { ctor._name2vfs = Object.create(null); const isWorkerThread = - "function" === typeof importScripts + 'function' === typeof importScripts ? (n) => toss3( - "The VFS for", + 'The VFS for', n, - "is only available in the main window thread." + 'is only available in the main window thread.', ) : false; - ctor._name2vfs[":localStorage:"] = { - vfs: "kvvfs", - filename: isWorkerThread || (() => "local"), + ctor._name2vfs[':localStorage:'] = { + vfs: 'kvvfs', + filename: isWorkerThread || (() => 'local'), }; - ctor._name2vfs[":sessionStorage:"] = { - vfs: "kvvfs", - filename: isWorkerThread || (() => "session"), + ctor._name2vfs[':sessionStorage:'] = { + vfs: 'kvvfs', + filename: isWorkerThread || (() => 'session'), }; } const opt = ctor.normalizeArgs(...args); @@ -10235,16 +10548,16 @@ var sqlite3InitModule = (() => { vfsName = opt.vfs, flagsStr = opt.flags; if ( - ("string" !== typeof fn && "number" !== typeof fn) || - "string" !== typeof flagsStr || + ('string' !== typeof fn && 'number' !== typeof fn) || + 'string' !== typeof flagsStr || (vfsName && - "string" !== typeof vfsName && - "number" !== typeof vfsName) + 'string' !== typeof vfsName && + 'number' !== typeof vfsName) ) { - sqlite3.config.error("Invalid DB ctor args", opt, arguments); - toss3("Invalid arguments for DB constructor."); + sqlite3.config.error('Invalid DB ctor args', opt, arguments); + toss3('Invalid arguments for DB constructor.'); } - let fnJs = "number" === typeof fn ? wasm.cstrToJs(fn) : fn; + let fnJs = 'number' === typeof fn ? wasm.cstrToJs(fn) : fn; const vfsCheck = ctor._name2vfs[fnJs]; if (vfsCheck) { vfsName = vfsCheck.vfs; @@ -10252,10 +10565,10 @@ var sqlite3InitModule = (() => { } let pDb, oflags = 0; - if (flagsStr.indexOf("c") >= 0) { + if (flagsStr.indexOf('c') >= 0) { oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; } - if (flagsStr.indexOf("w") >= 0) oflags |= capi.SQLITE_OPEN_READWRITE; + if (flagsStr.indexOf('w') >= 0) oflags |= capi.SQLITE_OPEN_READWRITE; if (0 === oflags) oflags |= capi.SQLITE_OPEN_READONLY; oflags |= capi.SQLITE_OPEN_EXRESCODE; const stack = wasm.pstack.pointer; @@ -10265,12 +10578,12 @@ var sqlite3InitModule = (() => { pDb = wasm.peekPtr(pPtr); checkSqlite3Rc(pDb, rc); capi.sqlite3_extended_result_codes(pDb, 1); - if (flagsStr.indexOf("t") >= 0) { + if (flagsStr.indexOf('t') >= 0) { capi.sqlite3_trace_v2( pDb, capi.SQLITE_TRACE_STMT, __dbTraceToConsole, - pDb + pDb, ); } } catch (e) { @@ -10285,7 +10598,7 @@ var sqlite3InitModule = (() => { try { const pVfs = capi.sqlite3_js_db_vfs(pDb) || - toss3("Internal error: cannot get VFS for new db handle."); + toss3('Internal error: cannot get VFS for new db handle.'); const postInitSql = __vfsPostOpenSql[pVfs]; if (postInitSql) { if (postInitSql instanceof Function) { @@ -10293,7 +10606,7 @@ var sqlite3InitModule = (() => { } else { checkSqlite3Rc( pDb, - capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0) + capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0), ); } } @@ -10308,20 +10621,20 @@ var sqlite3InitModule = (() => { }; dbCtorHelper.normalizeArgs = function ( - filename = ":memory:", - flags = "c", - vfs = null + filename = ':memory:', + flags = 'c', + vfs = null, ) { const arg = {}; if ( 1 === arguments.length && arguments[0] && - "object" === typeof arguments[0] + 'object' === typeof arguments[0] ) { Object.assign(arg, arguments[0]); - if (undefined === arg.flags) arg.flags = "c"; + if (undefined === arg.flags) arg.flags = 'c'; if (undefined === arg.vfs) arg.vfs = null; - if (undefined === arg.filename) arg.filename = ":memory:"; + if (undefined === arg.filename) arg.filename = ':memory:'; } else { arg.filename = filename; arg.flags = flags; @@ -10342,7 +10655,7 @@ var sqlite3InitModule = (() => { boolean: 4, blob: 5, }; - BindTypes["undefined"] == BindTypes.null; + BindTypes['undefined'] == BindTypes.null; if (wasm.bigIntEnabled) { BindTypes.bigint = BindTypes.number; } @@ -10351,7 +10664,7 @@ var sqlite3InitModule = (() => { if (BindTypes !== arguments[2]) { toss3( capi.SQLITE_MISUSE, - "Do not call the Stmt constructor directly. Use DB.prepare()." + 'Do not call the Stmt constructor directly. Use DB.prepare().', ); } this.db = arguments[0]; @@ -10360,13 +10673,13 @@ var sqlite3InitModule = (() => { }; const affirmDbOpen = function (db) { - if (!db.pointer) toss3("DB has been closed."); + if (!db.pointer) toss3('DB has been closed.'); return db; }; const affirmColIndex = function (stmt, ndx) { if (ndx !== (ndx | 0) || ndx < 0 || ndx >= stmt.columnCount) { - toss3("Column index", ndx, "is out of range."); + toss3('Column index', ndx, 'is out of range.'); } return stmt; }; @@ -10377,13 +10690,13 @@ var sqlite3InitModule = (() => { switch (args.length) { case 1: if ( - "string" === typeof args[0] || + 'string' === typeof args[0] || util.isSQLableTypedArray(args[0]) ) { out.sql = args[0]; } else if (Array.isArray(args[0])) { out.sql = args[0]; - } else if (args[0] && "object" === typeof args[0]) { + } else if (args[0] && 'object' === typeof args[0]) { out.opt = args[0]; out.sql = out.opt.sql; } @@ -10393,36 +10706,36 @@ var sqlite3InitModule = (() => { out.opt = args[1]; break; default: - toss3("Invalid argument count for exec()."); + toss3('Invalid argument count for exec().'); } out.sql = util.flexibleString(out.sql); - if ("string" !== typeof out.sql) { - toss3("Missing SQL argument or unsupported SQL value type."); + if ('string' !== typeof out.sql) { + toss3('Missing SQL argument or unsupported SQL value type.'); } const opt = out.opt; switch (opt.returnValue) { - case "resultRows": + case 'resultRows': if (!opt.resultRows) opt.resultRows = []; out.returnVal = () => opt.resultRows; break; - case "saveSql": + case 'saveSql': if (!opt.saveSql) opt.saveSql = []; out.returnVal = () => opt.saveSql; break; case undefined: - case "this": + case 'this': out.returnVal = () => db; break; default: - toss3("Invalid returnValue value:", opt.returnValue); + toss3('Invalid returnValue value:', opt.returnValue); } if (!opt.callback && !opt.returnValue && undefined !== opt.rowMode) { if (!opt.resultRows) opt.resultRows = []; out.returnVal = () => opt.resultRows; } if (opt.callback || opt.resultRows) { - switch (undefined === opt.rowMode ? "array" : opt.rowMode) { - case "object": + switch (undefined === opt.rowMode ? 'array' : opt.rowMode) { + case 'object': out.cbArg = (stmt, cache) => { if (!cache.columnNames) cache.columnNames = stmt.getColumnNames([]); @@ -10434,15 +10747,15 @@ var sqlite3InitModule = (() => { return rv; }; break; - case "array": + case 'array': out.cbArg = (stmt) => stmt.get([]); break; - case "stmt": + case 'stmt': if (Array.isArray(opt.resultRows)) { toss3( - "exec(): invalid rowMode for a resultRows array: must", + 'exec(): invalid rowMode for a resultRows array: must', "be one of 'array', 'object',", - "a result column number, or column name reference." + 'a result column number, or column name reference.', ); } out.cbArg = (stmt) => stmt; @@ -10452,9 +10765,9 @@ var sqlite3InitModule = (() => { out.cbArg = (stmt) => stmt.get(opt.rowMode); break; } else if ( - "string" === typeof opt.rowMode && + 'string' === typeof opt.rowMode && opt.rowMode.length > 1 && - "$" === opt.rowMode[0] + '$' === opt.rowMode[0] ) { const $colName = opt.rowMode.substr(1); out.cbArg = (stmt) => { @@ -10462,14 +10775,14 @@ var sqlite3InitModule = (() => { return undefined === rc ? toss3( capi.SQLITE_NOTFOUND, - "exec(): unknown result column:", - $colName + 'exec(): unknown result column:', + $colName, ) : rc; }; break; } - toss3("Invalid rowMode:", opt.rowMode); + toss3('Invalid rowMode:', opt.rowMode); } } return out; @@ -10493,7 +10806,7 @@ var sqlite3InitModule = (() => { sql, bind, rowMode, - returnValue: "resultRows", + returnValue: 'resultRows', }); DB.checkRc = (db, resultCode) => checkSqlite3Rc(db, resultCode); @@ -10547,7 +10860,7 @@ var sqlite3InitModule = (() => { } }, - dbFilename: function (dbName = "main") { + dbFilename: function (dbName = 'main') { return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName); }, @@ -10559,7 +10872,7 @@ var sqlite3InitModule = (() => { let rc; const pVfs = capi.sqlite3_js_db_vfs( affirmDbOpen(this).pointer, - dbName + dbName, ); if (pVfs) { const v = new capi.sqlite3_vfs(pVfs); @@ -10580,13 +10893,13 @@ var sqlite3InitModule = (() => { ppStmt = wasm.pstack.alloc(8); DB.checkRc( this, - capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null) + capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null), ); pStmt = wasm.peekPtr(ppStmt); } finally { wasm.pstack.restore(stack); } - if (!pStmt) toss3("Cannot prepare empty SQL."); + if (!pStmt) toss3('Cannot prepare empty SQL.'); const stmt = new Stmt(this, pStmt, BindTypes); __stmtMap.get(this)[pStmt] = stmt; return stmt; @@ -10596,7 +10909,7 @@ var sqlite3InitModule = (() => { affirmDbOpen(this); const arg = parseExecArgs(this, arguments); if (!arg.sql) { - return toss3("exec() requires an SQL string."); + return toss3('exec() requires an SQL string.'); } const opt = arg.opt; const callback = opt.callback; @@ -10620,7 +10933,7 @@ var sqlite3InitModule = (() => { ? arg.sql.byteLength : wasm.jstrlen(arg.sql); const ppStmt = wasm.scopedAlloc( - 2 * wasm.ptrSizeof + (sqlByteLen + 1) + 2 * wasm.ptrSizeof + (sqlByteLen + 1), ); const pzTail = ppStmt + wasm.ptrSizeof; let pSql = pzTail + wasm.ptrSizeof; @@ -10628,7 +10941,7 @@ var sqlite3InitModule = (() => { if (isTA) wasm.heap8().set(arg.sql, pSql); else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false); wasm.poke(pSql + sqlByteLen, 0); - while (pSql && wasm.peek(pSql, "i8")) { + while (pSql && wasm.peek(pSql, 'i8')) { wasm.pokePtr([ppStmt, pzTail], 0); DB.checkRc( this, @@ -10638,8 +10951,8 @@ var sqlite3InitModule = (() => { sqlByteLen, 0, ppStmt, - pzTail - ) + pzTail, + ), ); const pStmt = wasm.peekPtr(ppStmt); pSql = wasm.peekPtr(pzTail); @@ -10659,7 +10972,7 @@ var sqlite3InitModule = (() => { for (; stmt.step(); stmt._lockedByExec = false) { if (0 === gotColNames++) { stmt.getColumnNames( - (cbArgCache.columnNames = opt.columnNames || []) + (cbArgCache.columnNames = opt.columnNames || []), ); } stmt._lockedByExec = true; @@ -10706,8 +11019,8 @@ var sqlite3InitModule = (() => { break; } if (!opt) opt = {}; - if ("string" !== typeof name) { - toss3("Invalid arguments: missing function name."); + if ('string' !== typeof name) { + toss3('Invalid arguments: missing function name.'); } let xStep = opt.xStep || 0; let xFinal = opt.xFinal || 0; @@ -10717,62 +11030,62 @@ var sqlite3InitModule = (() => { if (isFunc(xFunc)) { isWindow = false; if (isFunc(xStep) || isFunc(xFinal)) { - toss3("Ambiguous arguments: scalar or aggregate?"); + toss3('Ambiguous arguments: scalar or aggregate?'); } xStep = xFinal = null; } else if (isFunc(xStep)) { if (!isFunc(xFinal)) { - toss3("Missing xFinal() callback for aggregate or window UDF."); + toss3('Missing xFinal() callback for aggregate or window UDF.'); } xFunc = null; } else if (isFunc(xFinal)) { - toss3("Missing xStep() callback for aggregate or window UDF."); + toss3('Missing xStep() callback for aggregate or window UDF.'); } else { - toss3("Missing function-type properties."); + toss3('Missing function-type properties.'); } if (false === isWindow) { if (isFunc(xValue) || isFunc(xInverse)) { toss3( - "xValue and xInverse are not permitted for non-window UDFs." + 'xValue and xInverse are not permitted for non-window UDFs.', ); } } else if (isFunc(xValue)) { if (!isFunc(xInverse)) { - toss3("xInverse must be provided if xValue is."); + toss3('xInverse must be provided if xValue is.'); } isWindow = true; } else if (isFunc(xInverse)) { - toss3("xValue must be provided if xInverse is."); + toss3('xValue must be provided if xInverse is.'); } const pApp = opt.pApp; if ( undefined !== pApp && null !== pApp && - ("number" !== typeof pApp || !util.isInt32(pApp)) + ('number' !== typeof pApp || !util.isInt32(pApp)) ) { toss3( - "Invalid value for pApp property. Must be a legal WASM pointer value." + 'Invalid value for pApp property. Must be a legal WASM pointer value.', ); } const xDestroy = opt.xDestroy || 0; if (xDestroy && !isFunc(xDestroy)) { - toss3("xDestroy property must be a function."); + toss3('xDestroy property must be a function.'); } let fFlags = 0; - if (getOwnOption(opt, "deterministic")) + if (getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC; - if (getOwnOption(opt, "directOnly")) + if (getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY; - if (getOwnOption(opt, "innocuous")) fFlags |= capi.SQLITE_INNOCUOUS; + if (getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS; name = name.toLowerCase(); const xArity = xFunc || xStep; - const arity = getOwnOption(opt, "arity"); + const arity = getOwnOption(opt, 'arity'); const arityArg = - "number" === typeof arity + 'number' === typeof arity ? arity : xArity.length - ? xArity.length - 1 - : 0; + ? xArity.length - 1 + : 0; let rc; if (isWindow) { rc = capi.sqlite3_create_window_function( @@ -10785,7 +11098,7 @@ var sqlite3InitModule = (() => { xFinal, xValue, xInverse, - xDestroy + xDestroy, ); } else { rc = capi.sqlite3_create_function_v2( @@ -10797,7 +11110,7 @@ var sqlite3InitModule = (() => { xFunc, xStep, xFinal, - xDestroy + xDestroy, ); } DB.checkRc(this, rc); @@ -10830,11 +11143,11 @@ var sqlite3InitModule = (() => { }, selectArrays: function (sql, bind) { - return __selectAll(this, sql, bind, "array"); + return __selectAll(this, sql, bind, 'array'); }, selectObjects: function (sql, bind) { - return __selectAll(this, sql, bind, "object"); + return __selectAll(this, sql, bind, 'object'); }, openStatementCount: function () { @@ -10842,36 +11155,36 @@ var sqlite3InitModule = (() => { }, transaction: function (callback) { - let opener = "BEGIN"; + let opener = 'BEGIN'; if (arguments.length > 1) { if (/[^a-zA-Z]/.test(arguments[0])) { toss3( capi.SQLITE_MISUSE, - "Invalid argument for BEGIN qualifier." + 'Invalid argument for BEGIN qualifier.', ); } - opener += " " + arguments[0]; + opener += ' ' + arguments[0]; callback = arguments[1]; } affirmDbOpen(this).exec(opener); try { const rc = callback(this); - this.exec("COMMIT"); + this.exec('COMMIT'); return rc; } catch (e) { - this.exec("ROLLBACK"); + this.exec('ROLLBACK'); throw e; } }, savepoint: function (callback) { - affirmDbOpen(this).exec("SAVEPOINT oo1"); + affirmDbOpen(this).exec('SAVEPOINT oo1'); try { const rc = callback(this); - this.exec("RELEASE oo1"); + this.exec('RELEASE oo1'); return rc; } catch (e) { - this.exec("ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1"); + this.exec('ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1'); throw e; } }, @@ -10882,12 +11195,12 @@ var sqlite3InitModule = (() => { }; const affirmStmtOpen = function (stmt) { - if (!stmt.pointer) toss3("Stmt has been closed."); + if (!stmt.pointer) toss3('Stmt has been closed.'); return stmt; }; const isSupportedBindType = function (v) { - let t = BindTypes[null === v || undefined === v ? "null" : typeof v]; + let t = BindTypes[null === v || undefined === v ? 'null' : typeof v]; switch (t) { case BindTypes.boolean: case BindTypes.null: @@ -10905,39 +11218,39 @@ var sqlite3InitModule = (() => { const affirmSupportedBindType = function (v) { return ( isSupportedBindType(v) || - toss3("Unsupported bind() argument type:", typeof v) + toss3('Unsupported bind() argument type:', typeof v) ); }; const affirmParamIndex = function (stmt, key) { const n = - "number" === typeof key + 'number' === typeof key ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key); if (0 === n || !util.isInt32(n)) { - toss3("Invalid bind() parameter name: " + key); + toss3('Invalid bind() parameter name: ' + key); } else if (n < 1 || n > stmt.parameterCount) - toss3("Bind index", key, "is out of range."); + toss3('Bind index', key, 'is out of range.'); return n; }; const affirmNotLockedByExec = function (stmt, currentOpName) { if (stmt._lockedByExec) { toss3( - "Operation is illegal when statement is locked:", - currentOpName + 'Operation is illegal when statement is locked:', + currentOpName, ); } return stmt; }; const bindOne = function f(stmt, ndx, bindType, val) { - affirmNotLockedByExec(affirmStmtOpen(stmt), "bind()"); + affirmNotLockedByExec(affirmStmtOpen(stmt), 'bind()'); if (!f._) { f._tooBigInt = (v) => toss3( - "BigInt value is too big to store without precision loss:", - v + 'BigInt value is too big to store without precision loss:', + v, ); f._ = { string: function (stmt, ndx, val, asBlob) { @@ -10964,7 +11277,7 @@ var sqlite3InitModule = (() => { case BindTypes.number: { let m; if (util.isInt32(val)) m = capi.sqlite3_bind_int; - else if ("bigint" === typeof val) { + else if ('bigint' === typeof val) { if (!util.bigIntFits64(val)) { f._tooBigInt(val); } else if (wasm.bigIntEnabled) { @@ -10990,15 +11303,15 @@ var sqlite3InitModule = (() => { rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0); break; case BindTypes.blob: { - if ("string" === typeof val) { + if ('string' === typeof val) { rc = f._.string(stmt, ndx, val, true); break; } else if (val instanceof ArrayBuffer) { val = new Uint8Array(val); } else if (!util.isBindableTypedArray(val)) { toss3( - "Binding a value as a blob requires", - "that it be a string, Uint8Array, Int8Array, or ArrayBuffer." + 'Binding a value as a blob requires', + 'that it be a string, Uint8Array, Int8Array, or ArrayBuffer.', ); } const pBlob = wasm.alloc(val.byteLength || 1); @@ -11008,13 +11321,13 @@ var sqlite3InitModule = (() => { ndx, pBlob, val.byteLength, - capi.SQLITE_WASM_DEALLOC + capi.SQLITE_WASM_DEALLOC, ); break; } default: - sqlite3.config.warn("Unsupported bind() argument type:", val); - toss3("Unsupported bind() argument type: " + typeof val); + sqlite3.config.warn('Unsupported bind() argument type:', val); + toss3('Unsupported bind() argument type: ' + typeof val); } if (rc) DB.checkRc(stmt.db.pointer, rc); stmt._mayGet = false; @@ -11024,7 +11337,7 @@ var sqlite3InitModule = (() => { Stmt.prototype = { finalize: function () { if (this.pointer) { - affirmNotLockedByExec(this, "finalize()"); + affirmNotLockedByExec(this, 'finalize()'); const rc = capi.sqlite3_finalize(this.pointer); delete __stmtMap.get(this.db)[this.pointer]; __ptrMap.delete(this); @@ -11037,14 +11350,14 @@ var sqlite3InitModule = (() => { }, clearBindings: function () { - affirmNotLockedByExec(affirmStmtOpen(this), "clearBindings()"); + affirmNotLockedByExec(affirmStmtOpen(this), 'clearBindings()'); capi.sqlite3_clear_bindings(this.pointer); this._mayGet = false; return this; }, reset: function (alsoClearBinds) { - affirmNotLockedByExec(this, "reset()"); + affirmNotLockedByExec(this, 'reset()'); if (alsoClearBinds) this.clearBindings(); const rc = capi.sqlite3_reset(affirmStmtOpen(this).pointer); this._mayGet = false; @@ -11065,12 +11378,12 @@ var sqlite3InitModule = (() => { arg = arguments[1]; break; default: - toss3("Invalid bind() arguments."); + toss3('Invalid bind() arguments.'); } if (undefined === arg) { return this; } else if (!this.parameterCount) { - toss3("This statement has no bindable parameters."); + toss3('This statement has no bindable parameters.'); } this._mayGet = false; if (null === arg) { @@ -11078,24 +11391,24 @@ var sqlite3InitModule = (() => { } else if (Array.isArray(arg)) { if (1 !== arguments.length) { toss3( - "When binding an array, an index argument is not permitted." + 'When binding an array, an index argument is not permitted.', ); } arg.forEach((v, i) => - bindOne(this, i + 1, affirmSupportedBindType(v), v) + bindOne(this, i + 1, affirmSupportedBindType(v), v), ); return this; } else if (arg instanceof ArrayBuffer) { arg = new Uint8Array(arg); } - if ("object" === typeof arg && !util.isBindableTypedArray(arg)) { + if ('object' === typeof arg && !util.isBindableTypedArray(arg)) { if (1 !== arguments.length) { toss3( - "When binding an object, an index argument is not permitted." + 'When binding an object, an index argument is not permitted.', ); } Object.keys(arg).forEach((k) => - bindOne(this, k, affirmSupportedBindType(arg[k]), arg[k]) + bindOne(this, k, affirmSupportedBindType(arg[k]), arg[k]), ); return this; } else { @@ -11115,13 +11428,13 @@ var sqlite3InitModule = (() => { BindTypes.blob !== t && BindTypes.null !== t ) { - toss3("Invalid value type for bindAsBlob()"); + toss3('Invalid value type for bindAsBlob()'); } return bindOne(this, ndx, BindTypes.blob, arg); }, step: function () { - affirmNotLockedByExec(this, "step()"); + affirmNotLockedByExec(this, 'step()'); const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer); switch (rc) { case capi.SQLITE_DONE: @@ -11131,11 +11444,11 @@ var sqlite3InitModule = (() => { default: this._mayGet = false; sqlite3.config.warn( - "sqlite3_step() rc=", + 'sqlite3_step() rc=', rc, capi.sqlite3_js_rc_str(rc), - "SQL =", - capi.sqlite3_sql(this.pointer) + 'SQL =', + capi.sqlite3_sql(this.pointer), ); DB.checkRc(this.db.pointer, rc); } @@ -11160,7 +11473,7 @@ var sqlite3InitModule = (() => { get: function (ndx, asType) { if (!affirmStmtOpen(this)._mayGet) { - toss3("Stmt.step() has not (recently) returned true."); + toss3('Stmt.step() has not (recently) returned true.'); } if (Array.isArray(ndx)) { let i = 0; @@ -11169,7 +11482,7 @@ var sqlite3InitModule = (() => { ndx[i] = this.get(i++); } return ndx; - } else if (ndx && "object" === typeof ndx) { + } else if (ndx && 'object' === typeof ndx) { let i = 0; const n = this.columnCount; while (i < n) { @@ -11202,7 +11515,7 @@ var sqlite3InitModule = (() => { rc < Number.MIN_SAFE_INTEGER ) { toss3( - "Integer is out of range for JS integer range: " + rc + 'Integer is out of range for JS integer range: ' + rc, ); } @@ -11228,10 +11541,10 @@ var sqlite3InitModule = (() => { default: toss3( "Don't know how to translate", - "type of result column #" + ndx + "." + 'type of result column #' + ndx + '.', ); } - toss3("Not reached."); + toss3('Not reached.'); }, getInt: function (ndx) { @@ -11258,7 +11571,7 @@ var sqlite3InitModule = (() => { getColumnName: function (ndx) { return capi.sqlite3_column_name( affirmColIndex(affirmStmtOpen(this), ndx).pointer, - ndx + ndx, ); }, @@ -11284,18 +11597,18 @@ var sqlite3InitModule = (() => { get: function () { return __ptrMap.get(this); }, - set: () => toss3("The pointer property is read-only."), + set: () => toss3('The pointer property is read-only.'), }; - Object.defineProperty(Stmt.prototype, "pointer", prop); - Object.defineProperty(DB.prototype, "pointer", prop); + Object.defineProperty(Stmt.prototype, 'pointer', prop); + Object.defineProperty(DB.prototype, 'pointer', prop); } - Object.defineProperty(Stmt.prototype, "columnCount", { + Object.defineProperty(Stmt.prototype, 'columnCount', { enumerable: false, get: function () { return capi.sqlite3_column_count(this.pointer); }, - set: () => toss3("The columnCount property is read-only."), + set: () => toss3('The columnCount property is read-only.'), }); sqlite3.oo1 = { @@ -11304,13 +11617,13 @@ var sqlite3InitModule = (() => { }; if (util.isUIThread()) { - sqlite3.oo1.JsStorageDb = function (storageName = "session") { + sqlite3.oo1.JsStorageDb = function (storageName = 'session') { const opt = dbCtorHelper.normalizeArgs(...arguments); storageName = opt.filename; - if ("session" !== storageName && "local" !== storageName) { + if ('session' !== storageName && 'local' !== storageName) { toss3("JsStorageDb db name must be one of 'session' or 'local'."); } - opt.vfs = "kvvfs"; + opt.vfs = 'kvvfs'; dbCtorHelper.call(this, opt); }; const jdb = sqlite3.oo1.JsStorageDb; @@ -11334,18 +11647,18 @@ var sqlite3InitModule = (() => { const util = sqlite3.util; sqlite3.initWorker1API = function () { const toss = (...args) => { - throw new Error(args.join(" ")); + throw new Error(args.join(' ')); }; if (!(globalThis.WorkerGlobalScope instanceof Function)) { - toss("initWorker1API() must be run from a Worker thread."); + toss('initWorker1API() must be run from a Worker thread.'); } - const sqlite3 = this.sqlite3 || toss("Missing this.sqlite3 object."); + const sqlite3 = this.sqlite3 || toss('Missing this.sqlite3 object.'); const DB = sqlite3.oo1.DB; const getDbId = function (db) { let id = wState.idMap.get(db); if (id) return id; - id = "db#" + ++wState.idSeq + "@" + db.pointer; + id = 'db#' + ++wState.idSeq + '@' + db.pointer; wState.idMap.set(db, id); return id; @@ -11393,13 +11706,13 @@ var sqlite3InitModule = (() => { getDb: function (id, require = true) { return ( this.dbs[id] || - (require ? toss("Unknown (or closed) DB ID:", id) : undefined) + (require ? toss('Unknown (or closed) DB ID:', id) : undefined) ); }, }; const affirmDbOpen = function (db = wState.dbList[0]) { - return db && db.pointer ? db : toss("DB is not opened."); + return db && db.pointer ? db : toss('DB is not opened.'); }; const getMsgDb = function (msgData, affirmExists = true) { @@ -11416,16 +11729,16 @@ var sqlite3InitModule = (() => { const oargs = Object.create(null), args = ev.args || Object.create(null); if (args.simulateError) { - toss("Throwing because of simulateError flag."); + toss('Throwing because of simulateError flag.'); } const rc = Object.create(null); oargs.vfs = args.vfs; - oargs.filename = args.filename || ""; + oargs.filename = args.filename || ''; const db = wState.open(oargs); rc.filename = db.filename; rc.persistent = !!sqlite3.capi.sqlite3_js_db_uses_vfs( db.pointer, - "opfs" + 'opfs', ); rc.dbId = getDbId(db); rc.vfs = db.dbVfsName(); @@ -11439,7 +11752,7 @@ var sqlite3InitModule = (() => { }; if (db) { const doUnlink = - ev.args && "object" === typeof ev.args + ev.args && 'object' === typeof ev.args ? !!ev.args.unlink : false; wState.close(db, doUnlink); @@ -11449,13 +11762,13 @@ var sqlite3InitModule = (() => { exec: function (ev) { const rc = - "string" === typeof ev.args + 'string' === typeof ev.args ? { sql: ev.args } : ev.args || Object.create(null); - if ("stmt" === rc.rowMode) { + if ('stmt' === rc.rowMode) { toss( "Invalid rowMode for 'exec': stmt mode", - "does not work in the Worker API." + 'does not work in the Worker API.', ); } else if (!rc.sql) { toss("'exec' requires input SQL."); @@ -11467,7 +11780,7 @@ var sqlite3InitModule = (() => { const theCallback = rc.callback; let rowNumber = 0; const hadColNames = !!rc.columnNames; - if ("string" === typeof theCallback) { + if ('string' === typeof theCallback) { if (!hadColNames) rc.columnNames = []; rc.callback = function (row, stmt) { @@ -11478,7 +11791,7 @@ var sqlite3InitModule = (() => { rowNumber: ++rowNumber, row: row, }, - wState.xfer + wState.xfer, ); }; } @@ -11508,10 +11821,10 @@ var sqlite3InitModule = (() => { return rc; }, - "config-get": function () { + 'config-get': function () { const rc = Object.create(null), src = sqlite3.config; - ["bigIntEnabled"].forEach(function (k) { + ['bigIntEnabled'].forEach(function (k) { if (Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k]; }); rc.version = sqlite3.version; @@ -11525,18 +11838,18 @@ var sqlite3InitModule = (() => { const response = { byteArray: sqlite3.capi.sqlite3_js_db_export(db.pointer), filename: db.filename, - mimetype: "application/x-sqlite3", + mimetype: 'application/x-sqlite3', }; wState.xfer.push(response.byteArray.buffer); return response; }, toss: function (ev) { - toss("Testing worker exception"); + toss('Testing worker exception'); }, - "opfs-tree": async function (ev) { - if (!sqlite3.opfs) toss("OPFS support is unavailable."); + 'opfs-tree': async function (ev) { + if (!sqlite3.opfs) toss('OPFS support is unavailable.'); const response = await sqlite3.opfs.treeList(); return response; }, @@ -11555,10 +11868,10 @@ var sqlite3InitModule = (() => { ) { result = await wMsgHandler[evType](ev); } else { - toss("Unknown db worker message type:", ev.type); + toss('Unknown db worker message type:', ev.type); } } catch (err) { - evType = "error"; + evType = 'error'; result = { operation: ev.type, message: err.message, @@ -11567,7 +11880,7 @@ var sqlite3InitModule = (() => { }; if (err.stack) { result.stack = - "string" === typeof err.stack + 'string' === typeof err.stack ? err.stack.split(/\n\s*/) : err.stack; } @@ -11587,12 +11900,12 @@ var sqlite3InitModule = (() => { result: result, }, - wState.xfer + wState.xfer, ); }; globalThis.postMessage({ - type: "sqlite3-api", - result: "worker1-ready", + type: 'sqlite3-api', + result: 'worker1-ready', }); }.bind({ sqlite3 }); }); @@ -11605,16 +11918,16 @@ var sqlite3InitModule = (() => { capi.sqlite3_vfs.prototype.registerVfs = function (asDefault = false) { if (!(this instanceof sqlite3.capi.sqlite3_vfs)) { - toss("Expecting a sqlite3_vfs-type argument."); + toss('Expecting a sqlite3_vfs-type argument.'); } const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0); if (rc) { - toss("sqlite3_vfs_register(", this, ") failed with rc", rc); + toss('sqlite3_vfs_register(', this, ') failed with rc', rc); } if (this.pointer !== capi.sqlite3_vfs_find(this.$zName)) { toss( - "BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS", - this + 'BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS', + this, ); } return this; @@ -11622,16 +11935,16 @@ var sqlite3InitModule = (() => { vfs.installVfs = function (opt) { let count = 0; - const propList = ["io", "vfs"]; + const propList = ['io', 'vfs']; for (const key of propList) { const o = opt[key]; if (o) { ++count; o.struct.installMethods(o.methods, !!o.applyArgcCheck); - if ("vfs" === key) { - if (!o.struct.$zName && "string" === typeof o.name) { + if ('vfs' === key) { + if (!o.struct.$zName && 'string' === typeof o.name) { o.struct.addOnDispose( - (o.struct.$zName = wasm.allocCString(o.name)) + (o.struct.$zName = wasm.allocCString(o.name)), ); } o.struct.registerVfs(!!o.asDefault); @@ -11640,9 +11953,9 @@ var sqlite3InitModule = (() => { } if (!count) toss( - "Misuse: installVfs() options object requires at least", - "one of:", - propList + 'Misuse: installVfs() options object requires at least', + 'one of:', + propList, ); return this; }; @@ -11687,8 +12000,8 @@ var sqlite3InitModule = (() => { return ptr; } else if (!wasm.isPtr(ptr)) { sqlite3.SQLite3Error.toss( - "Invalid argument to", - methodName + "()" + 'Invalid argument to', + methodName + '()', ); } let rc = this.get(ptr); @@ -11720,9 +12033,9 @@ var sqlite3InitModule = (() => { }); }; - vtab.xVtab = StructPtrMapper("xVtab", capi.sqlite3_vtab); + vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab); - vtab.xCursor = StructPtrMapper("xCursor", capi.sqlite3_vtab_cursor); + vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor); vtab.xIndexInfo = (pIdxInfo) => new capi.sqlite3_index_info(pIdxInfo); @@ -11730,7 +12043,7 @@ var sqlite3InitModule = (() => { if (f.errorReporter instanceof Function) { try { f.errorReporter( - "sqlite3_module::" + methodName + "(): " + err.message + 'sqlite3_module::' + methodName + '(): ' + err.message, ); } catch (e) {} } @@ -11740,9 +12053,9 @@ var sqlite3InitModule = (() => { else if (err instanceof sqlite3.SQLite3Error) rc = err.resultCode; return rc || capi.SQLITE_ERROR; }; - vtab.xError.errorReporter = console.error.bind(console); + vtab.xError.errorReporter = console.error.bind(console) ; - vtab.xRowid = (ppRowid64, value) => wasm.poke(ppRowid64, value, "i64"); + vtab.xRowid = (ppRowid64, value) => wasm.poke(ppRowid64, value, 'i64'); vtab.setupModule = function (opt) { let createdMod = false; @@ -11753,8 +12066,8 @@ var sqlite3InitModule = (() => { try { const methods = opt.methods || toss("Missing 'methods' object."); for (const e of Object.entries({ - xConnect: "xCreate", - xDisconnect: "xDestroy", + xConnect: 'xCreate', + xDisconnect: 'xDestroy', })) { const k = e[0], v = e[1]; @@ -11763,7 +12076,7 @@ var sqlite3InitModule = (() => { } if (opt.catchExceptions) { const fwrap = function (methodName, func) { - if (["xConnect", "xCreate"].indexOf(methodName) >= 0) { + if (['xConnect', 'xCreate'].indexOf(methodName) >= 0) { return function (pDb, pAux, argc, argv, ppVtab, pzErr) { try { return func(...arguments) || 0; @@ -11786,37 +12099,37 @@ var sqlite3InitModule = (() => { } }; const mnames = [ - "xCreate", - "xConnect", - "xBestIndex", - "xDisconnect", - "xDestroy", - "xOpen", - "xClose", - "xFilter", - "xNext", - "xEof", - "xColumn", - "xRowid", - "xUpdate", - "xBegin", - "xSync", - "xCommit", - "xRollback", - "xFindFunction", - "xRename", - "xSavepoint", - "xRelease", - "xRollbackTo", - "xShadowName", + 'xCreate', + 'xConnect', + 'xBestIndex', + 'xDisconnect', + 'xDestroy', + 'xOpen', + 'xClose', + 'xFilter', + 'xNext', + 'xEof', + 'xColumn', + 'xRowid', + 'xUpdate', + 'xBegin', + 'xSync', + 'xCommit', + 'xRollback', + 'xFindFunction', + 'xRename', + 'xSavepoint', + 'xRelease', + 'xRollbackTo', + 'xShadowName', ]; const remethods = Object.create(null); for (const k of mnames) { const m = methods[k]; if (!(m instanceof Function)) continue; - else if ("xConnect" === k && methods.xCreate === m) { + else if ('xConnect' === k && methods.xCreate === m) { remethods[k] = methods.xCreate; - } else if ("xCreate" === k && methods.xConnect === m) { + } else if ('xCreate' === k && methods.xConnect === m) { remethods[k] = methods.xConnect; } else { remethods[k] = fwrap(k, m); @@ -11828,7 +12141,7 @@ var sqlite3InitModule = (() => { } if (0 === mod.$iVersion) { let v; - if ("number" === typeof opt.iVersion) v = opt.iVersion; + if ('number' === typeof opt.iVersion) v = opt.iVersion; else if (mod.$xShadowName) v = 3; else if (mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) v = 2; @@ -11851,17 +12164,17 @@ var sqlite3InitModule = (() => { if (!globalThis.SharedArrayBuffer || !globalThis.Atomics) { return Promise.reject( new Error( - "Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. " + - "The server must emit the COOP/COEP response headers to enable those. " + - "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep" - ) + 'Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. ' + + 'The server must emit the COOP/COEP response headers to enable those. ' + + 'See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep', + ), ); - } else if ("undefined" === typeof WorkerGlobalScope) { + } else if ('undefined' === typeof WorkerGlobalScope) { return Promise.reject( new Error( - "The OPFS sqlite3_vfs cannot run in the main thread " + - "because it requires Atomics.wait()." - ) + 'The OPFS sqlite3_vfs cannot run in the main thread ' + + 'because it requires Atomics.wait().', + ), ); } else if ( !globalThis.FileSystemHandle || @@ -11870,33 +12183,33 @@ var sqlite3InitModule = (() => { !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || !navigator?.storage?.getDirectory ) { - return Promise.reject(new Error("Missing required OPFS APIs.")); + return Promise.reject(new Error('Missing required OPFS APIs.')); } - if (!options || "object" !== typeof options) { + if (!options || 'object' !== typeof options) { options = Object.create(null); } const urlParams = new URL(globalThis.location.href).searchParams; - if (urlParams.has("opfs-disable")) { + if (urlParams.has('opfs-disable')) { return Promise.resolve(sqlite3); } if (undefined === options.verbose) { - options.verbose = urlParams.has("opfs-verbose") - ? +urlParams.get("opfs-verbose") || 2 + options.verbose = urlParams.has('opfs-verbose') + ? +urlParams.get('opfs-verbose') || 2 : 1; } if (undefined === options.sanityChecks) { - options.sanityChecks = urlParams.has("opfs-sanity-check"); + options.sanityChecks = urlParams.has('opfs-sanity-check'); } if (undefined === options.proxyUri) { options.proxyUri = callee.defaultProxyUri; } - if ("function" === typeof options.proxyUri) { + if ('function' === typeof options.proxyUri) { options.proxyUri = options.proxyUri(); } const thePromise = new Promise(function ( promiseResolve_, - promiseReject_ + promiseReject_, ) { const loggers = [ sqlite3.config.error, @@ -11905,7 +12218,7 @@ var sqlite3InitModule = (() => { ]; const logImpl = (level, ...args) => { if (options.verbose > level) - loggers[level]("OPFS syncer:", ...args); + loggers[level]('OPFS syncer:', ...args); }; const log = (...args) => logImpl(2, ...args); const warn = (...args) => logImpl(1, ...args); @@ -11947,18 +12260,18 @@ var sqlite3InitModule = (() => { } sqlite3.config.log( globalThis.location.href, - "metrics for", + 'metrics for', globalThis.location.href, - ":", + ':', metrics, - "\nTotal of", + '\nTotal of', n, - "op(s) for", + 'op(s) for', t, - "ms (incl. " + w + " ms of waiting on the async side)" + 'ms (incl. ' + w + ' ms of waiting on the async side)', ); - sqlite3.config.log("Serialization metrics:", metrics.s11n); - W.postMessage({ type: "opfs-async-metrics" }); + sqlite3.config.log('Serialization metrics:', metrics.s11n); + W.postMessage({ type: 'opfs-async-metrics' }); }, reset: function () { let k; @@ -11975,7 +12288,7 @@ var sqlite3InitModule = (() => { }; const opfsIoMethods = new sqlite3_io_methods(); const opfsVfs = new sqlite3_vfs().addOnDispose(() => - opfsIoMethods.dispose() + opfsIoMethods.dispose(), ); let promiseWasRejected = undefined; const promiseReject = (err) => { @@ -11988,24 +12301,24 @@ var sqlite3InitModule = (() => { return promiseResolve_(sqlite3); }; const W = new Worker( - new URL("sqlite3-opfs-async-proxy.js", import.meta.url) + new URL('sqlite3-opfs-async-proxy.js', import.meta.url), ); setTimeout(() => { if (undefined === promiseWasRejected) { promiseReject( new Error( - "Timeout while waiting for OPFS async proxy worker." - ) + 'Timeout while waiting for OPFS async proxy worker.', + ), ); } }, 4000); W._originalOnError = W.onerror; W.onerror = function (err) { - error("Error initializing OPFS asyncer:", err); + error('Error initializing OPFS asyncer:', err); promiseReject( new Error( - "Loading OPFS async Worker failed for unknown reasons." - ) + 'Loading OPFS async Worker failed for unknown reasons.', + ), ); }; const pDVfs = capi.sqlite3_vfs_find(null); @@ -12014,7 +12327,7 @@ var sqlite3InitModule = (() => { opfsVfs.$iVersion = 2; opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; opfsVfs.$mxPathname = 1024; - opfsVfs.$zName = wasm.allocCString("opfs"); + opfsVfs.$zName = wasm.allocCString('opfs'); opfsVfs.$xDlOpen = opfsVfs.$xDlError = @@ -12022,10 +12335,10 @@ var sqlite3InitModule = (() => { opfsVfs.$xDlClose = null; opfsVfs.addOnDispose( - "$zName", + '$zName', opfsVfs.$zName, - "cleanup default VFS wrapper", - () => (dVfs ? dVfs.dispose() : null) + 'cleanup default VFS wrapper', + () => (dVfs ? dVfs.dispose() : null), ); const state = Object.create(null); @@ -12047,7 +12360,7 @@ var sqlite3InitModule = (() => { state.sabS11nSize = opfsVfs.$mxPathname * 2; state.sabIO = new SharedArrayBuffer( - state.fileBufferSize + state.sabS11nSize + state.fileBufferSize + state.sabS11nSize, ); state.opIds = Object.create(null); const metrics = Object.create(null); @@ -12072,8 +12385,8 @@ var sqlite3InitModule = (() => { state.opIds.xUnlock = i++; state.opIds.xWrite = i++; state.opIds.mkdir = i++; - state.opIds["opfs-async-metrics"] = i++; - state.opIds["opfs-async-shutdown"] = i++; + state.opIds['opfs-async-metrics'] = i++; + state.opIds['opfs-async-shutdown'] = i++; state.opIds.retry = i++; state.sabOP = new SharedArrayBuffer(i * 4); @@ -12082,37 +12395,37 @@ var sqlite3InitModule = (() => { state.sq3Codes = Object.create(null); [ - "SQLITE_ACCESS_EXISTS", - "SQLITE_ACCESS_READWRITE", - "SQLITE_BUSY", - "SQLITE_CANTOPEN", - "SQLITE_ERROR", - "SQLITE_IOERR", - "SQLITE_IOERR_ACCESS", - "SQLITE_IOERR_CLOSE", - "SQLITE_IOERR_DELETE", - "SQLITE_IOERR_FSYNC", - "SQLITE_IOERR_LOCK", - "SQLITE_IOERR_READ", - "SQLITE_IOERR_SHORT_READ", - "SQLITE_IOERR_TRUNCATE", - "SQLITE_IOERR_UNLOCK", - "SQLITE_IOERR_WRITE", - "SQLITE_LOCK_EXCLUSIVE", - "SQLITE_LOCK_NONE", - "SQLITE_LOCK_PENDING", - "SQLITE_LOCK_RESERVED", - "SQLITE_LOCK_SHARED", - "SQLITE_LOCKED", - "SQLITE_MISUSE", - "SQLITE_NOTFOUND", - "SQLITE_OPEN_CREATE", - "SQLITE_OPEN_DELETEONCLOSE", - "SQLITE_OPEN_MAIN_DB", - "SQLITE_OPEN_READONLY", + 'SQLITE_ACCESS_EXISTS', + 'SQLITE_ACCESS_READWRITE', + 'SQLITE_BUSY', + 'SQLITE_CANTOPEN', + 'SQLITE_ERROR', + 'SQLITE_IOERR', + 'SQLITE_IOERR_ACCESS', + 'SQLITE_IOERR_CLOSE', + 'SQLITE_IOERR_DELETE', + 'SQLITE_IOERR_FSYNC', + 'SQLITE_IOERR_LOCK', + 'SQLITE_IOERR_READ', + 'SQLITE_IOERR_SHORT_READ', + 'SQLITE_IOERR_TRUNCATE', + 'SQLITE_IOERR_UNLOCK', + 'SQLITE_IOERR_WRITE', + 'SQLITE_LOCK_EXCLUSIVE', + 'SQLITE_LOCK_NONE', + 'SQLITE_LOCK_PENDING', + 'SQLITE_LOCK_RESERVED', + 'SQLITE_LOCK_SHARED', + 'SQLITE_LOCKED', + 'SQLITE_MISUSE', + 'SQLITE_NOTFOUND', + 'SQLITE_OPEN_CREATE', + 'SQLITE_OPEN_DELETEONCLOSE', + 'SQLITE_OPEN_MAIN_DB', + 'SQLITE_OPEN_READONLY', ].forEach((k) => { if (undefined === (state.sq3Codes[k] = capi[k])) { - toss("Maintenance required: not found:", k); + toss('Maintenance required: not found:', k); } }); state.opfsFlags = Object.assign(Object.create(null), { @@ -12124,14 +12437,14 @@ var sqlite3InitModule = (() => { }); const opRun = (op, ...args) => { - const opNdx = state.opIds[op] || toss("Invalid op ID:", op); + const opNdx = state.opIds[op] || toss('Invalid op ID:', op); state.s11n.serialize(...args); Atomics.store(state.sabOPView, state.opIds.rc, -1); Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); Atomics.notify(state.sabOPView, state.opIds.whichOp); const t = performance.now(); while ( - "not-equal" !== + 'not-equal' !== Atomics.wait(state.sabOPView, state.opIds.rc, -1) ) {} @@ -12139,7 +12452,7 @@ var sqlite3InitModule = (() => { metrics[op].wait += performance.now() - t; if (rc && state.asyncS11nExceptions) { const err = state.s11n.deserialize(); - if (err) error(op + "() async error:", ...err); + if (err) error(op + '() async error:', ...err); } return rc; }; @@ -12147,31 +12460,31 @@ var sqlite3InitModule = (() => { opfsUtil.debug = { asyncShutdown: () => { warn( - "Shutting down OPFS async listener. The OPFS VFS will no longer work." + 'Shutting down OPFS async listener. The OPFS VFS will no longer work.', ); - opRun("opfs-async-shutdown"); + opRun('opfs-async-shutdown'); }, asyncRestart: () => { warn( - "Attempting to restart OPFS VFS async listener. Might work, might not." + 'Attempting to restart OPFS VFS async listener. Might work, might not.', ); - W.postMessage({ type: "opfs-async-restart" }); + W.postMessage({ type: 'opfs-async-restart' }); }, }; const initS11n = () => { if (state.s11n) return state.s11n; const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder("utf-8"), + textEncoder = new TextEncoder('utf-8'), viewU8 = new Uint8Array( state.sabIO, state.sabS11nOffset, - state.sabS11nSize + state.sabS11nSize, ), viewDV = new DataView( state.sabIO, state.sabS11nOffset, - state.sabS11nSize + state.sabS11nSize, ); state.s11n = Object.create(null); @@ -12179,28 +12492,28 @@ var sqlite3InitModule = (() => { TypeIds.number = { id: 1, size: 8, - getter: "getFloat64", - setter: "setFloat64", + getter: 'getFloat64', + setter: 'setFloat64', }; TypeIds.bigint = { id: 2, size: 8, - getter: "getBigInt64", - setter: "setBigInt64", + getter: 'getBigInt64', + setter: 'setBigInt64', }; TypeIds.boolean = { id: 3, size: 4, - getter: "getInt32", - setter: "setInt32", + getter: 'getInt32', + setter: 'setInt32', }; TypeIds.string = { id: 4 }; const getTypeId = (v) => TypeIds[typeof v] || toss( - "Maintenance required: this value type cannot be serialized.", - v + 'Maintenance required: this value type cannot be serialized.', + v, ); const getTypeIdById = (tid) => { switch (tid) { @@ -12213,7 +12526,7 @@ var sqlite3InitModule = (() => { case TypeIds.string.id: return TypeIds.string; default: - toss("Invalid type ID:", tid); + toss('Invalid type ID:', tid); } }; @@ -12287,9 +12600,9 @@ var sqlite3InitModule = (() => { const randomFilename = function f(len = 16) { if (!f._chars) { f._chars = - "abcdefghijklmnopqrstuvwxyz" + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "012346789"; + 'abcdefghijklmnopqrstuvwxyz' + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + + '012346789'; f._n = f._chars.length; } const a = []; @@ -12298,7 +12611,7 @@ var sqlite3InitModule = (() => { const ndx = (Math.random() * (f._n * 64)) % f._n | 0; a[i] = f._chars[ndx]; } - return a.join(""); + return a.join(''); }; const __openFiles = Object.create(null); @@ -12317,17 +12630,17 @@ var sqlite3InitModule = (() => { const ioSyncWrappers = { xCheckReservedLock: function (pFile, pOut) { { - wasm.poke(pOut, 0, "i32"); + wasm.poke(pOut, 0, 'i32'); } return 0; }, xClose: function (pFile) { - mTimeStart("xClose"); + mTimeStart('xClose'); let rc = 0; const f = __openFiles[pFile]; if (f) { delete __openFiles[pFile]; - rc = opRun("xClose", pFile); + rc = opRun('xClose', pFile); if (f.sq3File) f.sq3File.dispose(); } mTimeEnd(); @@ -12340,14 +12653,14 @@ var sqlite3InitModule = (() => { return capi.SQLITE_NOTFOUND; }, xFileSize: function (pFile, pSz64) { - mTimeStart("xFileSize"); - let rc = opRun("xFileSize", pFile); + mTimeStart('xFileSize'); + let rc = opRun('xFileSize', pFile); if (0 == rc) { try { const sz = state.s11n.deserialize()[0]; - wasm.poke(pSz64, sz, "i64"); + wasm.poke(pSz64, sz, 'i64'); } catch (e) { - error("Unexpected error reading xFileSize() result:", e); + error('Unexpected error reading xFileSize() result:', e); rc = state.sq3Codes.SQLITE_IOERR; } } @@ -12355,12 +12668,12 @@ var sqlite3InitModule = (() => { return rc; }, xLock: function (pFile, lockType) { - mTimeStart("xLock"); + mTimeStart('xLock'); const f = __openFiles[pFile]; let rc = 0; if (!f.lockType) { - rc = opRun("xLock", pFile, lockType); + rc = opRun('xLock', pFile, lockType); if (0 === rc) f.lockType = lockType; } else { f.lockType = lockType; @@ -12369,54 +12682,54 @@ var sqlite3InitModule = (() => { return rc; }, xRead: function (pFile, pDest, n, offset64) { - mTimeStart("xRead"); + mTimeStart('xRead'); const f = __openFiles[pFile]; let rc; try { - rc = opRun("xRead", pFile, n, Number(offset64)); + rc = opRun('xRead', pFile, n, Number(offset64)); if (0 === rc || capi.SQLITE_IOERR_SHORT_READ === rc) { wasm.heap8u().set(f.sabView.subarray(0, n), pDest); } } catch (e) { - error("xRead(", arguments, ") failed:", e, f); + error('xRead(', arguments, ') failed:', e, f); rc = capi.SQLITE_IOERR_READ; } mTimeEnd(); return rc; }, xSync: function (pFile, flags) { - mTimeStart("xSync"); + mTimeStart('xSync'); ++metrics.xSync.count; - const rc = opRun("xSync", pFile, flags); + const rc = opRun('xSync', pFile, flags); mTimeEnd(); return rc; }, xTruncate: function (pFile, sz64) { - mTimeStart("xTruncate"); - const rc = opRun("xTruncate", pFile, Number(sz64)); + mTimeStart('xTruncate'); + const rc = opRun('xTruncate', pFile, Number(sz64)); mTimeEnd(); return rc; }, xUnlock: function (pFile, lockType) { - mTimeStart("xUnlock"); + mTimeStart('xUnlock'); const f = __openFiles[pFile]; let rc = 0; if (capi.SQLITE_LOCK_NONE === lockType && f.lockType) { - rc = opRun("xUnlock", pFile, lockType); + rc = opRun('xUnlock', pFile, lockType); } if (0 === rc) f.lockType = lockType; mTimeEnd(); return rc; }, xWrite: function (pFile, pSrc, n, offset64) { - mTimeStart("xWrite"); + mTimeStart('xWrite'); const f = __openFiles[pFile]; let rc; try { f.sabView.set(wasm.heap8u().subarray(pSrc, pSrc + n)); - rc = opRun("xWrite", pFile, n, Number(offset64)); + rc = opRun('xWrite', pFile, n, Number(offset64)); } catch (e) { - error("xWrite(", arguments, ") failed:", e, f); + error('xWrite(', arguments, ') failed:', e, f); rc = capi.SQLITE_IOERR_WRITE; } mTimeEnd(); @@ -12426,9 +12739,9 @@ var sqlite3InitModule = (() => { const vfsSyncWrappers = { xAccess: function (pVfs, zName, flags, pOut) { - mTimeStart("xAccess"); - const rc = opRun("xAccess", wasm.cstrToJs(zName)); - wasm.poke(pOut, rc ? 0 : 1, "i32"); + mTimeStart('xAccess'); + const rc = opRun('xAccess', wasm.cstrToJs(zName)); + wasm.poke(pOut, rc ? 0 : 1, 'i32'); mTimeEnd(); return 0; }, @@ -12436,7 +12749,7 @@ var sqlite3InitModule = (() => { wasm.poke( pOut, 2440587.5 + new Date().getTime() / 86400000, - "double" + 'double', ); return 0; }, @@ -12444,17 +12757,17 @@ var sqlite3InitModule = (() => { wasm.poke( pOut, 2440587.5 * 86400000 + new Date().getTime(), - "i64" + 'i64', ); return 0; }, xDelete: function (pVfs, zName, doSyncDir) { - mTimeStart("xDelete"); + mTimeStart('xDelete'); const rc = opRun( - "xDelete", + 'xDelete', wasm.cstrToJs(zName), doSyncDir, - false + false, ); mTimeEnd(); return rc; @@ -12464,21 +12777,21 @@ var sqlite3InitModule = (() => { return i < nOut ? 0 : capi.SQLITE_CANTOPEN; }, xGetLastError: function (pVfs, nOut, pOut) { - warn("OPFS xGetLastError() has nothing sensible to return."); + warn('OPFS xGetLastError() has nothing sensible to return.'); return 0; }, xOpen: function f(pVfs, zName, pFile, flags, pOutFlags) { - mTimeStart("xOpen"); + mTimeStart('xOpen'); let opfsFlags = 0; if (0 === zName) { zName = randomFilename(); } else if (wasm.isPtr(zName)) { - if (capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)) { + if (capi.sqlite3_uri_boolean(zName, 'opfs-unlock-asap', 0)) { opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP; } if ( - capi.sqlite3_uri_boolean(zName, "delete-before-open", 0) + capi.sqlite3_uri_boolean(zName, 'delete-before-open', 0) ) { opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN; } @@ -12489,10 +12802,10 @@ var sqlite3InitModule = (() => { fh.filename = zName; fh.sab = new SharedArrayBuffer(state.fileBufferSize); fh.flags = flags; - const rc = opRun("xOpen", pFile, zName, flags, opfsFlags); + const rc = opRun('xOpen', pFile, zName, flags, opfsFlags); if (!rc) { if (fh.readOnly) { - wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, "i32"); + wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, 'i32'); } __openFiles[pFile] = fh; fh.sabView = state.sabFileBufView; @@ -12526,13 +12839,13 @@ var sqlite3InitModule = (() => { } opfsUtil.getResolvedPath = function (filename, splitIt) { - const p = new URL(filename, "file://irrelevant").pathname; - return splitIt ? p.split("/").filter((v) => !!v) : p; + const p = new URL(filename, 'file://irrelevant').pathname; + return splitIt ? p.split('/').filter((v) => !!v) : p; }; opfsUtil.getDirForFilename = async function f( absFilename, - createDirs = false + createDirs = false, ) { const path = opfsUtil.getResolvedPath(absFilename, true); const filename = path.pop(); @@ -12550,8 +12863,8 @@ var sqlite3InitModule = (() => { opfsUtil.mkdir = async function (absDirName) { try { await opfsUtil.getDirForFilename( - absDirName + "/filepart", - true + absDirName + '/filepart', + true, ); return true; } catch (e) { @@ -12577,7 +12890,7 @@ var sqlite3InitModule = (() => { tgt.dirs = []; tgt.files = []; for await (const handle of dirHandle.values()) { - if ("directory" === handle.kind) { + if ('directory' === handle.kind) { const subDir = Object.create(null); tgt.dirs.push(subDir); await callee(handle, subDir); @@ -12602,24 +12915,24 @@ var sqlite3InitModule = (() => { opfsUtil.unlink = async function ( fsEntryName, recursive = false, - throwOnError = false + throwOnError = false, ) { try { const [hDir, filenamePart] = await opfsUtil.getDirForFilename( fsEntryName, - false + false, ); await hDir.removeEntry(filenamePart, { recursive }); return true; } catch (e) { if (throwOnError) { throw new Error( - "unlink(", + 'unlink(', arguments[0], - ") failed: " + e.message, + ') failed: ' + e.message, { cause: e, - } + }, ); } return false; @@ -12631,7 +12944,7 @@ var sqlite3InitModule = (() => { recursive: true, directory: opfsUtil.rootDirectory, }; - if ("function" === typeof opt) { + if ('function' === typeof opt) { opt = { callback: opt }; } opt = Object.assign(defaultOpt, opt || {}); @@ -12639,7 +12952,7 @@ var sqlite3InitModule = (() => { for await (const handle of dirHandle.values()) { if (false === opt.callback(handle, dirHandle, depth)) return false; - else if (opt.recursive && "directory" === handle.kind) { + else if (opt.recursive && 'directory' === handle.kind) { if (false === (await callee(handle, depth + 1))) break; } } @@ -12650,7 +12963,7 @@ var sqlite3InitModule = (() => { const importDbChunked = async function (filename, callback) { const [hDir, fnamePart] = await opfsUtil.getDirForFilename( filename, - true + true, ); const hFile = await hDir.getFileHandle(fnamePart, { create: true, @@ -12673,9 +12986,9 @@ var sqlite3InitModule = (() => { } if (nWrote < 512 || 0 !== nWrote % 512) { toss( - "Input size", + 'Input size', nWrote, - "is not correct for an SQLite database." + 'is not correct for an SQLite database.', ); } if (!checkedHeader) { @@ -12704,7 +13017,7 @@ var sqlite3InitModule = (() => { const n = bytes.byteLength; const [hDir, fnamePart] = await opfsUtil.getDirForFilename( filename, - true + true, ); let sah, nWrote = 0; @@ -12717,11 +13030,11 @@ var sqlite3InitModule = (() => { nWrote = sah.write(bytes, { at: 0 }); if (nWrote != n) { toss( - "Expected to write " + + 'Expected to write ' + n + - " bytes but wrote " + + ' bytes but wrote ' + nWrote + - "." + '.', ); } sah.write(new Uint8Array([1, 1]), { at: 18 }); @@ -12754,15 +13067,15 @@ var sqlite3InitModule = (() => { sqlite3.capi.sqlite3_exec( oo1Db, [ - "pragma journal_mode=DELETE;", + 'pragma journal_mode=DELETE;', - "pragma cache_size=-16384;", + 'pragma cache_size=-16384;', ], 0, 0, - 0 + 0, ); - } + }, ); } @@ -12776,70 +13089,70 @@ var sqlite3InitModule = (() => { capi.SQLITE_OPEN_READWRITE | capi.SQLITE_OPEN_MAIN_DB; const pOut = wasm.scopedAlloc(8); - const dbFile = "/sanity/check/file" + randomFilename(8); + const dbFile = '/sanity/check/file' + randomFilename(8); const zDbFile = wasm.scopedAllocCString(dbFile); let rc; - state.s11n.serialize("This is ä string."); + state.s11n.serialize('This is ä string.'); rc = state.s11n.deserialize(); - log("deserialize() says:", rc); - if ("This is ä string." !== rc[0]) toss("String d13n error."); + log('deserialize() says:', rc); + if ('This is ä string.' !== rc[0]) toss('String d13n error.'); vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, "i32"); - log("xAccess(", dbFile, ") exists ?=", rc); + rc = wasm.peek(pOut, 'i32'); + log('xAccess(', dbFile, ') exists ?=', rc); rc = vfsSyncWrappers.xOpen( opfsVfs.pointer, zDbFile, fid, openFlags, - pOut + pOut, ); log( - "open rc =", + 'open rc =', rc, - "state.sabOPView[xOpen] =", - state.sabOPView[state.opIds.xOpen] + 'state.sabOPView[xOpen] =', + state.sabOPView[state.opIds.xOpen], ); if (0 !== rc) { - error("open failed with code", rc); + error('open failed with code', rc); return; } vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, "i32"); - if (!rc) toss("xAccess() failed to detect file."); + rc = wasm.peek(pOut, 'i32'); + if (!rc) toss('xAccess() failed to detect file.'); rc = ioSyncWrappers.xSync(sq3File.pointer, 0); - if (rc) toss("sync failed w/ rc", rc); + if (rc) toss('sync failed w/ rc', rc); rc = ioSyncWrappers.xTruncate(sq3File.pointer, 1024); - if (rc) toss("truncate failed w/ rc", rc); - wasm.poke(pOut, 0, "i64"); + if (rc) toss('truncate failed w/ rc', rc); + wasm.poke(pOut, 0, 'i64'); rc = ioSyncWrappers.xFileSize(sq3File.pointer, pOut); - if (rc) toss("xFileSize failed w/ rc", rc); - log("xFileSize says:", wasm.peek(pOut, "i64")); + if (rc) toss('xFileSize failed w/ rc', rc); + log('xFileSize says:', wasm.peek(pOut, 'i64')); rc = ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1); - if (rc) toss("xWrite() failed!"); + if (rc) toss('xWrite() failed!'); const readBuf = wasm.scopedAlloc(16); rc = ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); wasm.poke(readBuf + 6, 0); let jRead = wasm.cstrToJs(readBuf); - log("xRead() got:", jRead); - if ("sanity" !== jRead) toss("Unexpected xRead() value."); + log('xRead() got:', jRead); + if ('sanity' !== jRead) toss('Unexpected xRead() value.'); if (vfsSyncWrappers.xSleep) { - log("xSleep()ing before close()ing..."); + log('xSleep()ing before close()ing...'); vfsSyncWrappers.xSleep(opfsVfs.pointer, 2000); - log("waking up from xSleep()"); + log('waking up from xSleep()'); } rc = ioSyncWrappers.xClose(fid); - log("xClose rc =", rc, "sabOPView =", state.sabOPView); - log("Deleting file:", dbFile); + log('xClose rc =', rc, 'sabOPView =', state.sabOPView); + log('Deleting file:', dbFile); vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234); vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut, "i32"); + rc = wasm.peek(pOut, 'i32'); if (rc) toss( - "Expecting 0 from xAccess(", + 'Expecting 0 from xAccess(', dbFile, - ") after xDelete()." + ') after xDelete().', ); - warn("End of OPFS sanity checks."); + warn('End of OPFS sanity checks.'); } finally { sq3File.dispose(); wasm.scopedAllocPop(scope); @@ -12848,13 +13161,13 @@ var sqlite3InitModule = (() => { W.onmessage = function ({ data }) { switch (data.type) { - case "opfs-unavailable": - promiseReject(new Error(data.payload.join(" "))); + case 'opfs-unavailable': + promiseReject(new Error(data.payload.join(' '))); break; - case "opfs-async-loaded": - W.postMessage({ type: "opfs-async-init", args: state }); + case 'opfs-async-loaded': + W.postMessage({ type: 'opfs-async-init', args: state }); break; - case "opfs-async-inited": { + case 'opfs-async-inited': { if (true === promiseWasRejected) { break; } @@ -12867,17 +13180,17 @@ var sqlite3InitModule = (() => { state.sabFileBufView = new Uint8Array( state.sabIO, 0, - state.fileBufferSize + state.fileBufferSize, ); state.sabS11nView = new Uint8Array( state.sabIO, state.sabS11nOffset, - state.sabS11nSize + state.sabS11nSize, ); initS11n(); if (options.sanityChecks) { warn( - "Running sanity checks because of opfs-sanity-check URL arg..." + 'Running sanity checks because of opfs-sanity-check URL arg...', ); sanityCheck(); } @@ -12889,7 +13202,7 @@ var sqlite3InitModule = (() => { delete W._originalOnError; sqlite3.opfs = opfsUtil; opfsUtil.rootDirectory = d; - log("End of OPFS sqlite3_vfs setup.", opfsVfs); + log('End of OPFS sqlite3_vfs setup.', opfsVfs); promiseResolve(); }) .catch(promiseReject); @@ -12904,7 +13217,7 @@ var sqlite3InitModule = (() => { } default: { const errMsg = - "Unexpected message from the OPFS async worker: " + + 'Unexpected message from the OPFS async worker: ' + JSON.stringify(data); error(errMsg); promiseReject(new Error(errMsg)); @@ -12915,7 +13228,7 @@ var sqlite3InitModule = (() => { }); return thePromise; }; - installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; + installOpfsVfs.defaultProxyUri = 'sqlite3-opfs-async-proxy.js'; globalThis.sqlite3ApiBootstrap.initializersAsync.push( async (sqlite3) => { try { @@ -12926,15 +13239,15 @@ var sqlite3InitModule = (() => { } return installOpfsVfs().catch((e) => { sqlite3.config.warn( - "Ignoring inability to install OPFS sqlite3_vfs:", - e.message + 'Ignoring inability to install OPFS sqlite3_vfs:', + e.message, ); }); } catch (e) { - sqlite3.config.error("installOpfsVfs() exception:", e); + sqlite3.config.error('installOpfsVfs() exception:', e); return Promise.reject(e); } - } + }, ); }); @@ -12961,7 +13274,7 @@ var sqlite3InitModule = (() => { capi.SQLITE_OPEN_SUPER_JOURNAL | capi.SQLITE_OPEN_WAL; - const OPAQUE_DIR_NAME = ".opaque"; + const OPAQUE_DIR_NAME = '.opaque'; const getRandomName = () => Math.random().toString(36).slice(2); @@ -12969,7 +13282,7 @@ var sqlite3InitModule = (() => { const textEncoder = new TextEncoder(); const optionDefaults = Object.assign(Object.create(null), { - name: "opfs-sahpool", + name: 'opfs-sahpool', directory: undefined, initialCapacity: 6, clearOnInit: false, @@ -13003,7 +13316,7 @@ var sqlite3InitModule = (() => { const ioMethods = { xCheckReservedLock: function (pFile, pOut) { const pool = getPoolForPFile(pFile); - pool.log("xCheckReservedLock"); + pool.log('xCheckReservedLock'); pool.storeErr(); wasm.poke32(pOut, 1); return 0; @@ -13057,7 +13370,7 @@ var sqlite3InitModule = (() => { try { const nRead = file.sah.read( wasm.heap8u().subarray(pDest, pDest + n), - { at: HEADER_OFFSET_DATA + Number(offset64) } + { at: HEADER_OFFSET_DATA + Number(offset64) }, ); if (nRead < n) { wasm.heap8u().fill(0, pDest + nRead, pDest + n); @@ -13099,7 +13412,7 @@ var sqlite3InitModule = (() => { }, xUnlock: function (pFile, lockType) { const pool = getPoolForPFile(pFile); - pool.log("xUnlock"); + pool.log('xUnlock'); const file = pool.getOFileForS3File(pFile); file.lockType = lockType; return 0; @@ -13112,9 +13425,9 @@ var sqlite3InitModule = (() => { try { const nBytes = file.sah.write( wasm.heap8u().subarray(pSrc, pSrc + n), - { at: HEADER_OFFSET_DATA + Number(offset64) } + { at: HEADER_OFFSET_DATA + Number(offset64) }, ); - return n === nBytes ? 0 : toss("Unknown write() failure."); + return n === nBytes ? 0 : toss('Unknown write() failure.'); } catch (e) { return pool.storeErr(e, capi.SQLITE_IOERR); } @@ -13143,12 +13456,12 @@ var sqlite3InitModule = (() => { wasm.poke( pOut, 2440587.5 + new Date().getTime() / 86400000, - "double" + 'double', ); return 0; }, xCurrentTimeInt64: function (pVfs, pOut) { - wasm.poke(pOut, 2440587.5 * 86400000 + new Date().getTime(), "i64"); + wasm.poke(pOut, 2440587.5 * 86400000 + new Date().getTime(), 'i64'); return 0; }, xDelete: function (pVfs, zName, doSyncDir) { @@ -13201,11 +13514,11 @@ var sqlite3InitModule = (() => { sah = pool.nextAvailableSAH(); pool.setAssociatedPath(sah, path, flags); } else { - toss("SAH pool is full. Cannot create file", path); + toss('SAH pool is full. Cannot create file', path); } } if (!sah) { - toss("file not found:", path); + toss('file not found:', path); } const file = { path, flags, sah }; @@ -13225,7 +13538,7 @@ var sqlite3InitModule = (() => { const createOpfsVfs = function (vfsName) { if (sqlite3.capi.sqlite3_vfs_find(vfsName)) { - toss3("VFS name is already registered:", vfsName); + toss3('VFS name is already registered:', vfsName); } const opfsVfs = new capi.sqlite3_vfs(); @@ -13236,7 +13549,7 @@ var sqlite3InitModule = (() => { opfsVfs.$mxPathname = HEADER_MAX_PATH_SIZE; opfsVfs.addOnDispose( (opfsVfs.$zName = wasm.allocCString(vfsName)), - () => setPoolForVfs(opfsVfs.pointer, 0) + () => setPoolForVfs(opfsVfs.pointer, 0), ); if (dVfs) { @@ -13292,26 +13605,26 @@ var sqlite3InitModule = (() => { this.vfsName = options.name || optionDefaults.name; this.#cVfs = createOpfsVfs(this.vfsName); setPoolForVfs(this.#cVfs.pointer, this); - this.vfsDir = options.directory || "." + this.vfsName; + this.vfsDir = options.directory || '.' + this.vfsName; this.#dvBody = new DataView( this.#apBody.buffer, - this.#apBody.byteOffset + this.#apBody.byteOffset, ); this.isReady = this.reset( - !!(options.clearOnInit ?? optionDefaults.clearOnInit) + !!(options.clearOnInit ?? optionDefaults.clearOnInit), ).then(() => { if (this.$error) throw this.$error; return this.getCapacity() ? Promise.resolve(undefined) : this.addCapacity( - options.initialCapacity || optionDefaults.initialCapacity + options.initialCapacity || optionDefaults.initialCapacity, ); }); } #logImpl(level, ...args) { if (this.#verbosity > level) - loggers[level](this.vfsName + ":", ...args); + loggers[level](this.vfsName + ':', ...args); } log(...args) { this.#logImpl(2, ...args); @@ -13350,7 +13663,7 @@ var sqlite3InitModule = (() => { }); const ah = await h.createSyncAccessHandle(); this.#mapSAHToName.set(ah, name); - this.setAssociatedPath(ah, "", 0); + this.setAssociatedPath(ah, '', 0); } return this.getCapacity(); } @@ -13382,7 +13695,7 @@ var sqlite3InitModule = (() => { async acquireAccessHandles(clearFiles) { const files = []; for await (const [name, h] of this.#dhOpaque) { - if ("file" === h.kind) { + if ('file' === h.kind) { files.push([name, h]); } } @@ -13393,7 +13706,7 @@ var sqlite3InitModule = (() => { this.#mapSAHToName.set(ah, name); if (clearFiles) { ah.truncate(HEADER_OFFSET_DATA); - this.setAssociatedPath(ah, "", 0); + this.setAssociatedPath(ah, '', 0); } else { const path = this.getAssociatedPath(ah); if (path) { @@ -13407,7 +13720,7 @@ var sqlite3InitModule = (() => { this.releaseAccessHandles(); throw e; } - }) + }), ); } @@ -13422,10 +13735,10 @@ var sqlite3InitModule = (() => { ) { warn( `Removing file with unexpected flags ${flags.toString(16)}`, - this.#apBody + this.#apBody, ); - this.setAssociatedPath(sah, "", 0); - return ""; + this.setAssociatedPath(sah, '', 0); + return ''; } const fileDigest = new Uint32Array(HEADER_DIGEST_SIZE / 4); @@ -13438,18 +13751,18 @@ var sqlite3InitModule = (() => { } return pathBytes ? textDecoder.decode(this.#apBody.subarray(0, pathBytes)) - : ""; + : ''; } else { - warn("Disassociating file with bad digest."); - this.setAssociatedPath(sah, "", 0); - return ""; + warn('Disassociating file with bad digest.'); + this.setAssociatedPath(sah, '', 0); + return ''; } } setAssociatedPath(sah, path, flags) { const enc = textEncoder.encodeInto(path, this.#apBody); if (HEADER_MAX_PATH_SIZE <= enc.written + 1) { - toss("Path too long:", path); + toss('Path too long:', path); } this.#apBody.fill(0, enc.written, HEADER_MAX_PATH_SIZE); this.#dvBody.setUint32(HEADER_OFFSET_FLAGS, flags); @@ -13482,7 +13795,7 @@ var sqlite3InitModule = (() => { await this.isReady; let h = await navigator.storage.getDirectory(); let prev; - for (const d of this.vfsDir.split("/")) { + for (const d of this.vfsDir.split('/')) { if (d) { prev = h; h = await h.getDirectoryHandle(d, { create: true }); @@ -13492,7 +13805,7 @@ var sqlite3InitModule = (() => { this.#dhVfsParent = prev; this.#dhOpaque = await this.#dhVfsRoot.getDirectoryHandle( OPAQUE_DIR_NAME, - { create: true } + { create: true }, ); this.releaseAccessHandles(); return this.acquireAccessHandles(clearFiles); @@ -13501,7 +13814,7 @@ var sqlite3InitModule = (() => { getPath(arg) { if (wasm.isPtr(arg)) arg = wasm.cstrToJs(arg); return ( - arg instanceof URL ? arg : new URL(arg, "file://localhost/") + arg instanceof URL ? arg : new URL(arg, 'file://localhost/') ).pathname; } @@ -13509,7 +13822,7 @@ var sqlite3InitModule = (() => { const sah = this.#mapFilenameToSAH.get(path); if (sah) { this.#mapFilenameToSAH.delete(path); - this.setAssociatedPath(sah, "", 0); + this.setAssociatedPath(sah, '', 0); } return !!sah; } @@ -13571,21 +13884,21 @@ var sqlite3InitModule = (() => { }); this.#dhVfsRoot = this.#dhVfsParent = undefined; } catch (e) { - sqlite3.config.error(this.vfsName, "removeVfs() failed:", e); + sqlite3.config.error(this.vfsName, 'removeVfs() failed:', e); } return true; } exportFile(name) { const sah = - this.#mapFilenameToSAH.get(name) || toss("File not found:", name); + this.#mapFilenameToSAH.get(name) || toss('File not found:', name); const n = sah.getSize() - HEADER_OFFSET_DATA; const b = new Uint8Array(n > 0 ? n : 0); if (n > 0) { const nRead = sah.read(b, { at: HEADER_OFFSET_DATA }); if (nRead != n) { toss( - "Expected to read " + n + " bytes but read " + nRead + "." + 'Expected to read ' + n + ' bytes but read ' + nRead + '.', ); } } @@ -13596,7 +13909,7 @@ var sqlite3InitModule = (() => { const sah = this.#mapFilenameToSAH.get(name) || this.nextAvailableSAH() || - toss("No available handles to import to."); + toss('No available handles to import to.'); sah.truncate(0); let nWrote = 0, chunk, @@ -13613,9 +13926,9 @@ var sqlite3InitModule = (() => { } if (nWrote < 512 || 0 !== nWrote % 512) { toss( - "Input size", + 'Input size', nWrote, - "is not correct for an SQLite database." + 'is not correct for an SQLite database.', ); } if (!checkedHeader) { @@ -13627,7 +13940,7 @@ var sqlite3InitModule = (() => { at: HEADER_OFFSET_DATA + 18, }); } catch (e) { - this.setAssociatedPath(sah, "", 0); + this.setAssociatedPath(sah, '', 0); throw e; } this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB); @@ -13641,22 +13954,22 @@ var sqlite3InitModule = (() => { const sah = this.#mapFilenameToSAH.get(name) || this.nextAvailableSAH() || - toss("No available handles to import to."); + toss('No available handles to import to.'); const n = bytes.byteLength; if (n < 512 || n % 512 != 0) { - toss("Byte array size is invalid for an SQLite db."); + toss('Byte array size is invalid for an SQLite db.'); } - const header = "SQLite format 3"; + const header = 'SQLite format 3'; for (let i = 0; i < header.length; ++i) { if (header.charCodeAt(i) !== bytes[i]) { - toss("Input does not contain an SQLite database header."); + toss('Input does not contain an SQLite database header.'); } } const nWrote = sah.write(bytes, { at: HEADER_OFFSET_DATA }); if (nWrote != n) { - this.setAssociatedPath(sah, "", 0); + this.setAssociatedPath(sah, '', 0); toss( - "Expected to write " + n + " bytes but wrote " + nWrote + "." + 'Expected to write ' + n + ' bytes but wrote ' + nWrote + '.', ); } else { sah.write(new Uint8Array([1, 1]), { @@ -13723,7 +14036,7 @@ var sqlite3InitModule = (() => { const apiVersionCheck = async () => { const dh = await navigator.storage.getDirectory(); - const fn = ".opfs-sahpool-sync-check-" + getRandomName(); + const fn = '.opfs-sahpool-sync-check-' + getRandomName(); const fh = await dh.getFileHandle(fn, { create: true }); const ah = await fh.createSyncAccessHandle(); const close = ah.close(); @@ -13731,15 +14044,15 @@ var sqlite3InitModule = (() => { await dh.removeEntry(fn); if (close?.then) { toss( - "The local OPFS API is too old for opfs-sahpool:", - "it has an async FileSystemSyncAccessHandle.close() method." + 'The local OPFS API is too old for opfs-sahpool:', + 'it has an async FileSystemSyncAccessHandle.close() method.', ); } return true; }; sqlite3.installOpfsSAHPoolVfs = async function ( - options = Object.create(null) + options = Object.create(null), ) { const vfsName = options.name || optionDefaults.name; if (initPromises[vfsName]) { @@ -13753,7 +14066,7 @@ var sqlite3InitModule = (() => { !navigator?.storage?.getDirectory ) { return (initPromises[vfsName] = Promise.reject( - new Error("Missing required OPFS APIs.") + new Error('Missing required OPFS APIs.'), )); } @@ -13783,17 +14096,17 @@ var sqlite3InitModule = (() => { sqlite3.capi.sqlite3_exec( oo1Db, [ - "pragma journal_mode=DELETE;", - "pragma cache_size=-16384;", + 'pragma journal_mode=DELETE;', + 'pragma cache_size=-16384;', ], 0, 0, - 0 + 0, ); - } + }, ); } - thePool.log("VFS initialized."); + thePool.log('VFS initialized.'); return poolUtil; }) .catch(async (e) => { @@ -13806,15 +14119,15 @@ var sqlite3InitModule = (() => { })); }; }); - if ("undefined" !== typeof Module) { + if ('undefined' !== typeof Module) { const SABC = Object.assign( Object.create(null), { exports: - "undefined" === typeof wasmExports ? Module["asm"] : wasmExports, + 'undefined' === typeof wasmExports ? Module['asm'] : wasmExports, memory: Module.wasmMemory, }, - globalThis.sqlite3ApiConfig || {} + globalThis.sqlite3ApiConfig || {}, ); globalThis.sqlite3ApiConfig = SABC; @@ -13822,7 +14135,7 @@ var sqlite3InitModule = (() => { try { sqlite3 = globalThis.sqlite3ApiBootstrap(); } catch (e) { - console.error("sqlite3ApiBootstrap() error:", e); + console.error('sqlite3ApiBootstrap() error:', e); throw e; } finally { delete globalThis.sqlite3ApiBootstrap; @@ -13832,10 +14145,10 @@ var sqlite3InitModule = (() => { Module.sqlite3 = sqlite3; } else { console.warn( - "This is not running in an Emscripten module context, so", - "globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack", - "of config info for the WASM environment.", - "It must be called manually." + 'This is not running in an Emscripten module context, so', + 'globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack', + 'of config info for the WASM environment.', + 'It must be called manually.', ); } }); @@ -13848,7 +14161,7 @@ const toExportForESM = (function () { const originalInit = sqlite3InitModule; if (!originalInit) { throw new Error( - "Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build." + 'Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build.', ); } @@ -13856,26 +14169,26 @@ const toExportForESM = (function () { Object.create(null), { moduleScript: globalThis?.document?.currentScript, - isWorker: "undefined" !== typeof WorkerGlobalScope, + isWorker: 'undefined' !== typeof WorkerGlobalScope, location: globalThis.location, urlParams: globalThis?.location?.href ? new URL(globalThis.location.href).searchParams : new URLSearchParams(), - } + }, )); initModuleState.debugModule = initModuleState.urlParams.has( - "sqlite3.debugModule" + 'sqlite3.debugModule', ) - ? (...args) => console.warn("sqlite3.debugModule:", ...args) + ? (...args) => console.warn('sqlite3.debugModule:', ...args) : () => {}; - if (initModuleState.urlParams.has("sqlite3.dir")) { + if (initModuleState.urlParams.has('sqlite3.dir')) { initModuleState.sqlite3Dir = - initModuleState.urlParams.get("sqlite3.dir") + "/"; + initModuleState.urlParams.get('sqlite3.dir') + '/'; } else if (initModuleState.moduleScript) { - const li = initModuleState.moduleScript.src.split("/"); + const li = initModuleState.moduleScript.src.split('/'); li.pop(); - initModuleState.sqlite3Dir = li.join("/") + "/"; + initModuleState.sqlite3Dir = li.join('/') + '/'; } globalThis.sqlite3InitModule = function ff(...args) { @@ -13890,7 +14203,7 @@ const toExportForESM = (function () { return f(); }) .catch((e) => { - console.error("Exception loading sqlite3 module:", e); + console.error('Exception loading sqlite3 module:', e); throw e; }); }; @@ -13898,11 +14211,11 @@ const toExportForESM = (function () { if (globalThis.sqlite3InitModuleState.moduleScript) { const sim = globalThis.sqlite3InitModuleState; - let src = sim.moduleScript.src.split("/"); + let src = sim.moduleScript.src.split('/'); src.pop(); - sim.scriptDir = src.join("/") + "/"; + sim.scriptDir = src.join('/') + '/'; } - initModuleState.debugModule("sqlite3InitModuleState =", initModuleState); + initModuleState.debugModule('sqlite3InitModuleState =', initModuleState); return globalThis.sqlite3InitModule; })(); sqlite3InitModule = toExportForESM; @@ -13933,9 +14246,9 @@ var sqlite3InitModule$1 = sqlite3InitModule; */ globalThis.sqlite3Worker1Promiser = function callee( - config = callee.defaultConfig + config = callee.defaultConfig, ) { - if (1 === arguments.length && "function" === typeof arguments[0]) { + if (1 === arguments.length && 'function' === typeof arguments[0]) { const f = config; config = Object.assign(Object.create(null), callee.defaultConfig); config.onready = f; @@ -13951,22 +14264,22 @@ globalThis.sqlite3Worker1Promiser = function callee( config.generateMessageId || function (msg) { return ( - msg.type + "#" + (idTypeMap[msg.type] = (idTypeMap[msg.type] || 0) + 1) + msg.type + '#' + (idTypeMap[msg.type] = (idTypeMap[msg.type] || 0) + 1) ); }; const toss = (...args) => { - throw new Error(args.join(" ")); + throw new Error(args.join(' ')); }; if (!config.worker) config.worker = callee.defaultConfig.worker; - if ("function" === typeof config.worker) config.worker = config.worker(); + if ('function' === typeof config.worker) config.worker = config.worker(); let dbId; let promiserFunc; config.worker.onmessage = function (ev) { ev = ev.data; - debug("worker1.onmessage", ev); + debug('worker1.onmessage', ev); let msgHandler = handlerMap[ev.messageId]; if (!msgHandler) { - if (ev && "sqlite3-api" === ev.type && "worker1-ready" === ev.result) { + if (ev && 'sqlite3-api' === ev.type && 'worker1-ready' === ev.result) { if (config.onready) config.onready(promiserFunc); return; } @@ -13976,18 +14289,18 @@ globalThis.sqlite3Worker1Promiser = function callee( return; } if (config.onunhandled) config.onunhandled(arguments[0]); - else err("sqlite3Worker1Promiser() unhandled worker message:", ev); + else err('sqlite3Worker1Promiser() unhandled worker message:', ev); return; } delete handlerMap[ev.messageId]; switch (ev.type) { - case "error": + case 'error': msgHandler.reject(ev); return; - case "open": + case 'open': if (!dbId) dbId = ev.dbId; break; - case "close": + case 'close': if (ev.dbId === dbId) dbId = undefined; break; } @@ -14007,23 +14320,23 @@ globalThis.sqlite3Worker1Promiser = function callee( msg.args = arguments[1]; msg.dbId = msg.args.dbId; } else { - toss("Invalid arguments for sqlite3Worker1Promiser()-created factory."); + toss('Invalid arguments for sqlite3Worker1Promiser()-created factory.'); } - if (!msg.dbId && msg.type !== "open") msg.dbId = dbId; + if (!msg.dbId && msg.type !== 'open') msg.dbId = dbId; msg.messageId = genMsgId(msg); msg.departureTime = performance.now(); const proxy = Object.create(null); proxy.message = msg; let rowCallbackId; - if ("exec" === msg.type && msg.args) { - if ("function" === typeof msg.args.callback) { - rowCallbackId = msg.messageId + ":row"; + if ('exec' === msg.type && msg.args) { + if ('function' === typeof msg.args.callback) { + rowCallbackId = msg.messageId + ':row'; proxy.onrow = msg.args.callback; msg.args.callback = rowCallbackId; handlerMap[rowCallbackId] = proxy; - } else if ("string" === typeof msg.args.callback) { + } else if ('string' === typeof msg.args.callback) { toss( - "exec callback may not be a string when using the Promise interface." + 'exec callback may not be a string when using the Promise interface.', ); } } @@ -14033,10 +14346,10 @@ globalThis.sqlite3Worker1Promiser = function callee( proxy.reject = reject; handlerMap[msg.messageId] = proxy; debug( - "Posting", + 'Posting', msg.type, - "message to Worker dbId=" + (dbId || "default") + ":", - msg + 'message to Worker dbId=' + (dbId || 'default') + ':', + msg, ); config.worker.postMessage(msg); }); @@ -14048,21 +14361,21 @@ globalThis.sqlite3Worker1Promiser = function callee( globalThis.sqlite3Worker1Promiser.defaultConfig = { worker: function () { return new Worker( - new URL("sqlite3-worker1-bundler-friendly.mjs", import.meta.url), + new URL('sqlite3-worker1-bundler-friendly.mjs', import.meta.url), { - type: "module", - } + type: 'module', + }, ); }, - onerror: (...args) => console.error("worker1 promiser error", ...args), + onerror: (...args) => console.error('worker1 promiser error', ...args), }; sqlite3Worker1Promiser.v2 = function (config) { let oldFunc; - if ("function" == typeof config) { + if ('function' == typeof config) { oldFunc = config; config = {}; - } else if ("function" === typeof config?.onready) { + } else if ('function' === typeof config?.onready) { oldFunc = config.onready; delete config.onready; } @@ -14109,7 +14422,7 @@ class SQLite { constructor(sqlite3) { if (typeof sqlite3 === "undefined") { throw new Error( - "`sqliteObject` must be defined before calling constructor" + "`sqliteObject` must be defined before calling constructor", ); } this.sqlite3 = sqlite3; @@ -14239,15 +14552,7 @@ class SQLite { open(database_url, iflags) { try { - let db; - if (database_url === ":memory:") { - db = new this.sqlite3.oo1.DB("transient_in_memory_db:"); - console.log(`Created in-memory database`); - } else { - db = new this.sqlite3.oo1.OpfsDb(database_url); - console.log(`Created persistent database at ${db.filename}`); - } - return db; + return new this.sqlite3.oo1.OpfsDb(database_url); } catch (error) { console.log("OPFS open error", error); throw error; @@ -14295,7 +14600,7 @@ class SQLite { nByte, prepFlags, ppStmt, - pzTail + pzTail, ); } @@ -14339,7 +14644,7 @@ class SQLite { pApp, xFunc, xStep, - xFinal + xFinal, ) { try { this.sqlite3.capi.sqlite3_create_function( @@ -14350,7 +14655,7 @@ class SQLite { pApp, // pApp is ignored xFunc, xStep, - xFinal + xFinal, ); console.log("create function"); } catch (error) { @@ -14390,9 +14695,9 @@ class SQLite { log(`Created trigger for ${table_name}`); log(row); log(`------------------------------------`); - } + }, ); - } + }, ); } catch (error) { console.log("error creating diesel trigger"); @@ -14404,12 +14709,18 @@ class SQLite { return this.sqlite3.capi.sqlite3_value_free(value); } - sqlite3_free(value) { - return this.sqlite3.capi.sqlite3_free(value); - } - - sqlite3_serialize(database, zSchema, size, flags) { - return this.sqlite3.capi.sqlite3_serialize(database, zSchema, size, flags); + sqlite3_serialize(database, z_schema, p_size, m_flags) { + try { + return this.sqlite3.capi.sqlite3_serialize( + database, + z_schema, + p_size, + m_flags, + ); + } catch (error) { + console.log("error serializing"); + throw error; + } } sqlite3_deserialize( @@ -14418,16 +14729,25 @@ class SQLite { p_data, sz_database, sz_buffer, - m_flags + m_flags, ) { - return this.sqlite3.capi.sqlite3_deserialize( - database, - z_schema, - p_data, - sz_database, - sz_buffer, - m_flags - ); + try { + return this.sqlite3.capi.sqlite3_deserialize( + database, + z_schema, + p_data, + sz_database, + sz_buffer, + m_flags, + ); + } catch (error) { + console.log("error deserializing"); + throw error; + } + } + + sqlite3_free(_database, arg1) { + return this.sqlite3.capi.sqlite3_free(arg1); } } diff --git a/diesel-wasm-sqlite/tests/test/row.rs b/diesel-wasm-sqlite/tests/test/row.rs index eaa7d2814..588c02e68 100644 --- a/diesel-wasm-sqlite/tests/test/row.rs +++ b/diesel-wasm-sqlite/tests/test/row.rs @@ -131,75 +131,3 @@ async fn fun_with_row_iters() { expected[0].1 ); } - -// not sure if we need to replicate parallel test for wasm -/* -crate::define_sql_function! {fn sleep(a: diesel::sql_types::Integer) -> diesel::sql_types::Integer} -#[test] -fn parallel_iter_with_error() { - use crate::WasmSqliteConnection; - use diesel::connection::Connection; - use diesel::connection::LoadConnection; - use diesel::connection::SimpleConnection; - use diesel::expression_methods::ExpressionMethods; - use std::sync::{Arc, Barrier}; - use std::time::Duration; - - let temp_dir = tempfile::tempdir().unwrap(); - let db_path = format!("{}/test.db", temp_dir.path().display()); - let mut conn1 = SqliteConnection::establish(&db_path).unwrap(); - let mut conn2 = SqliteConnection::establish(&db_path).unwrap(); - - crate::table! { - users { - id -> Integer, - name -> Text, - } - } - - conn1 - .batch_execute("CREATE TABLE users(id INTEGER NOT NULL PRIMARY KEY, name TEXT)") - .unwrap(); - - let barrier = Arc::new(Barrier::new(2)); - let barrier2 = barrier.clone(); - - // we unblock the main thread from the sleep function - sleep_utils::register_impl(&mut conn2, move |a: i32| { - barrier.wait(); - std::thread::sleep(Duration::from_secs(a as u64)); - a - }) - .unwrap(); - - // spawn a background thread that locks the database file - let handle = std::thread::spawn(move || { - use crate::query_dsl::RunQueryDsl; - - conn2 - .immediate_transaction(|conn| diesel::select(sleep(1)).execute(conn)) - .unwrap(); - }); - barrier2.wait(); - - // execute some action that also requires a lock - let mut iter = conn1 - .load( - diesel::insert_into(users::table) - .values((users::id.eq(1), users::name.eq("John"))) - .returning(users::id), - ) - .unwrap(); - - // get the first iterator result, that should return the lock error - let n = iter.next().unwrap(); - assert!(n.is_err()); - - // check that the iterator is now empty - let n = iter.next(); - assert!(n.is_none()); - - // join the background thread - handle.join().unwrap(); -} -*/ diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index 8d469027d..a08ff55d3 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -1,6 +1,5 @@ //! General tests for migrations/diesel ORM/persistant databases use crate::common::prelude::*; -use diesel::dsl::count; use diesel_wasm_sqlite::dsl::RunQueryDsl; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/migrations/"); @@ -67,14 +66,6 @@ fn insert_books(conn: &mut WasmSqliteConnection, new_books: Vec) -> Qu Ok(rows_changed) } -fn insert_book(conn: &mut WasmSqliteConnection, new_book: BookForm) -> QueryResult { - use schema::books::dsl::*; - let query = insert_into(books).values(new_book); - let sql = debug_query::(&query).to_string(); - tracing::info!("QUERY = {}", sql); - let rows_changed = query.execute(conn).unwrap(); - Ok(rows_changed) -} /* #[wasm_bindgen_test] fn examine_sql_from_insert_default_values() { diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 063cc450e..3baed20d7 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -409,7 +409,7 @@ async fn main() { } async fn create_client(cli: &Cli, account: IdentityStrategy) -> Result { - let msg_store = get_encrypted_store(&cli.db).unwrap(); + let msg_store = get_encrypted_store(&cli.db).await.unwrap(); let mut builder = ClientBuilder::new(account).store(msg_store); if cli.local { @@ -536,17 +536,17 @@ fn static_enc_key() -> EncryptionKey { [2u8; 32] } -fn get_encrypted_store(db: &Option) -> Result { +async fn get_encrypted_store(db: &Option) -> Result { let store = match db { Some(path) => { let s = path.as_path().to_string_lossy().to_string(); info!("Using persistent storage: {} ", s); - EncryptedMessageStore::new_unencrypted(StorageOption::Persistent(s)) + EncryptedMessageStore::new_unencrypted(StorageOption::Persistent(s)).await } None => { info!("Using ephemeral store"); - EncryptedMessageStore::new(StorageOption::Ephemeral, static_enc_key()) + EncryptedMessageStore::new(StorageOption::Ephemeral, static_enc_key()).await } }; diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index 14fb07920..1d0320b4a 100755 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -78,6 +78,7 @@ impl ClientWithMetadata for XmtpHttpApiClient { self.app_version = Some(version); let mut headers = header::HeaderMap::new(); + if let Some(app_version) = &self.app_version { headers.insert("x-app-version", app_version.parse().map_err(metadata_err)?); } @@ -87,6 +88,7 @@ impl ClientWithMetadata for XmtpHttpApiClient { libxmtp_version.parse().map_err(metadata_err)?, ); } + self.http_client = reqwest_builder() .default_headers(headers) .build() @@ -97,6 +99,7 @@ impl ClientWithMetadata for XmtpHttpApiClient { self.libxmtp_version = Some(version); let mut headers = header::HeaderMap::new(); + if let Some(app_version) = &self.app_version { headers.insert( "x-app-version", @@ -113,6 +116,7 @@ impl ClientWithMetadata for XmtpHttpApiClient { .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?, ); } + self.http_client = reqwest_builder() .default_headers(headers) .build() diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index 319e8b236..e84af8920 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -27,7 +27,7 @@ tokio = { workspace = true, features = ["macros"] } tracing.workspace = true xmtp_cryptography.workspace = true xmtp_proto = { workspace = true, features = ["proto_full"] } -wasm-timer = "0.2" +wasm-timer.workspace = true [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2", features = ["js"] } diff --git a/xmtp_id/src/associations/association_log.rs b/xmtp_id/src/associations/association_log.rs index bf0ca611b..ded06670c 100644 --- a/xmtp_id/src/associations/association_log.rs +++ b/xmtp_id/src/associations/association_log.rs @@ -1,4 +1,3 @@ - use super::hashes::generate_inbox_id; use super::member::{Member, MemberIdentifier, MemberKind}; use super::serialization::DeserializationError; @@ -37,7 +36,6 @@ pub enum AssociationError { MissingIdentityUpdate, } - pub trait IdentityAction: Send + 'static { fn update_state( &self, diff --git a/xmtp_id/src/associations/mod.rs b/xmtp_id/src/associations/mod.rs index d77656c4c..b5874029c 100644 --- a/xmtp_id/src/associations/mod.rs +++ b/xmtp_id/src/associations/mod.rs @@ -116,9 +116,9 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::associations::verified_signature::VerifiedSignature; use self::test_utils::{rand_string, rand_vec}; use super::*; + use crate::associations::verified_signature::VerifiedSignature; pub async fn new_test_inbox() -> AssociationState { let create_request = CreateInbox::default(); diff --git a/xmtp_id/src/associations/signature.rs b/xmtp_id/src/associations/signature.rs index 08a4cbcca..0c3fe0c1f 100644 --- a/xmtp_id/src/associations/signature.rs +++ b/xmtp_id/src/associations/signature.rs @@ -164,4 +164,3 @@ impl ValidatedLegacySignedPublicKey { self.created_ns } } - diff --git a/xmtp_id/src/lib.rs b/xmtp_id/src/lib.rs index a003f97ac..1156897fa 100644 --- a/xmtp_id/src/lib.rs +++ b/xmtp_id/src/lib.rs @@ -60,6 +60,7 @@ impl InboxOwner for LocalWallet { #[cfg(test)] mod tests { + use super::*; use ethers::contract::abigen; #[cfg(target_arch = "wasm32")] @@ -80,7 +81,7 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] #[cfg(not(target_arch = "wasm32"))] async fn test_is_smart_contract() { - use crate::scw_verifier::tests::with_smart_contracts; + use scw_verifier::tests::with_smart_contracts; with_smart_contracts(|anvil, _provider, _client, smart_contracts| async move { let deployer: LocalWallet = anvil.keys()[0].clone().into(); diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 06329c326..501e134ef 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -40,6 +40,7 @@ async-trait.workspace = true futures.workspace = true reqwest = { version = "0.12.4", features = ["stream"] } dyn-clone = "1" +wasm-timer.workspace = true # XMTP/Local xmtp_cryptography = { workspace = true } @@ -88,7 +89,7 @@ chrono = { workspace = true, features = ["wasmbind"] } tokio = { workspace = true, features = ["macros", "rt"] } openmls = { workspace = true, features = ["test-utils", "js"] } gloo-timers = { workspace = true, features = ["futures"] } - +wasm-bindgen-futures.workspace = true [dev-dependencies] ethers.workspace = true diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index 448146aef..52ce725db 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -18,7 +18,7 @@ use xmtp_proto::{ }, }; -#[cfg(feature = "http-api")] +#[cfg(any(feature = "http-api", target_arch = "wasm32"))] use xmtp_proto::xmtp::mls::api::v1::WelcomeMessage; use crate::XmtpTestClient; diff --git a/xmtp_mls/src/bin/update-schema.rs b/xmtp_mls/src/bin/update-schema.rs index 11505e245..0f5fd6f63 100644 --- a/xmtp_mls/src/bin/update-schema.rs +++ b/xmtp_mls/src/bin/update-schema.rs @@ -28,11 +28,12 @@ const DIESEL_TOML: &str = "./diesel.toml"; /// Notes: /// - there is not great handling around tmp database cleanup in error cases. /// - https://github.com/diesel-rs/diesel/issues/852 -> BigInts are weird. -fn main() { - update_schemas_encrypted_message_store().unwrap(); +#[tokio::main] +async fn main() { + update_schemas_encrypted_message_store().await.unwrap(); } -fn update_schemas_encrypted_message_store() -> Result<(), std::io::Error> { +async fn update_schemas_encrypted_message_store() -> Result<(), std::io::Error> { let tmp_db = format!( "update-{}.db3", Alphanumeric.sample_string(&mut rand::thread_rng(), 16) @@ -41,6 +42,7 @@ fn update_schemas_encrypted_message_store() -> Result<(), std::io::Error> { { // Initialize DB to read the latest table definitions let _ = EncryptedMessageStore::new_unencrypted(StorageOption::Persistent(tmp_db.clone())) + .await .unwrap(); } diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 4150f6cf7..e2468b9e0 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -347,6 +347,7 @@ pub(crate) mod tests { for test_case in identity_strategies_test_cases { let result = ClientBuilder::new(test_case.strategy) .temp_store() + .await .local_client() .await .build() @@ -382,6 +383,7 @@ pub(crate) mod tests { StorageOption::Persistent(tmp_path()), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let client1 = ClientBuilder::new(identity_strategy.clone()) @@ -427,6 +429,7 @@ pub(crate) mod tests { Some(legacy_key), )) .temp_store() + .await .local_client() .await .build() @@ -449,6 +452,7 @@ pub(crate) mod tests { StorageOption::Persistent(tmpdb), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let nonce = 0; let address = generate_local_wallet().get_address(); @@ -490,6 +494,7 @@ pub(crate) mod tests { StorageOption::Persistent(tmpdb), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let nonce = 0; let address = generate_local_wallet().get_address(); @@ -529,6 +534,7 @@ pub(crate) mod tests { StorageOption::Persistent(tmpdb), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let nonce = 0; let address = generate_local_wallet().get_address(); @@ -567,6 +573,7 @@ pub(crate) mod tests { StorageOption::Persistent(tmpdb), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let stored: StoredIdentity = (&Identity { @@ -603,8 +610,9 @@ pub(crate) mod tests { let db_key = EncryptedMessageStore::generate_enc_key(); // Generate a new Wallet + Store - let store_a = - EncryptedMessageStore::new(StorageOption::Persistent(tmpdb.clone()), db_key).unwrap(); + let store_a = EncryptedMessageStore::new(StorageOption::Persistent(tmpdb.clone()), db_key) + .await + .unwrap(); let nonce = 1; let inbox_id = generate_inbox_id(&wallet.get_address(), &nonce); @@ -627,8 +635,9 @@ pub(crate) mod tests { drop(client_a); // Reload the existing store and wallet - let store_b = - EncryptedMessageStore::new(StorageOption::Persistent(tmpdb.clone()), db_key).unwrap(); + let store_b = EncryptedMessageStore::new(StorageOption::Persistent(tmpdb.clone()), db_key) + .await + .unwrap(); let client_b = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( inbox_id, @@ -666,8 +675,9 @@ pub(crate) mod tests { // .expect_err("Testing expected mismatch error"); // Use cached only strategy - let store_d = - EncryptedMessageStore::new(StorageOption::Persistent(tmpdb.clone()), db_key).unwrap(); + let store_d = EncryptedMessageStore::new(StorageOption::Persistent(tmpdb.clone()), db_key) + .await + .unwrap(); let client_d = ClientBuilder::new(IdentityStrategy::CachedOnly) .local_client() .await diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 56bc8733d..fa18f0718 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -234,7 +234,7 @@ pub struct XmtpMlsLocalContext { /// XMTP Identity pub(crate) identity: Identity, /// XMTP Local Storage - pub(crate) store: EncryptedMessageStore, + store: EncryptedMessageStore, pub(crate) mutexes: MutexRegistry, } @@ -254,6 +254,10 @@ impl XmtpMlsLocalContext { self.identity.sequence_id(conn) } + pub fn store(&self) -> &EncryptedMessageStore { + &self.store + } + /// Pulls a new database connection and creates a new provider pub fn mls_provider(&self) -> Result { Ok(self.store.conn()?.into()) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 3349de508..3cd6fd57b 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -263,7 +263,7 @@ impl MlsGroup { /// Instantiate a new [`XmtpOpenMlsProvider`] pulling a connection from the database. /// prefer to use an already-instantiated mls provider if possible. pub fn mls_provider(&self) -> Result { - Ok(self.context.store.conn()?.into()) + Ok(self.context.mls_provider()?) } // Load the stored MLS group from the OpenMLS provider's keystore @@ -287,7 +287,7 @@ impl MlsGroup { permissions_policy_set: PolicySet, opts: GroupMetadataOptions, ) -> Result { - let conn = context.store.conn()?; + let conn = context.store().conn()?; let provider = XmtpOpenMlsProvider::new(conn); let protected_metadata = build_protected_metadata_extension(&context.identity, Purpose::Conversation)?; @@ -407,7 +407,7 @@ impl MlsGroup { pub(crate) fn create_and_insert_sync_group( context: Arc, ) -> Result { - let conn = context.store.conn()?; + let conn = context.store().conn()?; // let my_sequence_id = context.inbox_sequence_id(&conn)?; let provider = XmtpOpenMlsProvider::new(conn); let protected_metadata = @@ -458,7 +458,7 @@ impl MlsGroup { ApiClient: XmtpApi, { let update_interval_ns = Some(SEND_MESSAGE_UPDATE_INSTALLATIONS_INTERVAL_NS); - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let provider = XmtpOpenMlsProvider::from(conn); self.maybe_update_installations(&provider, update_interval_ns, client) .await?; @@ -481,7 +481,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let provider = XmtpOpenMlsProvider::from(conn); let update_interval_ns = Some(SEND_MESSAGE_UPDATE_INSTALLATIONS_INTERVAL_NS); self.maybe_update_installations(&provider, update_interval_ns, client) @@ -499,7 +499,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let provider = XmtpOpenMlsProvider::from(conn); self.maybe_update_installations(&provider, Some(0), client) .await?; @@ -508,7 +508,7 @@ impl MlsGroup { /// Send a message, optimistically returning the ID of the message before the result of a message publish. pub fn send_message_optimistic(&self, message: &[u8]) -> Result, GroupError> { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let message_id = self.prepare_message(message, &conn, |now| Self::into_envelope(message, now))?; Ok(message_id) @@ -578,7 +578,7 @@ impl MlsGroup { delivery_status: Option, limit: Option, ) -> Result, GroupError> { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let messages = conn.get_group_messages( &self.group_id, sent_after_ns, @@ -704,7 +704,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let intent_data: Vec = UpdateMetadataIntentData::new_update_group_name(group_name).into(); let intent = conn.insert_group_intent(NewGroupIntent::new( @@ -770,7 +770,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let intent_data: Vec = UpdateMetadataIntentData::new_update_group_description(group_description).into(); let intent = conn.insert_group_intent(NewGroupIntent::new( @@ -804,7 +804,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let intent_data: Vec = UpdateMetadataIntentData::new_update_group_image_url_square(group_image_url_square) .into(); @@ -842,7 +842,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let intent_data: Vec = UpdateMetadataIntentData::new_update_group_pinned_frame_url(pinned_frame_url).into(); let intent = conn.insert_group_intent(NewGroupIntent::new( @@ -911,7 +911,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let intent_action_type = match action_type { UpdateAdminListType::Add => AdminListActionType::Add, UpdateAdminListType::Remove => AdminListActionType::Remove, @@ -932,7 +932,7 @@ impl MlsGroup { /// Find the `inbox_id` of the group member who added the member to the group pub fn added_by_inbox_id(&self) -> Result { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; conn.find_group(self.group_id.clone()) .map_err(GroupError::from) .and_then(|fetch_result| { @@ -947,7 +947,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let intent = conn.insert_group_intent(NewGroupIntent::new( IntentKind::KeyUpdate, self.group_id.clone(), @@ -978,7 +978,7 @@ impl MlsGroup { } pub fn permissions(&self) -> Result { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let provider = XmtpOpenMlsProvider::new(conn); let mls_group = self.load_mls_group(&provider)?; @@ -1297,19 +1297,20 @@ pub(crate) mod tests { group_mutable_metadata::MetadataField, intents::{PermissionPolicyOption, PermissionUpdateType}, members::{GroupMember, PermissionLevel}, - DeliveryStatus, GroupMetadataOptions, PreconfiguredPolicies, UpdateAdminListType, + DeliveryStatus, GroupError, GroupMetadataOptions, PreconfiguredPolicies, + UpdateAdminListType, }, storage::{ group_intent::{IntentKind, IntentState, NewGroupIntent}, group_message::{GroupMessageKind, StoredGroupMessage}, }, xmtp_openmls_provider::XmtpOpenMlsProvider, - Client, InboxOwner, XmtpApi, + Client, InboxOwner, StreamHandle as _, XmtpApi, }; use super::{ intents::{Installation, SendWelcomesAction}, - GroupError, MlsGroup, + MlsGroup, }; async fn receive_group_invite(client: &Client) -> MlsGroup @@ -1548,13 +1549,13 @@ pub(crate) mod tests { .expect_err("expected error"); // Check Amal's MLS group state. - let amal_db = XmtpOpenMlsProvider::from(amal.context.store.conn().unwrap()); + let amal_db = XmtpOpenMlsProvider::from(amal.context.store().conn().unwrap()); let amal_mls_group = amal_group.load_mls_group(&amal_db).unwrap(); let amal_members: Vec = amal_mls_group.members().collect(); assert_eq!(amal_members.len(), 3); // Check Bola's MLS group state. - let bola_db = XmtpOpenMlsProvider::from(bola.context.store.conn().unwrap()); + let bola_db = XmtpOpenMlsProvider::from(bola.context.store().conn().unwrap()); let bola_mls_group = bola_group.load_mls_group(&bola_db).unwrap(); let bola_members: Vec = bola_mls_group.members().collect(); assert_eq!(bola_members.len(), 3); @@ -1763,7 +1764,7 @@ pub(crate) mod tests { .unwrap(); assert_eq!(messages.len(), 2); - let provider: XmtpOpenMlsProvider = client.context.store.conn().unwrap().into(); + let provider: XmtpOpenMlsProvider = client.context.store().conn().unwrap().into(); let mls_group = group.load_mls_group(&provider).unwrap(); let pending_commit = mls_group.pending_commit(); assert!(pending_commit.is_none()); @@ -1938,7 +1939,7 @@ pub(crate) mod tests { assert_eq!(group.members().unwrap().len(), 2); - let provider: XmtpOpenMlsProvider = amal.context.store.conn().unwrap().into(); + let provider: XmtpOpenMlsProvider = amal.context.store().conn().unwrap().into(); // Finished with setup // add a second installation for amal using the same wallet @@ -2966,6 +2967,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + // #[cfg(not(target_arch = "wasm32"))] async fn process_messages_abort_on_retryable_error() { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2998,10 +3000,14 @@ pub(crate) mod tests { .unwrap(); let conn_1: XmtpOpenMlsProvider = bo.store().conn().unwrap().into(); - let mut conn_2 = bo.store().raw_conn().unwrap(); + let conn_2 = bo.store().conn().unwrap(); + conn_2 + .raw_query(|c| { + c.batch_execute("BEGIN EXCLUSIVE").unwrap(); + Ok::<_, diesel::result::Error>(()) + }) + .unwrap(); - // Begin an exclusive transaction on a second connection to lock the database - conn_2.batch_execute("BEGIN EXCLUSIVE").unwrap(); let process_result = bo_group.process_messages(bo_messages, &conn_1, &bo).await; if let Some(GroupError::ReceiveErrors(errors)) = process_result.err() { assert_eq!(errors.len(), 1); @@ -3035,7 +3041,7 @@ pub(crate) mod tests { let client_clone = alix1.clone(); // Each of these syncs is going to trigger the client to invite alix2 to the group // because of the race - crate::spawn(async move { group_clone.sync(&client_clone).await }) + crate::spawn(None, async move { group_clone.sync(&client_clone).await }).join() }) .collect(); diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index 65659deee..1aa67f282 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -7,7 +7,7 @@ use super::{extract_message_v1, GroupError, MlsGroup}; use crate::storage::group_message::StoredGroupMessage; use crate::storage::refresh_state::EntityKind; use crate::storage::StorageError; -use crate::subscriptions::{MessagesStreamInfo, StreamHandle}; +use crate::subscriptions::MessagesStreamInfo; use crate::XmtpApi; use crate::{retry::Retry, retry_async, Client}; use prost::Message; @@ -39,7 +39,7 @@ impl MlsGroup { let client_id = client_id.clone(); let msgv1 = msgv1.clone(); self.context - .store + .store() .transaction_async(|provider| async move { let mut openmls_group = self.load_mls_group(&provider)?; @@ -85,7 +85,7 @@ impl MlsGroup { // another thread let new_message = self .context - .store + .store() .conn()? .get_group_message_by_timestamp(&self.group_id, created_ns as i64)?; @@ -95,7 +95,7 @@ impl MlsGroup { // Checks if a message has already been processed through a sync async fn has_already_synced(&self, id: u64) -> Result { let check_for_last_cursor = || -> Result { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; conn.get_last_cursor_for_id(&self.group_id, EntityKind::Group) }; @@ -141,7 +141,7 @@ impl MlsGroup { group_id: Vec, created_at_ns: i64, callback: impl FnMut(StoredGroupMessage) + Send + 'static, - ) -> StreamHandle> + ) -> impl crate::StreamHandle> where ApiClient: crate::XmtpApi + 'static, { @@ -165,7 +165,7 @@ pub(crate) mod tests { wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); use super::*; - use std::time::Duration; + use core::time::Duration; use tokio_stream::wrappers::UnboundedReceiverStream; use xmtp_cryptography::utils::generate_local_wallet; @@ -244,7 +244,7 @@ pub(crate) mod tests { let notify_ptr = notify.clone(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let mut stream = UnboundedReceiverStream::new(rx); - crate::spawn(async move { + crate::spawn(None, async move { let stream = bola_group_ptr.stream(&bola_ptr).await.unwrap(); futures::pin_mut!(stream); while let Some(item) = stream.next().await { @@ -293,7 +293,7 @@ pub(crate) mod tests { let stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); let amal_ptr = amal.clone(); let group_ptr = group.clone(); - crate::spawn(async move { + crate::spawn(None, async move { let stream = group_ptr.stream(&amal_ptr).await.unwrap(); futures::pin_mut!(stream); while let Some(item) = stream.next().await { @@ -340,7 +340,7 @@ pub(crate) mod tests { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let (start_tx, start_rx) = tokio::sync::oneshot::channel(); let mut stream = UnboundedReceiverStream::new(rx); - crate::spawn(async move { + crate::spawn(None, async move { let stream = amal_group_ptr.stream(&amal_ptr).await.unwrap(); let _ = start_tx.send(()); futures::pin_mut!(stream); @@ -352,7 +352,7 @@ pub(crate) mod tests { // just to make sure stream is started let _ = start_rx.await; // Adding in a sleep, since the HTTP API client may acknowledge requests before they are ready - crate::sleep(tokio::time::Duration::from_millis(100)).await; + crate::sleep(core::time::Duration::from_millis(100)).await; amal_group .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index 5b769f103..5c846bf1a 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -89,7 +89,7 @@ impl MlsGroup { where ApiClient: XmtpApi, { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let mls_provider = XmtpOpenMlsProvider::from(conn); log::info!("[{}] syncing group", client.inbox_id()); @@ -1329,7 +1329,7 @@ pub(crate) mod tests { amal_group.send_message_optimistic(b"5").unwrap(); amal_group.send_message_optimistic(b"6").unwrap(); - let conn = amal.context().store.conn().unwrap(); + let conn = amal.context().store().conn().unwrap(); let provider: XmtpOpenMlsProvider = conn.into(); let mut futures = vec![]; diff --git a/xmtp_mls/src/identity.rs b/xmtp_mls/src/identity.rs index 1b21f1f21..6fbe26af1 100644 --- a/xmtp_mls/src/identity.rs +++ b/xmtp_mls/src/identity.rs @@ -367,7 +367,7 @@ impl Identity { pub(crate) fn new_key_package( &self, - provider: impl OpenMlsProvider, + provider: impl OpenMlsProvider>, ) -> Result { let last_resort = Extension::LastResort(LastResortExtension::default()); let key_package_extensions = Extensions::single(last_resort); diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index f0d695075..8d50a808e 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -13,6 +13,7 @@ mod identity_updates; mod mutex_registry; pub mod retry; pub mod storage; +mod stream_handles; pub mod subscriptions; pub mod types; pub mod utils; @@ -20,9 +21,7 @@ pub mod verified_key_package_v2; mod xmtp_openmls_provider; pub use client::{Client, Network}; -use std::future::Future; use storage::StorageError; -use tokio::task::JoinHandle; pub use trait_impls::*; /// XMTP Api Super Trait @@ -177,33 +176,19 @@ pub trait Delete { fn delete(&self, key: Self::Key) -> Result; } -#[cfg(target_arch = "wasm32")] -fn spawn(future: F) -> JoinHandle -where - F: Future + 'static, - F::Output: 'static, -{ - tokio::task::spawn_local(future) -} - -#[cfg(not(target_arch = "wasm32"))] -fn spawn(future: F) -> JoinHandle -where - F: Future + Send + 'static, - F::Output: 'static + Send, -{ - tokio::task::spawn(future) -} +pub use stream_handles::{ + spawn, AbortHandle, GenericStreamHandle, StreamHandle, StreamHandleError, +}; #[cfg(target_arch = "wasm32")] #[doc(hidden)] -pub async fn sleep(duration: std::time::Duration) { +pub async fn sleep(duration: core::time::Duration) { gloo_timers::future::TimeoutFuture::new(duration.as_millis() as u32).await; } #[cfg(not(target_arch = "wasm32"))] #[doc(hidden)] -pub async fn sleep(duration: std::time::Duration) { +pub async fn sleep(duration: core::time::Duration) { tokio::time::sleep(duration).await } diff --git a/xmtp_mls/src/retry.rs b/xmtp_mls/src/retry.rs index 1359b649f..50ac52752 100644 --- a/xmtp_mls/src/retry.rs +++ b/xmtp_mls/src/retry.rs @@ -16,8 +16,6 @@ //! } //! ``` -use std::time::Duration; - use rand::Rng; /// Specifies which errors are retryable. @@ -30,7 +28,7 @@ pub trait RetryableError: std::error::Error { #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct Retry { retries: usize, - duration: std::time::Duration, + duration: core::time::Duration, // The amount to multiply the duration on each subsequent attempt multiplier: u32, max_jitter_ms: usize, @@ -40,7 +38,7 @@ impl Default for Retry { fn default() -> Self { Self { retries: 5, - duration: std::time::Duration::from_millis(50), + duration: core::time::Duration::from_millis(50), multiplier: 3, max_jitter_ms: 25, } @@ -56,14 +54,14 @@ impl Retry { /// Get the duration to wait between retries. /// Multiples the duration by the multiplier for each subsequent attempt /// and adds a random jitter to avoid repeated collisions - pub fn duration(&self, attempts: usize) -> Duration { + pub fn duration(&self, attempts: usize) -> core::time::Duration { let mut duration = self.duration; for _ in 0..attempts - 1 { duration *= self.multiplier; } let jitter = rand::thread_rng().gen_range(0..=self.max_jitter_ms); - duration + Duration::from_millis(jitter as u64) + duration + core::time::Duration::from_millis(jitter as u64) } } @@ -71,7 +69,7 @@ impl Retry { #[derive(Default, PartialEq, Eq, Copy, Clone)] pub struct RetryBuilder { retries: Option, - duration: Option, + duration: Option, } /// Builder for [`Retry`]. @@ -82,7 +80,7 @@ pub struct RetryBuilder { /// /// RetryBuilder::default() /// .retries(5) -/// .duration(std::time::Duration::from_millis(1000)) +/// .duration(core::time::Duration::from_millis(1000)) /// .build(); /// ``` impl RetryBuilder { @@ -93,7 +91,7 @@ impl RetryBuilder { } /// Specify the duration to wait before retrying again - pub fn duration(mut self, duration: std::time::Duration) -> Self { + pub fn duration(mut self, duration: core::time::Duration) -> Self { self.duration = Some(duration); self } @@ -312,7 +310,7 @@ pub(crate) mod tests { return Ok(()); } // do some work - crate::sleep(std::time::Duration::from_nanos(100)).await; + crate::sleep(core::time::Duration::from_nanos(100)).await; Err(SomeError::ARetryableError) } @@ -338,7 +336,7 @@ pub(crate) mod tests { } *data += 1; // do some work - crate::sleep(std::time::Duration::from_nanos(100)).await; + crate::sleep(core::time::Duration::from_nanos(100)).await; Err(SomeError::ARetryableError) } diff --git a/xmtp_mls/src/storage/encrypted_store/association_state.rs b/xmtp_mls/src/storage/encrypted_store/association_state.rs index 72cabb530..06929aadc 100644 --- a/xmtp_mls/src/storage/encrypted_store/association_state.rs +++ b/xmtp_mls/src/storage/encrypted_store/association_state.rs @@ -128,8 +128,8 @@ pub(crate) mod tests { use super::*; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_batch_read() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_batch_read() { with_connection(|conn| { let association_state = AssociationState::new("1234".to_string(), 0); let inbox_id = association_state.inbox_id().clone(); @@ -175,5 +175,6 @@ pub(crate) mod tests { .unwrap(); assert_eq!(no_results.len(), 0); }) + .await } } diff --git a/xmtp_mls/src/storage/encrypted_store/consent_record.rs b/xmtp_mls/src/storage/encrypted_store/consent_record.rs index 8ecb9cc99..609aca1cb 100644 --- a/xmtp_mls/src/storage/encrypted_store/consent_record.rs +++ b/xmtp_mls/src/storage/encrypted_store/consent_record.rs @@ -1,5 +1,6 @@ use crate::{impl_store, storage::StorageError}; +use super::Sqlite; use super::{ db_connection::DbConnection, schema::consent_records::{self, dsl}, @@ -14,7 +15,6 @@ use diesel::{ upsert::excluded, }; use serde::{Deserialize, Serialize}; -use super::Sqlite; /// StoredConsentRecord holds a serialized ConsentRecord #[derive(Insertable, Queryable, Debug, Clone, PartialEq, Eq)] @@ -48,7 +48,7 @@ impl DbConnection { entity: String, entity_type: ConsentType, ) -> Result, StorageError> { - Ok(self.raw_query(|conn| { + Ok(self.raw_query(|conn| -> diesel::QueryResult<_> { dsl::consent_records .filter(dsl::entity.eq(entity)) .filter(dsl::entity_type.eq(entity_type)) @@ -62,7 +62,7 @@ impl DbConnection { &self, record: StoredConsentRecord, ) -> Result<(), StorageError> { - self.raw_query(|conn| { + self.raw_query(|conn| -> diesel::QueryResult<_> { diesel::insert_into(dsl::consent_records) .values(&record) .on_conflict((dsl::entity_type, dsl::entity)) @@ -165,8 +165,8 @@ mod tests { } } - #[test] - fn insert_and_read() { + #[tokio::test] + async fn insert_and_read() { with_connection(|conn| { let inbox_id = "inbox_1"; let consent_record = generate_consent_record( @@ -184,6 +184,7 @@ mod tests { .expect("query should work"); assert_eq!(consent_record.unwrap().entity, consent_record_entity); - }); + }) + .await; } } diff --git a/xmtp_mls/src/storage/encrypted_store/db_connection.rs b/xmtp_mls/src/storage/encrypted_store/db_connection.rs index 5e143c49d..e2ef9a970 100644 --- a/xmtp_mls/src/storage/encrypted_store/db_connection.rs +++ b/xmtp_mls/src/storage/encrypted_store/db_connection.rs @@ -1,9 +1,13 @@ +use crate::xmtp_openmls_provider::XmtpOpenMlsProvider; use parking_lot::Mutex; use std::fmt; use std::sync::Arc; -use crate::storage::RawDbConnection; -use crate::xmtp_openmls_provider::XmtpOpenMlsProvider; +#[cfg(not(target_arch = "wasm32"))] +pub type DbConnection = DbConnectionPrivate; + +#[cfg(target_arch = "wasm32")] +pub type DbConnection = DbConnectionPrivate; /// A wrapper for RawDbConnection that houses all XMTP DB operations. /// Uses a [`Mutex]` internally for interior mutability, so that the connection @@ -12,32 +16,44 @@ use crate::xmtp_openmls_provider::XmtpOpenMlsProvider; // ~~~~ _NOTE_ ~~~~~ // Do not derive clone here. // callers should be able to accomplish everything with one conn/reference. -pub struct DbConnection { - wrapped_conn: Arc>, +#[doc(hidden)] +pub struct DbConnectionPrivate { + inner: Arc>, } /// Owned DBConnection Methods -/// Lifetime is 'static' because we are using [`RefOrValue::Value`] variant. -impl DbConnection { - pub(super) fn new(conn: RawDbConnection) -> Self { - Self { - wrapped_conn: Arc::new(Mutex::new(conn)), - } - } - - pub(super) fn from_arc_mutex(conn: Arc>) -> Self { - Self { wrapped_conn: conn } +impl DbConnectionPrivate { + /// Create a new [`DbConnectionPrivate`] from an existing Arc> + pub(super) fn from_arc_mutex(conn: Arc>) -> Self { + Self { inner: conn } } +} - // Note: F is a synchronous fn. If it ever becomes async, we need to use - // tokio::sync::mutex instead of std::sync::Mutex - pub(crate) fn raw_query(&self, fun: F) -> Result +impl DbConnectionPrivate +where + C: diesel::Connection, +{ + /// Do a scoped query with a mutable [`diesel::Connection`] + /// reference + pub(crate) fn raw_query(&self, fun: F) -> Result where - F: FnOnce(&mut RawDbConnection) -> Result, + F: FnOnce(&mut C) -> Result, { - let mut lock = self.wrapped_conn.lock(); + let mut lock = self.inner.lock(); fun(&mut lock) } + + /// Internal-only API to get the underlying `diesel::Connection` reference + /// without a scope + /// Must be used with care. holding this reference while calling `raw_query` + /// will cause a deadlock. + pub(super) fn inner_mut_ref(&self) -> parking_lot::MutexGuard<'_, C> { + self.inner.lock() + } + + pub(super) fn inner_ref(&self) -> Arc> { + self.inner.clone() + } } // Forces a move for conn @@ -51,7 +67,7 @@ impl From for XmtpOpenMlsProvider { } } -impl fmt::Debug for DbConnection { +impl fmt::Debug for DbConnectionPrivate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DbConnection") .field("wrapped_conn", &"DbConnection") diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index 482dbe2e2..00cbf3d43 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -191,7 +191,7 @@ impl DbConnection { .select(dsl::installations_last_checked) .first(conn) .optional()?; - Ok(ts) + Ok::<_, diesel::result::Error>(ts) })?; last_ts.ok_or(StorageError::NotFound(format!( @@ -338,8 +338,8 @@ pub(crate) mod tests { } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_it_stores_group() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_it_stores_group() { with_connection(|conn| { let test_group = generate_group(None); @@ -350,11 +350,12 @@ pub(crate) mod tests { test_group ); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_it_fetches_group() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_it_fetches_group() { with_connection(|conn| { let test_group = generate_group(None); @@ -368,11 +369,12 @@ pub(crate) mod tests { let fetched_group: Option = conn.fetch(&test_group.id).unwrap(); assert_eq!(fetched_group, Some(test_group)); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_it_updates_group_membership_state() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_it_updates_group_membership_state() { with_connection(|conn| { let test_group = generate_group(Some(GroupMembershipState::Pending)); @@ -389,10 +391,11 @@ pub(crate) mod tests { } ); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_find_groups() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_find_groups() { with_connection(|conn| { let test_group_1 = generate_group(Some(GroupMembershipState::Pending)); test_group_1.store(conn).unwrap(); @@ -425,11 +428,12 @@ pub(crate) mod tests { // test that ONLY normal groups show up. }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_installations_last_checked_is_updated() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_installations_last_checked_is_updated() { with_connection(|conn| { let test_group = generate_group(None); test_group.store(conn).unwrap(); @@ -447,11 +451,12 @@ pub(crate) mod tests { assert_ne!(fetched_group.installations_last_checked, 0); assert!(fetched_group.created_at_ns < fetched_group.installations_last_checked); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_new_group_has_correct_purpose() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_new_group_has_correct_purpose() { with_connection(|conn| { let test_group = generate_group(None); @@ -467,11 +472,12 @@ pub(crate) mod tests { let purpose = fetched_group.unwrap().purpose; assert_eq!(purpose, Purpose::Conversation); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_new_sync_group() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_new_sync_group() { with_connection(|conn| { let id = rand_vec(); let created_at_ns = now_ns(); @@ -487,5 +493,6 @@ pub(crate) mod tests { assert_eq!(found.len(), 1); assert_eq!(found[0].purpose, Purpose::Sync) }) + .await } } diff --git a/xmtp_mls/src/storage/encrypted_store/group_intent.rs b/xmtp_mls/src/storage/encrypted_store/group_intent.rs index 89d895529..0bd44a675 100644 --- a/xmtp_mls/src/storage/encrypted_store/group_intent.rs +++ b/xmtp_mls/src/storage/encrypted_store/group_intent.rs @@ -439,8 +439,8 @@ pub(crate) mod tests { } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_store_and_fetch() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_store_and_fetch() { let group_id = rand_vec(); let data = rand_vec(); let kind = IntentKind::UpdateGroupMembership; @@ -469,11 +469,12 @@ pub(crate) mod tests { assert_eq!(fetched.id, id); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_query() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_query() { let group_id = rand_vec(); let test_intents: Vec = vec![ @@ -548,11 +549,12 @@ pub(crate) mod tests { results = conn.find_group_intents(group_id, None, None).unwrap(); assert_eq!(results.len(), 3); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn find_by_payload_hash() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn find_by_payload_hash() { let group_id = rand_vec(); with_connection(|conn| { @@ -590,11 +592,12 @@ pub(crate) mod tests { assert_eq!(find_result.id, intent.id); assert_eq!(find_result.published_in_epoch, Some(1)); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_happy_path_state_transitions() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_happy_path_state_transitions() { let group_id = rand_vec(); with_connection(|conn| { @@ -635,11 +638,12 @@ pub(crate) mod tests { // Make sure we haven't lost the payload hash assert_eq!(intent.payload_hash, Some(payload_hash.clone())); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_republish_state_transition() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_republish_state_transition() { let group_id = rand_vec(); with_connection(|conn| { @@ -679,11 +683,12 @@ pub(crate) mod tests { assert!(intent.payload_hash.is_none()); assert!(intent.post_commit_data.is_none()); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_invalid_state_transition() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_invalid_state_transition() { let group_id = rand_vec(); with_connection(|conn| { @@ -714,11 +719,12 @@ pub(crate) mod tests { StorageError::NotFound(_) )); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_increment_publish_attempts() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_increment_publish_attempts() { let group_id = rand_vec(); with_connection(|conn| { insert_group(conn, group_id.clone()); @@ -741,5 +747,6 @@ pub(crate) mod tests { intent = find_first_intent(conn, group_id.clone()); assert_eq!(intent.publish_attempts, 2); }) + .await } } diff --git a/xmtp_mls/src/storage/encrypted_store/group_message.rs b/xmtp_mls/src/storage/encrypted_store/group_message.rs index db0e83e16..d4c3bc705 100644 --- a/xmtp_mls/src/storage/encrypted_store/group_message.rs +++ b/xmtp_mls/src/storage/encrypted_store/group_message.rs @@ -234,17 +234,18 @@ pub(crate) mod tests { } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn it_does_not_error_on_empty_messages() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn it_does_not_error_on_empty_messages() { with_connection(|conn| { let id = vec![0x0]; assert_eq!(conn.get_group_message(id).unwrap(), None); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn it_gets_messages() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn it_gets_messages() { with_connection(|conn| { let group = generate_group(None); let message = generate_message(None, Some(&group.id), None); @@ -256,11 +257,12 @@ pub(crate) mod tests { let stored_message = conn.get_group_message(id); assert_eq!(stored_message.unwrap(), Some(message)); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn it_cannot_insert_message_without_group() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn it_cannot_insert_message_without_group() { use diesel::result::{DatabaseErrorKind::ForeignKeyViolation, Error::DatabaseError}; with_connection(|conn| { @@ -270,11 +272,12 @@ pub(crate) mod tests { StorageError::DieselResult(DatabaseError(ForeignKeyViolation, _)) ); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn it_gets_many_messages() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn it_gets_many_messages() { use crate::storage::encrypted_store::schema::group_messages::dsl; with_connection(|conn| { @@ -305,11 +308,12 @@ pub(crate) mod tests { msg.sent_at_ns }); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn it_gets_messages_by_time() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn it_gets_messages_by_time() { with_connection(|conn| { let group = generate_group(None); group.store(conn).unwrap(); @@ -337,11 +341,12 @@ pub(crate) mod tests { .unwrap(); assert_eq!(messages.len(), 2); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn it_gets_messages_by_kind() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn it_gets_messages_by_kind() { with_connection(|conn| { let group = generate_group(None); group.store(conn).unwrap(); @@ -392,5 +397,6 @@ pub(crate) mod tests { .unwrap(); assert_eq!(membership_changes.len(), 15); }) + .await } } diff --git a/xmtp_mls/src/storage/encrypted_store/identity.rs b/xmtp_mls/src/storage/encrypted_store/identity.rs index e583c8cbb..edf912d30 100644 --- a/xmtp_mls/src/storage/encrypted_store/identity.rs +++ b/xmtp_mls/src/storage/encrypted_store/identity.rs @@ -71,12 +71,13 @@ pub(crate) mod tests { use crate::{utils::test::rand_vec, Store}; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn can_only_store_one_identity() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn can_only_store_one_identity() { let store = EncryptedMessageStore::new( StorageOption::Ephemeral, EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn = &store.conn().unwrap(); diff --git a/xmtp_mls/src/storage/encrypted_store/identity_update.rs b/xmtp_mls/src/storage/encrypted_store/identity_update.rs index 52315b71d..fdf460fd3 100644 --- a/xmtp_mls/src/storage/encrypted_store/identity_update.rs +++ b/xmtp_mls/src/storage/encrypted_store/identity_update.rs @@ -86,7 +86,7 @@ impl DbConnection { .values(updates) .execute(conn)?; - Ok(()) + Ok::<_, diesel::result::Error>(()) })?) } @@ -147,8 +147,8 @@ pub(crate) mod tests { } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn insert_and_read() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn insert_and_read() { with_connection(|conn| { let inbox_id = "inbox_1"; let update_1 = build_update(inbox_id, 1); @@ -168,12 +168,13 @@ pub(crate) mod tests { assert_eq!(first_update.payload, update_1_payload); let second_update = all_updates.last().unwrap(); assert_eq!(second_update.payload, update_2_payload); - }); + }) + .await; } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_filter() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_filter() { with_connection(|conn| { let inbox_id = "inbox_1"; let update_1 = build_update(inbox_id, 1); @@ -202,11 +203,12 @@ pub(crate) mod tests { assert_eq!(only_update_2.len(), 1); assert_eq!(only_update_2[0].sequence_id, 2); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_get_latest_sequence_id() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_get_latest_sequence_id() { with_connection(|conn| { let inbox_1 = "inbox_1"; let inbox_2 = "inbox_2"; @@ -238,11 +240,12 @@ pub(crate) mod tests { None ); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn get_single_sequence_id() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn get_single_sequence_id() { with_connection(|conn| { let inbox_id = "inbox_1"; let update = build_update(inbox_id, 1); @@ -255,5 +258,6 @@ pub(crate) mod tests { .expect("query should work"); assert_eq!(sequence_id, 2); }) + .await } } diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 9511a27b8..2e4971aac 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -19,52 +19,47 @@ pub mod group_message; pub mod identity; pub mod identity_update; pub mod key_store_entry; +#[cfg(not(target_arch = "wasm32"))] +mod native; pub mod refresh_state; pub mod schema; #[cfg(not(target_arch = "wasm32"))] mod sqlcipher_connection; +#[cfg(target_arch = "wasm32")] +mod wasm; -use std::sync::Arc; - +pub use self::db_connection::DbConnection; +#[cfg(not(target_arch = "wasm32"))] +pub use self::native::SqliteConnection; +#[cfg(target_arch = "wasm32")] +pub use self::wasm::SqliteConnection; +use super::StorageError; +use crate::{xmtp_openmls_provider::XmtpOpenMlsProviderPrivate, Store}; +use db_connection::DbConnectionPrivate; +#[cfg(not(target_arch = "wasm32"))] +pub use diesel::sqlite::Sqlite; use diesel::{ - connection::{AnsiTransactionManager, SimpleConnection, TransactionManager}, + connection::{LoadConnection, TransactionManager}, + migration::MigrationConnection, prelude::*, - r2d2::{self, PoolTransactionManager, CustomizeConnection, Error as R2Error}, result::{DatabaseErrorKind, Error}, sql_query, }; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; -use parking_lot::RwLock; - -#[cfg(not(target_arch = "wasm32"))] -pub use diesel::sqlite::Sqlite; #[cfg(target_arch = "wasm32")] pub use diesel_wasm_sqlite::WasmSqlite as Sqlite; - #[cfg(not(target_arch = "wasm32"))] -pub use diesel::sqlite::SqliteConnection; -#[cfg(target_arch = "wasm32")] -pub use diesel_wasm_sqlite::connection::WasmSqliteConnection as SqliteConnection; - - -use self::db_connection::DbConnection; - -#[cfg(not(target_arch = "wasm32"))] -pub use self::sqlcipher_connection::EncryptedConnection; - -use super::StorageError; -use crate::{xmtp_openmls_provider::XmtpOpenMlsProvider, Store}; +pub use sqlcipher_connection::EncryptedConnection; +use std::sync::Arc; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations/"); -#[cfg(not(target_arch = "wasm32"))] -pub type ConnectionManager = r2d2::ConnectionManager; #[cfg(target_arch = "wasm32")] -pub type ConnectionManager = - r2d2::ConnectionManager; +pub use diesel_wasm_sqlite::connection::WasmSqliteConnection as RawDbConnection; +#[cfg(not(target_arch = "wasm32"))] +pub use native::RawDbConnection; -pub type RawDbConnection = r2d2::PooledConnection; -pub type Pool = r2d2::Pool; +pub type EncryptionKey = [u8; 32]; // For PRAGMA query log statements #[derive(QueryableByName, Debug)] @@ -90,327 +85,248 @@ pub enum StorageOption { Persistent(String), } -#[cfg(not(target_arch = "wasm32"))] -impl StorageOption { - // create a completely new standalone connection - fn conn(&self) -> Result { - use StorageOption::*; - match self { - Persistent(path) => SqliteConnection::establish(path), - Ephemeral => SqliteConnection::establish(":memory:"), - } - } -} +/// Global Marker trait for WebAssembly +#[cfg(target_arch = "wasm32")] +pub trait Wasm {} +#[cfg(target_arch = "wasm32")] +impl Wasm for T {} + +#[allow(async_fn_in_trait)] +pub trait XmtpDb { + type Connection: diesel::Connection + + diesel::connection::SimpleConnection + + LoadConnection + + MigrationConnection + + MigrationHarness<::Backend> + + Send; + type TransactionManager: diesel::connection::TransactionManager; -/// An Unencrypted Connection -/// Creates a Sqlite3 Database/Connection in WAL mode. -/// Sets `busy_timeout` on each connection. -/// _*NOTE:*_Unencrypted Connections are not validated and mostly meant for testing. -/// It is not recommended to use an unencrypted connection in production. -#[derive(Clone, Debug)] -pub struct UnencryptedConnection; -impl ValidatedConnection for UnencryptedConnection {} - -impl CustomizeConnection - for UnencryptedConnection -{ - fn on_acquire(&self, conn: &mut SqliteConnection) -> Result<(), R2Error> { - conn.batch_execute("PRAGMA busy_timeout = 5000;") - .map_err(R2Error::QueryError)?; + fn validate(&self, _opts: &StorageOption) -> Result<(), StorageError> { Ok(()) } -} - - -pub type EncryptionKey = [u8; 32]; -trait XmtpConnection: ValidatedConnection + CustomizeConnection + dyn_clone::DynClone + IntoSuper> {} -impl XmtpConnection for T where T: ValidatedConnection + CustomizeConnection + dyn_clone::DynClone + IntoSuper> {} -dyn_clone::clone_trait_object!(XmtpConnection); + /// Returns the Connection implementation for this Database + fn conn(&self) -> Result, StorageError>; -// we can remove this once https://github.com/rust-lang/rust/issues/65991 -// is merged, which should be happening soon (next ~2 releases) -trait IntoSuper { - fn into_super(self: Box) -> Box; -} + fn reconnect(&self) -> Result<(), StorageError>; -impl> IntoSuper> for T { - fn into_super(self: Box) -> Box> { self } + fn release_connection(&self) -> Result<(), StorageError>; } -trait ValidatedConnection { - fn validate(&self, _opts: &StorageOption) -> Result<(), StorageError> { - Ok(()) - } -} - -#[allow(dead_code)] -#[derive(Clone, Debug)] -/// Manages a Sqlite db for persisting messages and other objects. -pub struct EncryptedMessageStore { - connect_opt: StorageOption, - pool: Arc>>, - enc_key: Option, - customizer: Option> -} +#[cfg(not(target_arch = "wasm32"))] +pub type EncryptedMessageStore = self::private::EncryptedMessageStore; +#[cfg(not(target_arch = "wasm32"))] impl EncryptedMessageStore { - pub fn new(opts: StorageOption, enc_key: EncryptionKey) -> Result { + pub async fn new(opts: StorageOption, enc_key: EncryptionKey) -> Result { Self::new_database(opts, Some(enc_key)) } - pub fn new_unencrypted(opts: StorageOption) -> Result { + pub async fn new_unencrypted(opts: StorageOption) -> Result { Self::new_database(opts, None) } /// This function is private so that an unencrypted database cannot be created by accident - #[cfg(not(target_arch = "wasm32"))] fn new_database( opts: StorageOption, enc_key: Option, ) -> Result { log::info!("Setting up DB connection pool"); - let mut builder = Pool::builder(); - - let customizer = if let Some(key) = enc_key { - let enc_opts = EncryptedConnection::new(key, &opts)?; - builder = builder.connection_customizer(Box::new(enc_opts.clone())); - Some(Box::new(enc_opts) as Box) - } else if matches!(opts, StorageOption::Persistent(_)) { - builder = builder.connection_customizer(Box::new(UnencryptedConnection)); - Some(Box::new(UnencryptedConnection) as Box) - } else { - None - }; - - let pool = match opts { - StorageOption::Ephemeral => builder - .max_size(1) - .build(ConnectionManager::new(":memory:"))?, - StorageOption::Persistent(ref path) => builder - .max_size(25) - .build(ConnectionManager::new(path))?, - }; - - let mut this = Self { - connect_opt: opts, - pool: Arc::new(Some(pool).into()), - enc_key, - customizer, - }; - + let db = native::NativeDb::new(&opts, enc_key)?; + let mut this = Self { db, opts }; this.init_db()?; Ok(this) } +} - #[cfg(target_arch = "wasm32")] - fn new_database( +#[cfg(target_arch = "wasm32")] +pub type EncryptedMessageStore = self::private::EncryptedMessageStore; + +#[cfg(target_arch = "wasm32")] +impl EncryptedMessageStore { + pub async fn new(opts: StorageOption, enc_key: EncryptionKey) -> Result { + Self::new_database(opts, Some(enc_key)).await + } + + pub async fn new_unencrypted(opts: StorageOption) -> Result { + Self::new_database(opts, None).await + } + + /// This function is private so that an unencrypted database cannot be created by accident + async fn new_database( opts: StorageOption, enc_key: Option, ) -> Result { log::info!("Setting up DB connection pool"); - let builder = Pool::builder(); - - let pool = match opts { - StorageOption::Ephemeral => builder - .max_size(1) - .build(ConnectionManager::new(":memory:"))?, - StorageOption::Persistent(ref path) => builder - .max_size(1) - .build(ConnectionManager::new(path))?, - }; - - let mut this = Self { - connect_opt: opts, - pool: Arc::new(Some(pool).into()), - customizer: None, - enc_key - }; - + let db = wasm::WasmDb::new(&opts, enc_key).await?; + let mut this = Self { db, opts }; this.init_db()?; Ok(this) } +} - fn init_db(&mut self) -> Result<(), StorageError> { - if let Some(ref encrypted_conn) = self.customizer { - encrypted_conn.validate(&self.connect_opt)?; - } - - let conn = &mut self.raw_conn()?; - conn.batch_execute("PRAGMA journal_mode = WAL;")?; - log::info!("Running DB migrations"); - conn.run_pending_migrations(MIGRATIONS) - .map_err(|e| StorageError::DbInit(format!("Failed to run migrations: {}", e)))?; - - let sqlite_version = - sql_query("SELECT sqlite_version() AS version").load::(conn)?; - log::info!("sqlite_version={}", sqlite_version[0].version); - - log::info!("Migrations successful"); - Ok(()) - } - - pub(crate) fn raw_conn(&self) -> Result { - let pool_guard = self.pool.read(); - - let pool = pool_guard - .as_ref() - .ok_or(StorageError::PoolNeedsConnection)?; - - log::debug!( - "Pulling connection from pool, idle_connections={}, total_connections={}", - pool.state().idle_connections, - pool.state().connections - ); - - Ok(pool.get()?) - } - - pub fn conn(&self) -> Result { - let conn = self.raw_conn()?; - Ok(DbConnection::new(conn)) - } - - /// Start a new database transaction with the OpenMLS Provider from XMTP - /// # Arguments - /// `fun`: Scoped closure providing a MLSProvider to carry out the transaction - /// - /// # Examples - /// - /// ```ignore - /// store.transaction(|provider| { - /// // do some operations requiring provider - /// // access the connection with .conn() - /// provider.conn().db_operation()?; - /// }) - /// ``` - pub fn transaction(&self, fun: F) -> Result - where - F: FnOnce(&XmtpOpenMlsProvider) -> Result, - E: From + From, - { - log::debug!("Transaction beginning"); - let mut connection = self.raw_conn()?; - AnsiTransactionManager::begin_transaction(&mut *connection)?; - - let db_connection = DbConnection::new(connection); - let provider = XmtpOpenMlsProvider::new(db_connection); - let conn = provider.conn_ref(); - - match fun(&provider) { - Ok(value) => { - conn.raw_query(|conn| { - PoolTransactionManager::::commit_transaction(&mut *conn) - })?; - log::debug!("Transaction being committed"); - Ok(value) - } - Err(err) => { - log::debug!("Transaction being rolled back"); - match conn.raw_query(|conn| { - PoolTransactionManager::::rollback_transaction( - &mut *conn, - ) - }) { - Ok(()) => Err(err), - Err(Error::BrokenTransactionManager) => Err(err), - Err(rollback) => Err(rollback.into()), - } - } - } +#[doc(hidden)] +pub mod private { + use super::*; + use diesel::connection::SimpleConnection; + use diesel_migrations::MigrationHarness; + + #[derive(Clone, Debug)] + /// Manages a Sqlite db for persisting messages and other objects. + pub struct EncryptedMessageStore { + pub(super) opts: StorageOption, + pub(super) db: Db, } - /// Start a new database transaction with the OpenMLS Provider from XMTP - /// # Arguments - /// `fun`: Scoped closure providing an [`XmtpOpenMLSProvider`] to carry out the transaction in - /// async context. - /// - /// # Examples - /// - /// ```ignore - /// store.transaction_async(|provider| async move { - /// // do some operations requiring provider - /// // access the connection with .conn() - /// provider.conn().db_operation()?; - /// }).await - /// ``` - pub async fn transaction_async(&self, fun: F) -> Result + impl EncryptedMessageStore where - F: FnOnce(XmtpOpenMlsProvider) -> Fut, - Fut: futures::Future>, - E: From + From, + Db: XmtpDb, { - log::debug!("Transaction async beginning"); - let mut connection = self.raw_conn()?; - AnsiTransactionManager::begin_transaction(&mut *connection)?; - let connection = Arc::new(parking_lot::Mutex::new(connection)); - let local_connection = Arc::clone(&connection); - let db_connection = DbConnection::from_arc_mutex(connection); - let provider = XmtpOpenMlsProvider::new(db_connection); - - // the other connection is dropped in the closure - // ensuring we have only one strong reference - let result = fun(provider).await; - if Arc::strong_count(&local_connection) > 1 { - log::warn!("More than 1 strong connection references still exist during transaction"); + pub(super) fn init_db(&mut self) -> Result<(), StorageError> { + self.db.validate(&self.opts)?; + self.db.conn()?.raw_query(|conn| { + conn.batch_execute("PRAGMA journal_mode = WAL;")?; + log::info!("Running DB migrations"); + conn.run_pending_migrations(MIGRATIONS)?; + + let sqlite_version = + sql_query("SELECT sqlite_version() AS version").load::(conn)?; + log::info!("sqlite_version={}", sqlite_version[0].version); + + log::info!("Migrations successful"); + Ok::<_, StorageError>(()) + })?; + Ok::<_, StorageError>(()) } - if Arc::weak_count(&local_connection) > 1 { - log::warn!("More than 1 weak connection references still exist during transaction"); + pub fn conn( + &self, + ) -> Result::Connection>, StorageError> { + self.db.conn() } - // after the closure finishes, `local_provider` should have the only reference ('strong') - // to `XmtpOpenMlsProvider` inner `DbConnection`.. - let local_connection = DbConnection::from_arc_mutex(local_connection); - match result { - Ok(value) => { - local_connection.raw_query(|conn| { - PoolTransactionManager::::commit_transaction(&mut *conn) - })?; - log::debug!("Transaction async being committed"); - Ok(value) + /// Start a new database transaction with the OpenMLS Provider from XMTP + /// # Arguments + /// `fun`: Scoped closure providing a MLSProvider to carry out the transaction + /// + /// # Examples + /// + /// ```ignore + /// store.transaction(|provider| { + /// // do some operations requiring provider + /// // access the connection with .conn() + /// provider.conn().db_operation()?; + /// }) + /// ``` + pub fn transaction(&self, fun: F) -> Result + where + F: FnOnce(&XmtpOpenMlsProviderPrivate<::Connection>) -> Result, + E: From + From, + { + log::debug!("Transaction beginning"); + let connection = self.db.conn()?; + { + let mut connection = connection.inner_mut_ref(); + ::TransactionManager::begin_transaction(&mut *connection)?; } - Err(err) => { - log::debug!("Transaction async being rolled back"); - match local_connection.raw_query(|conn| { - PoolTransactionManager::::rollback_transaction( - &mut *conn, - ) - }) { - Ok(()) => Err(err), - Err(Error::BrokenTransactionManager) => Err(err), - Err(rollback) => Err(rollback.into()), + + let provider = XmtpOpenMlsProviderPrivate::new(connection); + let conn = provider.conn_ref(); + + match fun(&provider) { + Ok(value) => { + conn.raw_query(|conn| { + ::TransactionManager::commit_transaction(&mut *conn) + })?; + log::debug!("Transaction being committed"); + Ok(value) + } + Err(err) => { + log::debug!("Transaction being rolled back"); + match conn.raw_query(|conn| { + ::TransactionManager::rollback_transaction(&mut *conn) + }) { + Ok(()) => Err(err), + Err(Error::BrokenTransactionManager) => Err(err), + Err(rollback) => Err(rollback.into()), + } } } } - } - pub fn release_connection(&self) -> Result<(), StorageError> { - let mut pool_guard = self.pool.write(); - pool_guard.take(); - Ok(()) - } + /// Start a new database transaction with the OpenMLS Provider from XMTP + /// # Arguments + /// `fun`: Scoped closure providing an [`XmtpOpenMLSProvider`] to carry out the transaction in + /// async context. + /// + /// # Examples + /// + /// ```ignore + /// store.transaction_async(|provider| async move { + /// // do some operations requiring provider + /// // access the connection with .conn() + /// provider.conn().db_operation()?; + /// }).await + /// ``` + pub async fn transaction_async(&self, fun: F) -> Result + where + F: FnOnce(XmtpOpenMlsProviderPrivate<::Connection>) -> Fut, + Fut: futures::Future>, + E: From + From, + { + log::debug!("Transaction async beginning"); + let db_connection = self.db.conn()?; + { + let mut connection = db_connection.inner_mut_ref(); + ::TransactionManager::begin_transaction(&mut *connection)?; + } + let local_connection = db_connection.inner_ref(); + let provider = XmtpOpenMlsProviderPrivate::new(db_connection); + + // the other connection is dropped in the closure + // ensuring we have only one strong reference + let result = fun(provider).await; + if Arc::strong_count(&local_connection) > 1 { + log::warn!( + "More than 1 strong connection references still exist during transaction" + ); + } - pub fn reconnect(&self) -> Result<(), StorageError> { - let mut builder = Pool::builder(); + if Arc::weak_count(&local_connection) > 1 { + log::warn!("More than 1 weak connection references still exist during transaction"); + } - if let Some(ref opts) = self.customizer { - builder = builder.connection_customizer(opts.clone().into_super()); + // after the closure finishes, `local_provider` should have the only reference ('strong') + // to `XmtpOpenMlsProvider` inner `DbConnection`.. + let local_connection = DbConnectionPrivate::from_arc_mutex(local_connection); + match result { + Ok(value) => { + local_connection.raw_query(|conn| { + ::TransactionManager::commit_transaction(&mut *conn) + })?; + log::debug!("Transaction async being committed"); + Ok(value) + } + Err(err) => { + log::debug!("Transaction async being rolled back"); + match local_connection.raw_query(|conn| { + ::TransactionManager::rollback_transaction(&mut *conn) + }) { + Ok(()) => Err(err), + Err(Error::BrokenTransactionManager) => Err(err), + Err(rollback) => Err(rollback.into()), + } + } + } } - let pool = match self.connect_opt { - StorageOption::Ephemeral => builder - .max_size(1) - .build(ConnectionManager::new(":memory:"))?, - StorageOption::Persistent(ref path) => builder - .max_size(25) - .build(ConnectionManager::new(path))?, - }; - - let mut pool_write = self.pool.write(); - *pool_write = Some(pool); + pub fn release_connection(&self) -> Result<(), StorageError> { + self.db.release_connection() + } - Ok(()) + pub fn reconnect(&self) -> Result<(), StorageError> { + self.db.reconnect() + } } } @@ -515,17 +431,18 @@ pub(crate) mod tests { wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); use super::*; - use std::sync::Barrier; use crate::{ - storage::group::{GroupMembershipState, StoredGroup}, - storage::identity::StoredIdentity, + storage::{ + group::{GroupMembershipState, StoredGroup}, + identity::StoredIdentity, + }, utils::test::{rand_vec, tmp_path}, - Fetch, Store, + Fetch, Store, StreamHandle as _, }; - use std::sync::Arc; + use std::sync::Barrier; /// Test harness that loads an Ephemeral store. - pub fn with_connection(fun: F) -> R + pub async fn with_connection(fun: F) -> R where F: FnOnce(&DbConnection) -> R, { @@ -533,29 +450,32 @@ pub(crate) mod tests { StorageOption::Ephemeral, EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn = &store.conn().expect("acquiring a Connection failed"); fun(conn) } impl EncryptedMessageStore { - pub fn new_test() -> Self { + pub async fn new_test() -> Self { let tmp_path = tmp_path(); EncryptedMessageStore::new( StorageOption::Persistent(tmp_path), EncryptedMessageStore::generate_enc_key(), ) + .await .expect("constructing message store failed.") } } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn ephemeral_store() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn ephemeral_store() { let store = EncryptedMessageStore::new( StorageOption::Ephemeral, EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn = &store.conn().unwrap(); @@ -569,14 +489,15 @@ pub(crate) mod tests { } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn persistent_store() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn persistent_store() { let db_path = tmp_path(); { let store = EncryptedMessageStore::new( StorageOption::Persistent(db_path.clone()), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn = &store.conn().unwrap(); @@ -591,15 +512,17 @@ pub(crate) mod tests { EncryptedMessageStore::remove_db_files(db_path) } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn releases_db_lock() { + // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + async fn releases_db_lock() { let db_path = tmp_path(); { let store = EncryptedMessageStore::new( StorageOption::Persistent(db_path.clone()), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn = &store.conn().unwrap(); @@ -613,7 +536,7 @@ pub(crate) mod tests { assert_eq!(fetched_identity.inbox_id, inbox_id); store.release_connection().unwrap(); - assert!(store.pool.read().is_none()); + assert!(store.db.pool.read().is_none()); store.reconnect().unwrap(); let fetched_identity2: StoredIdentity = conn.fetch(&()).unwrap().unwrap(); @@ -623,9 +546,9 @@ pub(crate) mod tests { EncryptedMessageStore::remove_db_files(db_path) } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn mismatched_encryption_key() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + async fn mismatched_encryption_key() { let mut enc_key = [1u8; 32]; let db_path = tmp_path(); @@ -633,6 +556,7 @@ pub(crate) mod tests { // Setup a persistent store let store = EncryptedMessageStore::new(StorageOption::Persistent(db_path.clone()), enc_key) + .await .unwrap(); StoredIdentity::new("dummy_address".to_string(), rand_vec(), rand_vec()) @@ -641,7 +565,8 @@ pub(crate) mod tests { } // Drop it enc_key[3] = 145; // Alter the enc_key - let res = EncryptedMessageStore::new(StorageOption::Persistent(db_path.clone()), enc_key); + let res = + EncryptedMessageStore::new(StorageOption::Persistent(db_path.clone()), enc_key).await; // Ensure it fails assert!( @@ -660,6 +585,7 @@ pub(crate) mod tests { StorageOption::Persistent(db_path.clone()), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn1 = &store.conn().unwrap(); @@ -728,13 +654,14 @@ pub(crate) mod tests { // write should fail & rollback // first thread succeeds #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn test_transaction_rollback() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_transaction_rollback() { let db_path = tmp_path(); let store = EncryptedMessageStore::new( StorageOption::Persistent(db_path.clone()), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let barrier = Arc::new(Barrier::new(2)); @@ -800,11 +727,12 @@ pub(crate) mod tests { StorageOption::Persistent(db_path.clone()), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let store_pointer = store.clone(); - let handle = crate::spawn(async move { + let handle = crate::spawn(None, async move { store_pointer .transaction_async(|provider| async move { let conn1 = provider.conn_ref(); @@ -826,7 +754,7 @@ pub(crate) mod tests { Ok::<_, anyhow::Error>(()) }); - let result = handle.await.unwrap(); + let result = handle.join().await.unwrap(); assert!(result.is_err()); let conn = store.conn().unwrap(); diff --git a/xmtp_mls/src/storage/encrypted_store/native.rs b/xmtp_mls/src/storage/encrypted_store/native.rs new file mode 100644 index 000000000..864b0a082 --- /dev/null +++ b/xmtp_mls/src/storage/encrypted_store/native.rs @@ -0,0 +1,190 @@ +use crate::storage::encrypted_store::DbConnectionPrivate; +use crate::storage::StorageError; +pub use diesel::sqlite::SqliteConnection; +use diesel::{ + connection::{AnsiTransactionManager, SimpleConnection}, + r2d2::{self, CustomizeConnection, PoolTransactionManager, PooledConnection}, + Connection, +}; +use parking_lot::RwLock; +use std::sync::Arc; + +pub type ConnectionManager = r2d2::ConnectionManager; +pub type Pool = r2d2::Pool; +pub type RawDbConnection = PooledConnection; + +use super::{sqlcipher_connection::EncryptedConnection, EncryptionKey, StorageOption, XmtpDb}; + +trait XmtpConnection: + ValidatedConnection + + CustomizeConnection + + dyn_clone::DynClone + + IntoSuper> +{ +} + +impl XmtpConnection for T where + T: ValidatedConnection + + CustomizeConnection + + dyn_clone::DynClone + + IntoSuper> +{ +} +dyn_clone::clone_trait_object!(XmtpConnection); + +pub(crate) trait ValidatedConnection { + fn validate(&self, _opts: &StorageOption) -> Result<(), StorageError> { + Ok(()) + } +} + +// we can remove this once https://github.com/rust-lang/rust/issues/65991 +// is merged, which should be happening soon (next ~2 releases) +trait IntoSuper { + fn into_super(self: Box) -> Box; +} + +impl> + IntoSuper> for T +{ + fn into_super(self: Box) -> Box> { + self + } +} + +/// An Unencrypted Connection +/// Creates a Sqlite3 Database/Connection in WAL mode. +/// Sets `busy_timeout` on each connection. +/// _*NOTE:*_Unencrypted Connections are not validated and mostly meant for testing. +/// It is not recommended to use an unencrypted connection in production. +#[derive(Clone, Debug)] +pub struct UnencryptedConnection; +impl ValidatedConnection for UnencryptedConnection {} + +impl CustomizeConnection for UnencryptedConnection { + fn on_acquire(&self, conn: &mut SqliteConnection) -> Result<(), r2d2::Error> { + conn.batch_execute("PRAGMA busy_timeout = 5000;") + .map_err(r2d2::Error::QueryError)?; + Ok(()) + } +} + +impl StorageOption { + // create a completely new standalone connection + pub(super) fn conn(&self) -> Result { + use StorageOption::*; + match self { + Persistent(path) => SqliteConnection::establish(path), + Ephemeral => SqliteConnection::establish(":memory:"), + } + } +} + +#[derive(Clone, Debug)] +/// Database used in `native` (everywhere but web) +pub struct NativeDb { + pub(super) pool: Arc>>, + customizer: Option>, + opts: StorageOption, +} + +impl NativeDb { + /// This function is private so that an unencrypted database cannot be created by accident + pub(super) fn new( + opts: &StorageOption, + enc_key: Option, + ) -> Result { + let mut builder = Pool::builder(); + + let customizer = if let Some(key) = enc_key { + let enc_opts = EncryptedConnection::new(key, opts)?; + builder = builder.connection_customizer(Box::new(enc_opts.clone())); + Some(Box::new(enc_opts) as Box) + } else if matches!(opts, StorageOption::Persistent(_)) { + builder = builder.connection_customizer(Box::new(UnencryptedConnection)); + Some(Box::new(UnencryptedConnection) as Box) + } else { + None + }; + + let pool = match opts { + StorageOption::Ephemeral => builder + .max_size(1) + .build(ConnectionManager::new(":memory:"))?, + StorageOption::Persistent(ref path) => { + builder.max_size(25).build(ConnectionManager::new(path))? + } + }; + + Ok(Self { + pool: Arc::new(Some(pool).into()), + customizer, + opts: opts.clone(), + }) + } + + fn raw_conn(&self) -> Result { + let pool_guard = self.pool.read(); + + let pool = pool_guard + .as_ref() + .ok_or(StorageError::PoolNeedsConnection)?; + + log::debug!( + "Pulling connection from pool, idle_connections={}, total_connections={}", + pool.state().idle_connections, + pool.state().connections + ); + + Ok(pool.get()?) + } +} + +impl XmtpDb for NativeDb { + type Connection = RawDbConnection; + type TransactionManager = PoolTransactionManager; + + /// Returns the Wrapped [`super::db_connection::DbConnection`] Connection implementation for this Database + fn conn(&self) -> Result, StorageError> { + let conn = self.raw_conn()?; + Ok(DbConnectionPrivate::from_arc_mutex(Arc::new( + parking_lot::Mutex::new(conn), + ))) + } + + fn validate(&self, opts: &StorageOption) -> Result<(), StorageError> { + if let Some(c) = &self.customizer { + c.validate(opts) + } else { + Ok(()) + } + } + + fn release_connection(&self) -> Result<(), StorageError> { + let mut pool_guard = self.pool.write(); + pool_guard.take(); + Ok(()) + } + + fn reconnect(&self) -> Result<(), StorageError> { + let mut builder = Pool::builder(); + + if let Some(ref opts) = self.customizer { + builder = builder.connection_customizer(opts.clone().into_super()); + } + + let pool = match self.opts { + StorageOption::Ephemeral => builder + .max_size(1) + .build(ConnectionManager::new(":memory:"))?, + StorageOption::Persistent(ref path) => { + builder.max_size(25).build(ConnectionManager::new(path))? + } + }; + + let mut pool_write = self.pool.write(); + *pool_write = Some(pool); + + Ok(()) + } +} diff --git a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs index f3864ca70..536d2975d 100644 --- a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs +++ b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs @@ -126,8 +126,8 @@ pub(crate) mod tests { use crate::{storage::encrypted_store::tests::with_connection, Store}; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn get_cursor_with_no_existing_state() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn get_cursor_with_no_existing_state() { with_connection(|conn| { let id = vec![1, 2, 3]; let kind = EntityKind::Group; @@ -137,11 +137,12 @@ pub(crate) mod tests { let entry: Option = conn.get_refresh_state(&id, kind).unwrap(); assert!(entry.is_some()); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn get_timestamp_with_existing_state() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn get_timestamp_with_existing_state() { with_connection(|conn| { let id = vec![1, 2, 3]; let entity_kind = EntityKind::Welcome; @@ -153,11 +154,12 @@ pub(crate) mod tests { entry.store(conn).unwrap(); assert_eq!(conn.get_last_cursor_for_id(&id, entity_kind).unwrap(), 123); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn update_timestamp_when_bigger() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn update_timestamp_when_bigger() { with_connection(|conn| { let id = vec![1, 2, 3]; let entity_kind = EntityKind::Group; @@ -171,11 +173,12 @@ pub(crate) mod tests { let entry: Option = conn.get_refresh_state(&id, entity_kind).unwrap(); assert_eq!(entry.unwrap().cursor, 124); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn dont_update_timestamp_when_smaller() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn dont_update_timestamp_when_smaller() { with_connection(|conn| { let entity_id = vec![1, 2, 3]; let entity_kind = EntityKind::Welcome; @@ -191,11 +194,12 @@ pub(crate) mod tests { conn.get_refresh_state(&entity_id, entity_kind).unwrap(); assert_eq!(entry.unwrap().cursor, 123); }) + .await } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn allow_installation_and_welcome_same_id() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn allow_installation_and_welcome_same_id() { with_connection(|conn| { let entity_id = vec![1, 2, 3]; let welcome_state = RefreshState { @@ -224,5 +228,6 @@ pub(crate) mod tests { .unwrap(); assert_eq!(group_state_retrieved.cursor, 456); }) + .await } } diff --git a/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs b/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs index 6d8a5f7a0..d03a22ddf 100644 --- a/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs +++ b/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs @@ -15,7 +15,7 @@ use std::{ use crate::storage::StorageError; -use super::{StorageOption, EncryptionKey}; +use super::{EncryptionKey, StorageOption}; pub type Salt = [u8; 16]; const PLAINTEXT_HEADER_SIZE: usize = 32; @@ -202,7 +202,7 @@ impl EncryptedConnection { } } -impl super::ValidatedConnection for EncryptedConnection { +impl super::native::ValidatedConnection for EncryptedConnection { fn validate(&self, opts: &StorageOption) -> Result<(), StorageError> { let conn = &mut opts.conn()?; @@ -279,14 +279,15 @@ mod tests { const SQLITE3_PLAINTEXT_HEADER: &str = "SQLite format 3\0"; use StorageOption::*; - #[test] - fn test_db_creates_with_plaintext_header() { + #[tokio::test] + async fn test_db_creates_with_plaintext_header() { let db_path = tmp_path(); { let _ = EncryptedMessageStore::new( Persistent(db_path.clone()), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); assert!(EncryptedConnection::salt_file(&db_path).unwrap().exists()); @@ -306,8 +307,8 @@ mod tests { EncryptedMessageStore::remove_db_files(db_path) } - #[test] - fn test_db_migrates() { + #[tokio::test] + async fn test_db_migrates() { let db_path = tmp_path(); { let key = EncryptedMessageStore::generate_enc_key(); @@ -332,7 +333,9 @@ mod tests { file.read_exact(&mut plaintext_header).unwrap(); assert!(String::from_utf8_lossy(&plaintext_header) != SQLITE3_PLAINTEXT_HEADER); - let _ = EncryptedMessageStore::new(Persistent(db_path.clone()), key).unwrap(); + let _ = EncryptedMessageStore::new(Persistent(db_path.clone()), key) + .await + .unwrap(); assert!(EncryptedConnection::salt_file(&db_path).unwrap().exists()); let bytes = std::fs::read(EncryptedConnection::salt_file(&db_path).unwrap()).unwrap(); diff --git a/xmtp_mls/src/storage/encrypted_store/wasm.rs b/xmtp_mls/src/storage/encrypted_store/wasm.rs new file mode 100644 index 000000000..cefb87fea --- /dev/null +++ b/xmtp_mls/src/storage/encrypted_store/wasm.rs @@ -0,0 +1,68 @@ +use std::sync::Arc; + +use diesel::{connection::AnsiTransactionManager, prelude::*}; +pub use diesel_wasm_sqlite::connection::WasmSqliteConnection as SqliteConnection; +use parking_lot::Mutex; + +use super::{ + db_connection::DbConnectionPrivate, EncryptionKey, StorageError, StorageOption, XmtpDb, +}; + +#[derive(Clone)] +pub struct WasmDb { + conn: Arc>, + enc_key: Option, + opts: StorageOption, +} + +impl std::fmt::Debug for WasmDb { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("WasmDb") + .field("conn", &"WasmSqliteConnection") + .field("enc_key", &self.enc_key) + .field("opts", &self.opts) + .finish() + } +} + +impl WasmDb { + pub async fn new( + opts: &StorageOption, + enc_key: Option, + ) -> Result { + use super::StorageOption::*; + diesel_wasm_sqlite::init_sqlite().await; + let conn = match opts { + Ephemeral => SqliteConnection::establish(":memory:"), + Persistent(ref db_path) => SqliteConnection::establish(db_path), + }; + Ok(Self { + conn: Arc::new(Mutex::new(conn?)), + opts: opts.clone(), + enc_key, + }) + } +} + +impl XmtpDb for WasmDb { + type Connection = SqliteConnection; + type TransactionManager = AnsiTransactionManager; + + fn conn(&self) -> Result, StorageError> { + Ok(DbConnectionPrivate::from_arc_mutex(self.conn.clone())) + } + + fn validate(&self, _opts: &StorageOption) -> Result<(), StorageError> { + Ok(()) + } + + #[allow(unreachable_code)] + fn release_connection(&self) -> Result<(), StorageError> { + unimplemented!(); + } + + #[allow(unreachable_code)] + fn reconnect(&self) -> Result<(), StorageError> { + unimplemented!(); + } +} diff --git a/xmtp_mls/src/storage/sql_key_store.rs b/xmtp_mls/src/storage/sql_key_store.rs index e53bec56b..2b16cc889 100644 --- a/xmtp_mls/src/storage/sql_key_store.rs +++ b/xmtp_mls/src/storage/sql_key_store.rs @@ -1,6 +1,6 @@ use crate::{retry::RetryableError, retryable}; -use super::encrypted_store::db_connection::DbConnection; +use super::encrypted_store::db_connection::DbConnectionPrivate; use bincode; use diesel::{ prelude::*, @@ -26,20 +26,25 @@ struct StorageData { } #[derive(Debug)] -pub struct SqlKeyStore { +pub struct SqlKeyStore { // Directly wrap the DbConnection which is a SqliteConnection in this case - conn: DbConnection, + conn: DbConnectionPrivate, } -impl SqlKeyStore { - pub fn new(conn: DbConnection) -> Self { +impl SqlKeyStore { + pub fn new(conn: DbConnectionPrivate) -> Self { Self { conn } } - pub fn conn_ref(&self) -> &DbConnection { + pub fn conn_ref(&self) -> &DbConnectionPrivate { &self.conn } +} +impl SqlKeyStore +where + C: diesel::Connection + diesel::connection::LoadConnection, +{ fn select_query( &self, storage_key: &Vec, @@ -278,7 +283,10 @@ const QUEUED_PROPOSAL_LABEL: &[u8] = b"QueuedProposal"; const PROPOSAL_QUEUE_REFS_LABEL: &[u8] = b"ProposalQueueRefs"; const RESUMPTION_PSK_STORE_LABEL: &[u8] = b"ResumptionPskStore"; -impl StorageProvider for SqlKeyStore { +impl StorageProvider for SqlKeyStore +where + C: diesel::Connection + diesel::connection::LoadConnection, +{ type Error = SqlKeyStoreError; fn queue_proposal< @@ -1037,13 +1045,14 @@ pub(crate) mod tests { }; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn store_read_delete() { + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn store_read_delete() { let db_path = tmp_path(); let store = EncryptedMessageStore::new( StorageOption::Persistent(db_path), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn = store.conn().unwrap(); @@ -1094,6 +1103,7 @@ pub(crate) mod tests { StorageOption::Persistent(db_path), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn = store.conn().unwrap(); let provider = XmtpOpenMlsProvider::new(conn); @@ -1177,6 +1187,7 @@ pub(crate) mod tests { StorageOption::Persistent(db_path), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(); let conn = store.conn().unwrap(); let provider = XmtpOpenMlsProvider::new(conn); diff --git a/xmtp_mls/src/stream_handles.rs b/xmtp_mls/src/stream_handles.rs new file mode 100644 index 000000000..869b3dbc7 --- /dev/null +++ b/xmtp_mls/src/stream_handles.rs @@ -0,0 +1,255 @@ +//! Consistent Stream behavior between WebAssembly and Native utilizing `tokio::task::spawn` in native and +//! `wasm_bindgen_futures::spawn` for web. +use futures::{Future, FutureExt}; + +#[cfg(target_arch = "wasm32")] +pub type GenericStreamHandle = dyn StreamHandle; + +#[cfg(not(target_arch = "wasm32"))] +pub type GenericStreamHandle = dyn StreamHandle + Send + Sync; + +#[derive(thiserror::Error, Debug)] +pub enum StreamHandleError { + #[error("Result Channel closed")] + ChannelClosed, + #[error("The stream was closed")] + StreamClosed, + #[error(transparent)] + JoinHandleError(#[from] tokio::task::JoinError), + #[error("Stream Cancelled")] + Cancelled, + #[error("Stream Panicked With {0}")] + Panicked(String), +} +/// A handle to a spawned Stream +/// the spawned stream can be 'joined` by awaiting its Future implementation. +/// All spawned tasks are detached, so waiting the handle is not required. +#[allow(async_fn_in_trait)] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +pub trait StreamHandle { + /// The Output type for the stream + type StreamOutput; + + /// Asyncronously waits for the stream to be fully spawned + async fn wait_for_ready(&mut self); + /// Signal the stream to end + /// Does not wait for the stream to end, so will not receive the result of stream. + fn end(&self); + + // Its better to: + // `StreamHandle: Future>` + // but then crate::spawn` generates `Unused future must be used` since + // `async fn` desugars to `fn() -> impl Future`. There's no way + // to get rid of that warning, so we separate the future impl to here. + // See this rust-playground for an example: + // https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a2a88b144c9459176e8fae41ee569553 + /// Join the task back to the current thread, waiting until it ends. + async fn join(self) -> Result; + + /// End the stream and asyncronously wait for it to shutdown, getting the result of its + /// execution. + async fn end_and_wait(&mut self) -> Result; + /// Get an Abort Handle to the stream. + /// This handle may be cloned/sent/etc easily + /// and many handles may exist at once. + fn abort_handle(&self) -> Box; +} + +/// A handle that can be moved/cloned/sent, but can only close the stream. +pub trait AbortHandle: Send + Sync { + /// Send a signal to end the stream, without waiting for a result. + fn end(&self); + fn is_finished(&self) -> bool; +} + +#[cfg(not(target_arch = "wasm32"))] +pub use native::*; + +#[cfg(target_arch = "wasm32")] +#[allow(unused)] +pub use wasm::*; + +#[cfg(target_arch = "wasm32")] +mod wasm { + use futures::future::Either; + + use super::*; + + pub struct WasmStreamHandle { + result: tokio::sync::oneshot::Receiver, + // we only send once but oneshot senders aren't cloneable + // so we use mpsc here to keep the `&self` on `end`. + closer: tokio::sync::mpsc::Sender<()>, + ready: Option>, + } + + impl Future for WasmStreamHandle> { + type Output = Result; + + fn poll( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + FutureExt::poll_unpin(&mut self.result, cx).map(|r| match r { + Ok(r) => r, + Err(_) => Err(StreamHandleError::ChannelClosed), + }) + } + } + + #[async_trait::async_trait(?Send)] + impl StreamHandle for WasmStreamHandle> { + type StreamOutput = T; + + async fn wait_for_ready(&mut self) { + if let Some(s) = self.ready.take() { + let _ = s.await; + } + } + + async fn end_and_wait(&mut self) -> Result { + self.end(); + self.await + } + + fn end(&self) { + let _ = self.closer.try_send(()); + } + + fn abort_handle(&self) -> Box { + Box::new(CloseHandle(self.closer.clone())) + } + + async fn join(self) -> Result { + self.await + } + } + + #[derive(Clone)] + pub struct CloseHandle(tokio::sync::mpsc::Sender<()>); + impl AbortHandle for CloseHandle { + fn end(&self) { + let _ = self.0.try_send(()); + } + + fn is_finished(&self) -> bool { + self.0.is_closed() + } + } + + /// Spawn a future on the `wasm-bindgen` local current-thread executer + /// future does not require `Send`. + /// optionally pass in `ready` to signal whne stream will be ready. + pub fn spawn( + ready: Option>, + future: F, + ) -> impl StreamHandle + where + F: Future + 'static, + F::Output: 'static, + { + let (res_tx, res_rx) = tokio::sync::oneshot::channel(); + let (closer_tx, mut closer_rx) = tokio::sync::mpsc::channel::<()>(1); + + let handle = WasmStreamHandle { + result: res_rx, + closer: closer_tx, + ready, + }; + + wasm_bindgen_futures::spawn_local(async move { + let recv = closer_rx.recv(); + futures::pin_mut!(recv); + futures::pin_mut!(future); + let value = match futures::future::select(recv, future).await { + Either::Left((_, _)) => Err(StreamHandleError::StreamClosed), + Either::Right((v, _)) => Ok(v), + }; + let _ = res_tx.send(value); + }); + + handle + } +} + +#[cfg(not(target_arch = "wasm32"))] +mod native { + use super::*; + use tokio::task::JoinHandle; + + pub struct TokioStreamHandle { + inner: JoinHandle, + ready: Option>, + } + + impl Future for TokioStreamHandle { + type Output = Result; + + fn poll( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + self.inner.poll_unpin(cx).map_err(StreamHandleError::from) + } + } + + #[async_trait::async_trait] + impl StreamHandle for TokioStreamHandle { + type StreamOutput = T; + + async fn wait_for_ready(&mut self) { + if let Some(s) = self.ready.take() { + let _ = s.await; + } + } + + fn end(&self) { + self.inner.abort(); + } + + async fn end_and_wait(&mut self) -> Result { + use crate::StreamHandleError::*; + + self.end(); + match self.await { + Err(JoinHandleError(e)) if e.is_panic() => Err(Panicked(e.to_string())), + Err(JoinHandleError(e)) if e.is_cancelled() => Err(Cancelled), + Ok(t) => Ok(t), + Err(e) => Err(e), + } + } + + fn abort_handle(&self) -> Box { + Box::new(self.inner.abort_handle()) + } + + async fn join(self) -> Result { + self.await + } + } + + impl AbortHandle for tokio::task::AbortHandle { + fn end(&self) { + self.abort() + } + + fn is_finished(&self) -> bool { + self.is_finished() + } + } + + pub fn spawn( + ready: Option>, + future: F, + ) -> impl StreamHandle + where + F: Future + Send + 'static, + F::Output: Send + 'static, + { + TokioStreamHandle { + inner: tokio::task::spawn(future), + ready, + } + } +} diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index ecaef0a83..f4988010e 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -20,7 +20,7 @@ use crate::{ /// Wrapper around a [`tokio::task::JoinHandle`] but with a oneshot receiver /// which allows waiting for a `with_callback` stream fn to be ready for stream items. pub struct StreamHandle { - pub handle: JoinHandle, + handle: JoinHandle, start: Option>, } @@ -79,7 +79,7 @@ where (async { let welcome_v1 = welcome_v1.clone(); self.context - .store + .store() .transaction_async(|provider| async move { MlsGroup::create_from_encrypted_welcome( self, @@ -95,7 +95,7 @@ where ); if let Some(err) = creation_result.as_ref().err() { - let conn = self.context.store.conn()?; + let conn = self.context.store().conn()?; let result = conn.find_group_by_welcome_id(welcome_v1.id as i64); match result { Ok(Some(group)) => { @@ -234,10 +234,10 @@ where pub fn stream_conversations_with_callback( client: Arc>, mut convo_callback: impl FnMut(MlsGroup) + Send + 'static, - ) -> StreamHandle> { + ) -> impl crate::StreamHandle> { let (tx, rx) = oneshot::channel(); - let handle = crate::spawn(async move { + crate::spawn(Some(rx), async move { let stream = client.stream_conversations().await?; futures::pin_mut!(stream); let _ = tx.send(()); @@ -245,25 +245,20 @@ where convo_callback(convo) } log::debug!("`stream_conversations` stream ended, dropping stream"); - Ok(()) - }); - - StreamHandle { - start: Some(rx), - handle, - } + Ok::<_, ClientError>(()) + }) } pub(crate) fn stream_messages_with_callback( client: Arc>, group_id_to_info: HashMap, MessagesStreamInfo>, mut callback: impl FnMut(StoredGroupMessage) + Send + 'static, - ) -> StreamHandle> { + ) -> impl crate::StreamHandle> { let (tx, rx) = oneshot::channel(); let client = client.clone(); - let handle = crate::spawn(async move { + crate::spawn(Some(rx), async move { let stream = Self::stream_messages(&client, Arc::new(group_id_to_info)).await?; futures::pin_mut!(stream); let _ = tx.send(()); @@ -271,13 +266,8 @@ where callback(message) } log::debug!("`stream_messages` stream ended, dropping stream"); - Ok(()) - }); - - StreamHandle { - start: Some(rx), - handle, - } + Ok::<_, ClientError>(()) + }) } pub async fn stream_all_messages( @@ -360,10 +350,10 @@ where pub fn stream_all_messages_with_callback( client: Arc>, mut callback: impl FnMut(StoredGroupMessage) + Send + Sync + 'static, - ) -> StreamHandle> { + ) -> impl crate::StreamHandle> { let (tx, rx) = oneshot::channel(); - let handle = crate::spawn(async move { + crate::spawn(Some(rx), async move { let stream = Self::stream_all_messages(&client).await?; futures::pin_mut!(stream); let _ = tx.send(()); @@ -374,13 +364,8 @@ where } } log::debug!("`stream_all_messages` stream ended, dropping stream"); - Ok(()) - }); - - StreamHandle { - start: Some(rx), - handle, - } + Ok::<_, ClientError>(()) + }) } } @@ -389,11 +374,14 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::utils::test::{Delivery, TestClient}; use crate::{ builder::ClientBuilder, groups::GroupMetadataOptions, storage::group_message::StoredGroupMessage, Client, }; + use crate::{ + utils::test::{Delivery, TestClient}, + StreamHandle, + }; use futures::StreamExt; use parking_lot::Mutex; use std::sync::{ @@ -420,7 +408,7 @@ pub(crate) mod tests { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let mut stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); let bob_ptr = bob.clone(); - crate::spawn(async move { + crate::spawn(None, async move { let bob_stream = bob_ptr.stream_conversations().await.unwrap(); futures::pin_mut!(bob_stream); while let Some(item) = bob_stream.next().await { @@ -451,7 +439,7 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); - // let mut bob_stream = bob.stream_conversations().await.unwrap(); + // let mut bob_stream = bob.stream_conversations().await.unwrap()warning: unused implementer of `futures::Future` that must be used; alice_group .add_members_by_inbox_id(&alice, vec![bob.inbox_id()]) .await @@ -462,7 +450,7 @@ pub(crate) mod tests { let notify = Delivery::new(None); let notify_ptr = notify.clone(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - crate::spawn(async move { + crate::spawn(None, async move { let stream = alice_group.stream(&alice).await.unwrap(); futures::pin_mut!(stream); while let Some(item) = stream.next().await { @@ -510,7 +498,7 @@ pub(crate) mod tests { .add_members_by_inbox_id(&bo, vec![caro.inbox_id()]) .await .unwrap(); - crate::sleep(std::time::Duration::from_millis(100)).await; + crate::sleep(core::time::Duration::from_millis(100)).await; let messages: Arc>> = Arc::new(Mutex::new(Vec::new())); let messages_clone = messages.clone(); @@ -652,16 +640,16 @@ pub(crate) mod tests { assert_eq!(messages.len(), 5); } - let a = handle.handle.abort_handle(); - a.abort(); - let _ = handle.handle.await; + let a = handle.abort_handle(); + a.end(); + let _ = handle.join().await; assert!(a.is_finished()); alix_group .send_message("should not show up".as_bytes(), &alix) .await .unwrap(); - crate::sleep(std::time::Duration::from_millis(100)).await; + crate::sleep(core::time::Duration::from_millis(100)).await; let messages = messages.lock(); assert_eq!(messages.len(), 5); @@ -700,13 +688,13 @@ pub(crate) mod tests { let alix_group_pointer = alix_group.clone(); let alix_pointer = alix.clone(); - crate::spawn(async move { + crate::spawn(None, async move { for _ in 0..50 { alix_group_pointer .send_message(b"spam", &alix_pointer) .await .unwrap(); - crate::sleep(std::time::Duration::from_micros(200)).await; + crate::sleep(core::time::Duration::from_micros(200)).await; } }); @@ -724,7 +712,7 @@ pub(crate) mod tests { .unwrap(); } - let _ = tokio::time::timeout(std::time::Duration::from_secs(60), async { + let _ = tokio::time::timeout(core::time::Duration::from_secs(120), async { while blocked.load(Ordering::SeqCst) > 0 { tokio::task::yield_now().await; } @@ -783,6 +771,6 @@ pub(crate) mod tests { assert_eq!(grps.len(), 2); } - closer.handle.abort(); + closer.end(); } } diff --git a/xmtp_mls/src/utils/hash.rs b/xmtp_mls/src/utils/hash.rs deleted file mode 100644 index 829f2d7ea..000000000 --- a/xmtp_mls/src/utils/hash.rs +++ /dev/null @@ -1,5 +0,0 @@ -use xmtp_cryptography::hash::sha256_bytes; - -pub fn sha256(bytes: &[u8]) -> Vec { - sha256_bytes(bytes) -} diff --git a/xmtp_mls/src/utils/id.rs b/xmtp_mls/src/utils/id.rs deleted file mode 100644 index b518e48ab..000000000 --- a/xmtp_mls/src/utils/id.rs +++ /dev/null @@ -1,21 +0,0 @@ -use super::hash::sha256; - -pub fn serialize_group_id(group_id: &[u8]) -> String { - hex::encode(group_id) -} - -/// Relies on a client-created idempotency_key (which could be a timestamp) -pub fn calculate_message_id( - group_id: &[u8], - decrypted_message_bytes: &[u8], - idempotency_key: &str, -) -> Vec { - let separator = b"\t"; - let mut id_vec = Vec::new(); - id_vec.extend_from_slice(group_id); - id_vec.extend_from_slice(separator); - id_vec.extend_from_slice(idempotency_key.as_bytes()); - id_vec.extend_from_slice(separator); - id_vec.extend_from_slice(decrypted_message_bytes); - sha256(&id_vec) -} diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index 3b9ee78bd..17a26d706 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -1,7 +1,45 @@ #[cfg(feature = "bench")] pub mod bench; -pub mod hash; -pub mod id; #[cfg(any(test, feature = "test-utils"))] pub mod test; -pub mod time; + +pub mod hash { + pub use xmtp_cryptography::hash::sha256_bytes as sha256; +} + +pub mod time { + use wasm_timer::{SystemTime, UNIX_EPOCH}; + + pub const NS_IN_SEC: i64 = 1_000_000_000; + + pub fn now_ns() -> i64 { + log::debug!("GETTING NOW"); + let now = SystemTime::now(); + + now.duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_nanos() as i64 + } +} + +pub mod id { + /// Relies on a client-created idempotency_key (which could be a timestamp) + pub fn calculate_message_id( + group_id: &[u8], + decrypted_message_bytes: &[u8], + idempotency_key: &str, + ) -> Vec { + let separator = b"\t"; + let mut id_vec = Vec::new(); + id_vec.extend_from_slice(group_id); + id_vec.extend_from_slice(separator); + id_vec.extend_from_slice(idempotency_key.as_bytes()); + id_vec.extend_from_slice(separator); + id_vec.extend_from_slice(decrypted_message_bytes); + super::hash::sha256(&id_vec) + } + + pub fn serialize_group_id(group_id: &[u8]) -> String { + hex::encode(group_id) + } +} diff --git a/xmtp_mls/src/utils/test.rs b/xmtp_mls/src/utils/test.rs index 73fecb1c1..83224c7db 100755 --- a/xmtp_mls/src/utils/test.rs +++ b/xmtp_mls/src/utils/test.rs @@ -107,13 +107,14 @@ impl EncryptedMessageStore { } impl ClientBuilder { - pub fn temp_store(self) -> Self { + pub async fn temp_store(self) -> Self { let tmpdb = tmp_path(); self.store( EncryptedMessageStore::new( StorageOption::Persistent(tmpdb), EncryptedMessageStore::generate_enc_key(), ) + .await .unwrap(), ) } @@ -136,6 +137,7 @@ impl ClientBuilder { )) .scw_signatuer_verifier(MockSmartContractSignatureVerifier::new(true)) .temp_store() + .await .local_client() .await .build() @@ -159,6 +161,7 @@ impl ClientBuilder { None, )) .temp_store() + .await .api_client(dev_client) .build() .await @@ -174,12 +177,12 @@ impl ClientBuilder { #[derive(Clone, Default)] pub struct Delivery { notify: Arc, - timeout: std::time::Duration, + timeout: core::time::Duration, } impl Delivery { - pub fn new(timeout: Option) -> Self { - let timeout = timeout.unwrap_or(std::time::Duration::from_secs(60)); + pub fn new(timeout: Option) -> Self { + let timeout = timeout.unwrap_or(core::time::Duration::from_secs(60)); Self { notify: Arc::new(Notify::new()), timeout, diff --git a/xmtp_mls/src/utils/time.rs b/xmtp_mls/src/utils/time.rs deleted file mode 100644 index 71917ed39..000000000 --- a/xmtp_mls/src/utils/time.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::time::{SystemTime, UNIX_EPOCH}; - -pub const NS_IN_SEC: i64 = 1_000_000_000; - -pub fn now_ns() -> i64 { - let now = SystemTime::now(); - - now.duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_nanos() as i64 -} diff --git a/xmtp_mls/src/xmtp_openmls_provider.rs b/xmtp_mls/src/xmtp_openmls_provider.rs index b3e7b36a8..cfe695fd6 100644 --- a/xmtp_mls/src/xmtp_openmls_provider.rs +++ b/xmtp_mls/src/xmtp_openmls_provider.rs @@ -1,31 +1,36 @@ use openmls_rust_crypto::RustCrypto; use openmls_traits::OpenMlsProvider; -use crate::storage::{db_connection::DbConnection, sql_key_store::SqlKeyStore}; +use crate::storage::{db_connection::DbConnectionPrivate, sql_key_store::SqlKeyStore}; + +pub type XmtpOpenMlsProvider = XmtpOpenMlsProviderPrivate; #[derive(Debug)] -pub struct XmtpOpenMlsProvider { +pub struct XmtpOpenMlsProviderPrivate { crypto: RustCrypto, - key_store: SqlKeyStore, + key_store: SqlKeyStore, } -impl XmtpOpenMlsProvider { - pub fn new(conn: DbConnection) -> Self { +impl XmtpOpenMlsProviderPrivate { + pub fn new(conn: DbConnectionPrivate) -> Self { Self { crypto: RustCrypto::default(), key_store: SqlKeyStore::new(conn), } } - pub(crate) fn conn_ref(&self) -> &DbConnection { + pub(crate) fn conn_ref(&self) -> &DbConnectionPrivate { self.key_store.conn_ref() } } -impl OpenMlsProvider for XmtpOpenMlsProvider { +impl OpenMlsProvider for XmtpOpenMlsProviderPrivate +where + C: diesel::Connection + diesel::connection::LoadConnection, +{ type CryptoProvider = RustCrypto; type RandProvider = RustCrypto; - type StorageProvider = SqlKeyStore; + type StorageProvider = SqlKeyStore; fn crypto(&self) -> &Self::CryptoProvider { &self.crypto @@ -40,10 +45,13 @@ impl OpenMlsProvider for XmtpOpenMlsProvider { } } -impl<'a> OpenMlsProvider for &'a XmtpOpenMlsProvider { +impl<'a, C> OpenMlsProvider for &'a XmtpOpenMlsProviderPrivate +where + C: diesel::Connection + diesel::connection::LoadConnection, +{ type CryptoProvider = RustCrypto; type RandProvider = RustCrypto; - type StorageProvider = SqlKeyStore; + type StorageProvider = SqlKeyStore; fn crypto(&self) -> &Self::CryptoProvider { &self.crypto From 9987ac7b20a81ca3410c22ac280c512c01c6e217 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 20 Sep 2024 17:22:59 -0400 Subject: [PATCH 37/97] fix bindings_wasm build --- xmtp_mls/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index c7040c38b..679d93dbc 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -855,10 +855,10 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use super::Client; use diesel::RunQueryDsl; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::InboxOwner; - use super::Client; use crate::{ builder::ClientBuilder, From 4c4460701dc52d2613237c7e6fcb21b34fd6a15c Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Fri, 20 Sep 2024 17:23:26 -0400 Subject: [PATCH 38/97] add bindings_wasm Cargo.lock to git --- bindings_wasm/.gitignore | 3 +- bindings_wasm/Cargo.lock | 5557 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 5558 insertions(+), 2 deletions(-) create mode 100644 bindings_wasm/Cargo.lock diff --git a/bindings_wasm/.gitignore b/bindings_wasm/.gitignore index 3ad01bda7..82448ccd9 100644 --- a/bindings_wasm/.gitignore +++ b/bindings_wasm/.gitignore @@ -1,3 +1,2 @@ /target -/Cargo.lock -/build \ No newline at end of file +/build diff --git a/bindings_wasm/Cargo.lock b/bindings_wasm/Cargo.lock new file mode 100644 index 000000000..8bd33bd22 --- /dev/null +++ b/bindings_wasm/Cargo.lock @@ -0,0 +1,5557 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "axum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 1.0.1", + "tower 0.5.1", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.1", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.7.4", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindings_wasm" +version = "0.1.0" +dependencies = [ + "js-sys", + "serde", + "serde-wasm-bindgen", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test", + "xmtp_api_http", + "xmtp_cryptography", + "xmtp_id", + "xmtp_mls", + "xmtp_proto", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +dependencies = [ + "serde", +] + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest", + "hmac", + "k256 0.13.3", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest", + "generic-array", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2", + "sha3", + "thiserror", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.76", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "diesel" +version = "2.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +dependencies = [ + "diesel_derives 2.2.0", + "downcast-rs", + "libsqlite3-sys", + "r2d2", + "time", +] + +[[package]] +name = "diesel-wasm-sqlite" +version = "0.0.1" +dependencies = [ + "diesel", + "diesel_derives 2.2.3", + "js-sys", + "serde", + "serde-wasm-bindgen", + "talc", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "diesel_derives" +version = "2.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +dependencies = [ + "diesel_table_macro_syntax 0.2.0 (git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub)", + "dsl_auto_type 0.1.0", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "diesel_derives" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" +dependencies = [ + "diesel_table_macro_syntax 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dsl_auto_type 0.1.2", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "diesel_migrations" +version = "2.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +dependencies = [ + "diesel", + "migrations_internals", + "migrations_macros", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" +dependencies = [ + "syn 2.0.76", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +dependencies = [ + "syn 2.0.76", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dsl_auto_type" +version = "0.1.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "dsl_auto_type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "ecdsa" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12844141594ad74185a926d030f3b605f6a903b4e3fec351f3ea338ac5b7637e" +dependencies = [ + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.9", + "digest", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature", + "spki 0.7.3", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8 0.10.2", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "signature", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", + "digest", + "ff 0.12.1", + "generic-array", + "group 0.12.1", + "hkdf", + "pkcs8 0.9.0", + "rand_core", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest", + "ff 0.13.0", + "generic-array", + "group 0.13.0", + "hkdf", + "pem-rfc7468", + "pkcs8 0.10.2", + "rand_core", + "sec1 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256 0.13.3", + "log", + "rand", + "rlp", + "serde", + "sha3", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "ethers-etherscan", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "reqwest 0.11.27", + "serde", + "serde_json", + "syn 2.0.76", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.76", +] + +[[package]] +name = "ethers-core" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +dependencies = [ + "arrayvec", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve 0.13.8", + "ethabi", + "generic-array", + "k256 0.13.3", + "num_enum", + "once_cell", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.76", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" +dependencies = [ + "chrono", + "ethers-core", + "reqwest 0.11.27", + "semver", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http 0.2.12", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve 0.13.8", + "eth-keystore", + "ethers-core", + "rand", + "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66244a771d9163282646dbeffe0e6eca4dda4146b6498644e678ac6089b11edd" +dependencies = [ + "cfg-if", + "const-hex", + "dirs", + "dunce", + "ethers-core", + "glob", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver", + "serde", + "serde_json", + "solang-parser", + "svm-rs", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] + +[[package]] +name = "fluvio-wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b768c170dc045fa587a8f948c91f9bcfb87f774930477c6215addf54317f137f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers 0.2.6", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "rand_core", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.4.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.4.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "hpke-rs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11bd4ee27b79fa1820e72ef8489cc729c87299ec3f7f52b8fc8dcb87cb2d485" +dependencies = [ + "hpke-rs-crypto", + "log", + "serde", + "tls_codec", + "zeroize", +] + +[[package]] +name = "hpke-rs-crypto" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c3f1ae0a26c18d6469a70db1217136056261c4a244b09a755bc60bd4e055b67" +dependencies = [ + "rand_core", +] + +[[package]] +name = "hpke-rs-rust-crypto" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08d4500baf0aced746723d3515d08212bdb9d941df6d1aca3d46d1619b2a1cf" +dependencies = [ + "aes-gcm", + "chacha20poly1305", + "hkdf", + "hpke-rs-crypto", + "p256", + "p384", + "rand_chacha", + "rand_core", + "sha2", + "x25519-dalek", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.30", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls 0.23.12", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +dependencies = [ + "hyper 1.4.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2", + "tokio", + "tower 0.4.13", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a55e0ff3b72c262bcf041d9e97f1b84492b68f1c1a384de2323d3dc9403397" +dependencies = [ + "cfg-if", + "ecdsa 0.15.1", + "elliptic-curve 0.12.3", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools 0.11.0", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4588d65215825ee71ebff9e1c9982067833b1355d7546845ffdb3165cbd7456" +dependencies = [ + "cc", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "migrations_internals" +version = "2.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +dependencies = [ + "serde", + "toml", +] + +[[package]] +name = "migrations_macros" +version = "2.2.0" +source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" +dependencies = [ + "migrations_internals", + "proc-macro2", + "quote", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "openmls" +version = "0.6.0-pre.2" +source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" +dependencies = [ + "backtrace", + "fluvio-wasm-timer", + "getrandom", + "itertools 0.10.5", + "log", + "once_cell", + "openmls_basic_credential", + "openmls_memory_storage", + "openmls_rust_crypto", + "openmls_test", + "openmls_traits", + "rand", + "rayon", + "serde", + "serde_json", + "thiserror", + "tls_codec", + "wasm-bindgen-test", +] + +[[package]] +name = "openmls_basic_credential" +version = "0.3.0-pre.1" +source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" +dependencies = [ + "ed25519-dalek", + "openmls_traits", + "p256", + "rand", + "serde", + "tls_codec", +] + +[[package]] +name = "openmls_memory_storage" +version = "0.3.0-pre.2" +source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" +dependencies = [ + "hex", + "log", + "openmls_traits", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "openmls_rust_crypto" +version = "0.3.0-pre.1" +source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" +dependencies = [ + "aes-gcm", + "chacha20poly1305", + "ed25519-dalek", + "hkdf", + "hmac", + "hpke-rs", + "hpke-rs-crypto", + "hpke-rs-rust-crypto", + "openmls_memory_storage", + "openmls_traits", + "p256", + "rand", + "rand_chacha", + "serde", + "sha2", + "thiserror", + "tls_codec", +] + +[[package]] +name = "openmls_test" +version = "0.1.0-pre.1" +source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" +dependencies = [ + "ansi_term", + "openmls_rust_crypto", + "openmls_traits", + "proc-macro2", + "quote", + "rstest", + "rstest_reuse", + "syn 2.0.76", +] + +[[package]] +name = "openmls_traits" +version = "0.3.0-pre.2" +source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" +dependencies = [ + "serde", + "tls_codec", +] + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "300.3.1+3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "elliptic-curve 0.13.8", + "primeorder", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.3", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pbjson" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" +dependencies = [ + "base64 0.21.7", + "serde", +] + +[[package]] +name = "pbjson-build" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" +dependencies = [ + "heck", + "itertools 0.13.0", + "prost", + "prost-types", +] + +[[package]] +name = "pbjson-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" +dependencies = [ + "bytes", + "chrono", + "pbjson", + "pbjson-build", + "prost", + "prost-build", + "serde", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.4.0", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.9", + "spki 0.7.3", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +dependencies = [ + "proc-macro2", + "syn 2.0.76", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve 0.13.8", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "unarray", +] + +[[package]] +name = "prost" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" +dependencies = [ + "bytes", + "heck", + "itertools 0.12.1", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.76", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "prost-types" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot 0.12.3", + "scheduled-thread-pool", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "hyper-rustls 0.24.2", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-rustls 0.27.2", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.1.3", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration 0.6.1", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "windows-registry", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rstest" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", + "unicode-ident", +] + +[[package]] +name = "rstest_reuse" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45f80dcc84beab3a327bbe161f77db25f336a1452428176787c8c79ac79d7073" +dependencies = [ + "quote", + "rand", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.7", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot 0.12.3", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct 0.1.1", + "der 0.6.1", + "generic-array", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.9", + "generic-array", + "pkcs8 0.10.2", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "serde_json" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "solang-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" +dependencies = [ + "itertools 0.11.0", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der 0.7.9", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot 0.12.3", + "phf_shared 0.10.0", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.76", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "svm-rs" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11297baafe5fa0c99d5722458eac6a5e25c01eb1b8e5cd137f54079093daa7a4" +dependencies = [ + "dirs", + "fs2", + "hex", + "once_cell", + "reqwest 0.11.27", + "semver", + "serde", + "serde_json", + "sha2", + "thiserror", + "url", + "zip", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "talc" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" +dependencies = [ + "lock_api", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tls_codec" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a" +dependencies = [ + "serde", + "tls_codec_derive", + "zeroize", +] + +[[package]] +name = "tls_codec_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "tokio" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.12", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", + "tungstenite", + "webpki-roots", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap 2.4.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tonic" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "socket2", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 0.2.12", + "httparse", + "log", + "rand", + "rustls 0.21.12", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.76", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "xmtp_api_http" +version = "0.0.1" +dependencies = [ + "async-stream", + "futures", + "hyper 1.4.1", + "log", + "reqwest 0.12.7", + "serde", + "serde_json", + "thiserror", + "tokio", + "xmtp_proto", +] + +[[package]] +name = "xmtp_cryptography" +version = "0.0.1" +dependencies = [ + "curve25519-dalek", + "ecdsa 0.16.9", + "ethers", + "getrandom", + "hex", + "k256 0.13.3", + "log", + "rand", + "rand_chacha", + "rustc-hex", + "serde", + "sha2", + "sha3", + "thiserror", +] + +[[package]] +name = "xmtp_id" +version = "0.0.1" +dependencies = [ + "async-trait", + "chrono", + "ed25519", + "ed25519-dalek", + "ethers", + "futures", + "getrandom", + "hex", + "log", + "openmls", + "openmls_basic_credential", + "openmls_rust_crypto", + "openmls_traits", + "prost", + "rand", + "regex", + "rustc-hex", + "serde", + "sha2", + "thiserror", + "tokio", + "tracing", + "url", + "wasm-timer", + "xmtp_cryptography", + "xmtp_proto", +] + +[[package]] +name = "xmtp_mls" +version = "0.1.0" +dependencies = [ + "aes-gcm", + "async-stream", + "async-trait", + "bincode", + "chrono", + "diesel", + "diesel-wasm-sqlite", + "diesel_migrations", + "dyn-clone", + "ed25519-dalek", + "futures", + "getrandom", + "gloo-timers 0.3.0", + "hex", + "libsqlite3-sys", + "log", + "openmls", + "openmls_basic_credential", + "openmls_rust_crypto", + "openmls_traits", + "parking_lot 0.12.3", + "prost", + "rand", + "reqwest 0.12.7", + "serde", + "serde_json", + "sha2", + "thiserror", + "tls_codec", + "tokio", + "tokio-stream", + "tracing", + "trait-variant", + "wasm-bindgen-futures", + "wasm-timer", + "xmtp_cryptography", + "xmtp_id", + "xmtp_proto", + "xmtp_v2", +] + +[[package]] +name = "xmtp_proto" +version = "0.0.1" +dependencies = [ + "futures", + "openmls", + "pbjson", + "pbjson-types", + "prost", + "prost-types", + "serde", + "tonic", + "trait-variant", +] + +[[package]] +name = "xmtp_v2" +version = "0.0.1" +dependencies = [ + "aes-gcm", + "ecdsa 0.15.1", + "generic-array", + "getrandom", + "hex", + "hkdf", + "k256 0.12.0", + "rand", + "rand_chacha", + "sha2", + "sha3", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2 0.11.0", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] From 49444aa8a68fdc6f1de574279b9bf534e5c62728 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 24 Sep 2024 16:11:38 -0500 Subject: [PATCH 39/97] wasm debug WIP --- xmtp_api_http/src/lib.rs | 4 ---- xmtp_mls/src/storage/serialization.rs | 7 +++++-- xmtp_mls/src/utils/mod.rs | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index 1d0320b4a..14fb07920 100755 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -78,7 +78,6 @@ impl ClientWithMetadata for XmtpHttpApiClient { self.app_version = Some(version); let mut headers = header::HeaderMap::new(); - if let Some(app_version) = &self.app_version { headers.insert("x-app-version", app_version.parse().map_err(metadata_err)?); } @@ -88,7 +87,6 @@ impl ClientWithMetadata for XmtpHttpApiClient { libxmtp_version.parse().map_err(metadata_err)?, ); } - self.http_client = reqwest_builder() .default_headers(headers) .build() @@ -99,7 +97,6 @@ impl ClientWithMetadata for XmtpHttpApiClient { self.libxmtp_version = Some(version); let mut headers = header::HeaderMap::new(); - if let Some(app_version) = &self.app_version { headers.insert( "x-app-version", @@ -116,7 +113,6 @@ impl ClientWithMetadata for XmtpHttpApiClient { .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?, ); } - self.http_client = reqwest_builder() .default_headers(headers) .build() diff --git a/xmtp_mls/src/storage/serialization.rs b/xmtp_mls/src/storage/serialization.rs index c8efb2017..7441cc998 100644 --- a/xmtp_mls/src/storage/serialization.rs +++ b/xmtp_mls/src/storage/serialization.rs @@ -6,14 +6,17 @@ pub fn db_serialize(value: &T) -> Result, StorageError> where T: ?Sized + Serialize, { - bincode::serialize(value) - .map_err(|_| StorageError::Serialization("Failed to db_serialize".to_string())) + let bytes = bincode::serialize(value) + .map_err(|_| StorageError::Serialization("Failed to db_serialize".to_string())); + log::debug!("SER bytes: {:?}", bytes); + bytes } pub fn db_deserialize(bytes: &[u8]) -> Result where T: serde::de::DeserializeOwned, { + log::debug!("deser bytes {:?}", bytes); bincode::deserialize::(bytes) .map_err(|_| StorageError::Deserialization("Failed to db_deserialize".to_string())) } diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index 17a26d706..59fbf10f8 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -43,3 +43,20 @@ pub mod id { hex::encode(group_id) } } + +pub mod wasm { + /* + use once_cell::sync::OnceCell; + static INIT: OnceCell<()> = OnceCell::const_new(); + + pub async fn init() { + INIT.get_or_init(|| async { + console::log_1(&"INIT".into()); + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + diesel_wasm_sqlite::init_sqlite().await; + }) + .await; + } + */ +} From fc28a4850972218f735d1ecf5de0d54013650150 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 25 Sep 2024 16:13:10 -0500 Subject: [PATCH 40/97] init tracing for wasm --- Cargo.lock | 1 + xmtp_mls/Cargo.toml | 1 + xmtp_mls/src/utils/mod.rs | 14 ++++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d21a03ea0..ad1cb3f58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6501,6 +6501,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-bindgen-test", "wasm-timer", + "web-sys", "xmtp_api_grpc", "xmtp_api_http", "xmtp_cryptography", diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index f947c8bbb..d9749c8d1 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -91,6 +91,7 @@ tokio = { workspace = true, features = ["macros", "rt"] } openmls = { workspace = true, features = ["test-utils", "js"] } gloo-timers = { workspace = true, features = ["futures"] } wasm-bindgen-futures.workspace = true +web-sys = "0.3" [dev-dependencies] ethers.workspace = true diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index 59fbf10f8..bbf6a41b7 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -13,7 +13,7 @@ pub mod time { pub const NS_IN_SEC: i64 = 1_000_000_000; pub fn now_ns() -> i64 { - log::debug!("GETTING NOW"); + tracing::debug!("GETTING NOW"); let now = SystemTime::now(); now.duration_since(UNIX_EPOCH) @@ -45,11 +45,14 @@ pub mod id { } pub mod wasm { - /* - use once_cell::sync::OnceCell; + use tokio::sync::OnceCell; static INIT: OnceCell<()> = OnceCell::const_new(); + #[cfg(all(target_arch = "wasm32", test))] pub async fn init() { + use web_sys::console; + tracing_log::LogTracer::init().unwrap(); + INIT.get_or_init(|| async { console::log_1(&"INIT".into()); console_error_panic_hook::set_once(); @@ -58,5 +61,8 @@ pub mod wasm { }) .await; } - */ + + // no-op + #[cfg(not(target_arch = "wasm32"))] + pub async fn init() {} } From bed2c81eec342e9fe7ccf98a37fc85ccb29a28e4 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 30 Sep 2024 18:14:25 -0400 Subject: [PATCH 41/97] fix tests --- bindings_ffi/Cargo.lock | 1 + bindings_node/Cargo.lock | 1 + bindings_wasm/Cargo.lock | 1 + diesel-wasm-sqlite/Cargo.lock | 137 ++++++++++++++++-- diesel-wasm-sqlite/Cargo.toml | 2 +- .../src/connection/sqlite_value.rs | 2 +- diesel-wasm-sqlite/src/ffi.rs | 6 +- diesel-wasm-sqlite/src/sqlite_types/to_sql.rs | 1 + diesel-wasm-sqlite/tests/common/mod.rs | 3 +- diesel-wasm-sqlite/tests/test/web.rs | 77 +++++++++- xmtp_mls/Cargo.toml | 1 + xmtp_mls/src/builder.rs | 1 + xmtp_mls/src/groups/mod.rs | 2 +- xmtp_mls/src/identity_updates.rs | 2 +- xmtp_mls/src/storage/encrypted_store/mod.rs | 2 +- xmtp_mls/src/storage/encrypted_store/wasm.rs | 4 +- xmtp_mls/src/utils/mod.rs | 6 +- 17 files changed, 223 insertions(+), 26 deletions(-) diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 64b0dff02..1d3bbffd8 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -5922,6 +5922,7 @@ dependencies = [ "trait-variant", "wasm-bindgen-futures", "wasm-timer", + "web-sys", "xmtp_api_grpc", "xmtp_cryptography", "xmtp_id", diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index b20dd466a..b97263d38 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -5427,6 +5427,7 @@ dependencies = [ "trait-variant", "wasm-bindgen-futures", "wasm-timer", + "web-sys", "xmtp_cryptography", "xmtp_id", "xmtp_proto", diff --git a/bindings_wasm/Cargo.lock b/bindings_wasm/Cargo.lock index 8bd33bd22..6af417434 100644 --- a/bindings_wasm/Cargo.lock +++ b/bindings_wasm/Cargo.lock @@ -5422,6 +5422,7 @@ dependencies = [ "trait-variant", "wasm-bindgen-futures", "wasm-timer", + "web-sys", "xmtp_cryptography", "xmtp_id", "xmtp_proto", diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index b795f340e..de705aacb 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -114,16 +123,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "ctor" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "darling" version = "0.20.10" @@ -176,7 +175,6 @@ version = "0.0.1" dependencies = [ "chrono", "console_error_panic_hook", - "ctor", "diesel", "diesel_derives 2.2.2", "diesel_migrations", @@ -189,6 +187,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "tracing-subscriber", "tracing-wasm", "wasm-bindgen", "wasm-bindgen-futures", @@ -406,6 +405,15 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.4" @@ -440,6 +448,16 @@ dependencies = [ "adler", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -464,6 +482,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.3" @@ -570,6 +594,50 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -781,6 +849,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", ] [[package]] @@ -789,9 +869,16 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", + "smallvec", "thread_local", + "tracing", "tracing-core", + "tracing-log", ] [[package]] @@ -811,6 +898,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -918,6 +1011,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.52.0" diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index b766beb7c..6809293f5 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -39,7 +39,7 @@ chrono = { version = "0.4", features = ["wasmbind", "serde"] } diesel_migrations = "2.2" diesel = { version = "2.2", features = ["chrono"]} tracing-wasm = { version = "0.2" } -ctor = "0.2" +tracing-subscriber = { version = "0.3", features = ["env-filter", "tracing-log"] } [patch.crates-io] diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } diff --git a/diesel-wasm-sqlite/src/connection/sqlite_value.rs b/diesel-wasm-sqlite/src/connection/sqlite_value.rs index 9ecfc131f..1803b82d0 100644 --- a/diesel-wasm-sqlite/src/connection/sqlite_value.rs +++ b/diesel-wasm-sqlite/src/connection/sqlite_value.rs @@ -118,8 +118,8 @@ impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { let ptr = sqlite3.value_blob(self.value); let len = sqlite3.value_bytes(self.value); let mut bytes = Vec::with_capacity(len as usize); + bytes.set_len(len as usize); ffi::raw_copy_from_sqlite(ptr, len, bytes.as_mut_slice()); - // bytes.set_len(len); // not sure we need this bytes } } diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index b49f7a39a..45be75222 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -82,8 +82,10 @@ pub fn raw_copy_to_sqlite>(bytes: B, dst: *mut u8) { pub unsafe fn raw_copy_from_sqlite(src: *mut u8, len: u32, buf: &mut [u8]) { let wasm = crate::get_sqlite_unchecked().inner().wasm(); let mem = wasm.heap8u(); - mem.slice(src as u32, src as u32 + len) - .raw_copy_to_ptr(buf.as_mut_ptr()); + // this is safe because we view the slice and immediately copy it into + // our memory. + let view = Uint8Array::new_with_byte_offset_and_length(&mem.buffer(), src as u32, len); + view.raw_copy_to_ptr(buf.as_mut_ptr()) } pub async fn init_sqlite() { diff --git a/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs b/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs index 4915e6a86..74e34bcc3 100644 --- a/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs +++ b/diesel-wasm-sqlite/src/sqlite_types/to_sql.rs @@ -23,6 +23,7 @@ use diesel::sql_types::SqlType; /* // Not posible until we share mem with sqlite. There's no // way to avoid an allocation into our host memory until then. + impl FromSql for *const str { fn from_sql(value: SqliteValue<'_, '_, '_>) -> deserialize::Result { tracing::debug!("IN FROM SQL"); diff --git a/diesel-wasm-sqlite/tests/common/mod.rs b/diesel-wasm-sqlite/tests/common/mod.rs index 16e4dab4d..26d309276 100644 --- a/diesel-wasm-sqlite/tests/common/mod.rs +++ b/diesel-wasm-sqlite/tests/common/mod.rs @@ -2,14 +2,15 @@ use prelude::*; use tokio::sync::OnceCell; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; static INIT: OnceCell<()> = OnceCell::const_new(); pub async fn init() { INIT.get_or_init(|| async { console::log_1(&"INIT".into()); - console_error_panic_hook::set_once(); tracing_wasm::set_as_global_default(); + console_error_panic_hook::set_once(); diesel_wasm_sqlite::init_sqlite().await; }) .await; diff --git a/diesel-wasm-sqlite/tests/test/web.rs b/diesel-wasm-sqlite/tests/test/web.rs index a08ff55d3..b59fab616 100755 --- a/diesel-wasm-sqlite/tests/test/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -35,13 +35,13 @@ pub struct BookForm { } #[derive(Queryable, QueryableByName, Selectable, PartialEq, Debug)] -#[diesel(table_name = books)] +#[diesel(table_name = books, check_for_backend(diesel_wasm_sqlite::WasmSqlite))] pub struct StoredBook { #[diesel(sql_type = Integer)] id: i32, #[diesel(sql_type = Text)] title: String, - #[diesel(sql_type = Nullable)] + #[diesel(sql_type = Nullable)] author: Option, // published_year: NaiveDateTime, } @@ -176,7 +176,7 @@ async fn test_orm_insert() { } /// StoredIdentityUpdate holds a serialized IdentityUpdate record -#[derive(Insertable, Identifiable, Queryable, Debug, Clone, PartialEq, Eq)] +#[derive(Insertable, Identifiable, Queryable, Selectable, Debug, Clone, PartialEq, Eq)] #[diesel(table_name = test_table)] #[diesel(primary_key(id, id2))] pub struct Item { @@ -216,6 +216,36 @@ async fn can_insert_or_ignore() { insert_or_ignore(&updates, &mut conn); } +#[wasm_bindgen_test] +async fn can_retrieve_blob() { + init().await; + let mut conn = establish_connection().await; + let updates = vec![ + Item { + id: "test".into(), + id2: 13, + timestamp_ns: 1231232, + payload: b"testing 1".to_vec(), + }, + Item { + id: "test2".into(), + id2: 14, + timestamp_ns: 1201222, + payload: b"testing 2".to_vec(), + }, + ]; + insert_or_ignore(&updates, &mut conn); + + let res = schema::test_table::dsl::test_table + .select(Item::as_select()) + .load(&mut conn) + .unwrap(); + + assert_eq!(res[0].payload, b"testing 1"); + assert_eq!(res[1].payload, b"testing 2"); + +} + #[wasm_bindgen_test] async fn serializing() { init().await; @@ -259,3 +289,44 @@ async fn serializing() { },] ); } + +#[wasm_bindgen_test] +async fn can_find() { + use schema::{books::dsl, self}; + + init().await; + let mut conn = establish_connection().await; + let new_books = vec![ + BookForm { + title: "Game of Thrones".into(), + author: Some("George R.R".into()), + }, + BookForm { + title: "1984".into(), + author: Some("George Orwell".into()), + } + ]; + + let changed = insert_books(&mut conn, new_books).unwrap(); + tracing::info!("{changed} rows changed"); + + let res: Option = dsl::books.find(1).first(&mut conn).optional().unwrap(); + tracing::debug!("res: {:?}", res); + tracing::debug!("FIND RES: {:?}", res); + + let res: Vec = diesel::sql_query("SELECT * FROM books where (id = 1)") + .load::(&mut conn).unwrap(); + tracing::debug!("SQL_QUERY RES: {:?}", res); +/* + assert_eq!(res, vec![ + StoredBook { id: 0, title: "Game of Thrones".into(), author: Some("George R.R".into()) } + ]); +*/ + let stored_books = schema::books::dsl::books + .select(StoredBook::as_select()) + .load(&mut conn); + tracing::debug!("Books: {:?}", stored_books); + + let first: Option = dsl::books.first(&mut conn).optional().unwrap(); + tracing::debug!("FIRST BOOK {:?}", first) +} diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index d9749c8d1..2369ab331 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -114,6 +114,7 @@ tracing-wasm = { version = "0.2" } diesel-wasm-sqlite = { workspace = true, features = ["unsafe-debug-query", "r2d2"] } console_error_panic_hook = { version = "0.1"} wasm-bindgen-test.workspace = true +tracing-subscriber = { workspace = true, features = ["env-filter"] } [[bin]] doc = false diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 3d4d52f65..b5eaca39b 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -612,6 +612,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn identity_persistence_test() { + // crate::utils::wasm::init().await; let tmpdb = tmp_path(); let wallet = &generate_local_wallet(); let db_key = EncryptedMessageStore::generate_enc_key(); diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 61bba1c46..e7c961105 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -1634,7 +1634,7 @@ pub(crate) mod tests { assert!(matching_message.is_some()); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr( not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread", worker_threads = 1) diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index 6244ad6e9..aa172d1d2 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -608,7 +608,7 @@ pub(crate) mod tests { assert!(association_state.get(&wallet_2_address.into()).is_some()); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] #[tracing_test::traced_test] async fn cache_association_state() { diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index dadbc05a5..af192d95c 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -654,7 +654,7 @@ pub(crate) mod tests { // try to write with second connection // write should fail & rollback // first thread succeeds - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_transaction_rollback() { let db_path = tmp_path(); diff --git a/xmtp_mls/src/storage/encrypted_store/wasm.rs b/xmtp_mls/src/storage/encrypted_store/wasm.rs index cefb87fea..9938dd808 100644 --- a/xmtp_mls/src/storage/encrypted_store/wasm.rs +++ b/xmtp_mls/src/storage/encrypted_store/wasm.rs @@ -35,9 +35,9 @@ impl WasmDb { let conn = match opts { Ephemeral => SqliteConnection::establish(":memory:"), Persistent(ref db_path) => SqliteConnection::establish(db_path), - }; + }?; Ok(Self { - conn: Arc::new(Mutex::new(conn?)), + conn: Arc::new(Mutex::new(conn)), opts: opts.clone(), enc_key, }) diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index bbf6a41b7..5313c69eb 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -48,15 +48,17 @@ pub mod wasm { use tokio::sync::OnceCell; static INIT: OnceCell<()> = OnceCell::const_new(); + /// can be used to debug wasm tests + /// normal tracing logs are output to the browser console #[cfg(all(target_arch = "wasm32", test))] pub async fn init() { use web_sys::console; - tracing_log::LogTracer::init().unwrap(); + use tracing_subscriber::prelude::*; INIT.get_or_init(|| async { console::log_1(&"INIT".into()); - console_error_panic_hook::set_once(); tracing_wasm::set_as_global_default(); + console_error_panic_hook::set_once(); diesel_wasm_sqlite::init_sqlite().await; }) .await; From 7adbb97a100ac63bc02a28db309c582762a46b83 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 30 Sep 2024 19:24:53 -0400 Subject: [PATCH 42/97] fix bindings_ffi build --- bindings_ffi/Cargo.lock | 98 ++++++++++++++++++++- bindings_ffi/src/mls.rs | 7 +- bindings_node/Cargo.lock | 180 ++++++++++++++++++++++++++++++++++----- bindings_wasm/Cargo.lock | 9 +- xmtp_mls/Cargo.toml | 2 +- 5 files changed, 261 insertions(+), 35 deletions(-) diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 729d34607..49d17ce08 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -2621,6 +2621,15 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matchit" version = "0.7.3" @@ -2746,6 +2755,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -3019,6 +3038,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "p256" version = "0.13.2" @@ -3688,10 +3713,19 @@ checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata", + "regex-automata 0.4.4", "regex-syntax 0.8.2", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + [[package]] name = "regex-automata" version = "0.4.4" @@ -3703,6 +3737,12 @@ dependencies = [ "regex-syntax 0.8.2", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.7.5" @@ -4332,6 +4372,15 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -4658,6 +4707,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.3.36" @@ -5011,6 +5070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", ] [[package]] @@ -5023,6 +5083,35 @@ dependencies = [ "tracing", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "trait-variant" version = "0.1.2" @@ -5317,6 +5406,12 @@ dependencies = [ "rand", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -5849,6 +5944,7 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "tracing-subscriber", "trait-variant", "wasm-bindgen-futures", "wasm-timer", diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 78784ff1d..c65ccec5a 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -7,16 +7,11 @@ use std::convert::TryInto; use std::sync::Arc; use tokio::sync::Mutex; use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; -use xmtp_id::associations::unverified::UnverifiedSignature; -use xmtp_id::associations::AccountId; -use xmtp_id::associations::AssociationState; -use xmtp_id::associations::MemberIdentifier; -use xmtp_id::scw_verifier::RpcSmartContractWalletVerifier; -use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_id::{ associations::{ builder::SignatureRequest, generate_inbox_id as xmtp_id_generate_inbox_id, unverified::UnverifiedSignature, AccountId, AssociationState, + MemberIdentifier }, scw_verifier::{RpcSmartContractWalletVerifier, SmartContractSignatureVerifier}, InboxId, diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index 3e95fcbd6..9c9fd7239 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -858,6 +858,25 @@ dependencies = [ "time", ] +[[package]] +name = "diesel-wasm-sqlite" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "174378a6e27ada82d3faaac17ec226044f2b2590554bcb549622d3d2317f9909" +dependencies = [ + "diesel", + "diesel_derives", + "js-sys", + "serde", + "serde-wasm-bindgen", + "talc", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", +] + [[package]] name = "diesel_derives" version = "2.2.0" @@ -965,6 +984,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "ecdsa" version = "0.15.1" @@ -1505,6 +1530,21 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fluvio-wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b768c170dc045fa587a8f948c91f9bcfb87f774930477c6215addf54317f137f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1638,7 +1678,7 @@ version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ - "gloo-timers", + "gloo-timers 0.2.6", "send_wrapper 0.4.0", ] @@ -1727,6 +1767,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "group" version = "0.12.1" @@ -2197,6 +2249,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -2469,13 +2524,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2683,6 +2739,8 @@ version = "0.6.0-pre.2" source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" dependencies = [ "backtrace", + "fluvio-wasm-timer", + "getrandom", "itertools 0.10.5", "log", "once_cell", @@ -2882,6 +2940,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -2889,7 +2958,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -2900,7 +2983,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", "windows-targets 0.52.5", ] @@ -3317,7 +3400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ "log", - "parking_lot", + "parking_lot 0.12.3", "scheduled-thread-pool", ] @@ -3386,6 +3469,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.1" @@ -3829,7 +3921,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -3947,6 +4039,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.202" @@ -4135,7 +4238,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "phf_shared 0.10.0", "precomputed-hash", ] @@ -4249,6 +4352,15 @@ dependencies = [ "libc", ] +[[package]] +name = "talc" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" +dependencies = [ + "lock_api", +] + [[package]] name = "tap" version = "1.0.1" @@ -4377,27 +4489,26 @@ dependencies = [ [[package]] name = "tokio" -version = "1.37.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -4746,9 +4857,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -4912,6 +5023,21 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.69" @@ -5237,10 +5363,13 @@ version = "0.0.1" dependencies = [ "async-trait", "chrono", + "ed25519", "ed25519-dalek", "ethers", "futures", + "getrandom", "hex", + "openmls", "openmls_traits", "prost", "rand", @@ -5252,28 +5381,35 @@ dependencies = [ "tokio", "tracing", "url", + "wasm-timer", "xmtp_cryptography", "xmtp_proto", ] [[package]] name = "xmtp_mls" -version = "0.0.1" +version = "0.1.0" dependencies = [ "aes-gcm", "async-stream", + "async-trait", "bincode", + "chrono", "diesel", + "diesel-wasm-sqlite", "diesel_migrations", + "dyn-clone", "ed25519-dalek", "futures", + "getrandom", + "gloo-timers 0.3.0", "hex", "libsqlite3-sys", "openmls", "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", - "parking_lot", + "parking_lot 0.12.3", "prost", "rand", "reqwest 0.12.4", @@ -5284,13 +5420,15 @@ dependencies = [ "tls_codec", "tokio", "tokio-stream", - "toml", "tracing", "trait-variant", - "xmtp_api_grpc", + "wasm-bindgen-futures", + "wasm-timer", + "web-sys", "xmtp_cryptography", "xmtp_id", "xmtp_proto", + "xmtp_v2", ] [[package]] diff --git a/bindings_wasm/Cargo.lock b/bindings_wasm/Cargo.lock index 6af417434..8e844bb2f 100644 --- a/bindings_wasm/Cargo.lock +++ b/bindings_wasm/Cargo.lock @@ -4694,6 +4694,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5322,12 +5323,12 @@ dependencies = [ "async-stream", "futures", "hyper 1.4.1", - "log", "reqwest 0.12.7", "serde", "serde_json", "thiserror", "tokio", + "tracing", "xmtp_proto", ] @@ -5341,7 +5342,6 @@ dependencies = [ "getrandom", "hex", "k256 0.13.3", - "log", "rand", "rand_chacha", "rustc-hex", @@ -5349,6 +5349,7 @@ dependencies = [ "sha2", "sha3", "thiserror", + "tracing", ] [[package]] @@ -5363,10 +5364,7 @@ dependencies = [ "futures", "getrandom", "hex", - "log", "openmls", - "openmls_basic_credential", - "openmls_rust_crypto", "openmls_traits", "prost", "rand", @@ -5402,7 +5400,6 @@ dependencies = [ "gloo-timers 0.3.0", "hex", "libsqlite3-sys", - "log", "openmls", "openmls_basic_credential", "openmls_rust_crypto", diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index ab88e1d45..27b9e3ae0 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -10,7 +10,7 @@ targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown", "aarch64-apple- [features] default = [] -test-utils = ["dep:xmtp_api_grpc", "xmtp_id/test-utils"] +test-utils = ["dep:xmtp_api_grpc", "xmtp_id/test-utils", "tracing-subscriber"] bench = ["test-utils", "indicatif", "tracing-subscriber", "anyhow", "tracing-flame", "once_cell", "dep:xmtp_api_grpc", "criterion"] update-schema = ["toml"] http-api = ["xmtp_api_http"] From 9f4e45f95f82a2a783915dd2e240f74e3f8e5fa4 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 30 Sep 2024 19:50:55 -0400 Subject: [PATCH 43/97] fmt --- bindings_ffi/src/mls.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index c65ccec5a..01e25954c 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -10,8 +10,7 @@ use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_id::{ associations::{ builder::SignatureRequest, generate_inbox_id as xmtp_id_generate_inbox_id, - unverified::UnverifiedSignature, AccountId, AssociationState, - MemberIdentifier + unverified::UnverifiedSignature, AccountId, AssociationState, MemberIdentifier, }, scw_verifier::{RpcSmartContractWalletVerifier, SmartContractSignatureVerifier}, InboxId, From 895ec4ad8a983dbdb68d151363f51022d7cff419 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 14:31:50 -0400 Subject: [PATCH 44/97] Fix WASM tests (138/151) (#1100) * make bindings_wasm a part of the workspace * fmt * fix test_add_missing_installations * handle allocations of length 0 in webassembly --- Cargo.lock | 17 + Cargo.toml | 7 +- bindings_wasm/Cargo.lock | 5555 ----------------- bindings_wasm/Cargo.toml | 10 +- bindings_wasm/src/mls_client.rs | 1 - diesel-wasm-sqlite/package.js | 18 +- diesel-wasm-sqlite/src/connection/stmt.rs | 28 +- diesel-wasm-sqlite/src/ffi/wasm.rs | 30 +- .../src/js/wa-sqlite-diesel-bundle.js | 18 +- xmtp_mls/Cargo.toml | 4 +- xmtp_mls/src/builder.rs | 1 - xmtp_mls/src/groups/validated_commit.rs | 2 +- xmtp_mls/src/storage/encrypted_store/mod.rs | 13 +- xmtp_mls/src/storage/encrypted_store/wasm.rs | 14 +- xmtp_mls/src/utils/mod.rs | 6 +- 15 files changed, 100 insertions(+), 5624 deletions(-) delete mode 100644 bindings_wasm/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index 14479f1fd..545513fa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,6 +367,23 @@ dependencies = [ "serde", ] +[[package]] +name = "bindings_wasm" +version = "0.0.1" +dependencies = [ + "js-sys", + "serde", + "serde-wasm-bindgen", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test", + "xmtp_api_http", + "xmtp_cryptography", + "xmtp_id", + "xmtp_mls", + "xmtp_proto", +] + [[package]] name = "bit-set" version = "0.5.3" diff --git a/Cargo.toml b/Cargo.toml index de4b10c51..09a1bea67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,12 +10,12 @@ members = [ "xmtp_user_preferences", "xmtp_v2", "xmtp_mls", - "xmtp_id" + "xmtp_id", + "bindings_wasm" ] exclude = [ "bindings_ffi", - "bindings_wasm", "bindings_node", "diesel-wasm-sqlite" ] @@ -67,7 +67,10 @@ diesel-wasm-sqlite = "0.0.1" diesel_migrations = { version = "2.2", default-features = false } wasm-bindgen-test = "0.3.42" wasm-bindgen-futures = "0.4" +wasm-bindgen = "=0.2.92" gloo-timers = "0.3" +web-sys = "0.3" +js-sys = "0.3" # Internal Crate Dependencies xmtp_cryptography = { path = "xmtp_cryptography" } diff --git a/bindings_wasm/Cargo.lock b/bindings_wasm/Cargo.lock deleted file mode 100644 index 8e844bb2f..000000000 --- a/bindings_wasm/Cargo.lock +++ /dev/null @@ -1,5555 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "async-trait" -version = "0.1.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "auto_impl" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "axum" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 1.0.1", - "tower 0.5.1", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 1.0.1", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide 0.7.4", - "object", - "rustc-demangle", -] - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bindings_wasm" -version = "0.1.0" -dependencies = [ - "js-sys", - "serde", - "serde-wasm-bindgen", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test", - "xmtp_api_http", - "xmtp_cryptography", - "xmtp_id", - "xmtp_mls", - "xmtp_proto", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "sha2", - "tinyvec", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" -dependencies = [ - "serde", -] - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "coins-bip32" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" -dependencies = [ - "bs58", - "coins-core", - "digest", - "hmac", - "k256 0.13.3", - "serde", - "sha2", - "thiserror", -] - -[[package]] -name = "coins-bip39" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" -dependencies = [ - "bitvec", - "coins-bip32", - "hmac", - "once_cell", - "pbkdf2 0.12.2", - "rand", - "sha2", - "thiserror", -] - -[[package]] -name = "coins-core" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" -dependencies = [ - "base64 0.21.7", - "bech32", - "bs58", - "digest", - "generic-array", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2", - "sha3", - "thiserror", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "const-hex" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" -dependencies = [ - "cfg-if", - "cpufeatures", - "hex", - "proptest", - "serde", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.76", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "diesel" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "diesel_derives 2.2.0", - "downcast-rs", - "libsqlite3-sys", - "r2d2", - "time", -] - -[[package]] -name = "diesel-wasm-sqlite" -version = "0.0.1" -dependencies = [ - "diesel", - "diesel_derives 2.2.3", - "js-sys", - "serde", - "serde-wasm-bindgen", - "talc", - "thiserror", - "tokio", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", -] - -[[package]] -name = "diesel_derives" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "diesel_table_macro_syntax 0.2.0 (git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub)", - "dsl_auto_type 0.1.0", - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "diesel_derives" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" -dependencies = [ - "diesel_table_macro_syntax 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dsl_auto_type 0.1.2", - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "diesel_migrations" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "diesel", - "migrations_internals", - "migrations_macros", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" -dependencies = [ - "syn 2.0.76", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "syn 2.0.76", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[package]] -name = "dsl_auto_type" -version = "0.1.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "darling", - "either", - "heck", - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "dsl_auto_type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" -dependencies = [ - "darling", - "either", - "heck", - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" - -[[package]] -name = "ecdsa" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12844141594ad74185a926d030f3b605f6a903b4e3fec351f3ea338ac5b7637e" -dependencies = [ - "der 0.6.1", - "elliptic-curve 0.12.3", - "rfc6979 0.3.1", - "signature", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der 0.7.9", - "digest", - "elliptic-curve 0.13.8", - "rfc6979 0.4.0", - "signature", - "spki 0.7.3", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8 0.10.2", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", - "serde", - "sha2", - "signature", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct 0.1.1", - "crypto-bigint 0.4.9", - "der 0.6.1", - "digest", - "ff 0.12.1", - "generic-array", - "group 0.12.1", - "hkdf", - "pkcs8 0.9.0", - "rand_core", - "sec1 0.3.0", - "subtle", - "zeroize", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.5", - "digest", - "ff 0.13.0", - "generic-array", - "group 0.13.0", - "hkdf", - "pem-rfc7468", - "pkcs8 0.10.2", - "rand_core", - "sec1 0.7.3", - "subtle", - "zeroize", -] - -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enr" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" -dependencies = [ - "base64 0.21.7", - "bytes", - "hex", - "k256 0.13.3", - "log", - "rand", - "rlp", - "serde", - "sha3", - "zeroize", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "eth-keystore" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" -dependencies = [ - "aes", - "ctr", - "digest", - "hex", - "hmac", - "pbkdf2 0.11.0", - "rand", - "scrypt", - "serde", - "serde_json", - "sha2", - "sha3", - "thiserror", - "uuid", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" -dependencies = [ - "ethers-addressbook", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-middleware", - "ethers-providers", - "ethers-signers", - "ethers-solc", -] - -[[package]] -name = "ethers-addressbook" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" -dependencies = [ - "ethers-core", - "once_cell", - "serde", - "serde_json", -] - -[[package]] -name = "ethers-contract" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" -dependencies = [ - "const-hex", - "ethers-contract-abigen", - "ethers-contract-derive", - "ethers-core", - "ethers-providers", - "futures-util", - "once_cell", - "pin-project", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "ethers-contract-abigen" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" -dependencies = [ - "Inflector", - "const-hex", - "dunce", - "ethers-core", - "ethers-etherscan", - "eyre", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "reqwest 0.11.27", - "serde", - "serde_json", - "syn 2.0.76", - "toml", - "walkdir", -] - -[[package]] -name = "ethers-contract-derive" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" -dependencies = [ - "Inflector", - "const-hex", - "ethers-contract-abigen", - "ethers-core", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.76", -] - -[[package]] -name = "ethers-core" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" -dependencies = [ - "arrayvec", - "bytes", - "cargo_metadata", - "chrono", - "const-hex", - "elliptic-curve 0.13.8", - "ethabi", - "generic-array", - "k256 0.13.3", - "num_enum", - "once_cell", - "open-fastrlp", - "rand", - "rlp", - "serde", - "serde_json", - "strum", - "syn 2.0.76", - "tempfile", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ethers-etherscan" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" -dependencies = [ - "chrono", - "ethers-core", - "reqwest 0.11.27", - "semver", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "ethers-middleware" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" -dependencies = [ - "async-trait", - "auto_impl", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", - "futures-channel", - "futures-locks", - "futures-util", - "instant", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-futures", - "url", -] - -[[package]] -name = "ethers-providers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" -dependencies = [ - "async-trait", - "auto_impl", - "base64 0.21.7", - "bytes", - "const-hex", - "enr", - "ethers-core", - "futures-core", - "futures-timer", - "futures-util", - "hashers", - "http 0.2.12", - "instant", - "jsonwebtoken", - "once_cell", - "pin-project", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-tungstenite", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "ws_stream_wasm", -] - -[[package]] -name = "ethers-signers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" -dependencies = [ - "async-trait", - "coins-bip32", - "coins-bip39", - "const-hex", - "elliptic-curve 0.13.8", - "eth-keystore", - "ethers-core", - "rand", - "sha2", - "thiserror", - "tracing", -] - -[[package]] -name = "ethers-solc" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66244a771d9163282646dbeffe0e6eca4dda4146b6498644e678ac6089b11edd" -dependencies = [ - "cfg-if", - "const-hex", - "dirs", - "dunce", - "ethers-core", - "glob", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver", - "serde", - "serde_json", - "solang-parser", - "svm-rs", - "thiserror", - "tiny-keccak", - "tokio", - "tracing", - "walkdir", - "yansi", -] - -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "fastrand" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" -dependencies = [ - "crc32fast", - "miniz_oxide 0.8.0", -] - -[[package]] -name = "fluvio-wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b768c170dc045fa587a8f948c91f9bcfb87f774930477c6215addf54317f137f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-locks" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" -dependencies = [ - "futures-channel", - "futures-task", -] - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" -dependencies = [ - "gloo-timers 0.2.6", - "send_wrapper 0.4.0", -] - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff 0.12.1", - "rand_core", - "subtle", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff 0.13.0", - "rand_core", - "subtle", -] - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.4.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.1.0", - "indexmap 2.4.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashers" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "hpke-rs" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11bd4ee27b79fa1820e72ef8489cc729c87299ec3f7f52b8fc8dcb87cb2d485" -dependencies = [ - "hpke-rs-crypto", - "log", - "serde", - "tls_codec", - "zeroize", -] - -[[package]] -name = "hpke-rs-crypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3f1ae0a26c18d6469a70db1217136056261c4a244b09a755bc60bd4e055b67" -dependencies = [ - "rand_core", -] - -[[package]] -name = "hpke-rs-rust-crypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08d4500baf0aced746723d3515d08212bdb9d941df6d1aca3d46d1619b2a1cf" -dependencies = [ - "aes-gcm", - "chacha20poly1305", - "hkdf", - "hpke-rs-crypto", - "p256", - "p384", - "rand_chacha", - "rand_core", - "sha2", - "x25519-dalek", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.1.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" -dependencies = [ - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.30", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" -dependencies = [ - "futures-util", - "http 1.1.0", - "hyper 1.4.1", - "hyper-util", - "rustls 0.23.12", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.0", - "tower-service", -] - -[[package]] -name = "hyper-timeout" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" -dependencies = [ - "hyper 1.4.1", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.4.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.4.1", - "pin-project-lite", - "socket2", - "tokio", - "tower 0.4.13", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" -dependencies = [ - "equivalent", - "hashbrown 0.14.5", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" -dependencies = [ - "base64 0.21.7", - "pem", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "k256" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a55e0ff3b72c262bcf041d9e97f1b84492b68f1c1a384de2323d3dc9403397" -dependencies = [ - "cfg-if", - "ecdsa 0.15.1", - "elliptic-curve 0.12.3", - "once_cell", - "sha2", - "signature", -] - -[[package]] -name = "k256" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" -dependencies = [ - "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "once_cell", - "sha2", - "signature", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4588d65215825ee71ebff9e1c9982067833b1355d7546845ffdb3165cbd7456" -dependencies = [ - "cc", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "migrations_internals" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "serde", - "toml", -] - -[[package]] -name = "migrations_macros" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" -dependencies = [ - "hermit-abi", - "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "object" -version = "0.36.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "openmls" -version = "0.6.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "backtrace", - "fluvio-wasm-timer", - "getrandom", - "itertools 0.10.5", - "log", - "once_cell", - "openmls_basic_credential", - "openmls_memory_storage", - "openmls_rust_crypto", - "openmls_test", - "openmls_traits", - "rand", - "rayon", - "serde", - "serde_json", - "thiserror", - "tls_codec", - "wasm-bindgen-test", -] - -[[package]] -name = "openmls_basic_credential" -version = "0.3.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "ed25519-dalek", - "openmls_traits", - "p256", - "rand", - "serde", - "tls_codec", -] - -[[package]] -name = "openmls_memory_storage" -version = "0.3.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "hex", - "log", - "openmls_traits", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "openmls_rust_crypto" -version = "0.3.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "aes-gcm", - "chacha20poly1305", - "ed25519-dalek", - "hkdf", - "hmac", - "hpke-rs", - "hpke-rs-crypto", - "hpke-rs-rust-crypto", - "openmls_memory_storage", - "openmls_traits", - "p256", - "rand", - "rand_chacha", - "serde", - "sha2", - "thiserror", - "tls_codec", -] - -[[package]] -name = "openmls_test" -version = "0.1.0-pre.1" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "ansi_term", - "openmls_rust_crypto", - "openmls_traits", - "proc-macro2", - "quote", - "rstest", - "rstest_reuse", - "syn 2.0.76", -] - -[[package]] -name = "openmls_traits" -version = "0.3.0-pre.2" -source = "git+https://github.com/xmtp/openmls?rev=87e7e257d8eb15d6662b104518becfc75ef6db76#87e7e257d8eb15d6662b104518becfc75ef6db76" -dependencies = [ - "serde", - "tls_codec", -] - -[[package]] -name = "openssl" -version = "0.10.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.3.1+3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "primeorder", - "sha2", -] - -[[package]] -name = "p384" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" -dependencies = [ - "elliptic-curve 0.13.8", - "primeorder", -] - -[[package]] -name = "parity-scale-codec" -version = "3.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.3", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "path-slash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" - -[[package]] -name = "pbjson" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" -dependencies = [ - "base64 0.21.7", - "serde", -] - -[[package]] -name = "pbjson-build" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" -dependencies = [ - "heck", - "itertools 0.13.0", - "prost", - "prost-types", -] - -[[package]] -name = "pbjson-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" -dependencies = [ - "bytes", - "chrono", - "pbjson", - "pbjson-build", - "prost", - "prost-build", - "serde", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.4.0", -] - -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der 0.6.1", - "spki 0.6.0", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der 0.7.9", - "spki 0.7.3", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" -dependencies = [ - "proc-macro2", - "syn 2.0.76", -] - -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve 0.13.8", -] - -[[package]] -name = "primitive-types" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proptest" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" -dependencies = [ - "bitflags 2.6.0", - "lazy_static", - "num-traits", - "rand", - "rand_chacha", - "rand_xorshift", - "regex-syntax", - "unarray", -] - -[[package]] -name = "prost" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" -dependencies = [ - "bytes", - "heck", - "itertools 0.12.1", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.76", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" -dependencies = [ - "anyhow", - "itertools 0.12.1", - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "prost-types" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot 0.12.3", - "scheduled-thread-pool", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "hyper-rustls 0.24.2", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration 0.5.1", - "tokio", - "tokio-rustls 0.24.1", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", - "winreg", -] - -[[package]] -name = "reqwest" -version = "0.12.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.4.1", - "hyper-rustls 0.27.2", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 2.1.3", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 1.0.1", - "system-configuration 0.6.1", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "windows-registry", -] - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac", - "zeroize", -] - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rlp-derive", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rstest" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962" -dependencies = [ - "futures", - "futures-timer", - "rstest_macros", - "rustc_version", -] - -[[package]] -name = "rstest_macros" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", - "unicode-ident", -] - -[[package]] -name = "rstest_reuse" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f80dcc84beab3a327bbe161f77db25f336a1452428176787c8c79ac79d7073" -dependencies = [ - "quote", - "rand", - "rustc_version", - "syn 1.0.109", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring 0.17.8", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki 0.102.7", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-pemfile" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" -dependencies = [ - "base64 0.22.1", - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "rustls-webpki" -version = "0.102.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" -dependencies = [ - "ring 0.17.8", - "rustls-pki-types", - "untrusted 0.9.0", -] - -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scale-info" -version = "2.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot 0.12.3", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scrypt" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" -dependencies = [ - "hmac", - "pbkdf2 0.11.0", - "salsa20", - "sha2", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array", - "pkcs8 0.9.0", - "subtle", - "zeroize", -] - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct 0.2.0", - "der 0.7.9", - "generic-array", - "pkcs8 0.10.2", - "subtle", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] - -[[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - -[[package]] -name = "serde" -version = "1.0.209" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.209" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "serde_json" -version = "1.0.127" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signature" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "solang-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" -dependencies = [ - "itertools 0.11.0", - "lalrpop", - "lalrpop-util", - "phf", - "thiserror", - "unicode-xid", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der 0.7.9", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot 0.12.3", - "phf_shared 0.10.0", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.76", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "svm-rs" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11297baafe5fa0c99d5722458eac6a5e25c01eb1b8e5cd137f54079093daa7a4" -dependencies = [ - "dirs", - "fs2", - "hex", - "once_cell", - "reqwest 0.11.27", - "semver", - "serde", - "serde_json", - "sha2", - "thiserror", - "url", - "zip", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" -dependencies = [ - "futures-core", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys 0.5.0", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "system-configuration-sys 0.6.0", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "talc" -version = "4.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" -dependencies = [ - "lock_api", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tls_codec" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a" -dependencies = [ - "serde", - "tls_codec_derive", - "zeroize", -] - -[[package]] -name = "tls_codec_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "tokio" -version = "1.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "tokio-macros", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" -dependencies = [ - "rustls 0.23.12", - "rustls-pki-types", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", - "tungstenite", - "webpki-roots", -] - -[[package]] -name = "tokio-util" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap 2.4.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tonic" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.22.1", - "bytes", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.4.1", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost", - "socket2", - "tokio", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper 0.1.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 0.2.12", - "httparse", - "log", - "rand", - "rustls 0.21.12", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unarray" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.76", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "wasm-bindgen-test" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "wasm-streams" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-registry" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" -dependencies = [ - "windows-result", - "windows-strings", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "ws_stream_wasm" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version", - "send_wrapper 0.6.0", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "x25519-dalek" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" -dependencies = [ - "curve25519-dalek", - "rand_core", - "serde", - "zeroize", -] - -[[package]] -name = "xmtp_api_http" -version = "0.0.1" -dependencies = [ - "async-stream", - "futures", - "hyper 1.4.1", - "reqwest 0.12.7", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "xmtp_proto", -] - -[[package]] -name = "xmtp_cryptography" -version = "0.0.1" -dependencies = [ - "curve25519-dalek", - "ecdsa 0.16.9", - "ethers", - "getrandom", - "hex", - "k256 0.13.3", - "rand", - "rand_chacha", - "rustc-hex", - "serde", - "sha2", - "sha3", - "thiserror", - "tracing", -] - -[[package]] -name = "xmtp_id" -version = "0.0.1" -dependencies = [ - "async-trait", - "chrono", - "ed25519", - "ed25519-dalek", - "ethers", - "futures", - "getrandom", - "hex", - "openmls", - "openmls_traits", - "prost", - "rand", - "regex", - "rustc-hex", - "serde", - "sha2", - "thiserror", - "tokio", - "tracing", - "url", - "wasm-timer", - "xmtp_cryptography", - "xmtp_proto", -] - -[[package]] -name = "xmtp_mls" -version = "0.1.0" -dependencies = [ - "aes-gcm", - "async-stream", - "async-trait", - "bincode", - "chrono", - "diesel", - "diesel-wasm-sqlite", - "diesel_migrations", - "dyn-clone", - "ed25519-dalek", - "futures", - "getrandom", - "gloo-timers 0.3.0", - "hex", - "libsqlite3-sys", - "openmls", - "openmls_basic_credential", - "openmls_rust_crypto", - "openmls_traits", - "parking_lot 0.12.3", - "prost", - "rand", - "reqwest 0.12.7", - "serde", - "serde_json", - "sha2", - "thiserror", - "tls_codec", - "tokio", - "tokio-stream", - "tracing", - "trait-variant", - "wasm-bindgen-futures", - "wasm-timer", - "web-sys", - "xmtp_cryptography", - "xmtp_id", - "xmtp_proto", - "xmtp_v2", -] - -[[package]] -name = "xmtp_proto" -version = "0.0.1" -dependencies = [ - "futures", - "openmls", - "pbjson", - "pbjson-types", - "prost", - "prost-types", - "serde", - "tonic", - "trait-variant", -] - -[[package]] -name = "xmtp_v2" -version = "0.0.1" -dependencies = [ - "aes-gcm", - "ecdsa 0.15.1", - "generic-array", - "getrandom", - "hex", - "hkdf", - "k256 0.12.0", - "rand", - "rand_chacha", - "sha2", - "sha3", -] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.76", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index b75956af2..689cb953a 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -1,18 +1,18 @@ [package] edition = "2021" name = "bindings_wasm" -version = "0.1.0" resolver = "2" +version.workspace = true [lib] crate-type = ["cdylib", "rlib"] [dependencies] -js-sys = "0.3" -serde = { version = "1.0", features = ["derive"] } +js-sys.workspace = true +serde = { workspace = true, features = ["derive"] } serde-wasm-bindgen = "0.6.5" -wasm-bindgen = "=0.2.92" -wasm-bindgen-futures = "0.4.41" +wasm-bindgen.workspace = true +wasm-bindgen-futures.workspace = true xmtp_api_http = { path = "../xmtp_api_http" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } diff --git a/bindings_wasm/src/mls_client.rs b/bindings_wasm/src/mls_client.rs index 68b005c0f..17320273b 100644 --- a/bindings_wasm/src/mls_client.rs +++ b/bindings_wasm/src/mls_client.rs @@ -45,7 +45,6 @@ pub async fn create_client( EncryptedMessageStore::new(storage_option, key) .await .map_err(|_| JsError::new("Error creating encrypted message store"))? - } None => EncryptedMessageStore::new_unencrypted(storage_option) .await diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index d51990cf7..b391d131d 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -198,22 +198,6 @@ export class SQLite { ); } - into_statement(pStmt) { - const BindTypes = { - null: 1, - number: 2, - string: 3, - boolean: 4, - blob: 5, - }; - BindTypes["undefined"] == BindTypes.null; - if (wasm.bigIntEnabled) { - BindTypes.bigint = BindTypes.number; - } - - new Stmt(this, pStmt, BindTypes); - } - step(stmt) { return this.sqlite3.capi.sqlite3_step(stmt); } @@ -259,7 +243,7 @@ export class SQLite { } //TODO: At some point need a way to register functions from rust - //but for just libxmtp this is fine. + //but for now this is fine. register_diesel_sql_functions(database) { try { this.sqlite3.capi.sqlite3_create_function( diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index b5dc418f0..cc3255b61 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -86,6 +86,24 @@ impl Statement { }) } + fn copy_value_to_sqlite(bytes: &[u8]) -> *mut u8 { + let sqlite3 = crate::get_sqlite_unchecked(); + let wasm = sqlite3.inner().wasm(); + let wasm_inner = wasm.alloc_inner(); + + let len = bytes.len(); + let ptr = if len == 0 { + wasm.alloc_ptr(1, true) + } else { + wasm_inner.alloc_impl(len as u32) + }; + ffi::raw_copy_to_sqlite(bytes, ptr); + // TODO: Maybe check for null here and return [`std::ptr::NonNull`]? + // null is valid for bind function, it will just bind_null instead + // but seems like something that should be an error. + ptr + } + // The caller of this function has to ensure that: // * Any buffer provided as `SqliteBindValue::BorrowedBinary`, `SqliteBindValue::Binary` // `SqliteBindValue::String` or `SqliteBindValue::BorrowedString` is valid @@ -108,8 +126,8 @@ impl Statement { } (SqliteType::Binary, InternalSqliteBindValue::BorrowedBinary(bytes)) => { // copy bytes from our WASM memory to SQLites WASM memory - let ptr = wasm.alloc(bytes.len() as u32); - ffi::raw_copy_to_sqlite(bytes, ptr); + tracing::trace!("Binding binary Borrowed! len={}", bytes.len()); + let ptr = Self::copy_value_to_sqlite(bytes); ret_ptr = NonNull::new(ptr); sqlite3.bind_blob( &self.inner_statement, @@ -120,8 +138,8 @@ impl Statement { ) } (SqliteType::Binary, InternalSqliteBindValue::Binary(bytes)) => { - let ptr = wasm.alloc(bytes.len() as u32); - ffi::raw_copy_to_sqlite(bytes.as_slice(), ptr); + tracing::trace!("Binding binary Owned! len={}", bytes.len()); + let ptr = Self::copy_value_to_sqlite(bytes.as_slice()); ret_ptr = NonNull::new(ptr); sqlite3.bind_blob( &self.inner_statement, @@ -132,6 +150,7 @@ impl Statement { ) } (SqliteType::Text, InternalSqliteBindValue::BorrowedString(bytes)) => { + tracing::trace!("Binding Borrowed String! len={}", bytes.len()); let ptr = wasm.alloc_cstring(bytes.to_string()); ret_ptr = NonNull::new(ptr); sqlite3.bind_text( @@ -143,6 +162,7 @@ impl Statement { ) } (SqliteType::Text, InternalSqliteBindValue::String(bytes)) => { + tracing::trace!("Binding Owned String!"); let len = bytes.len(); let ptr = wasm.alloc_cstring(bytes); ret_ptr = NonNull::new(ptr); diff --git a/diesel-wasm-sqlite/src/ffi/wasm.rs b/diesel-wasm-sqlite/src/ffi/wasm.rs index 3f02bdd55..7fa4415f8 100644 --- a/diesel-wasm-sqlite/src/ffi/wasm.rs +++ b/diesel-wasm-sqlite/src/ffi/wasm.rs @@ -22,11 +22,27 @@ extern "C" { #[wasm_bindgen(method)] pub fn alloc(this: &Wasm, bytes: u32) -> *mut u8; - // Uses alloc() to allocate enough memory for the byte-length of the given JS string, plus 1 (for a NUL terminator), copies the given JS string to that memory using jstrcpy(), NUL-terminates it, and returns the pointer to that C-string. Ownership of the pointer is transfered to the caller, who must eventually pass the pointer to dealloc() to free it. - // + #[wasm_bindgen(method, getter, js_name = "alloc")] + pub fn alloc_inner(this: &Wasm) -> Alloc; + + /// Uses alloc() to allocate enough memory for the byte-length of the given JS string, + /// plus 1 (for a NUL terminator), copies the given JS string to that memory using jstrcpy(), + /// NUL-terminates it, and returns the pointer to that C-string. + /// Ownership of the pointer is transfered to the caller, who must eventually pass the pointer to dealloc() to free it. + //TODO: Avoid using this since it allocates in JS and other webassembly. Instead use technique + // used in Statement::prepare #[wasm_bindgen(method, js_name = "allocCString")] pub fn alloc_cstring(this: &Wasm, string: String) -> *mut u8; + /// Allocates one or more pointers as a single chunk of memory and zeroes them out. + /// The first argument is the number of pointers to allocate. + /// The second specifies whether they should use a "safe" pointer size (8 bytes) + /// or whether they may use the default pointer size (typically 4 but also possibly 8). + /// How the result is returned depends on its first argument: if passed 1, it returns the allocated memory address. + /// If passed more than one then an array of pointer addresses is returned + #[wasm_bindgen(method, js_name = "allocPtr")] + pub fn alloc_ptr(this: &Wasm, how_many: u32, safe_ptr_size: bool) -> *mut u8; + #[wasm_bindgen(method)] pub fn dealloc(this: &Wasm, ptr: NonNull); @@ -63,3 +79,13 @@ extern "C" { pub fn restore(this: &PStack, ptr: &JsValue); } + +#[wasm_bindgen] +extern "C" { + pub type Alloc; + + /// Non-throwing version of `Wasm::Alloc` + /// returns NULL pointer if cannot allocate + #[wasm_bindgen(method, js_name = "impl")] + pub fn alloc_impl(this: &Alloc, bytes: u32) -> *mut u8; +} diff --git a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js index cd5904897..44ad73da3 100644 --- a/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js @@ -14604,22 +14604,6 @@ class SQLite { ); } - into_statement(pStmt) { - const BindTypes = { - null: 1, - number: 2, - string: 3, - boolean: 4, - blob: 5, - }; - BindTypes["undefined"] == BindTypes.null; - if (wasm.bigIntEnabled) { - BindTypes.bigint = BindTypes.number; - } - - new Stmt(this, pStmt, BindTypes); - } - step(stmt) { return this.sqlite3.capi.sqlite3_step(stmt); } @@ -14665,7 +14649,7 @@ class SQLite { } //TODO: At some point need a way to register functions from rust - //but for just libxmtp this is fine. + //but for now this is fine. register_diesel_sql_functions(database) { try { this.sqlite3.capi.sqlite3_create_function( diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 27b9e3ae0..84ae50c69 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -84,14 +84,14 @@ diesel = { workspace = true, features = [ "returning_clauses_for_sqlite_3_35", ] } diesel_migrations.workspace = true -getrandom = { version = "0.2", features = ["js"] } +getrandom = { workspace = true, features = ["js"] } chrono = { workspace = true, features = ["wasmbind"] } tokio = { workspace = true, features = ["macros", "rt"] } openmls = { workspace = true, features = ["test-utils", "js"] } gloo-timers = { workspace = true, features = ["futures"] } wasm-bindgen-futures.workspace = true -web-sys = "0.3" +web-sys.workspace = true [dev-dependencies] ethers.workspace = true mockall = "0.13.0" diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index cb9baab87..0d7482ee2 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -612,7 +612,6 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn identity_persistence_test() { - // crate::utils::wasm::init().await; let tmpdb = tmp_path(); let wallet = &generate_local_wallet(); let db_key = EncryptedMessageStore::generate_enc_key(); diff --git a/xmtp_mls/src/groups/validated_commit.rs b/xmtp_mls/src/groups/validated_commit.rs index bf67580e2..92742ddb0 100644 --- a/xmtp_mls/src/groups/validated_commit.rs +++ b/xmtp_mls/src/groups/validated_commit.rs @@ -289,7 +289,6 @@ impl ValidatedCommit { removed_installations, current_group_members, )?; - credentials_to_verify.push(actor.clone()); // Verify the credentials of the following entities @@ -480,6 +479,7 @@ async fn extract_expected_diff<'diff, ApiClient: XmtpApi>( .map(|inbox_id| build_inbox(inbox_id, immutable_metadata, mutable_metadata)) .collect::>(); + tracing::debug!("\n\n------------------------GETTING INSTALLATION DIFF ------------------------------------\n\n"); let expected_installation_diff = client .get_installation_diff( conn, diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index c6434132e..934240ce4 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -156,9 +156,9 @@ impl EncryptedMessageStore { /// This function is private so that an unencrypted database cannot be created by accident async fn new_database( opts: StorageOption, - enc_key: Option, + _enc_key: Option, ) -> Result { - let db = wasm::WasmDb::new(&opts, enc_key).await?; + let db = wasm::WasmDb::new(&opts).await?; let mut this = Self { db, opts }; this.init_db()?; Ok(this) @@ -404,12 +404,13 @@ macro_rules! impl_store_or_ignore { &self, into: &$crate::storage::encrypted_store::db_connection::DbConnection, ) -> Result<(), $crate::StorageError> { - let result = into.raw_query(|conn| { - diesel::insert_into($table::table) + into.raw_query(|conn| { + diesel::insert_or_ignore_into($table::table) .values(self) .execute(conn) - }); - $crate::storage::ignore_unique_violation(result) + .map_err(Into::into) + .map(|_| ()) + }) } } }; diff --git a/xmtp_mls/src/storage/encrypted_store/wasm.rs b/xmtp_mls/src/storage/encrypted_store/wasm.rs index 9938dd808..2d551c8a9 100644 --- a/xmtp_mls/src/storage/encrypted_store/wasm.rs +++ b/xmtp_mls/src/storage/encrypted_store/wasm.rs @@ -1,17 +1,16 @@ +//! WebAssembly specific connection for a SQLite Database +//! Stores a single connection behind a mutex that's used for every libxmtp operation use std::sync::Arc; use diesel::{connection::AnsiTransactionManager, prelude::*}; pub use diesel_wasm_sqlite::connection::WasmSqliteConnection as SqliteConnection; use parking_lot::Mutex; -use super::{ - db_connection::DbConnectionPrivate, EncryptionKey, StorageError, StorageOption, XmtpDb, -}; +use super::{db_connection::DbConnectionPrivate, StorageError, StorageOption, XmtpDb}; #[derive(Clone)] pub struct WasmDb { conn: Arc>, - enc_key: Option, opts: StorageOption, } @@ -19,17 +18,13 @@ impl std::fmt::Debug for WasmDb { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("WasmDb") .field("conn", &"WasmSqliteConnection") - .field("enc_key", &self.enc_key) .field("opts", &self.opts) .finish() } } impl WasmDb { - pub async fn new( - opts: &StorageOption, - enc_key: Option, - ) -> Result { + pub async fn new(opts: &StorageOption) -> Result { use super::StorageOption::*; diesel_wasm_sqlite::init_sqlite().await; let conn = match opts { @@ -39,7 +34,6 @@ impl WasmDb { Ok(Self { conn: Arc::new(Mutex::new(conn)), opts: opts.clone(), - enc_key, }) } } diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index 9eebf5646..5d4ac8bf7 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -13,7 +13,6 @@ pub mod time { pub const NS_IN_SEC: i64 = 1_000_000_000; pub fn now_ns() -> i64 { - tracing::debug!("GETTING NOW"); let now = SystemTime::now(); now.duration_since(UNIX_EPOCH) @@ -63,3 +62,8 @@ pub mod wasm { .await; } } + +#[cfg(not(target_arch = "wasm32"))] +pub mod wasm { + pub async fn init() {} +} From 75725b32c5820989679a83a6361aa982029a0870 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 2 Oct 2024 15:17:44 -0400 Subject: [PATCH 45/97] remove diesel-wasm-sqlite crate, use git repo --- Cargo.lock | 1 + Cargo.toml | 2 +- bindings_wasm/Cargo.toml | 9 - diesel-wasm-sqlite/.gitignore | 9 - diesel-wasm-sqlite/.vscode/settings.json | 34 - diesel-wasm-sqlite/.yarnrc.yml | 7 - diesel-wasm-sqlite/Cargo.lock | 1142 -- diesel-wasm-sqlite/Cargo.toml | 64 - diesel-wasm-sqlite/README.md | 96 - diesel-wasm-sqlite/build.rs | 19 - diesel-wasm-sqlite/package-lock.json | 756 - diesel-wasm-sqlite/package.js | 330 - diesel-wasm-sqlite/package.json | 22 - diesel-wasm-sqlite/rollup.config.js | 34 - diesel-wasm-sqlite/src/backend.rs | 85 - .../src/connection/bind_collector.rs | 250 - .../connection/diesel_manage_updated_at.sql | 11 - diesel-wasm-sqlite/src/connection/err.rs | 42 - .../src/connection/functions.rs | 237 - diesel-wasm-sqlite/src/connection/mod.rs | 345 - .../src/connection/owned_row.rs | 94 - diesel-wasm-sqlite/src/connection/raw.rs | 144 - diesel-wasm-sqlite/src/connection/row.rs | 203 - .../src/connection/serialized_database.rs | 19 - .../src/connection/sqlite_value.rs | 181 - .../src/connection/statement_iterator.rs | 159 - diesel-wasm-sqlite/src/connection/stmt.rs | 489 - diesel-wasm-sqlite/src/ffi.rs | 352 - diesel-wasm-sqlite/src/ffi/constants.rs | 180 - diesel-wasm-sqlite/src/ffi/wasm.rs | 91 - .../src/js/sqlite3-opfs-async-proxy.js | 692 - diesel-wasm-sqlite/src/js/sqlite3.wasm | Bin 939204 -> 0 bytes .../src/js/wa-sqlite-diesel-bundle.js | 14738 ---------------- diesel-wasm-sqlite/src/lib.rs | 53 - .../insert_with_default_sqlite.rs | 567 - .../src/query_builder/limit_offset.rs | 127 - diesel-wasm-sqlite/src/query_builder/mod.rs | 45 - .../src/query_builder/query_fragment_impls.rs | 40 - .../src/query_builder/returning.rs | 16 - diesel-wasm-sqlite/src/sqlite_fixes.rs | 290 - diesel-wasm-sqlite/src/sqlite_types.rs | 30 - diesel-wasm-sqlite/src/sqlite_types/to_sql.rs | 194 - diesel-wasm-sqlite/src/utils.rs | 1 - diesel-wasm-sqlite/tests/common/mod.rs | 45 - .../tests/dedicated_web_worker.rs | 17 - .../2024-08-20-203551_create_books/down.sql | 1 - .../2024-08-20-203551_create_books/up.sql | 5 - .../2024-09-03-193701_test_table/down.sql | 1 - .../2024-09-03-193701_test_table/up.sql | 15 - diesel-wasm-sqlite/tests/test/row.rs | 133 - diesel-wasm-sqlite/tests/test/web.rs | 332 - diesel-wasm-sqlite/yarn.lock | 1600 -- 52 files changed, 2 insertions(+), 24347 deletions(-) delete mode 100644 diesel-wasm-sqlite/.gitignore delete mode 100644 diesel-wasm-sqlite/.vscode/settings.json delete mode 100644 diesel-wasm-sqlite/.yarnrc.yml delete mode 100644 diesel-wasm-sqlite/Cargo.lock delete mode 100644 diesel-wasm-sqlite/Cargo.toml delete mode 100644 diesel-wasm-sqlite/README.md delete mode 100644 diesel-wasm-sqlite/build.rs delete mode 100644 diesel-wasm-sqlite/package-lock.json delete mode 100644 diesel-wasm-sqlite/package.js delete mode 100644 diesel-wasm-sqlite/package.json delete mode 100644 diesel-wasm-sqlite/rollup.config.js delete mode 100644 diesel-wasm-sqlite/src/backend.rs delete mode 100644 diesel-wasm-sqlite/src/connection/bind_collector.rs delete mode 100644 diesel-wasm-sqlite/src/connection/diesel_manage_updated_at.sql delete mode 100644 diesel-wasm-sqlite/src/connection/err.rs delete mode 100644 diesel-wasm-sqlite/src/connection/functions.rs delete mode 100644 diesel-wasm-sqlite/src/connection/mod.rs delete mode 100644 diesel-wasm-sqlite/src/connection/owned_row.rs delete mode 100755 diesel-wasm-sqlite/src/connection/raw.rs delete mode 100644 diesel-wasm-sqlite/src/connection/row.rs delete mode 100644 diesel-wasm-sqlite/src/connection/serialized_database.rs delete mode 100644 diesel-wasm-sqlite/src/connection/sqlite_value.rs delete mode 100644 diesel-wasm-sqlite/src/connection/statement_iterator.rs delete mode 100644 diesel-wasm-sqlite/src/connection/stmt.rs delete mode 100644 diesel-wasm-sqlite/src/ffi.rs delete mode 100644 diesel-wasm-sqlite/src/ffi/constants.rs delete mode 100644 diesel-wasm-sqlite/src/ffi/wasm.rs delete mode 100644 diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js delete mode 100644 diesel-wasm-sqlite/src/js/sqlite3.wasm delete mode 100644 diesel-wasm-sqlite/src/js/wa-sqlite-diesel-bundle.js delete mode 100755 diesel-wasm-sqlite/src/lib.rs delete mode 100644 diesel-wasm-sqlite/src/query_builder/insert_with_default_sqlite.rs delete mode 100644 diesel-wasm-sqlite/src/query_builder/limit_offset.rs delete mode 100644 diesel-wasm-sqlite/src/query_builder/mod.rs delete mode 100644 diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs delete mode 100644 diesel-wasm-sqlite/src/query_builder/returning.rs delete mode 100644 diesel-wasm-sqlite/src/sqlite_fixes.rs delete mode 100644 diesel-wasm-sqlite/src/sqlite_types.rs delete mode 100644 diesel-wasm-sqlite/src/sqlite_types/to_sql.rs delete mode 100644 diesel-wasm-sqlite/src/utils.rs delete mode 100644 diesel-wasm-sqlite/tests/common/mod.rs delete mode 100755 diesel-wasm-sqlite/tests/dedicated_web_worker.rs delete mode 100644 diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/down.sql delete mode 100644 diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql delete mode 100644 diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/down.sql delete mode 100644 diesel-wasm-sqlite/tests/migrations/2024-09-03-193701_test_table/up.sql delete mode 100644 diesel-wasm-sqlite/tests/test/row.rs delete mode 100755 diesel-wasm-sqlite/tests/test/web.rs delete mode 100644 diesel-wasm-sqlite/yarn.lock diff --git a/Cargo.lock b/Cargo.lock index 545513fa0..94fee6eaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1076,6 +1076,7 @@ dependencies = [ [[package]] name = "diesel-wasm-sqlite" version = "0.0.1" +source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#b8bca417559da55258fccdb771b3190d8577fb5a" dependencies = [ "diesel", "diesel_derives 2.2.2", diff --git a/Cargo.toml b/Cargo.toml index 09a1bea67..0362ec3a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,5 +88,5 @@ opt-level = "s" diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -diesel-wasm-sqlite = { path = "./diesel-wasm-sqlite" } +diesel-wasm-sqlite = { git = "https://github.com/xmtp/diesel-wasm-sqlite", branch = "main" } diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 689cb953a..2eb5586eb 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -25,15 +25,6 @@ wasm-bindgen-test = "0.3.42" [profile.release] opt-level = "s" -# patch needed until some items -# are made public for third-party dependencies: https://github.com/diesel-rs/diesel/pull/4236 -# (cfg-specific patch support does not exist) -[patch.crates-io] -diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -diesel-wasm-sqlite = { path = "../diesel-wasm-sqlite" } - [build] target = "wasm32-unknown-unknown" diff --git a/diesel-wasm-sqlite/.gitignore b/diesel-wasm-sqlite/.gitignore deleted file mode 100644 index 63e51e284..000000000 --- a/diesel-wasm-sqlite/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# yarn -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions -node_modules/** diff --git a/diesel-wasm-sqlite/.vscode/settings.json b/diesel-wasm-sqlite/.vscode/settings.json deleted file mode 100644 index e861191a0..000000000 --- a/diesel-wasm-sqlite/.vscode/settings.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "rust-analyzer": { - "cargo": { - "sysroot": "discover", - "allTargets": false, - "target": "wasm32-unknown-unknown" - }, - "procMacro": { - "enable": true, - "attributes.enable": true, - "ignored": { - "async-trait": ["async_trait"], - "napi-derive": ["napi"], - "async-recursion": ["async_recursion"], - "ctor": ["ctor"], - "tokio": ["test"], - "diesel": ["table"], - "wasm-bindgen": ["wasm-bindgen"] - } - } - }, - "[toml]": { - "editor.defaultFormatter": "tamasfe.even-better-toml" - }, - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - } -} diff --git a/diesel-wasm-sqlite/.yarnrc.yml b/diesel-wasm-sqlite/.yarnrc.yml deleted file mode 100644 index 77ffe90a8..000000000 --- a/diesel-wasm-sqlite/.yarnrc.yml +++ /dev/null @@ -1,7 +0,0 @@ -compressionLevel: mixed - -enableGlobalCache: false - -enableTelemetry: false - -nodeLinker: node-modules diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock deleted file mode 100644 index de705aacb..000000000 --- a/diesel-wasm-sqlite/Cargo.lock +++ /dev/null @@ -1,1142 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "diesel" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "chrono", - "diesel_derives 2.2.0", - "downcast-rs", - "r2d2", -] - -[[package]] -name = "diesel-wasm-sqlite" -version = "0.0.1" -dependencies = [ - "chrono", - "console_error_panic_hook", - "diesel", - "diesel_derives 2.2.2", - "diesel_migrations", - "getrandom", - "js-sys", - "rand", - "serde", - "serde-wasm-bindgen", - "talc", - "thiserror", - "tokio", - "tracing", - "tracing-subscriber", - "tracing-wasm", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test", - "web-sys", -] - -[[package]] -name = "diesel_derives" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "diesel_table_macro_syntax 0.2.0 (git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub)", - "dsl_auto_type 0.1.0", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diesel_derives" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" -dependencies = [ - "diesel_table_macro_syntax 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dsl_auto_type 0.1.2", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diesel_migrations" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "diesel", - "migrations_internals", - "migrations_macros", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" -dependencies = [ - "syn", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "syn", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[package]] -name = "dsl_auto_type" -version = "0.1.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "darling", - "either", - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dsl_auto_type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" -dependencies = [ - "darling", - "either", - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indexmap" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "migrations_internals" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "serde", - "toml", -] - -[[package]] -name = "migrations_macros" -version = "2.2.0" -source = "git+https://github.com/xmtp/diesel?branch=insipx/sqlite-replace-ignore-pub#78ece4f82ab6f77beb40c162b08444ea3a30b355" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.36.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.8", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "serde" -version = "1.0.204" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.204" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_spanned" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" -dependencies = [ - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "2.0.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "talc" -version = "4.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04be12ec299aadd63a0bf781d893e4b6139d33cdca6dcd6f6be31f849cedcac8" -dependencies = [ - "lock_api", -] - -[[package]] -name = "thiserror" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tokio" -version = "1.39.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" -dependencies = [ - "backtrace", - "pin-project-lite", -] - -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "tracing-wasm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" -dependencies = [ - "tracing", - "tracing-subscriber", - "wasm-bindgen", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "wasm-bindgen-test" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" -dependencies = [ - "memchr", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[patch.unused]] -name = "wasm-bindgen" -version = "0.2.93" -source = "git+https://github.com/rustwasm/wasm-bindgen?branch=main#e4f8c4540aee2f3c0798fdae51ac7dace28e102b" diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml deleted file mode 100644 index 6809293f5..000000000 --- a/diesel-wasm-sqlite/Cargo.toml +++ /dev/null @@ -1,64 +0,0 @@ -[package] -name = "diesel-wasm-sqlite" -version = "0.0.1" -edition = "2021" -resolver = "2" -authors = ["XMTP Labs "] -description = "SQLite WebAssembly backend for Diesel" -homepage = "https://xmtp.org/" -repository = "https://github.com/xmtp/libxmtp" -license = "MIT" -keywords = ["orm", "database", "sql", "wasm"] -categories = ["database", "wasm"] - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] -targets = ["wasm32-unknown-unknown"] - -[dependencies] -talc = { version = "4.4", default-features = false, features = ["lock_api"] } -diesel = { version = "2.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } -diesel_derives = "2.2" -wasm-bindgen = "=0.2.92" -wasm-bindgen-futures = "0.4" -js-sys = { version = "0.3" } -tracing = "0.1" -tokio = { version = "1.38", default-features = false, features = ["sync"] } -serde = { version = "1.0", default-features = false, features = ["derive"] } -serde-wasm-bindgen = "0.6" -thiserror = "1" - -[dev-dependencies] -console_error_panic_hook = { version = "0.1"} -rand = "0.8" -getrandom = { version = "0.2", features = ["js"] } -wasm-bindgen-test = "0.3.42" -web-sys = { version = "0.3", features = ["console"] } -chrono = { version = "0.4", features = ["wasmbind", "serde"] } -diesel_migrations = "2.2" -diesel = { version = "2.2", features = ["chrono"]} -tracing-wasm = { version = "0.2" } -tracing-subscriber = { version = "0.3", features = ["env-filter", "tracing-log"] } - -[patch.crates-io] -diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -diesel_derives = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -diesel_migrations = { git = "https://github.com/xmtp/diesel", branch = "insipx/sqlite-replace-ignore-pub" } -wasm-bindgen = { git = "https://github.com/rustwasm/wasm-bindgen", branch = "main" } -# [profile.release] -# opt-level = "s" - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -default = [] -r2d2 = ["diesel/r2d2"] -# enables a `DebugQueryWrapper` for diesel -# but is unsafe because of mem::transmute -unsafe-debug-query = [] - -[build] -target = "wasm32-unknown-unknown" - diff --git a/diesel-wasm-sqlite/README.md b/diesel-wasm-sqlite/README.md deleted file mode 100644 index eedd3d0de..000000000 --- a/diesel-wasm-sqlite/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# Diesel Backend for SQLite and WASM - -### Use SQLite with Diesel ORM in your web apps! - -## Quickstart - -add `diesel-wasm-sqlite` to your project. SQLite is automatically bundled with -the library. - -```toml -[dependencies] -diesel = { version = "2.2" } -diesel-wasm-sqlite = { git = "https://github.com/xmtp/libxmtp", branch = "wasm-backend" } -wasm-bindgen = "0.2" -``` - -```rust -use diesel_wasm_sqlite::{connection::WasmSqliteConnection, WasmSqlite}; -use wasm_bindgen::prelude::*; - -pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/web/migrations/"); - -mod schema { - diesel::table! { - books { - id -> Integer, - title -> Text, - author -> Nullable, - } - } -} - - -#[derive(Deserialize, Insertable, Debug, PartialEq, Clone)] -#[diesel(table_name = books)] -pub struct BookForm { - title: String, - author: Option, -} - -// SQLite must be instantiated in a web-worker -// to take advantage of OPFS -#[wasm_bindgen] -async fn code_in_web_worker() -> Result> { - use schema::books::dsl::*; - // `init_sqlite` sets up OPFS and SQLite. It must be ran before anything else, - // or we crash once we start trying to do queries. - diesel_wasm_sqlite::init_sqlite().await; - - // create a new persistent SQLite database with OPFS - let result = WasmSqliteConnection::establish(&format!("test-{}", rng)); - let query = insert_into(books).values(vec![ - BookForm { - title: "Game of Thrones".into(), - author: Some("George R.R".into()), - }, - BookForm { - title: "The Hobbit".into(), - author: Some("J.R.R. Tolkien".into()), - }, - ]); - Ok(query.execute(conn)?) -} -``` - -look in `tests/web.rs` for working example! - -## Development - -### Install yarn dependencies - -`yarn install` - -### Build the SQLite/OPFS BUndle - -`yarn run build` - -### Build the rust code, and re-build `package.json` if it changed - -`cargo build --target wasm32-unknown-unknown` - -### Run Tests - -`wasm-pack test --safari --features unsafe-debug-query` - -navigate to `http://localhost:8000` to observe test output - -### Run Tests (headless) - -`wasm-pack test --safari --headless` - -### Setting up the project in VSCode - -rust-analyzer does not like crates with different targets in the same workspace. -If you want this to work well with your LSP, open `diesel-wasm-sqlite` as it's -own project in VSCode. diff --git a/diesel-wasm-sqlite/build.rs b/diesel-wasm-sqlite/build.rs deleted file mode 100644 index 7684ecf6c..000000000 --- a/diesel-wasm-sqlite/build.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::env; -// use std::process::Command; - -fn main() { -// println!("cargo::rerun-if-changed=package.js"); -// println!("cargo::rerun-if-changed=package.json"); - - // Command::new("yarn").args(["install"]).status().unwrap(); - // Command::new("yarn") - // .args(["run", "build"]) - // .status() - // .unwrap(); - - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - if target_arch != "wasm32" { - // Emit a compile error if the target is not wasm32-unknown-unknown - panic!("This crate only supports the wasm32 architecture"); - } -} diff --git a/diesel-wasm-sqlite/package-lock.json b/diesel-wasm-sqlite/package-lock.json deleted file mode 100644 index e92a88e09..000000000 --- a/diesel-wasm-sqlite/package-lock.json +++ /dev/null @@ -1,756 +0,0 @@ -{ - "name": "diesel-wasm-sqlite", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "diesel-wasm-sqlite", - "version": "1.0.0", - "dependencies": { - "@xmtp/wa-sqlite": "^1.0.1" - }, - "devDependencies": { - "@rollup/plugin-node-resolve": "^15.2.3", - "rollup": "^4.19.0", - "rollup-plugin-base64": "^1.0.1", - "rollup-plugin-copy": "^3.5.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.19.0", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/fs-extra": { - "version": "8.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.14.11", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@xmtp/wa-sqlite": { - "version": "1.0.1" - }, - "node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/colorette": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globby": { - "version": "10.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/globby/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "license": "ISC" - }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-core-module": { - "version": "2.15.0", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-object": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "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/resolve": { - "version": "1.22.8", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.19.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.19.0", - "@rollup/rollup-android-arm64": "4.19.0", - "@rollup/rollup-darwin-arm64": "4.19.0", - "@rollup/rollup-darwin-x64": "4.19.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.19.0", - "@rollup/rollup-linux-arm-musleabihf": "4.19.0", - "@rollup/rollup-linux-arm64-gnu": "4.19.0", - "@rollup/rollup-linux-arm64-musl": "4.19.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.19.0", - "@rollup/rollup-linux-riscv64-gnu": "4.19.0", - "@rollup/rollup-linux-s390x-gnu": "4.19.0", - "@rollup/rollup-linux-x64-gnu": "4.19.0", - "@rollup/rollup-linux-x64-musl": "4.19.0", - "@rollup/rollup-win32-arm64-msvc": "4.19.0", - "@rollup/rollup-win32-ia32-msvc": "4.19.0", - "@rollup/rollup-win32-x64-msvc": "4.19.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-base64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-base64/-/rollup-plugin-base64-1.0.1.tgz", - "integrity": "sha512-IbdX8fjuXO/Op3hYmRPjVo0VwcSenwsQDaDTFdoe+70B5ZGoLMtr96L2yhHXCfxv7HwZVvxZqLsuWj6VwzRt3g==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0" - } - }, - "node_modules/rollup-plugin-base64/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/rollup-plugin-base64/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/rollup-plugin-base64/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/rollup-plugin-base64/node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "peer": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-copy": { - "version": "3.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "engines": { - "node": ">=8.3" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "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": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "dev": true, - "license": "MIT" - }, - "node_modules/universalify": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "license": "ISC" - } - } -} diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js deleted file mode 100644 index b391d131d..000000000 --- a/diesel-wasm-sqlite/package.js +++ /dev/null @@ -1,330 +0,0 @@ -import sqlite3InitModule from "@sqlite.org/sqlite-wasm"; - -const log = console.log; -const err_log = console.error; - -export class SQLiteError extends Error { - constructor(message, code) { - super(message); - this.code = code; - } -} - -export class SQLite { - #module; - #sqlite3; - constructor(sqlite3) { - if (typeof sqlite3 === "undefined") { - throw new Error( - "`sqliteObject` must be defined before calling constructor", - ); - } - this.sqlite3 = sqlite3; - } - - static async init_module(opts) { - return await sqlite3InitModule({ - print: log, - printErr: err_log, - ...opts, - }); - } - - version() { - return this.sqlite3.version; - } - - filename(db, name) { - return this.sqlite3.capi.sqlite3_db_filename(db, name); - } - - extended_errcode(connection) { - return this.sqlite3.capi.sqlite3_extended_errcode(connection); - } - - errstr(code) { - return this.sqlite3.capi.sqlite3_errstr(code); - } - - errmsg(connection) { - return this.sqlite3.capi.sqlite3_errmsg(connection); - } - - result_js(context, value) { - return this.sqlite3.capi.sqlite3_result_js(context, value); - } - - result_text(context, value) { - return this.sqlite3.capi.sqlite3_result_text(context, value); - } - - result_int(context, value) { - return this.sqlite3.capi.sqlite3_result_int(context, value); - } - - result_int64(context, value) { - return this.sqlite3.capi.sqlite3_result_int64(context, value); - } - - result_double(context, value) { - return this.sqlite3.capi.sqlite3_result_double(context, value); - } - - result_blob(context, value) { - return this.sqlite3.capi.sqlite3_result_blob(context, value); - } - - result_null(context) { - return this.sqlite3.capi.sqlite3_result_null(context); - } - - bind_blob(stmt, i, value, len, flags) { - return this.sqlite3.capi.sqlite3_bind_blob(stmt, i, value, len, flags); - } - - bind_text(stmt, i, value, len, flags) { - return this.sqlite3.capi.sqlite3_bind_text(stmt, i, value, len, flags); - } - - bind_double(stmt, i, value) { - return this.sqlite3.capi.sqlite3_bind_double(stmt, i, value); - } - - bind_int(stmt, i, value) { - return this.sqlite3.capi.sqlite3_bind_int(stmt, i, value); - } - - bind_int64(stmt, i, value) { - return this.sqlite3.capi.sqlite3_bind_int64(stmt, i, value); - } - - bind_null(stmt, i) { - this.sqlite3.capi.sqlite3_bind_null(stmt, i); - /// There's no way bind_null can fail. - return this.sqlite3.capi.SQLITE_OK; - } - - bind_parameter_count(stmt) { - return this.sqlite3.capi.sqlite3_bind_parameter_count(stmt); - } - - bind_parameter_name(stmt, i) { - return this.sqlite3.capi.sqlite3_bind_paramater_name(stmt, it); - } - - value_dup(pValue) { - return this.sqlite3.capi.sqlite3_value_dup(pValue); - } - - value_blob(pValue) { - return this.sqlite3.capi.sqlite3_value_blob(pValue); - } - - value_bytes(pValue) { - return this.sqlite3.capi.sqlite3_value_bytes(pValue); - } - - value_double(pValue) { - return this.sqlite3.capi.sqlite3_value_double(pValue); - } - - value_int(pValue) { - return this.sqlite3.capi.sqlite3_value_int(pValue); - } - - value_int64(pValue) { - return this.sqlite3.capi.sqlite3_value_int64(pValue); - } - - value_text(pValue) { - return this.sqlite3.capi.sqlite3_value_text(pValue); - } - - value_type(pValue) { - return this.sqlite3.capi.sqlite3_value_type(pValue); - } - - open(database_url, iflags) { - try { - return new this.sqlite3.oo1.OpfsDb(database_url); - } catch (error) { - console.log("OPFS open error", error); - throw error; - } - } - - exec(db, query) { - try { - return db.exec(query, { - callback: (row) => {}, - }); - } catch (error) { - throw error; - } - } - - finalize(stmt) { - return this.sqlite3.capi.sqlite3_finalize(stmt); - } - - changes(db) { - return this.sqlite3.capi.sqlite3_changes(db); - } - - clear_bindings(stmt) { - return this.sqlite3.capi.sqlite3_clear_bindings(stmt); - } - - reset(stmt) { - return this.sqlite3.capi.sqlite3_reset(stmt); - } - - close(db) { - return this.sqlite3.capi.sqlite3_close_v2(db.pointer); - } - - db_handle(stmt) { - return this.sqlite3.capi.sqlite3_db_handle(stmt); - } - - prepare_v3(db, sql, nByte, prepFlags, ppStmt, pzTail) { - return this.sqlite3.capi.sqlite3_prepare_v3( - db.pointer, - sql, - nByte, - prepFlags, - ppStmt, - pzTail, - ); - } - - step(stmt) { - return this.sqlite3.capi.sqlite3_step(stmt); - } - - column_value(stmt, i) { - return this.sqlite3.capi.sqlite3_column_value(stmt, i); - } - - column_name(stmt, idx) { - return this.sqlite3.capi.sqlite3_column_name(stmt, idx); - } - - column_count(stmt) { - return this.sqlite3.capi.sqlite3_column_count(stmt); - } - - create_function( - database, - functionName, - nArg, - textRep, - pApp, - xFunc, - xStep, - xFinal, - ) { - try { - this.sqlite3.capi.sqlite3_create_function( - database, - functionName, - nArg, - textRep, - pApp, // pApp is ignored - xFunc, - xStep, - xFinal, - ); - console.log("create function"); - } catch (error) { - console.log("create function err"); - throw error; - } - } - - //TODO: At some point need a way to register functions from rust - //but for now this is fine. - register_diesel_sql_functions(database) { - try { - this.sqlite3.capi.sqlite3_create_function( - database, - "diesel_manage_updated_at", - 1, - this.sqlite3.capi.SQLITE_UTF8, - 0, - async (context, values) => { - const table_name = this.sqlite3.value_text(values[0]); - - database.exec( - context, - `CREATE TRIGGER __diesel_manage_updated_at_${table_name} - AFTER UPDATE ON ${table_name} - FOR EACH ROW WHEN - old.updated_at IS NULL AND - new.updated_at IS NULL OR - old.updated_at == new.updated_at - BEGIN - UPDATE ${table_name} - SET updated_at = CURRENT_TIMESTAMP - WHERE ROWID = new.ROWID; - END`, - (row) => { - log(`------------------------------------`); - log(`Created trigger for ${table_name}`); - log(row); - log(`------------------------------------`); - }, - ); - }, - ); - } catch (error) { - console.log("error creating diesel trigger"); - throw error; - } - } - - value_free(value) { - return this.sqlite3.capi.sqlite3_value_free(value); - } - - sqlite3_serialize(database, z_schema, p_size, m_flags) { - try { - return this.sqlite3.capi.sqlite3_serialize( - database, - z_schema, - p_size, - m_flags, - ); - } catch (error) { - console.log("error serializing"); - throw error; - } - } - - sqlite3_deserialize( - database, - z_schema, - p_data, - sz_database, - sz_buffer, - m_flags, - ) { - try { - return this.sqlite3.capi.sqlite3_deserialize( - database, - z_schema, - p_data, - sz_database, - sz_buffer, - m_flags, - ); - } catch (error) { - console.log("error deserializing"); - throw error; - } - } - - sqlite3_free(_database, arg1) { - return this.sqlite3.capi.sqlite3_free(arg1); - } -} diff --git a/diesel-wasm-sqlite/package.json b/diesel-wasm-sqlite/package.json deleted file mode 100644 index 21afc9243..000000000 --- a/diesel-wasm-sqlite/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "diesel-wasm-sqlite", - "type": "module", - "version": "1.0.0", - "description": "", - "main": "package.js", - "scripts": { - "build": "rollup -c" - }, - "dependencies": { - "@sqlite.org/sqlite-wasm": "latest" - }, - "packageManager": "yarn@4.3.1", - "engines": { - "node": ">=18" - }, - "devDependencies": { - "@rollup/plugin-node-resolve": "^15.2.3", - "rollup": "^4.19.0", - "rollup-plugin-copy": "^3.5.0" - } -} diff --git a/diesel-wasm-sqlite/rollup.config.js b/diesel-wasm-sqlite/rollup.config.js deleted file mode 100644 index e61d08116..000000000 --- a/diesel-wasm-sqlite/rollup.config.js +++ /dev/null @@ -1,34 +0,0 @@ -import { defineConfig } from "rollup"; -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import copy from "rollup-plugin-copy"; - -export default defineConfig([ - { - input: "package.js", - output: { - file: "src/js/wa-sqlite-diesel-bundle.js", - format: "es", - }, - plugins: [ - nodeResolve(), - copy({ - targets: [ - { - src: - "./node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm/sqlite3.wasm", - dest: "src/js", - }, - ], - }), - ], - // external: ["@sqlite.org/sqlite-wasm"], - }, - { - input: - "./node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-opfs-async-proxy.js", - output: { - file: "src/js/sqlite3-opfs-async-proxy.js", - format: "es", - }, - }, -]); diff --git a/diesel-wasm-sqlite/src/backend.rs b/diesel-wasm-sqlite/src/backend.rs deleted file mode 100644 index f967dc273..000000000 --- a/diesel-wasm-sqlite/src/backend.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! The WasmSQLite backend - -use super::connection::SqliteBindCollector; -use super::connection::SqliteValue; -use super::query_builder::SqliteQueryBuilder; -use diesel::backend::*; -use diesel::sql_types::TypeMetadata; - -/// The SQLite backend -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)] -pub struct WasmSqlite; - -/// Determines how a bind parameter is given to SQLite -/// -/// Diesel deals with bind parameters after serialization as opaque blobs of -/// bytes. However, SQLite instead has several functions where it expects the -/// relevant C types. -/// -/// The variants of this struct determine what bytes are expected from -/// `ToSql` impls. -#[allow(missing_debug_implementations)] -#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] -pub enum SqliteType { - /// Bind using `sqlite3_bind_blob` - Binary, - /// Bind using `sqlite3_bind_text` - Text, - /// `bytes` should contain an `f32` - Float, - /// `bytes` should contain an `f64` - Double, - /// `bytes` should contain an `i16` - SmallInt, - /// `bytes` should contain an `i32` - Integer, - /// `bytes` should contain an `i64` - Long, -} - -impl Backend for WasmSqlite { - type QueryBuilder = SqliteQueryBuilder; - type RawValue<'a> = SqliteValue<'a, 'a, 'a>; - type BindCollector<'a> = SqliteBindCollector<'a>; -} - -impl TypeMetadata for WasmSqlite { - type TypeMetadata = SqliteType; - type MetadataLookup = (); -} - -impl SqlDialect for WasmSqlite { - type ReturningClause = SqliteReturningClause; - - type OnConflictClause = SqliteOnConflictClause; - - type InsertWithDefaultKeyword = - sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword; - type BatchInsertSupport = SqliteBatchInsert; - type ConcatClause = sql_dialect::concat_clause::ConcatWithPipesClause; - type DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause; - - type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax; - type SelectStatementSyntax = sql_dialect::select_statement_syntax::AnsiSqlSelectStatement; - - type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax; - type ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison; - type AliasSyntax = sql_dialect::alias_syntax::AsAliasSyntax; -} - -impl DieselReserveSpecialization for WasmSqlite {} -impl TrustedBackend for WasmSqlite {} - -#[derive(Debug, Copy, Clone)] -pub struct SqliteOnConflictClause; - -impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for SqliteOnConflictClause {} -impl sql_dialect::on_conflict_clause::PgLikeOnConflictClause for SqliteOnConflictClause {} - -#[derive(Debug, Copy, Clone)] -pub struct SqliteBatchInsert; - -#[derive(Debug, Copy, Clone)] -pub struct SqliteReturningClause; - -impl sql_dialect::returning_clause::SupportsReturningClause for SqliteReturningClause {} diff --git a/diesel-wasm-sqlite/src/connection/bind_collector.rs b/diesel-wasm-sqlite/src/connection/bind_collector.rs deleted file mode 100644 index 13b1bae68..000000000 --- a/diesel-wasm-sqlite/src/connection/bind_collector.rs +++ /dev/null @@ -1,250 +0,0 @@ -use crate::{SqliteType, WasmSqlite}; -use diesel::{ - query_builder::{BindCollector, MoveableBindCollector}, - result::QueryResult, - serialize::{IsNull, Output}, - sql_types::HasSqlType, -}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default)] -pub struct SqliteBindCollector<'a> { - pub(crate) binds: Vec<(InternalSqliteBindValue<'a>, SqliteType)>, -} - -impl SqliteBindCollector<'_> { - pub(crate) fn new() -> Self { - Self { binds: Vec::new() } - } -} - -/// This type represents a value bound to -/// a sqlite prepared statement -/// -/// It can be constructed via the various `From` implementations -#[derive(Debug)] -pub struct SqliteBindValue<'a> { - pub(crate) inner: InternalSqliteBindValue<'a>, -} - -impl<'a> From for SqliteBindValue<'a> { - fn from(i: i32) -> Self { - Self { - inner: InternalSqliteBindValue::I32(i), - } - } -} - -impl<'a> From for SqliteBindValue<'a> { - fn from(i: i64) -> Self { - Self { - inner: InternalSqliteBindValue::I64(i), - } - } -} - -impl<'a> From for SqliteBindValue<'a> { - fn from(f: f64) -> Self { - Self { - inner: InternalSqliteBindValue::F64(f), - } - } -} - -impl<'a, T> From> for SqliteBindValue<'a> -where - T: Into>, -{ - fn from(o: Option) -> Self { - match o { - Some(v) => v.into(), - None => Self { - inner: InternalSqliteBindValue::Null, - }, - } - } -} - -impl<'a> From<&'a str> for SqliteBindValue<'a> { - fn from(s: &'a str) -> Self { - Self { - inner: InternalSqliteBindValue::BorrowedString(s), - } - } -} - -impl<'a> From for SqliteBindValue<'a> { - fn from(s: String) -> Self { - Self { - inner: InternalSqliteBindValue::String(s), - } - } -} - -impl<'a> From> for SqliteBindValue<'a> { - fn from(b: Vec) -> Self { - Self { - inner: InternalSqliteBindValue::Binary(b), - } - } -} - -impl<'a> From<&'a [u8]> for SqliteBindValue<'a> { - fn from(b: &'a [u8]) -> Self { - Self { - inner: InternalSqliteBindValue::BorrowedBinary(b), - } - } -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub(crate) enum InternalSqliteBindValue<'a> { - BorrowedString(&'a str), - String(String), - BorrowedBinary(&'a [u8]), - Binary(Vec), - I32(i32), - I64(i64), - F64(f64), - Null, -} - -impl std::fmt::Display for InternalSqliteBindValue<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let n = match self { - InternalSqliteBindValue::BorrowedString(_) | InternalSqliteBindValue::String(_) => { - "Text" - } - InternalSqliteBindValue::BorrowedBinary(_) | InternalSqliteBindValue::Binary(_) => { - "Binary" - } - InternalSqliteBindValue::I32(_) | InternalSqliteBindValue::I64(_) => "Integer", - InternalSqliteBindValue::F64(_) => "Float", - InternalSqliteBindValue::Null => "Null", - }; - f.write_str(n) - } -} -/* -impl InternalSqliteBindValue<'_> { - #[allow(unsafe_code)] // ffi function calls - pub(crate) fn result_of(self, ctx: &mut i32) { - let sqlite3 = crate::get_sqlite_unchecked(); - match self { - InternalSqliteBindValue::BorrowedString(s) => sqlite3.result_text(*ctx, s.to_string()), - InternalSqliteBindValue::String(s) => sqlite3.result_text(*ctx, s.to_string()), - InternalSqliteBindValue::Binary(b) => sqlite3.result_blob(*ctx, b.to_vec()), - InternalSqliteBindValue::BorrowedBinary(b) => sqlite3.result_blob(*ctx, b.to_vec()), - InternalSqliteBindValue::I32(i) => sqlite3.result_int(*ctx, i), - InternalSqliteBindValue::I64(l) => sqlite3.result_int64(*ctx, l), - InternalSqliteBindValue::F64(d) => sqlite3.result_double(*ctx, d), - InternalSqliteBindValue::Null => sqlite3.result_null(*ctx), - } - } -} -*/ - -impl<'a> BindCollector<'a, WasmSqlite> for SqliteBindCollector<'a> { - type Buffer = SqliteBindValue<'a>; - - fn push_bound_value(&mut self, bind: &'a U, metadata_lookup: &mut ()) -> QueryResult<()> - where - WasmSqlite: diesel::sql_types::HasSqlType, - U: diesel::serialize::ToSql + ?Sized, - { - let value = SqliteBindValue { - inner: InternalSqliteBindValue::Null, - }; - let mut to_sql_output = Output::new(value, metadata_lookup); - let is_null = bind - .to_sql(&mut to_sql_output) - .map_err(diesel::result::Error::SerializationError)?; - let bind = to_sql_output.into_inner(); - let metadata = WasmSqlite::metadata(metadata_lookup); - - self.binds.push(( - match is_null { - IsNull::No => bind.inner, - IsNull::Yes => InternalSqliteBindValue::Null, - }, - metadata, - )); - Ok(()) - } - - fn push_null_value(&mut self, metadata: SqliteType) -> QueryResult<()> { - self.binds.push((InternalSqliteBindValue::Null, metadata)); - Ok(()) - } -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub enum OwnedSqliteBindValue { - String(String), - Binary(Vec), - I32(i32), - I64(i64), - F64(f64), - Null, -} - -impl<'a> std::convert::From<&InternalSqliteBindValue<'a>> for OwnedSqliteBindValue { - fn from(value: &InternalSqliteBindValue<'a>) -> Self { - match value { - InternalSqliteBindValue::String(s) => Self::String(s.clone()), - InternalSqliteBindValue::BorrowedString(s) => Self::String(String::from(*s)), - InternalSqliteBindValue::Binary(b) => Self::Binary(b.clone()), - InternalSqliteBindValue::BorrowedBinary(s) => Self::Binary(Vec::from(*s)), - InternalSqliteBindValue::I32(val) => Self::I32(*val), - InternalSqliteBindValue::I64(val) => Self::I64(*val), - InternalSqliteBindValue::F64(val) => Self::F64(*val), - InternalSqliteBindValue::Null => Self::Null, - } - } -} - -impl<'a> std::convert::From<&OwnedSqliteBindValue> for InternalSqliteBindValue<'a> { - fn from(value: &OwnedSqliteBindValue) -> Self { - match value { - OwnedSqliteBindValue::String(s) => Self::String(s.clone()), - OwnedSqliteBindValue::Binary(b) => Self::Binary(b.clone()), - OwnedSqliteBindValue::I32(val) => Self::I32(*val), - OwnedSqliteBindValue::I64(val) => Self::I64(*val), - OwnedSqliteBindValue::F64(val) => Self::F64(*val), - OwnedSqliteBindValue::Null => Self::Null, - } - } -} - -#[derive(Debug)] -/// Sqlite bind collector data that is movable across threads -pub struct SqliteBindCollectorData { - pub binds: Vec<(OwnedSqliteBindValue, SqliteType)>, -} - -impl MoveableBindCollector for SqliteBindCollector<'_> { - type BindData = SqliteBindCollectorData; - - fn moveable(&self) -> Self::BindData { - let mut binds = Vec::with_capacity(self.binds.len()); - for b in self - .binds - .iter() - .map(|(bind, tpe)| (OwnedSqliteBindValue::from(bind), *tpe)) - { - binds.push(b); - } - SqliteBindCollectorData { binds } - } - - fn append_bind_data(&mut self, from: &Self::BindData) { - self.binds.reserve_exact(from.binds.len()); - self.binds.extend( - from.binds - .iter() - .map(|(bind, tpe)| (InternalSqliteBindValue::from(bind), *tpe)), - ); - } -} diff --git a/diesel-wasm-sqlite/src/connection/diesel_manage_updated_at.sql b/diesel-wasm-sqlite/src/connection/diesel_manage_updated_at.sql deleted file mode 100644 index 83c3d33d4..000000000 --- a/diesel-wasm-sqlite/src/connection/diesel_manage_updated_at.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TRIGGER __diesel_manage_updated_at_{table_name} -AFTER UPDATE ON {table_name} -FOR EACH ROW WHEN - old.updated_at IS NULL AND - new.updated_at IS NULL OR - old.updated_at == new.updated_at -BEGIN - UPDATE {table_name} - SET updated_at = CURRENT_TIMESTAMP - WHERE ROWID = new.ROWID; -END diff --git a/diesel-wasm-sqlite/src/connection/err.rs b/diesel-wasm-sqlite/src/connection/err.rs deleted file mode 100644 index 841dee922..000000000 --- a/diesel-wasm-sqlite/src/connection/err.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::ffi; -use diesel::result::Error::DatabaseError; -use diesel::result::*; -use wasm_bindgen::JsValue; - -pub(super) fn error_message(code: i32) -> String { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.errstr(code) -} - -pub(super) fn ensure_sqlite_ok(code: i32, raw_connection: &JsValue) -> QueryResult<()> { - if code == *ffi::SQLITE_OK { - Ok(()) - } else { - Err(last_error(raw_connection)) - } -} - -pub(super) fn last_error(raw_connection: &JsValue) -> diesel::result::Error { - let error_message = last_error_message(raw_connection); - let error_information = Box::new(error_message); - let error_kind = match last_error_code(raw_connection) { - e if *ffi::SQLITE_CONSTRAINT_UNIQUE | *ffi::SQLITE_CONSTRAINT_PRIMARYKEY == e => { - DatabaseErrorKind::UniqueViolation - } - e if *ffi::SQLITE_CONSTRAINT_FOREIGNKEY == e => DatabaseErrorKind::ForeignKeyViolation, - e if *ffi::SQLITE_CONSTRAINT_NOTNULL == e => DatabaseErrorKind::NotNullViolation, - e if *ffi::SQLITE_CONSTRAINT_CHECK == e => DatabaseErrorKind::CheckViolation, - _ => DatabaseErrorKind::Unknown, - }; - DatabaseError(error_kind, error_information) -} - -fn last_error_message(conn: &JsValue) -> String { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.errmsg(conn) -} - -fn last_error_code(conn: &JsValue) -> i32 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.extended_errcode(conn) -} diff --git a/diesel-wasm-sqlite/src/connection/functions.rs b/diesel-wasm-sqlite/src/connection/functions.rs deleted file mode 100644 index 2fbf1e303..000000000 --- a/diesel-wasm-sqlite/src/connection/functions.rs +++ /dev/null @@ -1,237 +0,0 @@ -use super::raw::RawConnection; -use super::row::PrivateSqliteRow; -use super::{/*SqliteAggregateFunction,*/ SqliteBindValue, WasmSqlite}; -use crate::connection::bind_collector::InternalSqliteBindValue; -use crate::connection::sqlite_value::OwnedSqliteValue; -use crate::connection::SqliteValue; -use diesel::backend::Backend; -use diesel::deserialize::{FromSqlRow, StaticallySizedRow}; -use diesel::result::{DatabaseErrorKind, Error, QueryResult}; -use diesel::row::{Field, PartialRow, Row, RowIndex, RowSealed}; -use diesel::serialize::{IsNull, Output, ToSql}; -use diesel::sql_types::HasSqlType; -use std::cell::{Ref, RefCell}; -use std::marker::PhantomData; -use std::mem::ManuallyDrop; -use std::ops::DerefMut; -use std::rc::Rc; -use wasm_bindgen::JsValue; - -pub(super) fn register( - conn: &RawConnection, - fn_name: &str, - deterministic: bool, - mut f: F, -) -> QueryResult<()> -where - F: FnMut(&RawConnection, Args) -> QueryResult, - Args: FromSqlRow + StaticallySizedRow, - Ret: ToSql, - WasmSqlite: HasSqlType, -{ - let fields_needed = Args::FIELD_COUNT; - if fields_needed > 127 { - return Err(Error::DatabaseError( - DatabaseErrorKind::UnableToSendCommand, - Box::new("SQLite functions cannot take more than 127 parameters".to_string()), - )); - } - - conn.register_sql_function(fn_name, fields_needed, deterministic, move |conn, args| { - async { - let args = build_sql_function_args::(args)?; - let conn = RawConnection { - internal_connection: conn, - }; - Ok(f(&conn, args)) - } - .boxed() - })?; - Ok(()) -} - -/* -pub(super) fn register_noargs( - conn: &RawConnection, - fn_name: &str, - deterministic: bool, - mut f: F, -) -> QueryResult<()> -where - F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static, - Ret: ToSql, - WasmSqlite: HasSqlType, -{ - conn.register_sql_function(fn_name, 0, deterministic, move |_, _| Ok(f()))?; - Ok(()) -} - -pub(super) fn register_aggregate( - conn: &RawConnection, - fn_name: &str, -) -> QueryResult<()> -where - A: SqliteAggregateFunction + 'static + Send + std::panic::UnwindSafe, - Args: FromSqlRow + StaticallySizedRow, - Ret: ToSql, - WasmSqlite: HasSqlType, -{ - let fields_needed = Args::FIELD_COUNT; - if fields_needed > 127 { - return Err(Error::DatabaseError( - DatabaseErrorKind::UnableToSendCommand, - Box::new("SQLite functions cannot take more than 127 parameters".to_string()), - )); - } - - conn.register_aggregate_function::( - fn_name, - fields_needed, - )?; - - Ok(()) -} -*/ - -pub(super) fn build_sql_function_args(args: Vec) -> Result -where - Args: FromSqlRow, -{ - let row = FunctionRow::new(args); - Args::build_from_row(&row).map_err(Error::DeserializationError) -} - -// clippy is wrong here, the let binding is required -// for lifetime reasons -#[allow(clippy::let_unit_value)] -pub(super) fn process_sql_function_result( - result: &'_ Ret, -) -> QueryResult> -where - Ret: ToSql, - WasmSqlite: HasSqlType, -{ - let mut metadata_lookup = (); - let value = SqliteBindValue { - inner: InternalSqliteBindValue::Null, - }; - let mut buf = Output::new(value, &mut metadata_lookup); - let is_null = result.to_sql(&mut buf).map_err(Error::SerializationError)?; - - if let IsNull::Yes = is_null { - Ok(InternalSqliteBindValue::Null) - } else { - Ok(buf.into_inner().inner) - } -} - -struct FunctionRow<'a> { - // we use `ManuallyDrop` to prevent dropping the content of the internal vector - // as this buffer is owned by sqlite not by diesel - args: Rc>>>, - field_count: usize, - marker: PhantomData<&'a JsValue>, -} - -impl<'a> Drop for FunctionRow<'a> { - #[allow(unsafe_code)] // manual drop calls - fn drop(&mut self) { - if let Some(args) = Rc::get_mut(&mut self.args) { - if let PrivateSqliteRow::Duplicated { column_names, .. } = - DerefMut::deref_mut(RefCell::get_mut(args)) - { - if Rc::strong_count(column_names) == 1 { - // According the https://doc.rust-lang.org/std/mem/struct.ManuallyDrop.html#method.drop - // it's fine to just drop the values here - unsafe { std::ptr::drop_in_place(column_names as *mut _) } - } - } - } - } -} - -impl<'a> FunctionRow<'a> { - #[allow(unsafe_code)] // complicated ptr cast - fn new(args: Vec) -> Self { - let lengths = args.len(); - - Self { - field_count: lengths, - args: Rc::new(RefCell::new(ManuallyDrop::new( - PrivateSqliteRow::Duplicated { - values: args - .into_iter() - .map(|a| Some(OwnedSqliteValue { value: a.into() })) - .collect(), - column_names: Rc::from(vec![None; lengths]), - }, - ))), - marker: PhantomData, - } - } -} - -impl RowSealed for FunctionRow<'_> {} - -impl<'a> Row<'a, WasmSqlite> for FunctionRow<'a> { - type Field<'f> = FunctionArgument<'f> where 'a: 'f, Self: 'f; - type InnerPartialRow = Self; - - fn field_count(&self) -> usize { - self.field_count - } - - fn get<'b, I>(&'b self, idx: I) -> Option> - where - 'a: 'b, - Self: RowIndex, - { - let idx = self.idx(idx)?; - Some(FunctionArgument { - args: self.args.borrow(), - col_idx: idx as i32, - }) - } - - fn partial_row(&self, range: std::ops::Range) -> PartialRow<'_, Self::InnerPartialRow> { - PartialRow::new(self, range) - } -} - -impl<'a> RowIndex for FunctionRow<'a> { - fn idx(&self, idx: usize) -> Option { - if idx < self.field_count() { - Some(idx) - } else { - None - } - } -} - -impl<'a, 'b> RowIndex<&'a str> for FunctionRow<'b> { - fn idx(&self, _idx: &'a str) -> Option { - None - } -} - -struct FunctionArgument<'a> { - args: Ref<'a, ManuallyDrop>>, - col_idx: i32, -} - -impl<'a> Field<'a, WasmSqlite> for FunctionArgument<'a> { - fn field_name(&self) -> Option<&str> { - None - } - - fn is_null(&self) -> bool { - self.value().is_none() - } - - fn value(&self) -> Option<::RawValue<'_>> { - SqliteValue::new( - Ref::map(Ref::clone(&self.args), |drop| std::ops::Deref::deref(drop)), - self.col_idx, - ) - } -} diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs deleted file mode 100644 index b8492f450..000000000 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ /dev/null @@ -1,345 +0,0 @@ -mod bind_collector; -mod err; -mod owned_row; -mod raw; -mod row; -mod serialized_database; -mod sqlite_value; -mod statement_iterator; -mod stmt; - -pub(crate) use self::bind_collector::SqliteBindCollector; -pub use self::bind_collector::SqliteBindValue; -pub use self::sqlite_value::SqliteValue; -// pub use self::serialized_database::SerializedDatabase; - -use self::raw::RawConnection; -pub use self::statement_iterator::*; -use self::stmt::{Statement, StatementUse}; -use err::*; -// use diesel::connection::DynInstrumentation; -use diesel::{ - connection::WithMetadataLookup, - connection::{statement_cache::StatementCache, DefaultLoadingMode, LoadConnection}, - expression::QueryMetadata, - query_builder::Query, - result::*, - sql_types::TypeMetadata, - RunQueryDsl, -}; - -use diesel::{ - connection::{ - AnsiTransactionManager, Connection, ConnectionSealed, Instrumentation, SimpleConnection, - TransactionManager, - }, - query_builder::{QueryFragment, QueryId}, - QueryResult, -}; -use serialized_database::SerializedDatabase; - -use crate::{get_sqlite_unchecked, WasmSqlite, WasmSqliteError}; - -// This relies on the invariant that RawConnection or Statement are never -// leaked. If a reference to one of those was held on a different thread, this -// would not be thread safe. -// Web is in one thread. Web workers can establish & hold a WasmSqliteConnection -// separately. -#[allow(unsafe_code)] -unsafe impl Send for WasmSqliteConnection {} - -pub struct WasmSqliteConnection { - // statement_cache needs to be before raw_connection - // otherwise we will get errors about open statements before closing the - // connection itself - statement_cache: StatementCache, - raw_connection: RawConnection, - transaction_manager: AnsiTransactionManager, - metadata_lookup: (), - // this exists for the sole purpose of implementing `WithMetadataLookup` trait - // and avoiding static mut which will be deprecated in 2024 edition - instrumentation: Box, -} - -impl ConnectionSealed for WasmSqliteConnection {} - -impl SimpleConnection for WasmSqliteConnection { - fn batch_execute(&mut self, query: &str) -> diesel::prelude::QueryResult<()> { - get_sqlite_unchecked() - .exec(&self.raw_connection.internal_connection, query) - .map_err(WasmSqliteError::from) - .map_err(Into::into) - } -} - -impl Connection for WasmSqliteConnection { - type Backend = WasmSqlite; - type TransactionManager = AnsiTransactionManager; - - fn establish(database_url: &str) -> ConnectionResult { - WasmSqliteConnection::establish_inner(database_url) - } - - fn execute_returning_count(&mut self, source: &T) -> QueryResult - where - T: QueryFragment + QueryId, - { - let statement_use = self.prepared_query(source)?; - statement_use - .run() - .map(|_| self.raw_connection.rows_affected_by_last_query()) - } - - fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) { - self.instrumentation = Box::new(instrumentation); - } - - fn instrumentation(&mut self) -> &mut dyn Instrumentation { - self.instrumentation.as_mut() - } - - fn transaction_state(&mut self) -> &mut AnsiTransactionManager - where - Self: Sized, - { - &mut self.transaction_manager - } - - fn set_prepared_statement_cache_size(&mut self, size: diesel::connection::CacheSize) { - self.statement_cache.set_cache_size(size) - } -} - -impl LoadConnection for WasmSqliteConnection { - type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>; - type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>; - - fn load<'conn, 'query, T>( - &'conn mut self, - source: T, - ) -> QueryResult> - where - T: Query + QueryFragment + QueryId + 'query, - Self::Backend: QueryMetadata, - { - let statement = self.prepared_query(source)?; - - Ok(StatementIterator::new(statement)) - } -} - -impl WithMetadataLookup for WasmSqliteConnection { - fn metadata_lookup(&mut self) -> &mut ::MetadataLookup { - &mut self.metadata_lookup - } -} - -impl diesel::migration::MigrationConnection for WasmSqliteConnection { - fn setup(&mut self) -> QueryResult { - use diesel::RunQueryDsl; - diesel::sql_query(diesel::migration::CREATE_MIGRATIONS_TABLE).execute(self) - } -} - -#[derive(diesel::QueryId)] -pub(crate) struct CheckConnectionQuery; - -impl QueryFragment for CheckConnectionQuery -where - DB: diesel::backend::Backend, -{ - fn walk_ast<'b>( - &'b self, - mut pass: diesel::query_builder::AstPass<'_, 'b, DB>, - ) -> QueryResult<()> { - pass.push_sql("SELECT 1"); - Ok(()) - } -} - -impl Query for CheckConnectionQuery { - type SqlType = diesel::sql_types::Integer; -} - -impl RunQueryDsl for CheckConnectionQuery {} - -#[cfg(feature = "r2d2")] -impl diesel::r2d2::R2D2Connection for crate::connection::WasmSqliteConnection { - fn ping(&mut self) -> QueryResult<()> { - CheckConnectionQuery.execute(self).map(|_| ()) - } - - fn is_broken(&mut self) -> bool { - AnsiTransactionManager::is_broken_transaction_manager(self) - } -} - -impl diesel::connection::MultiConnectionHelper for WasmSqliteConnection { - fn to_any<'a>( - lookup: &mut ::MetadataLookup, - ) -> &mut (dyn std::any::Any + 'a) { - lookup - } - - fn from_any( - lookup: &mut dyn std::any::Any, - ) -> Option<&mut ::MetadataLookup> { - lookup.downcast_mut() - } -} - -impl WasmSqliteConnection { - /// Run a transaction with `BEGIN IMMEDIATE` - /// - /// This method will return an error if a transaction is already open. - /// - /// # Example - /// - /// ```rust - /// # include!("../../doctest_setup.rs"); - /// # - /// # fn main() { - /// # run_test().unwrap(); - /// # } - /// # - /// # fn run_test() -> QueryResult<()> { - /// # let mut conn = SqliteConnection::establish(":memory:").unwrap(); - /// conn.immediate_transaction(|conn| { - /// // Do stuff in a transaction - /// Ok(()) - /// }) - /// # } - /// ``` - pub fn immediate_transaction(&mut self, f: F) -> Result - where - F: FnOnce(&mut Self) -> Result, - E: From, - { - self.transaction_sql(f, "BEGIN IMMEDIATE") - } - - /// Run a transaction with `BEGIN EXCLUSIVE` - /// - /// This method will return an error if a transaction is already open. - /// - /// # Example - /// - /// ```rust - /// # include!("../../doctest_setup.rs"); - /// # - /// # fn main() { - /// # run_test().unwrap(); - /// # } - /// # - /// # fn run_test() -> QueryResult<()> { - /// # let mut conn = SqliteConnection::establish(":memory:").unwrap(); - /// conn.exclusive_transaction(|conn| { - /// // Do stuff in a transaction - /// Ok(()) - /// }) - /// # } - /// ``` - pub fn exclusive_transaction(&mut self, f: F) -> Result - where - F: FnOnce(&mut Self) -> Result, - E: From, - { - self.transaction_sql(f, "BEGIN EXCLUSIVE") - } - - fn transaction_sql(&mut self, f: F, sql: &str) -> Result - where - F: FnOnce(&mut Self) -> Result, - E: From, - { - AnsiTransactionManager::begin_transaction_sql(&mut *self, sql)?; - match f(&mut *self) { - Ok(value) => { - AnsiTransactionManager::commit_transaction(&mut *self)?; - Ok(value) - } - Err(e) => { - AnsiTransactionManager::rollback_transaction(&mut *self)?; - Err(e) - } - } - } - - fn prepared_query<'conn, 'query, T>( - &'conn mut self, - source: T, - ) -> QueryResult> - where - T: QueryFragment + QueryId + 'query, - { - /* - self.instrumentation - .on_connection_event(InstrumentationEvent::StartQuery { - query: &crate::debug_query(&source), - }); - */ - let WasmSqliteConnection { - ref mut raw_connection, - ref mut statement_cache, - ref mut instrumentation, - .. - } = self; - - let statement = match statement_cache.cached_statement( - &source, - &WasmSqlite, - &[], - |sql, is_cached| Statement::prepare(raw_connection, sql, is_cached), - instrumentation.as_mut(), - ) { - Ok(statement) => statement, - Err(e) => { - /* - self.instrumentation - .on_connection_event(InstrumentationEvent::FinishQuery { - query: &crate::debug_query(&source), - error: Some(&e), - }); - */ - return Err(e); - } - }; - - StatementUse::bind(statement, source, instrumentation.as_mut()) - } - - fn establish_inner(database_url: &str) -> Result { - let sqlite3 = crate::get_sqlite_unchecked(); - let raw_connection = RawConnection::establish(database_url).unwrap(); - tracing::debug!( - "Established database at {}", - sqlite3.filename(&raw_connection.internal_connection, "main".into()) - ); - sqlite3 - .register_diesel_sql_functions(&raw_connection.internal_connection) - .map_err(WasmSqliteError::from)?; - Ok(Self { - statement_cache: StatementCache::new(), - raw_connection, - transaction_manager: AnsiTransactionManager::default(), - instrumentation: Box::new(Nothing) as Box, - metadata_lookup: (), - }) - } - - pub fn serialize(&self) -> SerializedDatabase { - self.raw_connection.serialize() - } - - pub fn deserialize(&self, data: &[u8]) -> i32 { - self.raw_connection.deserialize(data) - } -} - -pub struct Nothing; - -impl Instrumentation for Nothing { - fn on_connection_event(&mut self, event: diesel::connection::InstrumentationEvent<'_>) { - tracing::trace!("{:?}", event); - } -} diff --git a/diesel-wasm-sqlite/src/connection/owned_row.rs b/diesel-wasm-sqlite/src/connection/owned_row.rs deleted file mode 100644 index f29dd8370..000000000 --- a/diesel-wasm-sqlite/src/connection/owned_row.rs +++ /dev/null @@ -1,94 +0,0 @@ -use std::sync::Arc; - -use super::sqlite_value::{OwnedSqliteValue, SqliteValue}; -use crate::WasmSqlite; -use diesel::{ - backend::Backend, - row::{Field, PartialRow, Row, RowIndex, RowSealed}, -}; - -#[derive(Debug)] -pub struct OwnedSqliteRow { - pub(super) values: Vec>, - column_names: Arc<[Option]>, -} - -impl OwnedSqliteRow { - pub(super) fn new( - values: Vec>, - column_names: Arc<[Option]>, - ) -> Self { - OwnedSqliteRow { - values, - column_names, - } - } -} - -impl RowSealed for OwnedSqliteRow {} - -impl<'a> Row<'a, WasmSqlite> for OwnedSqliteRow { - type Field<'field> = OwnedSqliteField<'field> where 'a: 'field, Self: 'field; - type InnerPartialRow = Self; - - fn field_count(&self) -> usize { - self.values.len() - } - - fn get<'field, I>(&'field self, idx: I) -> Option> - where - 'a: 'field, - Self: RowIndex, - { - let idx = self.idx(idx)?; - Some(OwnedSqliteField { - row: self, - col_idx: i32::try_from(idx).ok()?, - }) - } - - fn partial_row(&self, range: std::ops::Range) -> PartialRow<'_, Self::InnerPartialRow> { - PartialRow::new(self, range) - } -} - -impl RowIndex for OwnedSqliteRow { - fn idx(&self, idx: usize) -> Option { - if idx < self.field_count() { - Some(idx) - } else { - None - } - } -} - -impl<'idx> RowIndex<&'idx str> for OwnedSqliteRow { - fn idx(&self, field_name: &'idx str) -> Option { - self.column_names - .iter() - .position(|n| n.as_ref().map(|s| s as &str) == Some(field_name)) - } -} - -#[allow(missing_debug_implementations)] -pub struct OwnedSqliteField<'row> { - pub(super) row: &'row OwnedSqliteRow, - pub(super) col_idx: i32, -} - -impl<'row> Field<'row, WasmSqlite> for OwnedSqliteField<'row> { - fn field_name(&self) -> Option<&str> { - self.row - .column_names - .get(self.col_idx as usize) - .and_then(|o| o.as_ref().map(|s| s.as_ref())) - } - - fn is_null(&self) -> bool { - self.value().is_none() - } - - fn value(&self) -> Option<::RawValue<'row>> { - SqliteValue::from_owned_row(self.row, self.col_idx) - } -} diff --git a/diesel-wasm-sqlite/src/connection/raw.rs b/diesel-wasm-sqlite/src/connection/raw.rs deleted file mode 100755 index 4e614a586..000000000 --- a/diesel-wasm-sqlite/src/connection/raw.rs +++ /dev/null @@ -1,144 +0,0 @@ -#![allow(dead_code)] -// functions are needed, but missing functionality means they aren't used yet. - -use crate::{ffi, WasmSqlite, WasmSqliteError}; -use diesel::{result::*, sql_types::HasSqlType}; -use wasm_bindgen::{closure::Closure, JsValue}; - -use super::serialized_database::SerializedDatabase; - -#[allow(missing_copy_implementations)] -pub(super) struct RawConnection { - pub(super) internal_connection: JsValue, -} - -impl RawConnection { - pub(super) fn establish(database_url: &str) -> ConnectionResult { - let sqlite3 = crate::get_sqlite_unchecked(); - let database_url = if database_url.starts_with("sqlite://") { - database_url.replacen("sqlite://", "file:", 1) - } else { - database_url.to_string() - }; - - let capi = sqlite3.inner().capi(); - let flags = - capi.SQLITE_OPEN_READWRITE() | capi.SQLITE_OPEN_CREATE() | capi.SQLITE_OPEN_URI(); - - // TODO: flags are ignored for now - Ok(RawConnection { - internal_connection: sqlite3 - .open(&database_url, Some(flags as i32)) - .map_err(WasmSqliteError::from) - .map_err(ConnectionError::from)?, - }) - } - - pub(super) fn exec(&self, query: &str) -> QueryResult<()> { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3 - .exec(&self.internal_connection, query) - .map_err(WasmSqliteError::from)?; - Ok(()) - } - - pub(super) fn rows_affected_by_last_query(&self) -> usize { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.changes(&self.internal_connection) - } - - pub(super) fn register_sql_function( - &self, - fn_name: &str, - num_args: usize, - deterministic: bool, - f: F, - ) -> QueryResult<()> - where - F: FnMut(JsValue, Vec) -> JsValue + 'static, - WasmSqlite: HasSqlType, - { - let sqlite3 = crate::get_sqlite_unchecked(); - let flags = Self::get_flags(deterministic); - - let cb = Closure::new(f); - sqlite3 - .create_function( - &self.internal_connection, - fn_name, - num_args - .try_into() - .expect("usize to i32 panicked in register_sql_function"), - flags, - 0, - Some(&cb), - None, - None, - ) - .unwrap(); - Ok(()) - } - - fn get_flags(deterministic: bool) -> i32 { - let capi = crate::get_sqlite_unchecked().inner().capi(); - let mut flags = capi.SQLITE_UTF8(); - if deterministic { - flags |= capi.SQLITE_DETERMINISTIC(); - } - flags as i32 - } - - /// Serializes the database from sqlite to be stored by the user/client. - pub(super) fn serialize(&self) -> SerializedDatabase { - let sqlite3 = crate::get_sqlite_unchecked(); - let wasm = sqlite3.inner().wasm(); - - let p_size = wasm.pstack().alloc(std::mem::size_of::() as u32); - let data_ptr = sqlite3.sqlite3_serialize(&self.internal_connection, "main", &p_size, 0); - if data_ptr.is_null() { - panic!("Serialization failed"); - } - - let len = p_size.as_f64().unwrap() as u32; - unsafe { SerializedDatabase::new(data_ptr, len) } - } - - /// Deserializes the database from the data slice given to be loaded - /// by sqlite in the wasm space. - pub(super) fn deserialize(&self, data: &[u8]) -> i32 { - let sqlite3 = crate::get_sqlite_unchecked(); - let wasm = sqlite3.inner().wasm(); - - // allocate the space in wasm, and copy the buffer to the wasm - // memory space. - let p_data = wasm.alloc(data.len() as u32); - ffi::raw_copy_to_sqlite(data, p_data); - - let result = sqlite3.sqlite3_deserialize( - &self.internal_connection, - "main", - p_data, - data.len() as i64, - data.len() as i64, - 0, - ); - - if result != 0 { - panic!("Deserialization failed"); - } - - result - } -} - -impl Drop for RawConnection { - fn drop(&mut self) { - let sqlite3 = crate::get_sqlite_unchecked(); - - let result = sqlite3.close(&self.internal_connection); - if result != *crate::ffi::SQLITE_OK { - let error_message = super::error_message(result); - panic!("Error closing SQLite connection: {}", error_message); - } - } -} diff --git a/diesel-wasm-sqlite/src/connection/row.rs b/diesel-wasm-sqlite/src/connection/row.rs deleted file mode 100644 index 1af468dbf..000000000 --- a/diesel-wasm-sqlite/src/connection/row.rs +++ /dev/null @@ -1,203 +0,0 @@ -use std::cell::{Ref, RefCell}; -use std::rc::Rc; -use std::sync::Arc; - -use super::owned_row::OwnedSqliteRow; -use super::sqlite_value::{OwnedSqliteValue, SqliteValue}; -use super::stmt::StatementUse; -use crate::WasmSqlite; -use diesel::{ - backend::Backend, - row::{Field, IntoOwnedRow, PartialRow, Row, RowIndex, RowSealed}, -}; - -#[allow(missing_debug_implementations)] -pub struct SqliteRow<'stmt, 'query> { - pub(super) inner: Rc>>, - pub(super) field_count: usize, -} - -pub(super) enum PrivateSqliteRow<'stmt, 'query> { - Direct(StatementUse<'stmt, 'query>), - Duplicated { - values: Vec>, - column_names: Rc<[Option]>, - }, -} - -impl<'stmt, 'query> IntoOwnedRow<'stmt, WasmSqlite> for SqliteRow<'stmt, 'query> { - type OwnedRow = OwnedSqliteRow; - - type Cache = Option]>>; - - fn into_owned(self, column_name_cache: &mut Self::Cache) -> Self::OwnedRow { - self.inner.borrow().moveable(column_name_cache) - } -} - -impl<'stmt, 'query> PrivateSqliteRow<'stmt, 'query> { - pub(super) fn duplicate( - &mut self, - column_names: &mut Option]>>, - ) -> PrivateSqliteRow<'stmt, 'query> { - match self { - PrivateSqliteRow::Direct(stmt) => { - let column_names = if let Some(column_names) = column_names { - column_names.clone() - } else { - let c: Rc<[Option]> = Rc::from( - (0..stmt.column_count()) - .map(|idx| stmt.field_name(idx).map(|s| s.to_owned())) - .collect::>(), - ); - *column_names = Some(c.clone()); - c - }; - PrivateSqliteRow::Duplicated { - values: (0..stmt.column_count()) - .map(|idx| stmt.copy_value(idx)) - .collect(), - column_names, - } - } - PrivateSqliteRow::Duplicated { - values, - column_names, - } => PrivateSqliteRow::Duplicated { - values: values - .iter() - .map(|v| v.as_ref().map(|v| v.duplicate())) - .collect(), - column_names: column_names.clone(), - }, - } - } - - pub(super) fn moveable( - &self, - column_name_cache: &mut Option]>>, - ) -> OwnedSqliteRow { - match self { - PrivateSqliteRow::Direct(stmt) => { - if column_name_cache.is_none() { - *column_name_cache = Some( - (0..stmt.column_count()) - .map(|idx| stmt.field_name(idx).map(|s| s.to_owned())) - .collect::>() - .into(), - ); - } - let column_names = Arc::clone( - column_name_cache - .as_ref() - .expect("This is initialized above"), - ); - OwnedSqliteRow::new( - (0..stmt.column_count()) - .map(|idx| stmt.copy_value(idx)) - .collect(), - column_names, - ) - } - PrivateSqliteRow::Duplicated { - values, - column_names, - } => { - if column_name_cache.is_none() { - *column_name_cache = Some( - (*column_names) - .iter() - .map(|s| s.to_owned()) - .collect::>() - .into(), - ); - } - let column_names = Arc::clone( - column_name_cache - .as_ref() - .expect("This is initialized above"), - ); - OwnedSqliteRow::new( - values - .iter() - .map(|v| v.as_ref().map(|v| v.duplicate())) - .collect(), - column_names, - ) - } - } - } -} - -impl<'stmt, 'query> RowSealed for SqliteRow<'stmt, 'query> {} - -impl<'stmt, 'query> Row<'stmt, WasmSqlite> for SqliteRow<'stmt, 'query> { - type Field<'field> = SqliteField<'field, 'field> where 'stmt: 'field, Self: 'field; - type InnerPartialRow = Self; - - fn field_count(&self) -> usize { - self.field_count - } - - fn get<'field, I>(&'field self, idx: I) -> Option> - where - 'stmt: 'field, - Self: RowIndex, - { - let idx = self.idx(idx)?; - Some(SqliteField { - row: self.inner.borrow(), - col_idx: i32::try_from(idx).ok()?, - }) - } - - fn partial_row(&self, range: std::ops::Range) -> PartialRow<'_, Self::InnerPartialRow> { - PartialRow::new(self, range) - } -} - -impl<'stmt, 'query> RowIndex for SqliteRow<'stmt, 'query> { - fn idx(&self, idx: usize) -> Option { - if idx < self.field_count { - Some(idx) - } else { - None - } - } -} - -impl<'stmt, 'idx, 'query> RowIndex<&'idx str> for SqliteRow<'stmt, 'query> { - fn idx(&self, field_name: &'idx str) -> Option { - match &mut *self.inner.borrow_mut() { - PrivateSqliteRow::Direct(stmt) => stmt.index_for_column_name(field_name), - PrivateSqliteRow::Duplicated { column_names, .. } => column_names - .iter() - .position(|n| n.as_ref().map(|s| s as &str) == Some(field_name)), - } - } -} - -#[allow(missing_debug_implementations)] -pub struct SqliteField<'stmt, 'query> { - pub(super) row: Ref<'stmt, PrivateSqliteRow<'stmt, 'query>>, - pub(super) col_idx: i32, -} - -impl<'stmt, 'query> Field<'stmt, WasmSqlite> for SqliteField<'stmt, 'query> { - fn field_name(&self) -> Option<&str> { - match &*self.row { - PrivateSqliteRow::Direct(stmt) => stmt.field_name(self.col_idx), - PrivateSqliteRow::Duplicated { column_names, .. } => column_names - .get(self.col_idx as usize) - .and_then(|t| t.as_ref().map(|n| n as &str)), - } - } - - fn is_null(&self) -> bool { - self.value().is_none() - } - - fn value(&self) -> Option<::RawValue<'_>> { - SqliteValue::new(Ref::clone(&self.row), self.col_idx) - } -} diff --git a/diesel-wasm-sqlite/src/connection/serialized_database.rs b/diesel-wasm-sqlite/src/connection/serialized_database.rs deleted file mode 100644 index 876b37ebc..000000000 --- a/diesel-wasm-sqlite/src/connection/serialized_database.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi; - -/// `SerializedDatabase` is a wrapper for a serialized database that is dynamically allocated by calling `sqlite3_serialize`. -/// This RAII wrapper is necessary to deallocate the memory when it goes out of scope with `sqlite3_free`. -#[derive(Debug)] -pub struct SerializedDatabase { - pub data: Vec, -} - -impl SerializedDatabase { - pub(crate) unsafe fn new(data_ptr: *mut u8, len: u32) -> Self { - let mut data = vec![0; len as usize]; - ffi::raw_copy_from_sqlite(data_ptr, len, data.as_mut_slice()); - - crate::get_sqlite_unchecked().sqlite3_free(data_ptr); - - Self { data } - } -} diff --git a/diesel-wasm-sqlite/src/connection/sqlite_value.rs b/diesel-wasm-sqlite/src/connection/sqlite_value.rs deleted file mode 100644 index 1803b82d0..000000000 --- a/diesel-wasm-sqlite/src/connection/sqlite_value.rs +++ /dev/null @@ -1,181 +0,0 @@ -#![allow(unsafe_code)] // ffi calls - -use std::cell::Ref; - -use crate::backend::SqliteType; -use crate::ffi; - -use super::owned_row::OwnedSqliteRow; -use super::row::PrivateSqliteRow; - -/// Raw sqlite value as received from the database -/// -/// Use existing `FromSql` implementations to convert this into -/// rust values -#[allow(missing_debug_implementations, missing_copy_implementations)] -pub struct SqliteValue<'row, 'stmt, 'query> { - // This field exists to ensure that nobody - // can modify the underlying row while we are - // holding a reference to some row value here - _row: Option>>, - // we extract the raw value pointer as part of the constructor - // to safe the match statements for each method - // According to benchmarks this leads to a ~20-30% speedup - // - // - // This is sound as long as nobody calls `stmt.step()` - // while holding this value. We ensure this by including - // a reference to the row above. - /// We are referencing SQLites WASM memory, - /// so we just have to trust its not null rather than using `NonNull` - /// (i dont think that would work unless its our mem) - value: *mut u8, -} - -#[derive(Debug)] -pub(super) struct OwnedSqliteValue { - // maybe make JsValue? - pub(super) value: *mut u8, -} - -impl Drop for OwnedSqliteValue { - fn drop(&mut self) { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_free(self.value) - } -} - -// Unsafe Send impl safe since sqlite3_value is built with sqlite3_value_dup -// see https://www.sqlite.org/c3ref/value.html -unsafe impl Send for OwnedSqliteValue {} - -impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> { - pub(super) fn new( - row: Ref<'row, PrivateSqliteRow<'stmt, 'query>>, - col_idx: i32, - ) -> Option> { - let value = match &*row { - PrivateSqliteRow::Direct(stmt) => stmt.column_value(col_idx), - PrivateSqliteRow::Duplicated { values, .. } => { - values.get(col_idx as usize).and_then(|v| v.as_ref())?.value - } - }; - - let ret = Self { - _row: Some(row), - value, - }; - if ret.value_type().is_none() { - None - } else { - Some(ret) - } - } - - pub(super) fn from_owned_row( - row: &'row OwnedSqliteRow, - col_idx: i32, - ) -> Option> { - let value = row - .values - .get(col_idx as usize) - .and_then(|v| v.as_ref())? - .value; - let ret = Self { _row: None, value }; - if ret.value_type().is_none() { - None - } else { - Some(ret) - } - } - - pub(crate) fn read_text(&self) -> String { - self.parse_string(|s| s) - } - - // TODO: If we share memory with SQLITE, we can return a &'value str here rathre than an - // allocated String - pub(crate) fn parse_string(&self, f: impl FnOnce(String) -> R) -> R { - let sqlite3 = crate::get_sqlite_unchecked(); - // TODO: - // for some reason sqlite3_value_text returns the String and not a - // pointer. There's probably a way to make it return a pointer - let s = sqlite3.value_text(self.value); - // let s = unsafe { - // let ptr = sqlite3.value_text(self.value); - // let len = sqlite3.value_bytes(self.value); - // let mut bytes = Vec::with_capacity(len as usize); - // ffi::raw_copy_from_sqlite(ptr, len, bytes.as_mut_slice()); - // unsafe { bytes.set_len(len) }; // not sure we need this - // String::from_utf8_unchecked(bytes) - // }; - f(s) - } - - pub(crate) fn read_blob(&self) -> Vec { - let sqlite3 = crate::get_sqlite_unchecked(); - unsafe { - let ptr = sqlite3.value_blob(self.value); - let len = sqlite3.value_bytes(self.value); - let mut bytes = Vec::with_capacity(len as usize); - bytes.set_len(len as usize); - ffi::raw_copy_from_sqlite(ptr, len, bytes.as_mut_slice()); - bytes - } - } - - pub(crate) fn read_integer(&self) -> i32 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_int(self.value) - } - - pub(crate) fn read_long(&self) -> i64 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_int64(self.value) - } - - pub(crate) fn read_double(&self) -> f64 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.value_double(self.value) - } - - /// Get the type of the value as returned by sqlite - pub fn value_type(&self) -> Option { - let sqlite3 = crate::get_sqlite_unchecked(); - let tpe = sqlite3.value_type(self.value); - - match tpe { - _ if *ffi::SQLITE_TEXT == tpe => Some(SqliteType::Text), - _ if *ffi::SQLITE_INTEGER == tpe => Some(SqliteType::Long), - _ if *ffi::SQLITE_FLOAT == tpe => Some(SqliteType::Double), - _ if *ffi::SQLITE_BLOB == tpe => Some(SqliteType::Binary), - _ if *ffi::SQLITE_NULL == tpe => None, - _ => unreachable!( - "Sqlite's documentation state that this case ({}) is not reachable. \ - If you ever see this error message please open an issue at \ - https://github.com/diesel-rs/diesel.", - tpe - ), - } - } -} - -impl OwnedSqliteValue { - pub(super) fn copy_from_ptr(ptr: *mut u8) -> Option { - let sqlite3 = crate::get_sqlite_unchecked(); - let tpe = sqlite3.value_type(ptr); - if *ffi::SQLITE_NULL == tpe { - return None; - } - - let value = sqlite3.value_dup(ptr); - - Some(Self { value }) - } - - pub(super) fn duplicate(&self) -> OwnedSqliteValue { - let sqlite3 = crate::get_sqlite_unchecked(); - let value = sqlite3.value_dup(self.value); - OwnedSqliteValue { value } - } -} diff --git a/diesel-wasm-sqlite/src/connection/statement_iterator.rs b/diesel-wasm-sqlite/src/connection/statement_iterator.rs deleted file mode 100644 index 2e47d59cd..000000000 --- a/diesel-wasm-sqlite/src/connection/statement_iterator.rs +++ /dev/null @@ -1,159 +0,0 @@ -use std::cell::RefCell; -use std::rc::Rc; - -use super::row::{PrivateSqliteRow, SqliteRow}; -use super::stmt::StatementUse; -use diesel::result::QueryResult; - -#[allow(missing_debug_implementations)] -pub struct StatementIterator<'stmt, 'query> { - inner: PrivateStatementIterator<'stmt, 'query>, - column_names: Option]>>, - field_count: usize, -} - -impl<'stmt, 'query> StatementIterator<'stmt, 'query> { - #[cold] - fn handle_duplicated_row_case( - outer_last_row: &mut Rc>>, - column_names: &mut Option]>>, - field_count: usize, - ) -> Option>> { - // We don't own the statement. There is another existing reference, likely because - // a user stored the row in some long time container before calling next another time - // In this case we copy out the current values into a temporary store and advance - // the statement iterator internally afterwards - let last_row = { - let mut last_row = match outer_last_row.try_borrow_mut() { - Ok(o) => o, - Err(_e) => { - return Some(Err(diesel::result::Error::DeserializationError( - "Failed to reborrow row. Try to release any `SqliteField` or `SqliteValue` \ - that exists at this point" - .into(), - ))); - } - }; - let last_row = &mut *last_row; - let duplicated = last_row.duplicate(column_names); - std::mem::replace(last_row, duplicated) - }; - if let PrivateSqliteRow::Direct(mut stmt) = last_row { - // This is actually safe here as we've already - // performed one step. For the first step we would have - // used `PrivateStatementIterator::NotStarted` where we don't - // have access to `PrivateSqliteRow` at all - let res = stmt.step(false); - *outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); - match res { - Err(e) => Some(Err(e)), - Ok(false) => None, - Ok(true) => Some(Ok(SqliteRow { - inner: Rc::clone(outer_last_row), - field_count, - })), - } - } else { - // any other state than `PrivateSqliteRow::Direct` is invalid here - // and should not happen. If this ever happens this is a logic error - // in the code above - unreachable!( - "You've reached an impossible internal state. \ - If you ever see this error message please open \ - an issue at https://github.com/diesel-rs/diesel \ - providing example code how to trigger this error." - ) - } - } -} - -enum PrivateStatementIterator<'stmt, 'query> { - NotStarted(Option>), - Started(Rc>>), -} - -impl<'stmt, 'query> StatementIterator<'stmt, 'query> { - pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> { - Self { - inner: PrivateStatementIterator::NotStarted(Some(stmt)), - column_names: None, - field_count: 0, - } - } -} - -impl<'stmt, 'query> Iterator for StatementIterator<'stmt, 'query> { - type Item = QueryResult>; - - fn next(&mut self) -> Option { - use PrivateStatementIterator::{NotStarted, Started}; - match &mut self.inner { - NotStarted(ref mut stmt @ Some(_)) => { - let mut stmt = stmt - .take() - .expect("It must be there because we checked that above"); - let step = stmt.step(true); - match step { - Err(e) => Some(Err(e)), - Ok(false) => None, - Ok(true) => { - let field_count = stmt.column_count() as usize; - self.field_count = field_count; - let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt))); - self.inner = Started(inner.clone()); - Some(Ok(SqliteRow { inner, field_count })) - } - } - } - Started(ref mut last_row) => { - // There was already at least one iteration step - // We check here if the caller already released the row value or not - // by checking if our Rc owns the data or not - if let Some(last_row_ref) = Rc::get_mut(last_row) { - // We own the statement, there is no other reference here. - // This means we don't need to copy out values from the sqlite provided - // datastructures for now - // We don't need to use the runtime borrowing system of the RefCell here - // as we have a mutable reference, so all of this below is checked at compile time - if let PrivateSqliteRow::Direct(ref mut stmt) = last_row_ref.get_mut() { - let step = stmt.step(false); - - match step { - Err(e) => Some(Err(e)), - Ok(false) => None, - Ok(true) => { - let field_count = self.field_count; - Some(Ok(SqliteRow { - inner: Rc::clone(last_row), - field_count, - })) - } - } - } else { - // any other state than `PrivateSqliteRow::Direct` is invalid here - // and should not happen. If this ever happens this is a logic error - // in the code above - unreachable!( - "You've reached an impossible internal state. \ - If you ever see this error message please open \ - an issue at https://github.com/diesel-rs/diesel \ - providing example code how to trigger this error." - ) - } - } else { - Self::handle_duplicated_row_case( - last_row, - &mut self.column_names, - self.field_count, - ) - } - } - NotStarted(_s) => { - // we likely got an error while executing the other - // `NotStarted` branch above. In this case we just want to stop - // iterating here - None - } - } - } -} diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs deleted file mode 100644 index cc3255b61..000000000 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ /dev/null @@ -1,489 +0,0 @@ -#![allow(unsafe_code)] //TODO: can probably remove for wa-sqlite -use super::raw::RawConnection; -use super::sqlite_value::OwnedSqliteValue; -use crate::ffi; -use crate::{ - connection::{bind_collector::InternalSqliteBindValue, err::*, SqliteBindCollector}, - SqliteType, WasmSqlite, -}; -use diesel::{ - connection::{ - statement_cache::{MaybeCached, PrepareForCache}, - Instrumentation, - }, - query_builder::{QueryFragment, QueryId}, - result::{Error, QueryResult}, -}; -use std::ffi::CString; -use std::{cell::OnceCell, ptr::NonNull}; - -use wasm_bindgen::JsValue; - -// this is OK b/c web runs in one thread -unsafe impl Send for Statement {} -#[derive(Debug)] -pub(super) struct Statement { - // each iteration compiles a new statement for use - inner_statement: JsValue, -} - -impl Statement { - // NOTE: During diesel prepared statements, - // statements are cached. WASM might not like statements being cached - // since the statement pointer might be invalidated if a memory resize - // takes place. - pub fn prepare( - raw_connection: &RawConnection, - sql: &str, - is_cached: PrepareForCache, - ) -> QueryResult { - let sqlite3 = crate::get_sqlite_unchecked(); - - let flags = if matches!(is_cached, PrepareForCache::Yes { counter: _ }) { - Some(*ffi::SQLITE_PREPARE_PERSISTENT) - } else { - None - }; - - let wasm = sqlite3.inner().wasm(); - let stack = wasm.pstack().pointer(); - - // convert the query to a cstring - let sql = CString::new(sql)?; - let sql_bytes_with_nul = sql.as_bytes_with_nul(); - // we want to move the query over to sqlite-wasm - // allocate space for the query in sqlite-wasm space - let sql_ptr = wasm.alloc(sql_bytes_with_nul.len() as u32); - // copy cstring query to sqlite-wasm - ffi::raw_copy_to_sqlite(sql_bytes_with_nul, sql_ptr); - - // allocate one 64bit pointer value - let pp_stmt = wasm.pstack().alloc(8); - let prepare_result = sqlite3.prepare_v3( - &raw_connection.internal_connection, - sql_ptr, - sql_bytes_with_nul.len() as i32, - flags.unwrap_or(0), - &pp_stmt, - &JsValue::NULL, - ); - - let p_stmt = wasm.peek_ptr(&pp_stmt); - - ensure_sqlite_ok(prepare_result, &raw_connection.internal_connection)?; - - wasm.pstack().restore(&stack); - // sqlite3_prepare_v3 returns a null pointer for empty statements. This includes - // empty or only whitespace strings or any other non-op query string like a comment - if p_stmt.is_null() { - return Err(diesel::result::Error::QueryBuilderError(Box::new( - diesel::result::EmptyQuery, - ))); - } - - Ok(Self { - inner_statement: p_stmt, - }) - } - - fn copy_value_to_sqlite(bytes: &[u8]) -> *mut u8 { - let sqlite3 = crate::get_sqlite_unchecked(); - let wasm = sqlite3.inner().wasm(); - let wasm_inner = wasm.alloc_inner(); - - let len = bytes.len(); - let ptr = if len == 0 { - wasm.alloc_ptr(1, true) - } else { - wasm_inner.alloc_impl(len as u32) - }; - ffi::raw_copy_to_sqlite(bytes, ptr); - // TODO: Maybe check for null here and return [`std::ptr::NonNull`]? - // null is valid for bind function, it will just bind_null instead - // but seems like something that should be an error. - ptr - } - - // The caller of this function has to ensure that: - // * Any buffer provided as `SqliteBindValue::BorrowedBinary`, `SqliteBindValue::Binary` - // `SqliteBindValue::String` or `SqliteBindValue::BorrowedString` is valid - // till either a new value is bound to the same parameter or the underlying - // prepared statement is dropped. - fn bind( - &self, - tpe: SqliteType, - value: InternalSqliteBindValue<'_>, - bind_index: i32, - ) -> QueryResult>> { - let sqlite3 = crate::get_sqlite_unchecked(); - - let mut ret_ptr = None; - let wasm = sqlite3.inner().wasm(); - - let result = match (tpe, value) { - (_, InternalSqliteBindValue::Null) => { - sqlite3.bind_null(&self.inner_statement, bind_index) - } - (SqliteType::Binary, InternalSqliteBindValue::BorrowedBinary(bytes)) => { - // copy bytes from our WASM memory to SQLites WASM memory - tracing::trace!("Binding binary Borrowed! len={}", bytes.len()); - let ptr = Self::copy_value_to_sqlite(bytes); - ret_ptr = NonNull::new(ptr); - sqlite3.bind_blob( - &self.inner_statement, - bind_index, - ptr, - bytes.len() as i32, - *ffi::SQLITE_STATIC, - ) - } - (SqliteType::Binary, InternalSqliteBindValue::Binary(bytes)) => { - tracing::trace!("Binding binary Owned! len={}", bytes.len()); - let ptr = Self::copy_value_to_sqlite(bytes.as_slice()); - ret_ptr = NonNull::new(ptr); - sqlite3.bind_blob( - &self.inner_statement, - bind_index, - ptr, - bytes.len() as i32, - *ffi::SQLITE_STATIC, - ) - } - (SqliteType::Text, InternalSqliteBindValue::BorrowedString(bytes)) => { - tracing::trace!("Binding Borrowed String! len={}", bytes.len()); - let ptr = wasm.alloc_cstring(bytes.to_string()); - ret_ptr = NonNull::new(ptr); - sqlite3.bind_text( - &self.inner_statement, - bind_index, - ptr, - bytes.len() as i32, - *ffi::SQLITE_STATIC, - ) - } - (SqliteType::Text, InternalSqliteBindValue::String(bytes)) => { - tracing::trace!("Binding Owned String!"); - let len = bytes.len(); - let ptr = wasm.alloc_cstring(bytes); - ret_ptr = NonNull::new(ptr); - sqlite3.bind_text( - &self.inner_statement, - bind_index, - ptr, - len as i32, - *ffi::SQLITE_STATIC, - ) - } - (SqliteType::Float, InternalSqliteBindValue::F64(value)) - | (SqliteType::Double, InternalSqliteBindValue::F64(value)) => { - sqlite3.bind_double(&self.inner_statement, bind_index, value) - } - (SqliteType::SmallInt, InternalSqliteBindValue::I32(value)) - | (SqliteType::Integer, InternalSqliteBindValue::I32(value)) => { - sqlite3.bind_int(&self.inner_statement, bind_index, value) - } - (SqliteType::Long, InternalSqliteBindValue::I64(value)) => { - sqlite3.bind_int64(&self.inner_statement, bind_index, value) - } - (t, b) => { - return Err(Error::SerializationError( - format!("Type mismatch: Expected {t:?}, got {b}").into(), - )) - } - }; - match ensure_sqlite_ok(result, &self.raw_connection()) { - Ok(()) => Ok(ret_ptr), - Err(e) => { - if let Some(ptr) = ret_ptr { - wasm.dealloc(ptr); - } - Err(e) - } - } - } - - fn reset(&self) { - let sqlite3 = crate::get_sqlite_unchecked(); - let _ = sqlite3.reset(&self.inner_statement); - } - - fn raw_connection(&self) -> JsValue { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.db_handle(&self.inner_statement) - } -} - -impl Drop for Statement { - fn drop(&mut self) { - let sqlite3 = crate::get_sqlite_unchecked(); - tracing::trace!("Statement dropped & finalized!"); - sqlite3 - .finalize(&self.inner_statement) - .expect("Error finalized SQLite prepared statement"); - } -} - -// A warning for future editors: -// Changing this code to something "simpler" may -// introduce undefined behaviour. Make sure you read -// the following discussions for details about -// the current version: -// -// * https://github.com/weiznich/diesel/pull/7 -// * https://users.rust-lang.org/t/code-review-for-unsafe-code-in-diesel/66798/ -// * https://github.com/rust-lang/unsafe-code-guidelines/issues/194 -struct BoundStatement<'stmt, 'query> { - statement: MaybeCached<'stmt, Statement>, - // we need to store the query here to ensure no one does - // drop it till the end of the statement - // We use a boxed queryfragment here just to erase the - // generic type, we use NonNull to communicate - // that this is a shared buffer - query: Option + 'query>>, - binds_to_free: Vec<(i32, Option>)>, - #[allow(unused)] - instrumentation: &'stmt mut dyn Instrumentation, - has_error: bool, -} - -impl<'stmt, 'query> BoundStatement<'stmt, 'query> { - fn bind( - statement: MaybeCached<'stmt, Statement>, - query: T, - instrumentation: &'stmt mut dyn Instrumentation, - ) -> QueryResult> - where - T: QueryFragment + QueryId + 'query, - { - // Don't use a trait object here to prevent using a virtual function call - // For sqlite this can introduce a measurable overhead - // Query is boxed here to make sure it won't move in memory anymore, so any bind - // it could output would stay valid. - let query = Box::new(query); - - let mut bind_collector = SqliteBindCollector::new(); - query.collect_binds(&mut bind_collector, &mut (), &WasmSqlite)?; - let SqliteBindCollector { binds } = bind_collector; - - let mut ret = BoundStatement { - statement, - query: None, - binds_to_free: Vec::new(), - instrumentation, - has_error: false, - }; - - ret.bind_buffers(binds)?; - - let query = query as Box + 'query>; - ret.query = Some(query); - - Ok(ret) - } - - // This is a separated function so that - // not the whole constructor is generic over the query type T. - // This hopefully prevents binary bloat. - fn bind_buffers( - &mut self, - binds: Vec<(InternalSqliteBindValue<'_>, SqliteType)>, - ) -> QueryResult<()> { - self.binds_to_free.reserve( - binds - .iter() - .filter(|&(b, _)| { - matches!( - b, - InternalSqliteBindValue::BorrowedBinary(_) - | InternalSqliteBindValue::BorrowedString(_) - | InternalSqliteBindValue::String(_) - | InternalSqliteBindValue::Binary(_) - ) - }) - .count(), - ); - for (bind_idx, (bind, tpe)) in (1..).zip(binds) { - // It's safe to call bind here as: - // * The type and value matches - // * We ensure that corresponding buffers lives long enough below - // * The statement is not used yet by `step` or anything else - let res = self.statement.bind(tpe, bind, bind_idx)?; - - // it's important to push these only after - // the call to bind succeeded, otherwise we might attempt to - // call bind to an non-existing bind position in - // the destructor - - if let Some(ptr) = res { - // Store the id + pointer for a owned bind - // as we must unbind and free them on drop - self.binds_to_free.push((bind_idx, Some(ptr))); - } - } - Ok(()) - } - - fn finish_query_with_error(mut self, e: &Error) { - if let Some(q) = &self.query { - tracing::warn!( - "Query finished with error query={:?}, err={:?}", - &diesel::debug_query(&q), - e - ); - } - self.has_error = true; - } -} - -// we have to free the wawsm memory here not C memory so this will change significantly -impl<'stmt, 'query> Drop for BoundStatement<'stmt, 'query> { - fn drop(&mut self) { - self.statement.reset(); - // self.statement.clear_bindings().unwrap(); - let wasm = ffi::get_sqlite_unchecked().inner().wasm(); - for (idx, buffer) in std::mem::take(&mut self.binds_to_free) { - // It's always safe to bind null values, as there is no buffer that needs to outlife something - self.statement - .bind(SqliteType::Text, InternalSqliteBindValue::Null, idx) - .expect( - "Binding a null value should never fail. \ - If you ever see this error message please open \ - an issue at diesels issue tracker containing \ - code how to trigger this message.", - ); - - if let Some(buffer) = buffer { - wasm.dealloc(buffer); - } - } - if let Some(query) = self.query.take() { - std::mem::drop(query); - } - } -} - -#[allow(missing_debug_implementations)] -pub struct StatementUse<'stmt, 'query> { - statement: BoundStatement<'stmt, 'query>, - column_names: OnceCell>, -} - -impl<'stmt, 'query> StatementUse<'stmt, 'query> { - pub(super) fn bind( - statement: MaybeCached<'stmt, Statement>, - query: T, - instrumentation: &'stmt mut dyn Instrumentation, - ) -> QueryResult> - where - T: QueryFragment + QueryId + 'query, - { - Ok(Self { - statement: BoundStatement::bind(statement, query, instrumentation)?, - column_names: OnceCell::new(), - }) - } - - pub(super) fn run(mut self) -> QueryResult<()> { - // This is safe as we pass `first_step = true` - // and we consume the statement so nobody could - // access the columns later on anyway. - let r = self.step(true).map(|_| ()); - if let Err(ref e) = r { - self.statement.finish_query_with_error(e); - } - r - } - - // This function is marked as unsafe incorrectly passing `false` to `first_step` - // for a first call to this function could cause access to freed memory via - // the cached column names. - // - // It's always safe to call this function with `first_step = true` as this removes - // the cached column names - pub(super) fn step(&mut self, first_step: bool) -> QueryResult { - let sqlite3 = crate::get_sqlite_unchecked(); - let res = match sqlite3.step(&self.statement.statement.inner_statement) { - v if *ffi::SQLITE_DONE == v => Ok(false), - v if *ffi::SQLITE_ROW == v => Ok(true), - _ => Err(last_error(&self.statement.statement.raw_connection())), - }; - if first_step { - self.column_names = OnceCell::new(); - } - res - } - - // The returned string pointer is valid until either the prepared statement is - // destroyed by sqlite3_finalize() or until the statement is automatically - // reprepared by the first call to sqlite3_step() for a particular run or - // until the next call to sqlite3_column_name() or sqlite3_column_name16() - // on the same column. - // - // https://sqlite.org/c3ref/column_name.html - // - // Note: This function is marked as unsafe, as calling it can invalidate - // other existing column name pointers on the same column. To prevent that, - // it should maximally be called once per column at all. - fn column_name(&self, idx: i32) -> String { - let sqlite3 = crate::get_sqlite_unchecked(); - - sqlite3.column_name(&self.statement.statement.inner_statement, idx) - } - - pub(super) fn column_count(&self) -> i32 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.column_count(&self.statement.statement.inner_statement) - } - - pub(super) fn index_for_column_name(&mut self, field_name: &str) -> Option { - (0..self.column_count()) - .find(|idx| self.field_name(*idx) == Some(field_name)) - .map(|v| v as usize) - } - - pub(super) fn field_name(&self, idx: i32) -> Option<&str> { - let column_names = self.column_names.get_or_init(|| { - let count = self.column_count(); - (0..count).map(|idx| self.column_name(idx)).collect() - }); - - column_names.get(idx as usize).map(AsRef::as_ref) - } - - pub(super) fn copy_value(&self, idx: i32) -> Option { - OwnedSqliteValue::copy_from_ptr(self.column_value(idx)) - } - - pub(super) fn column_value(&self, idx: i32) -> *mut u8 { - let sqlite3 = crate::get_sqlite_unchecked(); - sqlite3.column_value(&self.statement.statement.inner_statement, idx) - } -} - -/* -#[cfg(test)] -mod tests { - use crate::prelude::*; - use crate::sql_types::Text; - - // this is a regression test for - // https://github.com/diesel-rs/diesel/issues/3558 - #[test] - fn check_out_of_bounds_bind_does_not_panic_on_drop() { - let mut conn = SqliteConnection::establish(":memory:").unwrap(); - - let e = crate::sql_query("SELECT '?'") - .bind::("foo") - .execute(&mut conn); - - assert!(e.is_err()); - let e = e.unwrap_err(); - if let crate::result::Error::DatabaseError(crate::result::DatabaseErrorKind::Unknown, m) = e - { - assert_eq!(m.message(), "column index out of range"); - } else { - panic!("Wrong error returned"); - } - } -} -*/ diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs deleted file mode 100644 index 45be75222..000000000 --- a/diesel-wasm-sqlite/src/ffi.rs +++ /dev/null @@ -1,352 +0,0 @@ -mod constants; -mod wasm; - -use js_sys::{Object, Uint8Array, WebAssembly::Memory}; -use serde::{Deserialize, Serialize}; -use tokio::sync::OnceCell; -use wasm_bindgen::{prelude::*, JsValue}; - -pub use constants::*; -pub use wasm::*; -// WASM is ran in the browser thread, either main or worker`. Tokio is only a single-threaded runtime. -// We need SQLite available globally, so this should be ok until we get threads with WASI or -// something. -unsafe impl Send for SQLite {} -unsafe impl Sync for SQLite {} - -/// The SQLite Library -/// this global constant references the loaded SQLite WASM. -pub(super) static SQLITE: OnceCell = OnceCell::const_new(); - -// it should be possible to: -// - shared WASM memory between us and SQLite, thereby reducing allocation overhead -// - Instantiate the WebAssembly.Module + WebAssembly.Instance from Rust (this could enable sharing -// of memory) -// - SQLite OpfsVfs just needs to be instantiated from WASM -// - OpfsVfs instantiation would be a one-time cost -// - this would make things overall more efficient since we wouldn't -// have to go through JS/browser at all. - -/// the raw WASM bytes -pub(super) const WASM: &[u8] = include_bytes!("js/sqlite3.wasm"); - -/// Options for instantiating memory constraints -#[derive(Serialize, Deserialize)] -struct MemoryOpts { - initial: u32, - maximum: u32, -} -/// Opts for the WASM Module -#[derive(Serialize, Deserialize)] -struct Opts { - /// The Sqlite3 WASM blob, compiled from C - #[serde(rename = "wasmBinary")] - wasm_binary: &'static [u8], - /// the shared WebAssembly Memory buffer - /// this allows us to manipulate the WASM memory from rust - #[serde(with = "serde_wasm_bindgen::preserve", rename = "wasmMemory")] - wasm_memory: Memory, - /// The URI for the OPFS async proxy. - #[serde(rename = "proxyUri")] - proxy_uri: String, -} - -/// Copy the contents of this wasms typed array into SQLite's memory. -/// -/// This function will efficiently copy the memory from a typed -/// array into this wasm module's own linear memory, initializing -/// the memory destination provided. -/// -/// # Safety -/// -/// This function requires `dst` to point to a buffer -/// large enough to fit this array's contents. -pub fn raw_copy_to_sqlite>(bytes: B, dst: *mut u8) { - let wasm = get_sqlite_unchecked().inner().wasm(); - let bytes: Uint8Array = bytes.into(); - let wasm_sqlite_mem = wasm.heap8u(); - let offset = dst as usize / std::mem::size_of::(); - wasm_sqlite_mem.set(&bytes, offset as u32); -} - -/// Copy the contents of this SQLite bytes this Wasms memory. -/// -/// This function will efficiently copy the memory from a typed -/// array into this wasm module's own linear memory, initializing -/// the memory destination provided. -/// -/// # Safety -/// -/// This function requires `buf` to point to a buffer -/// large enough to fit this array's contents. -pub unsafe fn raw_copy_from_sqlite(src: *mut u8, len: u32, buf: &mut [u8]) { - let wasm = crate::get_sqlite_unchecked().inner().wasm(); - let mem = wasm.heap8u(); - // this is safe because we view the slice and immediately copy it into - // our memory. - let view = Uint8Array::new_with_byte_offset_and_length(&mem.buffer(), src as u32, len); - view.raw_copy_to_ptr(buf.as_mut_ptr()) -} - -pub async fn init_sqlite() { - SQLITE - .get_or_init(|| async { - let mem = serde_wasm_bindgen::to_value(&MemoryOpts { - initial: 16_777_216 / 65_536, - maximum: 2_147_483_648 / 65_536, - }) - .expect("Serialization must be infallible for const struct"); - let mem = Memory::new(&js_sys::Object::from(mem)) - .expect("Wasm Memory could not be instantiated"); - let opts = serde_wasm_bindgen::to_value(&Opts { - wasm_binary: WASM, - wasm_memory: mem, - proxy_uri: wasm_bindgen::link_to!(module = "/src/js/sqlite3-opfs-async-proxy.js"), - }) - .expect("serialization must be infallible for const struct"); - let opts = Object::from(opts); - let object = SQLite::init_module(&opts).await; - let sqlite3 = SQLite::new(object); - let version: crate::ffi::Version = serde_wasm_bindgen::from_value(sqlite3.version()) - .expect("Version unexpected format"); - tracing::info!( - "SQLite initialized. version={}, download_version={}", - version.lib_version, - version.download_version - ); - - sqlite3 - }) - .await; -} - -pub(super) fn get_sqlite_unchecked() -> &'static SQLite { - SQLITE.get().expect("SQLite is not initialized") -} - -#[wasm_bindgen] -#[derive(Serialize, Deserialize, Debug)] -struct Version { - #[serde(rename = "libVersion")] - lib_version: String, - #[serde(rename = "libVersionNumber")] - lib_version_number: u32, - #[serde(rename = "sourceId")] - source_id: String, - #[serde(rename = "downloadVersion")] - download_version: u32, -} - -/// Direct Sqlite3 bindings -#[wasm_bindgen(module = "/src/js/wa-sqlite-diesel-bundle.js")] -extern "C" { - #[derive(Debug)] - pub type SQLite; - - #[derive(Debug)] - #[wasm_bindgen(extends = SQLite)] - pub type Inner; - - #[wasm_bindgen(method, getter, js_name = "sqlite3")] - pub fn inner(this: &SQLite) -> Inner; - - #[wasm_bindgen(method, getter)] - pub fn wasm(this: &Inner) -> Wasm; - - #[wasm_bindgen(method, getter)] - pub fn capi(this: &Inner) -> CApi; - - #[wasm_bindgen(static_method_of = SQLite)] - pub async fn init_module(module: &Object) -> JsValue; - - #[wasm_bindgen(constructor)] - pub fn new(module: JsValue) -> SQLite; - - #[wasm_bindgen(method)] - pub fn version(this: &SQLite) -> JsValue; - - #[wasm_bindgen(method)] - pub fn filename(this: &SQLite, db: &JsValue, name: String) -> String; - - #[wasm_bindgen(method)] - pub fn errstr(this: &SQLite, code: i32) -> String; - - #[wasm_bindgen(method)] - pub fn errmsg(this: &SQLite, conn: &JsValue) -> String; - - #[wasm_bindgen(method)] - pub fn extended_errcode(this: &SQLite, conn: &JsValue) -> i32; - - #[wasm_bindgen(method)] - pub fn result_text(this: &SQLite, context: i32, value: String); - - #[wasm_bindgen(method)] - pub fn result_int(this: &SQLite, context: i32, value: i32); - - #[wasm_bindgen(method)] - pub fn result_int64(this: &SQLite, context: i32, value: i64); - - #[wasm_bindgen(method)] - pub fn result_double(this: &SQLite, context: i32, value: f64); - - #[wasm_bindgen(method)] - pub fn result_blob(this: &SQLite, context: i32, value: Vec); - - #[wasm_bindgen(method)] - pub fn result_null(this: &SQLite, context: i32); - - #[wasm_bindgen(method)] - pub fn bind_parameter_count(this: &SQLite, stmt: &JsValue) -> i32; - - #[wasm_bindgen(method)] - pub fn bind_parameter_name(this: &SQLite, stmt: &JsValue, idx: i32) -> String; - - #[wasm_bindgen(method)] - pub fn bind_null(this: &SQLite, stmt: &JsValue, idx: i32) -> i32; - - #[wasm_bindgen(method)] - pub fn bind_text( - this: &SQLite, - stmt: &JsValue, - idx: i32, - ptr: *mut u8, - len: i32, - flags: i32, - ) -> i32; - - #[wasm_bindgen(method)] - pub fn bind_blob( - this: &SQLite, - stmt: &JsValue, - idx: i32, - ptr: *mut u8, - len: i32, - flags: i32, - ) -> i32; - - #[wasm_bindgen(method)] - pub fn bind_double(this: &SQLite, stmt: &JsValue, idx: i32, value: f64) -> i32; - - #[wasm_bindgen(method)] - pub fn bind_int(this: &SQLite, stmt: &JsValue, idx: i32, value: i32) -> i32; - - #[wasm_bindgen(method)] - pub fn bind_int64(this: &SQLite, stmt: &JsValue, idx: i32, value: i64) -> i32; - - #[wasm_bindgen(method)] - pub fn reset(this: &SQLite, stmt: &JsValue) -> i32; - - #[wasm_bindgen(method)] - pub fn value_dup(this: &SQLite, pValue: *mut u8) -> *mut u8; - - #[wasm_bindgen(method)] - pub fn value_blob(this: &SQLite, pValue: *mut u8) -> *mut u8; - - #[wasm_bindgen(method)] - pub fn value_bytes(this: &SQLite, pValue: *mut u8) -> u32; - - #[wasm_bindgen(method)] - pub fn value_double(this: &SQLite, pValue: *mut u8) -> f64; - - #[wasm_bindgen(method)] - pub fn value_free(this: &SQLite, pValue: *mut u8); - - #[wasm_bindgen(method)] - pub fn sqlite3_free(this: &SQLite, pValue: *mut u8); - - #[wasm_bindgen(method)] - pub fn value_int(this: &SQLite, pValue: *mut u8) -> i32; - - #[wasm_bindgen(method)] - pub fn value_int64(this: &SQLite, pValue: *mut u8) -> i64; - - #[wasm_bindgen(method)] - pub fn value_text(this: &SQLite, pValue: *mut u8) -> String; - - #[wasm_bindgen(method)] - pub fn value_type(this: &SQLite, pValue: *mut u8) -> i32; - - #[wasm_bindgen(method, catch)] - pub fn open(this: &SQLite, database_url: &str, iflags: Option) - -> Result; - - #[wasm_bindgen(method, catch)] - pub fn exec(this: &SQLite, database: &JsValue, query: &str) -> Result<(), JsValue>; - - #[wasm_bindgen(method, catch)] - pub fn finalize(this: &SQLite, stmt: &JsValue) -> Result<(), JsValue>; - - #[wasm_bindgen(method)] - pub fn changes(this: &SQLite, database: &JsValue) -> usize; - - #[wasm_bindgen(method, catch)] - pub fn get_stmt_from_iterator(this: &SQLite, iterator: &JsValue) -> Result; - - #[wasm_bindgen(method)] - pub fn step(this: &SQLite, stmt: &JsValue) -> i32; - - #[wasm_bindgen(method)] - pub fn clear_bindings(this: &SQLite, stmt: &JsValue) -> i32; - - #[wasm_bindgen(method)] - pub fn close(this: &SQLite, database: &JsValue) -> i32; - - #[wasm_bindgen(method)] - pub fn db_handle(this: &SQLite, stmt: &JsValue) -> JsValue; - - #[wasm_bindgen(method)] - pub fn column_value(this: &SQLite, stmt: &JsValue, idx: i32) -> *mut u8; - - #[wasm_bindgen(method)] - pub fn prepare_v3( - this: &SQLite, - database: &JsValue, - sql: *mut u8, - n_byte: i32, - prep_flags: u32, - stmt: &JsValue, - pzTail: &JsValue, - ) -> i32; - - #[wasm_bindgen(method)] - pub fn column_name(this: &SQLite, stmt: &JsValue, idx: i32) -> String; - - #[wasm_bindgen(method)] - pub fn column_count(this: &SQLite, stmt: &JsValue) -> i32; - - #[wasm_bindgen(method, catch)] - pub fn create_function( - this: &SQLite, - database: &JsValue, - functionName: &str, - n_arg: i32, - textRep: i32, - pApp: i32, //ignored - x_func: Option<&Closure) -> JsValue>>, - x_step: Option<&Closure) -> JsValue>>, - x_final: Option<&Closure>, - ) -> Result<(), JsValue>; - - #[wasm_bindgen(method, catch)] - pub fn register_diesel_sql_functions(this: &SQLite, database: &JsValue) -> Result<(), JsValue>; - - #[wasm_bindgen(method)] - pub fn sqlite3_serialize( - this: &SQLite, - database: &JsValue, - z_schema: &str, - p_size: &JsValue, - m_flags: u32, - ) -> *mut u8; - - #[wasm_bindgen(method)] - pub fn sqlite3_deserialize( - this: &SQLite, - database: &JsValue, - z_schema: &str, - p_data: *mut u8, - sz_database: i64, - sz_buffer: i64, - m_flags: u32, - ) -> i32; -} diff --git a/diesel-wasm-sqlite/src/ffi/constants.rs b/diesel-wasm-sqlite/src/ffi/constants.rs deleted file mode 100644 index 3282911f9..000000000 --- a/diesel-wasm-sqlite/src/ffi/constants.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! WASM Constant bindings -use std::sync::LazyLock; -use wasm_bindgen::prelude::*; - -/// Normally, statics or methods cannot be pattern-matched. -/// Pattern matching also does not automatically dereference. -/// constants are imported into wasm-bindgen as statics and/or const -/// methods. We use a combination of `LazyCell` -/// and exported wasm getters to achieve some kind of -/// pattern-matching syntax -/// ``` -/// match variable { -/// v if *ffi::SQLITE_DONE == v { -/// /* SQLITE_DONE */ -/// }, -/// v if *ffi:SQLITE_ROW == v { -/// /* SQLITE_ROW */ -/// } -/// } -/// ``` -/// -/// This is also a micro-optimization, -/// These constants will be initialized exactly once, rather -/// than on every access thus reducing the context-switching between wasm-js barrier. -macro_rules! generate_sqlite_constant { - ($fn_name:ident, $ty: ident) => { - pub static $fn_name: LazyLock<$ty> = LazyLock::new(|| { - let capi: CApi = crate::get_sqlite_unchecked().inner().capi(); - CApi::$fn_name(&capi) - }); - }; -} - -generate_sqlite_constant!(SQLITE_OK, i32); - -generate_sqlite_constant!(SQLITE_DONE, i32); -generate_sqlite_constant!(SQLITE_ROW, i32); - -generate_sqlite_constant!(SQLITE_INTEGER, i32); -generate_sqlite_constant!(SQLITE_FLOAT, i32); -generate_sqlite_constant!(SQLITE_TEXT, i32); -generate_sqlite_constant!(SQLITE_BLOB, i32); -generate_sqlite_constant!(SQLITE_NULL, i32); - -generate_sqlite_constant!(SQLITE_PREPARE_PERSISTENT, u32); - -generate_sqlite_constant!(SQLITE_CONSTRAINT_PRIMARYKEY, i32); -generate_sqlite_constant!(SQLITE_CONSTRAINT_UNIQUE, i32); -generate_sqlite_constant!(SQLITE_CONSTRAINT_FOREIGNKEY, i32); -generate_sqlite_constant!(SQLITE_CONSTRAINT_NOTNULL, i32); -generate_sqlite_constant!(SQLITE_CONSTRAINT_CHECK, i32); - -generate_sqlite_constant!(SQLITE_STATIC, i32); - -// C-Style API Constants -#[wasm_bindgen] -extern "C" { - /// C-Api Style bindings - #[wasm_bindgen(extends = super::Inner)] - pub type CApi; - - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OK(this: &CApi) -> i32; - - /// SQLite statement returns - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_DONE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_ROW(this: &CApi) -> i32; - - // Fundamental datatypes. - // https://www.sqlite.org/c3ref/c_blob.html - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_INTEGER(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_FLOAT(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_TEXT(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_BLOB(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_NULL(this: &CApi) -> i32; - - /// SQLite Open Flags - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_READONLY(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_READWRITE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_CREATE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_DELETEONCLOSE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_EXCLUSIVE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_AUTOPROXY(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_URI(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_MEMORY(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_MAIN_DB(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_TEMP_DB(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_TRANSIENT_DB(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_MAIN_JOURNAL(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_TEMP_JOURNAL(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_SUBJOURNAL(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_SUPER_JOURNAL(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_NOMUTEX(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_FULLMUTEX(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_SHAREDCACHE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_PRIVATECACHE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_WAL(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_NOFOLLOW(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_OPEN_EXRESCODE(this: &CApi) -> i32; - - // SQLite Text Encodings https://www.sqlite.org/capi3ref.html#SQLITE_ANY - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_UTF8(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_UTF16LE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_UTF16BE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_UTF16(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_ANY(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_UTF16_ALIGNED(this: &CApi) -> i32; - - /// SQLite Function Flags https://www.sqlite.org/capi3ref.html#sqlitedeterministic - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_DETERMINISTIC(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_DIRECTONLY(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_SUBTYPE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_INNOCUOUS(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_RESULT_SUBTYPE(this: &CApi) -> i32; - - // SQLite Prepare Flags https://www.sqlite.org/c3ref/c_prepare_normalize.html#sqlitepreparepersistent - #[wasm_bindgen(method, getter)] - pub const fn SQLITE_PREPARE_PERSISTENT(this: &CApi) -> u32; - #[wasm_bindgen(method, getter)] - pub fn SQLITE_PREPARE_NORMALIZE(this: &CApi) -> u32; - #[wasm_bindgen(method, getter)] - pub fn SQLITE_PREPARE_NO_VTAB(this: &CApi) -> u32; - - /// Constraint - - #[wasm_bindgen(method, getter)] - pub fn SQLITE_CONSTRAINT_UNIQUE(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub fn SQLITE_CONSTRAINT_PRIMARYKEY(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub fn SQLITE_CONSTRAINT_FOREIGNKEY(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub fn SQLITE_CONSTRAINT_NOTNULL(this: &CApi) -> i32; - #[wasm_bindgen(method, getter)] - pub fn SQLITE_CONSTRAINT_CHECK(this: &CApi) -> i32; - - /// Binds - #[wasm_bindgen(method, getter)] - pub fn SQLITE_STATIC(this: &CApi) -> i32; -} diff --git a/diesel-wasm-sqlite/src/ffi/wasm.rs b/diesel-wasm-sqlite/src/ffi/wasm.rs deleted file mode 100644 index 7fa4415f8..000000000 --- a/diesel-wasm-sqlite/src/ffi/wasm.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! WASM bindings for memory management -use std::ptr::NonNull; -use wasm_bindgen::prelude::*; - -#[wasm_bindgen] -extern "C" { - #[derive(Debug)] - #[wasm_bindgen(extends = super::Inner)] - pub type Wasm; - - #[wasm_bindgen(method, js_name = "peekPtr")] - pub fn peek_ptr(this: &Wasm, stmt: &JsValue) -> JsValue; - /// The "pstack" (pseudo-stack) API is a special-purpose allocator - /// intended solely for use with allocating small amounts of memory such - /// as that needed for output pointers. - /// It is more efficient than the scoped allocation API, - /// and covers many of the use cases for that API, but it - /// has a tiny static memory limit (with an unspecified total size no less than 4kb). - #[wasm_bindgen(method, getter)] - pub fn pstack(this: &Wasm) -> PStack; - - #[wasm_bindgen(method)] - pub fn alloc(this: &Wasm, bytes: u32) -> *mut u8; - - #[wasm_bindgen(method, getter, js_name = "alloc")] - pub fn alloc_inner(this: &Wasm) -> Alloc; - - /// Uses alloc() to allocate enough memory for the byte-length of the given JS string, - /// plus 1 (for a NUL terminator), copies the given JS string to that memory using jstrcpy(), - /// NUL-terminates it, and returns the pointer to that C-string. - /// Ownership of the pointer is transfered to the caller, who must eventually pass the pointer to dealloc() to free it. - //TODO: Avoid using this since it allocates in JS and other webassembly. Instead use technique - // used in Statement::prepare - #[wasm_bindgen(method, js_name = "allocCString")] - pub fn alloc_cstring(this: &Wasm, string: String) -> *mut u8; - - /// Allocates one or more pointers as a single chunk of memory and zeroes them out. - /// The first argument is the number of pointers to allocate. - /// The second specifies whether they should use a "safe" pointer size (8 bytes) - /// or whether they may use the default pointer size (typically 4 but also possibly 8). - /// How the result is returned depends on its first argument: if passed 1, it returns the allocated memory address. - /// If passed more than one then an array of pointer addresses is returned - #[wasm_bindgen(method, js_name = "allocPtr")] - pub fn alloc_ptr(this: &Wasm, how_many: u32, safe_ptr_size: bool) -> *mut u8; - - #[wasm_bindgen(method)] - pub fn dealloc(this: &Wasm, ptr: NonNull); - - /// View into the wasm memory reprsented as unsigned 8-bit integers - #[wasm_bindgen(method)] - pub fn heap8u(this: &Wasm) -> js_sys::Uint8Array; -} - -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(extends = Wasm)] - pub type PStack; - - /// allocate some memory on the PStack - #[wasm_bindgen(method)] - pub fn alloc(this: &PStack, bytes: u32) -> JsValue; - - /// Resolves the current pstack position pointer. - /// should only be used in argument for `restore` - #[wasm_bindgen(method, getter)] - pub fn pointer(this: &PStack) -> JsValue; - - /// resolves to total number of bytes available in pstack, including any - /// space currently allocated. compile-time constant - #[wasm_bindgen(method, getter)] - pub fn quota(this: &PStack) -> u32; - - // Property resolves to the amount of space remaining in the pstack - #[wasm_bindgen(method, getter)] - pub fn remaining(this: &PStack) -> u32; - - /// sets current pstack - #[wasm_bindgen(method)] - pub fn restore(this: &PStack, ptr: &JsValue); - -} - -#[wasm_bindgen] -extern "C" { - pub type Alloc; - - /// Non-throwing version of `Wasm::Alloc` - /// returns NULL pointer if cannot allocate - #[wasm_bindgen(method, js_name = "impl")] - pub fn alloc_impl(this: &Alloc, bytes: u32) -> *mut u8; -} diff --git a/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js b/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js deleted file mode 100644 index 07d4ac1f8..000000000 --- a/diesel-wasm-sqlite/src/js/sqlite3-opfs-async-proxy.js +++ /dev/null @@ -1,692 +0,0 @@ -/* - 2022-09-16 - - The author disclaims copyright to this source code. In place of a - legal notice, here is a blessing: - - * May you do good and not evil. - * May you find forgiveness for yourself and forgive others. - * May you share freely, never taking more than you give. - - *********************************************************************** - - A Worker which manages asynchronous OPFS handles on behalf of a - synchronous API which controls it via a combination of Worker - messages, SharedArrayBuffer, and Atomics. It is the asynchronous - counterpart of the API defined in sqlite3-vfs-opfs.js. - - Highly indebted to: - - https://github.com/rhashimoto/wa-sqlite/blob/master/src/examples/OriginPrivateFileSystemVFS.js - - for demonstrating how to use the OPFS APIs. - - This file is to be loaded as a Worker. It does not have any direct - access to the sqlite3 JS/WASM bits, so any bits which it needs (most - notably SQLITE_xxx integer codes) have to be imported into it via an - initialization process. - - This file represents an implementation detail of a larger piece of - code, and not a public interface. Its details may change at any time - and are not intended to be used by any client-level code. - - 2022-11-27: Chrome v108 changes some async methods to synchronous, as - documented at: - - https://developer.chrome.com/blog/sync-methods-for-accesshandles/ - - Firefox v111 and Safari 16.4, both released in March 2023, also - include this. - - We cannot change to the sync forms at this point without breaking - clients who use Chrome v104-ish or higher. truncate(), getSize(), - flush(), and close() are now (as of v108) synchronous. Calling them - with an "await", as we have to for the async forms, is still legal - with the sync forms but is superfluous. Calling the async forms with - theFunc().then(...) is not compatible with the change to - synchronous, but we do do not use those APIs that way. i.e. we don't - _need_ to change anything for this, but at some point (after Chrome - versions (approximately) 104-107 are extinct) should change our - usage of those methods to remove the "await". -*/ -const wPost = (type, ...args) => postMessage({ type, payload: args }); -const installAsyncProxy = function () { - const toss = function (...args) { - throw new Error(args.join(' ')); - }; - if (globalThis.window === globalThis) { - toss( - 'This code cannot run from the main thread.', - 'Load it as a Worker from a separate Worker.', - ); - } else if (!navigator?.storage?.getDirectory) { - toss('This API requires navigator.storage.getDirectory.'); - } - - const state = Object.create(null); - - state.verbose = 1; - - const loggers = { - 0: console.error.bind(console), - 1: console.warn.bind(console), - 2: console.log.bind(console), - }; - const logImpl = (level, ...args) => { - if (state.verbose > level) loggers[level]('OPFS asyncer:', ...args); - }; - const log = (...args) => logImpl(2, ...args); - const warn = (...args) => logImpl(1, ...args); - const error = (...args) => logImpl(0, ...args); - - const __openFiles = Object.create(null); - - const __implicitLocks = new Set(); - - const getResolvedPath = function (filename, splitIt) { - const p = new URL(filename, 'file://irrelevant').pathname; - return splitIt ? p.split('/').filter((v) => !!v) : p; - }; - - const getDirForFilename = async function f(absFilename, createDirs = false) { - const path = getResolvedPath(absFilename, true); - const filename = path.pop(); - let dh = state.rootDir; - for (const dirName of path) { - if (dirName) { - dh = await dh.getDirectoryHandle(dirName, { create: !!createDirs }); - } - } - return [dh, filename]; - }; - - const closeSyncHandle = async (fh) => { - if (fh.syncHandle) { - log('Closing sync handle for', fh.filenameAbs); - const h = fh.syncHandle; - delete fh.syncHandle; - delete fh.xLock; - __implicitLocks.delete(fh.fid); - return h.close(); - } - }; - - const closeSyncHandleNoThrow = async (fh) => { - try { - await closeSyncHandle(fh); - } catch (e) { - warn('closeSyncHandleNoThrow() ignoring:', e, fh); - } - }; - - const releaseImplicitLocks = async () => { - if (__implicitLocks.size) { - for (const fid of __implicitLocks) { - const fh = __openFiles[fid]; - await closeSyncHandleNoThrow(fh); - log('Auto-unlocked', fid, fh.filenameAbs); - } - } - }; - - const releaseImplicitLock = async (fh) => { - if (fh.releaseImplicitLocks && __implicitLocks.has(fh.fid)) { - return closeSyncHandleNoThrow(fh); - } - }; - - class GetSyncHandleError extends Error { - constructor(errorObject, ...msg) { - super( - [...msg, ': ' + errorObject.name + ':', errorObject.message].join(' '), - { - cause: errorObject, - }, - ); - this.name = 'GetSyncHandleError'; - } - } - - GetSyncHandleError.convertRc = (e, rc) => { - if (e instanceof GetSyncHandleError) { - if ( - e.cause.name === 'NoModificationAllowedError' || - (e.cause.name === 'DOMException' && - 0 === e.cause.message.indexOf('Access Handles cannot')) - ) { - return state.sq3Codes.SQLITE_BUSY; - } else if ('NotFoundError' === e.cause.name) { - return state.sq3Codes.SQLITE_CANTOPEN; - } - } else if ('NotFoundError' === e?.name) { - return state.sq3Codes.SQLITE_CANTOPEN; - } - return rc; - }; - - const getSyncHandle = async (fh, opName) => { - if (!fh.syncHandle) { - const t = performance.now(); - log('Acquiring sync handle for', fh.filenameAbs); - const maxTries = 6, - msBase = state.asyncIdleWaitTime * 2; - let i = 1, - ms = msBase; - for (; true; ms = msBase * ++i) { - try { - fh.syncHandle = await fh.fileHandle.createSyncAccessHandle(); - break; - } catch (e) { - if (i === maxTries) { - throw new GetSyncHandleError( - e, - 'Error getting sync handle for', - opName + '().', - maxTries, - 'attempts failed.', - fh.filenameAbs, - ); - } - warn( - 'Error getting sync handle for', - opName + '(). Waiting', - ms, - 'ms and trying again.', - fh.filenameAbs, - e, - ); - Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms); - } - } - log( - 'Got', - opName + '() sync handle for', - fh.filenameAbs, - 'in', - performance.now() - t, - 'ms', - ); - if (!fh.xLock) { - __implicitLocks.add(fh.fid); - log( - 'Acquired implicit lock for', - opName + '()', - fh.fid, - fh.filenameAbs, - ); - } - } - return fh.syncHandle; - }; - - const storeAndNotify = (opName, value) => { - log(opName + '() => notify(', value, ')'); - Atomics.store(state.sabOPView, state.opIds.rc, value); - Atomics.notify(state.sabOPView, state.opIds.rc); - }; - - const affirmNotRO = function (opName, fh) { - if (fh.readOnly) toss(opName + '(): File is read-only: ' + fh.filenameAbs); - }; - - let flagAsyncShutdown = false; - - const vfsAsyncImpls = { - 'opfs-async-shutdown': async () => { - flagAsyncShutdown = true; - storeAndNotify('opfs-async-shutdown', 0); - }, - mkdir: async (dirname) => { - let rc = 0; - try { - await getDirForFilename(dirname + '/filepart', true); - } catch (e) { - state.s11n.storeException(2, e); - rc = state.sq3Codes.SQLITE_IOERR; - } - storeAndNotify('mkdir', rc); - }, - xAccess: async (filename) => { - let rc = 0; - try { - const [dh, fn] = await getDirForFilename(filename); - await dh.getFileHandle(fn); - } catch (e) { - state.s11n.storeException(2, e); - rc = state.sq3Codes.SQLITE_IOERR; - } - storeAndNotify('xAccess', rc); - }, - xClose: async function (fid) { - const opName = 'xClose'; - __implicitLocks.delete(fid); - const fh = __openFiles[fid]; - let rc = 0; - if (fh) { - delete __openFiles[fid]; - await closeSyncHandle(fh); - if (fh.deleteOnClose) { - try { - await fh.dirHandle.removeEntry(fh.filenamePart); - } catch (e) { - warn('Ignoring dirHandle.removeEntry() failure of', fh, e); - } - } - } else { - state.s11n.serialize(); - rc = state.sq3Codes.SQLITE_NOTFOUND; - } - storeAndNotify(opName, rc); - }, - xDelete: async function (...args) { - const rc = await vfsAsyncImpls.xDeleteNoWait(...args); - storeAndNotify('xDelete', rc); - }, - xDeleteNoWait: async function (filename, syncDir = 0, recursive = false) { - let rc = 0; - try { - while (filename) { - const [hDir, filenamePart] = await getDirForFilename(filename, false); - if (!filenamePart) break; - await hDir.removeEntry(filenamePart, { recursive }); - if (0x1234 !== syncDir) break; - recursive = false; - filename = getResolvedPath(filename, true); - filename.pop(); - filename = filename.join('/'); - } - } catch (e) { - state.s11n.storeException(2, e); - rc = state.sq3Codes.SQLITE_IOERR_DELETE; - } - return rc; - }, - xFileSize: async function (fid) { - const fh = __openFiles[fid]; - let rc = 0; - try { - const sz = await (await getSyncHandle(fh, 'xFileSize')).getSize(); - state.s11n.serialize(Number(sz)); - } catch (e) { - state.s11n.storeException(1, e); - rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR); - } - await releaseImplicitLock(fh); - storeAndNotify('xFileSize', rc); - }, - xLock: async function (fid, lockType) { - const fh = __openFiles[fid]; - let rc = 0; - const oldLockType = fh.xLock; - fh.xLock = lockType; - if (!fh.syncHandle) { - try { - await getSyncHandle(fh, 'xLock'); - __implicitLocks.delete(fid); - } catch (e) { - state.s11n.storeException(1, e); - rc = GetSyncHandleError.convertRc( - e, - state.sq3Codes.SQLITE_IOERR_LOCK, - ); - fh.xLock = oldLockType; - } - } - storeAndNotify('xLock', rc); - }, - xOpen: async function (fid, filename, flags, opfsFlags) { - const opName = 'xOpen'; - const create = state.sq3Codes.SQLITE_OPEN_CREATE & flags; - try { - let hDir, filenamePart; - try { - [hDir, filenamePart] = await getDirForFilename(filename, !!create); - } catch (e) { - state.s11n.storeException(1, e); - storeAndNotify(opName, state.sq3Codes.SQLITE_NOTFOUND); - return; - } - if (state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN & opfsFlags) { - try { - await hDir.removeEntry(filenamePart); - } catch (e) {} - } - const hFile = await hDir.getFileHandle(filenamePart, { create }); - const fh = Object.assign(Object.create(null), { - fid: fid, - filenameAbs: filename, - filenamePart: filenamePart, - dirHandle: hDir, - fileHandle: hFile, - sabView: state.sabFileBufView, - readOnly: create - ? false - : state.sq3Codes.SQLITE_OPEN_READONLY & flags, - deleteOnClose: !!(state.sq3Codes.SQLITE_OPEN_DELETEONCLOSE & flags), - }); - fh.releaseImplicitLocks = - opfsFlags & state.opfsFlags.OPFS_UNLOCK_ASAP || - state.opfsFlags.defaultUnlockAsap; - __openFiles[fid] = fh; - storeAndNotify(opName, 0); - } catch (e) { - error(opName, e); - state.s11n.storeException(1, e); - storeAndNotify(opName, state.sq3Codes.SQLITE_IOERR); - } - }, - xRead: async function (fid, n, offset64) { - let rc = 0, - nRead; - const fh = __openFiles[fid]; - try { - nRead = (await getSyncHandle(fh, 'xRead')).read( - fh.sabView.subarray(0, n), - { at: Number(offset64) }, - ); - if (nRead < n) { - fh.sabView.fill(0, nRead, n); - rc = state.sq3Codes.SQLITE_IOERR_SHORT_READ; - } - } catch (e) { - error('xRead() failed', e, fh); - state.s11n.storeException(1, e); - rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_READ); - } - await releaseImplicitLock(fh); - storeAndNotify('xRead', rc); - }, - xSync: async function (fid, flags) { - const fh = __openFiles[fid]; - let rc = 0; - if (!fh.readOnly && fh.syncHandle) { - try { - await fh.syncHandle.flush(); - } catch (e) { - state.s11n.storeException(2, e); - rc = state.sq3Codes.SQLITE_IOERR_FSYNC; - } - } - storeAndNotify('xSync', rc); - }, - xTruncate: async function (fid, size) { - let rc = 0; - const fh = __openFiles[fid]; - try { - affirmNotRO('xTruncate', fh); - await (await getSyncHandle(fh, 'xTruncate')).truncate(size); - } catch (e) { - error('xTruncate():', e, fh); - state.s11n.storeException(2, e); - rc = GetSyncHandleError.convertRc( - e, - state.sq3Codes.SQLITE_IOERR_TRUNCATE, - ); - } - await releaseImplicitLock(fh); - storeAndNotify('xTruncate', rc); - }, - xUnlock: async function (fid, lockType) { - let rc = 0; - const fh = __openFiles[fid]; - if (state.sq3Codes.SQLITE_LOCK_NONE === lockType && fh.syncHandle) { - try { - await closeSyncHandle(fh); - } catch (e) { - state.s11n.storeException(1, e); - rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; - } - } - storeAndNotify('xUnlock', rc); - }, - xWrite: async function (fid, n, offset64) { - let rc; - const fh = __openFiles[fid]; - try { - affirmNotRO('xWrite', fh); - rc = - n === - (await getSyncHandle(fh, 'xWrite')).write(fh.sabView.subarray(0, n), { - at: Number(offset64), - }) - ? 0 - : state.sq3Codes.SQLITE_IOERR_WRITE; - } catch (e) { - error('xWrite():', e, fh); - state.s11n.storeException(1, e); - rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_WRITE); - } - await releaseImplicitLock(fh); - storeAndNotify('xWrite', rc); - }, - }; - - const initS11n = () => { - if (state.s11n) return state.s11n; - const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder('utf-8'), - viewU8 = new Uint8Array( - state.sabIO, - state.sabS11nOffset, - state.sabS11nSize, - ), - viewDV = new DataView( - state.sabIO, - state.sabS11nOffset, - state.sabS11nSize, - ); - state.s11n = Object.create(null); - const TypeIds = Object.create(null); - TypeIds.number = { - id: 1, - size: 8, - getter: 'getFloat64', - setter: 'setFloat64', - }; - TypeIds.bigint = { - id: 2, - size: 8, - getter: 'getBigInt64', - setter: 'setBigInt64', - }; - TypeIds.boolean = { - id: 3, - size: 4, - getter: 'getInt32', - setter: 'setInt32', - }; - TypeIds.string = { id: 4 }; - const getTypeId = (v) => - TypeIds[typeof v] || - toss('Maintenance required: this value type cannot be serialized.', v); - const getTypeIdById = (tid) => { - switch (tid) { - case TypeIds.number.id: - return TypeIds.number; - case TypeIds.bigint.id: - return TypeIds.bigint; - case TypeIds.boolean.id: - return TypeIds.boolean; - case TypeIds.string.id: - return TypeIds.string; - default: - toss('Invalid type ID:', tid); - } - }; - state.s11n.deserialize = function (clear = false) { - const argc = viewU8[0]; - const rc = argc ? [] : null; - if (argc) { - const typeIds = []; - let offset = 1, - i, - n, - v; - for (i = 0; i < argc; ++i, ++offset) { - typeIds.push(getTypeIdById(viewU8[offset])); - } - for (i = 0; i < argc; ++i) { - const t = typeIds[i]; - if (t.getter) { - v = viewDV[t.getter](offset, state.littleEndian); - offset += t.size; - } else { - n = viewDV.getInt32(offset, state.littleEndian); - offset += 4; - v = textDecoder.decode(viewU8.slice(offset, offset + n)); - offset += n; - } - rc.push(v); - } - } - if (clear) viewU8[0] = 0; - - return rc; - }; - state.s11n.serialize = function (...args) { - if (args.length) { - const typeIds = []; - let i = 0, - offset = 1; - viewU8[0] = args.length & 0xff; - for (; i < args.length; ++i, ++offset) { - typeIds.push(getTypeId(args[i])); - viewU8[offset] = typeIds[i].id; - } - for (i = 0; i < args.length; ++i) { - const t = typeIds[i]; - if (t.setter) { - viewDV[t.setter](offset, args[i], state.littleEndian); - offset += t.size; - } else { - const s = textEncoder.encode(args[i]); - viewDV.setInt32(offset, s.byteLength, state.littleEndian); - offset += 4; - viewU8.set(s, offset); - offset += s.byteLength; - } - } - } else { - viewU8[0] = 0; - } - }; - - state.s11n.storeException = state.asyncS11nExceptions - ? (priority, e) => { - if (priority <= state.asyncS11nExceptions) { - state.s11n.serialize([e.name, ': ', e.message].join('')); - } - } - : () => {}; - - return state.s11n; - }; - - const waitLoop = async function f() { - const opHandlers = Object.create(null); - for (let k of Object.keys(state.opIds)) { - const vi = vfsAsyncImpls[k]; - if (!vi) continue; - const o = Object.create(null); - opHandlers[state.opIds[k]] = o; - o.key = k; - o.f = vi; - } - while (!flagAsyncShutdown) { - try { - if ( - 'not-equal' !== - Atomics.wait( - state.sabOPView, - state.opIds.whichOp, - 0, - state.asyncIdleWaitTime, - ) - ) { - await releaseImplicitLocks(); - continue; - } - const opId = Atomics.load(state.sabOPView, state.opIds.whichOp); - Atomics.store(state.sabOPView, state.opIds.whichOp, 0); - const hnd = - opHandlers[opId] ?? toss('No waitLoop handler for whichOp #', opId); - const args = state.s11n.deserialize(true) || []; - - if (hnd.f) await hnd.f(...args); - else error('Missing callback for opId', opId); - } catch (e) { - error('in waitLoop():', e); - } - } - }; - - navigator.storage - .getDirectory() - .then(function (d) { - state.rootDir = d; - globalThis.onmessage = function ({ data }) { - switch (data.type) { - case 'opfs-async-init': { - const opt = data.args; - for (const k in opt) state[k] = opt[k]; - state.verbose = opt.verbose ?? 1; - state.sabOPView = new Int32Array(state.sabOP); - state.sabFileBufView = new Uint8Array( - state.sabIO, - 0, - state.fileBufferSize, - ); - state.sabS11nView = new Uint8Array( - state.sabIO, - state.sabS11nOffset, - state.sabS11nSize, - ); - Object.keys(vfsAsyncImpls).forEach((k) => { - if (!Number.isFinite(state.opIds[k])) { - toss('Maintenance required: missing state.opIds[', k, ']'); - } - }); - initS11n(); - log('init state', state); - wPost('opfs-async-inited'); - waitLoop(); - break; - } - case 'opfs-async-restart': - if (flagAsyncShutdown) { - warn( - 'Restarting after opfs-async-shutdown. Might or might not work.', - ); - flagAsyncShutdown = false; - waitLoop(); - } - break; - } - }; - wPost('opfs-async-loaded'); - }) - .catch((e) => error('error initializing OPFS asyncer:', e)); -}; -if (!globalThis.SharedArrayBuffer) { - wPost( - 'opfs-unavailable', - 'Missing SharedArrayBuffer API.', - 'The server must emit the COOP/COEP response headers to enable that.', - ); -} else if (!globalThis.Atomics) { - wPost( - 'opfs-unavailable', - 'Missing Atomics API.', - 'The server must emit the COOP/COEP response headers to enable that.', - ); -} else if ( - !globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory -) { - wPost('opfs-unavailable', 'Missing required OPFS APIs.'); -} else { - installAsyncProxy(); -} diff --git a/diesel-wasm-sqlite/src/js/sqlite3.wasm b/diesel-wasm-sqlite/src/js/sqlite3.wasm deleted file mode 100644 index c31c0ce353a1dae8d3562241e52ae402f63b3ba3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 939204 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