diff --git a/.gitignore b/.gitignore index b41bbce9..5fd6dfec 100644 --- a/.gitignore +++ b/.gitignore @@ -77,4 +77,8 @@ _load_test # JS node_modules -.temp \ No newline at end of file +.temp +node_modules/ +docs/.vuepress/.cache/ +docs/.vuepress/.temp/ +docs/.vuepress/dist/ diff --git a/Cargo.lock b/Cargo.lock index fc0b9c9b..e7e6678a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,6 +572,15 @@ version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +[[package]] +name = "inventory" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b31349d02fe60f80bbbab1a9402364cad7460626d6030494b08ac4a2075bf81" +dependencies = [ + "rustversion", +] + [[package]] name = "itertools" version = "0.12.1" @@ -997,7 +1006,7 @@ dependencies = [ [[package]] name = "psqlpy" -version = "0.10.1" +version = "0.11.1" dependencies = [ "byteorder", "bytes", @@ -1061,6 +1070,7 @@ dependencies = [ "cfg-if", "chrono", "indoc", + "inventory", "libc", "memoffset", "once_cell", @@ -1291,6 +1301,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" version = "1.0.18" diff --git a/Cargo.toml b/Cargo.toml index b33f08c2..d4c171a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "psqlpy" -version = "0.10.1" +version = "0.11.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -10,7 +10,14 @@ crate-type = ["cdylib"] [dependencies] deadpool-postgres = { git = "https://github.com/chandr-andr/deadpool.git", branch = "psqlpy" } -pyo3 = { version = "0.23.4", features = ["chrono", "experimental-async", "rust_decimal", "py-clone", "macros"] } +pyo3 = { version = "0.23.4", features = [ + "chrono", + "experimental-async", + "rust_decimal", + "py-clone", + "macros", + "multiple-pymethods", +] } pyo3-async-runtimes = { git = "https://github.com/chandr-andr/pyo3-async-runtimes.git", branch = "psqlpy", features = [ "tokio-runtime", ] } diff --git a/README.md b/README.md index 1272db9c..57f7509b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ [![PyPI - Python Version](https://img.shields.io/badge/PYTHON-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue?style=for-the-badge )](https://pypi.org/project/psqlpy/) +[![PyPI - Python Version](https://img.shields.io/badge/Tested%20On%20PostgreSQL-14%20%7C%2015%20%7C%2016%20%7C17-2be28a?style=for-the-badge +)](https://pypi.org/project/psqlpy/) [![PyPI](https://img.shields.io/pypi/v/psqlpy?style=for-the-badge)](https://pypi.org/project/psqlpy/) [![PyPI - Downloads](https://img.shields.io/pypi/dm/psqlpy?style=for-the-badge)](https://pypistats.org/packages/psqlpy) diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts index c98c5b05..7fbde9c7 100644 --- a/docs/.vuepress/config.ts +++ b/docs/.vuepress/config.ts @@ -1,15 +1,14 @@ import { defineUserConfig } from "vuepress"; import { hopeTheme } from "vuepress-theme-hope"; import sidebar from "./sidebar.js"; - -import { viteBundler } from '@vuepress/bundler-vite' +import { markdownTabPlugin } from '@vuepress/plugin-markdown-tab' export default defineUserConfig({ lang: "en-US", title: "PSQLPy", description: "PSQLPy Documentation", - bundler: viteBundler(), + // bundler: viteBundler(), theme: hopeTheme({ repo: "psqlpy-python/psqlpy", @@ -22,22 +21,20 @@ export default defineUserConfig({ hostname: "https://psqlpy-python.github.io/", + markdown: { + tabs: true, + mermaid: true, + chartjs: true, + }, + plugins: { readingTime: false, - copyCode: { showInMobile: true, }, - searchPro: { + slimsearch: { indexContent: true, - autoSuggestions: false, - }, - - mdEnhance: { - tabs: true, - mermaid: true, - chart: true, }, sitemap: { diff --git a/docs/.vuepress/sidebar.ts b/docs/.vuepress/sidebar.ts index 1a3c1efd..7a03377d 100644 --- a/docs/.vuepress/sidebar.ts +++ b/docs/.vuepress/sidebar.ts @@ -23,6 +23,7 @@ export default sidebar({ "connection", "transaction", "cursor", + "prepared_statement", "listener", "results", "exceptions", @@ -45,6 +46,15 @@ export default sidebar({ "advanced_type_usage", ] }, + { + text: "Row Factories Usage", + prefix: "row_factories/", + collapsible: true, + children: [ + "row_factories", + "predefined_row_factories", + ] + }, { text: "Frameworks Usage", prefix: "frameworks/", @@ -57,15 +67,6 @@ export default sidebar({ "robyn", ] }, - { - text: "Row Factories Usage", - prefix: "row_factories/", - collapsible: true, - children: [ - "row_factories", - "predefined_row_factories", - ] - }, ], }, { diff --git a/docs/.vuepress/styles/config.scss b/docs/.vuepress/styles/config.scss new file mode 100644 index 00000000..613ae09e --- /dev/null +++ b/docs/.vuepress/styles/config.scss @@ -0,0 +1,3 @@ +$code-dark-theme: dracula; +$code-light-theme: one-light; +$theme-color: #264934; \ No newline at end of file diff --git a/docs/.vuepress/styles/index.scss b/docs/.vuepress/styles/index.scss new file mode 100644 index 00000000..8fe3ba67 --- /dev/null +++ b/docs/.vuepress/styles/index.scss @@ -0,0 +1,19 @@ +// place your custom styles here +.vp-site-name { + visibility: hidden; +} + +.vp-hero-info { + img { + max-width: 60% !important; + padding: 1rem; + } +} + +.vp-hero-title { + font-size: 3rem; +} + +.vp-actions { + align-items: flex-end; +} diff --git a/docs/.vuepress/styles/palette.scss b/docs/.vuepress/styles/palette.scss new file mode 100644 index 00000000..d271cb05 --- /dev/null +++ b/docs/.vuepress/styles/palette.scss @@ -0,0 +1 @@ +// you can change colors here diff --git a/docs/.vuepress/theme.ts b/docs/.vuepress/theme.ts deleted file mode 100644 index 5686d1af..00000000 --- a/docs/.vuepress/theme.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { hopeTheme } from "vuepress-theme-hope"; -import sidebar from "./sidebar.js"; - -export default hopeTheme({ - hostname: "https://github.com/psqlpy-python/psqlpy", - - iconAssets: "fontawesome-with-brands", - - logo: "./logo.png", - - repo: "psqlpy-python/psqlpy", - - docsDir: "src", - - // sidebar - sidebar, - - footer: "MIT Licensed | Copyright© 2024", - - displayFooter: true, - - encrypt: { - config: { - "/demo/encrypt.html": ["1234"], - }, - }, - - metaLocales: { - editLink: "Edit this page on GitHub", - }, - - plugins: { - // You should generate and use your own comment service - // comment: { - // provider: "Giscus", - // repo: "vuepress-theme-hope/giscus-discussions", - // repoId: "R_kgDOG_Pt2A", - // category: "Announcements", - // categoryId: "DIC_kwDOG_Pt2M4COD69", - // }, - - components: { - components: ["Badge", "VPCard"], - }, - - // All features are enabled for demo, only preserve features you need here - mdEnhance: { - align: true, - attrs: true, - codetabs: true, - component: true, - demo: true, - figure: true, - imgLazyload: true, - imgSize: true, - include: true, - mark: true, - chart: true, - stylize: [ - { - matcher: "Recommended", - replacer: ({ tag }) => { - if (tag === "em") - return { - tag: "Badge", - attrs: { type: "tip" }, - content: "Recommended", - }; - }, - }, - ], - sub: true, - sup: true, - tabs: true, - vPre: true, - - // install chart.js before enabling it - // chart: true, - - // insert component easily - - // install echarts before enabling it - // echarts: true, - - // install flowchart.ts before enabling it - // flowchart: true, - - // gfm requires mathjax-full to provide tex support - // gfm: true, - - // install katex before enabling it - // katex: true, - - // install mathjax-full before enabling it - // mathjax: true, - - // install mermaid before enabling it - mermaid: true, - - // playground: { - // presets: ["ts", "vue"], - // }, - - // install reveal.js before enabling it - // revealJs: { - // plugins: ["highlight", "math", "search", "notes", "zoom"], - // }, - - // install @vue/repl before enabling it - // vuePlayground: true, - - // install sandpack-vue3 before enabling it - // sandpack: true, - }, - - // install @vuepress/plugin-pwa and uncomment these if you want a PWA - // pwa: { - // favicon: "/favicon.ico", - // cacheHTML: true, - // cachePic: true, - // appendBase: true, - // apple: { - // icon: "/assets/icon/apple-icon-152.png", - // statusBarColor: "black", - // }, - // msTile: { - // image: "/assets/icon/ms-icon-144.png", - // color: "#ffffff", - // }, - // manifest: { - // icons: [ - // { - // src: "/assets/icon/chrome-mask-512.png", - // sizes: "512x512", - // purpose: "maskable", - // type: "image/png", - // }, - // { - // src: "/assets/icon/chrome-mask-192.png", - // sizes: "192x192", - // purpose: "maskable", - // type: "image/png", - // }, - // { - // src: "/assets/icon/chrome-512.png", - // sizes: "512x512", - // type: "image/png", - // }, - // { - // src: "/assets/icon/chrome-192.png", - // sizes: "192x192", - // type: "image/png", - // }, - // ], - // shortcuts: [ - // { - // name: "Demo", - // short_name: "Demo", - // url: "/demo/", - // icons: [ - // { - // src: "/assets/icon/guide-maskable.png", - // sizes: "192x192", - // purpose: "maskable", - // type: "image/png", - // }, - // ], - // }, - // ], - // }, - // }, - }, -}); diff --git a/docs/README.md b/docs/README.md index d2dece04..00c1b642 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,10 +28,9 @@ highlights: details: PSQLPy is under active development. --- ## What is PSQLPy -`PSQLPy` is a new Python driver for `PostgreSQL` fully written in Rust. It was inspired by `Psycopg3` and `AsyncPG`. +`PSQLPy` is a Python driver for `PostgreSQL` fully written in Rust. It was inspired by `Psycopg3` and `AsyncPG`. This project has two main goals: -Make a interaction with the database as fast as possible and now `PSQLPy` shows itself to be times faster than the above drivers. -Don't make useless abstractions and make it like a mirror to `PostgreSQL`. +We found that communication with the database can be faster and safer, so we tried to implement a new PostgreSQL driver in Rust for Python. It has all necessary components to create high-load and fault tolerance applications. @@ -59,4 +58,5 @@ pip install git+https://github.com/psqlpy-python/psqlpy ## Join community! You can get support from the creators and users of `PSQLPy` in some social media: -- [Telegram](https://t.me/+f3Y8mYKgXxhmYThi) \ No newline at end of file +- [Telegram](https://t.me/+f3Y8mYKgXxhmYThi) +- [Discord](https://discord.gg/ugNhzmhZ) diff --git a/docs/benchmarks.md b/docs/benchmarks.md index b850e67d..061f09ad 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -27,7 +27,7 @@ However, if you have application and database located on different machines, you ## Local Database ::: tabs @tab Simple Connection Select -::: chart Simple Connection Select +::: chartjs Simple Connection Select ```json { @@ -80,7 +80,7 @@ However, if you have application and database located on different machines, you } ``` @tab Hard Connection Select -::: chart Hard Connection Select +::: chartjs Hard Connection Select ```json { @@ -133,7 +133,7 @@ However, if you have application and database located on different machines, you } ``` @tab Combined Connection Query -::: chart Combined Connection Query +::: chartjs Combined Connection Query ```json { @@ -186,7 +186,7 @@ However, if you have application and database located on different machines, you } ``` @tab Simple Transaction Select -::: chart Simple Transaction Select +::: chartjs Simple Transaction Select ```json { @@ -239,7 +239,7 @@ However, if you have application and database located on different machines, you } ``` @tab Hard Transaction Select -::: chart Hard Transaction Select +::: chartjs Hard Transaction Select ```json { @@ -292,7 +292,7 @@ However, if you have application and database located on different machines, you } ``` @tab Combined Transaction Query -::: chart Combined Transaction Query +::: chartjs Combined Transaction Query ```json { @@ -349,7 +349,7 @@ However, if you have application and database located on different machines, you ## External Database ::: tabs @tab Simple Connection Select -::: chart Simple Connection Select +::: chartjs Simple Connection Select ```json { @@ -403,7 +403,7 @@ However, if you have application and database located on different machines, you ``` @tab Hard Connection Select -::: chart Hard Connection Select +::: chartjs Hard Connection Select ```json { @@ -457,7 +457,7 @@ However, if you have application and database located on different machines, you ``` @tab Combined Connection Query -::: chart Combined Connection Query +::: chartjs Combined Connection Query ```json { @@ -511,7 +511,7 @@ However, if you have application and database located on different machines, you ``` @tab Simple Transaction Select -::: chart Simple Transaction Select +::: chartjs Simple Transaction Select ```json { @@ -565,7 +565,7 @@ However, if you have application and database located on different machines, you ``` @tab Hard Transaction Select -::: chart Hard Transaction Select +::: chartjs Hard Transaction Select ```json { @@ -619,7 +619,7 @@ However, if you have application and database located on different machines, you ``` @tab Combined Transaction Query -::: chart Combined Transaction Query +::: chartjs Combined Transaction Query ```json { diff --git a/docs/components/components_overview.md b/docs/components/components_overview.md index 90b05b70..14a5d5d4 100644 --- a/docs/components/components_overview.md +++ b/docs/components/components_overview.md @@ -5,11 +5,11 @@ title: Components ## Components - `ConnectionPool`: holds connections in itself and give them when requested. - `ConnectionPoolBuilder`: Chainable builder for `ConnectionPool`, for people who prefer it over big initialization. -- `Connection`: represents single database connection, can be retrieved from `ConnectionPool`. +- `Connection`: represents single database connection, can be retrieved from `ConnectionPool` or created with `connect` method. - `Transaction`: represents database transaction, can be made from `Connection`. -- `Cursor`: represents database cursor, can be made from `Transaction`. +- `Cursor`: represents database cursor, can be made from `Connection`, `Transaction` and `PreparedStatement`. +- `PreparedStatement`: represents PostgreSQL prepared statement. - `Listener`: object to work with [LISTEN](https://www.postgresql.org/docs/current/sql-listen.html)/[NOTIFY](https://www.postgresql.org/docs/current/sql-notify.html) functionality, can be mode from `ConnectionPool`. - `QueryResult`: represents list of results from database. - `SingleQueryResult`: represents single result from the database. - `Exceptions`: we have some custom exceptions. - diff --git a/docs/components/connection.md b/docs/components/connection.md index 7a470b06..180777d2 100644 --- a/docs/components/connection.md +++ b/docs/components/connection.md @@ -20,6 +20,17 @@ async def main() -> None: connection = await db_pool.connection() ``` +@tab single connection +```python +from psqlpy import connect + +async def main() -> None: + db_connection: Final = await connect( + dsn="postgres://postgres:postgres@localhost:5432/postgres", + ) + await db_connection.execute(...) +``` + @tab async context manager ```python from psqlpy import ConnectionPool @@ -83,48 +94,48 @@ async def main() -> None: ) ``` -### Fetch +### Execute Many #### Parameters: - `querystring`: Statement string. -- `parameters`: List of parameters for the statement string. +- `parameters`: List of list of parameters for the statement string. - `prepared`: Prepare statement before execution or not. -The same as the `execute` method, for some people this naming is preferable. +This method supports parameters, each parameter must be marked as `$` in querystring (number starts with 1). +Atomicity is provided, so you don't need to worry about unsuccessful result, because there is a transaction used internally. +This method returns nothing. ```python async def main() -> None: ... connection = await db_pool.connection() - results: QueryResult = await connection.fetch( - "SELECT * FROM users WHERE id = $1 and username = $2", - [100, "Alex"], + await connection.execute_many( + "INSERT INTO users (name, age) VALUES ($1, $2)", + [["boba", 10], ["boba", 20]], ) - - dict_results: list[dict[str, Any]] = results.result() ``` -### Execute Many +### Fetch #### Parameters: - `querystring`: Statement string. -- `parameters`: List of list of parameters for the statement string. +- `parameters`: List of parameters for the statement string. - `prepared`: Prepare statement before execution or not. -This method supports parameters, each parameter must be marked as `$` in querystring (number starts with 1). -Atomicity is provided, so you don't need to worry about unsuccessful result, because there is a transaction used internally. -This method returns nothing. +The same as the `execute` method, for some people this naming is preferable. ```python async def main() -> None: ... connection = await db_pool.connection() - await connection.execute_many( - "INSERT INTO users (name, age) VALUES ($1, $2)", - [["boba", 10], ["boba", 20]], + results: QueryResult = await connection.fetch( + "SELECT * FROM users WHERE id = $1 and username = $2", + [100, "Alex"], ) + + dict_results: list[dict[str, Any]] = results.result() ``` ### Fetch Row @@ -177,17 +188,14 @@ async def main() -> None: ### Transaction -`Connection` is the only object that can be used to build `Transaction` object. - #### Parameters: - `isolation_level`: level of isolation. Default how it is in PostgreSQL. - `read_variant`: configure read variant of the transaction. Default how it is in PostgreSQL. - `deferrable`: configure deferrable of the transaction. Default how it is in PostgreSQL. -- `synchronous_commit`: configure [synchronous_commit](https://postgresqlco.nf/doc/en/param/synchronous_commit/) option for transaction. Default how it is in PostgreSQL. ```python -from psqlpy import IsolationLevel, ReadVariant, SynchronousCommit +from psqlpy import IsolationLevel, ReadVariant async def main() -> None: ... @@ -196,11 +204,48 @@ async def main() -> None: isolation_level=IsolationLevel.Serializable, read_variant=ReadVariant.ReadWrite, deferrable=True, - synchronous_commit=SynchronousCommit.On, ) ``` -### Back To Pool +### Cursor +Create new server-side cursor + +#### Parameters +- `querystring`: querystring for cursor. +- `parameters`: parameters for querystring. +- `fetch_number`: default value for fetch number, can be changed. + +```python +async def main() -> None: + ... + connection = await db_pool.connection() + cursor = connection.cursor( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + fetch_number=5, + ) +``` + +### Prepare +Prepare statement and return new instance. + +#### Parameters: +- `querystring`: querystring for statement. +- `parameters`: parameters for querystring. + +```python +from psqlpy import IsolationLevel, ReadVariant + +async def main() -> None: + ... + connection = await db_pool.connection() + prepared_stmt = await connection.prepare( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + ) +``` + +### Close Returns connection to the pool. It's crucial to commit all transactions and close all cursor which are made from the connection. Otherwise, this method won't do anything useful. @@ -213,5 +258,5 @@ There is no need in this method if you use async context manager. async def main() -> None: ... connection = await db_pool.connection() - connection.back_to_pool() + connection.close() ``` diff --git a/docs/components/connection_pool.md b/docs/components/connection_pool.md index 514f899d..b731135f 100644 --- a/docs/components/connection_pool.md +++ b/docs/components/connection_pool.md @@ -125,15 +125,15 @@ db_pool: Final = ConnectionPool( ```py from typing import Final -from psqlpy import connect +from psqlpy import connect_pool -db_pool: Final = connect( +db_pool: Final = connect_pool( dsn="postgres://postgres:postgres@localhost:5432/postgres", max_db_pool_size=10, ) ``` -`connect` function has the same parameters as `ConnectionPool`. +`connect_pool` function has the same parameters as `ConnectionPool`. ### Use Connection Pool as context manager ```py diff --git a/docs/components/cursor.md b/docs/components/cursor.md index 58d4e470..f8c2fbd3 100644 --- a/docs/components/cursor.md +++ b/docs/components/cursor.md @@ -2,161 +2,158 @@ title: Cursor --- -`Cursor` objects represents real `Cursor` in the `PostgreSQL`. [PostgreSQL docs](https://www.postgresql.org/docs/current/plpgsql-cursors.html) -It can be built only from `Transaction`. +`Cursor` objects represents server-side `Cursor` in the `PostgreSQL`. [PostgreSQL docs](https://www.postgresql.org/docs/current/plpgsql-cursors.html). +::: important +Cursor always lives inside a transaction. If you don't begin transaction explicitly, it will be opened anyway. +::: ## Cursor Parameters - `querystring`: specify query for cursor. - `parameters`: parameters for the querystring. Default `None` -- `fetch_number`: default fetch number. It is used in `fetch()` method and in async iterator. Default 10 -- `scroll`: is cursor scrollable or not. Default as in `PostgreSQL`. +- `fetch_number`: default fetch number. It is used in `fetch()` method and in async iterator. -## Cursor as async iterator +## Usage -The most common situation is using `Cursor` as async iterator. +Cursor can be used in different ways. +::: tabs +@tab Pre-Initialization ```python from psqlpy import ConnectionPool, QueryResult - async def main() -> None: db_pool = ConnectionPool() - - connection = await db_pool.connection() - transaction = await connection.transaction() - - # Here we fetch 5 results in each iteration. - async with cursor in transaction.cursor( - querystring="SELECT * FROM users WHERE username = $1", - parameters=["Some_Username"], - fetch_number=5, - ): - async for fetched_result in cursor: - dict_result: List[Dict[Any, Any]] = fetched_result.result() - ... # do something with this result. -``` -## Cursor methods - -There are a lot of methods to work with cursor. - -### Start -Declare (create) cursor. - -```python -async def main() -> None: + cursor = connection.cursor( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + fetch_number=10, + ) await cursor.start() ``` -### Close - -Close the cursor - +@tab Post-Initialization ```python -async def main() -> None: - await cursor.close() -``` - -### Fetch - -You can fetch next `N` records from the cursor. -It's possible to specify `N` fetch record with parameter `fetch_number`, otherwise will be used `fetch_number` from the `Cursor` initialization. +from psqlpy import ConnectionPool, QueryResult -```python async def main() -> None: - result: QueryResult = await cursor.fetch( - fetch_number=100, + db_pool = ConnectionPool() + connection = await db_pool.connection() + + cursor = connection.cursor() + await cursor.execute( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], ) + result: QueryResult = await cursor.fetchone() ``` -### Fetch Next - -Just fetch next record from the `Cursor`. - +@tab Async Context Manager ```python -async def main() -> None: - result: QueryResult = await cursor.fetch_next() -``` +from psqlpy import ConnectionPool, QueryResult -### Fetch Prior +async def main() -> None: + db_pool = ConnectionPool() + connection = await db_pool.connection() -Just fetch previous record. + async with connection.cursor( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + array_size=10, + ) as cursor: + result: QueryResult = await cursor.fetchone() +``` +@tab Async Iterator ```python -async def main() -> None: - result: QueryResult = await cursor.fetch_prior() -``` +from psqlpy import ConnectionPool, QueryResult -### Fetch First +async def main() -> None: + db_pool = ConnectionPool() + connection = await db_pool.connection() -Just fetch the first record. + cursor = connection.cursor( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + fetch_number=10, + ) + await cursor.start() -```python -async def main() -> None: - result: QueryResult = await cursor.fetch_first() + async for result in cursor: + print(result) ``` +::: -### Fetch Last +## Cursor attributes +- `array_size`: get and set attribute. Used in async iterator and `fetch_many` method. -Just fetch the last record. +## Cursor methods +### Start +Declare (create) cursor. ```python async def main() -> None: - result: QueryResult = await cursor.fetch_last() + await cursor.start() ``` -### Fetch Absolute +### Close -Just fetch absolute records. -It has `absolute_number` parameter, you must specify it. +Close the cursor ```python async def main() -> None: - result: QueryResult = await cursor.fetch_absolute( - absolute_number=10, - ) + await cursor.close() ``` -### Fetch Relative +### Execute + +Initialize cursor and make it ready for fetching. -Just fetch absolute records. -It has `relative_number` parameter, you must specify it. +::: important +If you initialized cursor with `start` method or via context manager, you don't have to use this method. +::: + +#### Parameters: +- `querystring`: specify query for cursor. +- `parameters`: parameters for the querystring. Default `None` ```python async def main() -> None: - result: QueryResult = await cursor.fetch_relative( - relative_number=10, + await cursor.execute( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], ) + result: QueryResult = await cursor.fetchone() ``` -### Fetch Forward All +### Fetchone -Fetch forward all records in the cursor. +Fetch one result from the cursor. ```python async def main() -> None: - result: QueryResult = await cursor.fetch_forward_all() + result: QueryResult = await cursor.fetchone() ``` -### Fetch Backward +### Fetchmany + +Fetch N results from the cursor. Default is `array_size`. -Just backward records. -It has `backward_count` parameter, you must specify it. +#### Parameters: +- `size`: number of records to fetch. ```python async def main() -> None: - result: QueryResult = await cursor.fetch_backward( - backward_count=10, - ) + result: QueryResult = await cursor.fetchmany(size=10) ``` -### Fetch Backward All +### Fetchall -Fetch backward all records in the cursor. +Fetch all results from the cursor. ```python async def main() -> None: - result: QueryResult = await cursor.fetch_backward_all() + result: QueryResult = await cursor.fetchall() ``` diff --git a/docs/components/exceptions.md b/docs/components/exceptions.md index fd2d86fb..1347b43f 100644 --- a/docs/components/exceptions.md +++ b/docs/components/exceptions.md @@ -7,141 +7,4 @@ They are split into different subclasses for `ConnectionPool`, `Connection`, `Tr You can use them to define code behavior based on exceptions. -## Exceptions dependency: -```mermaid - -stateDiagram-v2 - RustPSQLDriverPyBaseError --> BaseConnectionPoolError - RustPSQLDriverPyBaseError --> BaseConnectionError - RustPSQLDriverPyBaseError --> BaseTransactionError - RustPSQLDriverPyBaseError --> BaseCursorError - RustPSQLDriverPyBaseError --> BaseListenerError - RustPSQLDriverPyBaseError --> RustException - RustPSQLDriverPyBaseError --> RustToPyValueMappingError - RustPSQLDriverPyBaseError --> PyToRustValueMappingError - RustPSQLDriverPyBaseError --> UUIDValueConvertError - RustPSQLDriverPyBaseError --> MacAddrConversionError - - state BaseConnectionPoolError { - [*] --> ConnectionPoolBuildError - [*] --> ConnectionPoolConfigurationError - [*] --> ConnectionPoolExecuteError - } - state BaseConnectionError { - [*] --> ConnectionExecuteError - [*] --> ConnectionClosedError - } - state BaseTransactionError { - [*] --> TransactionBeginError - [*] --> TransactionCommitError - [*] --> TransactionRollbackError - [*] --> TransactionSavepointError - [*] --> TransactionExecuteError - [*] --> TransactionClosedError - } - state BaseCursorError { - [*] --> CursorStartError - [*] --> CursorCloseError - [*] --> CursorFetchError - [*] --> CursorClosedError - } - state BaseListenerError { - [*] --> ListenerStartError - [*] --> ListenerClosedError - [*] --> ListenerCallbackError - } - state RustException { - [*] --> DriverError - [*] --> MacAddrParseError - [*] --> RuntimeJoinError - } -``` - -## Exceptions: -### RustPSQLDriverPyBaseError -Main bas exception for all errors. - -### RustToPyValueMappingError -Error if it is not possible to covert rust type to python. - -You can get it if you database contains data type that it not supported by this library. - -### PyToRustValueMappingError -Error if it is not possible to covert python type to rust. - -You can get this exception when executing queries with parameters. So, if there are no parameters for the query, don't handle this error. - -### UUIDValueConvertError -Error if it's impossible to convert py string UUID into rust UUID. - -### MacAddrConversionError -Error if cannot convert MacAddr string value to rust type. - -### BaseConnectionPoolError -Base error for all Connection Pool errors. - -#### ConnectionPoolBuildError -Error for errors in building connection pool. - -#### ConnectionPoolConfigurationError -Error in connection pool configuration. - -#### ConnectionPoolExecuteError -Error in connection pool execution. - -### BaseConnectionError -Base error for Connection errors. - -#### ConnectionExecuteError -Error in connection execution. - -#### ConnectionClosedError -Error if underlying connection is closed. - -### BaseTransactionError -Base error for all transaction errors. - -#### TransactionBeginError -Error in transaction begin. - -#### TransactionCommitError -Error in transaction commit. - -#### TransactionRollbackError -Error in transaction rollback. - -#### TransactionSavepointError -Error in transaction savepoint. - -#### TransactionExecuteError -Error in transaction execution. - -#### TransactionClosedError -Error if underlying connection is closed. - -### BaseCursorError -Base error for Cursor errors. - -#### CursorStartError -Error in cursor declare. - -#### CursorCloseError -Error in cursor close. - -#### CursorFetchError -Error in cursor fetch (any fetch). - -#### CursorClosedError -Error if underlying connection is closed. - -### BaseListenerError -Base error for all Listener errors. - -#### ListenerStartError -Error if listener start failed. - -#### ListenerClosedError -Error if listener manipulated but it's closed - -#### ListenerCallbackError -Error if callback passed to listener isn't a coroutine +All exceptions described [here](https://github.com/psqlpy-python/psqlpy/blob/main/python/psqlpy/_internal/exceptions.pyi) diff --git a/docs/components/prepared_statement.md b/docs/components/prepared_statement.md new file mode 100644 index 00000000..ae38f682 --- /dev/null +++ b/docs/components/prepared_statement.md @@ -0,0 +1,78 @@ +--- +title: Prepared Statement +--- + +Representation of PostgreSQL PreparedStatement. + +## Usage + +::: tabs + +@tab Execute +```python +from psqlpy import ConnectionPool, QueryResult + +db_pool: Final = ConnectionPool( + dsn="postgres://postgres:postgres@localhost:5432/postgres", +) + +async def main() -> None: + connection = await db_pool.connection() + prepared_stmt = await connection.prepare( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + ) + + result: QueryResult = await prepared_stmt.execute() +``` + +@tab Cursor +```python +from psqlpy import ConnectionPool, Cursor, PreparedStatement + +db_pool: Final = ConnectionPool( + dsn="postgres://postgres:postgres@localhost:5432/postgres", +) + +async def main() -> None: + connection = await db_pool.connection() + prepared_stmt: PreparedStatement = await connection.prepare( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + ) + + cursor: Cursor = prepared_stmt.cursor() +``` +::: + +## PreparedStatement methods + +### Execute + +Just execute prepared statement. + +```python +async def main() -> None: + connection = await db_pool.connection() + prepared_stmt = await connection.prepare( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + ) + + result: QueryResult = await prepared_stmt.execute() +``` + +### Cursor + +Create new Cursor instance from the PreparedStatement. + +```python +async def main() -> None: + connection = await db_pool.connection() + prepared_stmt = await connection.prepare( + querystring="SELECT * FROM users WHERE id > $1", + parameters=[100], + ) + + result: QueryResult = await prepared_stmt.execute() +``` \ No newline at end of file diff --git a/docs/components/transaction.md b/docs/components/transaction.md index 1bed17e4..8f18a097 100644 --- a/docs/components/transaction.md +++ b/docs/components/transaction.md @@ -407,8 +407,6 @@ async def main() -> None: - `querystring`: Statement string. - `parameters`: List of list of parameters for the statement string. - `fetch_number`: rewrite default fetch_number. Default is 10. -- `scroll`: make cursor scrollable or not. Default is like in `PostgreSQL`. -- `prepared`: prepare querystring or not. From `Transaction` you can create new `Cursor` object which represents cursor in the `PostgreSQL`. [PostgreSQL Docs](https://www.postgresql.org/docs/current/plpgsql-cursors.html) diff --git a/docs/introduction/introduction.md b/docs/introduction/introduction.md index 545eb700..27f142d9 100644 --- a/docs/introduction/introduction.md +++ b/docs/introduction/introduction.md @@ -5,15 +5,14 @@ title: What is PSQLPy? `PSQLPy` is a new Python driver for PostgreSQL fully written in Rust. It was inspired by `Psycopg3` and `AsyncPG`. With `PSQLPy` you can: -- Make an interaction with the PostgeSQL in your application much faster (2-3 times). +- Make an interaction with the PostgeSQL in your application faster. - Be sure that there won't be any unexpected errors. -- Don't usually go to the documentation to search every question - we have awesome docstrings for every component. +- Don't usually go to the documentation to search every question - we have docstrings for every component. - Use `MyPy` (or any other Python type checker) with confidence that exactly the types specified in the typing will be returned. - Concentrate on writing your code, not understanding new abstractions in this library, we only have classes which represents PostgreSQL object (transaction, cursor, etc). ::: info -It is extremely important to understand that the library will provide a noticeable acceleration in working with the database only if your queries are optimized. -Otherwise, there will be acceleration, but not so significant +The library will provide a noticeable acceleration in working with the database only if your queries are optimized. ::: ## Important notes @@ -22,4 +21,5 @@ But in some situations this behavior can break you application. As an example, i ## Join community! You can get support from the creators of `PSQLPy` in some social media: -- [Telegram](https://t.me/+f3Y8mYKgXxhmYThi) \ No newline at end of file +- [Telegram](https://t.me/+f3Y8mYKgXxhmYThi) +- [Discord](https://discord.gg/ugNhzmhZ) diff --git a/package.json b/package.json index 0af7b856..14193ae6 100644 --- a/package.json +++ b/package.json @@ -5,21 +5,32 @@ "license": "MIT", "private": false, "scripts": { - "docs:dev": "vuepress dev docs --clean-cache", - "docs:build": "vuepress build docs", - "docs:serve": "vuepress serve docs" + "docs:dev": "vuepress-vite dev docs", + "docs:build": "vuepress-vite build docs", + "docs:serve": "vuepress serve docs", + "docs:clean-dev": "vuepress-vite dev docs --clean-cache", + "docs:update-package": "pnpm dlx vp-update" }, "packageManager": "pnpm@7.22.0", "devDependencies": { - "@vuepress/bundler-vite": "2.0.0-rc.9", - "mermaid": "^10.8.0", - "sass-loader": "^14.1.0", - "vue": "^3.4.15", - "vuepress": "2.0.0-rc.9", - "vuepress-plugin-search-pro": "2.0.0-rc.36", - "vuepress-theme-hope": "2.0.0-rc.36" + "@vuepress/bundler-vite": "2.0.0-rc.23", + "@vuepress/plugin-markdown-tab": "2.0.0-rc.47", + "@vuepress/plugin-slimsearch": "2.0.0-rc.106", + "mermaid": "^11.6.0", + "sass": "^1.89.0", + "sass-embedded": "^1.88.0", + "sass-loader": "^16.0.5", + "vue": "^3.5.13", + "vuepress": "2.0.0-rc.23", + "vuepress-plugin-md-enhance": "2.0.0-rc.88", + "vuepress-theme-hope": "2.0.0-rc.88" }, "dependencies": { - "chart.js": "^4.4.3" + "chart.js": "^4.4.9" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild" + ] } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80c92f84..1f1b31e4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,529 +4,625 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +onlyBuiltDependencies: + - esbuild + dependencies: chart.js: - specifier: ^4.4.3 - version: 4.4.3 + specifier: ^4.4.9 + version: 4.4.9 devDependencies: '@vuepress/bundler-vite': - specifier: 2.0.0-rc.9 - version: 2.0.0-rc.9 + specifier: 2.0.0-rc.23 + version: 2.0.0-rc.23(sass-embedded@1.89.0)(sass@1.89.0) + '@vuepress/plugin-markdown-tab': + specifier: 2.0.0-rc.47 + version: 2.0.0-rc.47(markdown-it@14.1.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-slimsearch': + specifier: 2.0.0-rc.106 + version: 2.0.0-rc.106(vuepress@2.0.0-rc.23) mermaid: - specifier: ^10.8.0 - version: 10.9.1 + specifier: ^11.6.0 + version: 11.6.0 + sass: + specifier: ^1.89.0 + version: 1.89.0 + sass-embedded: + specifier: ^1.88.0 + version: 1.89.0 sass-loader: - specifier: ^14.1.0 - version: 14.2.1 + specifier: ^16.0.5 + version: 16.0.5(sass-embedded@1.89.0)(sass@1.89.0) vue: - specifier: ^3.4.15 - version: 3.4.30 + specifier: ^3.5.13 + version: 3.5.15 vuepress: - specifier: 2.0.0-rc.9 - version: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) - vuepress-plugin-search-pro: - specifier: 2.0.0-rc.36 - version: 2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) + specifier: 2.0.0-rc.23 + version: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + vuepress-plugin-md-enhance: + specifier: 2.0.0-rc.88 + version: 2.0.0-rc.88(chart.js@4.4.9)(markdown-it@14.1.0)(mermaid@11.6.0)(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23) vuepress-theme-hope: - specifier: 2.0.0-rc.36 - version: 2.0.0-rc.36(chart.js@4.4.3)(markdown-it@14.1.0)(mermaid@10.9.1)(sass-loader@14.2.1)(vuepress-plugin-search-pro@2.0.0-rc.36)(vuepress@2.0.0-rc.9) + specifier: 2.0.0-rc.88 + version: 2.0.0-rc.88(@vuepress/plugin-slimsearch@2.0.0-rc.106)(chart.js@4.4.9)(markdown-it@14.1.0)(mermaid@11.6.0)(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23) packages: - /@babel/helper-string-parser@7.24.7: - resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} + /@antfu/install-pkg@1.1.0: + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + dependencies: + package-manager-detector: 1.3.0 + tinyexec: 1.0.1 + dev: true + + /@antfu/utils@8.1.1: + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} + dev: true + + /@babel/helper-string-parser@7.27.1: + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-identifier@7.24.7: - resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + /@babel/helper-validator-identifier@7.27.1: + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} dev: true - /@babel/parser@7.24.7: - resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} + /@babel/parser@7.27.2: + resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.27.1 dev: true - /@babel/types@7.24.7: - resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} + /@babel/types@7.27.1: + resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - to-fast-properties: 2.0.0 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 dev: true - /@braintree/sanitize-url@6.0.4: - resolution: {integrity: sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==} + /@braintree/sanitize-url@7.1.1: + resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} dev: true - /@esbuild/aix-ppc64@0.20.2: - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} - engines: {node: '>=12'} + /@bufbuild/protobuf@2.5.0: + resolution: {integrity: sha512-nniMblXT+dNyubek2OLKAYJnG/in4tmfS2c5CDnIvqfF9kFlERSG3FCBvmdqerpkWuPv0qhdGKReQ2OqKPG20w==} + dev: true + + /@chevrotain/cst-dts-gen@11.0.3: + resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} + dependencies: + '@chevrotain/gast': 11.0.3 + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + dev: true + + /@chevrotain/gast@11.0.3: + resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} + dependencies: + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + dev: true + + /@chevrotain/regexp-to-ast@11.0.3: + resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} + dev: true + + /@chevrotain/types@11.0.3: + resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} + dev: true + + /@chevrotain/utils@11.0.3: + resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + dev: true + + /@esbuild/aix-ppc64@0.25.4: + resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - requiresBuild: true dev: true optional: true - /@esbuild/android-arm64@0.20.2: - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} - engines: {node: '>=12'} + /@esbuild/android-arm64@0.25.4: + resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - requiresBuild: true dev: true optional: true - /@esbuild/android-arm@0.20.2: - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} - engines: {node: '>=12'} + /@esbuild/android-arm@0.25.4: + resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} + engines: {node: '>=18'} cpu: [arm] os: [android] - requiresBuild: true dev: true optional: true - /@esbuild/android-x64@0.20.2: - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} - engines: {node: '>=12'} + /@esbuild/android-x64@0.25.4: + resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} + engines: {node: '>=18'} cpu: [x64] os: [android] - requiresBuild: true dev: true optional: true - /@esbuild/darwin-arm64@0.20.2: - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} - engines: {node: '>=12'} + /@esbuild/darwin-arm64@0.25.4: + resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - requiresBuild: true dev: true optional: true - /@esbuild/darwin-x64@0.20.2: - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} - engines: {node: '>=12'} + /@esbuild/darwin-x64@0.25.4: + resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - requiresBuild: true dev: true optional: true - /@esbuild/freebsd-arm64@0.20.2: - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} - engines: {node: '>=12'} + /@esbuild/freebsd-arm64@0.25.4: + resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - requiresBuild: true dev: true optional: true - /@esbuild/freebsd-x64@0.20.2: - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} - engines: {node: '>=12'} + /@esbuild/freebsd-x64@0.25.4: + resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - requiresBuild: true dev: true optional: true - /@esbuild/linux-arm64@0.20.2: - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} - engines: {node: '>=12'} + /@esbuild/linux-arm64@0.25.4: + resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/linux-arm@0.20.2: - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} - engines: {node: '>=12'} + /@esbuild/linux-arm@0.25.4: + resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/linux-ia32@0.20.2: - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} - engines: {node: '>=12'} + /@esbuild/linux-ia32@0.25.4: + resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/linux-loong64@0.20.2: - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} - engines: {node: '>=12'} + /@esbuild/linux-loong64@0.25.4: + resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/linux-mips64el@0.20.2: - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} - engines: {node: '>=12'} + /@esbuild/linux-mips64el@0.25.4: + resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/linux-ppc64@0.20.2: - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} - engines: {node: '>=12'} + /@esbuild/linux-ppc64@0.25.4: + resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/linux-riscv64@0.20.2: - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} - engines: {node: '>=12'} + /@esbuild/linux-riscv64@0.25.4: + resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/linux-s390x@0.20.2: - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} - engines: {node: '>=12'} + /@esbuild/linux-s390x@0.25.4: + resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/linux-x64@0.20.2: - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} - engines: {node: '>=12'} + /@esbuild/linux-x64@0.25.4: + resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true - /@esbuild/netbsd-x64@0.20.2: - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} - engines: {node: '>=12'} + /@esbuild/netbsd-arm64@0.25.4: + resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + dev: true + optional: true + + /@esbuild/netbsd-x64@0.25.4: + resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - requiresBuild: true dev: true optional: true - /@esbuild/openbsd-x64@0.20.2: - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} - engines: {node: '>=12'} + /@esbuild/openbsd-arm64@0.25.4: + resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + dev: true + optional: true + + /@esbuild/openbsd-x64@0.25.4: + resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - requiresBuild: true dev: true optional: true - /@esbuild/sunos-x64@0.20.2: - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} - engines: {node: '>=12'} + /@esbuild/sunos-x64@0.25.4: + resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - requiresBuild: true dev: true optional: true - /@esbuild/win32-arm64@0.20.2: - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} - engines: {node: '>=12'} + /@esbuild/win32-arm64@0.25.4: + resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - requiresBuild: true dev: true optional: true - /@esbuild/win32-ia32@0.20.2: - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} - engines: {node: '>=12'} + /@esbuild/win32-ia32@0.25.4: + resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - requiresBuild: true dev: true optional: true - /@esbuild/win32-x64@0.20.2: - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} - engines: {node: '>=12'} + /@esbuild/win32-x64@0.25.4: + resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} + engines: {node: '>=18'} cpu: [x64] os: [win32] - requiresBuild: true dev: true optional: true - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + /@iconify/types@2.0.0: + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + dev: true + + /@iconify/utils@2.3.0: + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + dependencies: + '@antfu/install-pkg': 1.1.0 + '@antfu/utils': 8.1.1 + '@iconify/types': 2.0.0 + debug: 4.4.1 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.1.1 + mlly: 1.7.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@jridgewell/sourcemap-codec@1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} dev: true - /@kurkle/color@0.3.2: - resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} + /@kurkle/color@0.3.4: + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} - /@lit-labs/ssr-dom-shim@1.2.0: - resolution: {integrity: sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==} + /@lit-labs/ssr-dom-shim@1.3.0: + resolution: {integrity: sha512-nQIWonJ6eFAvUUrSlwyHDm/aE8PBDu5kRpL0vHMg6K8fK3Diq1xdPjTnsJSwxABhaZ+5eBi1btQB5ShUTKo4nQ==} dev: true - /@lit/reactive-element@2.0.4: - resolution: {integrity: sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==} + /@lit/reactive-element@2.1.0: + resolution: {integrity: sha512-L2qyoZSQClcBmq0qajBVbhYEcG6iK0XfLn66ifLe/RfC0/ihpc+pl0Wdn8bJ8o+hj38cG0fGXRgSS20MuXn7qA==} dependencies: - '@lit-labs/ssr-dom-shim': 1.2.0 + '@lit-labs/ssr-dom-shim': 1.3.0 dev: true - /@mdit-vue/plugin-component@2.1.3: - resolution: {integrity: sha512-9AG17beCgpEw/4ldo/M6Y/1Rh4E1bqMmr/rCkWKmCAxy9tJz3lzY7HQJanyHMJufwsb3WL5Lp7Om/aPcQTZ9SA==} + /@mdit-vue/plugin-component@2.1.4: + resolution: {integrity: sha512-fiLbwcaE6gZE4c8Mkdkc4X38ltXh/EdnuPE1hepFT2dLiW6I4X8ho2Wq7nhYuT8RmV4OKlCFENwCuXlKcpV/sw==} dependencies: - '@types/markdown-it': 14.1.1 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit-vue/plugin-frontmatter@2.1.3: - resolution: {integrity: sha512-KxsSCUVBEmn6sJcchSTiI5v9bWaoRxe68RBYRDGcSEY1GTnfQ5gQPMIsM48P4q1luLEIWurVGGrRu7u93//LDQ==} + /@mdit-vue/plugin-frontmatter@2.1.4: + resolution: {integrity: sha512-mOlavV176njnozIf0UZGFYymmQ2LK5S1rjrbJ1uGz4Df59tu0DQntdE7YZXqmJJA9MiSx7ViCTUQCNPKg7R8Ow==} dependencies: - '@mdit-vue/types': 2.1.0 - '@types/markdown-it': 14.1.1 + '@mdit-vue/types': 2.1.4 + '@types/markdown-it': 14.1.2 gray-matter: 4.0.3 markdown-it: 14.1.0 dev: true - /@mdit-vue/plugin-headers@2.1.3: - resolution: {integrity: sha512-AcL7a7LHQR3ISINhfjGJNE/bHyM0dcl6MYm1Sr//zF7ZgokPGwD/HhD7TzwmrKA9YNYCcO9P3QmF/RN9XyA6CA==} + /@mdit-vue/plugin-headers@2.1.4: + resolution: {integrity: sha512-tyZwGZu2mYkNSqigFP1CK3aZYxuYwrqcrIh8ljd8tfD1UDPJkAbQeayq62U572po2IuWVB1BqIG8JIXp5POOTA==} dependencies: - '@mdit-vue/shared': 2.1.3 - '@mdit-vue/types': 2.1.0 - '@types/markdown-it': 14.1.1 + '@mdit-vue/shared': 2.1.4 + '@mdit-vue/types': 2.1.4 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit-vue/plugin-sfc@2.1.3: - resolution: {integrity: sha512-Ezl0dNvQNS639Yl4siXm+cnWtQvlqHrg+u+lnau/OHpj9Xh3LVap/BSQVugKIV37eR13jXXYf3VaAOP1fXPN+w==} + /@mdit-vue/plugin-sfc@2.1.4: + resolution: {integrity: sha512-oqAlMulkz280xUJIkormzp6Ps0x5WULZrwRivylWJWDEyVAFCj5VgR3Dx6CP2jdgyuPXwW3+gh2Kzw+Xe+kEIQ==} dependencies: - '@mdit-vue/types': 2.1.0 - '@types/markdown-it': 14.1.1 + '@mdit-vue/types': 2.1.4 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit-vue/plugin-title@2.1.3: - resolution: {integrity: sha512-XWVOQoZqczoN97xCDrnQicmXKoqwOjIymIm9HQnRXhHnYKOgJPW1CxSGhkcOGzvDU1v0mD/adojVyyj/s6ggWw==} + /@mdit-vue/plugin-title@2.1.4: + resolution: {integrity: sha512-uuF24gJvvLVIWG/VBtCDRqMndfd5JzOXoBoHPdKKLk3PA4P84dsB0u0NnnBUEl/YBOumdCotasn7OfFMmco9uQ==} dependencies: - '@mdit-vue/shared': 2.1.3 - '@mdit-vue/types': 2.1.0 - '@types/markdown-it': 14.1.1 + '@mdit-vue/shared': 2.1.4 + '@mdit-vue/types': 2.1.4 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit-vue/plugin-toc@2.1.3: - resolution: {integrity: sha512-41Q+iXpLHZt0zJdApVwoVt7WF6za/xUjtjEPf90Z3KLzQO01TXsv48Xp9BsrFHPcPcm8tiZ0+O1/ICJO80V/MQ==} + /@mdit-vue/plugin-toc@2.1.4: + resolution: {integrity: sha512-vvOU7u6aNmvPwKXzmoHion1sv4zChBp20LDpSHlRlXc3btLwdYIA0DR+UiO5YeyLUAO0XSHQKBpsIWi57K9/3w==} dependencies: - '@mdit-vue/shared': 2.1.3 - '@mdit-vue/types': 2.1.0 - '@types/markdown-it': 14.1.1 + '@mdit-vue/shared': 2.1.4 + '@mdit-vue/types': 2.1.4 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit-vue/shared@2.1.3: - resolution: {integrity: sha512-27YI8b0VVZsAlNwaWoaOCWbr4eL8B04HxiYk/y2ktblO/nMcOEOLt4p0RjuobvdyUyjHvGOS09RKhq7qHm1CHQ==} + /@mdit-vue/shared@2.1.4: + resolution: {integrity: sha512-Axd8g2iKQTMuHcPXZH5JY3hbSMeLyoeu0ftdgMrjuPzHpJnWiPSAnA0dAx5NQFQqZkXHhyIrAssLSrOWjFmPKg==} dependencies: - '@mdit-vue/types': 2.1.0 - '@types/markdown-it': 14.1.1 + '@mdit-vue/types': 2.1.4 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit-vue/types@2.1.0: - resolution: {integrity: sha512-TMBB/BQWVvwtpBdWD75rkZx4ZphQ6MN0O4QB2Bc0oI5PC2uE57QerhNxdRZ7cvBHE2iY2C+BUNUziCfJbjIRRA==} + /@mdit-vue/types@2.1.4: + resolution: {integrity: sha512-QiGNZslz+zXUs2X8D11UQhB4KAMZ0DZghvYxa7+1B+VMLcDtz//XHpWbcuexjzE3kBXSxIUTPH3eSQCa0puZHA==} + dev: true + + /@mdit/helper@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-/4w+hKHmJUutRhmwX8w7dpYW4lgaNXW055m/x+apvemLGlDoRd3VZbAR5Gt0zWdkE0l4b5FWqbydiig9Sgj5gQ==} + engines: {node: '>= 18'} + peerDependencies: + markdown-it: ^14.1.0 + peerDependenciesMeta: + markdown-it: + optional: true + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 dev: true - /@mdit/plugin-alert@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-mxA/lhOyDDR6/qSAegGG/XZRjUbr1wjwdULudbpkA/CCQi6piW9D0Z8crDQGYz4KPQM9Bgx4Ac81QFSzHOV66Q==} + /@mdit/plugin-alert@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-nm6BJPZG6ux6hTUGstKEDL14AWwMTxTU7mxZFKUVqC/qDgCgmzeoFINE4N+4mrDKAnAF5uF5APfIZCh481PnaQ==} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-align@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-OJPYzSdmT0UZj/QTvnKYE4GelAL0OD8bNIPxpidXbFd3IqYv/8+xMjT6XeR+R3oZEvtbYSc2e1MmO5fo3DopJA==} + /@mdit/plugin-align@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-93znJvVPOx1NY88Q1GLDSsPa272CPlXwrHTLiuWgBfKwbFQ016KKtrI5AyUgpA//BGv9QiTgYZI+mUR6MKdBgg==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@mdit/plugin-container': 0.8.0(markdown-it@14.1.0) - '@types/markdown-it': 13.0.8 + '@mdit/plugin-container': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-attrs@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-ewmx5i+b3M4CRJNDpDNBA0YTHa1snn+adDsDDpDtPPSzCH1NhtWXdzwI0TrcCQUnueeSEEWX/wY4ESo+NRkBNQ==} + /@mdit/plugin-attrs@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-WyjzLxKYuJYgcw9ydhVRzbcGLQ7h6CFZmoXZvou/K7fIJVF0XcAJ03uKPIRqp9F44qr+n3mzj0hUc4CnUMZtsQ==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@mdit/helper': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-container@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-uWK3t0CWssintcmT5PTJVhAwbstcD+SrtijQKs6BhLRtGGgHJ9mOf0ybGjlJhn4077yFFTHmaCIT3K+n5ZVjPg==} + /@mdit/plugin-container@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-lNXFxhgPU44UmrElp5oRUGUYx4q0Nkta6BYDC7tYIzqk3BBJLccBMv2iI0Hejz+LFTRytyMUBAuxh/F+i1DsGw==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-demo@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-yFRXnp3Lj0g4H9ImzHKQwwgtSykrL/BDNEQzql9fdA9FbSygfu0CIxfm+A8lsVos8cAvdsgxy3gILySxpfR89g==} + /@mdit/plugin-demo@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-oWrADUZmkFm0YTFKg8NT/YRDekL5I+xreryiwyFldVo7WyXDUxLJ7ae4TLHwU4KV2heCm3A1jTtPNORzQewUmA==} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-figure@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-/o4RoKjnkdWc+K7m6mR7BAu2J79yYE38s8HUc8iKk9v+e9j1E+6LeXcpx1LoPnHzUhT4EO2QmUsv+kAaPFfZYw==} + /@mdit/plugin-figure@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-LRSNtPDZJbCPtiMOEcSS2pPL9rN2s//MWlL5lvc/EF1XlB/ZMO7Huj9dqQZ/I34vNR+TlZtwt1WifAh2GSKZBw==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-footnote@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-AaX1rfkJwq9vLX+H/a+XQ3ZxahOXrnMLr5dVZfNdazjqdDEJ7Cc/A7UFtLfOM19F2w3EgvcHR1gbINxIVDn/eg==} + /@mdit/plugin-footnote@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-Qr99rLRBEAmcFo2rPtmdpZNrTK4cVH4cwSutLu2v1fWxsXP6Hfks1O8cmkRGKbcsBE2mqh1r3yo0w178zDO/cQ==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + dev: true + + /@mdit/plugin-icon@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-w7RA1vqP/ZumkKLSRGDm5D7bXFJJkD+VBtAurgR4J/slATcZWAmAGBUC/dq2tp1UueNGg0kJfrKvcqQMdxXqTA==} + peerDependencies: + markdown-it: ^14.1.0 + peerDependenciesMeta: + markdown-it: + optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@mdit/helper': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-img-lazyload@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-Rrlf2FzOxxyszbv3DpkIwEgmYKmtwHdxIO+Whkn0a9QckxnEKkaGl5KARCnM7LqX2fhEyFLgnfkr3onVOJG54g==} + /@mdit/plugin-img-lazyload@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-X2gbtWTHfW7NdPW2ceQrCnLZ9D/xvY1TTSPa3GBa2+7vR02bL36kRBIXTEyS0anC08R+7FHBN2uJljk8qQ2AJw==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-img-mark@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-4P6z2QOfLHLMSXUP4mB/2Rnd6KeHmJBkUXJWJhybcXoIG5S5FDTFHJxOycSP4eGzfdOYAWSlkx6XwXEUGGZz5w==} + /@mdit/plugin-img-mark@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-dLPOuUUcP/tlOVRTWJYeIhcFLE4DQgFovDE0ojlGZS/nS5YYjZGELujADHL2zUruCe99uJqAbHzTPeQvUsWckw==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-img-size@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-r+LbAizP/hw5SisY44VbHEnR7XUKpcHM2k2fwu5wb1+V1crxeigG4sa8rzrJEddU+k6uCl27yL5FTGbHjAl82Q==} + /@mdit/plugin-img-size@0.18.1(markdown-it@14.1.0): + resolution: {integrity: sha512-jomprQOuv2xEe4CDbDA+KmRlxmUhOF5psXvl+sjgNmxR2+So6q7hbPLJVTVV3Z2jK5sXmogOPQz0Wf7h72LNHA==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-include@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-e8Z8q5VkJ6UX04tTgELraupB/MdHio7hkdYT71wBJ6UQuhSmFv/xMOxFfTcGKH5yzsbEM45BtAFHzSXIi3dMCw==} + /@mdit/plugin-include@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-OsxTbORV3ZcmqIebAxV6Rxm9FFykGY1UePLJIffI46JYVZf6Nv6E1ArtHbz5ntr0sEKPifDXQtkmksl2SX9UKA==} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@mdit/helper': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 upath: 2.0.1 dev: true - /@mdit/plugin-katex@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-u7CX3Xv5nuc2bu2sHrk1nil83/9ETKTBMmy0icbW8zlqBC0ykLo1xTCEBXmdhXtnJtPi9f/wUZVs6iMZrJzbNg==} + /@mdit/plugin-katex-slim@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-VQE4UkTIV2Uv7Jzm2EnrvJamjkUXKnzHgpYpdVuLk954kwPTmSkBqGstly9G7C6CL34tqulpyBA2Pq90zHu79Q==} engines: {node: '>= 18'} peerDependencies: katex: ^0.16.9 - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: katex: optional: true markdown-it: optional: true dependencies: - '@mdit/plugin-tex': 0.8.0(markdown-it@14.1.0) - '@types/katex': 0.16.7 - '@types/markdown-it': 13.0.8 + '@mdit/helper': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-tex': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-mark@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-1hImu8FskIZ9dumWD2VIyB5USyVGwGY2IuaPxYO25tFvMZkhu4rYBjkSK8x+vXExwp94OLzFUlGgVl94S+nw9w==} + /@mdit/plugin-mark@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-mFEUrNV63z6Os5r5cZzjjdVaU5pz6YdwON8jM71h6HTgaM5EjsXm2c4zyfnUdN24lWz+O6gaYw67inhAFxZGwg==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-mathjax@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-y016KQHa3PoXDUIcQseISMAz5q2mZJ/qocEs2EABT4PjquXPEh/4rw7Ql7KX9gf/SQIUyzj8hYs4bHyRZc6x4w==} + /@mdit/plugin-mathjax-slim@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-U1LU/moBIda1auMPP657w6nL7zNcnw6c+LnuD8Kf/HgfGEBx5mEBO7ReEmrpXu9i6urP78/C0/oVGPrWZDzB8w==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 mathjax-full: ^3.2.2 peerDependenciesMeta: markdown-it: @@ -534,102 +630,150 @@ packages: mathjax-full: optional: true dependencies: - '@mdit/plugin-tex': 0.8.0(markdown-it@14.1.0) - '@types/markdown-it': 13.0.8 + '@mdit/plugin-tex': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 upath: 2.0.1 dev: true - /@mdit/plugin-stylize@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-oNFI3Z7UTxP8CKxS3CIuawLmsyrc0n9jIw9mPzUcPNp+LtYmLktfZc3FIRlqpUUq34YwHTH3yihayBRdSkVV6A==} + /@mdit/plugin-plantuml@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-JZCv706q5yLiGHRD0s/R65hCKBaHOrOgdyQM1d6kkcdakWwyeLJUeBSb+v6fFnbjM2GgGpoeioUMQHlSK/uiTQ==} + peerDependencies: + markdown-it: ^14.1.0 + peerDependenciesMeta: + markdown-it: + optional: true + dependencies: + '@mdit/plugin-uml': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + dev: true + + /@mdit/plugin-spoiler@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-YIJMUBkBme/DuIgH7ZwbpF4/jIRmzaQqdGNowmC5PVMd5OryBulVwDQ4lYKi4qeaS/xxIFe7ssgMpB1XNjA7JA==} + engines: {node: '>= 18'} + peerDependencies: + markdown-it: ^14.1.0 + peerDependenciesMeta: + markdown-it: + optional: true + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + dev: true + + /@mdit/plugin-stylize@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-6pJkvsB+HwN9up9lQo1tXRfoK5nj8u9z+Q7HM9AvWWc42JnsZ4iHgz2LMu5AqjaqfwAXfOLwJ20FZy6OSeHfcQ==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-sub@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-oqCcmJVJykESgNJ4fFmDKKxRRQddwkXWIT4PjF83XSeXHxTOz8gMfke/V1mE7BAfKKCLP4io8HbrYfvIiOTZ4A==} + /@mdit/plugin-sub@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-VqNwTeUjbLP2AZv9WGbGJPY7q32nf24fkFbuXlalzJk5FNArOo4qHCqWmswjBmfGWbtG5ZkrRM0v+f4adRELrQ==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@mdit/helper': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-sup@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-5/uE2lONNjCgGDXC8jZ265tzefjUNQNakmK4PSCI4D5jD80xFrxc6MKh70VLCOL8Xk6COK/K9f0SAU2lwa97Tg==} + /@mdit/plugin-sup@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-2l5BcRrZfivZi2vwrC/an4K/wZYsgA1k8m4VGgOcDllTKUW8IQHAmievYo7IuAwvY3CwBdqEtc5s0DHlHRFdnQ==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@mdit/helper': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-tab@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-SNa1S14Buuy564egiUTkU9HTTNFrEURJZLqA1+jr/2xYCdICPym0FWcB0cLtBl3lrQZkFtbxhzC6ws5JBt/ERQ==} + /@mdit/plugin-tab@0.13.2(markdown-it@14.1.0): + resolution: {integrity: sha512-evpIXvo6vXRWhgNE6vu4ok1I2dVOzrBYmBUGc1gW8nT9MvkW9litu7RbJ6CafscqaiiYRIM5Oib1ahS0lwte6g==} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-tasklist@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-vfOTZdXIL/jk/ConUqCODI5WuqgB9qiBGc+wIa7UMhe73KcpwFeGFJVQZm9AvjhXDDYqznJxSMVRP/TN7TxVVw==} + /@mdit/plugin-tab@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-nM/cqa8q7x2L6bXkrmePk9IEaSONhxIkgTVsmM4b6PQ3zoXq83SxGR+8vC7AFhiRYAjmtV8psBjy1pyUtY4Syw==} + peerDependencies: + markdown-it: ^14.1.0 + peerDependenciesMeta: + markdown-it: + optional: true + dependencies: + '@mdit/helper': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + dev: true + + /@mdit/plugin-tasklist@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-b1Fwx19Jaugvfp4i/bJQRmoAupNhG8ZGjn+sSAPtji9VyiYaqrfB19cPTImZA2/Z4LFPxMH4ZzwC2kOl/qDy/g==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-tex@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-uh4kOhwBVEESz6dMmHk4Hn/AVfVtUhMA1UKpwMc1EL9qelodJ0YzSYfNXp6d/PS+E1l53yp8nMZK90DUO+3vpA==} + /@mdit/plugin-tex@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-k4xSML1N6gFkCm/zsiRO1eI0IFpi+Nr6WcYs1Y8NojyuIgDUZSrKbIJTwuqIo/TrCUfgUQANpibYskRxQpgZLg==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true - /@mdit/plugin-uml@0.8.0(markdown-it@14.1.0): - resolution: {integrity: sha512-6TOVxLhmdzV7bzjlJCRP5uCFq62Xwk2ZAeYUK3RLx9lgM3s2Mww5ENhdysnQMd7VQlUHsPmp4XIMBZZjPddg3g==} + /@mdit/plugin-uml@0.18.0(markdown-it@14.1.0): + resolution: {integrity: sha512-zT08h34NF40LQcXSDuVvW0hANte6zYotSMMxW/288Ux5BSeY55yHfLrBFs4uRLRa989d0Ib7PcXrRkPN+kxHcA==} engines: {node: '>= 18'} peerDependencies: - markdown-it: ^14.0.0 + markdown-it: ^14.1.0 peerDependenciesMeta: markdown-it: optional: true dependencies: - '@types/markdown-it': 13.0.8 + '@mdit/helper': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true + /@mermaid-js/parser@0.4.0: + resolution: {integrity: sha512-wla8XOWvQAwuqy+gxiZqY+c7FokraOTHRWMsbB4AgRx9Sy7zKslNyejy7E+a77qHfey5GXw/ik3IXv/NHMJgaA==} + dependencies: + langium: 3.3.1 + dev: true + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -648,245 +792,601 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 - dev: true - - /@rollup/rollup-android-arm-eabi@4.18.0: - resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} - cpu: [arm] - os: [android] - requiresBuild: true + fastq: 1.19.1 dev: true - optional: true - /@rollup/rollup-android-arm64@4.18.0: - resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} + /@parcel/watcher-android-arm64@2.5.1: + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [android] - requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.18.0: - resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} + /@parcel/watcher-darwin-arm64@2.5.1: + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [darwin] - requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.18.0: - resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} + /@parcel/watcher-darwin-x64@2.5.1: + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [darwin] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.18.0: - resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} - cpu: [arm] - os: [linux] - requiresBuild: true + /@parcel/watcher-freebsd-x64@2.5.1: + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] dev: true optional: true - /@rollup/rollup-linux-arm-musleabihf@4.18.0: - resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} + /@parcel/watcher-linux-arm-glibc@2.5.1: + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.18.0: - resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} - cpu: [arm64] + /@parcel/watcher-linux-arm-musl@2.5.1: + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.18.0: - resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} + /@parcel/watcher-linux-arm64-glibc@2.5.1: + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-powerpc64le-gnu@4.18.0: - resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-riscv64-gnu@4.18.0: - resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} - cpu: [riscv64] - os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-s390x-gnu@4.18.0: - resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} - cpu: [s390x] + /@parcel/watcher-linux-arm64-musl@2.5.1: + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.18.0: - resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} + /@parcel/watcher-linux-x64-glibc@2.5.1: + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.18.0: - resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} + /@parcel/watcher-linux-x64-musl@2.5.1: + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.18.0: - resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} + /@parcel/watcher-win32-arm64@2.5.1: + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [win32] - requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.18.0: - resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} + /@parcel/watcher-win32-ia32@2.5.1: + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} cpu: [ia32] os: [win32] - requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.18.0: - resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} + /@parcel/watcher-win32-x64@2.5.1: + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [win32] - requiresBuild: true dev: true optional: true - /@sindresorhus/merge-streams@2.3.0: - resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} - engines: {node: '>=18'} + /@parcel/watcher@2.5.1: + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 dev: true + optional: true - /@stackblitz/sdk@1.10.0: - resolution: {integrity: sha512-IcvE9Xifo2c4/f+yNqjFM/OW5VTBPLed3TxsQ+n8n81Py358IqD5w0IYfFgV5gbDjp2g5H5YK2/Shls/kQNTWQ==} + /@pkgr/core@0.2.4: + resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dev: true - /@types/d3-scale-chromatic@3.0.3: - resolution: {integrity: sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==} + /@rollup/rollup-android-arm-eabi@4.41.1: + resolution: {integrity: sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==} + cpu: [arm] + os: [android] dev: true + optional: true - /@types/d3-scale@4.0.8: - resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} - dependencies: - '@types/d3-time': 3.0.3 + /@rollup/rollup-android-arm64@4.41.1: + resolution: {integrity: sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==} + cpu: [arm64] + os: [android] dev: true + optional: true - /@types/d3-time@3.0.3: - resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==} + /@rollup/rollup-darwin-arm64@4.41.1: + resolution: {integrity: sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==} + cpu: [arm64] + os: [darwin] dev: true + optional: true - /@types/debug@4.1.12: - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - dependencies: - '@types/ms': 0.7.34 + /@rollup/rollup-darwin-x64@4.41.1: + resolution: {integrity: sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==} + cpu: [x64] + os: [darwin] dev: true + optional: true - /@types/estree@1.0.5: - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + /@rollup/rollup-freebsd-arm64@4.41.1: + resolution: {integrity: sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==} + cpu: [arm64] + os: [freebsd] dev: true + optional: true - /@types/fs-extra@11.0.4: - resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} - dependencies: - '@types/jsonfile': 6.1.4 - '@types/node': 20.14.9 + /@rollup/rollup-freebsd-x64@4.41.1: + resolution: {integrity: sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==} + cpu: [x64] + os: [freebsd] dev: true + optional: true - /@types/hash-sum@1.0.2: - resolution: {integrity: sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==} + /@rollup/rollup-linux-arm-gnueabihf@4.41.1: + resolution: {integrity: sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==} + cpu: [arm] + os: [linux] dev: true + optional: true - /@types/jsonfile@6.1.4: - resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} - dependencies: - '@types/node': 20.14.9 + /@rollup/rollup-linux-arm-musleabihf@4.41.1: + resolution: {integrity: sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==} + cpu: [arm] + os: [linux] dev: true + optional: true - /@types/katex@0.16.7: - resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} + /@rollup/rollup-linux-arm64-gnu@4.41.1: + resolution: {integrity: sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==} + cpu: [arm64] + os: [linux] dev: true + optional: true - /@types/linkify-it@3.0.5: - resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==} - dev: true + /@rollup/rollup-linux-arm64-musl@4.41.1: + resolution: {integrity: sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==} + cpu: [arm64] + os: [linux] + dev: true + optional: true - /@types/linkify-it@5.0.0: - resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + /@rollup/rollup-linux-loongarch64-gnu@4.41.1: + resolution: {integrity: sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==} + cpu: [loong64] + os: [linux] + dev: true + optional: true + + /@rollup/rollup-linux-powerpc64le-gnu@4.41.1: + resolution: {integrity: sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==} + cpu: [ppc64] + os: [linux] + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.41.1: + resolution: {integrity: sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==} + cpu: [riscv64] + os: [linux] dev: true + optional: true - /@types/markdown-it-emoji@2.0.5: - resolution: {integrity: sha512-iJLsmCNpSWKtV6Ia3mLSjcXJPEt7ubGG342z+hGvYx++TpM19oTUrJcI7XjbOqRQ+W2UQ323E7B0eCLwlgT/9g==} + /@rollup/rollup-linux-riscv64-musl@4.41.1: + resolution: {integrity: sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==} + cpu: [riscv64] + os: [linux] + dev: true + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.41.1: + resolution: {integrity: sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==} + cpu: [s390x] + os: [linux] + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.41.1: + resolution: {integrity: sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==} + cpu: [x64] + os: [linux] + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.41.1: + resolution: {integrity: sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==} + cpu: [x64] + os: [linux] + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.41.1: + resolution: {integrity: sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==} + cpu: [arm64] + os: [win32] + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.41.1: + resolution: {integrity: sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==} + cpu: [ia32] + os: [win32] + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.41.1: + resolution: {integrity: sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==} + cpu: [x64] + os: [win32] + dev: true + optional: true + + /@shikijs/core@3.4.2: + resolution: {integrity: sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ==} dependencies: - '@types/markdown-it': 13.0.8 + '@shikijs/types': 3.4.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 dev: true - /@types/markdown-it@13.0.8: - resolution: {integrity: sha512-V+KmpgiipS+zoypeUSS9ojesWtY/0k4XfqcK2fnVrX/qInJhX7rsCxZ/rygiPH2zxlPPrhfuW0I6ddMcWTKLsg==} + /@shikijs/engine-javascript@3.4.2: + resolution: {integrity: sha512-1/adJbSMBOkpScCE/SB6XkjJU17ANln3Wky7lOmrnpl+zBdQ1qXUJg2GXTYVHRq+2j3hd1DesmElTXYDgtfSOQ==} dependencies: - '@types/linkify-it': 3.0.5 - '@types/mdurl': 1.0.5 + '@shikijs/types': 3.4.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.3 dev: true - /@types/markdown-it@14.1.1: - resolution: {integrity: sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==} + /@shikijs/engine-oniguruma@3.4.2: + resolution: {integrity: sha512-zcZKMnNndgRa3ORja6Iemsr3DrLtkX3cAF7lTJkdMB6v9alhlBsX9uNiCpqofNrXOvpA3h6lHcLJxgCIhVOU5Q==} dependencies: - '@types/linkify-it': 5.0.0 - '@types/mdurl': 2.0.0 + '@shikijs/types': 3.4.2 + '@shikijs/vscode-textmate': 10.0.2 + dev: true + + /@shikijs/langs@3.4.2: + resolution: {integrity: sha512-H6azIAM+OXD98yztIfs/KH5H4PU39t+SREhmM8LaNXyUrqj2mx+zVkr8MWYqjceSjDw9I1jawm1WdFqU806rMA==} + dependencies: + '@shikijs/types': 3.4.2 dev: true - /@types/mdast@3.0.15: - resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} + /@shikijs/themes@3.4.2: + resolution: {integrity: sha512-qAEuAQh+brd8Jyej2UDDf+b4V2g1Rm8aBIdvt32XhDPrHvDkEnpb7Kzc9hSuHUxz0Iuflmq7elaDuQAP9bHIhg==} dependencies: - '@types/unist': 2.0.10 + '@shikijs/types': 3.4.2 dev: true - /@types/mdurl@1.0.5: - resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} + /@shikijs/transformers@3.4.2: + resolution: {integrity: sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg==} + dependencies: + '@shikijs/core': 3.4.2 + '@shikijs/types': 3.4.2 + dev: true + + /@shikijs/types@3.4.2: + resolution: {integrity: sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg==} + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + dev: true + + /@shikijs/vscode-textmate@10.0.2: + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + dev: true + + /@sindresorhus/merge-streams@2.3.0: + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + dev: true + + /@stackblitz/sdk@1.11.0: + resolution: {integrity: sha512-DFQGANNkEZRzFk1/rDP6TcFdM82ycHE+zfl9C/M/jXlH68jiqHWHFMQURLELoD8koxvu/eW5uhg94NSAZlYrUQ==} + dev: true + + /@types/d3-array@3.2.1: + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + dev: true + + /@types/d3-axis@3.0.6: + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-brush@3.0.6: + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-chord@3.0.6: + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + dev: true + + /@types/d3-color@3.1.3: + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + dev: true + + /@types/d3-contour@3.0.6: + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.16 + dev: true + + /@types/d3-delaunay@6.0.4: + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + dev: true + + /@types/d3-dispatch@3.0.6: + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + dev: true + + /@types/d3-drag@3.0.7: + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-dsv@3.0.7: + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + dev: true + + /@types/d3-ease@3.0.2: + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + dev: true + + /@types/d3-fetch@3.0.7: + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + dependencies: + '@types/d3-dsv': 3.0.7 + dev: true + + /@types/d3-force@3.0.10: + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + dev: true + + /@types/d3-format@3.0.4: + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + dev: true + + /@types/d3-geo@3.1.0: + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + dependencies: + '@types/geojson': 7946.0.16 + dev: true + + /@types/d3-hierarchy@3.1.7: + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + dev: true + + /@types/d3-interpolate@3.0.4: + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + dependencies: + '@types/d3-color': 3.1.3 + dev: true + + /@types/d3-path@3.1.1: + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + dev: true + + /@types/d3-polygon@3.0.2: + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + dev: true + + /@types/d3-quadtree@3.0.6: + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + dev: true + + /@types/d3-random@3.0.3: + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + dev: true + + /@types/d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + dev: true + + /@types/d3-scale@4.0.9: + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + dependencies: + '@types/d3-time': 3.0.4 + dev: true + + /@types/d3-selection@3.0.11: + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + dev: true + + /@types/d3-shape@3.1.7: + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + dependencies: + '@types/d3-path': 3.1.1 + dev: true + + /@types/d3-time-format@4.0.3: + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + dev: true + + /@types/d3-time@3.0.4: + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + dev: true + + /@types/d3-timer@3.0.2: + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + dev: true + + /@types/d3-transition@3.0.9: + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-zoom@3.0.8: + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3@7.4.3: + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + dev: true + + /@types/debug@4.1.12: + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + dependencies: + '@types/ms': 2.1.0 + dev: true + + /@types/estree@1.0.7: + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + dev: true + + /@types/fs-extra@11.0.4: + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 22.15.21 + dev: true + + /@types/geojson@7946.0.16: + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + dev: true + + /@types/hash-sum@1.0.2: + resolution: {integrity: sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==} + dev: true + + /@types/hast@3.0.4: + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + dependencies: + '@types/unist': 3.0.3 + dev: true + + /@types/jsonfile@6.1.4: + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + dependencies: + '@types/node': 22.15.21 + dev: true + + /@types/linkify-it@5.0.0: + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + dev: true + + /@types/markdown-it-emoji@3.0.1: + resolution: {integrity: sha512-cz1j8R35XivBqq9mwnsrP2fsz2yicLhB8+PDtuVkKOExwEdsVBNI+ROL3sbhtR5occRZ66vT0QnwFZCqdjf3pA==} + dependencies: + '@types/markdown-it': 14.1.2 + dev: true + + /@types/markdown-it@14.1.2: + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + dev: true + + /@types/mdast@4.0.4: + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + dependencies: + '@types/unist': 3.0.3 dev: true /@types/mdurl@2.0.0: resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} dev: true - /@types/ms@0.7.34: - resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + /@types/ms@2.1.0: + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} dev: true /@types/node@17.0.45: resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} dev: true - /@types/node@20.14.9: - resolution: {integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==} + /@types/node@22.15.21: + resolution: {integrity: sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==} dependencies: - undici-types: 5.26.5 + undici-types: 6.21.0 dev: true /@types/sax@1.2.7: @@ -899,498 +1399,854 @@ packages: resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} dev: true - /@types/unist@2.0.10: - resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} + /@types/unist@3.0.3: + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} dev: true /@types/web-bluetooth@0.0.20: resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} dev: true - /@vitejs/plugin-vue@5.0.5(vite@5.2.13)(vue@3.4.30): - resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==} + /@types/web-bluetooth@0.0.21: + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + dev: true + + /@ungap/structured-clone@1.3.0: + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + dev: true + + /@vitejs/plugin-vue@5.2.4(vite@6.3.5)(vue@3.5.15): + resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: - vite: ^5.0.0 + vite: ^5.0.0 || ^6.0.0 vue: ^3.2.25 dependencies: - vite: 5.2.13 - vue: 3.4.30 + vite: 6.3.5(sass-embedded@1.89.0)(sass@1.89.0) + vue: 3.5.15 dev: true - /@vue/compiler-core@3.4.30: - resolution: {integrity: sha512-ZL8y4Xxdh8O6PSwfdZ1IpQ24PjTAieOz3jXb/MDTfDtANcKBMxg1KLm6OX2jofsaQGYfIVzd3BAG22i56/cF1w==} + /@vue/compiler-core@3.5.15: + resolution: {integrity: sha512-nGRc6YJg/kxNqbv/7Tg4juirPnjHvuVdhcmDvQWVZXlLHjouq7VsKmV1hIxM/8yKM0VUfwT/Uzc0lO510ltZqw==} dependencies: - '@babel/parser': 7.24.7 - '@vue/shared': 3.4.30 + '@babel/parser': 7.27.2 + '@vue/shared': 3.5.15 entities: 4.5.0 estree-walker: 2.0.2 - source-map-js: 1.2.0 + source-map-js: 1.2.1 dev: true - /@vue/compiler-dom@3.4.30: - resolution: {integrity: sha512-+16Sd8lYr5j/owCbr9dowcNfrHd+pz+w2/b5Lt26Oz/kB90C9yNbxQ3bYOvt7rI2bxk0nqda39hVcwDFw85c2Q==} + /@vue/compiler-dom@3.5.15: + resolution: {integrity: sha512-ZelQd9n+O/UCBdL00rlwCrsArSak+YLZpBVuNDio1hN3+wrCshYZEDUO3khSLAzPbF1oQS2duEoMDUHScUlYjA==} dependencies: - '@vue/compiler-core': 3.4.30 - '@vue/shared': 3.4.30 + '@vue/compiler-core': 3.5.15 + '@vue/shared': 3.5.15 dev: true - /@vue/compiler-sfc@3.4.30: - resolution: {integrity: sha512-8vElKklHn/UY8+FgUFlQrYAPbtiSB2zcgeRKW7HkpSRn/JjMRmZvuOtwDx036D1aqKNSTtXkWRfqx53Qb+HmMg==} + /@vue/compiler-sfc@3.5.15: + resolution: {integrity: sha512-3zndKbxMsOU6afQWer75Zot/aydjtxNj0T2KLg033rAFaQUn2PGuE32ZRe4iMhflbTcAxL0yEYsRWFxtPro8RQ==} dependencies: - '@babel/parser': 7.24.7 - '@vue/compiler-core': 3.4.30 - '@vue/compiler-dom': 3.4.30 - '@vue/compiler-ssr': 3.4.30 - '@vue/shared': 3.4.30 + '@babel/parser': 7.27.2 + '@vue/compiler-core': 3.5.15 + '@vue/compiler-dom': 3.5.15 + '@vue/compiler-ssr': 3.5.15 + '@vue/shared': 3.5.15 estree-walker: 2.0.2 - magic-string: 0.30.10 - postcss: 8.4.38 - source-map-js: 1.2.0 + magic-string: 0.30.17 + postcss: 8.5.3 + source-map-js: 1.2.1 dev: true - /@vue/compiler-ssr@3.4.30: - resolution: {integrity: sha512-ZJ56YZGXJDd6jky4mmM0rNaNP6kIbQu9LTKZDhcpddGe/3QIalB1WHHmZ6iZfFNyj5mSypTa4+qDJa5VIuxMSg==} + /@vue/compiler-ssr@3.5.15: + resolution: {integrity: sha512-gShn8zRREZbrXqTtmLSCffgZXDWv8nHc/GhsW+mbwBfNZL5pI96e7IWcIq8XGQe1TLtVbu7EV9gFIVSmfyarPg==} dependencies: - '@vue/compiler-dom': 3.4.30 - '@vue/shared': 3.4.30 + '@vue/compiler-dom': 3.5.15 + '@vue/shared': 3.5.15 dev: true - /@vue/devtools-api@6.6.3: - resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==} + /@vue/devtools-api@6.6.4: + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} dev: true - /@vue/reactivity@3.4.30: - resolution: {integrity: sha512-bVJurnCe3LS0JII8PPoAA63Zd2MBzcKrEzwdQl92eHCcxtIbxD2fhNwJpa+KkM3Y/A4T5FUnmdhgKwOf6BfbcA==} + /@vue/devtools-api@7.7.6: + resolution: {integrity: sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==} dependencies: - '@vue/shared': 3.4.30 + '@vue/devtools-kit': 7.7.6 dev: true - /@vue/runtime-core@3.4.30: - resolution: {integrity: sha512-qaFEbnNpGz+tlnkaualomogzN8vBLkgzK55uuWjYXbYn039eOBZrWxyXWq/7qh9Bz2FPifZqGjVDl/FXiq9L2g==} + /@vue/devtools-kit@7.7.6: + resolution: {integrity: sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA==} dependencies: - '@vue/reactivity': 3.4.30 - '@vue/shared': 3.4.30 + '@vue/devtools-shared': 7.7.6 + birpc: 2.3.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.2 dev: true - /@vue/runtime-dom@3.4.30: - resolution: {integrity: sha512-tV6B4YiZRj5QsaJgw2THCy5C1H+2UeywO9tqgWEc21tn85qHEERndHN/CxlyXvSBFrpmlexCIdnqPuR9RM9thw==} + /@vue/devtools-shared@7.7.6: + resolution: {integrity: sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA==} dependencies: - '@vue/reactivity': 3.4.30 - '@vue/runtime-core': 3.4.30 - '@vue/shared': 3.4.30 + rfdc: 1.4.1 + dev: true + + /@vue/reactivity@3.5.15: + resolution: {integrity: sha512-GaA5VUm30YWobCwpvcs9nvFKf27EdSLKDo2jA0IXzGS344oNpFNbEQ9z+Pp5ESDaxyS8FcH0vFN/XSe95BZtHQ==} + dependencies: + '@vue/shared': 3.5.15 + dev: true + + /@vue/runtime-core@3.5.15: + resolution: {integrity: sha512-CZAlIOQ93nj0OPpWWOx4+QDLCMzBNY85IQR4Voe6vIID149yF8g9WQaWnw042f/6JfvLttK7dnyWlC1EVCRK8Q==} + dependencies: + '@vue/reactivity': 3.5.15 + '@vue/shared': 3.5.15 + dev: true + + /@vue/runtime-dom@3.5.15: + resolution: {integrity: sha512-wFplHKzKO/v998up2iCW3RN9TNUeDMhdBcNYZgs5LOokHntrB48dyuZHspcahKZczKKh3v6i164gapMPxBTKNw==} + dependencies: + '@vue/reactivity': 3.5.15 + '@vue/runtime-core': 3.5.15 + '@vue/shared': 3.5.15 csstype: 3.1.3 dev: true - /@vue/server-renderer@3.4.30(vue@3.4.30): - resolution: {integrity: sha512-TBD3eqR1DeDc0cMrXS/vEs/PWzq1uXxnvjoqQuDGFIEHFIwuDTX/KWAQKIBjyMWLFHEeTDGYVsYci85z2UbTDg==} + /@vue/server-renderer@3.5.15(vue@3.5.15): + resolution: {integrity: sha512-Gehc693kVTYkLt6QSYEjGvqvdK2zZ/gf/D5zkgmvBdeB30dNnVZS8yY7+IlBmHRd1rR/zwaqeu06Ij04ZxBscg==} peerDependencies: - vue: 3.4.30 + vue: 3.5.15 dependencies: - '@vue/compiler-ssr': 3.4.30 - '@vue/shared': 3.4.30 - vue: 3.4.30 + '@vue/compiler-ssr': 3.5.15 + '@vue/shared': 3.5.15 + vue: 3.5.15 dev: true - /@vue/shared@3.4.30: - resolution: {integrity: sha512-CLg+f8RQCHQnKvuHY9adMsMaQOcqclh6Z5V9TaoMgy0ut0tz848joZ7/CYFFyF/yZ5i2yaw7Fn498C+CNZVHIg==} + /@vue/shared@3.5.15: + resolution: {integrity: sha512-bKvgFJJL1ZX9KxMCTQY6xD9Dhe3nusd1OhyOb1cJYGqvAr0Vg8FIjHPMOEVbJ9GDT9HG+Bjdn4oS8ohKP8EvoA==} dev: true - /@vuepress/bundler-vite@2.0.0-rc.9: - resolution: {integrity: sha512-GcM2eSqW2mPY5xXX4i5kuZujvwUeiTpsLX5kgau9LzPox+FdA3SMUkppCY3hsou2o2RxXPTfjocE7OlYQrUqvA==} + /@vuepress/bundler-vite@2.0.0-rc.23(sass-embedded@1.89.0)(sass@1.89.0): + resolution: {integrity: sha512-59oBof+QaCyrZVOussrmv3bHxpwFPsLlI9yQbq2ubR+dFNzgfAtb8Dpm2z9iB/duZnx6PgmWPke4qGl9wOjEKw==} dependencies: - '@vitejs/plugin-vue': 5.0.5(vite@5.2.13)(vue@3.4.30) - '@vuepress/client': 2.0.0-rc.9 - '@vuepress/core': 2.0.0-rc.9 - '@vuepress/shared': 2.0.0-rc.9 - '@vuepress/utils': 2.0.0-rc.9 - autoprefixer: 10.4.19(postcss@8.4.38) + '@vitejs/plugin-vue': 5.2.4(vite@6.3.5)(vue@3.5.15) + '@vuepress/bundlerutils': 2.0.0-rc.23 + '@vuepress/client': 2.0.0-rc.23 + '@vuepress/core': 2.0.0-rc.23 + '@vuepress/shared': 2.0.0-rc.23 + '@vuepress/utils': 2.0.0-rc.23 + autoprefixer: 10.4.21(postcss@8.5.3) connect-history-api-fallback: 2.0.0 - postcss: 8.4.38 - postcss-load-config: 5.1.0(postcss@8.4.38) - rollup: 4.18.0 - vite: 5.2.13 - vue: 3.4.30 - vue-router: 4.4.0(vue@3.4.30) + postcss: 8.5.3 + postcss-load-config: 6.0.1(postcss@8.5.3) + rollup: 4.41.1 + vite: 6.3.5(sass-embedded@1.89.0)(sass@1.89.0) + vue: 3.5.15 + vue-router: 4.5.1(vue@3.5.15) transitivePeerDependencies: - '@types/node' - jiti - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser - tsx - typescript + - yaml + dev: true + + /@vuepress/bundlerutils@2.0.0-rc.23: + resolution: {integrity: sha512-XgDbIT10xI7m8Pto+N8Mi+o+s1oAg+Mo65WLeHkaCexSRrF9Fa9WRun28EtB5PnyVhaZvnXh5XXuthXZl206JA==} + dependencies: + '@vuepress/client': 2.0.0-rc.23 + '@vuepress/core': 2.0.0-rc.23 + '@vuepress/shared': 2.0.0-rc.23 + '@vuepress/utils': 2.0.0-rc.23 + vue: 3.5.15 + vue-router: 4.5.1(vue@3.5.15) + transitivePeerDependencies: + - supports-color + - typescript dev: true - /@vuepress/cli@2.0.0-rc.9: - resolution: {integrity: sha512-uv7Xmv3QmPpzCaUAq0oKEwp2tY64AO+7mxamgr7tr+t6FEnCYqr+X0nLlH17UtMkmGWIsbHLIlMjteprxGxIMg==} + /@vuepress/cli@2.0.0-rc.23: + resolution: {integrity: sha512-lNAvRf4zyfnl8pgUA/uj2yCgsroJJzUm2dEwmudOIvfSV+N5jMUQuomdE5gZemDDk2oE2gqyRPBOZ12LP2EEIg==} hasBin: true dependencies: - '@vuepress/core': 2.0.0-rc.9 - '@vuepress/shared': 2.0.0-rc.9 - '@vuepress/utils': 2.0.0-rc.9 + '@vuepress/core': 2.0.0-rc.23 + '@vuepress/shared': 2.0.0-rc.23 + '@vuepress/utils': 2.0.0-rc.23 cac: 6.7.14 chokidar: 3.6.0 - envinfo: 7.13.0 - esbuild: 0.20.2 + envinfo: 7.14.0 + esbuild: 0.25.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@vuepress/client@2.0.0-rc.9: - resolution: {integrity: sha512-V5jA6L1nHQ8tXBshRHBJKei7HPFonGxFzmVK5yjj2Ho/Xtp/SD9rBS6dyYd5CSkKRGQDgy19Z+BUUPXtdI1qzg==} + /@vuepress/client@2.0.0-rc.23: + resolution: {integrity: sha512-/2sdQTOELCUgoEjy2XGqcDMHSAz1kdaMYBr+8zv5et2aYzpn9rYdW0SzXTprhc354ccN65xNHarr6uIbVJ1m0g==} dependencies: - '@vue/devtools-api': 6.6.3 - '@vuepress/shared': 2.0.0-rc.9 - vue: 3.4.30 - vue-router: 4.4.0(vue@3.4.30) + '@vue/devtools-api': 7.7.6 + '@vue/devtools-kit': 7.7.6 + '@vuepress/shared': 2.0.0-rc.23 + vue: 3.5.15 + vue-router: 4.5.1(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/core@2.0.0-rc.9: - resolution: {integrity: sha512-uvMkIqYJ7vjfYEC91rMmT8YJt8xXnob5YYY3TzlwWUSEv4yoV3nlVu0l6Zfhenx/7FwKaxRJ/ePlUGIgUHBcBw==} + /@vuepress/core@2.0.0-rc.23: + resolution: {integrity: sha512-CkXDOCKJATxFciEuLCDtAzdCkGyNfCcmBYyhsvYLSJU8oiXgt27EjmXNKTpN+MNXSl934/353UERExGafhsTfg==} dependencies: - '@vuepress/client': 2.0.0-rc.9 - '@vuepress/markdown': 2.0.0-rc.9 - '@vuepress/shared': 2.0.0-rc.9 - '@vuepress/utils': 2.0.0-rc.9 - vue: 3.4.30 + '@vuepress/client': 2.0.0-rc.23 + '@vuepress/markdown': 2.0.0-rc.23 + '@vuepress/shared': 2.0.0-rc.23 + '@vuepress/utils': 2.0.0-rc.23 + vue: 3.5.15 transitivePeerDependencies: - supports-color - typescript dev: true - /@vuepress/helper@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-qXC+tXTKfZ7eJ+h3wYC/7Q903Tbqcz9Vqxku63R6pmcpbsRtt3l8XQRdJ/LMT5yX0wZln4Qzx1NY6S4psr0lzw==} + /@vuepress/helper@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-GmsFstdmryNLjCDF+wVTP6wBmHYAenAbtd04TG4se/ZB+pfhCNT5Zq6dEO3TG35JLcdUm/bI4uE3BE4WVBkSgw==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vue/shared': 3.4.30 - cheerio: 1.0.0-rc.12 + '@vue/shared': 3.5.15 + '@vueuse/core': 13.2.0(vue@3.5.15) + cheerio: 1.0.0 fflate: 0.8.2 gray-matter: 4.0.3 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/markdown@2.0.0-rc.9: - resolution: {integrity: sha512-e7as2ar3RQp0bUyMiwBPi7L/G2fzscb3s0BywNcAwubFR22o0/dBEYRYdrN0clPQ2FXpPxF6AFj4aD7O1heCbw==} - dependencies: - '@mdit-vue/plugin-component': 2.1.3 - '@mdit-vue/plugin-frontmatter': 2.1.3 - '@mdit-vue/plugin-headers': 2.1.3 - '@mdit-vue/plugin-sfc': 2.1.3 - '@mdit-vue/plugin-title': 2.1.3 - '@mdit-vue/plugin-toc': 2.1.3 - '@mdit-vue/shared': 2.1.3 - '@mdit-vue/types': 2.1.0 - '@types/markdown-it': 13.0.8 - '@types/markdown-it-emoji': 2.0.5 - '@vuepress/shared': 2.0.0-rc.9 - '@vuepress/utils': 2.0.0-rc.9 + /@vuepress/helper@2.0.0-rc.106(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-z55+VY6jh6TBnluXH5DralRDvLEiaGRn53iqi6BrWD+f8Hef+Jus1ivOnjM5awitXaBYu9e4rrqC2IMtuSyWkA==} + peerDependencies: + vuepress: 2.0.0-rc.23 + dependencies: + '@vue/shared': 3.5.15 + '@vueuse/core': 13.2.0(vue@3.5.15) + cheerio: 1.0.0 + fflate: 0.8.2 + gray-matter: 4.0.3 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript + dev: true + + /@vuepress/helper@2.0.0-rc.47(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-XlfrkRjxv7Id3sc8Wjh7pHs2eFhOE/HAA+u9AMLZHcfxZUBkIftBfrSqg9ZBGybVkm4aGT+K/sC2IZxFhqukiA==} + peerDependencies: + vuepress: 2.0.0-rc.15 + dependencies: + '@vue/shared': 3.5.15 + '@vueuse/core': 11.3.0(vue@3.5.15) + cheerio: 1.0.0 + fflate: 0.8.2 + gray-matter: 4.0.3 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - '@vue/composition-api' + - typescript + dev: true + + /@vuepress/highlighter-helper@2.0.0-rc.103(@vueuse/core@13.2.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-gYOF+5Q4ilo3Km5KSZfie8w1Fs2Nit/YnvWaIenWelSfp3DHweLNiwOhVjp8e/s8bmCEozP3CtOxmWXEZNrHng==} + peerDependencies: + '@vueuse/core': ^13.1.0 + vuepress: 2.0.0-rc.23 + peerDependenciesMeta: + '@vueuse/core': + optional: true + dependencies: + '@vueuse/core': 13.2.0(vue@3.5.15) + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + dev: true + + /@vuepress/markdown@2.0.0-rc.23: + resolution: {integrity: sha512-KDC5xtd6GQBKsKkOKchJ5yxof/JES6StsBAmm5+S6WVJGOFRCVw5tpicFO9tgm1alwWFbX0WD5oloPq/ZOJtfA==} + dependencies: + '@mdit-vue/plugin-component': 2.1.4 + '@mdit-vue/plugin-frontmatter': 2.1.4 + '@mdit-vue/plugin-headers': 2.1.4 + '@mdit-vue/plugin-sfc': 2.1.4 + '@mdit-vue/plugin-title': 2.1.4 + '@mdit-vue/plugin-toc': 2.1.4 + '@mdit-vue/shared': 2.1.4 + '@mdit-vue/types': 2.1.4 + '@types/markdown-it': 14.1.2 + '@types/markdown-it-emoji': 3.0.1 + '@vuepress/shared': 2.0.0-rc.23 + '@vuepress/utils': 2.0.0-rc.23 markdown-it: 14.1.0 - markdown-it-anchor: 8.6.7(@types/markdown-it@13.0.8)(markdown-it@14.1.0) + markdown-it-anchor: 9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0) markdown-it-emoji: 3.0.0 mdurl: 2.0.0 transitivePeerDependencies: - supports-color dev: true - /@vuepress/plugin-active-header-links@2.0.0-rc.21(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-6i9TfGDV1zfszQ5aw6bV+/UvPdBWt3VxN2WB4Dg5o1g8Qn4z5CI6AW6VfLKRyaKUD+Rzj6W+Ikgx4xnF5RZAdA==} + /@vuepress/plugin-active-header-links@2.0.0-rc.103(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-NStHWt6pYpkytULiAN2HWExsETbJKo8iCRGVbKkm6rn4NFM5v5zODv/0Mw7aRZ35X8b6H75BYVY3zKe8ahUkDQ==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vueuse/core': 10.11.0(vue@3.4.30) - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vueuse/core': 13.2.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - - '@vue/composition-api' - typescript dev: true - /@vuepress/plugin-back-to-top@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-cU5KtsuqUBcDiNlAD+I2NaaEd7ZRDldWPggJMgE7VvhEQ8uJMOq4ogh2IabeqGZ26XiUYuGnNrp4JK5mDkQlvw==} + /@vuepress/plugin-back-to-top@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-8pdtoK1LlH+VVV+tAZuv5J6jyeILVtip51TkzfeenHtI6NSba3SxPq9qaUhX2GPHTcUZV62higM4rwG2zAEz5A==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - - '@vue/composition-api' - typescript dev: true - /@vuepress/plugin-blog@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-EEpJcTHhlB6/LWXWdhBN3f9dFRrkOJSWw9KyD/7/GBImqbPKrdWh2y6VZejUvZBK+1Onv0/KEXMgE3zI3LAB/g==} + /@vuepress/plugin-blog@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-WFr4yx5hgYE8RVOqE/sXqovAujd2HgAQEIFgZwKU1u1ncmtlbwBwdKWOU8I2mv0iEhYWu53TUyP+uZvNf/kVLg==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) chokidar: 3.6.0 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/plugin-catalog@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-MkJ14qOd0KoKb8cmFqT0tPNK9REJNP8bm1dZBdYOrqX8mDgt4nq2EyVOZTBZWqaYyXekJZyNfXkN4i556/8x+w==} + /@vuepress/plugin-catalog@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-HQSmDhHpx+1cPL0jWmKlLUzc0e0XwoqFbX5X5MX5wDVohqjx3j04iEKWEeYhE7NbirbxlA9dXc3/ssb/WoYY+A==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/plugin-comment@2.0.0-rc.24(sass-loader@14.2.1)(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-Kl5LHCbyoTIXFZwMmJa4f8neMbebC4ZhASf8cnfdNTBf6XRVbSH1fGJKGFK1lUm3EcjjBHIAuZIrlMWPmepUGQ==} + /@vuepress/plugin-comment@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-I0OENWem7z7g+OXOU9L9RGj2hfBZ3MRl8Wd3+1yXE3t8PUimUKrUUj3x0eVQPhAwupmzV1ncTsm72M2IwIVRmQ==} peerDependencies: - '@waline/client': ^3.1.0 - artalk: ^2.7.3 - sass-loader: ^14.0.0 - twikoo: ^1.5.0 - vuepress: 2.0.0-rc.9 + '@waline/client': ^3.5.5 + artalk: ^2.9.1 + twikoo: ^1.6.41 + vuepress: 2.0.0-rc.23 peerDependenciesMeta: '@waline/client': optional: true artalk: optional: true - sass-loader: - optional: true twikoo: optional: true dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - giscus: 1.5.0 - sass-loader: 14.2.1 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + giscus: 1.6.0 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/plugin-copy-code@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-anLxeQqTiU+LNdEBK7EUbeIcU0YEh6x9Bs9SQV4wrdFKjYc5x2U4Gf9l9NagOSf1e3c0QZRYL3wLQ5q3XZnGjA==} + /@vuepress/plugin-copy-code@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-WROusuYp+EWCZcfAu1MX/DtvWbfmDYipDmCDAdwA5C78qbjWJbEDeMOJKvyO4AhfjxrdS6wmOjw61M9t2ZJUIQ==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - - '@vue/composition-api' - typescript dev: true - /@vuepress/plugin-copyright@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-sposicjAxALPhXb6TBVq5x6dE2/87OvwyB4RFs0kCeUjE4Tg7WKj2E28vdRQtNGE0P8MC0D0qJbi/ORbg9UObw==} + /@vuepress/plugin-copyright@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-bURyvHxFWdwL+fz3OGjlEgmQiZTdu+WhaJixrRyRi05L7r4sBnV1MIbTH29757HerdFu5THona0mF15xgj0B2A==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - - '@vue/composition-api' - typescript dev: true - /@vuepress/plugin-external-link-icon@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-kry1EFkv6WaGOCzk9vRGHGcAuQHNVQ/jDEgtagUFaRk5+HtCQB60VzhmFdwM08DC2XAmDieBLm1MMR0T2DdHSw==} + /@vuepress/plugin-git@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-Gw9aLcrMKJ+ThLCFSeYMZRXkW2tak3OhuwyObchij63SiR8G8I6EZWzGaZAT8ad3BUUcst6qLX6phXVkShtQWQ==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 + dependencies: + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + rehype-parse: 9.0.1 + rehype-sanitize: 6.0.0 + rehype-stringify: 10.0.1 + unified: 11.0.5 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript + dev: true + + /@vuepress/plugin-icon@2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-UNopisXX8hWPRSyw2tgbz6u7Mtj/sm6moUbTCPD6YcJqJAyp9SnkQDzBMUtmvPnWrKUwbWdJvCvAdMIMKa/mSw==} + peerDependencies: + vuepress: 2.0.0-rc.23 dependencies: - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@mdit/plugin-icon': 0.18.0(markdown-it@14.1.0) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: + - markdown-it - typescript dev: true - /@vuepress/plugin-git@2.0.0-rc.22(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-+T50AdCZ68Pkld4r8IEHTXLugfNVCxxPp2G1hlI/lpQ6IZcpLbswMI6l9xbbo15RrOBg/V0jkim/B/jaaVIM6A==} + /@vuepress/plugin-links-check@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-duE6CUoc2eorW4sYw8tMFuPEStm35dmnk0XhxQQqkeIg2gpWDMkrb4sYqfU8twLU3Z+Tcq9FWYwyQ2QjyT8TYQ==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - execa: 8.0.1 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript dev: true - /@vuepress/plugin-links-check@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-+HPIutNZhMP2eSf1Gb217WLCQlQhsMkebTfuZYyDSGGvY5TQmXOAuu/X7Xwh1lJlml9asPUXTcFe2cZcEtHHIA==} + /@vuepress/plugin-markdown-ext@2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-W3vWwFsoAVgEWrNa8u+/FgGrRjIM7XYJYXhJzfJJdh1wOKJUOavBGdn20JGRnD3b3KAw0q4UzSeDeJPLA+vTKA==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@mdit/plugin-container': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-footnote': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-tasklist': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + js-yaml: 4.1.0 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - markdown-it + - typescript + dev: true + + /@vuepress/plugin-markdown-hint@2.0.0-rc.104(markdown-it@14.1.0)(vue@3.5.15)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-5ozO5Q9gTh7x7ZPAvAAXULdD6S0A1KrsunMtjG3TPREL99ExILwMnnRtgnDSDA11gH7SBMrKuS18E77ccHLaeA==} + peerDependencies: + vuepress: 2.0.0-rc.23 + dependencies: + '@mdit/plugin-alert': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-container': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - markdown-it + - typescript + - vue + dev: true + + /@vuepress/plugin-markdown-image@2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-UV/nRsvt7/aTfRFrdVD1n/M70IdTT988pGMdzAOexlcs0xdStLHmo9w9d9CwXOh5rrIWMM4JLzvJnpYY3Njluw==} + peerDependencies: + vuepress: 2.0.0-rc.23 + dependencies: + '@mdit/plugin-figure': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-img-lazyload': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-img-mark': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-img-size': 0.18.1(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: + - markdown-it - typescript dev: true - /@vuepress/plugin-nprogress@2.0.0-rc.21(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-qpGA76195SyfpuQC1Pb9LwgCYIp/zg+BBDnexukJMdLjP1KnaU7HLhS5NnRNIWv8E+IC61zLvlh/wRox17QE+w==} + /@vuepress/plugin-markdown-include@2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-MiuwUQZB4dz9Zx0o5wzP/GX23dzPLaEPATqhgN6+roO75tHaGUUpt0752b5HrUtny8R1evFHz/kk3mDjQfIN7g==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@mdit/plugin-include': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: + - markdown-it - typescript dev: true - /@vuepress/plugin-photo-swipe@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-2Rvi8ODFJgIDDfrXzt7ynY3nizCiEte2Cna4W73bH1+s9PMiOoa5rQ54/r+jbLe4Nw5Iw4x+PXcRN8fDQPllKg==} + /@vuepress/plugin-markdown-math@2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-w+Dn425WKY3oMf5jl1hjoDFsoENvEhIANMsLCDPDa9GRxTdxd1LZdRJ6UMfsolC2nPoa+diZG9/Z+Nk9jAIz1Q==} peerDependencies: - vuepress: 2.0.0-rc.9 + katex: ^0.16.21 + mathjax-full: ^3.2.2 + vuepress: 2.0.0-rc.23 + peerDependenciesMeta: + katex: + optional: true + mathjax-full: + optional: true dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) - photoswipe: 5.4.4 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@mdit/plugin-katex-slim': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-mathjax-slim': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - markdown-it + - typescript + dev: true + + /@vuepress/plugin-markdown-stylize@2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-jSIpE+p6/aPXZx4ipU3YVnqB9wPFwBRmbDhsw0xVg7x+9TBLHQGmp/fUg6bYWjgU/TSnrdzri6B1sgkzuoWZKg==} + peerDependencies: + vuepress: 2.0.0-rc.23 + dependencies: + '@mdit/plugin-align': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-attrs': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-mark': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-spoiler': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-stylize': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-sub': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-sup': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - markdown-it + - typescript + dev: true + + /@vuepress/plugin-markdown-tab@2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-M/c08lAfSg2fJq8KqOoX/kdFWlFjt+rT+0v8JzKtDjqNcK8GzhCsaLNw+9X09FLBqDOolrXYnjvGvGPSNh2JxA==} + peerDependencies: + vuepress: 2.0.0-rc.23 + dependencies: + '@mdit/plugin-tab': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - markdown-it + - typescript + dev: true + + /@vuepress/plugin-markdown-tab@2.0.0-rc.47(markdown-it@14.1.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-oB3/slwgCSOxPejsi8nuzVCFRpaVFqQXUwzyH5DJYofTiwl51ELT2Jhbiz3fqBljTCQk0Ts2e+H10jUgo8Yg+w==} + peerDependencies: + vuepress: 2.0.0-rc.15 + dependencies: + '@mdit/plugin-tab': 0.13.2(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.47(vuepress@2.0.0-rc.23) + '@vueuse/core': 11.3.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - '@vue/composition-api' + - markdown-it - typescript dev: true - /@vuepress/plugin-prismjs@2.0.0-rc.21(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-dMTCu/TZ1QCmTHXL4THVeh9gWzuqkJV8qhck5U77OP1qmgyf+r529A+MTOgp3ddcph1Yzb/FRb2orlefHk+yNQ==} + /@vuepress/plugin-notice@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-L5QQcCX5pQiPmI6g7j062m+DlSoiCpQClhq4sv+2vkpPefct4hpdH2h3L3WBwiijUUH2fZ/aZ8SPNI4aeqm4Nw==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - prismjs: 1.29.0 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + chokidar: 3.6.0 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript dev: true - /@vuepress/plugin-reading-time@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-La6dgul551Xp2Iacs1URZnLX5YdakfJWFfE9vIhhX/Q1+slUGRVftFLh/nb0oVUrsXNeRlqCUncTyilg51Q1fA==} + /@vuepress/plugin-nprogress@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-ZjdWXpoTY/+Aa+24mNLwMwFjx4qSn/jeKTAqtJTK697Tro7BCUa/KdKtDlXfdUVsm1O9Ewc/Nh0T9eMjEaWAfA==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/plugin-rtl@2.0.0-rc.21(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-r+4aP898KsFbF6m1J0e+776ZlSE9yaHr9zsMlib1GEUDcqP/OykMYaNKwRsOMB1eFXNmymgHlXFvswBGEHxS7w==} + /@vuepress/plugin-photo-swipe@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-/NiQ2n3wvhQ3vq9jwI98p9ecdfh6Q7bXfFZbkfVoYD3fQMgfg1pkRfO2VnR6uJUQkKOE7x/c1REB5ulm/lZQ1A==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + photoswipe: 5.4.4 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/plugin-seo@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-E0dRCNqV6RLoVV4j8xchmlsnlR7OyPQxWmWrk20mBiyluRI05OXdb20ZQbYJe3PfK8f8DnyETzob943HBg3sVA==} + /@vuepress/plugin-reading-time@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-5podLkwt9uJZy4rikwc2FP6R2ObWS9t73sUi0XBTUlAmv0fh55kXDY0bbyiOv0odlWwrmq48O2si3hggFZVdGA==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/plugin-sitemap@2.0.0-rc.24(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-su5ZD8vGuNpbqmb+uCOzWXCZ0eii8wnkdhn4V1xtmmXsrmYDr0FFHp61Ebb6EYAquB3HH1v3hWdfLRMU9DM6VQ==} + /@vuepress/plugin-redirect@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-/71G5+8NzhOFOxgrju3ocNJ0NocvRLBWIEXIDKscBqMMD5gD12WdkSS6TsFKDNLRWEaTgTsljD75yYn9WvNNNQ==} + hasBin: true peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - sitemap: 7.1.2 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + commander: 13.1.0 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/plugin-theme-data@2.0.0-rc.21(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-vLXvTKx4gWXY6oVaJ9Z2ECnojnKQuXBIe1ZGIAwJdxCYfr6aaqggrVvmphB8BwTURh0XAuis/l6YTcMrs0bX8Q==} + /@vuepress/plugin-rtl@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-nz4TkvdyWPoBeCB19UW0FThH/WqG0eH/KVr95bU9hSAQ3NCBxcSxT3RMBN+7gG0Mryfj5niSVb0HXMSCPf7RBw==} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vue/devtools-api': 6.6.3 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - typescript dev: true - /@vuepress/shared@2.0.0-rc.9: - resolution: {integrity: sha512-XfI6CWNv4/Vp9Iew6GJil9RUSy1rM7zGdjwikr0j3Rkh55q3f00w1wud47wE9kxRqsZ0PIvsMget5CxEn5rA/w==} + /@vuepress/plugin-sass-palette@2.0.0-rc.104(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-IwYUTRSPU4yMikfg8tfdFwWLx1Msv1y/KbMUrpn2nlVzEqpmYCDorvskM45jlTv05PIrcerrVbEfYLyJTIVmAQ==} + peerDependencies: + sass: ^1.86.3 + sass-embedded: ^1.86.3 + sass-loader: ^16.0.5 + vuepress: 2.0.0-rc.23 + peerDependenciesMeta: + sass: + optional: true + sass-embedded: + optional: true + sass-loader: + optional: true + dependencies: + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + chokidar: 4.0.3 + sass: 1.89.0 + sass-embedded: 1.89.0 + sass-loader: 16.0.5(sass-embedded@1.89.0)(sass@1.89.0) + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript + dev: true + + /@vuepress/plugin-seo@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-/+ssrAl8z5lT+Z6/dzTxlOEbqspJiCN/w5NpeAu46Tvrf9XqqBO47vQURAdRxJeUGi7ddsWt61ctthQnayOOmg==} + peerDependencies: + vuepress: 2.0.0-rc.23 + dependencies: + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript + dev: true + + /@vuepress/plugin-shiki@2.0.0-rc.104(@vueuse/core@13.2.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-FDkdUsXdBcxU2yya7/69qCogxjoRf+GCoKMyJ2GOyZ71hX48h4e9EngF0Tds81FI0yofDiA2XAN396IxiYTV+A==} + peerDependencies: + '@vuepress/shiki-twoslash': 2.0.0-rc.104 + vuepress: 2.0.0-rc.23 + peerDependenciesMeta: + '@vuepress/shiki-twoslash': + optional: true + dependencies: + '@shikijs/transformers': 3.4.2 + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/highlighter-helper': 2.0.0-rc.103(@vueuse/core@13.2.0)(vuepress@2.0.0-rc.23) + nanoid: 5.1.5 + shiki: 3.4.2 + synckit: 0.11.6 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - '@vueuse/core' + - typescript + dev: true + + /@vuepress/plugin-sitemap@2.0.0-rc.104(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-pisuHpJoM/b0jhP/LgnLeqbiCIyPBIzzN5SpZa6ivB+gt3hKqHxki/gE4GwgrlY/VrUkq2gOss9+LwHFyY7iGw==} + peerDependencies: + vuepress: 2.0.0-rc.23 + dependencies: + '@vuepress/helper': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + sitemap: 8.0.0 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript + dev: true + + /@vuepress/plugin-slimsearch@2.0.0-rc.106(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-bybriFMkazqK3gPBoEO2w2jNLO5ko+78kpIJ//BrfEXQ3VfSnLv5buEjQLAxwm9JboBteNYD+vCTn7iEdm6ZCw==} + peerDependencies: + vuepress: 2.0.0-rc.23 dependencies: - '@mdit-vue/types': 2.1.0 + '@vuepress/helper': 2.0.0-rc.106(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + cheerio: 1.0.0 + chokidar: 3.6.0 + slimsearch: 2.2.2 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript dev: true - /@vuepress/utils@2.0.0-rc.9: - resolution: {integrity: sha512-qk6Pel4JVKYKxp3bWxyvnwchvx3QaCWc7SqUw7L6qUo/um+0U2U45L0anWoAfckw12RXYhoIEbJ9UZpueiKOPg==} + /@vuepress/plugin-theme-data@2.0.0-rc.103(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-pHkCf7VZJDlVVE+LkDTmHMTdDxYkaUTNbglgTI1QoTq8cMpOb/M8BaBDtb8//DC2gbNTgx/x6wsPogwm0K45+w==} + peerDependencies: + vuepress: 2.0.0-rc.23 + dependencies: + '@vue/devtools-api': 7.7.6 + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + transitivePeerDependencies: + - typescript + dev: true + + /@vuepress/shared@2.0.0-rc.23: + resolution: {integrity: sha512-keUT4ZXVN0LvNWRxDOSjvyePZHoAmedVQvFqFWfH/3JjzLU1nrhn+WXucNtlJh6OqZZD5sdzCxnrotkb7MEnVw==} + dependencies: + '@mdit-vue/types': 2.1.4 + dev: true + + /@vuepress/utils@2.0.0-rc.23: + resolution: {integrity: sha512-nuert5yo58GS5g9UVGNPY3xCLuob1jg7p5t9gYThUIjWp4treFJZDgV8YGbrhmNxrvrS5pWyC9HYMTWRDdO98A==} dependencies: '@types/debug': 4.1.12 '@types/fs-extra': 11.0.4 '@types/hash-sum': 1.0.2 - '@vuepress/shared': 2.0.0-rc.9 - debug: 4.3.5 - fs-extra: 11.2.0 - globby: 14.0.1 + '@vuepress/shared': 2.0.0-rc.23 + debug: 4.4.1 + fs-extra: 11.3.0 + globby: 14.1.0 hash-sum: 2.0.0 - ora: 8.0.1 - picocolors: 1.0.1 + ora: 8.2.0 + picocolors: 1.1.1 upath: 2.0.1 transitivePeerDependencies: - supports-color dev: true - /@vueuse/core@10.11.0(vue@3.4.30): - resolution: {integrity: sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g==} + /@vueuse/core@11.3.0(vue@3.5.15): + resolution: {integrity: sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==} dependencies: '@types/web-bluetooth': 0.0.20 - '@vueuse/metadata': 10.11.0 - '@vueuse/shared': 10.11.0(vue@3.4.30) - vue-demi: 0.14.8(vue@3.4.30) + '@vueuse/metadata': 11.3.0 + '@vueuse/shared': 11.3.0(vue@3.5.15) + vue-demi: 0.14.10(vue@3.5.15) transitivePeerDependencies: - '@vue/composition-api' - vue dev: true - /@vueuse/metadata@10.11.0: - resolution: {integrity: sha512-kQX7l6l8dVWNqlqyN3ePW3KmjCQO3ZMgXuBMddIu83CmucrsBfXlH+JoviYyRBws/yLTQO8g3Pbw+bdIoVm4oQ==} + /@vueuse/core@13.2.0(vue@3.5.15): + resolution: {integrity: sha512-n5TZoIAxbWAQ3PqdVPDzLgIRQOujFfMlatdI+f7ditSmoEeNpPBvp7h2zamzikCmrhFIePAwdEQB6ENccHr7Rg==} + peerDependencies: + vue: ^3.5.0 + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.2.0 + '@vueuse/shared': 13.2.0(vue@3.5.15) + vue: 3.5.15 dev: true - /@vueuse/shared@10.11.0(vue@3.4.30): - resolution: {integrity: sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==} + /@vueuse/metadata@11.3.0: + resolution: {integrity: sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==} + dev: true + + /@vueuse/metadata@13.2.0: + resolution: {integrity: sha512-kPpzuQCU0+D8DZCzK0iPpIcXI+6ufWSgwnjJ6//GNpEn+SHViaCtR+XurzORChSgvpHO9YC8gGM97Y1kB+UabA==} + dev: true + + /@vueuse/shared@11.3.0(vue@3.5.15): + resolution: {integrity: sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==} dependencies: - vue-demi: 0.14.8(vue@3.4.30) + vue-demi: 0.14.10(vue@3.5.15) transitivePeerDependencies: - '@vue/composition-api' - vue dev: true + /@vueuse/shared@13.2.0(vue@3.5.15): + resolution: {integrity: sha512-vx9ZPDF5HcU9up3Jgt3G62dMUfZEdk6tLyBAHYAG4F4n73vpaA7J5hdncDI/lS9Vm7GA/FPlbOmh9TrDZROTpg==} + peerDependencies: + vue: ^3.5.0 + dependencies: + vue: 3.5.15 + dev: true + + /acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} dev: true - /ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + /ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} dev: true @@ -1423,29 +2279,33 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /autoprefixer@10.4.19(postcss@8.4.38): - resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} + /autoprefixer@10.4.21(postcss@8.5.3): + resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: postcss: ^8.1.0 dependencies: - browserslist: 4.23.1 - caniuse-lite: 1.0.30001638 + browserslist: 4.24.5 + caniuse-lite: 1.0.30001718 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.0.1 - postcss: 8.4.38 + picocolors: 1.1.1 + postcss: 8.5.3 postcss-value-parser: 4.2.0 dev: true + /bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + dev: true + /balloon-css@1.2.0: resolution: {integrity: sha512-urXwkHgwp6GsXVF+it01485Z2Cj4pnW02ICnM0TemOlkKmCNnDLmyy+ZZiRXBpwldUXO+aRNr7Hdia4CBvXJ5A==} dev: true - /bcrypt-ts@5.0.2: - resolution: {integrity: sha512-gDwQ5784AkkfhHACh3jGcg1hUubyZyeq9AtVd5gXkcyHGVOC+mORjRIHSj+fHfqwY5vxwyBLXQpcfk8MpK0ROg==} - engines: {node: '>=18'} + /bcrypt-ts@7.0.0: + resolution: {integrity: sha512-JMr30sbKPwF+2TccaNOYJuDx+nCmnTvHGB2rwkj+To/xZhBTX9f8zpTqGy3kpkS26KWOEYPsQlOJ5MVD00RHQQ==} + engines: {node: '>=20'} dev: true /binary-extensions@2.3.0: @@ -1453,6 +2313,10 @@ packages: engines: {node: '>=8'} dev: true + /birpc@2.3.0: + resolution: {integrity: sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==} + dev: true + /boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: true @@ -1464,15 +2328,19 @@ packages: fill-range: 7.1.1 dev: true - /browserslist@4.23.1: - resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} + /browserslist@4.24.5: + resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001638 - electron-to-chromium: 1.4.812 - node-releases: 2.0.14 - update-browserslist-db: 1.0.16(browserslist@4.23.1) + caniuse-lite: 1.0.30001718 + electron-to-chromium: 1.5.157 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.24.5) + dev: true + + /buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} dev: true /cac@6.7.14: @@ -1485,24 +2353,32 @@ packages: engines: {node: '>=6'} dev: true - /caniuse-lite@1.0.30001638: - resolution: {integrity: sha512-5SuJUJ7cZnhPpeLHaH0c/HPAnAHZvS6ElWyHK9GSIbVOQABLzowiI2pjmpvZ1WEbkyz46iFd4UXlOHR5SqgfMQ==} + /caniuse-lite@1.0.30001718: + resolution: {integrity: sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==} + dev: true + + /ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} dev: true - /chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + /chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} dev: true - /character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + /character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + dev: true + + /character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} dev: true - /chart.js@4.4.3: - resolution: {integrity: sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==} + /chart.js@4.4.9: + resolution: {integrity: sha512-EyZ9wWKgpAU0fLJ43YAEIF8sr5F2W3LqbS40ZJyHIner2lY14ufqv2VMp69MAiZ2rpwxEUxEhIH/0U3xyRynxg==} engines: {pnpm: '>=8'} dependencies: - '@kurkle/color': 0.3.2 + '@kurkle/color': 0.3.4 /cheerio-select@2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} @@ -1512,20 +2388,44 @@ packages: css-what: 6.1.0 domelementtype: 2.3.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 dev: true - /cheerio@1.0.0-rc.12: - resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} - engines: {node: '>= 6'} + /cheerio@1.0.0: + resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} + engines: {node: '>=18.17'} dependencies: cheerio-select: 2.1.0 dom-serializer: 2.0.0 domhandler: 5.0.3 - domutils: 3.1.0 - htmlparser2: 8.0.2 - parse5: 7.1.2 - parse5-htmlparser2-tree-adapter: 7.0.0 + domutils: 3.2.2 + encoding-sniffer: 0.2.0 + htmlparser2: 9.1.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 6.21.3 + whatwg-mimetype: 4.0.0 + dev: true + + /chevrotain-allstar@0.3.1(chevrotain@11.0.3): + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + dependencies: + chevrotain: 11.0.3 + lodash-es: 4.17.21 + dev: true + + /chevrotain@11.0.3: + resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + dependencies: + '@chevrotain/cst-dts-gen': 11.0.3 + '@chevrotain/gast': 11.0.3 + '@chevrotain/regexp-to-ast': 11.0.3 + '@chevrotain/types': 11.0.3 + '@chevrotain/utils': 11.0.3 + lodash-es: 4.17.21 dev: true /chokidar@3.6.0: @@ -1543,11 +2443,18 @@ packages: fsevents: 2.3.3 dev: true - /cli-cursor@4.0.0: - resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + /chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} dependencies: - restore-cursor: 4.0.0 + readdirp: 4.1.2 + dev: true + + /cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + dependencies: + restore-cursor: 5.1.0 dev: true /cli-spinners@2.9.2: @@ -1574,6 +2481,19 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + dev: true + + /comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + dev: true + + /commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + dev: true + /commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} @@ -1584,28 +2504,41 @@ packages: engines: {node: '>= 12'} dev: true + /confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + dev: true + + /confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + dev: true + /connect-history-api-fallback@2.0.0: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} dev: true + /copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + dependencies: + is-what: 4.1.16 + dev: true + /cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} dependencies: layout-base: 1.0.2 dev: true - /create-codepen@1.0.1: - resolution: {integrity: sha512-XzSWwGCFNeOnNGp3KdCDGaKq4Cp1SvjzpPGQqO0tj1HT3BhksLdl/xQ2ZEY4+0MQ3m1I/K1Fvpm4GGMthtamyA==} + /cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + dependencies: + layout-base: 2.0.1 dev: true - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 + /create-codepen@2.0.0: + resolution: {integrity: sha512-ehJ0Zw5RSV2G4+/azUb7vEZWRSA/K9cW7HDock1Y9ViDexkgSJUZJRcObdw/YAWeXKjreEQV9l/igNSsJ1yw5A==} + engines: {node: '>=18'} dev: true /css-select@5.1.0: @@ -1614,7 +2547,7 @@ packages: boolbase: 1.0.0 css-what: 6.1.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 nth-check: 2.1.1 dev: true @@ -1627,17 +2560,26 @@ packages: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} dev: true - /cytoscape-cose-bilkent@4.1.0(cytoscape@3.30.0): + /cytoscape-cose-bilkent@4.1.0(cytoscape@3.32.0): resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} peerDependencies: cytoscape: ^3.2.0 dependencies: cose-base: 1.0.3 - cytoscape: 3.30.0 + cytoscape: 3.32.0 dev: true - /cytoscape@3.30.0: - resolution: {integrity: sha512-l590mjTHT6/Cbxp13dGPC2Y7VXdgc+rUeF8AnF/JPzhjNevbDJfObnJgaSjlldOgBQZbue+X6IUZ7r5GAgvauQ==} + /cytoscape-fcose@2.2.0(cytoscape@3.32.0): + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + dependencies: + cose-base: 2.2.0 + cytoscape: 3.32.0 + dev: true + + /cytoscape@3.32.0: + resolution: {integrity: sha512-5JHBC9n75kz5851jeklCPmZWcg3hUe6sjqJvyk3+hVqFaKcHwHgxsjeN1yLmggoUc6STbtm9/NQyabQehfjvWQ==} engines: {node: '>=0.10'} dev: true @@ -1912,19 +2854,19 @@ packages: d3-zoom: 3.0.0 dev: true - /dagre-d3-es@7.0.10: - resolution: {integrity: sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==} + /dagre-d3-es@7.0.11: + resolution: {integrity: sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==} dependencies: d3: 7.9.0 lodash-es: 4.17.21 dev: true - /dayjs@1.11.11: - resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==} + /dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} dev: true - /debug@4.3.5: - resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + /debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -1932,7 +2874,7 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 + ms: 2.1.3 dev: true /decamelize@1.2.0: @@ -1940,12 +2882,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /decode-named-character-reference@1.0.2: - resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} - dependencies: - character-entities: 2.0.2 - dev: true - /delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} dependencies: @@ -1957,9 +2893,17 @@ packages: engines: {node: '>=6'} dev: true - /diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} - engines: {node: '>=0.3.1'} + /detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + dev: true + optional: true + + /devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dependencies: + dequal: 2.0.3 dev: true /dijkstrajs@1.0.3: @@ -1985,36 +2929,37 @@ packages: domelementtype: 2.3.0 dev: true - /dompurify@3.1.5: - resolution: {integrity: sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA==} + /dompurify@3.2.6: + resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==} + optionalDependencies: + '@types/trusted-types': 2.0.7 dev: true - /domutils@3.1.0: - resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + /domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 dev: true - /electron-to-chromium@1.4.812: - resolution: {integrity: sha512-7L8fC2Ey/b6SePDFKR2zHAy4mbdp1/38Yk5TsARO66W3hC5KEaeKMMHoxwtuH+jcu2AYLSn9QX04i95t6Fl1Hg==} - dev: true - - /elkjs@0.9.3: - resolution: {integrity: sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==} + /electron-to-chromium@1.5.157: + resolution: {integrity: sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w==} dev: true - /emoji-regex@10.3.0: - resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + /emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} dev: true /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true - /encode-utf8@1.0.3: - resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + /encoding-sniffer@0.2.0: + resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 dev: true /entities@4.5.0: @@ -2022,45 +2967,52 @@ packages: engines: {node: '>=0.12'} dev: true - /envinfo@7.13.0: - resolution: {integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==} + /entities@6.0.0: + resolution: {integrity: sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==} + engines: {node: '>=0.12'} + dev: true + + /envinfo@7.14.0: + resolution: {integrity: sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==} engines: {node: '>=4'} hasBin: true dev: true - /esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} - engines: {node: '>=12'} + /esbuild@0.25.4: + resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} + engines: {node: '>=18'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 - dev: true - - /escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + '@esbuild/aix-ppc64': 0.25.4 + '@esbuild/android-arm': 0.25.4 + '@esbuild/android-arm64': 0.25.4 + '@esbuild/android-x64': 0.25.4 + '@esbuild/darwin-arm64': 0.25.4 + '@esbuild/darwin-x64': 0.25.4 + '@esbuild/freebsd-arm64': 0.25.4 + '@esbuild/freebsd-x64': 0.25.4 + '@esbuild/linux-arm': 0.25.4 + '@esbuild/linux-arm64': 0.25.4 + '@esbuild/linux-ia32': 0.25.4 + '@esbuild/linux-loong64': 0.25.4 + '@esbuild/linux-mips64el': 0.25.4 + '@esbuild/linux-ppc64': 0.25.4 + '@esbuild/linux-riscv64': 0.25.4 + '@esbuild/linux-s390x': 0.25.4 + '@esbuild/linux-x64': 0.25.4 + '@esbuild/netbsd-arm64': 0.25.4 + '@esbuild/netbsd-x64': 0.25.4 + '@esbuild/openbsd-arm64': 0.25.4 + '@esbuild/openbsd-x64': 0.25.4 + '@esbuild/sunos-x64': 0.25.4 + '@esbuild/win32-arm64': 0.25.4 + '@esbuild/win32-ia32': 0.25.4 + '@esbuild/win32-x64': 0.25.4 + dev: true + + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} dev: true @@ -2074,19 +3026,8 @@ packages: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true - /execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 + /exsolve@1.0.5: + resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==} dev: true /extend-shallow@2.0.1: @@ -2096,21 +3037,36 @@ packages: is-extendable: 0.1.1 dev: true - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: true + + /fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.8 dev: true - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + /fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} dependencies: - reusify: 1.0.4 + reusify: 1.1.0 + dev: true + + /fdir@6.4.4(picomatch@4.0.2): + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + dependencies: + picomatch: 4.0.2 dev: true /fflate@0.8.2: @@ -2136,8 +3092,8 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true - /fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + /fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} engines: {node: '>=14.14'} dependencies: graceful-fs: 4.2.11 @@ -2149,7 +3105,6 @@ packages: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - requiresBuild: true dev: true optional: true @@ -2158,20 +3113,15 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true - /get-east-asian-width@1.2.0: - resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + /get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} engines: {node: '>=18'} dev: true - /get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - dev: true - - /giscus@1.5.0: - resolution: {integrity: sha512-t3LL0qbSO3JXq3uyQeKpF5CegstGfKX/0gI6eDe1cmnI7D56R7j52yLdzw4pdKrg3VnufwCgCM3FDz7G1Qr6lg==} + /giscus@1.6.0: + resolution: {integrity: sha512-Zrsi8r4t1LVW950keaWcsURuZUQwUaMKjvJgTCY125vkW6OiEBkatE7ScJDbpqKHdZwb///7FVC21SE3iFK3PQ==} dependencies: - lit: 3.1.4 + lit: 3.3.0 dev: true /glob-parent@5.1.2: @@ -2181,50 +3131,137 @@ packages: is-glob: 4.0.3 dev: true - /globby@14.0.1: - resolution: {integrity: sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==} + /globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + dev: true + + /globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} engines: {node: '>=18'} dependencies: '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.2 - ignore: 5.3.1 - path-type: 5.0.0 + fast-glob: 3.3.3 + ignore: 7.0.4 + path-type: 6.0.0 slash: 5.1.0 - unicorn-magic: 0.1.0 + unicorn-magic: 0.3.0 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + + /gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + dependencies: + js-yaml: 3.14.1 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + dev: true + + /hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + dev: true + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /hash-sum@2.0.0: + resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} + dev: true + + /hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.2 + dev: true + + /hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + dev: true + + /hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + dependencies: + '@types/hast': 3.0.4 + dev: true + + /hast-util-sanitize@5.0.2: + resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==} + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.0 + unist-util-position: 5.0.0 + dev: true + + /hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 dev: true - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + /hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + dependencies: + '@types/hast': 3.0.4 dev: true - /gray-matter@4.0.3: - resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} - engines: {node: '>=6.0'} + /hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} dependencies: - js-yaml: 3.14.1 - kind-of: 6.0.3 - section-matter: 1.0.0 - strip-bom-string: 1.0.0 + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 dev: true - /hash-sum@2.0.0: - resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} + /hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + dev: true + + /html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} dev: true - /htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + /htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 entities: 4.5.0 dev: true - /human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - dev: true - /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -2232,13 +3269,13 @@ packages: safer-buffer: 2.1.2 dev: true - /ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + /ignore@7.0.4: + resolution: {integrity: sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==} engines: {node: '>= 4'} dev: true - /immutable@4.3.6: - resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==} + /immutable@5.1.2: + resolution: {integrity: sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ==} dev: true /internmap@1.0.1: @@ -2289,9 +3326,9 @@ packages: engines: {node: '>=0.12.0'} dev: true - /is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + /is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} dev: true /is-unicode-supported@1.3.0: @@ -2299,13 +3336,14 @@ packages: engines: {node: '>=12'} dev: true - /is-unicode-supported@2.0.0: - resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==} + /is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} dev: true - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} dev: true /js-yaml@3.14.1: @@ -2331,8 +3369,8 @@ packages: graceful-fs: 4.2.11 dev: true - /katex@0.16.10: - resolution: {integrity: sha512-ZiqaC04tp2O5utMsl2TEZTXxa6WSC4yo0fv5ML++D3QZv/vx2Mct0mTlRx3O+uUkjfuAgOkzsCmq5MiUEsDDdA==} + /katex@0.16.22: + resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==} hasBin: true dependencies: commander: 8.3.0 @@ -2347,17 +3385,31 @@ packages: engines: {node: '>=0.10.0'} dev: true - /kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} + /kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + dev: true + + /langium@3.3.1: + resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==} + engines: {node: '>=16.0.0'} + dependencies: + chevrotain: 11.0.3 + chevrotain-allstar: 0.3.1(chevrotain@11.0.3) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 dev: true /layout-base@1.0.2: resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} dev: true - /lilconfig@3.1.2: - resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + /layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + dev: true + + /lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} dev: true @@ -2367,26 +3419,35 @@ packages: uc.micro: 2.1.0 dev: true - /lit-element@4.0.6: - resolution: {integrity: sha512-U4sdJ3CSQip7sLGZ/uJskO5hGiqtlpxndsLr6mt3IQIjheg93UKYeGQjWMRql1s/cXNOaRrCzC2FQwjIwSUqkg==} + /lit-element@4.2.0: + resolution: {integrity: sha512-MGrXJVAI5x+Bfth/pU9Kst1iWID6GHDLEzFEnyULB/sFiRLgkd8NPK/PeeXxktA3T6EIIaq8U3KcbTU5XFcP2Q==} dependencies: - '@lit-labs/ssr-dom-shim': 1.2.0 - '@lit/reactive-element': 2.0.4 - lit-html: 3.1.4 + '@lit-labs/ssr-dom-shim': 1.3.0 + '@lit/reactive-element': 2.1.0 + lit-html: 3.3.0 dev: true - /lit-html@3.1.4: - resolution: {integrity: sha512-yKKO2uVv7zYFHlWMfZmqc+4hkmSbFp8jgjdZY9vvR9jr4J8fH6FUMXhr+ljfELgmjpvlF7Z1SJ5n5/Jeqtc9YA==} + /lit-html@3.3.0: + resolution: {integrity: sha512-RHoswrFAxY2d8Cf2mm4OZ1DgzCoBKUKSPvA1fhtSELxUERq2aQQ2h05pO9j81gS1o7RIRJ+CePLogfyahwmynw==} dependencies: '@types/trusted-types': 2.0.7 dev: true - /lit@3.1.4: - resolution: {integrity: sha512-q6qKnKXHy2g1kjBaNfcoLlgbI3+aSOZ9Q4tiGa9bGYXq5RBXxkVTqTIVmP2VWMp29L4GyvCFm8ZQ2o56eUAMyA==} + /lit@3.3.0: + resolution: {integrity: sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==} dependencies: - '@lit/reactive-element': 2.0.4 - lit-element: 4.0.6 - lit-html: 3.1.4 + '@lit/reactive-element': 2.1.0 + lit-element: 4.2.0 + lit-html: 3.3.0 + dev: true + + /local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + engines: {node: '>=14'} + dependencies: + mlly: 1.7.4 + pkg-types: 2.1.0 + quansync: 0.2.10 dev: true /locate-path@5.0.0: @@ -2404,23 +3465,23 @@ packages: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} dependencies: - chalk: 5.3.0 + chalk: 5.4.1 is-unicode-supported: 1.3.0 dev: true - /magic-string@0.30.10: - resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + /magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 dev: true - /markdown-it-anchor@8.6.7(@types/markdown-it@13.0.8)(markdown-it@14.1.0): - resolution: {integrity: sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==} + /markdown-it-anchor@9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0): + resolution: {integrity: sha512-sa2ErMQ6kKOA4l31gLGYliFQrMKkqSO0ZJgGhDHKijPf0pNFM9vghjAh3gn26pS4JDRs7Iwa9S36gxm3vgZTzg==} peerDependencies: '@types/markdown-it': '*' markdown-it: '*' dependencies: - '@types/markdown-it': 13.0.8 + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 dev: true @@ -2440,289 +3501,142 @@ packages: uc.micro: 2.1.0 dev: true - /mdast-util-from-markdown@1.3.1: - resolution: {integrity: sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==} - dependencies: - '@types/mdast': 3.0.15 - '@types/unist': 2.0.10 - decode-named-character-reference: 1.0.2 - mdast-util-to-string: 3.2.0 - micromark: 3.2.0 - micromark-util-decode-numeric-character-reference: 1.1.0 - micromark-util-decode-string: 1.1.0 - micromark-util-normalize-identifier: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - unist-util-stringify-position: 3.0.3 - uvu: 0.5.6 - transitivePeerDependencies: - - supports-color + /marked@15.0.12: + resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} + engines: {node: '>= 18'} + hasBin: true dev: true - /mdast-util-to-string@3.2.0: - resolution: {integrity: sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==} + /mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} dependencies: - '@types/mdast': 3.0.15 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 dev: true /mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} dev: true - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} dev: true - /mermaid@10.9.1: - resolution: {integrity: sha512-Mx45Obds5W1UkW1nv/7dHRsbfMM1aOKA2+Pxs/IGHNonygDHwmng8xTHyS9z4KWVi0rbko8gjiBmuwwXQ7tiNA==} + /mermaid@11.6.0: + resolution: {integrity: sha512-PE8hGUy1LDlWIHWBP05SFdqUHGmRcCcK4IzpOKPE35eOw+G9zZgcnMpyunJVUEOgb//KBORPjysKndw8bFLuRg==} dependencies: - '@braintree/sanitize-url': 6.0.4 - '@types/d3-scale': 4.0.8 - '@types/d3-scale-chromatic': 3.0.3 - cytoscape: 3.30.0 - cytoscape-cose-bilkent: 4.1.0(cytoscape@3.30.0) + '@braintree/sanitize-url': 7.1.1 + '@iconify/utils': 2.3.0 + '@mermaid-js/parser': 0.4.0 + '@types/d3': 7.4.3 + cytoscape: 3.32.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.32.0) + cytoscape-fcose: 2.2.0(cytoscape@3.32.0) d3: 7.9.0 d3-sankey: 0.12.3 - dagre-d3-es: 7.0.10 - dayjs: 1.11.11 - dompurify: 3.1.5 - elkjs: 0.9.3 - katex: 0.16.10 + dagre-d3-es: 7.0.11 + dayjs: 1.11.13 + dompurify: 3.2.6 + katex: 0.16.22 khroma: 2.1.0 lodash-es: 4.17.21 - mdast-util-from-markdown: 1.3.1 - non-layered-tidy-tree-layout: 2.0.2 - stylis: 4.3.2 + marked: 15.0.12 + roughjs: 4.6.6 + stylis: 4.3.6 ts-dedent: 2.2.0 - uuid: 9.0.1 - web-worker: 1.3.0 + uuid: 11.1.0 transitivePeerDependencies: - supports-color dev: true - /micromark-core-commonmark@1.1.0: - resolution: {integrity: sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==} - dependencies: - decode-named-character-reference: 1.0.2 - micromark-factory-destination: 1.1.0 - micromark-factory-label: 1.1.0 - micromark-factory-space: 1.1.0 - micromark-factory-title: 1.1.0 - micromark-factory-whitespace: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-chunked: 1.1.0 - micromark-util-classify-character: 1.1.0 - micromark-util-html-tag-name: 1.2.0 - micromark-util-normalize-identifier: 1.1.0 - micromark-util-resolve-all: 1.1.0 - micromark-util-subtokenize: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - dev: true - - /micromark-factory-destination@1.1.0: - resolution: {integrity: sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==} - dependencies: - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - dev: true - - /micromark-factory-label@1.1.0: - resolution: {integrity: sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==} - dependencies: - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - dev: true - - /micromark-factory-space@1.1.0: - resolution: {integrity: sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==} - dependencies: - micromark-util-character: 1.2.0 - micromark-util-types: 1.1.0 - dev: true - - /micromark-factory-title@1.1.0: - resolution: {integrity: sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==} - dependencies: - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - dev: true - - /micromark-factory-whitespace@1.1.0: - resolution: {integrity: sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==} - dependencies: - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - dev: true - - /micromark-util-character@1.2.0: - resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==} - dependencies: - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - dev: true - - /micromark-util-chunked@1.1.0: - resolution: {integrity: sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==} - dependencies: - micromark-util-symbol: 1.1.0 - dev: true - - /micromark-util-classify-character@1.1.0: - resolution: {integrity: sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==} - dependencies: - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - dev: true - - /micromark-util-combine-extensions@1.1.0: - resolution: {integrity: sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==} - dependencies: - micromark-util-chunked: 1.1.0 - micromark-util-types: 1.1.0 - dev: true - - /micromark-util-decode-numeric-character-reference@1.1.0: - resolution: {integrity: sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==} + /micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} dependencies: - micromark-util-symbol: 1.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 dev: true - /micromark-util-decode-string@1.1.0: - resolution: {integrity: sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==} - dependencies: - decode-named-character-reference: 1.0.2 - micromark-util-character: 1.2.0 - micromark-util-decode-numeric-character-reference: 1.1.0 - micromark-util-symbol: 1.1.0 - dev: true - - /micromark-util-encode@1.1.0: - resolution: {integrity: sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==} - dev: true - - /micromark-util-html-tag-name@1.2.0: - resolution: {integrity: sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==} - dev: true - - /micromark-util-normalize-identifier@1.1.0: - resolution: {integrity: sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==} - dependencies: - micromark-util-symbol: 1.1.0 + /micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} dev: true - /micromark-util-resolve-all@1.1.0: - resolution: {integrity: sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==} + /micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} dependencies: - micromark-util-types: 1.1.0 - dev: true - - /micromark-util-sanitize-uri@1.2.0: - resolution: {integrity: sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==} - dependencies: - micromark-util-character: 1.2.0 - micromark-util-encode: 1.1.0 - micromark-util-symbol: 1.1.0 - dev: true - - /micromark-util-subtokenize@1.1.0: - resolution: {integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==} - dependencies: - micromark-util-chunked: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - dev: true - - /micromark-util-symbol@1.1.0: - resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==} + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 dev: true - /micromark-util-types@1.1.0: - resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==} + /micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} dev: true - /micromark@3.2.0: - resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==} - dependencies: - '@types/debug': 4.1.12 - debug: 4.3.5 - decode-named-character-reference: 1.0.2 - micromark-core-commonmark: 1.1.0 - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-chunked: 1.1.0 - micromark-util-combine-extensions: 1.1.0 - micromark-util-decode-numeric-character-reference: 1.1.0 - micromark-util-encode: 1.1.0 - micromark-util-normalize-identifier: 1.1.0 - micromark-util-resolve-all: 1.1.0 - micromark-util-sanitize-uri: 1.2.0 - micromark-util-subtokenize: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - transitivePeerDependencies: - - supports-color + /micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} dev: true - /micromatch@4.0.7: - resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + /micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} dependencies: braces: 3.0.3 picomatch: 2.3.1 dev: true - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} + /mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} dev: true - /mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} dev: true - /mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} + /mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + dependencies: + acorn: 8.14.1 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 dev: true - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true - /nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + /nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true dev: true + /nanoid@5.1.5: + resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} + engines: {node: ^18 || >=20} + hasBin: true + dev: true + /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true - /node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + /node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} dev: true + optional: true - /non-layered-tidy-tree-layout@2.0.2: - resolution: {integrity: sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==} + /node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} dev: true /normalize-path@3.0.0: @@ -2735,45 +3649,43 @@ packages: engines: {node: '>=0.10.0'} dev: true - /npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - path-key: 4.0.0 - dev: true - /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: boolbase: 1.0.0 dev: true - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + /onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} dependencies: - mimic-fn: 2.1.0 + mimic-function: 5.0.1 dev: true - /onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} + /oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + dev: true + + /oniguruma-to-es@4.3.3: + resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==} dependencies: - mimic-fn: 4.0.0 + oniguruma-parser: 0.12.1 + regex: 6.0.1 + regex-recursion: 6.0.2 dev: true - /ora@8.0.1: - resolution: {integrity: sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==} + /ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} dependencies: - chalk: 5.3.0 - cli-cursor: 4.0.0 + chalk: 5.4.1 + cli-cursor: 5.0.0 cli-spinners: 2.9.2 is-interactive: 2.0.0 - is-unicode-supported: 2.0.0 + is-unicode-supported: 2.1.0 log-symbols: 6.0.0 stdin-discarder: 0.2.2 - string-width: 7.1.0 + string-width: 7.2.0 strip-ansi: 7.1.0 dev: true @@ -2796,17 +3708,31 @@ packages: engines: {node: '>=6'} dev: true - /parse5-htmlparser2-tree-adapter@7.0.0: - resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} + /package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + dev: true + + /parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} dependencies: domhandler: 5.0.3 - parse5: 7.1.2 + parse5: 7.3.0 dev: true - /parse5@7.1.2: - resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + /parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} dependencies: - entities: 4.5.0 + parse5: 7.3.0 + dev: true + + /parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + dependencies: + entities: 6.0.0 + dev: true + + /path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} dev: true /path-exists@4.0.0: @@ -2814,19 +3740,17 @@ packages: engines: {node: '>=8'} dev: true - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} + /path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} dev: true - /path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} + /pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} dev: true - /path-type@5.0.0: - resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} - engines: {node: '>=12'} + /perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} dev: true /photoswipe@5.4.4: @@ -2834,8 +3758,8 @@ packages: engines: {node: '>= 0.12.0'} dev: true - /picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} dev: true /picomatch@2.3.1: @@ -2843,18 +3767,51 @@ packages: engines: {node: '>=8.6'} dev: true + /picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: true + + /pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + dev: true + + /pkg-types@2.1.0: + resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} + dependencies: + confbox: 0.2.2 + exsolve: 1.0.5 + pathe: 2.0.3 + dev: true + /pngjs@5.0.0: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} engines: {node: '>=10.13.0'} dev: true - /postcss-load-config@5.1.0(postcss@8.4.38): - resolution: {integrity: sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==} + /points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + dev: true + + /points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + dev: true + + /postcss-load-config@6.0.1(postcss@8.5.3): + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} peerDependencies: jiti: '>=1.21.0' postcss: '>=8.0.9' tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: jiti: optional: true @@ -2862,28 +3819,28 @@ packages: optional: true tsx: optional: true + yaml: + optional: true dependencies: - lilconfig: 3.1.2 - postcss: 8.4.38 - yaml: 2.4.5 + lilconfig: 3.1.3 + postcss: 8.5.3 dev: true /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true - /postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + /postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 dev: true - /prismjs@1.29.0: - resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} - engines: {node: '>=6'} + /property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} dev: true /punycode.js@2.3.1: @@ -2891,103 +3848,362 @@ packages: engines: {node: '>=6'} dev: true - /qrcode@1.5.3: - resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} + /qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} engines: {node: '>=10.13.0'} hasBin: true dependencies: dijkstrajs: 1.0.3 - encode-utf8: 1.0.3 pngjs: 5.0.0 yargs: 15.4.1 dev: true + /quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + dev: true + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + dev: true + + /regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + dependencies: + regex-utilities: 2.3.0 + dev: true + + /regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + dev: true + + /regex@6.0.1: + resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} + dependencies: + regex-utilities: 2.3.0 + dev: true + + /rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + dev: true + + /rehype-sanitize@6.0.0: + resolution: {integrity: sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==} + dependencies: + '@types/hast': 3.0.4 + hast-util-sanitize: 5.0.2 + dev: true + + /rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: true + + /restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + dev: true + + /reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + dev: true + + /robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + dev: true + + /rollup@4.41.1: + resolution: {integrity: sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.7 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.41.1 + '@rollup/rollup-android-arm64': 4.41.1 + '@rollup/rollup-darwin-arm64': 4.41.1 + '@rollup/rollup-darwin-x64': 4.41.1 + '@rollup/rollup-freebsd-arm64': 4.41.1 + '@rollup/rollup-freebsd-x64': 4.41.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.41.1 + '@rollup/rollup-linux-arm-musleabihf': 4.41.1 + '@rollup/rollup-linux-arm64-gnu': 4.41.1 + '@rollup/rollup-linux-arm64-musl': 4.41.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.41.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.41.1 + '@rollup/rollup-linux-riscv64-gnu': 4.41.1 + '@rollup/rollup-linux-riscv64-musl': 4.41.1 + '@rollup/rollup-linux-s390x-gnu': 4.41.1 + '@rollup/rollup-linux-x64-gnu': 4.41.1 + '@rollup/rollup-linux-x64-musl': 4.41.1 + '@rollup/rollup-win32-arm64-msvc': 4.41.1 + '@rollup/rollup-win32-ia32-msvc': 4.41.1 + '@rollup/rollup-win32-x64-msvc': 4.41.1 + fsevents: 2.3.3 + dev: true + + /roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + dev: true + + /rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + dependencies: + tslib: 2.8.1 + dev: true + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /sass-embedded-android-arm64@1.89.0: + resolution: {integrity: sha512-pr4R3p5R+Ul9ZA5nzYbBJQFJXW6dMGzgpNBhmaToYDgDhmNX5kg0mZAUlGLHvisLdTiR6oEfDDr9QI6tnD2nqA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + dev: true + optional: true + + /sass-embedded-android-arm@1.89.0: + resolution: {integrity: sha512-s6jxkEZQQrtyIGZX6Sbcu7tEixFG2VkqFgrX11flm/jZex7KaxnZtFace+wnYAgHqzzYpx0kNzJUpT+GXxm8CA==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + dev: true + optional: true + + /sass-embedded-android-ia32@1.89.0: + resolution: {integrity: sha512-GoNnNGYmp1F0ZMHqQbAurlQsjBMZKtDd5H60Ruq86uQFdnuNqQ9wHKJsJABxMnjfAn60IjefytM5PYTMcAmbfA==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [android] + dev: true + optional: true + + /sass-embedded-android-riscv64@1.89.0: + resolution: {integrity: sha512-di+i4KkKAWTNksaQYTqBEERv46qV/tvv14TPswEfak7vcTQ2pj2mvV4KGjLYfU2LqRkX/NTXix9KFthrzFN51Q==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + dev: true + optional: true + + /sass-embedded-android-x64@1.89.0: + resolution: {integrity: sha512-1cRRDAnmAS1wLaxfFf6PCHu9sKW8FNxdM7ZkanwxO9mztrCu/uvfqTmaurY9+RaKvPus7sGYFp46/TNtl/wRjg==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + dev: true + optional: true + + /sass-embedded-darwin-arm64@1.89.0: + resolution: {integrity: sha512-EUNUzI0UkbQ6dASPyf09S3x7fNT54PjyD594ZGTY14Yh4qTuacIj27ckLmreAJNNu5QxlbhyYuOtz+XN5bMMxA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + dev: true + optional: true + + /sass-embedded-darwin-x64@1.89.0: + resolution: {integrity: sha512-23R8zSuB31Fq/MYpmQ38UR2C26BsYb66VVpJgWmWl/N+sgv/+l9ECuSPMbYNgM3vb9TP9wk9dgL6KkiCS5tAyg==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + dev: true + optional: true + + /sass-embedded-linux-arm64@1.89.0: + resolution: {integrity: sha512-g9Lp57qyx51ttKj0AN/edV43Hu1fBObvD7LpYwVfs6u3I95r0Adi90KujzNrUqXxJVmsfUwseY8kA8zvcRjhYA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + dev: true + optional: true + + /sass-embedded-linux-arm@1.89.0: + resolution: {integrity: sha512-KAzA1XD74d8/fiJXxVnLfFwfpmD2XqUJZz+DL6ZAPNLH1sb+yCP7brktaOyClDc/MBu61JERdHaJjIZhfX0Yqw==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + dev: true + optional: true + + /sass-embedded-linux-ia32@1.89.0: + resolution: {integrity: sha512-5fxBeXyvBr3pb+vyrx9V6yd7QDRXkAPbwmFVVhjqshBABOXelLysEFea7xokh/tM8JAAQ4O8Ls3eW3Eojb477g==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] dev: true + optional: true - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} + /sass-embedded-linux-musl-arm64@1.89.0: + resolution: {integrity: sha512-50oelrOtN64u15vJN9uJryIuT0+UPjyeoq0zdWbY8F7LM9294Wf+Idea+nqDUWDCj1MHndyPFmR1mjeuRouJhw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] dev: true + optional: true - /require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + /sass-embedded-linux-musl-arm@1.89.0: + resolution: {integrity: sha512-0Q1JeEU4/tzH7fwAwarfIh+Swn3aXG/jPhVsZpbR1c1VzkeaPngmXdmLJcVXsdb35tjk84DuYcFtJlE1HYGw4Q==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] dev: true + optional: true - /restore-cursor@4.0.0: - resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 + /sass-embedded-linux-musl-ia32@1.89.0: + resolution: {integrity: sha512-ILWqpTd+0RdsSw977iVAJf4CLetIbcQgLQf17ycS1N4StZKVRZs1bBfZhg/f/HU/4p5HondPAwepgJepZZdnFA==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] dev: true + optional: true - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + /sass-embedded-linux-musl-riscv64@1.89.0: + resolution: {integrity: sha512-n2V+Tdjj7SAuiuElJYhWiHjjB1YU0cuFvL1/m5K+ecdNStfHFWIzvBT6/vzQnBOWjI4eZECNVuQ8GwGWCufZew==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] dev: true + optional: true - /robust-predicates@3.0.2: - resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + /sass-embedded-linux-musl-x64@1.89.0: + resolution: {integrity: sha512-KOHJdouBK3SLJKZLnFYzuxs3dn+6jaeO3p4p1JUYAcVfndcvh13Sg2sLGfOfpg7Og6ws2Nnqnx0CyL26jPJ7ag==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] dev: true + optional: true - /rollup@4.18.0: - resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.18.0 - '@rollup/rollup-android-arm64': 4.18.0 - '@rollup/rollup-darwin-arm64': 4.18.0 - '@rollup/rollup-darwin-x64': 4.18.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 - '@rollup/rollup-linux-arm-musleabihf': 4.18.0 - '@rollup/rollup-linux-arm64-gnu': 4.18.0 - '@rollup/rollup-linux-arm64-musl': 4.18.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 - '@rollup/rollup-linux-riscv64-gnu': 4.18.0 - '@rollup/rollup-linux-s390x-gnu': 4.18.0 - '@rollup/rollup-linux-x64-gnu': 4.18.0 - '@rollup/rollup-linux-x64-musl': 4.18.0 - '@rollup/rollup-win32-arm64-msvc': 4.18.0 - '@rollup/rollup-win32-ia32-msvc': 4.18.0 - '@rollup/rollup-win32-x64-msvc': 4.18.0 - fsevents: 2.3.3 + /sass-embedded-linux-riscv64@1.89.0: + resolution: {integrity: sha512-0A/UWeKX6MYhVLWLkdX3NPKHO+mvIwzaf6TxGCy3vS3TODWaeDUeBhHShAr7YlOKv5xRGxf7Gx7FXCPV0mUyMA==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] dev: true + optional: true - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 + /sass-embedded-linux-x64@1.89.0: + resolution: {integrity: sha512-dRBoOFPDWctHPYK3hTk3YzyX/icVrXiw7oOjbtpaDr6JooqIWBe16FslkWyvQzdmfOFy80raKVjgoqT7DsznkQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] dev: true + optional: true - /rw@1.3.3: - resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + /sass-embedded-win32-arm64@1.89.0: + resolution: {integrity: sha512-RnlVZ14hC/W7ubzvhqnbGfjU5PFNoFP/y5qycgCy+Mezb0IKbWvZ2Lyzux8TbL3OIjOikkNpfXoNQrX706WLAA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] dev: true + optional: true - /sade@1.8.1: - resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} - engines: {node: '>=6'} - dependencies: - mri: 1.2.0 + /sass-embedded-win32-ia32@1.89.0: + resolution: {integrity: sha512-eFe9VMNG+90nuoE3eXDy+38+uEHGf7xcqalq5+0PVZfR+H9RlaEbvIUNflZV94+LOH8Jb4lrfuekhHgWDJLfSg==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [win32] dev: true + optional: true - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + /sass-embedded-win32-x64@1.89.0: + resolution: {integrity: sha512-AaGpr5R6MLCuSvkvDdRq49ebifwLcuGPk0/10hbYw9nh3jpy2/CylYubQpIpR4yPcuD1wFwFqufTXC3HJYGb0g==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] dev: true + optional: true - /sass-loader@14.2.1: - resolution: {integrity: sha512-G0VcnMYU18a4N7VoNDegg2OuMjYtxnqzQWARVWCIVSZwJeiL9kg8QMsuIZOplsJgTzZLF6jGxI3AClj8I9nRdQ==} + /sass-embedded@1.89.0: + resolution: {integrity: sha512-EDrK1el9zdgJFpocCGlxatDWaP18tJBWoM1hxzo2KJBvjdmBichXI6O6KlQrigvQPO3uJ8DfmFmAAx7s7CG6uw==} + engines: {node: '>=16.0.0'} + hasBin: true + dependencies: + '@bufbuild/protobuf': 2.5.0 + buffer-builder: 0.2.0 + colorjs.io: 0.5.2 + immutable: 5.1.2 + rxjs: 7.8.2 + supports-color: 8.1.1 + sync-child-process: 1.0.2 + varint: 6.0.0 + optionalDependencies: + sass-embedded-android-arm: 1.89.0 + sass-embedded-android-arm64: 1.89.0 + sass-embedded-android-ia32: 1.89.0 + sass-embedded-android-riscv64: 1.89.0 + sass-embedded-android-x64: 1.89.0 + sass-embedded-darwin-arm64: 1.89.0 + sass-embedded-darwin-x64: 1.89.0 + sass-embedded-linux-arm: 1.89.0 + sass-embedded-linux-arm64: 1.89.0 + sass-embedded-linux-ia32: 1.89.0 + sass-embedded-linux-musl-arm: 1.89.0 + sass-embedded-linux-musl-arm64: 1.89.0 + sass-embedded-linux-musl-ia32: 1.89.0 + sass-embedded-linux-musl-riscv64: 1.89.0 + sass-embedded-linux-musl-x64: 1.89.0 + sass-embedded-linux-riscv64: 1.89.0 + sass-embedded-linux-x64: 1.89.0 + sass-embedded-win32-arm64: 1.89.0 + sass-embedded-win32-ia32: 1.89.0 + sass-embedded-win32-x64: 1.89.0 + dev: true + + /sass-loader@16.0.5(sass-embedded@1.89.0)(sass@1.89.0): + resolution: {integrity: sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==} engines: {node: '>= 18.12.0'} peerDependencies: '@rspack/core': 0.x || 1.x @@ -3008,16 +4224,20 @@ packages: optional: true dependencies: neo-async: 2.6.2 + sass: 1.89.0 + sass-embedded: 1.89.0 dev: true - /sass@1.77.6: - resolution: {integrity: sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==} + /sass@1.89.0: + resolution: {integrity: sha512-ld+kQU8YTdGNjOLfRWBzewJpU5cwEv/h5yyqlSeJcj6Yh8U4TDA9UA5FPicqDz/xgRPWRSYIQNiFks21TbA9KQ==} engines: {node: '>=14.0.0'} hasBin: true dependencies: - chokidar: 3.6.0 - immutable: 4.3.6 - source-map-js: 1.2.0 + chokidar: 4.0.3 + immutable: 5.1.2 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 dev: true /sax@1.4.1: @@ -3032,30 +4252,21 @@ packages: kind-of: 6.0.3 dev: true - /semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} - engines: {node: '>=10'} - hasBin: true - dev: true - /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + /shiki@3.4.2: + resolution: {integrity: sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ==} dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + '@shikijs/core': 3.4.2 + '@shikijs/engine-javascript': 3.4.2 + '@shikijs/engine-oniguruma': 3.4.2 + '@shikijs/langs': 3.4.2 + '@shikijs/themes': 3.4.2 + '@shikijs/types': 3.4.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 dev: true /signal-exit@4.1.0: @@ -3063,9 +4274,9 @@ packages: engines: {node: '>=14'} dev: true - /sitemap@7.1.2: - resolution: {integrity: sha512-ARCqzHJ0p4gWt+j7NlU5eDlIO9+Rkr/JhPFZKKQ1l5GCus7rJH4UdrlVAh0xC/gDS/Qir2UMxqYNHtsKr2rpCw==} - engines: {node: '>=12.0.0', npm: '>=5.6.0'} + /sitemap@8.0.0: + resolution: {integrity: sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A==} + engines: {node: '>=14.0.0', npm: '>=6.0.0'} hasBin: true dependencies: '@types/node': 17.0.45 @@ -3079,13 +4290,22 @@ packages: engines: {node: '>=14.16'} dev: true - /slimsearch@2.1.1: - resolution: {integrity: sha512-l1utJWal8F/RIheYk88DE2+enI12nIrn5SHt4ih/CNAH81PzkTv2GVBODlLynDJb7xan5hjd8XTL5f0L4cxLQA==} + /slimsearch@2.2.2: + resolution: {integrity: sha512-C+E3y4sKKzPzcOyty0G9CjXdLvY0ZWPSCQCDNqSv/P6+rvoL6RiHvuwr0wnxf0QgdbdyNiJQ0w7OdudHoabpCg==} engines: {node: '>=18.18.0'} dev: true - /source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + /source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + dev: true + + /space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + dev: true + + /speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} engines: {node: '>=0.10.0'} dev: true @@ -3107,15 +4327,22 @@ packages: strip-ansi: 6.0.1 dev: true - /string-width@7.1.0: - resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} + /string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} dependencies: - emoji-regex: 10.3.0 - get-east-asian-width: 1.2.0 + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 strip-ansi: 7.1.0 dev: true + /stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + dev: true + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -3127,7 +4354,7 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} dependencies: - ansi-regex: 6.0.1 + ansi-regex: 6.1.0 dev: true /strip-bom-string@1.0.0: @@ -3135,18 +4362,53 @@ packages: engines: {node: '>=0.10.0'} dev: true - /strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} + /stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + dev: true + + /superjson@2.2.2: + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + engines: {node: '>=16'} + dependencies: + copy-anything: 3.0.5 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 dev: true - /stylis@4.3.2: - resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} + /sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + dependencies: + sync-message-port: 1.1.3 dev: true - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} + /sync-message-port@1.1.3: + resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} + engines: {node: '>=16.0.0'} + dev: true + + /synckit@0.11.6: + resolution: {integrity: sha512-2pR2ubZSV64f/vqm9eLPz/KOvR9Dm+Co/5ChLgeHl0yEDRc6h5hXHoxEQH8Y5Ljycozd3p1k5TTSVdzYGkPvLw==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.2.4 + dev: true + + /tinyexec@1.0.1: + resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} + dev: true + + /tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 dev: true /to-regex-range@5.0.1: @@ -3156,28 +4418,88 @@ packages: is-number: 7.0.0 dev: true + /trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + dev: true + + /trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + dev: true + /ts-dedent@2.2.0: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} dev: true + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + dev: true + /uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} dev: true - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + /ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + dev: true + + /undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} dev: true - /unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + /undici@6.21.3: + resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==} + engines: {node: '>=18.17'} + dev: true + + /unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} dev: true - /unist-util-stringify-position@3.0.3: - resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==} + /unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + dev: true + + /unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + dependencies: + '@types/unist': 3.0.3 + dev: true + + /unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + dependencies: + '@types/unist': 3.0.3 + dev: true + + /unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + dependencies: + '@types/unist': 3.0.3 + dev: true + + /unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + dev: true + + /unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} dependencies: - '@types/unist': 2.0.10 + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 dev: true /universalify@2.0.1: @@ -3190,73 +4512,134 @@ packages: engines: {node: '>=4'} dev: true - /update-browserslist-db@1.0.16(browserslist@4.23.1): - resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + /update-browserslist-db@1.1.3(browserslist@4.24.5): + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.23.1 - escalade: 3.1.2 - picocolors: 1.0.1 + browserslist: 4.24.5 + escalade: 3.2.0 + picocolors: 1.1.1 dev: true - /uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + /uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true dev: true - /uvu@0.5.6: - resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} - engines: {node: '>=8'} - hasBin: true + /varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + dev: true + + /vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} dependencies: - dequal: 2.0.3 - diff: 5.2.0 - kleur: 4.1.5 - sade: 1.8.1 + '@types/unist': 3.0.3 + vfile: 6.0.3 dev: true - /vite@5.2.13: - resolution: {integrity: sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==} - engines: {node: ^18.0.0 || >=20.0.0} + /vfile-message@4.0.2: + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + dev: true + + /vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.2 + dev: true + + /vite@6.3.5(sass-embedded@1.89.0)(sass@1.89.0): + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' less: '*' lightningcss: ^1.21.0 sass: '*' + sass-embedded: '*' stylus: '*' sugarss: '*' - terser: ^5.4.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: '@types/node': optional: true + jiti: + optional: true less: optional: true lightningcss: optional: true sass: optional: true + sass-embedded: + optional: true stylus: optional: true sugarss: optional: true terser: optional: true + tsx: + optional: true + yaml: + optional: true dependencies: - esbuild: 0.20.2 - postcss: 8.4.38 - rollup: 4.18.0 + esbuild: 0.25.4 + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.3 + rollup: 4.41.1 + sass: 1.89.0 + sass-embedded: 1.89.0 + tinyglobby: 0.2.14 optionalDependencies: fsevents: 2.3.3 dev: true - /vue-demi@0.14.8(vue@3.4.30): - resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==} + /vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + dev: true + + /vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + dev: true + + /vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + dev: true + + /vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + dev: true + + /vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + dependencies: + vscode-languageserver-protocol: 3.17.5 + dev: true + + /vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + dev: true + + /vue-demi@0.14.10(vue@3.5.15): + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} engines: {node: '>=12'} hasBin: true - requiresBuild: true peerDependencies: '@vue/composition-api': ^1.0.0-rc.1 vue: ^3.0.0-0 || ^2.6.0 @@ -3264,44 +4647,46 @@ packages: '@vue/composition-api': optional: true dependencies: - vue: 3.4.30 + vue: 3.5.15 dev: true - /vue-router@4.4.0(vue@3.4.30): - resolution: {integrity: sha512-HB+t2p611aIZraV2aPSRNXf0Z/oLZFrlygJm+sZbdJaW6lcFqEDQwnzUBXn+DApw+/QzDU/I9TeWx9izEjTmsA==} + /vue-router@4.5.1(vue@3.5.15): + resolution: {integrity: sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==} peerDependencies: vue: ^3.2.0 dependencies: - '@vue/devtools-api': 6.6.3 - vue: 3.4.30 + '@vue/devtools-api': 6.6.4 + vue: 3.5.15 dev: true - /vue@3.4.30: - resolution: {integrity: sha512-NcxtKCwkdf1zPsr7Y8+QlDBCGqxvjLXF2EX+yi76rV5rrz90Y6gK1cq0olIhdWGgrlhs9ElHuhi9t3+W5sG5Xw==} + /vue@3.5.15: + resolution: {integrity: sha512-aD9zK4rB43JAMK/5BmS4LdPiEp8Fdh8P1Ve/XNuMF5YRf78fCyPE6FUbQwcaWQ5oZ1R2CD9NKE0FFOVpMR7gEQ==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@vue/compiler-dom': 3.4.30 - '@vue/compiler-sfc': 3.4.30 - '@vue/runtime-dom': 3.4.30 - '@vue/server-renderer': 3.4.30(vue@3.4.30) - '@vue/shared': 3.4.30 + '@vue/compiler-dom': 3.5.15 + '@vue/compiler-sfc': 3.5.15 + '@vue/runtime-dom': 3.5.15 + '@vue/server-renderer': 3.5.15(vue@3.5.15) + '@vue/shared': 3.5.15 dev: true - /vuepress-plugin-components@2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-JMIj+1VA+euB4TvmeUt0Fdm4inpAndzLgasadUd/C8j4Jj/99PtoTzBLR7Gxk6LaIYaR9IUsOTKPi3wnS0EOdg==} - engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} + /vuepress-plugin-components@2.0.0-rc.88(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-TwcHHiCdx9g8VlUhRTcMvvPAw1dmtmKNnfs9XgK3ejLMzVkmxT5uEH9xqmkbDdIFo4oy/CYBBX9qSCXH5/Qx0A==} + engines: {node: '>= 20.6.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} peerDependencies: artplayer: ^5.0.0 dashjs: 4.7.4 hls.js: ^1.4.12 mpegts.js: ^1.7.3 - sass-loader: ^14.0.0 - vidstack: ^1.11.11 - vuepress: 2.0.0-rc.9 + sass: ^1.88.0 + sass-embedded: ^1.88.0 + sass-loader: ^16.0.5 + vidstack: ^1.12.9 + vuepress: 2.0.0-rc.23 peerDependenciesMeta: artplayer: optional: true @@ -3311,50 +4696,51 @@ packages: optional: true mpegts.js: optional: true + sass: + optional: true + sass-embedded: + optional: true sass-loader: optional: true vidstack: optional: true dependencies: - '@stackblitz/sdk': 1.10.0 - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) + '@stackblitz/sdk': 1.11.0 + '@vuepress/helper': 2.0.0-rc.106(vuepress@2.0.0-rc.23) + '@vuepress/plugin-sass-palette': 2.0.0-rc.104(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) balloon-css: 1.2.0 - create-codepen: 1.0.1 - qrcode: 1.5.3 - sass-loader: 14.2.1 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) - vuepress-plugin-sass-palette: 2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) - vuepress-shared: 2.0.0-rc.36(vuepress@2.0.0-rc.9) + create-codepen: 2.0.0 + qrcode: 1.5.4 + sass: 1.89.0 + sass-embedded: 1.89.0 + sass-loader: 16.0.5(sass-embedded@1.89.0)(sass@1.89.0) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + vuepress-shared: 2.0.0-rc.88(vuepress@2.0.0-rc.23) transitivePeerDependencies: - - '@vue/composition-api' - typescript dev: true - /vuepress-plugin-md-enhance@2.0.0-rc.36(chart.js@4.4.3)(markdown-it@14.1.0)(mermaid@10.9.1)(sass-loader@14.2.1)(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-FvQ4foaqsE13WEXN2TaBqtSEN3tKnkkuDX7daLbNPQ1z0ghaMgcCDJ+ehEwwcNgXSs1vlbTRYL/Tf4M4RC1nfA==} - engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} + /vuepress-plugin-md-enhance@2.0.0-rc.88(chart.js@4.4.9)(markdown-it@14.1.0)(mermaid@11.6.0)(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-829rH7XUkRD9yYdnJxDmUleRx+mCXxO7A7xtQAXBlZbqX1dvB540iB1Uh8DYJCf8F/LmAmg7R2ftZjUqfhUy3Q==} + engines: {node: '>= 20.6.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} peerDependencies: - '@types/reveal.js': ^5.0.0 '@vue/repl': ^4.1.1 chart.js: ^4.0.0 echarts: ^5.0.0 - flowchart.ts: ^2.0.0 || ^3.0.0 - katex: ^0.16.0 + flowchart.ts: ^3.0.0 kotlin-playground: ^1.23.0 - markmap-lib: ^0.15.5 || ^0.16.0 - markmap-toolbar: ^0.15.5 || ^0.16.0 - markmap-view: ^0.15.5 || ^0.16.0 - mathjax-full: ^3.2.2 - mermaid: ^10.8.0 - reveal.js: ^5.0.0 + markmap-lib: ^0.18.5 + markmap-toolbar: ^0.18.5 + markmap-view: ^0.18.5 + mermaid: ^11.6.0 sandpack-vue3: ^3.0.0 - sass-loader: ^14.0.0 - vuepress: 2.0.0-rc.9 + sass: ^1.88.0 + sass-embedded: ^1.88.0 + sass-loader: ^16.0.5 + vuepress: 2.0.0-rc.23 peerDependenciesMeta: - '@types/reveal.js': - optional: true '@vue/repl': optional: true chart.js: @@ -3363,8 +4749,6 @@ packages: optional: true flowchart.ts: optional: true - katex: - optional: true kotlin-playground: optional: true markmap-lib: @@ -3373,190 +4757,146 @@ packages: optional: true markmap-view: optional: true - mathjax-full: - optional: true mermaid: optional: true - reveal.js: - optional: true sandpack-vue3: optional: true + sass: + optional: true + sass-embedded: + optional: true sass-loader: optional: true dependencies: - '@mdit/plugin-alert': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-align': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-attrs': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-container': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-demo': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-figure': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-footnote': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-img-lazyload': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-img-mark': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-img-size': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-include': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-katex': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-mark': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-mathjax': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-stylize': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-sub': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-sup': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-tab': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-tasklist': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-tex': 0.8.0(markdown-it@14.1.0) - '@mdit/plugin-uml': 0.8.0(markdown-it@14.1.0) - '@types/markdown-it': 14.1.1 - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) + '@mdit/plugin-container': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-demo': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-plantuml': 0.18.0(markdown-it@14.1.0) + '@mdit/plugin-uml': 0.18.0(markdown-it@14.1.0) + '@types/markdown-it': 14.1.2 + '@vuepress/helper': 2.0.0-rc.106(vuepress@2.0.0-rc.23) + '@vuepress/plugin-sass-palette': 2.0.0-rc.104(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) balloon-css: 1.2.0 - chart.js: 4.4.3 + chart.js: 4.4.9 js-yaml: 4.1.0 - mermaid: 10.9.1 - sass-loader: 14.2.1 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) - vuepress-plugin-sass-palette: 2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) - vuepress-shared: 2.0.0-rc.36(vuepress@2.0.0-rc.9) + mermaid: 11.6.0 + sass: 1.89.0 + sass-embedded: 1.89.0 + sass-loader: 16.0.5(sass-embedded@1.89.0)(sass@1.89.0) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + vuepress-shared: 2.0.0-rc.88(vuepress@2.0.0-rc.23) transitivePeerDependencies: - - '@vue/composition-api' - markdown-it - typescript dev: true - /vuepress-plugin-sass-palette@2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-kOfZHGZxfplVq/z7QtHmsrKfOlR6/s37QA/DilIYGFzj8XVL8h1eJ0ty7J1ySTZFVvDkK7r3TVVQZ2sPIEjbYQ==} - engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} - peerDependencies: - sass-loader: ^14.0.0 - vuepress: 2.0.0-rc.9 - peerDependenciesMeta: - sass-loader: - optional: true - dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - chokidar: 3.6.0 - sass: 1.77.6 - sass-loader: 14.2.1 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) - vuepress-shared: 2.0.0-rc.36(vuepress@2.0.0-rc.9) - transitivePeerDependencies: - - '@vue/composition-api' - - typescript - dev: true - - /vuepress-plugin-search-pro@2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-xumvvm0/V7WrWJXMs6ZVqFjjN6h4oIEm6YrBpeteBpbG2iUkuF9E2xhVPwhrV/dYzCSkKpR7bA31qp1CngWknA==} - engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} - peerDependencies: - sass-loader: ^14.0.0 - vuepress: 2.0.0-rc.9 - peerDependenciesMeta: - sass-loader: - optional: true - dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) - cheerio: 1.0.0-rc.12 - chokidar: 3.6.0 - sass-loader: 14.2.1 - slimsearch: 2.1.1 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) - vuepress-plugin-sass-palette: 2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) - vuepress-shared: 2.0.0-rc.36(vuepress@2.0.0-rc.9) - transitivePeerDependencies: - - '@vue/composition-api' - - typescript - dev: true - - /vuepress-shared@2.0.0-rc.36(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-a4XLodJk5U8qeon7jNqsyLGNUgOAdVr8YBZD7E9BGiu84+S3P6e5SCJLCLQ17v37jwdLoYwT2Fv67k586GAx7w==} - engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} + /vuepress-shared@2.0.0-rc.88(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-BbNs0idGkZIOuuRtH111Y4qDX0Rah4LBCyMGlMj5rPHtnSmrMXHzjZlevkzwpSsPTLVoOuYvreFuocI1bLl6qA==} + engines: {node: '>= 20.6.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} peerDependencies: - vuepress: 2.0.0-rc.9 + vuepress: 2.0.0-rc.23 dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) - cheerio: 1.0.0-rc.12 - dayjs: 1.11.11 - execa: 8.0.1 - fflate: 0.8.2 - gray-matter: 4.0.3 - semver: 7.6.2 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) + '@vuepress/helper': 2.0.0-rc.106(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) transitivePeerDependencies: - - '@vue/composition-api' - typescript dev: true - /vuepress-theme-hope@2.0.0-rc.36(chart.js@4.4.3)(markdown-it@14.1.0)(mermaid@10.9.1)(sass-loader@14.2.1)(vuepress-plugin-search-pro@2.0.0-rc.36)(vuepress@2.0.0-rc.9): - resolution: {integrity: sha512-kMCmlwPw4S0P0LYnAulaT98L3Z2jD+A4bgQ93rfuCVxmfCJEUs99V6ms9iu/GZ8CqJC10anDqwfJ+SjHCs0V8g==} - engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} + /vuepress-theme-hope@2.0.0-rc.88(@vuepress/plugin-slimsearch@2.0.0-rc.106)(chart.js@4.4.9)(markdown-it@14.1.0)(mermaid@11.6.0)(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23): + resolution: {integrity: sha512-XV33tgx84TuowHqxnYgG+rusqpdqbznPqDGbHrzOzJ+DMqGDHkVa6pejnUshpNryPSsHlNXtGLoqKLNQf/YVNw==} + engines: {node: '>= 20.6.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'} peerDependencies: - '@vuepress/plugin-docsearch': 2.0.0-rc.24 - '@vuepress/plugin-feed': 2.0.0-rc.24 - '@vuepress/plugin-pwa': 2.0.0-rc.24 - '@vuepress/plugin-redirect': 2.0.0-rc.24 - '@vuepress/plugin-search': 2.0.0-rc.24 - nodejs-jieba: ^0.1.2 - sass-loader: ^14.0.0 - vuepress: 2.0.0-rc.9 - vuepress-plugin-search-pro: 2.0.0-rc.36 + '@vuepress/plugin-docsearch': 2.0.0-rc.104 + '@vuepress/plugin-feed': 2.0.0-rc.104 + '@vuepress/plugin-meilisearch': 2.0.0-rc.104 + '@vuepress/plugin-prismjs': 2.0.0-rc.104 + '@vuepress/plugin-pwa': 2.0.0-rc.104 + '@vuepress/plugin-revealjs': 2.0.0-rc.104 + '@vuepress/plugin-search': 2.0.0-rc.104 + '@vuepress/plugin-slimsearch': 2.0.0-rc.104 + '@vuepress/plugin-watermark': 2.0.0-rc.104 + '@vuepress/shiki-twoslash': 2.0.0-rc.104 + nodejs-jieba: ^0.2.1 || ^0.3.0 + sass: ^1.88.0 + sass-embedded: ^1.88.0 + sass-loader: ^16.0.5 + vuepress: 2.0.0-rc.23 peerDependenciesMeta: '@vuepress/plugin-docsearch': optional: true '@vuepress/plugin-feed': optional: true + '@vuepress/plugin-meilisearch': + optional: true + '@vuepress/plugin-prismjs': + optional: true '@vuepress/plugin-pwa': optional: true - '@vuepress/plugin-redirect': + '@vuepress/plugin-revealjs': optional: true '@vuepress/plugin-search': optional: true + '@vuepress/plugin-slimsearch': + optional: true + '@vuepress/plugin-watermark': + optional: true + '@vuepress/shiki-twoslash': + optional: true nodejs-jieba: optional: true + sass: + optional: true + sass-embedded: + optional: true sass-loader: optional: true - vuepress-plugin-search-pro: - optional: true - dependencies: - '@vuepress/helper': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-active-header-links': 2.0.0-rc.21(vuepress@2.0.0-rc.9) - '@vuepress/plugin-back-to-top': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-blog': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-catalog': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-comment': 2.0.0-rc.24(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) - '@vuepress/plugin-copy-code': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-copyright': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-external-link-icon': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-git': 2.0.0-rc.22(vuepress@2.0.0-rc.9) - '@vuepress/plugin-links-check': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-nprogress': 2.0.0-rc.21(vuepress@2.0.0-rc.9) - '@vuepress/plugin-photo-swipe': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-prismjs': 2.0.0-rc.21(vuepress@2.0.0-rc.9) - '@vuepress/plugin-reading-time': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-rtl': 2.0.0-rc.21(vuepress@2.0.0-rc.9) - '@vuepress/plugin-seo': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-sitemap': 2.0.0-rc.24(vuepress@2.0.0-rc.9) - '@vuepress/plugin-theme-data': 2.0.0-rc.21(vuepress@2.0.0-rc.9) - '@vueuse/core': 10.11.0(vue@3.4.30) + dependencies: + '@vuepress/helper': 2.0.0-rc.106(vuepress@2.0.0-rc.23) + '@vuepress/plugin-active-header-links': 2.0.0-rc.103(vuepress@2.0.0-rc.23) + '@vuepress/plugin-back-to-top': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-blog': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-catalog': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-comment': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-copy-code': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-copyright': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-git': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-icon': 2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-links-check': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-markdown-ext': 2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-markdown-hint': 2.0.0-rc.104(markdown-it@14.1.0)(vue@3.5.15)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-markdown-image': 2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-markdown-include': 2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-markdown-math': 2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-markdown-stylize': 2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-markdown-tab': 2.0.0-rc.104(markdown-it@14.1.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-notice': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-nprogress': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-photo-swipe': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-reading-time': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-redirect': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-rtl': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-sass-palette': 2.0.0-rc.104(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-seo': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-shiki': 2.0.0-rc.104(@vueuse/core@13.2.0)(vuepress@2.0.0-rc.23) + '@vuepress/plugin-sitemap': 2.0.0-rc.104(vuepress@2.0.0-rc.23) + '@vuepress/plugin-slimsearch': 2.0.0-rc.106(vuepress@2.0.0-rc.23) + '@vuepress/plugin-theme-data': 2.0.0-rc.103(vuepress@2.0.0-rc.23) + '@vueuse/core': 13.2.0(vue@3.5.15) balloon-css: 1.2.0 - bcrypt-ts: 5.0.2 - cheerio: 1.0.0-rc.12 + bcrypt-ts: 7.0.0 chokidar: 3.6.0 - gray-matter: 4.0.3 - sass-loader: 14.2.1 - vue: 3.4.30 - vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30) - vuepress-plugin-components: 2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) - vuepress-plugin-md-enhance: 2.0.0-rc.36(chart.js@4.4.3)(markdown-it@14.1.0)(mermaid@10.9.1)(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) - vuepress-plugin-sass-palette: 2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) - vuepress-plugin-search-pro: 2.0.0-rc.36(sass-loader@14.2.1)(vuepress@2.0.0-rc.9) - vuepress-shared: 2.0.0-rc.36(vuepress@2.0.0-rc.9) + sass: 1.89.0 + sass-embedded: 1.89.0 + sass-loader: 16.0.5(sass-embedded@1.89.0)(sass@1.89.0) + vue: 3.5.15 + vuepress: 2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15) + vuepress-plugin-components: 2.0.0-rc.88(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23) + vuepress-plugin-md-enhance: 2.0.0-rc.88(chart.js@4.4.9)(markdown-it@14.1.0)(mermaid@11.6.0)(sass-embedded@1.89.0)(sass-loader@16.0.5)(sass@1.89.0)(vuepress@2.0.0-rc.23) + vuepress-shared: 2.0.0-rc.88(vuepress@2.0.0-rc.23) transitivePeerDependencies: - - '@types/reveal.js' - - '@vue/composition-api' - '@vue/repl' - '@waline/client' - artalk @@ -3575,54 +4915,57 @@ packages: - mathjax-full - mermaid - mpegts.js - - reveal.js - sandpack-vue3 - twikoo - typescript - vidstack dev: true - /vuepress@2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.30): - resolution: {integrity: sha512-jT1ln2lawdph+vVI6n2JfEUhQIcyc1RQWDdQu9DffhJGywJunFcumnUJudpqd1SNIES2Fz1hVCD6gdrE/rVKOQ==} - engines: {node: '>=18.16.0'} + /vuepress@2.0.0-rc.23(@vuepress/bundler-vite@2.0.0-rc.23)(vue@3.5.15): + resolution: {integrity: sha512-XID/zr7qDGLg7oYGwDTZpWRNXCVQcI1wQTfkN0spyumV2EpHe7XBsmnwICd+dTqRNZuD+JHyJsYLEqDEszFObw==} + engines: {node: ^18.19.0 || >=20.4.0} hasBin: true peerDependencies: - '@vuepress/bundler-vite': 2.0.0-rc.9 - '@vuepress/bundler-webpack': 2.0.0-rc.9 - vue: ^3.4.0 + '@vuepress/bundler-vite': 2.0.0-rc.23 + '@vuepress/bundler-webpack': 2.0.0-rc.23 + vue: ^3.5.13 peerDependenciesMeta: '@vuepress/bundler-vite': optional: true '@vuepress/bundler-webpack': optional: true dependencies: - '@vuepress/bundler-vite': 2.0.0-rc.9 - '@vuepress/cli': 2.0.0-rc.9 - '@vuepress/client': 2.0.0-rc.9 - '@vuepress/core': 2.0.0-rc.9 - '@vuepress/markdown': 2.0.0-rc.9 - '@vuepress/shared': 2.0.0-rc.9 - '@vuepress/utils': 2.0.0-rc.9 - vue: 3.4.30 + '@vuepress/bundler-vite': 2.0.0-rc.23(sass-embedded@1.89.0)(sass@1.89.0) + '@vuepress/cli': 2.0.0-rc.23 + '@vuepress/client': 2.0.0-rc.23 + '@vuepress/core': 2.0.0-rc.23 + '@vuepress/markdown': 2.0.0-rc.23 + '@vuepress/shared': 2.0.0-rc.23 + '@vuepress/utils': 2.0.0-rc.23 + vue: 3.5.15 transitivePeerDependencies: - supports-color - typescript dev: true - /web-worker@1.3.0: - resolution: {integrity: sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==} + /web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} dev: true - /which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + /whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + dependencies: + iconv-lite: 0.6.3 dev: true - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 + /whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + dev: true + + /which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} dev: true /wrap-ansi@6.2.0: @@ -3638,12 +4981,6 @@ packages: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} dev: true - /yaml@2.4.5: - resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} - engines: {node: '>= 14'} - hasBin: true - dev: true - /yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -3668,3 +5005,7 @@ packages: y18n: 4.0.3 yargs-parser: 18.1.3 dev: true + + /zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + dev: true diff --git a/pyproject.toml b/pyproject.toml index 84c00f42..c6f3b2e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,9 +96,16 @@ ignore = [ "D103", # Missing docstring in public function "S311", # Standard pseudo-random generators are not suitable for security/cryptographic purposes ] +"python/psqlpy/_internal/exceptions.pyi" = [ + "D205", + "RUF002", +] "./psqlpy-stress/psqlpy_stress/migrations/env.py" = ["INP001"] "examples/*" = ["INP001"] [tool.ruff.pydocstyle] convention = "pep257" ignore-decorators = ["typing.overload"] + +[project.entry-points."sqlalchemy.dialects"] +psqlpy = "psqlpy_sqlalchemy.dialect:PSQLPyAsyncDialect" diff --git a/python/psqlpy/__init__.py b/python/psqlpy/__init__.py index 6f899719..7c76be33 100644 --- a/python/psqlpy/__init__.py +++ b/python/psqlpy/__init__.py @@ -13,10 +13,13 @@ ReadVariant, SingleQueryResult, SslMode, - SynchronousCommit, TargetSessionAttrs, Transaction, connect, + connect_pool, +) +from psqlpy.exceptions import ( + Error, ) __all__ = [ @@ -25,6 +28,7 @@ "ConnectionPool", "ConnectionPoolBuilder", "Cursor", + "Error", "IsolationLevel", "KeepaliveConfig", "Listener", @@ -34,8 +38,8 @@ "ReadVariant", "SingleQueryResult", "SslMode", - "SynchronousCommit", "TargetSessionAttrs", "Transaction", "connect", + "connect_pool", ] diff --git a/python/psqlpy/_internal/__init__.pyi b/python/psqlpy/_internal/__init__.pyi index 8c391d96..73011b45 100644 --- a/python/psqlpy/_internal/__init__.pyi +++ b/python/psqlpy/_internal/__init__.pyi @@ -150,38 +150,6 @@ class SingleQueryResult: Type that return passed function. """ -class SynchronousCommit(Enum): - """ - Synchronous_commit option for transactions. - - ### Variants: - - `On`: The meaning may change based on whether you have - a synchronous standby or not. - If there is a synchronous standby, - setting the value to on will result in waiting till “remote flush”. - - `Off`: As the name indicates, the commit acknowledgment can come before - flushing the records to disk. - This is generally called as an asynchronous commit. - If the PostgreSQL instance crashes, - the last few asynchronous commits might be lost. - - `Local`: WAL records are written and flushed to local disks. - In this case, the commit will be acknowledged after the - local WAL Write and WAL flush completes. - - `RemoteWrite`: WAL records are successfully handed over to - remote instances which acknowledged back - about the write (not flush). - - `RemoteApply`: This will result in commits waiting until replies from the - current synchronous standby(s) indicate they have received - the commit record of the transaction and applied it so - that it has become visible to queries on the standby(s). - """ - - On = 1 - Off = 2 - Local = 3 - RemoteWrite = 4 - RemoteApply = 5 - class IsolationLevel(Enum): """Isolation Level for transactions.""" @@ -285,11 +253,12 @@ class KeepaliveConfig: """Initialize new config.""" class Cursor: - """Represent opened cursor in a transaction. + """Represent binary cursor in a transaction. It can be used as an asynchronous iterator. """ + array_size: int cursor_name: str querystring: str parameters: ParamsT = None @@ -314,118 +283,27 @@ class Cursor: Execute DECLARE command for the cursor. """ - async def close(self: Self) -> None: + def close(self: Self) -> None: """Close the cursor. Execute CLOSE command for the cursor. """ - async def fetch( - self: Self, - fetch_number: int | None = None, - ) -> QueryResult: - """Fetch next rows. - - By default fetches 10 next rows. - - ### Parameters: - - `fetch_number`: how many rows need to fetch. - - ### Returns: - result as `QueryResult`. - """ - async def fetch_next( - self: Self, - ) -> QueryResult: - """Fetch next row. - - Execute FETCH NEXT - - ### Returns: - result as `QueryResult`. - """ - async def fetch_prior( - self: Self, - ) -> QueryResult: - """Fetch previous row. - - Execute FETCH PRIOR - - ### Returns: - result as `QueryResult`. - """ - async def fetch_first( - self: Self, - ) -> QueryResult: - """Fetch first row. - - Execute FETCH FIRST - - ### Returns: - result as `QueryResult`. - """ - async def fetch_last( - self: Self, - ) -> QueryResult: - """Fetch last row. - - Execute FETCH LAST - - ### Returns: - result as `QueryResult`. - """ - async def fetch_absolute( - self: Self, - absolute_number: int, - ) -> QueryResult: - """Fetch absolute rows. - - Execute FETCH ABSOLUTE . - - ### Returns: - result as `QueryResult`. - """ - async def fetch_relative( - self: Self, - relative_number: int, - ) -> QueryResult: - """Fetch absolute rows. - - Execute FETCH RELATIVE . - - ### Returns: - result as `QueryResult`. - """ - async def fetch_forward_all( - self: Self, - ) -> QueryResult: - """Fetch forward all rows. - - Execute FETCH FORWARD ALL. - - ### Returns: - result as `QueryResult`. - """ - async def fetch_backward( - self: Self, - backward_count: int, - ) -> QueryResult: - """Fetch backward rows. - - Execute FETCH BACKWARD . - - ### Returns: - result as `QueryResult`. - """ - async def fetch_backward_all( + async def execute( self: Self, + querystring: str, + parameters: ParamsT = None, ) -> QueryResult: - """Fetch backward all rows. + """Start cursor with querystring and parameters. - Execute FETCH BACKWARD ALL. - - ### Returns: - result as `QueryResult`. + Method should be used instead of context manager + and `start` method. """ + async def fetchone(self: Self) -> QueryResult: + """Return next one row from the cursor.""" + async def fetchmany(self: Self, size: int | None = None) -> QueryResult: + """Return rows from the cursor.""" + async def fetchall(self: Self, size: int | None = None) -> QueryResult: + """Return all remaining rows from the cursor.""" class Transaction: """Single connection for executing queries. @@ -463,6 +341,26 @@ class Transaction: `commit()` can be called only once per transaction. """ + async def rollback(self: Self) -> None: + """Rollback all queries in the transaction. + + It can be done only one, after execution transaction marked + as `done`. + + ### Example: + ```python + import asyncio + + from psqlpy import PSQLPool, QueryResult + + async def main() -> None: + db_pool = PSQLPool() + connection = await db_pool.connection() + transaction = connection.transaction() + await transaction.execute(...) + await transaction.rollback() + ``` + """ async def execute( self: Self, querystring: str, @@ -744,26 +642,6 @@ class Transaction: await transaction.rollback_savepoint("my_savepoint") ``` """ - async def rollback(self: Self) -> None: - """Rollback all queries in the transaction. - - It can be done only one, after execution transaction marked - as `done`. - - ### Example: - ```python - import asyncio - - from psqlpy import PSQLPool, QueryResult - - async def main() -> None: - db_pool = PSQLPool() - connection = await db_pool.connection() - transaction = connection.transaction() - await transaction.execute(...) - await transaction.rollback() - ``` - """ async def rollback_savepoint(self: Self, savepoint_name: str) -> None: """ROLLBACK to the specified `savepoint_name`. @@ -818,8 +696,6 @@ class Transaction: querystring: str, parameters: ParamsT = None, fetch_number: int | None = None, - scroll: bool | None = None, - prepared: bool = True, ) -> Cursor: """Create new cursor object. @@ -829,9 +705,6 @@ class Transaction: - `querystring`: querystring to execute. - `parameters`: list of parameters to pass in the query. - `fetch_number`: how many rows need to fetch. - - `scroll`: SCROLL or NO SCROLL cursor. - - `prepared`: should the querystring be prepared before the request. - By default any querystring will be prepared. ### Returns: new initialized cursor. @@ -886,6 +759,34 @@ class Transaction: number of inserted rows; """ +async def connect( + dsn: str | None = None, + username: str | None = None, + password: str | None = None, + host: str | None = None, + hosts: list[str] | None = None, + port: int | None = None, + ports: list[int] | None = None, + db_name: str | None = None, + target_session_attrs: TargetSessionAttrs | None = None, + options: str | None = None, + application_name: str | None = None, + connect_timeout_sec: int | None = None, + connect_timeout_nanosec: int | None = None, + tcp_user_timeout_sec: int | None = None, + tcp_user_timeout_nanosec: int | None = None, + keepalives: bool | None = None, + keepalives_idle_sec: int | None = None, + keepalives_idle_nanosec: int | None = None, + keepalives_interval_sec: int | None = None, + keepalives_interval_nanosec: int | None = None, + keepalives_retries: int | None = None, + load_balance_hosts: LoadBalanceHosts | None = None, + ssl_mode: SslMode | None = None, + ca_file: str | None = None, +) -> Connection: + """Create new standalone connection.""" + class Connection: """Connection from Database Connection Pool. @@ -905,6 +806,25 @@ class Connection: exception: BaseException | None, traceback: types.TracebackType | None, ) -> None: ... + async def prepare( + self, + querystring: str, + parameters: ParamsT = None, + ) -> PreparedStatement: + """Prepare statement. + + Return representation of prepared statement. + """ + async def commit(self: Self) -> None: + """Commit the transaction. + + Do nothing if there is no active transaction. + """ + async def rollback(self: Self) -> None: + """Rollback the transaction. + + Do nothing if there is no active transaction. + """ async def execute( self: Self, querystring: str, @@ -1089,7 +1009,6 @@ class Connection: isolation_level: IsolationLevel | None = None, read_variant: ReadVariant | None = None, deferrable: bool | None = None, - synchronous_commit: SynchronousCommit | None = None, ) -> Transaction: """Create new transaction. @@ -1097,15 +1016,12 @@ class Connection: - `isolation_level`: configure isolation level of the transaction. - `read_variant`: configure read variant of the transaction. - `deferrable`: configure deferrable of the transaction. - - `synchronous_commit`: configure synchronous_commit option for transaction. """ def cursor( self: Self, querystring: str, parameters: ParamsT = None, fetch_number: int | None = None, - scroll: bool | None = None, - prepared: bool = True, ) -> Cursor: """Create new cursor object. @@ -1115,9 +1031,6 @@ class Connection: - `querystring`: querystring to execute. - `parameters`: list of parameters to pass in the query. - `fetch_number`: how many rows need to fetch. - - `scroll`: SCROLL or NO SCROLL cursor. - - `prepared`: should the querystring be prepared before the request. - By default any querystring will be prepared. ### Returns: new initialized cursor. @@ -1142,12 +1055,13 @@ class Connection: ... # do something with this result. ``` """ - def back_to_pool(self: Self) -> None: + def close(self: Self) -> None: """Return connection back to the pool. It necessary to commit all transactions and close all cursor made by this connection. Otherwise, it won't have any practical usage. """ + async def binary_copy_to_table( self: Self, source: bytes | bytearray | Buffer | BytesIO, @@ -1336,7 +1250,7 @@ class ConnectionPool: def close(self: Self) -> None: """Close the connection pool.""" -def connect( +def connect_pool( dsn: str | None = None, username: str | None = None, password: str | None = None, @@ -1857,3 +1771,15 @@ class ListenerNotificationMsg: channel: str payload: str connection: Connection + +class Column: + name: str + table_oid: int | None + +class PreparedStatement: + async def execute(self: Self) -> QueryResult: + """Execute prepared statement.""" + def cursor(self: Self) -> Cursor: + """Create new server-side cursor based on prepared statement.""" + def columns(self: Self) -> list[Column]: + """Return information about statement columns.""" diff --git a/python/psqlpy/_internal/exceptions.pyi b/python/psqlpy/_internal/exceptions.pyi index a0588e9f..0aabd342 100644 --- a/python/psqlpy/_internal/exceptions.pyi +++ b/python/psqlpy/_internal/exceptions.pyi @@ -1,7 +1,68 @@ -class RustPSQLDriverPyBaseError(Exception): - """Base PSQL-Rust-Engine exception.""" +class WarningError(Exception): + """ + Exception raised for important warnings + like data truncations while inserting, etc. + """ + +class Error(Exception): + """ + Exception that is the base class of all other error exceptions. -class BaseConnectionPoolError(RustPSQLDriverPyBaseError): + You can use this to catch all errors with one single except statement. + """ + +class InterfaceError(Error): + """ + Exception raised for errors that are related to the + database interface rather than the database itself. + """ + +class DatabaseError(Error): + """Exception raised for errors that are related to the database.""" + +class DataError(DatabaseError): + """ + Exception raised for errors that are due to problems with + the processed data like division by zero, numeric value out of range, etc. + """ + +class OperationalError(DatabaseError): + """ + Exception raised for errors that are related to the database’s operation + and not necessarily under the control of the programmer, + e.g. an unexpected disconnect occurs, the data source name is not found, + a transaction could not be processed, a memory allocation error + occurred during processing, etc. + """ + +class IntegrityError(DatabaseError): + """ + Exception raised when the relational integrity of the + database is affected, e.g. a foreign key check fails. + """ + +class InternalError(DatabaseError): + """ + Exception raised when the database encounters an internal error, + e.g. the cursor is not valid anymore, the transaction is out of sync, etc. + """ + +class ProgrammingError(DatabaseError): + """ + Exception raised for programming errors, e.g. table not found or + already exists, syntax error in the SQL statement, + wrong number of parameters specified, etc. + """ + +class NotSupportedError(DatabaseError): + """ + Exception raised in case a method or database API was used which + is not supported by the database, e.g. requesting a .rollback() + on a connection that does not support transaction + or has transactions turned off. + """ + +class BaseConnectionPoolError(InterfaceError): """Base error for all Connection Pool errors.""" class ConnectionPoolBuildError(BaseConnectionPoolError): @@ -13,7 +74,7 @@ class ConnectionPoolConfigurationError(BaseConnectionPoolError): class ConnectionPoolExecuteError(BaseConnectionPoolError): """Error in connection pool execution.""" -class BaseConnectionError(RustPSQLDriverPyBaseError): +class BaseConnectionError(InterfaceError): """Base error for Connection errors.""" class ConnectionExecuteError(BaseConnectionError): @@ -22,7 +83,7 @@ class ConnectionExecuteError(BaseConnectionError): class ConnectionClosedError(BaseConnectionError): """Error if underlying connection is already closed.""" -class BaseTransactionError(RustPSQLDriverPyBaseError): +class BaseTransactionError(InterfaceError): """Base error for all transaction errors.""" class TransactionBeginError(BaseTransactionError): @@ -43,7 +104,7 @@ class TransactionExecuteError(BaseTransactionError): class TransactionClosedError(BaseTransactionError): """Error if underlying connection is already closed.""" -class BaseCursorError(RustPSQLDriverPyBaseError): +class BaseCursorError(InterfaceError): """Base error for Cursor errors.""" class CursorStartError(BaseCursorError): @@ -58,29 +119,27 @@ class CursorFetchError(BaseCursorError): class CursorClosedError(BaseCursorError): """Error if underlying connection is already closed.""" -class UUIDValueConvertError(RustPSQLDriverPyBaseError): +class UUIDValueConvertError(DataError): """Error if it's impossible to convert py string UUID into rust UUID.""" -class MacAddrConversionError(RustPSQLDriverPyBaseError): +class MacAddrConversionError(DataError): """Error if cannot convert MacAddr string value to rust type.""" -class RustToPyValueMappingError(RustPSQLDriverPyBaseError): +class RustToPyValueMappingError(DataError): """Error if it is not possible to covert rust type to python. You can get it if you database contains data type that it not supported by this library. - - It's better to handle this exception. """ -class PyToRustValueMappingError(RustPSQLDriverPyBaseError): +class PyToRustValueMappingError(DataError): """Error if it is not possible to covert python type to rust. You can get this exception when executing queries with parameters. So, if there are no parameters for the query, don't handle this error. """ -class BaseListenerError(RustPSQLDriverPyBaseError): +class BaseListenerError(InterfaceError): """Base error for all Listener errors.""" class ListenerStartError(BaseListenerError): diff --git a/python/psqlpy/exceptions.py b/python/psqlpy/exceptions.py index 2d981ef3..da5f51a0 100644 --- a/python/psqlpy/exceptions.py +++ b/python/psqlpy/exceptions.py @@ -13,12 +13,20 @@ CursorCloseError, CursorFetchError, CursorStartError, + DatabaseError, + DataError, + Error, + IntegrityError, + InterfaceError, + InternalError, ListenerCallbackError, ListenerClosedError, ListenerStartError, MacAddrConversionError, + NotSupportedError, + OperationalError, + ProgrammingError, PyToRustValueMappingError, - RustPSQLDriverPyBaseError, RustToPyValueMappingError, TransactionBeginError, TransactionClosedError, @@ -27,6 +35,7 @@ TransactionRollbackError, TransactionSavepointError, UUIDValueConvertError, + WarningError, ) __all__ = [ @@ -44,12 +53,20 @@ "CursorClosedError", "CursorFetchError", "CursorStartError", + "DataError", + "DatabaseError", + "Error", + "IntegrityError", + "InterfaceError", + "InternalError", "ListenerCallbackError", "ListenerClosedError", "ListenerStartError", "MacAddrConversionError", + "NotSupportedError", + "OperationalError", + "ProgrammingError", "PyToRustValueMappingError", - "RustPSQLDriverPyBaseError", "RustToPyValueMappingError", "TransactionBeginError", "TransactionClosedError", @@ -58,4 +75,5 @@ "TransactionRollbackError", "TransactionSavepointError", "UUIDValueConvertError", + "WarningError", ] diff --git a/python/tests/test_connection.py b/python/tests/test_connection.py index 7af208f2..4643e0c6 100644 --- a/python/tests/test_connection.py +++ b/python/tests/test_connection.py @@ -145,7 +145,7 @@ async def test_connection_cursor( await transaction.begin() cursor = connection.cursor(querystring=f"SELECT * FROM {table_name}") await cursor.start() - await cursor.close() + cursor.close() await transaction.commit() @@ -172,7 +172,7 @@ async def test_closed_connection_error( ) -> None: """Test exception when connection is closed.""" connection = await psql_pool.connection() - connection.back_to_pool() + connection.close() with pytest.raises(expected_exception=ConnectionClosedError): await connection.execute("SELECT 1") diff --git a/python/tests/test_connection_pool.py b/python/tests/test_connection_pool.py index 405fceb7..dee61e86 100644 --- a/python/tests/test_connection_pool.py +++ b/python/tests/test_connection_pool.py @@ -5,11 +5,11 @@ ConnRecyclingMethod, LoadBalanceHosts, TargetSessionAttrs, - connect, + connect_pool, ) from psqlpy.exceptions import ( ConnectionPoolConfigurationError, - RustPSQLDriverPyBaseError, + InterfaceError, ) pytestmark = pytest.mark.anyio @@ -17,7 +17,7 @@ async def test_connect_func() -> None: """Test that connect function makes new connection pool.""" - pg_pool = connect( + pg_pool = connect_pool( dsn="postgres://postgres:postgres@localhost:5432/psqlpy_test", ) @@ -106,7 +106,7 @@ async def test_pool_target_session_attrs( ) if target_session_attrs == TargetSessionAttrs.ReadOnly: - with pytest.raises(expected_exception=RustPSQLDriverPyBaseError): + with pytest.raises(expected_exception=InterfaceError): await pg_pool.connection() else: conn = await pg_pool.connection() @@ -143,7 +143,7 @@ async def test_close_connection_pool() -> None: pg_pool.close() - with pytest.raises(expected_exception=RustPSQLDriverPyBaseError): + with pytest.raises(expected_exception=InterfaceError): await pg_pool.connection() @@ -156,5 +156,5 @@ async def test_connection_pool_as_context_manager() -> None: res = await conn.execute("SELECT 1") assert res.result() - with pytest.raises(expected_exception=RustPSQLDriverPyBaseError): + with pytest.raises(expected_exception=InterfaceError): await pg_pool.connection() diff --git a/python/tests/test_cursor.py b/python/tests/test_cursor.py index 07fca375..bd423a9b 100644 --- a/python/tests/test_cursor.py +++ b/python/tests/test_cursor.py @@ -1,177 +1,84 @@ from __future__ import annotations -import math from typing import TYPE_CHECKING import pytest if TYPE_CHECKING: - from psqlpy import ConnectionPool, Cursor, QueryResult, Transaction + from psqlpy import ConnectionPool, Cursor pytestmark = pytest.mark.anyio -async def test_cursor_fetch( +async def test_cursor_fetchmany( number_database_records: int, test_cursor: Cursor, ) -> None: """Test cursor fetch with custom number of fetch.""" - result = await test_cursor.fetch(fetch_number=number_database_records // 2) + result = await test_cursor.fetchmany(size=number_database_records // 2) assert len(result.result()) == number_database_records // 2 -async def test_cursor_fetch_next( +async def test_cursor_fetchone( test_cursor: Cursor, ) -> None: - """Test cursor fetch next.""" - result = await test_cursor.fetch_next() + result = await test_cursor.fetchone() assert len(result.result()) == 1 -async def test_cursor_fetch_prior( - test_cursor: Cursor, -) -> None: - """Test cursor fetch prior.""" - result = await test_cursor.fetch_prior() - assert len(result.result()) == 0 - - await test_cursor.fetch(fetch_number=2) - result = await test_cursor.fetch_prior() - assert len(result.result()) == 1 - - -async def test_cursor_fetch_first( - test_cursor: Cursor, -) -> None: - """Test cursor fetch first.""" - fetch_first = await test_cursor.fetch(fetch_number=1) - - await test_cursor.fetch(fetch_number=3) - - first = await test_cursor.fetch_first() - - assert fetch_first.result() == first.result() - - -async def test_cursor_fetch_last( - test_cursor: Cursor, +async def test_cursor_fetchall( number_database_records: int, -) -> None: - """Test cursor fetch last.""" - all_res = await test_cursor.fetch( - fetch_number=number_database_records, - ) - - last_res = await test_cursor.fetch_last() - - assert all_res.result()[-1] == last_res.result()[0] - - -async def test_cursor_fetch_absolute( test_cursor: Cursor, - number_database_records: int, ) -> None: - """Test cursor fetch Absolute.""" - all_res = await test_cursor.fetch( - fetch_number=number_database_records, - ) - - first_record = await test_cursor.fetch_absolute( - absolute_number=1, - ) - last_record = await test_cursor.fetch_absolute( - absolute_number=-1, - ) - - assert all_res.result()[0] == first_record.result()[0] - assert all_res.result()[-1] == last_record.result()[0] + result = await test_cursor.fetchall() + assert len(result.result()) == number_database_records -async def test_cursor_fetch_relative( - test_cursor: Cursor, +async def test_cursor_start( + psql_pool: ConnectionPool, + table_name: str, number_database_records: int, ) -> None: - """Test cursor fetch Relative.""" - first_absolute = await test_cursor.fetch_relative( - relative_number=1, + connection = await psql_pool.connection() + cursor = connection.cursor( + querystring=f"SELECT * FROM {table_name}", ) + await cursor.start() + results = await cursor.fetchall() - assert first_absolute.result() - - await test_cursor.fetch( - fetch_number=number_database_records, - ) - records = await test_cursor.fetch_relative( - relative_number=1, - ) + assert len(results.result()) == number_database_records - assert not (records.result()) + cursor.close() -async def test_cursor_fetch_forward_all( - test_cursor: Cursor, +async def test_cursor_as_async_context_manager( + psql_pool: ConnectionPool, + table_name: str, number_database_records: int, ) -> None: - """Test that cursor execute FETCH FORWARD ALL correctly.""" - default_fetch_number = 2 - await test_cursor.fetch(fetch_number=default_fetch_number) - - rest_results = await test_cursor.fetch_forward_all() - - assert len(rest_results.result()) == number_database_records - default_fetch_number - - -async def test_cursor_fetch_backward( - test_cursor: Cursor, -) -> None: - """Test cursor backward fetch.""" - must_be_empty = await test_cursor.fetch_backward(backward_count=10) - assert not (must_be_empty.result()) - - default_fetch_number = 5 - await test_cursor.fetch(fetch_number=default_fetch_number) - - expected_number_of_results = 3 - must_not_be_empty = await test_cursor.fetch_backward( - backward_count=expected_number_of_results, - ) - assert len(must_not_be_empty.result()) == expected_number_of_results - - -async def test_cursor_fetch_backward_all( - test_cursor: Cursor, -) -> None: - """Test cursor `fetch_backward_all`.""" - must_be_empty = await test_cursor.fetch_backward_all() - assert not (must_be_empty.result()) - - default_fetch_number = 5 - await test_cursor.fetch(fetch_number=default_fetch_number) + connection = await psql_pool.connection() + async with connection.cursor( + querystring=f"SELECT * FROM {table_name}", + ) as cursor: + results = await cursor.fetchall() - must_not_be_empty = await test_cursor.fetch_backward_all() - assert len(must_not_be_empty.result()) == default_fetch_number - 1 + assert len(results.result()) == number_database_records -async def test_cursor_as_async_manager( +async def test_cursor_as_async_iterator( psql_pool: ConnectionPool, table_name: str, number_database_records: int, ) -> None: - """Test cursor async manager and async iterator.""" connection = await psql_pool.connection() - transaction: Transaction - cursor: Cursor - all_results: list[QueryResult] = [] - expected_num_results = math.ceil(number_database_records / 3) - fetch_number = 3 - async with connection.transaction() as transaction, transaction.cursor( + all_results = [] + async with connection.cursor( querystring=f"SELECT * FROM {table_name}", - fetch_number=fetch_number, ) as cursor: - async for result in cursor: - all_results.append(result) # noqa: PERF401 + async for results in cursor: + all_results.extend(results.result()) - assert len(all_results) == expected_num_results + assert len(all_results) == number_database_records async def test_cursor_send_underlying_connection_to_pool( @@ -184,7 +91,7 @@ async def test_cursor_send_underlying_connection_to_pool( async with transaction.cursor( querystring=f"SELECT * FROM {table_name}", ) as cursor: - await cursor.fetch(10) + await cursor.fetchmany(10) assert not psql_pool.status().available assert not psql_pool.status().available assert not psql_pool.status().available @@ -200,9 +107,9 @@ async def test_cursor_send_underlying_connection_to_pool_manually( async with connection.transaction() as transaction: cursor = transaction.cursor(querystring=f"SELECT * FROM {table_name}") await cursor.start() - await cursor.fetch(10) + await cursor.fetchmany(10) assert not psql_pool.status().available - await cursor.close() + cursor.close() assert not psql_pool.status().available assert not psql_pool.status().available assert psql_pool.status().available == 1 diff --git a/python/tests/test_listener.py b/python/tests/test_listener.py index a1ff0742..8db12ae9 100644 --- a/python/tests/test_listener.py +++ b/python/tests/test_listener.py @@ -64,7 +64,7 @@ async def notify( connection = await psql_pool.connection() await connection.execute(f"NOTIFY {channel}, '{TEST_PAYLOAD}'") - connection.back_to_pool() + connection.close() async def check_insert_callback( @@ -91,7 +91,7 @@ async def check_insert_callback( assert data_record["payload"] == TEST_PAYLOAD assert data_record["channel"] == TEST_CHANNEL - connection.back_to_pool() + connection.close() async def clear_test_table( @@ -102,7 +102,7 @@ async def clear_test_table( await connection.execute( f"DELETE FROM {listener_table_name}", ) - connection.back_to_pool() + connection.close() @pytest.mark.usefixtures("create_table_for_listener_tests") diff --git a/python/tests/test_transaction.py b/python/tests/test_transaction.py index 3c60676a..343bb868 100644 --- a/python/tests/test_transaction.py +++ b/python/tests/test_transaction.py @@ -8,13 +8,11 @@ Cursor, IsolationLevel, ReadVariant, - SynchronousCommit, ) +from psqlpy._internal.exceptions import TransactionClosedError from psqlpy.exceptions import ( - RustPSQLDriverPyBaseError, - TransactionBeginError, + InterfaceError, TransactionExecuteError, - TransactionSavepointError, ) from tests.helpers import count_rows_in_test_table @@ -50,7 +48,7 @@ async def test_transaction_init_parameters( f"INSERT INTO {table_name} VALUES ($1, $2)", parameters=[100, "test_name"], ) - except RustPSQLDriverPyBaseError: + except InterfaceError: assert read_variant is ReadVariant.ReadOnly else: assert read_variant is not ReadVariant.ReadOnly @@ -65,10 +63,10 @@ async def test_transaction_begin( connection = await psql_pool.connection() transaction = connection.transaction() - with pytest.raises(expected_exception=TransactionBeginError): - await transaction.execute( - f"SELECT * FROM {table_name}", - ) + # with pytest.raises(expected_exception=TransactionBeginError): + await transaction.execute( + f"SELECT * FROM {table_name}", + ) await transaction.begin() @@ -171,7 +169,7 @@ async def test_transaction_rollback( await transaction.rollback() - with pytest.raises(expected_exception=TransactionBeginError): + with pytest.raises(expected_exception=TransactionClosedError): await transaction.execute( f"SELECT * FROM {table_name} WHERE name = $1", parameters=[test_name], @@ -182,7 +180,7 @@ async def test_transaction_rollback( f"INSERT INTO {table_name} VALUES ($1, $2)", parameters=[100, test_name], ) - connection.back_to_pool() + connection.close() assert not (result_from_conn.result()) @@ -199,9 +197,8 @@ async def test_transaction_release_savepoint( sp_name_2 = "sp2" await transaction.create_savepoint(sp_name_1) - - with pytest.raises(expected_exception=TransactionSavepointError): - await transaction.create_savepoint(sp_name_1) + # There is no problem in creating the same sp_name + await transaction.create_savepoint(sp_name_1) await transaction.create_savepoint(sp_name_2) @@ -287,7 +284,7 @@ async def test_transaction_fetch_row_more_than_one_row( ) -> None: connection = await psql_pool.connection() async with connection.transaction() as transaction: - with pytest.raises(RustPSQLDriverPyBaseError): + with pytest.raises(InterfaceError): await transaction.fetch_row( f"SELECT * FROM {table_name}", [], @@ -313,7 +310,7 @@ async def test_transaction_fetch_val_more_than_one_row( ) -> None: connection = await psql_pool.connection() async with connection.transaction() as transaction: - with pytest.raises(RustPSQLDriverPyBaseError): + with pytest.raises(InterfaceError): await transaction.fetch_row( f"SELECT * FROM {table_name}", [], @@ -361,30 +358,4 @@ async def test_execute_batch_method(psql_pool: ConnectionPool) -> None: await transaction.execute(querystring="SELECT * FROM execute_batch") await transaction.execute(querystring="SELECT * FROM execute_batch2") - connection.back_to_pool() - - -@pytest.mark.parametrize( - "synchronous_commit", - [ - SynchronousCommit.On, - SynchronousCommit.Off, - SynchronousCommit.Local, - SynchronousCommit.RemoteWrite, - SynchronousCommit.RemoteApply, - ], -) -async def test_synchronous_commit( - synchronous_commit: SynchronousCommit, - psql_pool: ConnectionPool, - table_name: str, - number_database_records: int, -) -> None: - async with psql_pool.acquire() as conn, conn.transaction( - synchronous_commit=synchronous_commit, - ) as trans: - res = await trans.execute( - f"SELECT * FROM {table_name}", - ) - - assert len(res.result()) == number_database_records + connection.close() diff --git a/src/connection/impls.rs b/src/connection/impls.rs new file mode 100644 index 00000000..931770aa --- /dev/null +++ b/src/connection/impls.rs @@ -0,0 +1,565 @@ +use bytes::Buf; +use pyo3::{PyAny, Python}; +use tokio_postgres::{CopyInSink, Portal as tp_Portal, Row, Statement, ToStatement}; + +use crate::{ + exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, + options::{IsolationLevel, ReadVariant}, + query_result::{PSQLDriverPyQueryResult, PSQLDriverSinglePyQueryResult}, + statement::{statement::PsqlpyStatement, statement_builder::StatementBuilder}, + transaction::structs::PSQLPyTransaction, + value_converter::to_python::postgres_to_py, +}; + +use deadpool_postgres::Transaction as dp_Transaction; +use tokio_postgres::Transaction as tp_Transaction; + +use super::{ + structs::{PSQLPyConnection, PoolConnection, SingleConnection}, + traits::{CloseTransaction, Connection, StartTransaction, Transaction}, +}; + +impl Transaction for T +where + T: Connection, +{ + async fn _start_transaction( + &mut self, + isolation_level: Option, + read_variant: Option, + deferrable: Option, + ) -> PSQLPyResult<()> { + let start_qs = self.build_start_qs(isolation_level, read_variant, deferrable); + self.batch_execute(start_qs.as_str()).await.map_err(|err| { + RustPSQLDriverError::TransactionBeginError( + format!("Cannot start transaction due to - {err}").into(), + ) + })?; + + Ok(()) + } + + async fn _commit(&self) -> PSQLPyResult<()> { + self.batch_execute("COMMIT;").await.map_err(|err| { + RustPSQLDriverError::TransactionCommitError(format!( + "Cannot execute COMMIT statement, error - {err}" + )) + })?; + Ok(()) + } + + async fn _rollback(&self) -> PSQLPyResult<()> { + self.batch_execute("ROLLBACK;").await.map_err(|err| { + RustPSQLDriverError::TransactionRollbackError(format!( + "Cannot execute ROLLBACK statement, error - {err}" + )) + })?; + Ok(()) + } +} + +impl Connection for SingleConnection { + async fn prepare(&self, query: &str, prepared: bool) -> PSQLPyResult { + let prepared_stmt = self.connection.prepare(query).await?; + + if !prepared { + self.drop_prepared(&prepared_stmt).await?; + } + return Ok(prepared_stmt); + } + + async fn drop_prepared(&self, stmt: &Statement) -> PSQLPyResult<()> { + let deallocate_query = format!("DEALLOCATE PREPARE {}", stmt.name()); + + Ok(self.connection.batch_execute(&deallocate_query).await?) + } + + async fn query( + &self, + statement: &T, + params: &[&(dyn postgres_types::ToSql + Sync)], + ) -> PSQLPyResult> + where + T: ?Sized + ToStatement, + { + Ok(self.connection.query(statement, params).await?) + } + + async fn query_typed( + &self, + statement: &str, + params: &[(&(dyn postgres_types::ToSql + Sync), postgres_types::Type)], + ) -> PSQLPyResult> { + Ok(self.connection.query_typed(statement, params).await?) + } + + async fn batch_execute(&self, query: &str) -> PSQLPyResult<()> { + Ok(self.connection.batch_execute(query).await?) + } + + async fn query_one( + &self, + statement: &T, + params: &[&(dyn postgres_types::ToSql + Sync)], + ) -> PSQLPyResult + where + T: ?Sized + ToStatement, + { + Ok(self.connection.query_one(statement, params).await?) + } +} + +impl StartTransaction for SingleConnection { + async fn start_transaction( + &mut self, + isolation_level: Option, + read_variant: Option, + deferrable: Option, + ) -> PSQLPyResult<()> { + let res = self + ._start_transaction(isolation_level, read_variant, deferrable) + .await?; + self.in_transaction = true; + + Ok(res) + } +} + +impl CloseTransaction for SingleConnection { + async fn commit(&mut self) -> PSQLPyResult<()> { + let res = self._commit().await?; + self.in_transaction = false; + + Ok(res) + } + + async fn rollback(&mut self) -> PSQLPyResult<()> { + let res = self._rollback().await?; + self.in_transaction = false; + + Ok(res) + } +} + +impl Connection for PoolConnection { + async fn prepare(&self, query: &str, prepared: bool) -> PSQLPyResult { + if prepared { + return Ok(self.connection.prepare_cached(query).await?); + } + + let prepared = self.connection.prepare(query).await?; + self.drop_prepared(&prepared).await?; + return Ok(prepared); + } + + async fn drop_prepared(&self, stmt: &Statement) -> PSQLPyResult<()> { + let deallocate_query = format!("DEALLOCATE PREPARE {}", stmt.name()); + + Ok(self.connection.batch_execute(&deallocate_query).await?) + } + + async fn query( + &self, + statement: &T, + params: &[&(dyn postgres_types::ToSql + Sync)], + ) -> PSQLPyResult> + where + T: ?Sized + ToStatement, + { + Ok(self.connection.query(statement, params).await?) + } + + async fn query_typed( + &self, + statement: &str, + params: &[(&(dyn postgres_types::ToSql + Sync), postgres_types::Type)], + ) -> PSQLPyResult> { + Ok(self.connection.query_typed(statement, params).await?) + } + + async fn batch_execute(&self, query: &str) -> PSQLPyResult<()> { + Ok(self.connection.batch_execute(query).await?) + } + + async fn query_one( + &self, + statement: &T, + params: &[&(dyn postgres_types::ToSql + Sync)], + ) -> PSQLPyResult + where + T: ?Sized + ToStatement, + { + Ok(self.connection.query_one(statement, params).await?) + } +} + +impl StartTransaction for PoolConnection { + async fn start_transaction( + &mut self, + isolation_level: Option, + read_variant: Option, + deferrable: Option, + ) -> PSQLPyResult<()> { + self.in_transaction = true; + self._start_transaction(isolation_level, read_variant, deferrable) + .await + } +} + +impl CloseTransaction for PoolConnection { + async fn commit(&mut self) -> PSQLPyResult<()> { + let res = self._commit().await?; + self.in_transaction = false; + + Ok(res) + } + + async fn rollback(&mut self) -> PSQLPyResult<()> { + let res = self._rollback().await?; + self.in_transaction = false; + + Ok(res) + } +} + +impl Connection for PSQLPyConnection { + async fn prepare(&self, query: &str, prepared: bool) -> PSQLPyResult { + match self { + PSQLPyConnection::PoolConn(p_conn) => p_conn.prepare(query, prepared).await, + PSQLPyConnection::SingleConnection(s_conn) => s_conn.prepare(query, prepared).await, + } + } + + async fn drop_prepared(&self, stmt: &Statement) -> PSQLPyResult<()> { + match self { + PSQLPyConnection::PoolConn(p_conn) => p_conn.drop_prepared(stmt).await, + PSQLPyConnection::SingleConnection(s_conn) => s_conn.drop_prepared(stmt).await, + } + } + + async fn query( + &self, + statement: &T, + params: &[&(dyn postgres_types::ToSql + Sync)], + ) -> PSQLPyResult> + where + T: ?Sized + ToStatement, + { + match self { + PSQLPyConnection::PoolConn(p_conn) => p_conn.query(statement, params).await, + PSQLPyConnection::SingleConnection(s_conn) => s_conn.query(statement, params).await, + } + } + + async fn query_typed( + &self, + statement: &str, + params: &[(&(dyn postgres_types::ToSql + Sync), postgres_types::Type)], + ) -> PSQLPyResult> { + match self { + PSQLPyConnection::PoolConn(p_conn) => p_conn.query_typed(statement, params).await, + PSQLPyConnection::SingleConnection(s_conn) => { + s_conn.query_typed(statement, params).await + } + } + } + + async fn batch_execute(&self, query: &str) -> PSQLPyResult<()> { + match self { + PSQLPyConnection::PoolConn(p_conn) => p_conn.batch_execute(query).await, + PSQLPyConnection::SingleConnection(s_conn) => s_conn.batch_execute(query).await, + } + } + + async fn query_one( + &self, + statement: &T, + params: &[&(dyn postgres_types::ToSql + Sync)], + ) -> PSQLPyResult + where + T: ?Sized + ToStatement, + { + match self { + PSQLPyConnection::PoolConn(p_conn) => p_conn.query_one(statement, params).await, + PSQLPyConnection::SingleConnection(s_conn) => s_conn.query_one(statement, params).await, + } + } +} + +impl StartTransaction for PSQLPyConnection { + async fn start_transaction( + &mut self, + isolation_level: Option, + read_variant: Option, + deferrable: Option, + ) -> PSQLPyResult<()> { + match self { + PSQLPyConnection::PoolConn(p_conn) => { + p_conn + .start_transaction(isolation_level, read_variant, deferrable) + .await + } + PSQLPyConnection::SingleConnection(s_conn) => { + s_conn + .start_transaction(isolation_level, read_variant, deferrable) + .await + } + } + } +} + +impl CloseTransaction for PSQLPyConnection { + async fn commit(&mut self) -> PSQLPyResult<()> { + match self { + PSQLPyConnection::PoolConn(p_conn) => p_conn.commit().await, + PSQLPyConnection::SingleConnection(s_conn) => s_conn.commit().await, + } + } + + async fn rollback(&mut self) -> PSQLPyResult<()> { + match self { + PSQLPyConnection::PoolConn(p_conn) => p_conn.rollback().await, + PSQLPyConnection::SingleConnection(s_conn) => s_conn.rollback().await, + } + } +} + +impl PSQLPyConnection { + pub fn in_transaction(&self) -> bool { + match self { + PSQLPyConnection::PoolConn(conn) => conn.in_transaction, + PSQLPyConnection::SingleConnection(conn) => conn.in_transaction, + } + } + + pub async fn prepare_statement( + &self, + querystring: String, + parameters: Option>, + ) -> PSQLPyResult { + StatementBuilder::new(&querystring, ¶meters, self, Some(true)) + .build() + .await + } + + pub async fn execute_statement( + &self, + statement: &PsqlpyStatement, + ) -> PSQLPyResult { + let result = self + .query(statement.statement_query()?, &statement.params()) + .await?; + + Ok(PSQLDriverPyQueryResult::new(result)) + } + + pub async fn execute( + &self, + querystring: String, + parameters: Option>, + prepared: Option, + ) -> PSQLPyResult { + let statement = StatementBuilder::new(&querystring, ¶meters, self, prepared) + .build() + .await?; + + let prepared = prepared.unwrap_or(true); + let result = match prepared { + true => { + self.query(statement.statement_query()?, &statement.params()) + .await + } + false => { + self.query_typed(statement.raw_query(), &statement.params_typed()) + .await + } + }; + + let return_result = result.map_err(|err| { + RustPSQLDriverError::ConnectionExecuteError(format!( + "Cannot execute query, error - {err}" + )) + })?; + + Ok(PSQLDriverPyQueryResult::new(return_result)) + } + + pub async fn execute_many( + &self, + querystring: String, + parameters: Option>>, + prepared: Option, + ) -> PSQLPyResult<()> { + let mut statements: Vec = vec![]; + if let Some(parameters) = parameters { + for vec_of_py_any in parameters { + // TODO: Fix multiple qs creation + let statement = + StatementBuilder::new(&querystring, &Some(vec_of_py_any), self, prepared) + .build() + .await?; + + statements.push(statement); + } + } + + let prepared = prepared.unwrap_or(true); + + for statement in statements { + let querystring_result = if prepared { + let prepared_stmt = &self.prepare(&statement.raw_query(), true).await; + if let Err(error) = prepared_stmt { + return Err(RustPSQLDriverError::ConnectionExecuteError(format!( + "Cannot prepare statement in execute_many, operation rolled back {error}", + ))); + } + self.query( + &self.prepare(&statement.raw_query(), true).await?, + &statement.params(), + ) + .await + } else { + self.query(statement.raw_query(), &statement.params()).await + }; + + if let Err(error) = querystring_result { + return Err(RustPSQLDriverError::ConnectionExecuteError(format!( + "Error occured in `execute_many` statement: {error}" + ))); + } + } + + return Ok(()); + } + + pub async fn fetch_row_raw( + &self, + querystring: String, + parameters: Option>, + prepared: Option, + ) -> PSQLPyResult { + let statement = StatementBuilder::new(&querystring, ¶meters, self, prepared) + .build() + .await?; + + let prepared = prepared.unwrap_or(true); + + let result = if prepared { + self.query_one( + &self + .prepare(&statement.raw_query(), true) + .await + .map_err(|err| { + RustPSQLDriverError::ConnectionExecuteError(format!( + "Cannot prepare statement, error - {err}" + )) + })?, + &statement.params(), + ) + .await + .map_err(|err| RustPSQLDriverError::ConnectionExecuteError(format!("{err}")))? + } else { + self.query_one(statement.raw_query(), &statement.params()) + .await + .map_err(|err| RustPSQLDriverError::ConnectionExecuteError(format!("{err}")))? + }; + + return Ok(result); + } + + pub async fn fetch_row( + &self, + querystring: String, + parameters: Option>, + prepared: Option, + ) -> PSQLPyResult { + let result = self + .fetch_row_raw(querystring, parameters, prepared) + .await?; + + return Ok(PSQLDriverSinglePyQueryResult::new(result)); + } + + pub async fn fetch_val( + &self, + querystring: String, + parameters: Option>, + prepared: Option, + ) -> PSQLPyResult> { + let result = self + .fetch_row_raw(querystring, parameters, prepared) + .await?; + + return Python::with_gil(|gil| match result.columns().first() { + Some(first_column) => postgres_to_py(gil, &result, first_column, 0, &None), + None => Ok(gil.None()), + }); + } + + pub async fn copy_in(&self, statement: &T) -> PSQLPyResult> + where + T: ?Sized + ToStatement, + U: Buf + 'static + Send, + { + match self { + PSQLPyConnection::PoolConn(pconn) => { + return Ok(pconn.connection.copy_in(statement).await?) + } + PSQLPyConnection::SingleConnection(sconn) => { + return Ok(sconn.connection.copy_in(statement).await?) + } + } + } + + pub async fn transaction(&mut self) -> PSQLPyResult { + match self { + PSQLPyConnection::PoolConn(conn) => { + let transaction = unsafe { + std::mem::transmute::, dp_Transaction<'static>>( + conn.connection.transaction().await?, + ) + }; + Ok(PSQLPyTransaction::PoolTransaction(transaction)) + } + PSQLPyConnection::SingleConnection(conn) => { + let transaction = unsafe { + std::mem::transmute::, tp_Transaction<'static>>( + conn.connection.transaction().await?, + ) + }; + Ok(PSQLPyTransaction::SingleTransaction(transaction)) + } + } + } + + pub async fn portal( + &mut self, + querystring: Option<&String>, + parameters: &Option>, + statement: Option<&PsqlpyStatement>, + ) -> PSQLPyResult<(PSQLPyTransaction, tp_Portal)> { + let statement = { + match statement { + Some(stmt) => stmt, + None => { + let Some(querystring) = querystring else { + return Err(RustPSQLDriverError::ConnectionExecuteError( + "Can't create cursor without querystring".into(), + )); + }; + + &StatementBuilder::new(querystring, parameters, self, Some(false)) + .build() + .await? + } + } + }; + + let transaction = self.transaction().await?; + let inner_portal = transaction + .portal(statement.raw_query(), &statement.params()) + .await?; + + Ok((transaction, inner_portal)) + } +} diff --git a/src/connection/mod.rs b/src/connection/mod.rs new file mode 100644 index 00000000..c8f176fa --- /dev/null +++ b/src/connection/mod.rs @@ -0,0 +1,3 @@ +pub mod impls; +pub mod structs; +pub mod traits; diff --git a/src/connection/structs.rs b/src/connection/structs.rs new file mode 100644 index 00000000..a50d3d69 --- /dev/null +++ b/src/connection/structs.rs @@ -0,0 +1,48 @@ +use std::sync::Arc; + +use deadpool_postgres::Object; +use tokio_postgres::{Client, Config}; + +#[derive(Debug)] +pub struct PoolConnection { + pub connection: Object, + pub in_transaction: bool, + pub in_cursor: bool, + pub pg_config: Arc, +} + +impl PoolConnection { + pub fn new(connection: Object, pg_config: Arc) -> Self { + Self { + connection, + in_transaction: false, + in_cursor: false, + pg_config, + } + } +} + +#[derive(Debug)] +pub struct SingleConnection { + pub connection: Client, + pub in_transaction: bool, + pub in_cursor: bool, + pub pg_config: Arc, +} + +impl SingleConnection { + pub fn new(connection: Client, pg_config: Arc) -> Self { + Self { + connection, + in_transaction: false, + in_cursor: false, + pg_config, + } + } +} + +#[derive(Debug)] +pub enum PSQLPyConnection { + PoolConn(PoolConnection), + SingleConnection(SingleConnection), +} diff --git a/src/connection/traits.rs b/src/connection/traits.rs new file mode 100644 index 00000000..ccf8f467 --- /dev/null +++ b/src/connection/traits.rs @@ -0,0 +1,103 @@ +use postgres_types::{ToSql, Type}; +use pyo3::PyAny; +use tokio_postgres::{Row, Statement, ToStatement}; + +use crate::exceptions::rust_errors::PSQLPyResult; + +use crate::options::{IsolationLevel, ReadVariant}; + +pub trait Connection { + fn prepare( + &self, + query: &str, + prepared: bool, + ) -> impl std::future::Future> + Send; + + fn drop_prepared( + &self, + stmt: &Statement, + ) -> impl std::future::Future> + Send; + + fn query( + &self, + statement: &T, + params: &[&(dyn ToSql + Sync)], + ) -> impl std::future::Future>> + where + T: ?Sized + ToStatement; + + fn query_typed( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> impl std::future::Future>>; + + fn batch_execute( + &self, + query: &str, + ) -> impl std::future::Future> + Send; + + fn query_one( + &self, + statement: &T, + params: &[&(dyn ToSql + Sync)], + ) -> impl std::future::Future> + where + T: ?Sized + ToStatement; +} + +pub trait Transaction { + fn build_start_qs( + &self, + isolation_level: Option, + read_variant: Option, + deferrable: Option, + ) -> String { + let mut querystring = "START TRANSACTION".to_string(); + + if let Some(level) = isolation_level { + let level = &level.to_str_level(); + querystring.push_str(format!(" ISOLATION LEVEL {level}").as_str()); + }; + + querystring.push_str(match read_variant { + Some(ReadVariant::ReadOnly) => " READ ONLY", + Some(ReadVariant::ReadWrite) => " READ WRITE", + None => "", + }); + + querystring.push_str(match deferrable { + Some(true) => " DEFERRABLE", + Some(false) => " NOT DEFERRABLE", + None => "", + }); + + querystring + } + + fn _start_transaction( + &mut self, + isolation_level: Option, + read_variant: Option, + deferrable: Option, + ) -> impl std::future::Future>; + + fn _commit(&self) -> impl std::future::Future>; + + fn _rollback(&self) -> impl std::future::Future>; +} + +pub trait StartTransaction: Transaction { + fn start_transaction( + &mut self, + isolation_level: Option, + read_variant: Option, + deferrable: Option, + ) -> impl std::future::Future>; +} + +pub trait CloseTransaction: StartTransaction { + fn commit(&mut self) -> impl std::future::Future>; + + fn rollback(&mut self) -> impl std::future::Future>; +} diff --git a/src/driver/common.rs b/src/driver/common.rs new file mode 100644 index 00000000..dc92a28f --- /dev/null +++ b/src/driver/common.rs @@ -0,0 +1,291 @@ +use tokio_postgres::config::Host; + +use std::net::IpAddr; + +use super::{ + connection::Connection, cursor::Cursor, prepared_statement::PreparedStatement, + transaction::Transaction, +}; + +use pyo3::{pymethods, Py, PyAny}; + +use crate::{ + connection::traits::CloseTransaction, + exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, +}; + +use bytes::BytesMut; +use futures_util::pin_mut; +use pyo3::{buffer::PyBuffer, PyErr, Python}; +use tokio_postgres::binary_copy::BinaryCopyInWriter; + +use crate::format_helpers::quote_ident; + +macro_rules! impl_config_py_methods { + ($name:ident) => { + #[pymethods] + impl $name { + #[getter] + fn conn_dbname(&self) -> Option<&str> { + self.pg_config.get_dbname() + } + + #[getter] + fn user(&self) -> Option<&str> { + self.pg_config.get_user() + } + + #[getter] + fn host_addrs(&self) -> Vec { + let mut host_addrs_vec = vec![]; + + let host_addrs = self.pg_config.get_hostaddrs(); + for ip_addr in host_addrs { + match ip_addr { + IpAddr::V4(ipv4) => { + host_addrs_vec.push(ipv4.to_string()); + } + IpAddr::V6(ipv6) => { + host_addrs_vec.push(ipv6.to_string()); + } + } + } + + host_addrs_vec + } + + #[cfg(unix)] + #[getter] + fn hosts(&self) -> Vec { + let mut hosts_vec = vec![]; + + let hosts = self.pg_config.get_hosts(); + for host in hosts { + match host { + Host::Tcp(host) => { + hosts_vec.push(host.to_string()); + } + Host::Unix(host) => { + hosts_vec.push(host.display().to_string()); + } + } + } + + hosts_vec + } + + #[cfg(not(unix))] + #[getter] + fn hosts(&self) -> Vec { + let mut hosts_vec = vec![]; + + let hosts = self.pg_config.get_hosts(); + for host in hosts { + match host { + Host::Tcp(host) => { + hosts_vec.push(host.to_string()); + } + _ => unreachable!(), + } + } + + hosts_vec + } + + #[getter] + fn ports(&self) -> Vec<&u16> { + return self.pg_config.get_ports().iter().collect::>(); + } + + #[getter] + fn options(&self) -> Option<&str> { + return self.pg_config.get_options(); + } + } + }; +} + +impl_config_py_methods!(Transaction); +impl_config_py_methods!(Connection); +impl_config_py_methods!(Cursor); +// impl_config_py_methods!(Portal); + +macro_rules! impl_is_closed_method { + ($name:ident) => { + #[pymethods] + impl $name { + fn is_closed(&self) -> bool { + if self.conn.is_some() { + return true; + } + false + } + } + }; +} + +impl_is_closed_method!(Transaction); +impl_is_closed_method!(Connection); +impl_is_closed_method!(Cursor); + +macro_rules! impl_cursor_method { + ($name:ident) => { + #[pymethods] + impl $name { + #[pyo3(signature = (querystring=None, parameters=None, array_size=None))] + pub fn cursor( + &self, + querystring: Option, + parameters: Option>, + array_size: Option, + ) -> PSQLPyResult { + Ok(Cursor::new( + self.conn.clone(), + querystring, + parameters, + array_size, + self.pg_config.clone(), + None, + )) + } + } + }; +} + +impl_cursor_method!(Transaction); +impl_cursor_method!(Connection); + +macro_rules! impl_prepare_method { + ($name:ident) => { + #[pymethods] + impl $name { + #[pyo3(signature = (querystring, parameters=None))] + pub async fn prepare( + &self, + querystring: String, + parameters: Option>, + ) -> PSQLPyResult { + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::ConnectionClosedError); + }; + + let read_conn_g = conn.read().await; + let prep_stmt = read_conn_g + .prepare_statement(querystring, parameters) + .await?; + + Ok(PreparedStatement::new( + self.conn.clone(), + self.pg_config.clone(), + prep_stmt, + )) + } + } + }; +} + +impl_prepare_method!(Transaction); +impl_prepare_method!(Connection); + +macro_rules! impl_transaction_methods { + ($name:ident, $val:expr $(,)?) => { + #[pymethods] + impl $name { + pub async fn commit(&mut self) -> PSQLPyResult<()> { + let conn = self.conn.clone(); + let Some(conn) = conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + let mut write_conn_g = conn.write().await; + write_conn_g.commit().await?; + + if $val { + self.conn = None; + } + + Ok(()) + } + + pub async fn rollback(&mut self) -> PSQLPyResult<()> { + let conn = self.conn.clone(); + let Some(conn) = conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + let mut write_conn_g = conn.write().await; + write_conn_g.rollback().await?; + + if $val { + self.conn = None; + } + + Ok(()) + } + } + }; +} + +impl_transaction_methods!(Transaction, true); + +macro_rules! impl_binary_copy_method { + ($name:ident) => { + #[pymethods] + impl $name { + #[pyo3(signature = (source, table_name, columns=None, schema_name=None))] + pub async fn binary_copy_to_table( + self_: pyo3::Py, + source: Py, + table_name: String, + columns: Option>, + schema_name: Option, + ) -> PSQLPyResult { + let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).conn.clone()); + let mut table_name = quote_ident(&table_name); + if let Some(schema_name) = schema_name { + table_name = format!("{}.{}", quote_ident(&schema_name), table_name); + } + + let mut formated_columns = String::default(); + if let Some(columns) = columns { + formated_columns = format!("({})", columns.join(", ")); + } + + let copy_qs = + format!("COPY {table_name}{formated_columns} FROM STDIN (FORMAT binary)"); + + if let Some(db_client) = db_client { + let mut psql_bytes: BytesMut = Python::with_gil(|gil| { + let possible_py_buffer: Result, PyErr> = + source.extract::>(gil); + if let Ok(py_buffer) = possible_py_buffer { + let vec_buf = py_buffer.to_vec(gil)?; + return Ok(BytesMut::from(vec_buf.as_slice())); + } + + if let Ok(py_bytes) = source.call_method0(gil, "getvalue") { + if let Ok(bytes) = py_bytes.extract::>(gil) { + return Ok(BytesMut::from(bytes.as_slice())); + } + } + + Err(RustPSQLDriverError::PyToRustValueConversionError( + "source must be bytes or support Buffer protocol".into(), + )) + })?; + + let read_conn_g = db_client.read().await; + let sink = read_conn_g.copy_in(©_qs).await?; + let writer = BinaryCopyInWriter::new_empty_buffer(sink, &[]); + pin_mut!(writer); + writer.as_mut().write_raw_bytes(&mut psql_bytes).await?; + let rows_created = writer.as_mut().finish_empty().await?; + return Ok(rows_created); + } + + Ok(0) + } + } + }; +} + +impl_binary_copy_method!(Connection); +impl_binary_copy_method!(Transaction); diff --git a/src/driver/connection.rs b/src/driver/connection.rs index d38b71f9..0d562b00 100644 --- a/src/driver/connection.rs +++ b/src/driver/connection.rs @@ -1,52 +1,141 @@ -use bytes::BytesMut; use deadpool_postgres::Pool; -use futures_util::pin_mut; -use pyo3::{buffer::PyBuffer, pyclass, pymethods, Py, PyAny, PyErr, Python}; -use std::{collections::HashSet, net::IpAddr, sync::Arc}; -use tokio_postgres::{binary_copy::BinaryCopyInWriter, config::Host, Config}; +use pyo3::{pyclass, pyfunction, pymethods, Py, PyAny, PyErr}; +use std::sync::Arc; +use tokio::sync::RwLock; +use tokio_postgres::Config; use crate::{ + connection::{ + structs::{PSQLPyConnection, PoolConnection}, + traits::Connection as _, + }, exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, - format_helpers::quote_ident, + options::{IsolationLevel, LoadBalanceHosts, ReadVariant, SslMode, TargetSessionAttrs}, query_result::{PSQLDriverPyQueryResult, PSQLDriverSinglePyQueryResult}, runtime::tokio_runtime, }; -use super::{ - cursor::Cursor, - inner_connection::PsqlpyConnection, - transaction::Transaction, - transaction_options::{IsolationLevel, ReadVariant, SynchronousCommit}, -}; +use super::{connection_pool::connect_pool, transaction::Transaction}; + +/// Make new connection pool. +/// +/// # Errors +/// May return error if cannot build new connection pool. +#[pyfunction] +#[pyo3(signature = ( + dsn=None, + username=None, + password=None, + host=None, + hosts=None, + port=None, + ports=None, + db_name=None, + target_session_attrs=None, + options=None, + application_name=None, + connect_timeout_sec=None, + connect_timeout_nanosec=None, + tcp_user_timeout_sec=None, + tcp_user_timeout_nanosec=None, + keepalives=None, + keepalives_idle_sec=None, + keepalives_idle_nanosec=None, + keepalives_interval_sec=None, + keepalives_interval_nanosec=None, + keepalives_retries=None, + load_balance_hosts=None, + ssl_mode=None, + ca_file=None, +))] +#[allow(clippy::too_many_arguments)] +pub async fn connect( + dsn: Option, + username: Option, + password: Option, + host: Option, + hosts: Option>, + port: Option, + ports: Option>, + db_name: Option, + target_session_attrs: Option, + options: Option, + application_name: Option, + connect_timeout_sec: Option, + connect_timeout_nanosec: Option, + tcp_user_timeout_sec: Option, + tcp_user_timeout_nanosec: Option, + keepalives: Option, + keepalives_idle_sec: Option, + keepalives_idle_nanosec: Option, + keepalives_interval_sec: Option, + keepalives_interval_nanosec: Option, + keepalives_retries: Option, + load_balance_hosts: Option, + ssl_mode: Option, + ca_file: Option, +) -> PSQLPyResult { + let mut connection_pool = connect_pool( + dsn, + username, + password, + host, + hosts, + port, + ports, + db_name, + target_session_attrs, + options, + application_name, + connect_timeout_sec, + connect_timeout_nanosec, + tcp_user_timeout_sec, + tcp_user_timeout_nanosec, + keepalives, + keepalives_idle_sec, + keepalives_idle_nanosec, + keepalives_interval_sec, + keepalives_interval_nanosec, + keepalives_retries, + load_balance_hosts, + ssl_mode, + ca_file, + Some(2), + None, + )?; + + let db_connection = tokio_runtime() + .spawn(async move { connection_pool.retrieve_connection().await }) + .await??; + + Ok(db_connection) +} #[pyclass(subclass)] -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Connection { - db_client: Option>, + pub conn: Option>>, db_pool: Option, - pg_config: Arc, - prepare: bool, + pub pg_config: Arc, } impl Connection { #[must_use] pub fn new( - db_client: Option>, + conn: Option>>, db_pool: Option, pg_config: Arc, - prepare: bool, ) -> Self { Connection { - db_client, + conn, db_pool, pg_config, - prepare, } } #[must_use] - pub fn db_client(&self) -> Option> { - self.db_client.clone() + pub fn db_client(&self) -> Option>> { + self.conn.clone() } #[must_use] @@ -57,96 +146,25 @@ impl Connection { impl Default for Connection { fn default() -> Self { - Connection::new(None, None, Arc::new(Config::default()), true) + Connection::new(None, None, Arc::new(Config::default())) } } #[pymethods] impl Connection { - #[getter] - fn conn_dbname(&self) -> Option<&str> { - self.pg_config.get_dbname() - } - - #[getter] - fn user(&self) -> Option<&str> { - self.pg_config.get_user() - } - - #[getter] - fn host_addrs(&self) -> Vec { - let mut host_addrs_vec = vec![]; - - let host_addrs = self.pg_config.get_hostaddrs(); - for ip_addr in host_addrs { - match ip_addr { - IpAddr::V4(ipv4) => { - host_addrs_vec.push(ipv4.to_string()); - } - IpAddr::V6(ipv6) => { - host_addrs_vec.push(ipv6.to_string()); - } - } - } - - host_addrs_vec - } - - #[cfg(unix)] - #[getter] - fn hosts(&self) -> Vec { - let mut hosts_vec = vec![]; - - let hosts = self.pg_config.get_hosts(); - for host in hosts { - match host { - Host::Tcp(host) => { - hosts_vec.push(host.to_string()); - } - Host::Unix(host) => { - hosts_vec.push(host.display().to_string()); - } - } - } - - hosts_vec - } - - #[cfg(not(unix))] - #[getter] - fn hosts(&self) -> Vec { - let mut hosts_vec = vec![]; - - let hosts = self.pg_config.get_hosts(); - for host in hosts { - match host { - Host::Tcp(host) => { - hosts_vec.push(host.to_string()); - } - _ => unreachable!(), - } - } - - hosts_vec - } - - #[getter] - fn ports(&self) -> Vec<&u16> { - return self.pg_config.get_ports().iter().collect::>(); - } - - #[getter] - fn options(&self) -> Option<&str> { - return self.pg_config.get_options(); + async fn in_transaction(&self) -> bool { + let Some(conn) = &self.conn else { return false }; + let read_conn_g = conn.read().await; + read_conn_g.in_transaction() } async fn __aenter__<'a>(self_: Py) -> PSQLPyResult> { - let (db_client, db_pool, prepare) = pyo3::Python::with_gil(|gil| { + let (db_client, db_pool, pg_config) = pyo3::Python::with_gil(|gil| { let self_ = self_.borrow(gil); ( - self_.db_client.clone(), + self_.conn.clone(), self_.db_pool.clone(), - self_.prepare, + self_.pg_config.clone(), ) }); @@ -155,15 +173,16 @@ impl Connection { } if let Some(db_pool) = db_pool { - let db_connection = tokio_runtime() + let connection = tokio_runtime() .spawn(async move { Ok::(db_pool.get().await?) }) .await??; pyo3::Python::with_gil(|gil| { let mut self_ = self_.borrow_mut(gil); - self_.db_client = - Some(Arc::new(PsqlpyConnection::PoolConn(db_connection, prepare))); + self_.conn = Some(Arc::new(RwLock::new(PSQLPyConnection::PoolConn( + PoolConnection::new(connection, pg_config), + )))); }); return Ok(self_); } @@ -188,7 +207,7 @@ impl Connection { pyo3::Python::with_gil(|gil| { let mut self_ = self_.borrow_mut(gil); - std::mem::take(&mut self_.db_client); + std::mem::take(&mut self_.conn); std::mem::take(&mut self_.db_pool); if is_exception_none { @@ -214,10 +233,11 @@ impl Connection { parameters: Option>, prepared: Option, ) -> PSQLPyResult { - let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).db_client.clone()); + let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).conn.clone()); if let Some(db_client) = db_client { - let res = db_client.execute(querystring, parameters, prepared).await; + let read_conn_g = db_client.read().await; + let res = read_conn_g.execute(querystring, parameters, prepared).await; return res; } @@ -237,10 +257,11 @@ impl Connection { /// 1) Connection is closed. /// 2) Cannot execute querystring. pub async fn execute_batch(self_: pyo3::Py, querystring: String) -> PSQLPyResult<()> { - let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).db_client.clone()); + let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).conn.clone()); if let Some(db_client) = db_client { - return db_client.batch_execute(&querystring).await; + let read_conn_g = db_client.read().await; + return read_conn_g.batch_execute(&querystring).await; } Err(RustPSQLDriverError::ConnectionClosedError) @@ -262,13 +283,17 @@ impl Connection { querystring: String, parameters: Option>>, prepared: Option, - ) -> PSQLPyResult<()> { - let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).db_client.clone()); + ) -> PSQLPyResult> { + let (db_client, py_none) = + pyo3::Python::with_gil(|gil| (self_.borrow(gil).conn.clone(), gil.None().into_any())); if let Some(db_client) = db_client { - return db_client + let read_conn_g = db_client.read().await; + read_conn_g .execute_many(querystring, parameters, prepared) - .await; + .await?; + + return Ok(py_none); } Err(RustPSQLDriverError::ConnectionClosedError) @@ -289,10 +314,11 @@ impl Connection { parameters: Option>, prepared: Option, ) -> PSQLPyResult { - let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).db_client.clone()); + let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).conn.clone()); if let Some(db_client) = db_client { - return db_client.execute(querystring, parameters, prepared).await; + let read_conn_g = db_client.read().await; + return read_conn_g.execute(querystring, parameters, prepared).await; } Err(RustPSQLDriverError::ConnectionClosedError) @@ -319,10 +345,13 @@ impl Connection { parameters: Option>, prepared: Option, ) -> PSQLPyResult { - let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).db_client.clone()); + let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).conn.clone()); if let Some(db_client) = db_client { - return db_client.fetch_row(querystring, parameters, prepared).await; + let read_conn_g = db_client.read().await; + return read_conn_g + .fetch_row(querystring, parameters, prepared) + .await; } Err(RustPSQLDriverError::ConnectionClosedError) @@ -346,10 +375,13 @@ impl Connection { parameters: Option>, prepared: Option, ) -> PSQLPyResult> { - let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).db_client.clone()); + let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).conn.clone()); if let Some(db_client) = db_client { - return db_client.fetch_val(querystring, parameters, prepared).await; + let read_conn_g = db_client.read().await; + return read_conn_g + .fetch_val(querystring, parameters, prepared) + .await; } Err(RustPSQLDriverError::ConnectionClosedError) @@ -363,137 +395,32 @@ impl Connection { isolation_level=None, read_variant=None, deferrable=None, - synchronous_commit=None, ))] pub fn transaction( &self, isolation_level: Option, read_variant: Option, deferrable: Option, - synchronous_commit: Option, ) -> PSQLPyResult { - if let Some(db_client) = &self.db_client { - return Ok(Transaction::new( - db_client.clone(), - self.pg_config.clone(), - false, - false, - isolation_level, - synchronous_commit, - read_variant, - deferrable, - HashSet::new(), - )); - } - - Err(RustPSQLDriverError::ConnectionClosedError) - } - - /// Create new cursor object. - /// - /// # Errors - /// May return Err Result if db_client is None. - #[pyo3(signature = ( - querystring, - parameters=None, - fetch_number=None, - scroll=None, - prepared=None, - ))] - pub fn cursor( - &self, - querystring: String, - parameters: Option>, - fetch_number: Option, - scroll: Option, - prepared: Option, - ) -> PSQLPyResult { - if let Some(db_client) = &self.db_client { - return Ok(Cursor::new( - db_client.clone(), - self.pg_config.clone(), - querystring, - parameters, - "cur_name".into(), - fetch_number.unwrap_or(10), - scroll, - prepared, - )); - } - - Err(RustPSQLDriverError::ConnectionClosedError) + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::ConnectionClosedError); + }; + Ok(Transaction::new( + Some(conn.clone()), + self.pg_config.clone(), + isolation_level, + read_variant, + deferrable, + )) } #[allow(clippy::needless_pass_by_value)] - pub fn back_to_pool(self_: pyo3::Py) { + pub fn close(self_: pyo3::Py) { pyo3::Python::with_gil(|gil| { let mut connection = self_.borrow_mut(gil); - if connection.db_client.is_some() { - std::mem::take(&mut connection.db_client); + if connection.conn.is_some() { + std::mem::take(&mut connection.conn); } }); } - - /// Perform binary copy to postgres table. - /// - /// # Errors - /// May return Err Result if cannot get bytes, - /// cannot perform request to the database, - /// cannot write bytes to the database. - #[pyo3(signature = ( - source, - table_name, - columns=None, - schema_name=None, - ))] - pub async fn binary_copy_to_table( - self_: pyo3::Py, - source: Py, - table_name: String, - columns: Option>, - schema_name: Option, - ) -> PSQLPyResult { - let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).db_client.clone()); - let mut table_name = quote_ident(&table_name); - if let Some(schema_name) = schema_name { - table_name = format!("{}.{}", quote_ident(&schema_name), table_name); - } - - let mut formated_columns = String::default(); - if let Some(columns) = columns { - formated_columns = format!("({})", columns.join(", ")); - } - - let copy_qs = format!("COPY {table_name}{formated_columns} FROM STDIN (FORMAT binary)"); - - if let Some(db_client) = db_client { - let mut psql_bytes: BytesMut = Python::with_gil(|gil| { - let possible_py_buffer: Result, PyErr> = - source.extract::>(gil); - if let Ok(py_buffer) = possible_py_buffer { - let vec_buf = py_buffer.to_vec(gil)?; - return Ok(BytesMut::from(vec_buf.as_slice())); - } - - if let Ok(py_bytes) = source.call_method0(gil, "getvalue") { - if let Ok(bytes) = py_bytes.extract::>(gil) { - return Ok(BytesMut::from(bytes.as_slice())); - } - } - - Err(RustPSQLDriverError::PyToRustValueConversionError( - "source must be bytes or support Buffer protocol".into(), - )) - })?; - - let sink = db_client.copy_in(©_qs).await?; - let writer = BinaryCopyInWriter::new_empty_buffer(sink, &[]); - pin_mut!(writer); - writer.as_mut().write_raw_bytes(&mut psql_bytes).await?; - let rows_created = writer.as_mut().finish_empty().await?; - return Ok(rows_created); - } - - Ok(0) - } } diff --git a/src/driver/connection_pool.rs b/src/driver/connection_pool.rs index aa897012..16e1fe90 100644 --- a/src/driver/connection_pool.rs +++ b/src/driver/connection_pool.rs @@ -1,16 +1,21 @@ -use crate::runtime::tokio_runtime; +use crate::{ + connection::structs::{PSQLPyConnection, PoolConnection}, + runtime::tokio_runtime, +}; use deadpool_postgres::{Manager, ManagerConfig, Pool, RecyclingMethod}; use postgres_types::Type; use pyo3::{pyclass, pyfunction, pymethods, Py, PyAny}; use std::sync::Arc; +use tokio::sync::RwLock; use tokio_postgres::Config; -use crate::exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}; +use crate::{ + exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, + options::{ConnRecyclingMethod, LoadBalanceHosts, SslMode, TargetSessionAttrs}, +}; use super::{ - common_options::{ConnRecyclingMethod, LoadBalanceHosts, SslMode, TargetSessionAttrs}, connection::Connection, - inner_connection::PsqlpyConnection, listener::core::Listener, utils::{build_connection_config, build_manager, build_tls}, }; @@ -66,7 +71,7 @@ impl ConnectionPoolConf { conn_recycling_method=None, ))] #[allow(clippy::too_many_arguments)] -pub fn connect( +pub fn connect_pool( dsn: Option, username: Option, password: Option, @@ -239,6 +244,18 @@ impl ConnectionPool { } } + pub async fn retrieve_connection(&mut self) -> PSQLPyResult { + let connection = self.pool.get().await?; + + Ok(Connection::new( + Some(Arc::new(RwLock::new(PSQLPyConnection::PoolConn( + PoolConnection::new(connection, self.pg_config.clone()), + )))), + None, + self.pg_config.clone(), + )) + } + pub fn remove_prepared_stmt(&mut self, query: &str, types: &[Type]) { self.pool.manager().statement_caches.remove(query, types); } @@ -308,7 +325,7 @@ impl ConnectionPool { ssl_mode: Option, ca_file: Option, ) -> PSQLPyResult { - connect( + connect_pool( dsn, username, password, @@ -378,12 +395,7 @@ impl ConnectionPool { #[must_use] pub fn acquire(&self) -> Connection { - Connection::new( - None, - Some(self.pool.clone()), - self.pg_config.clone(), - self.pool_conf.prepare, - ) + Connection::new(None, Some(self.pool.clone()), self.pg_config.clone()) } #[must_use] @@ -394,12 +406,7 @@ impl ConnectionPool { (b_gil.pg_config.clone(), b_gil.pool_conf.clone()) }); - Listener::new( - pg_config, - pool_conf.ca_file, - pool_conf.ssl_mode, - pool_conf.prepare, - ) + Listener::new(pg_config, pool_conf.ca_file, pool_conf.ssl_mode) } /// Return new single connection. @@ -407,28 +414,22 @@ impl ConnectionPool { /// # Errors /// May return Err Result if cannot get new connection from the pool. pub async fn connection(self_: pyo3::Py) -> PSQLPyResult { - let (db_pool, pg_config, pool_conf) = pyo3::Python::with_gil(|gil| { + let (db_pool, pg_config) = pyo3::Python::with_gil(|gil| { let slf = self_.borrow(gil); - ( - slf.pool.clone(), - slf.pg_config.clone(), - slf.pool_conf.clone(), - ) + (slf.pool.clone(), slf.pg_config.clone()) }); - let db_connection = tokio_runtime() + let connection = tokio_runtime() .spawn(async move { Ok::(db_pool.get().await?) }) .await??; Ok(Connection::new( - Some(Arc::new(PsqlpyConnection::PoolConn( - db_connection, - pool_conf.prepare, - ))), + Some(Arc::new(RwLock::new(PSQLPyConnection::PoolConn( + PoolConnection::new(connection, pg_config.clone()), + )))), None, pg_config, - pool_conf.prepare, )) } diff --git a/src/driver/connection_pool_builder.rs b/src/driver/connection_pool_builder.rs index 0cd7432b..dcecd761 100644 --- a/src/driver/connection_pool_builder.rs +++ b/src/driver/connection_pool_builder.rs @@ -3,10 +3,12 @@ use std::{net::IpAddr, time::Duration}; use deadpool_postgres::{Manager, ManagerConfig, Pool, RecyclingMethod}; use pyo3::{pyclass, pymethods, Py, Python}; -use crate::exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}; +use crate::{ + exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, + options::{ConnRecyclingMethod, LoadBalanceHosts, SslMode, TargetSessionAttrs}, +}; use super::{ - common_options, connection_pool::ConnectionPool, utils::{build_manager, build_tls}, }; @@ -17,7 +19,7 @@ pub struct ConnectionPoolBuilder { max_db_pool_size: Option, conn_recycling_method: Option, ca_file: Option, - ssl_mode: Option, + ssl_mode: Option, prepare: Option, } @@ -104,7 +106,7 @@ impl ConnectionPoolBuilder { /// Set connection recycling method. fn conn_recycling_method( self_: Py, - conn_recycling_method: super::common_options::ConnRecyclingMethod, + conn_recycling_method: ConnRecyclingMethod, ) -> Py { Python::with_gil(|gil| { let mut self_ = self_.borrow_mut(gil); @@ -171,7 +173,7 @@ impl ConnectionPoolBuilder { /// /// Defaults to `prefer`. #[must_use] - pub fn ssl_mode(self_: Py, ssl_mode: crate::driver::common_options::SslMode) -> Py { + pub fn ssl_mode(self_: Py, ssl_mode: SslMode) -> Py { Python::with_gil(|gil| { let mut self_ = self_.borrow_mut(gil); self_.ssl_mode = Some(ssl_mode); @@ -259,7 +261,7 @@ impl ConnectionPoolBuilder { #[must_use] pub fn target_session_attrs( self_: Py, - target_session_attrs: super::common_options::TargetSessionAttrs, + target_session_attrs: TargetSessionAttrs, ) -> Py { Python::with_gil(|gil| { let mut self_ = self_.borrow_mut(gil); @@ -274,10 +276,7 @@ impl ConnectionPoolBuilder { /// /// Defaults to `disable`. #[must_use] - pub fn load_balance_hosts( - self_: Py, - load_balance_hosts: super::common_options::LoadBalanceHosts, - ) -> Py { + pub fn load_balance_hosts(self_: Py, load_balance_hosts: LoadBalanceHosts) -> Py { Python::with_gil(|gil| { let mut self_ = self_.borrow_mut(gil); self_ diff --git a/src/driver/cursor.rs b/src/driver/cursor.rs index 1f435ef5..3a8abe59 100644 --- a/src/driver/cursor.rs +++ b/src/driver/cursor.rs @@ -1,229 +1,87 @@ -use std::{net::IpAddr, sync::Arc}; +use std::sync::Arc; use pyo3::{ exceptions::PyStopAsyncIteration, pyclass, pymethods, Py, PyAny, PyErr, PyObject, Python, }; -use tokio_postgres::{config::Host, Config}; +use tokio::sync::RwLock; +use tokio_postgres::{Config, Portal as tp_Portal}; use crate::{ exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, query_result::PSQLDriverPyQueryResult, runtime::rustdriver_future, + statement::statement::PsqlpyStatement, + transaction::structs::PSQLPyTransaction, }; -use super::inner_connection::PsqlpyConnection; - -/// Additional implementation for the `Object` type. -#[allow(clippy::ref_option)] -trait CursorObjectTrait { - async fn cursor_start( - &self, - cursor_name: &str, - scroll: &Option, - querystring: &str, - prepared: &Option, - parameters: &Option>, - ) -> PSQLPyResult<()>; - - async fn cursor_close(&self, closed: &bool, cursor_name: &str) -> PSQLPyResult<()>; -} - -impl CursorObjectTrait for PsqlpyConnection { - /// Start the cursor. - /// - /// Execute `DECLARE` command with parameters. - /// - /// # Errors - /// May return Err Result if cannot execute querystring. - #[allow(clippy::ref_option)] - async fn cursor_start( - &self, - cursor_name: &str, - scroll: &Option, - querystring: &str, - prepared: &Option, - parameters: &Option>, - ) -> PSQLPyResult<()> { - let mut cursor_init_query = format!("DECLARE {cursor_name}"); - if let Some(scroll) = scroll { - if *scroll { - cursor_init_query.push_str(" SCROLL"); - } else { - cursor_init_query.push_str(" NO SCROLL"); - } - } - - cursor_init_query.push_str(format!(" CURSOR FOR {querystring}").as_str()); - - self.execute(cursor_init_query, parameters.clone(), *prepared) - .await - .map_err(|err| { - RustPSQLDriverError::CursorStartError(format!("Cannot start cursor, error - {err}")) - })?; - - Ok(()) - } +use crate::connection::structs::PSQLPyConnection; - /// Close the cursor. - /// - /// Execute `CLOSE` command. - /// - /// # Errors - /// May return Err Result if cannot execute querystring. - async fn cursor_close(&self, closed: &bool, cursor_name: &str) -> PSQLPyResult<()> { - if *closed { - return Err(RustPSQLDriverError::CursorCloseError( - "Cursor is already closed".into(), - )); - } +#[pyclass] +pub struct Cursor { + pub conn: Option>>, + querystring: Option, + parameters: Option>, + array_size: i32, - self.execute( - format!("CLOSE {cursor_name}"), - Option::default(), - Some(false), - ) - .await?; + statement: Option, - Ok(()) - } -} + transaction: Option>, + inner: Option, -#[pyclass(subclass)] -pub struct Cursor { - db_transaction: Option>, - pg_config: Arc, - querystring: String, - parameters: Option>, - cursor_name: String, - fetch_number: usize, - scroll: Option, - prepared: Option, - is_started: bool, - closed: bool, + pub pg_config: Arc, } impl Cursor { - #[must_use] pub fn new( - db_transaction: Arc, - pg_config: Arc, - querystring: String, + conn: Option>>, + querystring: Option, parameters: Option>, - cursor_name: String, - fetch_number: usize, - scroll: Option, - prepared: Option, + array_size: Option, + pg_config: Arc, + statement: Option, ) -> Self { - Cursor { - db_transaction: Some(db_transaction), - pg_config, + Self { + conn, + transaction: None, + inner: None, querystring, parameters, - cursor_name, - fetch_number, - scroll, - prepared, - is_started: false, - closed: false, - } - } -} - -#[pymethods] -impl Cursor { - #[getter] - fn conn_dbname(&self) -> Option<&str> { - self.pg_config.get_dbname() - } - - #[getter] - fn user(&self) -> Option<&str> { - self.pg_config.get_user() - } - - #[getter] - fn host_addrs(&self) -> Vec { - let mut host_addrs_vec = vec![]; - - let host_addrs = self.pg_config.get_hostaddrs(); - for ip_addr in host_addrs { - match ip_addr { - IpAddr::V4(ipv4) => { - host_addrs_vec.push(ipv4.to_string()); - } - IpAddr::V6(ipv6) => { - host_addrs_vec.push(ipv6.to_string()); - } - } - } - - host_addrs_vec - } - - #[cfg(unix)] - #[getter] - fn hosts(&self) -> Vec { - let mut hosts_vec = vec![]; - - let hosts = self.pg_config.get_hosts(); - for host in hosts { - match host { - Host::Tcp(host) => { - hosts_vec.push(host.to_string()); - } - Host::Unix(host) => { - hosts_vec.push(host.display().to_string()); - } - } - } - - hosts_vec - } - - #[cfg(not(unix))] - #[getter] - fn hosts(&self) -> Vec { - let mut hosts_vec = vec![]; - - let hosts = self.pg_config.get_hosts(); - for host in hosts { - match host { - Host::Tcp(host) => { - hosts_vec.push(host.to_string()); - } - _ => unreachable!(), - } + array_size: array_size.unwrap_or(1), + pg_config, + statement, } - - hosts_vec } - #[getter] - fn ports(&self) -> Vec<&u16> { - return self.pg_config.get_ports().iter().collect::>(); - } - - #[getter] - fn cursor_name(&self) -> String { - return self.cursor_name.clone(); + async fn query_portal(&self, size: i32) -> PSQLPyResult { + let Some(transaction) = &self.transaction else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + let Some(portal) = &self.inner else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + transaction.query_portal(&portal, size).await } +} - #[getter] - fn querystring(&self) -> String { - return self.querystring.clone(); +impl Drop for Cursor { + fn drop(&mut self) { + self.transaction = None; + self.conn = None; } +} +#[pymethods] +impl Cursor { #[getter] - fn parameters(&self) -> Option> { - return self.parameters.clone(); + fn get_array_size(&self) -> i32 { + self.array_size } - #[getter] - fn prepared(&self) -> Option { - return self.prepared.clone(); + #[setter] + fn set_array_size(&mut self, value: i32) { + self.array_size = value; } - #[must_use] fn __aiter__(slf: Py) -> Py { slf } @@ -233,473 +91,158 @@ impl Cursor { } async fn __aenter__<'a>(slf: Py) -> PSQLPyResult> { - let (db_transaction, cursor_name, scroll, querystring, prepared, parameters) = - Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - ( - self_.db_transaction.clone(), - self_.cursor_name.clone(), - self_.scroll, - self_.querystring.clone(), - self_.prepared, - self_.parameters.clone(), - ) - }); - - if let Some(db_transaction) = db_transaction { - db_transaction - .cursor_start(&cursor_name, &scroll, &querystring, &prepared, ¶meters) - .await?; - Python::with_gil(|gil| { - let mut self_ = slf.borrow_mut(gil); - self_.is_started = true; - }); - return Ok(slf); - } - Err(RustPSQLDriverError::CursorClosedError) + let (conn, querystring, parameters, statement) = Python::with_gil(|gil| { + let self_ = slf.borrow(gil); + ( + self_.conn.clone(), + self_.querystring.clone(), + self_.parameters.clone(), + self_.statement.clone(), + ) + }); + + let Some(conn) = conn else { + return Err(RustPSQLDriverError::CursorClosedError); + }; + let mut write_conn_g = conn.write().await; + + let (txid, inner_portal) = match querystring { + Some(querystring) => { + write_conn_g + .portal(Some(&querystring), ¶meters, None) + .await? + } + None => { + let Some(statement) = statement else { + return Err(RustPSQLDriverError::CursorStartError( + "Cannot start cursor".into(), + )); + }; + write_conn_g.portal(None, &None, Some(&statement)).await? + } + }; + + Python::with_gil(|gil| { + let mut self_ = slf.borrow_mut(gil); + + self_.transaction = Some(Arc::new(txid)); + self_.inner = Some(inner_portal); + }); + + Ok(slf) } #[allow(clippy::needless_pass_by_value)] async fn __aexit__<'a>( - slf: Py, + &mut self, _exception_type: Py, exception: Py, _traceback: Py, ) -> PSQLPyResult<()> { - let (db_transaction, closed, cursor_name, is_exception_none, py_err) = - pyo3::Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - ( - self_.db_transaction.clone(), - self_.closed, - self_.cursor_name.clone(), - exception.is_none(gil), - PyErr::from_value(exception.into_bound(gil)), - ) - }); - - if let Some(db_transaction) = db_transaction { - db_transaction - .cursor_close(&closed, &cursor_name) - .await - .map_err(|err| { - RustPSQLDriverError::CursorCloseError(format!( - "Cannot close the cursor, error - {err}" - )) - })?; - pyo3::Python::with_gil(|gil| { - let mut self_ = slf.borrow_mut(gil); - std::mem::take(&mut self_.db_transaction); - }); - if !is_exception_none { - return Err(RustPSQLDriverError::RustPyError(py_err)); - } - return Ok(()); - } - Err(RustPSQLDriverError::CursorClosedError) - } - - /// Return next result from the SQL statement. - /// - /// Execute FETCH FROM - /// - /// This is the only place where we use `rustdriver_future` cuz - /// we didn't find any solution how to implement it without - /// # Errors - /// May return Err Result if can't execute querystring. - fn __anext__(&self) -> PSQLPyResult> { - let db_transaction = self.db_transaction.clone(); - let fetch_number = self.fetch_number; - let cursor_name = self.cursor_name.clone(); - let py_future = Python::with_gil(move |gil| { - rustdriver_future(gil, async move { - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute( - format!("FETCH {fetch_number} FROM {cursor_name}"), - None, - Some(false), - ) - .await?; - - if result.is_empty() { - return Err(PyStopAsyncIteration::new_err( - "Iteration is over, no more results in cursor", - ) - .into()); - }; - - return Ok(result); - } - Err(RustPSQLDriverError::CursorClosedError) - }) - }); - - Ok(Some(py_future?)) - } + self.close(); - /// Start the cursor - /// - /// # Errors - /// May return Err Result - /// if cannot execute querystring for cursor declaration. - pub async fn start(&mut self) -> PSQLPyResult<()> { - let db_transaction_arc = self.db_transaction.clone(); - - if let Some(db_transaction) = db_transaction_arc { - db_transaction - .cursor_start( - &self.cursor_name, - &self.scroll, - &self.querystring, - &self.prepared, - &self.parameters, - ) - .await?; - - self.is_started = true; - return Ok(()); - } - - Err(RustPSQLDriverError::CursorClosedError) - } - - /// Close the cursor. - /// - /// It executes CLOSE command to close cursor in the transaction. - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn close(&mut self) -> PSQLPyResult<()> { - let db_transaction_arc = self.db_transaction.clone(); - - if let Some(db_transaction) = db_transaction_arc { - db_transaction - .cursor_close(&self.closed, &self.cursor_name) - .await?; - - self.closed = true; - std::mem::take(&mut self.db_transaction); - return Ok(()); - } - - Err(RustPSQLDriverError::CursorClosedError) - } - - /// Fetch data from cursor. - /// - /// It's possible to specify fetch number. - /// - /// # Errors - /// May return Err Result if cannot execute query. - #[pyo3(signature = (fetch_number=None))] - pub async fn fetch<'a>( - slf: Py, - fetch_number: Option, - ) -> PSQLPyResult { - let (db_transaction, inner_fetch_number, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); + let (is_exc_none, py_err) = pyo3::Python::with_gil(|gil| { ( - self_.db_transaction.clone(), - self_.fetch_number, - self_.cursor_name.clone(), + exception.is_none(gil), + PyErr::from_value(exception.into_bound(gil)), ) }); - if let Some(db_transaction) = db_transaction { - let fetch_number = match fetch_number { - Some(usize) => usize, - None => inner_fetch_number, - }; - - let result = db_transaction - .execute( - format!("FETCH {fetch_number} FROM {cursor_name}"), - None, - Some(false), - ) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - - return Ok(result); + if !is_exc_none { + return Err(RustPSQLDriverError::RustPyError(py_err)); } - - Err(RustPSQLDriverError::CursorClosedError) + Ok(()) } - /// Fetch row from cursor. - /// - /// Execute FETCH NEXT. - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_next<'a>(slf: Py) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) - }); - - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute(format!("FETCH NEXT FROM {cursor_name}"), None, Some(false)) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } - - Err(RustPSQLDriverError::CursorClosedError) - } + fn __anext__(&self) -> PSQLPyResult> { + let txid = self.transaction.clone(); + let portal = self.inner.clone(); + let size = self.array_size.clone(); - /// Fetch previous from cursor. - /// - /// Execute FETCH PRIOR. - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_prior<'a>(slf: Py) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) + let py_future = Python::with_gil(move |gil| { + rustdriver_future(gil, async move { + let Some(txid) = &txid else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + let Some(portal) = &portal else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + let result = txid.query_portal(&portal, size).await?; + + if result.is_empty() { + return Err(PyStopAsyncIteration::new_err( + "Iteration is over, no more results in portal", + ) + .into()); + }; + + Ok(result) + }) }); - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute(format!("FETCH PRIOR FROM {cursor_name}"), None, Some(false)) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } - - Err(RustPSQLDriverError::CursorClosedError) + Ok(Some(py_future?)) } - /// Fetch first row from cursor. - /// - /// Execute FETCH FIRST (same as ABSOLUTE 1) - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_first<'a>(slf: Py) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) - }); - - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute(format!("FETCH FIRST FROM {cursor_name}"), None, Some(false)) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } + async fn start(&mut self) -> PSQLPyResult<()> { + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::ConnectionClosedError); + }; + let mut write_conn_g = conn.write().await; - Err(RustPSQLDriverError::CursorClosedError) - } - - /// Fetch last row from cursor. - /// - /// Execute FETCH LAST (same as ABSOLUTE -1) - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_last<'a>(slf: Py) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) - }); + let (txid, inner_portal) = match &self.querystring { + Some(querystring) => { + write_conn_g + .portal(Some(&querystring), &self.parameters, None) + .await? + } + None => { + let Some(statement) = &self.statement else { + return Err(RustPSQLDriverError::CursorStartError( + "Cannot start cursor".into(), + )); + }; + write_conn_g.portal(None, &None, Some(&statement)).await? + } + }; - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute(format!("FETCH LAST FROM {cursor_name}"), None, Some(false)) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } + self.transaction = Some(Arc::new(txid)); + self.inner = Some(inner_portal); - Err(RustPSQLDriverError::CursorClosedError) + Ok(()) } - /// Fetch absolute row from cursor. - /// - /// Execute FETCH ABSOLUTE. - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_absolute<'a>( - slf: Py, - absolute_number: i64, - ) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) - }); - - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute( - format!("FETCH ABSOLUTE {absolute_number} FROM {cursor_name}"), - None, - Some(false), - ) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } - - Err(RustPSQLDriverError::CursorClosedError) + fn close(&mut self) { + self.transaction = None; + self.conn = None; } - /// Fetch absolute row from cursor. - /// - /// Execute FETCH ABSOLUTE. - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_relative<'a>( - slf: Py, - relative_number: i64, - ) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) - }); + #[pyo3(signature = ( + querystring, + parameters=None, + ))] + async fn execute( + &mut self, + querystring: String, + parameters: Option>, + ) -> PSQLPyResult<()> { + self.querystring = Some(querystring); + self.parameters = parameters; - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute( - format!("FETCH RELATIVE {relative_number} FROM {cursor_name}"), - None, - Some(false), - ) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } + self.start().await?; - Err(RustPSQLDriverError::CursorClosedError) + Ok(()) } - /// Fetch forward all from cursor. - /// - /// Execute FORWARD ALL. - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_forward_all<'a>(slf: Py) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) - }); - - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute( - format!("FETCH FORWARD ALL FROM {cursor_name}"), - None, - Some(false), - ) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } - - Err(RustPSQLDriverError::CursorClosedError) + async fn fetchone(&self) -> PSQLPyResult { + self.query_portal(1).await } - /// Fetch backward from cursor. - /// - /// Execute BACKWARD . - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_backward<'a>( - slf: Py, - backward_count: i64, - ) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) - }); - - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute( - format!("FETCH BACKWARD {backward_count} FROM {cursor_name}",), - None, - Some(false), - ) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } - - Err(RustPSQLDriverError::CursorClosedError) + #[pyo3(signature = (size=None))] + async fn fetchmany(&self, size: Option) -> PSQLPyResult { + self.query_portal(size.unwrap_or(self.array_size)).await } - /// Fetch backward from cursor. - /// - /// Execute BACKWARD . - /// - /// # Errors - /// May return Err Result if cannot execute query. - pub async fn fetch_backward_all<'a>(slf: Py) -> PSQLPyResult { - let (db_transaction, cursor_name) = Python::with_gil(|gil| { - let self_ = slf.borrow(gil); - (self_.db_transaction.clone(), self_.cursor_name.clone()) - }); - - if let Some(db_transaction) = db_transaction { - let result = db_transaction - .execute( - format!("FETCH BACKWARD ALL FROM {cursor_name}"), - None, - Some(false), - ) - .await - .map_err(|err| { - RustPSQLDriverError::CursorFetchError(format!( - "Cannot fetch data from cursor, error - {err}" - )) - })?; - return Ok(result); - } - - Err(RustPSQLDriverError::CursorClosedError) + async fn fetchall(&self) -> PSQLPyResult { + self.query_portal(-1).await } } diff --git a/src/driver/inner_connection.rs b/src/driver/inner_connection.rs deleted file mode 100644 index d8acc4d8..00000000 --- a/src/driver/inner_connection.rs +++ /dev/null @@ -1,323 +0,0 @@ -use bytes::Buf; -use deadpool_postgres::Object; -use postgres_types::{ToSql, Type}; -use pyo3::{Py, PyAny, Python}; -use std::vec; -use tokio_postgres::{Client, CopyInSink, Row, Statement, ToStatement}; - -use crate::{ - exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, - query_result::{PSQLDriverPyQueryResult, PSQLDriverSinglePyQueryResult}, - statement::{statement::PsqlpyStatement, statement_builder::StatementBuilder}, - value_converter::to_python::postgres_to_py, -}; - -#[allow(clippy::module_name_repetitions)] -pub enum PsqlpyConnection { - PoolConn(Object, bool), - SingleConn(Client), -} - -impl PsqlpyConnection { - /// Prepare cached statement. - /// - /// # Errors - /// May return Err if cannot prepare statement. - pub async fn prepare(&self, query: &str, prepared: bool) -> PSQLPyResult { - match self { - PsqlpyConnection::PoolConn(pconn, _) => { - if prepared { - return Ok(pconn.prepare_cached(query).await?); - } else { - let prepared = pconn.prepare(query).await?; - self.drop_prepared(&prepared).await?; - return Ok(prepared); - } - } - PsqlpyConnection::SingleConn(sconn) => return Ok(sconn.prepare(query).await?), - } - } - - /// Delete prepared statement. - /// - /// # Errors - /// May return Err if cannot prepare statement. - pub async fn drop_prepared(&self, stmt: &Statement) -> PSQLPyResult<()> { - let deallocate_query = format!("DEALLOCATE PREPARE {}", stmt.name()); - match self { - PsqlpyConnection::PoolConn(pconn, _) => { - let res = Ok(pconn.batch_execute(&deallocate_query).await?); - res - } - PsqlpyConnection::SingleConn(sconn) => { - return Ok(sconn.batch_execute(&deallocate_query).await?) - } - } - } - - /// Execute statement with parameters. - /// - /// # Errors - /// May return Err if cannot execute statement. - pub async fn query( - &self, - statement: &T, - params: &[&(dyn ToSql + Sync)], - ) -> PSQLPyResult> - where - T: ?Sized + ToStatement, - { - match self { - PsqlpyConnection::PoolConn(pconn, _) => { - return Ok(pconn.query(statement, params).await?) - } - PsqlpyConnection::SingleConn(sconn) => { - return Ok(sconn.query(statement, params).await?) - } - } - } - - /// Execute statement with parameters. - /// - /// # Errors - /// May return Err if cannot execute statement. - pub async fn query_typed( - &self, - statement: &str, - params: &[(&(dyn ToSql + Sync), Type)], - ) -> PSQLPyResult> { - match self { - PsqlpyConnection::PoolConn(pconn, _) => { - return Ok(pconn.query_typed(statement, params).await?) - } - PsqlpyConnection::SingleConn(sconn) => { - return Ok(sconn.query_typed(statement, params).await?) - } - } - } - - /// Batch execute statement. - /// - /// # Errors - /// May return Err if cannot execute statement. - pub async fn batch_execute(&self, query: &str) -> PSQLPyResult<()> { - match self { - PsqlpyConnection::PoolConn(pconn, _) => return Ok(pconn.batch_execute(query).await?), - PsqlpyConnection::SingleConn(sconn) => return Ok(sconn.batch_execute(query).await?), - } - } - - /// Prepare cached statement. - /// - /// # Errors - /// May return Err if cannot execute copy data. - pub async fn copy_in(&self, statement: &T) -> PSQLPyResult> - where - T: ?Sized + ToStatement, - U: Buf + 'static + Send, - { - match self { - PsqlpyConnection::PoolConn(pconn, _) => return Ok(pconn.copy_in(statement).await?), - PsqlpyConnection::SingleConn(sconn) => return Ok(sconn.copy_in(statement).await?), - } - } - - /// Executes a statement which returns a single row, returning it. - /// - /// # Errors - /// May return Err if cannot execute statement. - pub async fn query_one( - &self, - statement: &T, - params: &[&(dyn ToSql + Sync)], - ) -> PSQLPyResult - where - T: ?Sized + ToStatement, - { - match self { - PsqlpyConnection::PoolConn(pconn, _) => { - return Ok(pconn.query_one(statement, params).await?) - } - PsqlpyConnection::SingleConn(sconn) => { - return Ok(sconn.query_one(statement, params).await?) - } - } - } - - pub async fn cursor_execute( - &self, - querystring: String, - parameters: Option>, - prepared: Option, - ) -> PSQLPyResult { - let statement = StatementBuilder::new(querystring, parameters, self, prepared) - .build() - .await?; - - let prepared = prepared.unwrap_or(true); - - let result = if prepared { - self.query( - &self - .prepare(&statement.raw_query(), true) - .await - .map_err(|err| { - RustPSQLDriverError::ConnectionExecuteError(format!( - "Cannot prepare statement, error - {err}" - )) - })?, - &statement.params(), - ) - .await - .map_err(|err| RustPSQLDriverError::ConnectionExecuteError(format!("{err}")))? - } else { - self.query(statement.raw_query(), &statement.params()) - .await - .map_err(|err| RustPSQLDriverError::ConnectionExecuteError(format!("{err}")))? - }; - - Ok(PSQLDriverPyQueryResult::new(result)) - } - - pub async fn execute( - &self, - querystring: String, - parameters: Option>, - prepared: Option, - ) -> PSQLPyResult { - let statement = StatementBuilder::new(querystring, parameters, self, prepared) - .build() - .await?; - - let prepared = prepared.unwrap_or(true); - - let result = match prepared { - true => self - .query(statement.statement_query()?, &statement.params()) - .await - .map_err(|err| { - RustPSQLDriverError::ConnectionExecuteError(format!( - "Cannot prepare statement, error - {err}" - )) - })?, - false => self - .query_typed(statement.raw_query(), &statement.params_typed()) - .await - .map_err(|err| RustPSQLDriverError::ConnectionExecuteError(format!("{err}")))?, - }; - - Ok(PSQLDriverPyQueryResult::new(result)) - } - - pub async fn execute_many( - &self, - querystring: String, - parameters: Option>>, - prepared: Option, - ) -> PSQLPyResult<()> { - let mut statements: Vec = vec![]; - if let Some(parameters) = parameters { - for vec_of_py_any in parameters { - // TODO: Fix multiple qs creation - let statement = - StatementBuilder::new(querystring.clone(), Some(vec_of_py_any), self, prepared) - .build() - .await?; - - statements.push(statement); - } - } - - let prepared = prepared.unwrap_or(true); - - for statement in statements { - let querystring_result = if prepared { - let prepared_stmt = &self.prepare(&statement.raw_query(), true).await; - if let Err(error) = prepared_stmt { - return Err(RustPSQLDriverError::ConnectionExecuteError(format!( - "Cannot prepare statement in execute_many, operation rolled back {error}", - ))); - } - self.query( - &self.prepare(&statement.raw_query(), true).await?, - &statement.params(), - ) - .await - } else { - self.query(statement.raw_query(), &statement.params()).await - }; - - if let Err(error) = querystring_result { - return Err(RustPSQLDriverError::ConnectionExecuteError(format!( - "Error occured in `execute_many` statement: {error}" - ))); - } - } - - return Ok(()); - } - - pub async fn fetch_row_raw( - &self, - querystring: String, - parameters: Option>, - prepared: Option, - ) -> PSQLPyResult { - let statement = StatementBuilder::new(querystring, parameters, self, prepared) - .build() - .await?; - - let prepared = prepared.unwrap_or(true); - - let result = if prepared { - self.query_one( - &self - .prepare(&statement.raw_query(), true) - .await - .map_err(|err| { - RustPSQLDriverError::ConnectionExecuteError(format!( - "Cannot prepare statement, error - {err}" - )) - })?, - &statement.params(), - ) - .await - .map_err(|err| RustPSQLDriverError::ConnectionExecuteError(format!("{err}")))? - } else { - self.query_one(statement.raw_query(), &statement.params()) - .await - .map_err(|err| RustPSQLDriverError::ConnectionExecuteError(format!("{err}")))? - }; - - return Ok(result); - } - - pub async fn fetch_row( - &self, - querystring: String, - parameters: Option>, - prepared: Option, - ) -> PSQLPyResult { - let result = self - .fetch_row_raw(querystring, parameters, prepared) - .await?; - - return Ok(PSQLDriverSinglePyQueryResult::new(result)); - } - - pub async fn fetch_val( - &self, - querystring: String, - parameters: Option>, - prepared: Option, - ) -> PSQLPyResult> { - let result = self - .fetch_row_raw(querystring, parameters, prepared) - .await?; - - return Python::with_gil(|gil| match result.columns().first() { - Some(first_column) => postgres_to_py(gil, &result, first_column, 0, &None), - None => Ok(gil.None()), - }); - } -} diff --git a/src/driver/listener/core.rs b/src/driver/listener/core.rs index 4a9580af..8ae57d22 100644 --- a/src/driver/listener/core.rs +++ b/src/driver/listener/core.rs @@ -12,13 +12,16 @@ use tokio::{ use tokio_postgres::{AsyncMessage, Config}; use crate::{ + connection::{ + structs::{PSQLPyConnection, SingleConnection}, + traits::Connection as _, + }, driver::{ - common_options::SslMode, connection::Connection, - inner_connection::PsqlpyConnection, utils::{build_tls, is_coroutine_function, ConfiguredTLS}, }, exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, + options::SslMode, runtime::{rustdriver_future, tokio_runtime}, }; @@ -42,19 +45,14 @@ pub struct Listener { impl Listener { #[must_use] - pub fn new( - pg_config: Arc, - ca_file: Option, - ssl_mode: Option, - prepare: bool, - ) -> Self { + pub fn new(pg_config: Arc, ca_file: Option, ssl_mode: Option) -> Self { Listener { pg_config: pg_config.clone(), ca_file, ssl_mode, channel_callbacks: Arc::default(), listen_abort_handler: Option::default(), - connection: Connection::new(None, None, pg_config.clone(), prepare), + connection: Connection::new(None, None, pg_config.clone()), receiver: Option::default(), listen_query: Arc::default(), is_listened: Arc::new(RwLock::new(false)), @@ -224,10 +222,11 @@ impl Listener { self.receiver = Some(Arc::new(RwLock::new(receiver))); self.connection = Connection::new( - Some(Arc::new(PsqlpyConnection::SingleConn(client))), + Some(Arc::new(RwLock::new(PSQLPyConnection::SingleConnection( + SingleConnection::new(client, self.pg_config.clone()), + )))), None, self.pg_config.clone(), - false, ); self.is_started = true; @@ -356,8 +355,9 @@ async fn dispatch_callback( async fn execute_listen( is_listened: &Arc>, listen_query: &Arc>, - client: &Arc, + client: &Arc>, ) -> PSQLPyResult<()> { + let read_conn_g = client.read().await; let mut write_is_listened = is_listened.write().await; if !write_is_listened.eq(&true) { @@ -366,7 +366,7 @@ async fn execute_listen( String::from(read_listen_query.as_str()) }; - client.batch_execute(listen_q.as_str()).await?; + read_conn_g.batch_execute(listen_q.as_str()).await?; } *write_is_listened = true; diff --git a/src/driver/mod.rs b/src/driver/mod.rs index e7827cd5..30fec7c7 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -1,10 +1,9 @@ -pub mod common_options; +pub mod common; pub mod connection; pub mod connection_pool; pub mod connection_pool_builder; pub mod cursor; -pub mod inner_connection; pub mod listener; +pub mod prepared_statement; pub mod transaction; -pub mod transaction_options; pub mod utils; diff --git a/src/driver/prepared_statement.rs b/src/driver/prepared_statement.rs new file mode 100644 index 00000000..03b6c27d --- /dev/null +++ b/src/driver/prepared_statement.rs @@ -0,0 +1,63 @@ +use std::sync::Arc; + +use pyo3::{pyclass, pymethods}; +use tokio::sync::RwLock; +use tokio_postgres::Config; + +use crate::{ + connection::structs::PSQLPyConnection, + exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, + query_result::PSQLDriverPyQueryResult, + statement::{parameters::Column, statement::PsqlpyStatement}, +}; + +use super::cursor::Cursor; + +#[pyclass(subclass)] +#[derive(Debug)] +pub struct PreparedStatement { + pub conn: Option>>, + pub pg_config: Arc, + statement: PsqlpyStatement, +} + +impl PreparedStatement { + pub fn new( + conn: Option>>, + pg_config: Arc, + statement: PsqlpyStatement, + ) -> Self { + Self { + conn, + pg_config, + statement, + } + } +} + +#[pymethods] +impl PreparedStatement { + async fn execute(&self) -> PSQLPyResult { + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + + let read_conn_g = conn.read().await; + read_conn_g.execute_statement(&self.statement).await + } + + fn cursor(&self) -> PSQLPyResult { + Ok(Cursor::new( + self.conn.clone(), + None, + None, + None, + self.pg_config.clone(), + Some(self.statement.clone()), + )) + } + + fn columns(&self) -> Vec { + self.statement.columns().clone() + } +} diff --git a/src/driver/transaction.rs b/src/driver/transaction.rs index 60f054b7..87f1a282 100644 --- a/src/driver/transaction.rs +++ b/src/driver/transaction.rs @@ -1,238 +1,55 @@ -use bytes::BytesMut; -use futures_util::{future, pin_mut}; +use std::sync::Arc; + +use futures::future; use pyo3::{ - buffer::PyBuffer, - prelude::*, - pyclass, - types::{PyList, PyTuple}, + pyclass, pymethods, + types::{PyAnyMethods, PyList, PyTuple}, + Py, PyAny, PyErr, PyResult, }; -use tokio_postgres::{binary_copy::BinaryCopyInWriter, config::Host, Config}; +use tokio::sync::RwLock; +use tokio_postgres::Config; use crate::{ + connection::{ + structs::PSQLPyConnection, + traits::{CloseTransaction, Connection, StartTransaction as _}, + }, exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, - format_helpers::quote_ident, + options::{IsolationLevel, ReadVariant}, query_result::{PSQLDriverPyQueryResult, PSQLDriverSinglePyQueryResult}, }; -use super::{ - cursor::Cursor, - inner_connection::PsqlpyConnection, - transaction_options::{IsolationLevel, ReadVariant, SynchronousCommit}, -}; -use std::{collections::HashSet, net::IpAddr, sync::Arc}; - -#[allow(clippy::module_name_repetitions)] -pub trait TransactionObjectTrait { - fn start_transaction( - &self, - isolation_level: Option, - read_variant: Option, - defferable: Option, - synchronous_commit: Option, - ) -> impl std::future::Future> + Send; - fn commit(&self) -> impl std::future::Future> + Send; - fn rollback(&self) -> impl std::future::Future> + Send; -} - -impl TransactionObjectTrait for PsqlpyConnection { - async fn start_transaction( - &self, - isolation_level: Option, - read_variant: Option, - deferrable: Option, - synchronous_commit: Option, - ) -> PSQLPyResult<()> { - let mut querystring = "START TRANSACTION".to_string(); - - if let Some(level) = isolation_level { - let level = &level.to_str_level(); - querystring.push_str(format!(" ISOLATION LEVEL {level}").as_str()); - }; - - querystring.push_str(match read_variant { - Some(ReadVariant::ReadOnly) => " READ ONLY", - Some(ReadVariant::ReadWrite) => " READ WRITE", - None => "", - }); - - querystring.push_str(match deferrable { - Some(true) => " DEFERRABLE", - Some(false) => " NOT DEFERRABLE", - None => "", - }); - - self.batch_execute(&querystring).await.map_err(|err| { - RustPSQLDriverError::TransactionBeginError(format!( - "Cannot execute statement to start transaction, err - {err}" - )) - })?; - - if let Some(synchronous_commit) = synchronous_commit { - let str_synchronous_commit = synchronous_commit.to_str_level(); - - let synchronous_commit_query = - format!("SET LOCAL synchronous_commit = '{str_synchronous_commit}'"); - - self.batch_execute(&synchronous_commit_query) - .await - .map_err(|err| { - RustPSQLDriverError::TransactionBeginError(format!( - "Cannot set synchronous_commit parameter, err - {err}" - )) - })?; - } - - Ok(()) - } - async fn commit(&self) -> PSQLPyResult<()> { - self.batch_execute("COMMIT;").await.map_err(|err| { - RustPSQLDriverError::TransactionCommitError(format!( - "Cannot execute COMMIT statement, error - {err}" - )) - })?; - Ok(()) - } - async fn rollback(&self) -> PSQLPyResult<()> { - self.batch_execute("ROLLBACK;").await.map_err(|err| { - RustPSQLDriverError::TransactionRollbackError(format!( - "Cannot execute ROLLBACK statement, error - {err}" - )) - })?; - Ok(()) - } -} - #[pyclass(subclass)] +#[derive(Debug)] pub struct Transaction { - pub db_client: Option>, - pg_config: Arc, - is_started: bool, - is_done: bool, + pub conn: Option>>, + pub pg_config: Arc, isolation_level: Option, - synchronous_commit: Option, read_variant: Option, deferrable: Option, - - savepoints_map: HashSet, } impl Transaction { - #[allow(clippy::too_many_arguments)] - #[must_use] pub fn new( - db_client: Arc, + conn: Option>>, pg_config: Arc, - is_started: bool, - is_done: bool, isolation_level: Option, - synchronous_commit: Option, read_variant: Option, deferrable: Option, - savepoints_map: HashSet, ) -> Self { Self { - db_client: Some(db_client), + conn, pg_config, - is_started, - is_done, isolation_level, - synchronous_commit, read_variant, deferrable, - savepoints_map, } } - - fn check_is_transaction_ready(&self) -> PSQLPyResult<()> { - if !self.is_started { - return Err(RustPSQLDriverError::TransactionBeginError( - "Transaction is not started, please call begin() on transaction".into(), - )); - } - if self.is_done { - return Err(RustPSQLDriverError::TransactionBeginError( - "Transaction is already committed or rolled back".into(), - )); - } - Ok(()) - } } #[pymethods] impl Transaction { - #[getter] - fn conn_dbname(&self) -> Option<&str> { - self.pg_config.get_dbname() - } - - #[getter] - fn user(&self) -> Option<&str> { - self.pg_config.get_user() - } - - #[getter] - fn host_addrs(&self) -> Vec { - let mut host_addrs_vec = vec![]; - - let host_addrs = self.pg_config.get_hostaddrs(); - for ip_addr in host_addrs { - match ip_addr { - IpAddr::V4(ipv4) => { - host_addrs_vec.push(ipv4.to_string()); - } - IpAddr::V6(ipv6) => { - host_addrs_vec.push(ipv6.to_string()); - } - } - } - - host_addrs_vec - } - - #[cfg(unix)] - #[getter] - fn hosts(&self) -> Vec { - let mut hosts_vec = vec![]; - - let hosts = self.pg_config.get_hosts(); - for host in hosts { - match host { - Host::Tcp(host) => { - hosts_vec.push(host.to_string()); - } - Host::Unix(host) => { - hosts_vec.push(host.display().to_string()); - } - } - } - - hosts_vec - } - - #[cfg(not(unix))] - #[getter] - fn hosts(&self) -> Vec { - let mut hosts_vec = vec![]; - - let hosts = self.pg_config.get_hosts(); - for host in hosts { - match host { - Host::Tcp(host) => { - hosts_vec.push(host.to_string()); - } - _ => unreachable!(), - } - } - - hosts_vec - } - - #[getter] - fn ports(&self) -> Vec<&u16> { - return self.pg_config.get_ports().iter().collect::>(); - } - #[must_use] pub fn __aiter__(self_: Py) -> Py { self_ @@ -243,57 +60,25 @@ impl Transaction { } async fn __aenter__<'a>(self_: Py) -> PSQLPyResult> { - let ( - is_started, - is_done, - isolation_level, - synchronous_commit, - read_variant, - deferrable, - db_client, - ) = pyo3::Python::with_gil(|gil| { + let (isolation_level, read_variant, deferrable, conn) = pyo3::Python::with_gil(|gil| { let self_ = self_.borrow(gil); ( - self_.is_started, - self_.is_done, self_.isolation_level, - self_.synchronous_commit, self_.read_variant, self_.deferrable, - self_.db_client.clone(), + self_.conn.clone(), ) }); - if is_started { - return Err(RustPSQLDriverError::TransactionBeginError( - "Transaction is already started".into(), - )); - } - - if is_done { - return Err(RustPSQLDriverError::TransactionBeginError( - "Transaction is already committed or rolled back".into(), - )); - } - - if let Some(db_client) = db_client { - db_client - .start_transaction( - isolation_level, - read_variant, - deferrable, - synchronous_commit, - ) - .await?; - - Python::with_gil(|gil| { - let mut self_ = self_.borrow_mut(gil); - self_.is_started = true; - }); - return Ok(self_); - } + let Some(conn) = conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + let mut write_conn_g = conn.write().await; + write_conn_g + .start_transaction(isolation_level, read_variant, deferrable) + .await?; - Err(RustPSQLDriverError::TransactionClosedError) + return Ok(self_); } #[allow(clippy::needless_pass_by_value)] @@ -303,469 +88,192 @@ impl Transaction { exception: Py, _traceback: Py, ) -> PSQLPyResult<()> { - let (is_transaction_ready, is_exception_none, py_err, db_client) = + let (conn, is_exception_none, py_err) = pyo3::Python::with_gil(|gil| { + let self_ = self_.borrow(gil); + ( + self_.conn.clone(), + exception.is_none(gil), + PyErr::from_value(exception.into_bound(gil)), + ) + }); + + let Some(conn) = conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + let mut write_conn_g = conn.write().await; + if is_exception_none { + write_conn_g.commit().await?; pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - ( - self_.check_is_transaction_ready(), - exception.is_none(gil), - PyErr::from_value(exception.into_bound(gil)), - self_.db_client.clone(), - ) + let mut self_ = self_.borrow_mut(gil); + self_.conn = None; }); - is_transaction_ready?; - - if let Some(db_client) = db_client { - let exit_result = if is_exception_none { - db_client.commit().await?; - Ok(()) - } else { - db_client.rollback().await?; - Err(RustPSQLDriverError::RustPyError(py_err)) - }; - + Ok(()) + } else { + write_conn_g.rollback().await?; pyo3::Python::with_gil(|gil| { let mut self_ = self_.borrow_mut(gil); - self_.is_done = true; - std::mem::take(&mut self_.db_client); + self_.conn = None; }); - return exit_result; - } - - Err(RustPSQLDriverError::TransactionClosedError) - } - - /// Commit the transaction. - /// - /// Execute `COMMIT` command and mark transaction as `done`. - /// - /// # Errors - /// - /// May return Err Result if: - /// 1) Transaction is not started - /// 2) Transaction is done - /// 3) Cannot execute `COMMIT` command - pub async fn commit(&mut self) -> PSQLPyResult<()> { - self.check_is_transaction_ready()?; - if let Some(db_client) = &self.db_client { - db_client.commit().await?; - self.is_done = true; - std::mem::take(&mut self.db_client); - return Ok(()); + return Err(RustPSQLDriverError::RustPyError(py_err)); } - - Err(RustPSQLDriverError::TransactionClosedError) } - /// Execute ROLLBACK command. - /// - /// Run ROLLBACK command and mark the transaction as done. - /// - /// # Errors - /// May return Err Result if: - /// 1) Transaction is not started - /// 2) Transaction is done - /// 3) Can not execute ROLLBACK command - pub async fn rollback(&mut self) -> PSQLPyResult<()> { - self.check_is_transaction_ready()?; - if let Some(db_client) = &self.db_client { - db_client.rollback().await?; - self.is_done = true; - std::mem::take(&mut self.db_client); - return Ok(()); - } + pub async fn begin(&mut self) -> PSQLPyResult<()> { + let conn = &self.conn; + let Some(conn) = conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + let mut write_conn_g = conn.write().await; + write_conn_g + .start_transaction(self.isolation_level, self.read_variant, self.deferrable) + .await?; - Err(RustPSQLDriverError::TransactionClosedError) + Ok(()) } - /// Execute querystring with parameters. - /// - /// It converts incoming parameters to rust readable - /// and then execute the query with them. - /// - /// # Errors - /// - /// May return Err Result if: - /// 1) Cannot convert python parameters - /// 2) Cannot execute querystring. #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn execute( - self_: Py, + &self, querystring: String, parameters: Option>, prepared: Option, ) -> PSQLPyResult { - let (is_transaction_ready, db_client) = pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - (self_.check_is_transaction_ready(), self_.db_client.clone()) - }); - is_transaction_ready?; - if let Some(db_client) = db_client { - return db_client.execute(querystring, parameters, prepared).await; - } - - Err(RustPSQLDriverError::TransactionClosedError) - } - - /// Executes a sequence of SQL statements using the simple query protocol. - /// - /// Statements should be separated by semicolons. - /// If an error occurs, execution of the sequence will stop at that point. - /// This is intended for use when, for example, - /// initializing a database schema. - /// - /// # Errors - /// - /// May return Err Result if: - /// 1) Transaction is closed. - /// 2) Cannot execute querystring. - pub async fn execute_batch(self_: Py, querystring: String) -> PSQLPyResult<()> { - let (is_transaction_ready, db_client) = pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - (self_.check_is_transaction_ready(), self_.db_client.clone()) - }); - is_transaction_ready?; - if let Some(db_client) = db_client { - return db_client.batch_execute(&querystring).await; - } + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; - Err(RustPSQLDriverError::TransactionClosedError) + let read_conn_g = conn.read().await; + read_conn_g.execute(querystring, parameters, prepared).await } - /// Fetch result from the database. - /// - /// It converts incoming parameters to rust readable - /// and then execute the query with them. - /// - /// # Errors - /// - /// May return Err Result if: - /// 1) Cannot convert python parameters - /// 2) Cannot execute querystring. #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn fetch( - self_: Py, + &self, querystring: String, parameters: Option>, prepared: Option, ) -> PSQLPyResult { - let (is_transaction_ready, db_client) = pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - (self_.check_is_transaction_ready(), self_.db_client.clone()) - }); - is_transaction_ready?; - if let Some(db_client) = db_client { - return db_client.execute(querystring, parameters, prepared).await; - } + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; - Err(RustPSQLDriverError::TransactionClosedError) + let read_conn_g = conn.read().await; + read_conn_g.execute(querystring, parameters, prepared).await } - /// Fetch exaclty single row from query. - /// - /// Method doesn't acquire lock on any structure fields. - /// It prepares and caches querystring in the inner Object object. - /// - /// Then execute the query. - /// - /// # Errors - /// May return Err Result if: - /// 1) Transaction is not started - /// 2) Transaction is done already - /// 3) Can not create/retrieve prepared statement - /// 4) Can not execute statement - /// 5) Query returns more than one row - #[pyo3(signature = (querystring, parameters=None, prepared=None))] - pub async fn fetch_row( - self_: Py, - querystring: String, - parameters: Option>, - prepared: Option, - ) -> PSQLPyResult { - let (is_transaction_ready, db_client) = pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - (self_.check_is_transaction_ready(), self_.db_client.clone()) - }); - is_transaction_ready?; - - if let Some(db_client) = db_client { - return db_client.fetch_row(querystring, parameters, prepared).await; - } - - Err(RustPSQLDriverError::TransactionClosedError) - } - /// Execute querystring with parameters and return first value in the first row. - /// - /// It converts incoming parameters to rust readable, - /// executes query with them and returns first row of response. - /// - /// # Errors - /// - /// May return Err Result if: - /// 1) Cannot convert python parameters - /// 2) Cannot execute querystring. - /// 3) Query returns more than one row #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn fetch_val( - self_: Py, + &self, querystring: String, parameters: Option>, prepared: Option, ) -> PSQLPyResult> { - let (is_transaction_ready, db_client) = pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - (self_.check_is_transaction_ready(), self_.db_client.clone()) - }); - is_transaction_ready?; - if let Some(db_client) = db_client { - return db_client.fetch_val(querystring, parameters, prepared).await; - } + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; - Err(RustPSQLDriverError::TransactionClosedError) + let read_conn_g = conn.read().await; + read_conn_g + .fetch_val(querystring, parameters, prepared) + .await + } + + pub async fn execute_batch(&self, querystring: String) -> PSQLPyResult<()> { + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; + + let read_conn_g = conn.read().await; + read_conn_g.batch_execute(&querystring).await } - /// Execute querystring with parameters. - /// - /// It converts incoming parameters to rust readable - /// and then execute the query with them. - /// - /// # Errors - /// - /// May return Err Result if: - /// 1) Cannot convert python parameters - /// 2) Cannot execute querystring. + #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn execute_many( - self_: Py, + &self, querystring: String, parameters: Option>>, prepared: Option, ) -> PSQLPyResult<()> { - let (is_transaction_ready, db_client) = pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - (self_.check_is_transaction_ready(), self_.db_client.clone()) - }); - - is_transaction_ready?; - if let Some(db_client) = db_client { - return db_client - .execute_many(querystring, parameters, prepared) - .await; - } + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; - Err(RustPSQLDriverError::TransactionClosedError) + let read_conn_g = conn.read().await; + read_conn_g + .execute_many(querystring, parameters, prepared) + .await } - /// Start the transaction. - /// - /// Execute `BEGIN` commands and mark transaction as `started`. - /// - /// # Errors - /// - /// May return Err Result if: - /// 1) Transaction is already started. - /// 2) Transaction is done. - /// 3) Cannot execute `BEGIN` command. - pub async fn begin(self_: Py) -> PSQLPyResult<()> { - let ( - is_started, - is_done, - isolation_level, - synchronous_commit, - read_variant, - deferrable, - db_client, - ) = pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - ( - self_.is_started, - self_.is_done, - self_.isolation_level, - self_.synchronous_commit, - self_.read_variant, - self_.deferrable, - self_.db_client.clone(), - ) - }); - if let Some(db_client) = db_client { - if is_started { - return Err(RustPSQLDriverError::TransactionBeginError( - "Transaction is already started".into(), - )); - } - - if is_done { - return Err(RustPSQLDriverError::TransactionBeginError( - "Transaction is already committed or rolled back".into(), - )); - } - db_client - .start_transaction( - isolation_level, - read_variant, - deferrable, - synchronous_commit, - ) - .await?; - - pyo3::Python::with_gil(|gil| { - let mut self_ = self_.borrow_mut(gil); - self_.is_started = true; - }); - - return Ok(()); - } + #[pyo3(signature = (querystring, parameters=None, prepared=None))] + pub async fn fetch_row( + &self, + querystring: String, + parameters: Option>, + prepared: Option, + ) -> PSQLPyResult { + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; - Err(RustPSQLDriverError::TransactionClosedError) + let read_conn_g = conn.read().await; + read_conn_g + .fetch_row(querystring, parameters, prepared) + .await } - /// Create new SAVEPOINT. - /// - /// Execute SAVEPOINT and - /// add it to the transaction `rollback_savepoint` `HashSet` - /// - /// # Errors - /// May return Err Result if: - /// 1) Transaction is not started - /// 2) Transaction is done - /// 3) Specified savepoint name is exists - /// 4) Can not execute SAVEPOINT command - pub async fn create_savepoint(self_: Py, savepoint_name: String) -> PSQLPyResult<()> { - let (is_transaction_ready, is_savepoint_name_exists, db_client) = - pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - ( - self_.check_is_transaction_ready(), - self_.savepoints_map.contains(&savepoint_name), - self_.db_client.clone(), - ) - }); - - if let Some(db_client) = db_client { - is_transaction_ready?; - - if is_savepoint_name_exists { - return Err(RustPSQLDriverError::TransactionSavepointError(format!( - "SAVEPOINT name {savepoint_name} is already taken by this transaction", - ))); - } - db_client - .batch_execute(format!("SAVEPOINT {savepoint_name}").as_str()) - .await?; + pub async fn create_savepoint(&mut self, savepoint_name: String) -> PSQLPyResult<()> { + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; - pyo3::Python::with_gil(|gil| { - self_.borrow_mut(gil).savepoints_map.insert(savepoint_name); - }); - return Ok(()); - } + let read_conn_g = conn.read().await; + read_conn_g + .batch_execute(format!("SAVEPOINT {savepoint_name}").as_str()) + .await?; - Err(RustPSQLDriverError::TransactionClosedError) + Ok(()) } - /// Execute RELEASE SAVEPOINT. - /// - /// Run RELEASE SAVEPOINT command. - /// - /// # Errors - /// May return Err Result if: - /// 1) Transaction is not started - /// 2) Transaction is done - /// 3) Specified savepoint name doesn't exists - /// 4) Can not execute RELEASE SAVEPOINT command - pub async fn release_savepoint(self_: Py, savepoint_name: String) -> PSQLPyResult<()> { - let (is_transaction_ready, is_savepoint_name_exists, db_client) = - pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - ( - self_.check_is_transaction_ready(), - self_.savepoints_map.contains(&savepoint_name), - self_.db_client.clone(), - ) - }); - if let Some(db_client) = db_client { - is_transaction_ready?; - - if !is_savepoint_name_exists { - return Err(RustPSQLDriverError::TransactionSavepointError( - "Don't have rollback with this name".into(), - )); - } - db_client - .batch_execute(format!("RELEASE SAVEPOINT {savepoint_name}").as_str()) - .await?; + pub async fn release_savepoint(&mut self, savepoint_name: String) -> PSQLPyResult<()> { + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; - pyo3::Python::with_gil(|gil| { - self_.borrow_mut(gil).savepoints_map.remove(&savepoint_name); - }); - return Ok(()); - } + let read_conn_g = conn.read().await; + read_conn_g + .batch_execute(format!("RELEASE SAVEPOINT {savepoint_name}").as_str()) + .await?; - Err(RustPSQLDriverError::TransactionClosedError) + Ok(()) } - /// ROLLBACK to the specified savepoint - /// - /// Execute ROLLBACK TO SAVEPOINT . - /// - /// # Errors - /// May return Err Result if: - /// 1) Transaction is not started - /// 2) Transaction is done - /// 3) Specified savepoint name doesn't exist - /// 4) Can not execute ROLLBACK TO SAVEPOINT command - pub async fn rollback_savepoint(self_: Py, savepoint_name: String) -> PSQLPyResult<()> { - let (is_transaction_ready, is_savepoint_name_exists, db_client) = - pyo3::Python::with_gil(|gil| { - let self_ = self_.borrow(gil); - ( - self_.check_is_transaction_ready(), - self_.savepoints_map.contains(&savepoint_name), - self_.db_client.clone(), - ) - }); - if let Some(db_client) = db_client { - is_transaction_ready?; - - if !is_savepoint_name_exists { - return Err(RustPSQLDriverError::TransactionSavepointError( - "Don't have rollback with this name".into(), - )); - } - db_client - .batch_execute(format!("ROLLBACK TO SAVEPOINT {savepoint_name}").as_str()) - .await?; + pub async fn rollback_savepoint(&mut self, savepoint_name: String) -> PSQLPyResult<()> { + let Some(conn) = &self.conn else { + return Err(RustPSQLDriverError::TransactionClosedError); + }; - pyo3::Python::with_gil(|gil| { - self_.borrow_mut(gil).savepoints_map.remove(&savepoint_name); - }); - return Ok(()); - } + let read_conn_g = conn.read().await; + read_conn_g + .batch_execute(format!("ROLLBACK TO SAVEPOINT {savepoint_name}").as_str()) + .await?; - Err(RustPSQLDriverError::TransactionClosedError) + Ok(()) } - /// Execute querystrings with parameters and return all results. - /// - /// Create pipeline of queries. - /// - /// # Errors - /// - /// May return Err Result if: - /// 1) Cannot convert python parameters - /// 2) Cannot execute any of querystring. + #[pyo3(signature = (queries=None, prepared=None))] pub async fn pipeline<'py>( self_: Py, queries: Option>, prepared: Option, ) -> PSQLPyResult> { - let (is_transaction_ready, db_client) = pyo3::Python::with_gil(|gil| { + let db_client = pyo3::Python::with_gil(|gil| { let self_ = self_.borrow(gil); - (self_.check_is_transaction_ready(), self_.db_client.clone()) + self_.conn.clone() }); - is_transaction_ready?; - if let Some(db_client) = db_client { + let conn_read_g = db_client.read().await; let mut futures = vec![]; if let Some(queries) = queries { let gil_result = pyo3::Python::with_gil(|gil| -> PyResult<()> { @@ -781,7 +289,7 @@ impl Transaction { Ok(param) => Some(param.into()), Err(_) => None, }; - futures.push(db_client.execute(querystring, params, prepared)); + futures.push(conn_read_g.execute(querystring, params, prepared)); } Ok(()) }); @@ -799,97 +307,4 @@ impl Transaction { Err(RustPSQLDriverError::TransactionClosedError) } - - /// Create new cursor object. - /// - /// # Errors - /// May return Err Result if db_client is None - #[pyo3(signature = ( - querystring, - parameters=None, - fetch_number=None, - scroll=None, - prepared=None, - ))] - pub fn cursor( - &self, - querystring: String, - parameters: Option>, - fetch_number: Option, - scroll: Option, - prepared: Option, - ) -> PSQLPyResult { - if let Some(db_client) = &self.db_client { - return Ok(Cursor::new( - db_client.clone(), - self.pg_config.clone(), - querystring, - parameters, - "cur_name".into(), - fetch_number.unwrap_or(10), - scroll, - prepared, - )); - } - - Err(RustPSQLDriverError::TransactionClosedError) - } - - /// Perform binary copy to postgres table. - /// - /// # Errors - /// May return Err Result if cannot get bytes, - /// cannot perform request to the database, - /// cannot write bytes to the database. - #[pyo3(signature = (source, table_name, columns=None, schema_name=None))] - pub async fn binary_copy_to_table( - self_: pyo3::Py, - source: Py, - table_name: String, - columns: Option>, - schema_name: Option, - ) -> PSQLPyResult { - let db_client = pyo3::Python::with_gil(|gil| self_.borrow(gil).db_client.clone()); - let mut table_name = quote_ident(&table_name); - if let Some(schema_name) = schema_name { - table_name = format!("{}.{}", quote_ident(&schema_name), table_name); - } - - let mut formated_columns = String::default(); - if let Some(columns) = columns { - formated_columns = format!("({})", columns.join(", ")); - } - - let copy_qs = format!("COPY {table_name}{formated_columns} FROM STDIN (FORMAT binary)"); - - if let Some(db_client) = db_client { - let mut psql_bytes: BytesMut = Python::with_gil(|gil| { - let possible_py_buffer: Result, PyErr> = - source.extract::>(gil); - if let Ok(py_buffer) = possible_py_buffer { - let vec_buf = py_buffer.to_vec(gil)?; - return Ok(BytesMut::from(vec_buf.as_slice())); - } - - if let Ok(py_bytes) = source.call_method0(gil, "getvalue") { - if let Ok(bytes) = py_bytes.extract::>(gil) { - return Ok(BytesMut::from(bytes.as_slice())); - } - } - - Err(RustPSQLDriverError::PyToRustValueConversionError( - "source must be bytes or support Buffer protocol".into(), - )) - })?; - - let sink = db_client.copy_in(©_qs).await?; - let writer = BinaryCopyInWriter::new_empty_buffer(sink, &[]); - pin_mut!(writer); - writer.as_mut().write_raw_bytes(&mut psql_bytes).await?; - let rows_created = writer.as_mut().finish_empty().await?; - return Ok(rows_created); - } - - Ok(0) - } } diff --git a/src/driver/transaction_options.rs b/src/driver/transaction_options.rs deleted file mode 100644 index 281b9a71..00000000 --- a/src/driver/transaction_options.rs +++ /dev/null @@ -1,81 +0,0 @@ -use pyo3::pyclass; - -#[pyclass(eq, eq_int)] -#[derive(Clone, Copy, PartialEq)] -pub enum IsolationLevel { - ReadUncommitted, - ReadCommitted, - RepeatableRead, - Serializable, -} - -impl IsolationLevel { - /// Return isolation level as String literal. - #[must_use] - pub fn to_str_level(&self) -> String { - match self { - IsolationLevel::ReadUncommitted => "READ UNCOMMITTED".into(), - IsolationLevel::ReadCommitted => "READ COMMITTED".into(), - IsolationLevel::RepeatableRead => "REPEATABLE READ".into(), - IsolationLevel::Serializable => "SERIALIZABLE".into(), - } - } -} - -#[pyclass(eq, eq_int)] -#[derive(Clone, Copy, PartialEq)] -pub enum ReadVariant { - ReadOnly, - ReadWrite, -} - -#[pyclass(eq, eq_int)] -#[derive(Clone, Copy, PartialEq)] -pub enum SynchronousCommit { - /// As the name indicates, the commit acknowledgment can come before - /// flushing the records to disk. - /// This is generally called as an asynchronous commit. - /// If the PostgreSQL instance crashes, - /// the last few asynchronous commits might be lost. - Off, - /// WAL records are written and flushed to local disks. - /// In this case, the commit will be acknowledged after the - /// local WAL Write and WAL flush completes. - Local, - /// WAL records are successfully handed over to - /// remote instances which acknowledged back - /// about the write (not flush). - RemoteWrite, - /// The meaning may change based on whether you have - /// a synchronous standby or not. - /// If there is a synchronous standby, - /// setting the value to on will result in waiting till “remote flush”. - On, - /// This will result in commits waiting until replies from the - /// current synchronous standby(s) indicate they have received - /// the commit record of the transaction and applied it so - /// that it has become visible to queries on the standby(s). - RemoteApply, -} - -impl SynchronousCommit { - /// Return isolation level as String literal. - #[must_use] - pub fn to_str_level(&self) -> String { - match self { - SynchronousCommit::Off => "off".into(), - SynchronousCommit::Local => "local".into(), - SynchronousCommit::RemoteWrite => "remote_write".into(), - SynchronousCommit::On => "on".into(), - SynchronousCommit::RemoteApply => "remote_apply".into(), - } - } -} - -#[derive(Clone, Copy, PartialEq)] -pub struct ListenerTransactionConfig { - isolation_level: Option, - read_variant: Option, - deferrable: Option, - synchronous_commit: Option, -} diff --git a/src/driver/utils.rs b/src/driver/utils.rs index 15ca4123..e3c0a1f9 100644 --- a/src/driver/utils.rs +++ b/src/driver/utils.rs @@ -6,9 +6,10 @@ use postgres_openssl::MakeTlsConnector; use pyo3::{types::PyAnyMethods, Py, PyAny, Python}; use tokio_postgres::{Config, NoTls}; -use crate::exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}; - -use super::common_options::{self, LoadBalanceHosts, SslMode, TargetSessionAttrs}; +use crate::{ + exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}, + options::{LoadBalanceHosts, SslMode, TargetSessionAttrs}, +}; /// Create new config. /// @@ -190,7 +191,7 @@ pub fn build_tls( builder.build(), ))); } else if let Some(ssl_mode) = ssl_mode { - if *ssl_mode == common_options::SslMode::Require { + if *ssl_mode == SslMode::Require { let mut builder = SslConnector::builder(SslMethod::tls())?; builder.set_verify(SslVerifyMode::NONE); return Ok(ConfiguredTLS::TlsConnector(MakeTlsConnector::new( diff --git a/src/exceptions/python_errors.rs b/src/exceptions/python_errors.rs index 4d3798cb..e7c0a214 100644 --- a/src/exceptions/python_errors.rs +++ b/src/exceptions/python_errors.rs @@ -4,27 +4,61 @@ use pyo3::{ Bound, PyResult, Python, }; -// Main exception. +// Exception raised for important warnings like data truncations while inserting, etc. create_exception!( psqlpy.exceptions, - RustPSQLDriverPyBaseError, + WarningError, pyo3::exceptions::PyException ); +// Exception that is the base class of all other error exceptions. +// You can use this to catch all errors with one single except statement. +create_exception!(psqlpy.exceptions, Error, pyo3::exceptions::PyException); + +// Exception raised for errors that are related to the +// database interface rather than the database itself. +create_exception!(psqlpy.exceptions, InterfaceError, Error); + +// Exception raised for errors that are related to the database. +create_exception!(psqlpy.exceptions, DatabaseError, Error); + +// Exception raised for errors that are due to problems with +// the processed data like division by zero, numeric value out of range, etc. +create_exception!(psqlpy.exceptions, DataError, DatabaseError); + +// Exception raised for errors that are related to the database’s operation +// and not necessarily under the control of the programmer, +// e.g. an unexpected disconnect occurs, the data source name is not found, +// a transaction could not be processed, a memory allocation error +// occurred during processing, etc. +create_exception!(psqlpy.exceptions, OperationalError, DatabaseError); + +// Exception raised when the relational integrity of the +// database is affected, e.g. a foreign key check fails. +create_exception!(psqlpy.exceptions, IntegrityError, DatabaseError); + +// Exception raised when the database encounters an internal error, +// e.g. the cursor is not valid anymore, the transaction is out of sync, etc. +create_exception!(psqlpy.exceptions, InternalError, DatabaseError); + +// Exception raised for programming errors, e.g. table not found or +// already exists, syntax error in the SQL statement, +// wrong number of parameters specified, etc. +create_exception!(psqlpy.exceptions, ProgrammingError, DatabaseError); +// Exception raised in case a method or database API was used which +// is not supported by the database, e.g. requesting a .rollback() +// on a connection that does not support transaction +// or has transactions turned off. +create_exception!(psqlpy.exceptions, NotSupportedError, DatabaseError); + // Rust exceptions // `Rust` means thats these exceptions come from external rust crates, // not from the code of the library. -create_exception!(psqlpy.exceptions, RustException, RustPSQLDriverPyBaseError); -create_exception!(psqlpy.exceptions, DriverError, RustException); -create_exception!(psqlpy.exceptions, MacAddrParseError, RustException); -create_exception!(psqlpy.exceptions, RuntimeJoinError, RustException); +create_exception!(psqlpy.exceptions, MacAddrParseError, DataError); +create_exception!(psqlpy.exceptions, RuntimeJoinError, DataError); // ConnectionPool exceptions -create_exception!( - psqlpy.exceptions, - BaseConnectionPoolError, - RustPSQLDriverPyBaseError -); +create_exception!(psqlpy.exceptions, BaseConnectionPoolError, InterfaceError); create_exception!( psqlpy.exceptions, ConnectionPoolBuildError, @@ -42,11 +76,7 @@ create_exception!( ); // Connection exceptions -create_exception!( - psqlpy.exceptions, - BaseConnectionError, - RustPSQLDriverPyBaseError -); +create_exception!(psqlpy.exceptions, BaseConnectionError, InterfaceError); create_exception!( psqlpy.exceptions, ConnectionExecuteError, @@ -59,11 +89,7 @@ create_exception!( ); // Transaction exceptions -create_exception!( - psqlpy.exceptions, - BaseTransactionError, - RustPSQLDriverPyBaseError -); +create_exception!(psqlpy.exceptions, BaseTransactionError, InterfaceError); create_exception!( psqlpy.exceptions, TransactionBeginError, @@ -96,59 +122,41 @@ create_exception!( ); // Cursor exceptions -create_exception!( - psqlpy.exceptions, - BaseCursorError, - RustPSQLDriverPyBaseError -); +create_exception!(psqlpy.exceptions, BaseCursorError, InterfaceError); create_exception!(psqlpy.exceptions, CursorStartError, BaseCursorError); create_exception!(psqlpy.exceptions, CursorCloseError, BaseCursorError); create_exception!(psqlpy.exceptions, CursorFetchError, BaseCursorError); create_exception!(psqlpy.exceptions, CursorClosedError, BaseCursorError); // Listener Error -create_exception!( - psqlpy.exceptions, - BaseListenerError, - RustPSQLDriverPyBaseError -); +create_exception!(psqlpy.exceptions, BaseListenerError, InterfaceError); create_exception!(psqlpy.exceptions, ListenerStartError, BaseListenerError); create_exception!(psqlpy.exceptions, ListenerClosedError, BaseListenerError); create_exception!(psqlpy.exceptions, ListenerCallbackError, BaseListenerError); // Inner exceptions -create_exception!( - psqlpy.exceptions, - RustToPyValueMappingError, - RustPSQLDriverPyBaseError -); -create_exception!( - psqlpy.exceptions, - PyToRustValueMappingError, - RustPSQLDriverPyBaseError -); +create_exception!(psqlpy.exceptions, RustToPyValueMappingError, DataError); +create_exception!(psqlpy.exceptions, PyToRustValueMappingError, DataError); -create_exception!( - psqlpy.exceptions, - UUIDValueConvertError, - RustPSQLDriverPyBaseError -); +create_exception!(psqlpy.exceptions, UUIDValueConvertError, DataError); -create_exception!( - psqlpy.exceptions, - MacAddrConversionError, - RustPSQLDriverPyBaseError -); +create_exception!(psqlpy.exceptions, MacAddrConversionError, DataError); -create_exception!(psqlpy.exceptions, SSLError, RustPSQLDriverPyBaseError); +create_exception!(psqlpy.exceptions, SSLError, DatabaseError); #[allow(clippy::missing_errors_doc)] #[allow(clippy::too_many_lines)] pub fn python_exceptions_module(py: Python<'_>, pymod: &Bound<'_, PyModule>) -> PyResult<()> { - pymod.add( - "RustPSQLDriverPyBaseError", - py.get_type::(), - )?; + pymod.add("WarningError", py.get_type::())?; + pymod.add("Error", py.get_type::())?; + pymod.add("InterfaceError", py.get_type::())?; + pymod.add("DatabaseError", py.get_type::())?; + pymod.add("DataError", py.get_type::())?; + pymod.add("OperationalError", py.get_type::())?; + pymod.add("IntegrityError", py.get_type::())?; + pymod.add("InternalError", py.get_type::())?; + pymod.add("ProgrammingError", py.get_type::())?; + pymod.add("NotSupportedError", py.get_type::())?; pymod.add( "BaseConnectionPoolError", diff --git a/src/exceptions/rust_errors.rs b/src/exceptions/rust_errors.rs index 94b89fa0..f133321b 100644 --- a/src/exceptions/rust_errors.rs +++ b/src/exceptions/rust_errors.rs @@ -8,7 +8,7 @@ use super::python_errors::{ BaseConnectionError, BaseConnectionPoolError, BaseCursorError, BaseListenerError, BaseTransactionError, ConnectionClosedError, ConnectionExecuteError, ConnectionPoolBuildError, ConnectionPoolConfigurationError, ConnectionPoolExecuteError, CursorCloseError, - CursorClosedError, CursorFetchError, CursorStartError, DriverError, ListenerCallbackError, + CursorClosedError, CursorFetchError, CursorStartError, DatabaseError, ListenerCallbackError, ListenerClosedError, ListenerStartError, MacAddrParseError, RuntimeJoinError, SSLError, TransactionBeginError, TransactionClosedError, TransactionCommitError, TransactionExecuteError, TransactionRollbackError, TransactionSavepointError, UUIDValueConvertError, @@ -104,7 +104,7 @@ impl From for pyo3::PyErr { let error_desc = error.to_string(); match error { RustPSQLDriverError::RustPyError(err) => err, - RustPSQLDriverError::RustDriverError(_) => DriverError::new_err((error_desc,)), + RustPSQLDriverError::RustDriverError(_) => DatabaseError::new_err((error_desc,)), RustPSQLDriverError::RustMacAddrConversionError(_) => { MacAddrParseError::new_err((error_desc,)) } diff --git a/src/lib.rs b/src/lib.rs index 6be59c75..a20c1ce4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,15 @@ pub mod common; +pub mod connection; pub mod driver; pub mod exceptions; pub mod extra_types; pub mod format_helpers; +pub mod options; pub mod query_result; pub mod row_factories; pub mod runtime; pub mod statement; +pub mod transaction; pub mod value_converter; use common::add_module; @@ -25,20 +28,26 @@ fn psqlpy(py: Python<'_>, pymod: &Bound<'_, PyModule>) -> PyResult<()> { pymod.add_class::()?; pymod.add_class::()?; pymod.add_class::()?; - pymod.add_function(wrap_pyfunction!(driver::connection_pool::connect, pymod)?)?; + pymod.add_function(wrap_pyfunction!( + driver::connection_pool::connect_pool, + pymod + )?)?; pymod.add_class::()?; + pymod.add_function(wrap_pyfunction!(driver::connection::connect, pymod)?)?; pymod.add_class::()?; + // pymod.add_class::()?; + pymod.add_class::()?; + pymod.add_class::()?; pymod.add_class::()?; pymod.add_class::()?; pymod.add_class::()?; - pymod.add_class::()?; - pymod.add_class::()?; - pymod.add_class::()?; - pymod.add_class::()?; - pymod.add_class::()?; - pymod.add_class::()?; - pymod.add_class::()?; - pymod.add_class::()?; + pymod.add_class::()?; + pymod.add_class::()?; + pymod.add_class::()?; + pymod.add_class::()?; + pymod.add_class::()?; + pymod.add_class::()?; + pymod.add_class::()?; pymod.add_class::()?; pymod.add_class::()?; add_module(py, pymod, "extra_types", extra_types_module)?; diff --git a/src/driver/common_options.rs b/src/options.rs similarity index 60% rename from src/driver/common_options.rs rename to src/options.rs index a76d37dd..f6e4152f 100644 --- a/src/driver/common_options.rs +++ b/src/options.rs @@ -139,3 +139,83 @@ impl CopyCommandFormat { } } } + +#[pyclass(eq, eq_int)] +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum IsolationLevel { + ReadUncommitted, + ReadCommitted, + RepeatableRead, + Serializable, +} + +impl IsolationLevel { + /// Return isolation level as String literal. + #[must_use] + pub fn to_str_level(&self) -> String { + match self { + IsolationLevel::ReadUncommitted => "READ UNCOMMITTED".into(), + IsolationLevel::ReadCommitted => "READ COMMITTED".into(), + IsolationLevel::RepeatableRead => "REPEATABLE READ".into(), + IsolationLevel::Serializable => "SERIALIZABLE".into(), + } + } +} + +#[pyclass(eq, eq_int)] +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum ReadVariant { + ReadOnly, + ReadWrite, +} + +#[pyclass(eq, eq_int)] +#[derive(Clone, Copy, PartialEq)] +pub enum SynchronousCommit { + /// As the name indicates, the commit acknowledgment can come before + /// flushing the records to disk. + /// This is generally called as an asynchronous commit. + /// If the PostgreSQL instance crashes, + /// the last few asynchronous commits might be lost. + Off, + /// WAL records are written and flushed to local disks. + /// In this case, the commit will be acknowledged after the + /// local WAL Write and WAL flush completes. + Local, + /// WAL records are successfully handed over to + /// remote instances which acknowledged back + /// about the write (not flush). + RemoteWrite, + /// The meaning may change based on whether you have + /// a synchronous standby or not. + /// If there is a synchronous standby, + /// setting the value to on will result in waiting till “remote flush”. + On, + /// This will result in commits waiting until replies from the + /// current synchronous standby(s) indicate they have received + /// the commit record of the transaction and applied it so + /// that it has become visible to queries on the standby(s). + RemoteApply, +} + +impl SynchronousCommit { + /// Return isolation level as String literal. + #[must_use] + pub fn to_str_level(&self) -> String { + match self { + SynchronousCommit::Off => "off".into(), + SynchronousCommit::Local => "local".into(), + SynchronousCommit::RemoteWrite => "remote_write".into(), + SynchronousCommit::On => "on".into(), + SynchronousCommit::RemoteApply => "remote_apply".into(), + } + } +} + +#[derive(Clone, Copy, PartialEq)] +pub struct ListenerTransactionConfig { + isolation_level: Option, + read_variant: Option, + deferrable: Option, + synchronous_commit: Option, +} diff --git a/src/query_result.rs b/src/query_result.rs index cda02a8b..d9dd8848 100644 --- a/src/query_result.rs +++ b/src/query_result.rs @@ -1,4 +1,9 @@ -use pyo3::{prelude::*, pyclass, pymethods, types::PyDict, Py, PyAny, Python, ToPyObject}; +use pyo3::{ + prelude::*, + pyclass, pymethods, + types::{PyDict, PyTuple}, + Py, PyAny, Python, ToPyObject, +}; use tokio_postgres::Row; use crate::{exceptions::rust_errors::PSQLPyResult, value_converter::to_python::postgres_to_py}; diff --git a/src/statement/cache.rs b/src/statement/cache.rs index 7d78898d..7c07da40 100644 --- a/src/statement/cache.rs +++ b/src/statement/cache.rs @@ -5,7 +5,7 @@ use postgres_types::Type; use tokio::sync::RwLock; use tokio_postgres::Statement; -use super::{query::QueryString, utils::hash_str}; +use super::{parameters::Column, query::QueryString, utils::hash_str}; #[derive(Default)] pub(crate) struct StatementsCache(HashMap); @@ -44,6 +44,14 @@ impl StatementCacheInfo { pub(crate) fn types(&self) -> Vec { self.inner_stmt.params().to_vec() } + + pub(crate) fn columns(&self) -> Vec { + self.inner_stmt + .columns() + .iter() + .map(|column| Column::new(column.name().to_string(), column.table_oid().clone())) + .collect::>() + } } pub(crate) static STMTS_CACHE: Lazy> = diff --git a/src/statement/parameters.rs b/src/statement/parameters.rs index 09e0cbef..3aa12160 100644 --- a/src/statement/parameters.rs +++ b/src/statement/parameters.rs @@ -3,6 +3,7 @@ use std::iter::zip; use postgres_types::{ToSql, Type}; use pyo3::{ conversion::FromPyObjectBound, + pyclass, pymethods, types::{PyAnyMethods, PyMapping}, Py, PyObject, PyTypeCheck, Python, }; @@ -17,16 +18,48 @@ use crate::{ pub type QueryParameter = (dyn ToSql + Sync); +#[pyclass] +#[derive(Default, Clone, Debug)] +pub struct Column { + name: String, + table_oid: Option, +} + +impl Column { + pub fn new(name: String, table_oid: Option) -> Self { + Self { name, table_oid } + } +} + +#[pymethods] +impl Column { + #[getter] + fn get_name(&self) -> String { + self.name.clone() + } + + #[getter] + fn get_table_oid(&self) -> Option { + self.table_oid.clone() + } +} + pub(crate) struct ParametersBuilder { parameters: Option, types: Option>, + columns: Vec, } impl ParametersBuilder { - pub fn new(parameters: &Option, types: Option>) -> Self { + pub fn new( + parameters: &Option, + types: Option>, + columns: Vec, + ) -> Self { Self { parameters: parameters.clone(), types, + columns, } } @@ -55,13 +88,15 @@ impl ParametersBuilder { match (sequence_typed, mapping_typed) { (Some(sequence), None) => { - prepared_parameters = - Some(SequenceParametersBuilder::new(sequence, self.types).prepare(gil)?); + prepared_parameters = Some( + SequenceParametersBuilder::new(sequence, self.types, self.columns) + .prepare(gil)?, + ); } (None, Some(mapping)) => { if let Some(parameters_names) = parameters_names { prepared_parameters = Some( - MappingParametersBuilder::new(mapping, self.types) + MappingParametersBuilder::new(mapping, self.types, self.columns) .prepare(gil, parameters_names)?, ) } @@ -110,13 +145,15 @@ impl ParametersBuilder { pub(crate) struct MappingParametersBuilder { map_parameters: Py, types: Option>, + columns: Vec, } impl MappingParametersBuilder { - fn new(map_parameters: Py, types: Option>) -> Self { + fn new(map_parameters: Py, types: Option>, columns: Vec) -> Self { Self { map_parameters, types, + columns, } } @@ -143,7 +180,11 @@ impl MappingParametersBuilder { .map(|(parameter, type_)| from_python_typed(parameter.bind(gil), &type_)) .collect::>>()?; - Ok(PreparedParameters::new(converted_parameters, types)) + Ok(PreparedParameters::new( + converted_parameters, + types, + self.columns, + )) } fn prepare_not_typed( @@ -157,7 +198,11 @@ impl MappingParametersBuilder { .map(|parameter| from_python_untyped(parameter.bind(gil))) .collect::>>()?; - Ok(PreparedParameters::new(converted_parameters, vec![])) + Ok(PreparedParameters::new( + converted_parameters, + vec![], + self.columns, + )) } fn extract_parameters( @@ -185,13 +230,15 @@ impl MappingParametersBuilder { pub(crate) struct SequenceParametersBuilder { seq_parameters: Vec, types: Option>, + columns: Vec, } impl SequenceParametersBuilder { - fn new(seq_parameters: Vec, types: Option>) -> Self { + fn new(seq_parameters: Vec, types: Option>, columns: Vec) -> Self { Self { seq_parameters: seq_parameters, types, + columns, } } @@ -208,7 +255,11 @@ impl SequenceParametersBuilder { .map(|(parameter, type_)| from_python_typed(parameter.bind(gil), &type_)) .collect::>>()?; - Ok(PreparedParameters::new(converted_parameters, types)) + Ok(PreparedParameters::new( + converted_parameters, + types, + self.columns, + )) } fn prepare_not_typed(self, gil: Python<'_>) -> PSQLPyResult { @@ -218,7 +269,11 @@ impl SequenceParametersBuilder { .map(|parameter| from_python_untyped(parameter.bind(gil))) .collect::>>()?; - Ok(PreparedParameters::new(converted_parameters, vec![])) + Ok(PreparedParameters::new( + converted_parameters, + vec![], + self.columns, + )) } } @@ -226,11 +281,16 @@ impl SequenceParametersBuilder { pub struct PreparedParameters { parameters: Vec, types: Vec, + columns: Vec, } impl PreparedParameters { - pub fn new(parameters: Vec, types: Vec) -> Self { - Self { parameters, types } + pub fn new(parameters: Vec, types: Vec, columns: Vec) -> Self { + Self { + parameters, + types, + columns, + } } pub fn params(&self) -> Box<[&(dyn ToSql + Sync)]> { @@ -251,4 +311,8 @@ impl PreparedParameters { .collect::>() .into_boxed_slice() } + + pub fn columns(&self) -> &Vec { + &self.columns + } } diff --git a/src/statement/statement.rs b/src/statement/statement.rs index addaae89..fc45b3eb 100644 --- a/src/statement/statement.rs +++ b/src/statement/statement.rs @@ -3,7 +3,10 @@ use tokio_postgres::Statement; use crate::exceptions::rust_errors::{PSQLPyResult, RustPSQLDriverError}; -use super::{parameters::PreparedParameters, query::QueryString}; +use super::{ + parameters::{Column, PreparedParameters}, + query::QueryString, +}; #[derive(Clone, Debug)] pub struct PsqlpyStatement { @@ -32,7 +35,11 @@ impl PsqlpyStatement { pub fn statement_query(&self) -> PSQLPyResult<&Statement> { match &self.prepared_statement { Some(prepared_stmt) => return Ok(prepared_stmt), - None => return Err(RustPSQLDriverError::ConnectionExecuteError("No".into())), + None => { + return Err(RustPSQLDriverError::ConnectionExecuteError( + "No prepared parameters".into(), + )) + } } } @@ -43,4 +50,8 @@ impl PsqlpyStatement { pub fn params_typed(&self) -> Box<[(&(dyn ToSql + Sync), Type)]> { self.prepared_parameters.params_typed() } + + pub fn columns(&self) -> &Vec { + &self.prepared_parameters.columns() + } } diff --git a/src/statement/statement_builder.rs b/src/statement/statement_builder.rs index 5954f88c..054352a3 100644 --- a/src/statement/statement_builder.rs +++ b/src/statement/statement_builder.rs @@ -2,27 +2,30 @@ use pyo3::PyObject; use tokio::sync::RwLockWriteGuard; use tokio_postgres::Statement; -use crate::{driver::inner_connection::PsqlpyConnection, exceptions::rust_errors::PSQLPyResult}; +use crate::{ + connection::{structs::PSQLPyConnection, traits::Connection}, + exceptions::rust_errors::PSQLPyResult, +}; use super::{ cache::{StatementCacheInfo, StatementsCache, STMTS_CACHE}, - parameters::ParametersBuilder, + parameters::{Column, ParametersBuilder}, query::QueryString, statement::PsqlpyStatement, }; pub struct StatementBuilder<'a> { - querystring: String, - parameters: Option, - inner_conn: &'a PsqlpyConnection, + querystring: &'a String, + parameters: &'a Option, + inner_conn: &'a PSQLPyConnection, prepared: bool, } impl<'a> StatementBuilder<'a> { pub fn new( - querystring: String, - parameters: Option, - inner_conn: &'a PsqlpyConnection, + querystring: &'a String, + parameters: &'a Option, + inner_conn: &'a PSQLPyConnection, prepared: Option, ) -> Self { Self { @@ -48,7 +51,8 @@ impl<'a> StatementBuilder<'a> { } fn build_with_cached(self, cached: StatementCacheInfo) -> PSQLPyResult { - let raw_parameters = ParametersBuilder::new(&self.parameters, Some(cached.types())); + let raw_parameters = + ParametersBuilder::new(&self.parameters, Some(cached.types()), cached.columns()); let parameters_names = if let Some(converted_qs) = &cached.query.converted_qs { Some(converted_qs.params_names().clone()) @@ -73,8 +77,17 @@ impl<'a> StatementBuilder<'a> { querystring.process_qs(); let prepared_stmt = self.prepare_query(&querystring, self.prepared).await?; - let parameters_builder = - ParametersBuilder::new(&self.parameters, Some(prepared_stmt.params().to_vec())); + + let columns = prepared_stmt + .columns() + .iter() + .map(|column| Column::new(column.name().to_string(), column.table_oid().clone())) + .collect::>(); + let parameters_builder = ParametersBuilder::new( + &self.parameters, + Some(prepared_stmt.params().to_vec()), + columns, + ); let parameters_names = if let Some(converted_qs) = &querystring.converted_qs { Some(converted_qs.params_names().clone()) diff --git a/src/transaction/impls.rs b/src/transaction/impls.rs new file mode 100644 index 00000000..a2a7c147 --- /dev/null +++ b/src/transaction/impls.rs @@ -0,0 +1,35 @@ +use crate::{exceptions::rust_errors::PSQLPyResult, query_result::PSQLDriverPyQueryResult}; + +use super::structs::PSQLPyTransaction; +use tokio_postgres::{Portal as tp_Portal, ToStatement}; + +impl PSQLPyTransaction { + pub async fn query_portal( + &self, + portal: &tp_Portal, + size: i32, + ) -> PSQLPyResult { + let portal_res = match self { + PSQLPyTransaction::PoolTransaction(txid) => txid.query_portal(portal, size).await?, + PSQLPyTransaction::SingleTransaction(txid) => txid.query_portal(portal, size).await?, + }; + + Ok(PSQLDriverPyQueryResult::new(portal_res)) + } + + pub async fn portal( + &self, + querystring: &T, + params: &[&(dyn postgres_types::ToSql + Sync)], + ) -> PSQLPyResult + where + T: ?Sized + ToStatement, + { + let portal: tp_Portal = match self { + PSQLPyTransaction::PoolTransaction(conn) => conn.bind(querystring, params).await?, + PSQLPyTransaction::SingleTransaction(conn) => conn.bind(querystring, params).await?, + }; + + Ok(portal) + } +} diff --git a/src/transaction/mod.rs b/src/transaction/mod.rs new file mode 100644 index 00000000..4bc01193 --- /dev/null +++ b/src/transaction/mod.rs @@ -0,0 +1,2 @@ +pub mod impls; +pub mod structs; diff --git a/src/transaction/structs.rs b/src/transaction/structs.rs new file mode 100644 index 00000000..0f8946cd --- /dev/null +++ b/src/transaction/structs.rs @@ -0,0 +1,7 @@ +use deadpool_postgres::Transaction as dp_Transaction; +use tokio_postgres::Transaction as tp_Transaction; + +pub enum PSQLPyTransaction { + PoolTransaction(dp_Transaction<'static>), + SingleTransaction(tp_Transaction<'static>), +} diff --git a/src/value_converter/to_python.rs b/src/value_converter/to_python.rs index c0801bac..6ee761bc 100644 --- a/src/value_converter/to_python.rs +++ b/src/value_converter/to_python.rs @@ -172,6 +172,12 @@ fn postgres_bytes_to_py( } Ok(py.None()) } + Type::OID => { + Ok(composite_field_postgres_to_py::>(type_, buf, is_simple)?.to_object(py)) + } + Type::NAME => Ok( + composite_field_postgres_to_py::>(type_, buf, is_simple)?.to_object(py), + ), // // ---------- String Types ---------- // // Convert TEXT and VARCHAR type into String, then into str Type::TEXT | Type::VARCHAR | Type::XML => Ok(composite_field_postgres_to_py::< @@ -342,6 +348,11 @@ fn postgres_bytes_to_py( composite_field_postgres_to_py::>>(type_, buf, is_simple)?, ) .to_object(py)), + Type::OID_ARRAY => Ok(postgres_array_to_py( + py, + composite_field_postgres_to_py::>>(type_, buf, is_simple)?, + ) + .to_object(py)), // Convert ARRAY of TEXT or VARCHAR into Vec, then into list[str] Type::TEXT_ARRAY | Type::VARCHAR_ARRAY | Type::XML_ARRAY => Ok(postgres_array_to_py( py, diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..6cf86fe1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "ES2022" + }, + "include": [ + "docs/.vuepress/**/*.ts", + "docs/.vuepress/**/*.vue" + ], + "exclude": [ + "node_modules" + ] +}