diff --git a/.gitignore b/.gitignore index 526d3a3f7..8309fa2ae 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ todo.txt examples/demo2 *.sqlite +*.sqlite-wal +*.sqlite-shm # IDE config files .idea diff --git a/CHANGELOG.md b/CHANGELOG.md index decc2642a..76878913f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ ## Unreleased + +## v0.11.0 + + +* Upgrade **SeaORM to v1.1.0** +* Added OpenAPI example +* Improve health route [https://github.com/loco-rs/loco/pull/851](https://github.com/loco-rs/loco/pull/851) +* Add good pragmas to Sqlite [https://github.com/loco-rs/loco/pull/848](https://github.com/loco-rs/loco/pull/848) +* Upgrade to rsbuild 1.0. [https://github.com/loco-rs/loco/pull/792](https://github.com/loco-rs/loco/pull/792) +* Implements fmt::Debug to pub structs. [https://github.com/loco-rs/loco/pull/812](https://github.com/loco-rs/loco/pull/812) +* Add num_workers config for sidekiq queue. [https://github.com/loco-rs/loco/pull/823](https://github.com/loco-rs/loco/pull/823) +* Fix some comments in the starters and example code. [https://github.com/loco-rs/loco/pull/824](https://github.com/loco-rs/loco/pull/824) +* Fix Y2038 bug for JWT on 32 bit platforms. [https://github.com/loco-rs/loco/pull/825](https://github.com/loco-rs/loco/pull/825) +* Make App URL in Boot Banner Clickable. [https://github.com/loco-rs/loco/pull/826](https://github.com/loco-rs/loco/pull/826) +* Add `--no-banner` flag to allow disabling the banner display. [https://github.com/loco-rs/loco/pull/839](https://github.com/loco-rs/loco/pull/839) +* add on_shutdown hook. [https://github.com/loco-rs/loco/pull/842](https://github.com/loco-rs/loco/pull/842) + + +## v0.10.1 + * `Format(respond_to): Format` extractor in controller can now be replaced with `respond_to: RespondTo` extractor for less typing. * When supplying data to views, you can now use `data!` instead of `serde_json::json!` for shorthand. * Refactor middlewares. [https://github.com/loco-rs/loco/pull/785](https://github.com/loco-rs/loco/pull/785). Middleware selection, configuration, and tweaking is MUCH more powerful and convenient now. You can keep the `middleware:` section empty or remove it now, see more in [the middleware docs](https://loco.rs/docs/the-app/controller/#middleware) diff --git a/Cargo.toml b/Cargo.toml index e5df7eebb..a7d342418 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "Apache-2.0" [package] name = "loco-rs" -version = "0.10.1" +version = "0.11.0" description = "The one-person framework for Rust" homepage = "https://loco.rs/" documentation = "https://docs.rs/loco-rs" @@ -47,10 +47,10 @@ colored = "2" sea-orm = { version = "1.0.0", features = [ - "sqlx-postgres", # `DATABASE_DRIVER` feature - "sqlx-sqlite", - "runtime-tokio-rustls", - "macros", + "sqlx-postgres", # `DATABASE_DRIVER` feature + "sqlx-sqlite", + "runtime-tokio-rustls", + "macros", ], optional = true } tokio = { version = "1.33.0", default-features = false } @@ -73,10 +73,10 @@ fs-err = "2.11.0" tera = "1.19.1" heck = "0.4.0" lettre = { version = "0.11.4", default-features = false, features = [ - "builder", - "hostname", - "smtp-transport", - "tokio1-rustls-tls", + "builder", + "hostname", + "smtp-transport", + "tokio1-rustls-tls", ] } include_dir = "0.7.3" thiserror = "1" @@ -128,13 +128,13 @@ tokio-cron-scheduler = { version = "0.11.0", features = ["signal"] } english-to-cron = { version = "0.1.2" } # bg_pg: postgres workers -sqlx = { version = "0.7", default-features = false, features = [ - "postgres", +sqlx = { version = "0.8.2", default-features = false, features = [ + "postgres", ], optional = true } ulid = { version = "1", optional = true } # bg_redis: redis workers -rusty-sidekiq = { version = "0.8.2", default-features = false, optional = true } +rusty-sidekiq = { version = "0.11.0", default-features = false, optional = true } bb8 = { version = "0.8.1", optional = true } [workspace.dependencies] @@ -142,26 +142,26 @@ async-trait = { version = "0.1.74" } axum = { version = "0.7.5", features = ["macros"] } tower = "0.4" tower-http = { version = "0.6.1", features = [ - "trace", - "catch-panic", - "timeout", - "add-extension", - "cors", - "fs", - "set-header", - "compression-full", + "trace", + "catch-panic", + "timeout", + "add-extension", + "cors", + "fs", + "set-header", + "compression-full", ] } [dependencies.sea-orm-migration] optional = true version = "1.0.0" features = [ - # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. - # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. - # e.g. - "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature - "sqlx-postgres", # `DATABASE_DRIVER` feature - "sqlx-sqlite", + # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. + # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. + # e.g. + "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature + "sqlx-postgres", # `DATABASE_DRIVER` feature + "sqlx-sqlite", ] [package.metadata.docs.rs] diff --git a/docs-site/config.toml b/docs-site/config.toml index a8df64ad2..3133b8eeb 100644 --- a/docs-site/config.toml +++ b/docs-site/config.toml @@ -87,9 +87,6 @@ impl Model { ).await?; } } - - - ``` ''' diff --git a/docs-site/content/blog/axum-session.md b/docs-site/content/blog/axum-session.md index 4a1f2d337..7054dcb05 100644 --- a/docs-site/content/blog/axum-session.md +++ b/docs-site/content/blog/axum-session.md @@ -64,7 +64,7 @@ impl Hooks for App { Now, you can create your controller that uses Axum session. Use the `cargo loco generate controller` command: ```sh -❯ cargo loco generate controller mysession -k api +❯ cargo loco generate controller mysession --api Finished dev [unoptimized + debuginfo] target(s) in 0.36s Running `target/debug/axum-session-cli generate controller mysession` added: "src/controllers/mysession.rs" @@ -166,7 +166,7 @@ impl Hooks for App { Create the controller as before using `cargo loco generate controller` ```sh -❯ cargo loco generate controller mysession -k api +❯ cargo loco generate controller mysession --api Finished dev [unoptimized + debuginfo] target(s) in 0.36s Running `target/debug/axum-session-cli generate controller mysession` added: "src/controllers/mysession.rs" diff --git a/docs-site/content/docs/getting-started/guide.md b/docs-site/content/docs/getting-started/guide.md index 195f52313..e39170a11 100644 --- a/docs-site/content/docs/getting-started/guide.md +++ b/docs-site/content/docs/getting-started/guide.md @@ -45,7 +45,7 @@ Loco is a Web or API framework for Rust. It's also a productivity suite for deve ## Creating a New Loco App -You can follow this guide for a step-by-step "bottom up" learning, or you can jump and go with the [tour](./tour.md) instead for a quicker "top down" intro. +You can follow this guide for a step-by-step "bottom up" learning, or you can jump and go with the [tour](@/docs/getting-started/tour/index.md) instead for a quicker "top down" intro. ### Installing @@ -131,7 +131,7 @@ $ curl localhost:5150/_health ```
-The built in _health route will tell you that you have configured your app properly: it can establish a connection to your Postgres and Redis instances successfully. +The built in _health route will tell you that you have configured your app properly: it can establish a connection to your Database and Redis instances successfully.
### Say "Hello", Loco @@ -139,7 +139,7 @@ The built in _health route will tell you that you have configured y Let's add a quick _hello_ response to our service. ```sh -$ cargo loco generate controller guide -k api +$ cargo loco generate controller guide --api added: "src/controllers/guide.rs" injected: "src/controllers/mod.rs" injected: "src/app.rs" @@ -465,7 +465,7 @@ $ cargo playground We're now ready to plug this into an `articles` controller. First, generate a new controller: ```sh -$ cargo loco generate controller articles -k api +$ cargo loco generate controller articles --api added: "src/controllers/articles.rs" injected: "src/controllers/mod.rs" injected: "src/app.rs" @@ -630,7 +630,7 @@ Let's add another model, this time: `Comment`. We want to create a relation - a Instead of coding the model and controller by hand, we're going to create a **comment scaffold** which will generate a fully working CRUD API comments. We're also going to use the special `references` type: ```sh -$ cargo loco generate scaffold comment content:text article:references -k api +$ cargo loco generate scaffold comment content:text article:references --api ``` If you peek into the new migration, you'll discover a new database relation in the articles table: diff --git a/docs-site/content/docs/getting-started/tour/index.md b/docs-site/content/docs/getting-started/tour/index.md index 379af1b7e..32cfc2066 100644 --- a/docs-site/content/docs/getting-started/tour/index.md +++ b/docs-site/content/docs/getting-started/tour/index.md @@ -13,6 +13,7 @@ top = false flair =[] +++ +

@@ -49,6 +50,12 @@ If you select all defaults, you'll have: Now `cd` into your `myapp` and start your app by running `cargo loco start`: + + +
+ + If you have the `Client` asset serving option configured, make sure you build your frontend before starting the server. This can be done by changing into the frontend directory (`cd frontend`) and running `pnpm install` and `pnpm build`. +
```sh @@ -76,6 +83,7 @@ listening on port 5150
+ You don't have to run things through `cargo` but in development it's highly recommended. If you build `--release`, your binary contains everything including your code and `cargo` or Rust is not needed.
@@ -84,8 +92,13 @@ listening on port 5150 We have a base SaaS app with user authentication generated for us. Let's make it a blog backend by adding a `post` and a full CRUD API using `scaffold`: +
+ +You can choose between generating an `api`, `html` or `htmx` scaffold using the required `-k` flag. +
+ ```sh -$ cargo loco generate scaffold post title:string content:text -k api +$ cargo loco generate scaffold post title:string content:text --api : : @@ -127,6 +140,14 @@ listening on port 5150 ``` +
+ +Depending on which `-k` option you chose, the steps for creating a scaffolded resource will change. With the `api` flag or the `htmx` flag you can use the below example. But with the `html` flag, it is recommended you do the post creation steps in your browser. + +If you want to use `curl` to test the `html` scaffold, you will need to send your requests with the Content-Type `application/x-www-form-urlencoded` and the body as `title=Your+Title&content=Your+Content` by default. This can be changed to allow `application/json` as a `Content-Type` in the code if desired. + +
+ Next, try adding a `post` with `curl`: ```sh @@ -147,7 +168,7 @@ For those counting -- the commands for creating a blog backend were: 1. `cargo install loco-cli` 2. `cargo install sea-orm-cli` 3. `loco new` -4. `cargo loco generate scaffold post title:string content:text -k api` +4. `cargo loco generate scaffold post title:string content:text --api` Done! enjoy your ride with `loco` πŸš‚ @@ -160,7 +181,7 @@ Your generated app contains a fully working authentication suite, based on JWTs. The `/api/auth/register` endpoint creates a new user in the database with an `email_verification_token` for account verification. A welcome email is sent to the user with a verification link. ```sh -$ curl --location '127.0.0.1:5150/api/auth/register' \ +$ curl --location 'localhost:5150/api/auth/register' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "Loco user", @@ -176,7 +197,7 @@ For security reasons, if the user is already registered, no new user is created, After registering a new user, use the following request to log in: ```sh -$ curl --location '127.0.0.1:5150/api/auth/login' \ +$ curl --location 'localhost:5150/api/auth/login' \ --header 'Content-Type: application/json' \ --data-raw '{ "email": "user@loco.rs", @@ -203,7 +224,7 @@ In your client-side app, you save this JWT token and make following requests wit This endpoint is protected by auth middleware. We will use the token we got earlier to perform a request with the _bearer token_ technique (replace `TOKEN` with the JWT token you got earlier): ```sh -$ curl --location --request GET '127.0.0.1:5150/api/user/current' \ +$ curl --location --request GET 'localhost:5150/api/user/current' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer TOKEN' ``` diff --git a/docs-site/content/docs/processing/scheduler.md b/docs-site/content/docs/processing/scheduler.md index 6bd888201..3cb7374ba 100644 --- a/docs-site/content/docs/processing/scheduler.md +++ b/docs-site/content/docs/processing/scheduler.md @@ -16,7 +16,7 @@ flair =[] +++ -Loco simplifies the traditional, often cumbersome `crontab` system, making it easier and more elegant to schedule cron jobs. The scheduler job can execute either a shell script command or run a registered [task](./task.md). +Loco simplifies the traditional, often cumbersome `crontab` system, making it easier and more elegant to schedule cron jobs. The scheduler job can execute either a shell script command or run a registered [task](@/docs/processing/task.md). ## Setting Up @@ -96,7 +96,7 @@ The scheduler configuration consists of the following elements: ``` * `shell`: by default `false` meaning executing the the `run` value as a task. if `true` execute the `run` value as shell command * `run`: Cronjob command to run. - * `Task:` The task name (with variables e.x `[TASK_NAME] KEY:VAl`. follow [here](./task.md) to see task arguments ). Note that the `shell` field should be false. + * `Task:` The task name (with variables e.x `[TASK_NAME] KEY:VAl`. follow [here](@/docs/processing/task.md) to see task arguments ). Note that the `shell` field should be false. * `Shell`: Run a shell command (e.x `"echo loco >> ./scheduler.txt"`). Note that the `shell` field should be true. * `tags` (Optional): A list of tags to categorize and manage the job. * `output` (Optional): Overrides the global `scheduler.output` for this job. diff --git a/docs-site/content/docs/resources/around-the-web.md b/docs-site/content/docs/resources/around-the-web.md new file mode 100644 index 000000000..a7f247195 --- /dev/null +++ b/docs-site/content/docs/resources/around-the-web.md @@ -0,0 +1,43 @@ ++++ +title = "Around the Web" +description = "" +date = 2024-01-21T19:00:00+00:00 +updated = 2024-01-21T19:00:00+00:00 +draft = false +weight = 1 +sort_by = "weight" +template = "docs/page.html" + +[extra] +lead = "" +toc = true +top = false +flair =[] ++++ + + +Check out Loco resources and links from around the Web. + + +## Blogs + +- [Introducing Loco: the "Rust on Rails"](https://blog.rng0.io/introducing-loco/) - by [@jondot](https://x.com/jondot) +- [Loco is a New Framework for Rust Inspired by Rails](https://www.infoq.com/news/2024/02/loco-new-framework-rust-rails/) - by [infoq.com](https://infoq.com) +- [Going in cold inside the locomotive](https://vanhalt.com/post/loco-rs/) by [@vanhalt](https://twitter.com/vanhalt) +- [Introducing Loco: The Rails of Rust](https://www.shuttle.dev/blog/2023/12/20/loco-rust-rails) by [shuttle](https://shuttle.dev) +- [Getting Started with Loco & SeaORM](https://www.sea-ql.org/blog/2024-05-28-getting-started-with-loco-seaorm/) by [Billy Chan (SeaORM)](https://github.com/billy1624) + +## Videos + +- [A Legendary Web Framework is Reborn... in Rust](https://www.youtube.com/watch?v=7utPutDORb4) - by [Code to the Moon](https://www.youtube.com/@codetothemoon) + + +## Ecosystem + +- [rhai-loco](https://docs.rs/rhai-loco/latest/rhai_loco/) - This crate adds [Rhai](https://rhai.rs) script support to [Loco](https://loco.rs) +- [loco-oauth2](https://github.com/yinho999/loco-oauth2) - Loco OAuth2 is a simple OAuth2 initializer for the Loco API. It is designed to be a tiny and easy-to-use library for implementing OAuth2 in your application. + +## App Examples + +* [Chat rooms](https://github.com/loco-rs/chat-rooms) - With opening a web socket +* [Todo list](https://github.com/loco-rs/todo-list) - working with rest API diff --git a/docs-site/content/docs/resources/faq.md b/docs-site/content/docs/resources/faq.md index 3b2e60660..77d501050 100644 --- a/docs-site/content/docs/resources/faq.md +++ b/docs-site/content/docs/resources/faq.md @@ -4,7 +4,7 @@ description = "Answers to frequently asked questions." date = 2021-05-01T19:30:00+00:00 updated = 2021-05-01T19:30:00+00:00 draft = false -weight = 1 +weight = 2 sort_by = "weight" template = "docs/page.html" diff --git a/docs-site/content/docs/resources/live-examples.md b/docs-site/content/docs/resources/live-examples.md deleted file mode 100644 index 252077f46..000000000 --- a/docs-site/content/docs/resources/live-examples.md +++ /dev/null @@ -1,23 +0,0 @@ -+++ -title = "Examples" -description = "" -date = 2024-01-21T19:00:00+00:00 -updated = 2024-01-21T19:00:00+00:00 -draft = false -weight = 2 -sort_by = "weight" -template = "docs/page.html" - -[extra] -lead = "" -toc = true -top = false -flair =[] -+++ - - -Explore a compilation of websites along with exemplary Loco implementations on this page. Feel free to contribute by adding additional websites to the list through the submission of a pull request. Your contributions are greatly appreciated! - - -* [Chat rooms](https://github.com/loco-rs/chat-rooms) - With opening a web socket -* [Todo list](https://github.com/loco-rs/todo-list) - working with rest API diff --git a/docs-site/content/docs/the-app/your-project.md b/docs-site/content/docs/the-app/your-project.md index 0be8f985b..22f8082cc 100644 --- a/docs-site/content/docs/the-app/your-project.md +++ b/docs-site/content/docs/the-app/your-project.md @@ -156,7 +156,7 @@ Options: You can begin by generating a scaffold for the Post resource, which will represent a single blog posting. To accomplish this, open your terminal and enter the following command: ```sh -cargo loco generate scaffold posts name:string title:string content:text +cargo loco generate scaffold posts name:string title:string content:text --api ``` @@ -282,6 +282,20 @@ if let Some(settings) = &ctx.config.settings { } ``` +### Server + + + +Here is a detailed description of the interface (listening, etc.) parameters under `server:`: + +* `port:` as the name says, for changing ports, mostly when behind a load balancer, etc. + +* `binding:` for changing what the IP interface "binds" to, mostly, when you are behind a load balancer like `ngnix` you bind to a local address (when the LB is also there). However you can also bind to "world" (`0.0.0.0`). You can set the binding: field via config, or via the CLI (using the `-b` flag) -- which is what Rails is doing. + +* `host:` - for "visibility" use cases or out-of-band use cases. For example, some times you want to display the current server host (in terms of domain name, etc.), which serves for visibility. And some times, as in the case of emails -- your server address is "out of band", meaning when I open my gmail account and I have your email -- I have to click what looks like your external address or visible address (official domain name, etc), and not an internal "host" address which is what may be the wrong thing to do (imagine an email link pointing to "http://127.0.0.1/account/verify") + + + ### Logger Other than the commented fields in the `logger:` section on your YAML file, here's some more context: diff --git a/docs-site/static/ahrefs_f06cfb9c2671c1b7a5b6eec0d47a07719bd6d5a2240b829cad6a3f40684fa370 b/docs-site/static/ahrefs_f06cfb9c2671c1b7a5b6eec0d47a07719bd6d5a2240b829cad6a3f40684fa370 new file mode 100644 index 000000000..0b57f2771 --- /dev/null +++ b/docs-site/static/ahrefs_f06cfb9c2671c1b7a5b6eec0d47a07719bd6d5a2240b829cad6a3f40684fa370 @@ -0,0 +1 @@ +ahrefs-site-verification_f06cfb9c2671c1b7a5b6eec0d47a07719bd6d5a2240b829cad6a3f40684fa370 \ No newline at end of file diff --git a/docs-site/translations/tour-fr.md b/docs-site/translations/tour-fr.md new file mode 100644 index 000000000..8a21b4683 --- /dev/null +++ b/docs-site/translations/tour-fr.md @@ -0,0 +1,215 @@ ++++ +title = "AperΓ§u rapide" +date = 2021-05-01T08:00:00+00:00 +updated = 2021-05-01T08:00:00+00:00 +draft = false +weight = 2 +sort_by = "weight" +template = "docs/page.html" + +[extra] +toc = true +top = false +flair =[] ++++ + +[English](./index.md) - FranΓ§ais + + +
+
+
+CrΓ©ons un blog cotΓ© serveur sur Loco en quelques minutes. CommenΓ§ons par installer `loco-cli` et `sea-orm-cli`: + + +```sh +cargo install loco-cli +cargo install sea-orm-cli # Only when DB is needed +``` + + + + Vous pouvez maintenant crΓ©er votre nouvelle application (choisissez "`SaaS` app"). + + ```sh + ❯ loco new +βœ” ❯ App name? Β· myapp +βœ” ❯ What would you like to build? Β· SaaS app (with DB and user auth) +βœ” ❯ Select a DB Provider Β· Sqlite +βœ” ❯ Select your background worker type Β· Async (in-process tokyo async tasks) +βœ” ❯ Select an asset serving configuration Β· Client (configures assets for frontend serving) + + πŸš‚ Loco app generated successfully in: + myapp/ + ``` + +Si vous sΓ©lectionnez tous les paramΓ¨tres par dΓ©faut, vous aurez: + +* `sqlite` pour la base de donnΓ©es. DΓ©couvrez les types de bases de donnΓ©es dans [Sqlite vs Postgres](@/docs/the-app/models.md#sqlite-vs-postgres) dans la section _models_ . +* `async` pour les _workers_ en arriΓ¨re-plan. En savoir plus sur la configuration des _workers_ [async vs queue](@/docs/processing/workers.md#async-vs-queue) dans la section _workers_ . +* `Client` configuration pour la diffusion des ressources. Cela signifie que votre backend servira d'API. + + + Maintenant, faites `cd` dans votre `myapp` et dΓ©marrez votre application en exΓ©cutant `cargo loco start`: + + +```sh +$ cargo loco start + + β–„ β–€ + β–€ β–„ + β–„ β–€ β–„ β–„ β–„β–€ + β–„ β–€β–„β–„ + β–„ β–€ β–€ β–€β–„β–€β–ˆβ–„ + β–€β–ˆβ–„ +β–„β–„β–„β–„β–„β–„β–„ β–„β–„β–„β–„β–„β–„β–„β–„β–„ β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„ β–„β–„β–„β–„β–„β–„β–„β–„β–„ β–€β–€β–ˆ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–€β–ˆ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–€β–€β–€ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–„β–ˆβ–„ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–„ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–„β–„β–„ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–€ + β–€β–€β–€β–ˆβ–ˆβ–„ β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ β–ˆβ–ˆβ–€ + β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ + https://loco.rs + +listening on port 5150 +``` + + + +
+ Vous n'Γͺtes pas obligΓ© d'exΓ©cuter via `cargo` mais en dΓ©veloppement, c'est fortement +recommandΓ©. Si vous compilez avec `--release`, votre binaire contiendra tout +y compris votre code. Ainsi `cargo` ou Rust ne seront plus nΓ©cessaire.
+ +## Ajouter une API de type CRUD + +Nous avons une application SaaS de base avec une authentification utilisateur gΓ©nΓ©rΓ©e pour nous. Faisons-en un backend de blog en ajoutant un `post` et une API CRUD complΓ¨te Γ  l'aide de `scaffold`Β : + +```sh +$ cargo loco generate scaffold post title:string content:text + + : + : +added: "src/controllers/post.rs" +injected: "src/controllers/mod.rs" +injected: "src/app.rs" +added: "tests/requests/post.rs" +injected: "tests/requests/mod.rs" +* Migration for `post` added! You can now apply it with `$ cargo loco db migrate`. +* A test for model `posts` was added. Run with `cargo test`. +* Controller `post` was added successfully. +* Tests for controller `post` was added successfully. Run `cargo test`. +``` + +Votre base de donnΓ©es a Γ©tΓ© migrΓ©e et le modΓ¨le, les entitΓ©s et un contrΓ΄leur CRUD complet ont Γ©tΓ© gΓ©nΓ©rΓ©s automatiquement. + +RedΓ©marrez votre applicationΒ : + +```sh +$ cargo loco start + + β–„ β–€ + β–€ β–„ + β–„ β–€ β–„ β–„ β–„β–€ + β–„ β–€β–„β–„ + β–„ β–€ β–€ β–€β–„β–€β–ˆβ–„ + β–€β–ˆβ–„ +β–„β–„β–„β–„β–„β–„β–„ β–„β–„β–„β–„β–„β–„β–„β–„β–„ β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„ β–„β–„β–„β–„β–„β–„β–„β–„β–„ β–€β–€β–ˆ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–€β–ˆ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–€β–€β–€ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–„β–ˆβ–„ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–„ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–„β–„β–„ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ +β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–€ + β–€β–€β–€β–ˆβ–ˆβ–„ β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ β–ˆβ–ˆβ–€ + β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ + https://loco.rs + +listening on port 5150 +``` + + +Ensuite, essayez d’ajouter un `post` avec `curl`: + +```sh +$ curl -X POST -H "Content-Type: application/json" -d '{ + "title": "Your Title", + "content": "Your Content xxx" +}' localhost:5150/posts +``` + +Vous pouvez lister vos publications (posts): + +```sh +$ curl localhost:5150/posts +``` + +Pour ceux qui comptent -- les commandes pour crΓ©er un backend de blog Γ©taient: + +1. `cargo install loco-cli` +2. `cargo install sea-orm-cli` +3. `loco new` +4. `cargo loco generate scaffold post title:string content:text` + +VoilΓ ! Profitez de votre balade avec `loco` πŸš‚ + +## VΓ©rifions l'authentification SaaS + +L'application Saas gΓ©nΓ©rΓ©e contient une suite d’authentification entiΓ¨rement fonctionnelle, basΓ©e sur les JWT. + +### Enregistrer un nouvel utilisateur + +Le point de terminaison `/api/auth/register` crΓ©e un nouvel utilisateur dans la base de donnΓ©es avec un `email_verification_token` pour la vΓ©rification du compte. Un e-mail de bienvenue est envoyΓ© Γ  l'utilisateur avec un lien de vΓ©rification. + +```sh +$ curl --location '127.0.0.1:5150/api/auth/register' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "name": "Loco user", + "email": "user@loco.rs", + "password": "12341234" + }' +``` + +Pour des raisons de sΓ©curitΓ©, si l'utilisateur est dΓ©jΓ  enregistrΓ©, aucun nouvel utilisateur n'est créé et un statut 200 est renvoyΓ© sans exposer les dΓ©tails de l'e-mail de l'utilisateur. + +### Login + +AprΓ¨s avoir enregistrΓ© un nouvel utilisateur, utilisez la requΓͺte suivante pour vous connecter: + +```sh +$ curl --location '127.0.0.1:5150/api/auth/login' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "email": "user@loco.rs", + "password": "12341234" + }' +``` + +La rΓ©ponse inclut un Token (jeton) JWT pour l’authentification, l’ID utilisateur, le nom et l’état de vΓ©rification. + +```sh +{ + "token": "...", + "pid": "2b20f998-b11e-4aeb-96d7-beca7671abda", + "name": "Loco user", + "claims": null + "is_verified": false +} +``` + +Dans votre application cΓ΄tΓ© client, vous enregistrez ce jeton JWT et effectuez les requΓͺtes suivantes avec le jeton en utilisant _bearer token_ (voir ci-dessous) afin que les requΓͺtes soient authentifiΓ©es. + +### Obtenir l'utilisateur actuel + +Ce point de terminaison est protΓ©gΓ© par un middleware d'authentification. Nous utiliserons le jeton que nous avons obtenu prΓ©cΓ©demment pour effectuer une requΓͺte avec la technique _bearer token_ (remplacez `TOKEN` par le jeton JWT que vous avez obtenu prΓ©cΓ©demment): + +```sh +$ curl --location --request GET '127.0.0.1:5150/api/user/current' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Bearer TOKEN' +``` + +VoilΓ  votre premiΓ¨re demande authentifiΓ©eΒ ! + +Consultez le code source de `controllers/auth.rs` pour voir comment utiliser le middleware d'authentification dans vos propres contrΓ΄leurs. diff --git a/examples/demo/Cargo.lock b/examples/demo/Cargo.lock index 407ecc5ec..52f92b4af 100644 --- a/examples/demo/Cargo.lock +++ b/examples/demo/Cargo.lock @@ -744,13 +744,16 @@ dependencies = [ [[package]] name = "bigdecimal" -version = "0.3.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" dependencies = [ + "autocfg", + "libm", "num-bigint", "num-integer", "num-traits", + "serde", ] [[package]] @@ -977,13 +980,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.99" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -1168,6 +1171,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.18.1" @@ -1436,6 +1448,7 @@ dependencies = [ "tracing-subscriber", "trycmd", "unic-langid", + "utoipa", "uuid", "validator", ] @@ -1478,7 +1491,7 @@ version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version 0.4.0", @@ -1593,18 +1606,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" -[[package]] -name = "educe" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 2.0.66", -] - [[package]] name = "either" version = "1.12.0" @@ -1667,26 +1668,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "enum-ordinalize" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" -dependencies = [ - "enum-ordinalize-derive", -] - -[[package]] -name = "enum-ordinalize-derive" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -2177,9 +2158,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown 0.14.5", ] @@ -2189,9 +2170,6 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] [[package]] name = "heck" @@ -2674,6 +2652,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.5", + "serde", ] [[package]] @@ -2907,7 +2886,7 @@ dependencies = [ "nom", "percent-encoding", "quoted_printable", - "rustls 0.23.10", + "rustls 0.23.15", "rustls-pemfile 2.1.2", "socket2 0.5.7", "tokio", @@ -2940,9 +2919,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -3580,9 +3559,9 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.17.2" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" +checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" dependencies = [ "aliasable", "ouroboros_macro", @@ -3591,13 +3570,14 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.17.2" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" +checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" dependencies = [ "heck 0.4.1", - "proc-macro-error", + "itertools 0.12.1", "proc-macro2", + "proc-macro2-diagnostics", "quote", "syn 2.0.66", ] @@ -3918,7 +3898,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", - "yansi", + "yansi 0.5.1", ] [[package]] @@ -3969,6 +3949,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "version_check", + "yansi 1.0.1", +] + [[package]] name = "prost" version = "0.12.6" @@ -4476,15 +4469,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -4510,9 +4503,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -4526,9 +4519,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -4543,26 +4536,28 @@ checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-sidekiq" -version = "0.8.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a00db3916faeea070039864f98d4fd759d96fc07722571a4918d996fea5621" +checksum = "c64e90d83ece20649320d4d7eab794c43390e3db4dd8e67a82e4c82419e3ac7b" dependencies = [ "async-trait", "bb8", "chrono", + "convert_case 0.6.0", "cron_clock", "gethostname", - "heck 0.4.1", "hex", "num_cpus", "rand", "redis", "serde", "serde_json", + "serial_test", "sha2", "slog-term", "thiserror", "tokio", + "tokio-util", "tracing", "tracing-subscriber", ] @@ -4628,9 +4623,9 @@ dependencies = [ [[package]] name = "sea-orm" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d4ec1cdd8bdd3553d3c946079f58efa33fedc477f32603652652abcef96fe6" +checksum = "4c4872675cc5d5d399a2a202c60f3a393ec8d3f3307c36adb166517f348e4db5" dependencies = [ "async-stream", "async-trait", @@ -4656,9 +4651,9 @@ dependencies = [ [[package]] name = "sea-orm-cli" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d525eee597817631f800857b0c2fe8645ec9c65b4304176a44bf14b93366009e" +checksum = "0aefbd960c9ed7b2dfbab97b11890f5d8c314ad6e2f68c7b36c73ea0967fcc25" dependencies = [ "chrono", "clap", @@ -4673,9 +4668,9 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f363ead48b625a6f8f905322a820464f728fa4fe4f1c222bed5234ccf8fb8555" +checksum = "85f714906b72e7265c0b2077d0ad8f235dabebda513c92f1326d5d40cef0dd01" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -4687,9 +4682,9 @@ dependencies = [ [[package]] name = "sea-orm-migration" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df62369752f91b9295f8d71c146d84f818301a9ae7295106ebe8bbaa989a072" +checksum = "aa7bbfbe3bec60b5925193acc9c98b9f8ae9853f52c8004df0c1ea5193c01ea0" dependencies = [ "async-trait", "clap", @@ -4704,13 +4699,12 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5073b2cfed767511a57d18115f3b3d8bcb5690bf8c89518caec6cb22c0cd74" +checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb" dependencies = [ "bigdecimal", "chrono", - "educe", "inherent", "ordered-float 3.9.2", "rust_decimal", @@ -4722,9 +4716,9 @@ dependencies = [ [[package]] name = "sea-query-binder" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754965d4aee6145bec25d0898e5c931e6c22859789ce62fd85a42a15ed5a8ce3" +checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" dependencies = [ "bigdecimal", "chrono", @@ -4738,10 +4732,11 @@ dependencies = [ [[package]] name = "sea-query-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a82fcb49253abcb45cdcb2adf92956060ec0928635eb21b4f7a6d8f25ab0bc" +checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" dependencies = [ + "darling 0.20.10", "heck 0.4.1", "proc-macro2", "quote", @@ -4751,9 +4746,9 @@ dependencies = [ [[package]] name = "sea-schema" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad52149fc81836ea7424c3425d8f6ed8ad448dd16d2e4f6a3907ba46f3f2fd78" +checksum = "aab1592d17860a9a8584d9b549aebcd06f7bdc3ff615f71752486ba0b05b1e6e" dependencies = [ "futures", "sea-query", @@ -5136,6 +5131,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "snafu" @@ -5262,9 +5260,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -5275,11 +5273,10 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ - "ahash 0.8.11", "atoi", "bigdecimal", "byteorder", @@ -5288,12 +5285,13 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener 2.5.3", + "event-listener 5.3.1", "futures-channel", "futures-core", "futures-intrusive", "futures-io", "futures-util", + "hashbrown 0.14.5", "hashlink", "hex", "indexmap 2.2.6", @@ -5303,8 +5301,8 @@ dependencies = [ "paste", "percent-encoding", "rust_decimal", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls 0.23.15", + "rustls-pemfile 2.1.2", "serde", "serde_json", "sha2", @@ -5317,31 +5315,31 @@ dependencies = [ "tracing", "url", "uuid", - "webpki-roots 0.25.4", + "webpki-roots 0.26.2", ] [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.66", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", - "heck 0.4.1", + "heck 0.5.0", "hex", "once_cell", "proc-macro2", @@ -5353,7 +5351,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.66", "tempfile", "tokio", "url", @@ -5361,12 +5359,12 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bigdecimal", "bitflags 2.5.0", "byteorder", @@ -5408,12 +5406,12 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bigdecimal", "bitflags 2.5.0", "byteorder", @@ -5452,9 +5450,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "chrono", @@ -5468,11 +5466,11 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", "time", "tracing", "url", - "urlencoding", "uuid", ] @@ -5812,7 +5810,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.10", + "rustls 0.23.15", "rustls-pki-types", "tokio", ] @@ -6436,6 +6434,30 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "utoipa" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c24e8ab68ff9ee746aad22d39b5535601e6416d1b0feeabf78be986a5c4392" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "uuid" version = "1.10.0" @@ -6908,6 +6930,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yoke" version = "0.7.4" diff --git a/examples/demo/Cargo.toml b/examples/demo/Cargo.toml index 164cf4f33..802c74735 100644 --- a/examples/demo/Cargo.toml +++ b/examples/demo/Cargo.toml @@ -22,7 +22,7 @@ async-trait = "0.1.74" tracing = "0.1.40" chrono = "0.4" validator = { version = "0.18" } -sea-orm = { version = "1.0.0", features = [ +sea-orm = { version = "1.1.0", features = [ "sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", @@ -42,6 +42,7 @@ unic-langid = "0.9.4" tera = "1.19.1" tower = "0.4.13" futures-util = "0.3.30" +utoipa = "4.2.3" [[bin]] name = "demo_app-cli" diff --git a/examples/demo/README.md b/examples/demo/README.md new file mode 100644 index 000000000..52561c753 --- /dev/null +++ b/examples/demo/README.md @@ -0,0 +1,9 @@ +# Demo + +This app is a kitchensink for various capabilities and examples of the [Loco](https://loco.rs) project. + +# Example Listings + +## OpenAPI with `utoipa` + +See [src/controllers/responses.rs](src/controllers/responses.rs) diff --git a/examples/demo/examples/start.rs b/examples/demo/examples/start.rs index fc5a0f250..a14250e6d 100644 --- a/examples/demo/examples/start.rs +++ b/examples/demo/examples/start.rs @@ -14,6 +14,6 @@ async fn main() -> loco_rs::Result<()> { port: boot_result.app_context.config.server.port, binding: boot_result.app_context.config.server.binding.to_string(), }; - start::(boot_result, serve_params).await?; + start::(boot_result, serve_params, false).await?; Ok(()) } diff --git a/examples/demo/examples/workers.rs b/examples/demo/examples/workers.rs index 23ccdb78c..ce19ffbf6 100644 --- a/examples/demo/examples/workers.rs +++ b/examples/demo/examples/workers.rs @@ -14,6 +14,6 @@ async fn main() -> loco_rs::Result<()> { port: boot_result.app_context.config.server.port, binding: boot_result.app_context.config.server.binding.to_string(), }; - start::(boot_result, serve_params).await?; + start::(boot_result, serve_params, false).await?; Ok(()) } diff --git a/examples/demo/src/controllers/responses.rs b/examples/demo/src/controllers/responses.rs index bb558309b..43e0ea505 100644 --- a/examples/demo/src/controllers/responses.rs +++ b/examples/demo/src/controllers/responses.rs @@ -2,6 +2,7 @@ use axum_extra::extract::cookie::Cookie; use loco_rs::prelude::*; use serde::Serialize; +use utoipa::{openapi, OpenApi, ToSchema}; #[derive(Serialize)] pub struct Health { @@ -97,6 +98,39 @@ pub async fn set_cookie() -> Result { format::render().cookies(&[cookie])?.json(()) } +#[derive(Serialize, Debug, ToSchema)] +pub struct Album { + title: String, + rating: u32, +} + +// +// OpenAPI spec with `utoipa` +// +#[derive(OpenApi)] +#[openapi(paths(album))] +struct Spec; + +/// Return an OpenAPI-spec'd response +/// +/// # Errors +/// +/// This function will return an error if it fails +#[utoipa::path( + get, + path = "/response/album", + responses( + (status = 200, description = "Album found", body = Album), + ), +)] +pub async fn album() -> Result { + println!("{}", Spec::openapi().to_pretty_json().unwrap()); + + format::json(Album { + title: "VH II".to_string(), + rating: 10, + }) +} pub fn routes() -> Routes { Routes::new() .prefix("response") @@ -108,5 +142,6 @@ pub fn routes() -> Routes { .add("/redirect", get(redirect)) .add("/render_with_status_code", get(render_with_status_code)) .add("/etag", get(etag)) + .add("/album", get(album)) .add("/set_cookie", get(set_cookie)) } diff --git a/examples/demo/src/models/users.rs b/examples/demo/src/models/users.rs index 40e35678d..bd2e3f2c3 100644 --- a/examples/demo/src/models/users.rs +++ b/examples/demo/src/models/users.rs @@ -112,7 +112,7 @@ impl super::_entities::users::Model { user.ok_or_else(|| ModelError::EntityNotFound) } - /// /// finds a user by the provided reset token + /// finds a user by the provided reset token /// /// # Errors /// @@ -286,7 +286,8 @@ impl super::_entities::users::ActiveModel { /// updates it in the database. /// /// This method hashes the provided password and sets it as the new password - /// for the user. + /// for the user. + /// /// # Errors /// /// when has DB query error or could not hashed the given password diff --git a/examples/demo/tests/cmd/cli.trycmd b/examples/demo/tests/cmd/cli.trycmd index a054f00a4..035e830b2 100644 --- a/examples/demo/tests/cmd/cli.trycmd +++ b/examples/demo/tests/cmd/cli.trycmd @@ -104,6 +104,7 @@ $ demo_app-cli routes --environment test [GET] /notes/:id [DELETE] /notes/:id [POST] /notes/:id +[GET] /response/album [GET] /response/empty [GET] /response/empty_json [GET] /response/etag diff --git a/loco-cli/src/generate.rs b/loco-cli/src/generate.rs index 72bcd5ba6..7a9dd040a 100644 --- a/loco-cli/src/generate.rs +++ b/loco-cli/src/generate.rs @@ -161,11 +161,12 @@ pub struct TemplateRule { } /// Collects template configurations from files named [`GENERATOR_FILE_NAME`] -/// within the root level directories in the provided path. This function -/// gracefully handles any issues related to the existence or format of the -/// generator files, allowing the code to skip problematic starter templates -/// without returning an error. This approach is designed to avoid negatively -/// impacting users due to faulty template configurations. +/// within the root level directories in the provided path. +/// +/// This function gracefully handles any issues related to the existence or +/// format of the generator files, allowing the code to skip problematic starter +/// templates without returning an error. This approach is designed to avoid +/// negatively impacting users due to faulty template configurations. /// /// # Errors /// The code should returns an error only when could get folder collections. diff --git a/snipdoc.yml b/snipdoc.yml index 010dc5f2d..dbe9c2ff1 100644 --- a/snipdoc.yml +++ b/snipdoc.yml @@ -94,7 +94,7 @@ snippets: path: ./snipdoc.yml scaffold-post-command: content: cargo loco generate scaffold posts - name:string title:string content:text + name:string title:string content:text --api path: ./snipdoc.yml generate-task-help-command: content: cd ./examples/demo && cargo loco generate task --help diff --git a/src/app.rs b/src/app.rs index 976e9bcc9..f9d0206b7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -16,7 +16,7 @@ use axum::Router as AxumRouter; use crate::controller::channels::AppChannels; use crate::{ bgworker::{self, Queue}, - boot::{BootResult, ServeParams, StartMode}, + boot::{shutdown_signal, BootResult, StartMode}, cache::{self}, config::{self, Config}, controller::{ @@ -63,7 +63,7 @@ pub struct AppContext { /// the application's routing, worker connections, task registration, and /// database actions according to their specific requirements and use cases. #[async_trait] -pub trait Hooks { +pub trait Hooks: Send { /// Defines the composite app version #[must_use] fn app_version() -> String { @@ -111,17 +111,23 @@ pub trait Hooks { /// /// # Returns /// A Result indicating success () or an error if the server fails to start. - async fn serve(app: AxumRouter, server_config: ServeParams) -> Result<()> { + async fn serve(app: AxumRouter, ctx: &AppContext) -> Result<()> { let listener = tokio::net::TcpListener::bind(&format!( "{}:{}", - server_config.binding, server_config.port + ctx.config.server.binding, ctx.config.server.port )) .await?; + let cloned_ctx = ctx.clone(); axum::serve( listener, app.into_make_service_with_connect_info::(), ) + .with_graceful_shutdown(async move { + shutdown_signal().await; + tracing::info!("shutting down..."); + Self::on_shutdown(&cloned_ctx).await; + }) .await?; Ok(()) @@ -208,6 +214,11 @@ pub trait Hooks { /// Seeds the database with initial data. #[cfg(feature = "with-db")] async fn seed(db: &DatabaseConnection, path: &Path) -> Result<()>; + + /// Called when the application is shutting down. + /// This function allows users to perform any necessary cleanup or final + /// actions before the application stops completely. + async fn on_shutdown(_ctx: &AppContext) {} } /// An initializer. diff --git a/src/auth/jwt.rs b/src/auth/jwt.rs index a32c424b8..88effa4a8 100644 --- a/src/auth/jwt.rs +++ b/src/auth/jwt.rs @@ -17,7 +17,7 @@ const JWT_ALGORITHM: Algorithm = Algorithm::HS512; #[derive(Debug, Serialize, Deserialize)] pub struct UserClaims { pub pid: String, - exp: usize, + exp: u64, claims: Option, } @@ -29,6 +29,7 @@ pub struct UserClaims { /// /// auth::jwt::JWT::new("PqRwLF2rhHe8J22oBeHy"); /// ``` +#[derive(Debug)] pub struct JWT { secret: String, algorithm: Algorithm, @@ -70,8 +71,7 @@ impl JWT { pid: String, claims: Option, ) -> JWTResult { - #[allow(clippy::cast_possible_truncation)] - let exp = (get_current_timestamp() + expiration) as usize; + let exp = get_current_timestamp().saturating_add(*expiration); let claims = UserClaims { pid, exp, claims }; diff --git a/src/banner.rs b/src/banner.rs index c26fe0223..924be70dd 100644 --- a/src/banner.rs +++ b/src/banner.rs @@ -70,7 +70,7 @@ pub fn print_banner(boot_result: &BootResult, server_config: &ServeParams) { if boot_result.router.is_some() { modes.push("server".green()); servingline.push(format!( - "listening on {}:{}", + "listening on http://{}:{}", server_config.binding.to_string().green(), server_config.port.to_string().green() )); diff --git a/src/bgworker/mod.rs b/src/bgworker/mod.rs index d32c23be7..8a1e0a199 100644 --- a/src/bgworker/mod.rs +++ b/src/bgworker/mod.rs @@ -273,6 +273,7 @@ pub async fn converge(queue: &Queue, config: &QueueConfig) -> Result<()> { dangerously_flush, uri: _, queues: _, + num_workers: _, }) => { if *dangerously_flush { queue.clear().await?; diff --git a/src/bgworker/pg.rs b/src/bgworker/pg.rs index b4ef06092..786acbd90 100644 --- a/src/bgworker/pg.rs +++ b/src/bgworker/pg.rs @@ -327,6 +327,7 @@ pub async fn ping(pool: &PgPool) -> Result<()> { Ok(()) } +#[derive(Debug)] pub struct RunOpts { pub num_workers: u32, pub poll_interval_sec: u32, diff --git a/src/bgworker/skq.rs b/src/bgworker/skq.rs index 9d883cda0..280c328e6 100644 --- a/src/bgworker/skq.rs +++ b/src/bgworker/skq.rs @@ -1,13 +1,13 @@ use std::{marker::PhantomData, sync::Arc}; -use async_trait::async_trait; -use bb8::Pool; -use sidekiq::{Processor, RedisConnectionManager}; - use super::{BackgroundWorker, Queue}; use crate::{config::RedisQueueConfig, Result}; +use async_trait::async_trait; +use bb8::Pool; +use sidekiq::{Processor, ProcessorConfig, RedisConnectionManager}; pub type RedisPool = Pool; +#[derive(Debug)] pub struct SidekiqBackgroundWorker { pub inner: W, // Now we store the worker with its actual type instead of a trait object _phantom: PhantomData, @@ -119,7 +119,10 @@ pub async fn create_provider(qcfg: &RedisQueueConfig) -> Result { let queues = get_queues(&qcfg.queues); Ok(Queue::Redis( redis.clone(), - Arc::new(tokio::sync::Mutex::new(Processor::new(redis, queues))), + Arc::new(tokio::sync::Mutex::new( + Processor::new(redis, queues) + .with_config(ProcessorConfig::default().num_workers(qcfg.num_workers as usize)), + )), )) } diff --git a/src/boot.rs b/src/boot.rs index 236f38043..f93cdba96 100644 --- a/src/boot.rs +++ b/src/boot.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use axum::Router; #[cfg(feature = "with-db")] use sea_orm_migration::MigratorTrait; +use tokio::signal; use tracing::{debug, error, info, warn}; #[cfg(feature = "with-db")] @@ -14,7 +15,7 @@ use crate::{ app::{AppContext, Hooks}, banner::print_banner, bgworker, cache, - config::{self}, + config::{self, WorkerMode}, controller::ListRoutes, environment::Environment, errors::Error, @@ -27,6 +28,7 @@ use crate::{ }; /// Represents the application startup mode. +#[derive(Debug)] pub enum StartMode { /// Run the application as a server only. when running web server only, /// workers job will not handle. @@ -36,6 +38,7 @@ pub enum StartMode { /// Pulling job worker and execute them WorkerOnly, } + pub struct BootResult { /// Application Context pub app_context: AppContext, @@ -46,6 +49,7 @@ pub struct BootResult { } /// Configuration structure for serving an application. +#[derive(Debug)] pub struct ServeParams { /// The port number on which the server will listen for incoming /// connections. @@ -63,8 +67,14 @@ pub struct ServeParams { /// # Errors /// /// When could not initialize the application. -pub async fn start(boot: BootResult, server_config: ServeParams) -> Result<()> { - print_banner(&boot, &server_config); +pub async fn start( + boot: BootResult, + server_config: ServeParams, + no_banner: bool, +) -> Result<()> { + if !no_banner { + print_banner(&boot, &server_config); + } let BootResult { router, @@ -74,27 +84,28 @@ pub async fn start(boot: BootResult, server_config: ServeParams) -> Re match (router, run_worker) { (Some(router), false) => { - H::serve(router, server_config).await?; + H::serve(router, &app_context).await?; } (Some(router), true) => { - tokio::spawn(async move { - debug!("note: worker is run in-process (tokio spawn)"); + debug!("note: worker is run in-process (tokio spawn)"); + if app_context.config.workers.mode == WorkerMode::BackgroundQueue { if let Some(queue) = &app_context.queue_provider { - let res = queue.run().await; - if res.is_err() { - error!( - err = res.unwrap_err().to_string(), - "error while running worker" - ); - } + let cloned_queue = queue.clone(); + tokio::spawn(async move { + let res = cloned_queue.run().await; + if res.is_err() { + error!( + err = res.unwrap_err().to_string(), + "error while running worker" + ); + } + }); } else { - error!( - err = Error::QueueProviderMissing.to_string(), - "cannot start worker" - ); + return Err(Error::QueueProviderMissing); } - }); - H::serve(router, server_config).await?; + } + + H::serve(router, &app_context).await?; } (None, true) => { if let Some(queue) = &app_context.queue_provider { @@ -364,14 +375,16 @@ pub async fn run_app(mode: &StartMode, app_context: AppContext) -> Res } async fn register_workers(app_context: &AppContext) -> Result<()> { - if let Some(queue) = &app_context.queue_provider { - queue.register(MailerWorker::build(app_context)).await?; - H::connect_workers(app_context, queue).await?; - } else { - return Err(Error::QueueProviderMissing); - } + if app_context.config.workers.mode == WorkerMode::BackgroundQueue { + if let Some(queue) = &app_context.queue_provider { + queue.register(MailerWorker::build(app_context)).await?; + H::connect_workers(app_context, queue).await?; + } else { + return Err(Error::QueueProviderMissing); + } - debug!("done registering workers and queues"); + debug!("done registering workers and queues"); + } Ok(()) } @@ -380,6 +393,36 @@ pub fn list_endpoints(ctx: &AppContext) -> Vec { H::routes(ctx).collect() } +/// Waits for a shutdown signal, either via Ctrl+C or termination signal. +/// +/// # Panics +/// +/// This function will panic if it fails to install the signal handlers for +/// Ctrl+C or the terminate signal on Unix-based systems. +pub async fn shutdown_signal() { + let ctrl_c = async { + signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + }; + + #[cfg(unix)] + let terminate = async { + signal::unix::signal(signal::unix::SignalKind::terminate()) + .expect("failed to install signal handler") + .recv() + .await; + }; + + #[cfg(not(unix))] + let terminate = std::future::pending::<()>(); + + tokio::select! { + () = ctrl_c => {}, + () = terminate => {}, + } +} + pub struct MiddlewareInfo { pub id: String, pub enabled: bool, diff --git a/src/cache/drivers/inmem.rs b/src/cache/drivers/inmem.rs index 741b9644a..9664d99bd 100644 --- a/src/cache/drivers/inmem.rs +++ b/src/cache/drivers/inmem.rs @@ -22,6 +22,7 @@ pub fn new() -> Box { } /// Represents the in-memory cache driver. +#[derive(Debug)] pub struct Inmem { cache: Cache, } diff --git a/src/cache/drivers/null.rs b/src/cache/drivers/null.rs index 9eef456c2..26a52971c 100644 --- a/src/cache/drivers/null.rs +++ b/src/cache/drivers/null.rs @@ -10,6 +10,7 @@ use super::CacheDriver; use crate::cache::{CacheError, CacheResult}; /// Represents the in-memory cache driver. +#[derive(Debug)] pub struct Null {} /// Creates a new null cache instance diff --git a/src/cli.rs b/src/cli.rs index fa3b7b19e..28a6b80c8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -26,7 +26,7 @@ cfg_if::cfg_if! { use std::path::PathBuf; -use clap::{Parser, Subcommand}; +use clap::{ArgAction, Parser, Subcommand}; use duct::cmd; use crate::{ @@ -77,6 +77,9 @@ enum Commands { /// server port address #[arg(short, long, action)] port: Option, + /// disable the banner display + #[arg(short, long, action = ArgAction::SetTrue)] + no_banner: bool, }, #[cfg(feature = "with-db")] /// Perform DB operations @@ -443,6 +446,7 @@ pub async fn main() -> crate::Result<()> { server_and_worker, binding, port, + no_banner, } => { let start_mode = if worker { StartMode::WorkerOnly @@ -458,7 +462,7 @@ pub async fn main() -> crate::Result<()> { binding: binding .unwrap_or_else(|| boot_result.app_context.config.server.binding.to_string()), }; - start::(boot_result, serve_params).await?; + start::(boot_result, serve_params, no_banner).await?; } #[cfg(feature = "with-db")] Commands::Db { command } => { @@ -577,6 +581,7 @@ pub async fn main() -> crate::Result<()> { server_and_worker, binding, port, + no_banner, } => { let start_mode = if worker { StartMode::WorkerOnly @@ -594,7 +599,7 @@ pub async fn main() -> crate::Result<()> { |b| b, ), }; - start::(boot_result, serve_params).await?; + start::(boot_result, serve_params, no_banner).await?; } Commands::Routes {} => { let app_context = create_context::(&environment).await?; diff --git a/src/config.rs b/src/config.rs index 77d781120..0b5322e31 100644 --- a/src/config.rs +++ b/src/config.rs @@ -237,6 +237,9 @@ pub struct RedisQueueConfig { /// Custom queue names declaration. Useful to model priority queues. /// First queue in list is more important. pub queues: Option>, + + #[serde(default = "num_workers")] + pub num_workers: u32, } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -264,7 +267,7 @@ pub struct PostgresQueueConfig { #[serde(default = "pgq_poll_interval")] pub poll_interval_sec: u32, - #[serde(default = "pgq_num_workers")] + #[serde(default = "num_workers")] pub num_workers: u32, } @@ -288,7 +291,7 @@ fn pgq_poll_interval() -> u32 { 1 } -fn pgq_num_workers() -> u32 { +fn num_workers() -> u32 { 2 } diff --git a/src/controller/app_routes.rs b/src/controller/app_routes.rs index 20b2481ad..5031aaaeb 100644 --- a/src/controller/app_routes.rs +++ b/src/controller/app_routes.rs @@ -29,6 +29,7 @@ pub struct AppRoutes { channels: Option, } +#[derive(Debug)] pub struct ListRoutes { pub uri: String, pub actions: Vec, diff --git a/src/controller/format.rs b/src/controller/format.rs index 8acb70382..5d7afa37e 100644 --- a/src/controller/format.rs +++ b/src/controller/format.rs @@ -186,6 +186,7 @@ where html(&views::template(template, data)?) } +#[derive(Debug)] pub struct RenderBuilder { response: Builder, } diff --git a/src/controller/middleware/_archive/content_etag.rs b/src/controller/middleware/_archive/content_etag.rs index d245b90d7..2728812b4 100644 --- a/src/controller/middleware/_archive/content_etag.rs +++ b/src/controller/middleware/_archive/content_etag.rs @@ -14,7 +14,7 @@ use hyper::header::{ETAG, IF_NONE_MATCH}; use sha2::{Digest, Sha256}; use tower::{Layer, Service}; // Corrected import -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct EtagLayer; impl EtagLayer { @@ -30,7 +30,7 @@ impl Layer for EtagLayer { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct EtagMiddleware { inner: S, } diff --git a/src/controller/middleware/fallback.rs b/src/controller/middleware/fallback.rs index 0ef7faf19..4e1f6dad8 100644 --- a/src/controller/middleware/fallback.rs +++ b/src/controller/middleware/fallback.rs @@ -11,6 +11,7 @@ use tower_http::services::ServeFile; use crate::{app::AppContext, controller::middleware::MiddlewareLayer, Result}; +#[derive(Debug)] pub struct StatusCodeWrapper(pub StatusCode); #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/src/controller/middleware/logger.rs b/src/controller/middleware/logger.rs index 6f30b16b6..9041f327b 100644 --- a/src/controller/middleware/logger.rs +++ b/src/controller/middleware/logger.rs @@ -25,7 +25,7 @@ pub struct Config { } /// [`Middleware`] struct responsible for logging HTTP requests. -#[derive(Serialize)] +#[derive(Serialize, Debug)] pub struct Middleware { config: Config, environment: Environment, diff --git a/src/controller/middleware/powered_by.rs b/src/controller/middleware/powered_by.rs index 3dd5ffdc3..927fc0128 100644 --- a/src/controller/middleware/powered_by.rs +++ b/src/controller/middleware/powered_by.rs @@ -18,6 +18,7 @@ lazy_static::lazy_static! { } /// [`Middleware`] struct responsible for managing the identifier value for the `X-Powered-By` header. +#[derive(Debug)] pub struct Middleware { ident: Option, } diff --git a/src/controller/middleware/remote_ip.rs b/src/controller/middleware/remote_ip.rs index b0fbf18d8..a4a71bf95 100644 --- a/src/controller/middleware/remote_ip.rs +++ b/src/controller/middleware/remote_ip.rs @@ -207,7 +207,7 @@ impl fmt::Display for RemoteIP { } } -#[derive(Clone)] +#[derive(Clone, Debug)] struct RemoteIPLayer { trusted_proxies: Option>, } @@ -252,7 +252,7 @@ impl Layer for RemoteIPLayer { } /// Remote IP Detection Middleware -#[derive(Clone)] +#[derive(Clone, Debug)] #[must_use] pub struct RemoteIPMiddleware { inner: S, diff --git a/src/controller/middleware/request_id.rs b/src/controller/middleware/request_id.rs index aab60f54a..eb548d10f 100644 --- a/src/controller/middleware/request_id.rs +++ b/src/controller/middleware/request_id.rs @@ -1,4 +1,5 @@ //! Middleware to generate or ensure a unique request ID for every request. +//! //! The request ID is stored in the `x-request-id` header, and it is either //! generated or sanitized if already present in the request. //! diff --git a/src/controller/middleware/secure_headers.rs b/src/controller/middleware/secure_headers.rs index bbdbe26c7..8fdda57bc 100644 --- a/src/controller/middleware/secure_headers.rs +++ b/src/controller/middleware/secure_headers.rs @@ -1,4 +1,5 @@ //! Sets secure headers for your backend to promote security-by-default. +//! //! This middleware applies secure HTTP headers, providing pre-defined presets //! (e.g., "github") and the ability to override or define custom headers. @@ -156,7 +157,7 @@ impl SecureHeader { /// The [`SecureHeaders`] layer which wraps around the service and injects /// security headers -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct SecureHeaders { headers: Vec<(HeaderName, HeaderValue)>, } @@ -187,7 +188,7 @@ impl Layer for SecureHeaders { } /// The secure headers middleware -#[derive(Clone)] +#[derive(Clone, Debug)] #[must_use] pub struct SecureHeadersMiddleware { inner: S, diff --git a/src/controller/routes.rs b/src/controller/routes.rs index 32da70207..fc482e739 100644 --- a/src/controller/routes.rs +++ b/src/controller/routes.rs @@ -5,14 +5,14 @@ use tower::{Layer, Service}; use super::describe; use crate::app::AppContext; -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] pub struct Routes { pub prefix: Option, pub handlers: Vec, // pub version: Option, } -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] pub struct Handler { pub uri: String, pub method: axum::routing::MethodRouter, diff --git a/src/db.rs b/src/db.rs index 77c12d1b2..781fd7d54 100644 --- a/src/db.rs +++ b/src/db.rs @@ -32,7 +32,7 @@ lazy_static! { pub static ref EXTRACT_DB_NAME: Regex = Regex::new(r"/([^/]+)$").unwrap(); } -#[derive(Default, Clone)] +#[derive(Default, Clone, Debug)] pub struct MultiDb { pub db: HashMap, } @@ -143,7 +143,24 @@ pub async fn connect(config: &config::Database) -> Result), @@ -23,7 +23,7 @@ pub enum EmailTransport { /// A structure representing the email sender, encapsulating the chosen /// transport method. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct EmailSender { pub transport: EmailTransport, } diff --git a/src/mailer/mod.rs b/src/mailer/mod.rs index 4b273e611..622a028ce 100644 --- a/src/mailer/mod.rs +++ b/src/mailer/mod.rs @@ -51,7 +51,7 @@ pub struct Email { } /// The options struct for configuring the email sender. -#[derive(Default)] +#[derive(Default, Debug)] #[allow(clippy::module_name_repetitions)] pub struct MailerOpts { pub from: String, diff --git a/src/model/query/dsl/date_range.rs b/src/model/query/dsl/date_range.rs index 1887cdc19..f8d48db55 100644 --- a/src/model/query/dsl/date_range.rs +++ b/src/model/query/dsl/date_range.rs @@ -2,6 +2,8 @@ use chrono::NaiveDateTime; use sea_orm::ColumnTrait; use super::{with, ConditionBuilder}; + +#[derive(Debug)] pub struct DateRangeBuilder { col: T, condition_builder: ConditionBuilder, diff --git a/src/model/query/dsl/mod.rs b/src/model/query/dsl/mod.rs index d1d48d165..f354dbdab 100644 --- a/src/model/query/dsl/mod.rs +++ b/src/model/query/dsl/mod.rs @@ -8,6 +8,7 @@ mod date_range; // pub mod pagination; +#[derive(Debug)] pub struct ConditionBuilder { condition: Condition, } diff --git a/src/scheduler.rs b/src/scheduler.rs index f98909f3c..f4caab4b9 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -110,7 +110,7 @@ impl fmt::Display for Scheduler { } /// Representing the scheduler itself. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Scheduler { pub jobs: HashMap, binary_path: PathBuf, @@ -119,6 +119,7 @@ pub struct Scheduler { } /// Specification used to filter all scheduler job with the given Spec. +#[derive(Debug)] pub struct Spec { pub name: Option, pub tag: Option, diff --git a/src/storage/contents.rs b/src/storage/contents.rs index a494a4a37..f33f63c95 100644 --- a/src/storage/contents.rs +++ b/src/storage/contents.rs @@ -1,5 +1,6 @@ use bytes::Bytes; +#[derive(Debug)] pub struct Contents { data: Bytes, } diff --git a/src/storage/drivers/aws.rs b/src/storage/drivers/aws.rs index 024d9e028..5cc2be526 100644 --- a/src/storage/drivers/aws.rs +++ b/src/storage/drivers/aws.rs @@ -13,6 +13,7 @@ use super::{object_store_adapter::ObjectStoreAdapter, StoreDriver}; use crate::Result; /// A set of AWS security credentials +#[derive(Debug)] pub struct Credential { /// `AWS_ACCESS_KEY_ID` pub key_id: String, diff --git a/src/storage/drivers/mod.rs b/src/storage/drivers/mod.rs index 3cdb6b367..7d2ecfe3f 100644 --- a/src/storage/drivers/mod.rs +++ b/src/storage/drivers/mod.rs @@ -14,6 +14,8 @@ pub mod null; pub mod object_store_adapter; use super::StorageResult; + +#[derive(Debug)] pub struct UploadResponse { pub e_tag: Option, pub version: Option, diff --git a/src/storage/strategies/backup.rs b/src/storage/strategies/backup.rs index e44d19b46..d53e84c8a 100644 --- a/src/storage/strategies/backup.rs +++ b/src/storage/strategies/backup.rs @@ -28,7 +28,7 @@ use bytes::Bytes; use crate::storage::{strategies::StorageStrategy, Storage, StorageError, StorageResult}; /// Enum representing the failure mode for the [`BackupStrategy`]. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum FailureMode { /// Fail if any secondary storage backend encounters an error. BackupAll, diff --git a/src/storage/strategies/mirror.rs b/src/storage/strategies/mirror.rs index 378a62d40..ff30286ba 100644 --- a/src/storage/strategies/mirror.rs +++ b/src/storage/strategies/mirror.rs @@ -27,7 +27,7 @@ use bytes::Bytes; use crate::storage::{strategies::StorageStrategy, Storage, StorageError, StorageResult}; /// Enum representing the failure mode for the [`MirrorStrategy`]. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum FailureMode { /// Fail if any secondary storage mirror encounters an error. MirrorAll, @@ -36,7 +36,7 @@ pub enum FailureMode { } /// Represents the Mirror Strategy for storage operations. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct MirrorStrategy { /// The primary storage backend. pub primary: String, diff --git a/src/task.rs b/src/task.rs index 3da449ee3..866bd2d0f 100644 --- a/src/task.rs +++ b/src/task.rs @@ -64,6 +64,7 @@ impl Vars { /// Information about a task, including its name and details. #[allow(clippy::module_name_repetitions)] +#[derive(Debug)] pub struct TaskInfo { pub name: String, pub detail: String, diff --git a/src/tests_cfg/config.rs b/src/tests_cfg/config.rs index 562e915f9..e27ab38a3 100644 --- a/src/tests_cfg/config.rs +++ b/src/tests_cfg/config.rs @@ -19,7 +19,7 @@ pub fn test_config() -> Config { }, server: config::Server { binding: "localhost".to_string(), - port: 3000, + port: 5555, host: "localhost".to_string(), ident: None, middlewares: middleware::Config::default(), diff --git a/src/tests_cfg/db.rs b/src/tests_cfg/db.rs index df1657871..a609b4420 100644 --- a/src/tests_cfg/db.rs +++ b/src/tests_cfg/db.rs @@ -70,6 +70,7 @@ pub mod test_db { impl ActiveModelBehavior for ActiveModel {} } +#[derive(Debug)] pub struct Migrator; #[async_trait::async_trait] @@ -79,6 +80,7 @@ impl MigratorTrait for Migrator { } } +#[derive(Debug)] pub struct AppHook; #[async_trait] impl Hooks for AppHook { diff --git a/src/tests_cfg/task.rs b/src/tests_cfg/task.rs index 03d05aa61..68a026a39 100644 --- a/src/tests_cfg/task.rs +++ b/src/tests_cfg/task.rs @@ -1,6 +1,8 @@ use crate::prelude::*; +#[derive(Debug)] pub struct Foo; + #[async_trait] impl Task for Foo { fn task(&self) -> TaskInfo { @@ -15,7 +17,9 @@ impl Task for Foo { } } +#[derive(Debug)] pub struct ParseArgs; + #[async_trait] impl Task for ParseArgs { fn task(&self) -> TaskInfo { diff --git a/src/validation.rs b/src/validation.rs index af20ab9c7..5d7f63388 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -66,12 +66,14 @@ pub fn is_valid_email(email: &str) -> Result<(), ValidationError> { /// /// /// -/// /// Convert `ModelValidationErrors` (pretty) into a `DbErr` (ugly) for database -/// handling. Because `DbErr` is used in model hooks and we implement the hooks +/// handling. +/// +/// Because `DbErr` is used in model hooks and we implement the hooks /// in the trait, we MUST use `DbErr`, so we need to "hide" a _representation_ /// of the error in `DbErr::Custom`, so that it can be unpacked later down the /// stream, in the central error response handler. +#[derive(Debug)] pub struct ModelValidationErrors(pub ValidationErrors); #[cfg(feature = "with-db")] diff --git a/starters/lightweight-service/Cargo.lock b/starters/lightweight-service/Cargo.lock index 43d503eef..7e2d1bfa7 100644 --- a/starters/lightweight-service/Cargo.lock +++ b/starters/lightweight-service/Cargo.lock @@ -1418,7 +1418,7 @@ dependencies = [ [[package]] name = "loco-rs" -version = "0.10.1" +version = "0.11.0" dependencies = [ "argon2", "async-trait", diff --git a/starters/lightweight-service/Cargo.toml b/starters/lightweight-service/Cargo.toml index 861062bba..e5ee0e1c7 100644 --- a/starters/lightweight-service/Cargo.toml +++ b/starters/lightweight-service/Cargo.toml @@ -11,7 +11,7 @@ default-run = "loco_starter_template-cli" [dependencies] -loco-rs = { version = "0.10.1", default-features = false, features = ["cli"] } +loco-rs = { version = "0.11.0", default-features = false, features = ["cli"] } serde = "1" serde_json = "1" tokio = { version = "1.33.0", default-features = false, features = [ @@ -35,7 +35,7 @@ required-features = [] [dev-dependencies] serial_test = "3.1.1" rstest = "0.21.0" -loco-rs = { version = "0.10.1", default-features = false, features = [ +loco-rs = { version = "0.11.0", default-features = false, features = [ "testing", "cli", ] } diff --git a/starters/lightweight-service/README.md b/starters/lightweight-service/README.md index 302acc3e6..371621bf0 100644 --- a/starters/lightweight-service/README.md +++ b/starters/lightweight-service/README.md @@ -42,7 +42,7 @@ environment: development compilation: debug modes: server -listening on localhost:5150 +listening on http://localhost:5150 ``` ## Getting help diff --git a/starters/rest-api/Cargo.lock b/starters/rest-api/Cargo.lock index b30a8dd9a..6007062f0 100644 --- a/starters/rest-api/Cargo.lock +++ b/starters/rest-api/Cargo.lock @@ -35,7 +35,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", "once_cell", "version_check", "zerocopy", @@ -583,13 +582,16 @@ dependencies = [ [[package]] name = "bigdecimal" -version = "0.3.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" dependencies = [ + "autocfg", + "libm", "num-bigint", "num-integer", "num-traits", + "serde", ] [[package]] @@ -960,6 +962,15 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.18.1" @@ -1236,18 +1247,6 @@ dependencies = [ "duct", ] -[[package]] -name = "educe" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 2.0.72", -] - [[package]] name = "either" version = "1.13.0" @@ -1289,26 +1288,6 @@ dependencies = [ "regex", ] -[[package]] -name = "enum-ordinalize" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" -dependencies = [ - "enum-ordinalize-derive", -] - -[[package]] -name = "enum-ordinalize-derive" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -1665,9 +1644,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown 0.14.5", ] @@ -1677,9 +1656,6 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] [[package]] name = "heck" @@ -2018,6 +1994,15 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -2105,13 +2090,13 @@ dependencies = [ "nom", "percent-encoding", "quoted_printable", - "rustls 0.23.12", - "rustls-pemfile 2.1.2", + "rustls", + "rustls-pemfile", "socket2 0.5.7", "tokio", "tokio-rustls", "url", - "webpki-roots 0.26.3", + "webpki-roots", ] [[package]] @@ -2138,9 +2123,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -2177,7 +2162,7 @@ dependencies = [ [[package]] name = "loco-rs" -version = "0.10.1" +version = "0.11.0" dependencies = [ "argon2", "async-trait", @@ -2493,7 +2478,7 @@ dependencies = [ "chrono", "futures", "humantime", - "itertools", + "itertools 0.13.0", "parking_lot", "percent-encoding", "snafu", @@ -2530,9 +2515,9 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.17.2" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" +checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" dependencies = [ "aliasable", "ouroboros_macro", @@ -2541,13 +2526,14 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.17.2" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" +checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" dependencies = [ "heck 0.4.1", - "proc-macro-error", + "itertools 0.12.1", "proc-macro2", + "proc-macro2-diagnostics", "quote", "syn 2.0.72", ] @@ -2841,7 +2827,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", - "yansi", + "yansi 0.5.1", ] [[package]] @@ -2886,6 +2872,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "version_check", + "yansi 1.0.1", +] + [[package]] name = "psm" version = "0.1.21" @@ -3295,17 +3294,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "ring", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.12" @@ -3316,20 +3304,11 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.1.2" @@ -3346,16 +3325,6 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.102.6" @@ -3375,26 +3344,28 @@ checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-sidekiq" -version = "0.8.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a00db3916faeea070039864f98d4fd759d96fc07722571a4918d996fea5621" +checksum = "15544f047600b602c7b11ff7ee0882f9034f9cbe2c205693edd5615e2a6c03ee" dependencies = [ "async-trait", "bb8", "chrono", + "convert_case", "cron_clock", "gethostname", - "heck 0.4.1", "hex", "num_cpus", "rand", "redis", "serde", "serde_json", + "serial_test", "sha2", "slog-term", "thiserror", "tokio", + "tokio-util", "tracing", "tracing-subscriber", ] @@ -3429,16 +3400,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sdd" version = "1.7.0" @@ -3460,9 +3421,9 @@ dependencies = [ [[package]] name = "sea-orm" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d4ec1cdd8bdd3553d3c946079f58efa33fedc477f32603652652abcef96fe6" +checksum = "4c4872675cc5d5d399a2a202c60f3a393ec8d3f3307c36adb166517f348e4db5" dependencies = [ "async-stream", "async-trait", @@ -3488,9 +3449,9 @@ dependencies = [ [[package]] name = "sea-orm-cli" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d525eee597817631f800857b0c2fe8645ec9c65b4304176a44bf14b93366009e" +checksum = "0aefbd960c9ed7b2dfbab97b11890f5d8c314ad6e2f68c7b36c73ea0967fcc25" dependencies = [ "chrono", "clap", @@ -3505,9 +3466,9 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f363ead48b625a6f8f905322a820464f728fa4fe4f1c222bed5234ccf8fb8555" +checksum = "85f714906b72e7265c0b2077d0ad8f235dabebda513c92f1326d5d40cef0dd01" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -3519,9 +3480,9 @@ dependencies = [ [[package]] name = "sea-orm-migration" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df62369752f91b9295f8d71c146d84f818301a9ae7295106ebe8bbaa989a072" +checksum = "aa7bbfbe3bec60b5925193acc9c98b9f8ae9853f52c8004df0c1ea5193c01ea0" dependencies = [ "async-trait", "clap", @@ -3536,13 +3497,12 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5073b2cfed767511a57d18115f3b3d8bcb5690bf8c89518caec6cb22c0cd74" +checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb" dependencies = [ "bigdecimal", "chrono", - "educe", "inherent", "ordered-float", "rust_decimal", @@ -3554,9 +3514,9 @@ dependencies = [ [[package]] name = "sea-query-binder" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754965d4aee6145bec25d0898e5c931e6c22859789ce62fd85a42a15ed5a8ce3" +checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" dependencies = [ "bigdecimal", "chrono", @@ -3570,10 +3530,11 @@ dependencies = [ [[package]] name = "sea-query-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a82fcb49253abcb45cdcb2adf92956060ec0928635eb21b4f7a6d8f25ab0bc" +checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" dependencies = [ + "darling", "heck 0.4.1", "proc-macro2", "quote", @@ -3583,9 +3544,9 @@ dependencies = [ [[package]] name = "sea-schema" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad52149fc81836ea7424c3425d8f6ed8ad448dd16d2e4f6a3907ba46f3f2fd78" +checksum = "aab1592d17860a9a8584d9b549aebcd06f7bdc3ff615f71752486ba0b05b1e6e" dependencies = [ "futures", "sea-query", @@ -3874,6 +3835,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "snafu" @@ -3947,9 +3911,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -3960,11 +3924,10 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ - "ahash 0.8.11", "atoi", "bigdecimal", "byteorder", @@ -3973,12 +3936,13 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener 2.5.3", + "event-listener 5.3.1", "futures-channel", "futures-core", "futures-intrusive", "futures-io", "futures-util", + "hashbrown 0.14.5", "hashlink", "hex", "indexmap", @@ -3988,8 +3952,8 @@ dependencies = [ "paste", "percent-encoding", "rust_decimal", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls", + "rustls-pemfile", "serde", "serde_json", "sha2", @@ -4002,31 +3966,31 @@ dependencies = [ "tracing", "url", "uuid", - "webpki-roots 0.25.4", + "webpki-roots", ] [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", - "heck 0.4.1", + "heck 0.5.0", "hex", "once_cell", "proc-macro2", @@ -4038,7 +4002,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.72", "tempfile", "tokio", "url", @@ -4046,12 +4010,12 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bigdecimal", "bitflags 2.6.0", "byteorder", @@ -4093,12 +4057,12 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bigdecimal", "bitflags 2.6.0", "byteorder", @@ -4137,9 +4101,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "chrono", @@ -4153,11 +4117,11 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", "time", "tracing", "url", - "urlencoding", "uuid", ] @@ -4438,7 +4402,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls", "rustls-pki-types", "tokio", ] @@ -4804,12 +4768,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf8-width" version = "0.1.7" @@ -5010,12 +4968,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.3" @@ -5248,6 +5200,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/starters/rest-api/Cargo.toml b/starters/rest-api/Cargo.toml index b4b5c2a96..a3ec29c8a 100644 --- a/starters/rest-api/Cargo.toml +++ b/starters/rest-api/Cargo.toml @@ -11,7 +11,7 @@ default-run = "loco_starter_template-cli" [dependencies] -loco-rs = { version = "0.10.1" } +loco-rs = { version = "0.11.0" } migration = { path = "migration" } serde = { version = "1", features = ["derive"] } @@ -21,7 +21,7 @@ async-trait = "0.1.74" tracing = "0.1.40" chrono = "0.4" validator = { version = "0.18" } -sea-orm = { version = "1.0.0", features = [ +sea-orm = { version = "1.1.0", features = [ "sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", @@ -46,5 +46,5 @@ required-features = [] [dev-dependencies] serial_test = "3.1.1" rstest = "0.21.0" -loco-rs = { version = "0.10.1", features = ["testing"] } +loco-rs = { version = "0.11.0", features = ["testing"] } insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] } diff --git a/starters/rest-api/README.md b/starters/rest-api/README.md index 74f1ff01d..a03686582 100644 --- a/starters/rest-api/README.md +++ b/starters/rest-api/README.md @@ -43,7 +43,7 @@ environment: development compilation: debug modes: server -listening on localhost:5150 +listening on http://localhost:5150 ``` ## Getting help diff --git a/starters/rest-api/migration/Cargo.toml b/starters/rest-api/migration/Cargo.toml index bf79cfe14..839562279 100644 --- a/starters/rest-api/migration/Cargo.toml +++ b/starters/rest-api/migration/Cargo.toml @@ -10,10 +10,10 @@ path = "src/lib.rs" [dependencies] async-std = { version = "1", features = ["attributes", "tokio1"] } -loco-rs = { version = "0.10.1" } +loco-rs = { version = "0.11.0" } [dependencies.sea-orm-migration] -version = "1.0.0" +version = "1.1.0" features = [ # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. diff --git a/starters/rest-api/src/models/users.rs b/starters/rest-api/src/models/users.rs index 4189157e9..b4f3aaea0 100644 --- a/starters/rest-api/src/models/users.rs +++ b/starters/rest-api/src/models/users.rs @@ -111,7 +111,7 @@ impl super::_entities::users::Model { user.ok_or_else(|| ModelError::EntityNotFound) } - /// /// finds a user by the provided reset token + /// finds a user by the provided reset token /// /// # Errors /// @@ -279,7 +279,8 @@ impl super::_entities::users::ActiveModel { /// updates it in the database. /// /// This method hashes the provided password and sets it as the new password - /// for the user. + /// for the user. + /// /// # Errors /// /// when has DB query error or could not hashed the given password diff --git a/starters/saas/Cargo.lock b/starters/saas/Cargo.lock index e2c8fd6ea..8cee134f7 100644 --- a/starters/saas/Cargo.lock +++ b/starters/saas/Cargo.lock @@ -35,7 +35,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", "once_cell", "version_check", "zerocopy", @@ -589,13 +588,16 @@ dependencies = [ [[package]] name = "bigdecimal" -version = "0.3.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" dependencies = [ + "autocfg", + "libm", "num-bigint", "num-integer", "num-traits", + "serde", ] [[package]] @@ -966,6 +968,15 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.18.1" @@ -1259,18 +1270,6 @@ dependencies = [ "duct", ] -[[package]] -name = "educe" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 2.0.72", -] - [[package]] name = "either" version = "1.13.0" @@ -1312,26 +1311,6 @@ dependencies = [ "regex", ] -[[package]] -name = "enum-ordinalize" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" -dependencies = [ - "enum-ordinalize-derive", -] - -[[package]] -name = "enum-ordinalize-derive" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -1781,9 +1760,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown 0.14.5", ] @@ -1793,9 +1772,6 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] [[package]] name = "heck" @@ -2153,6 +2129,15 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -2240,13 +2225,13 @@ dependencies = [ "nom", "percent-encoding", "quoted_printable", - "rustls 0.23.12", - "rustls-pemfile 2.1.2", + "rustls", + "rustls-pemfile", "socket2 0.5.7", "tokio", "tokio-rustls", "url", - "webpki-roots 0.26.3", + "webpki-roots", ] [[package]] @@ -2273,9 +2258,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -2312,7 +2297,7 @@ dependencies = [ [[package]] name = "loco-rs" -version = "0.10.1" +version = "0.11.0" dependencies = [ "argon2", "async-trait", @@ -2630,7 +2615,7 @@ dependencies = [ "chrono", "futures", "humantime", - "itertools", + "itertools 0.13.0", "parking_lot", "percent-encoding", "snafu 0.8.5", @@ -2667,9 +2652,9 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.17.2" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" +checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" dependencies = [ "aliasable", "ouroboros_macro", @@ -2678,13 +2663,14 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.17.2" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" +checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" dependencies = [ "heck 0.4.1", - "proc-macro-error", + "itertools 0.12.1", "proc-macro2", + "proc-macro2-diagnostics", "quote", "syn 2.0.72", ] @@ -2978,7 +2964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", - "yansi", + "yansi 0.5.1", ] [[package]] @@ -3029,6 +3015,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "version_check", + "yansi 1.0.1", +] + [[package]] name = "psm" version = "0.1.21" @@ -3444,17 +3443,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "ring", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.12" @@ -3465,20 +3453,11 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.1.2" @@ -3495,16 +3474,6 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.102.6" @@ -3524,26 +3493,28 @@ checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-sidekiq" -version = "0.8.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a00db3916faeea070039864f98d4fd759d96fc07722571a4918d996fea5621" +checksum = "15544f047600b602c7b11ff7ee0882f9034f9cbe2c205693edd5615e2a6c03ee" dependencies = [ "async-trait", "bb8", "chrono", + "convert_case", "cron_clock", "gethostname", - "heck 0.4.1", "hex", "num_cpus", "rand", "redis", "serde", "serde_json", + "serial_test", "sha2", "slog-term", "thiserror", "tokio", + "tokio-util", "tracing", "tracing-subscriber", ] @@ -3578,16 +3549,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sdd" version = "1.7.0" @@ -3609,9 +3570,9 @@ dependencies = [ [[package]] name = "sea-orm" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d4ec1cdd8bdd3553d3c946079f58efa33fedc477f32603652652abcef96fe6" +checksum = "4c4872675cc5d5d399a2a202c60f3a393ec8d3f3307c36adb166517f348e4db5" dependencies = [ "async-stream", "async-trait", @@ -3637,9 +3598,9 @@ dependencies = [ [[package]] name = "sea-orm-cli" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d525eee597817631f800857b0c2fe8645ec9c65b4304176a44bf14b93366009e" +checksum = "0aefbd960c9ed7b2dfbab97b11890f5d8c314ad6e2f68c7b36c73ea0967fcc25" dependencies = [ "chrono", "clap", @@ -3654,9 +3615,9 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f363ead48b625a6f8f905322a820464f728fa4fe4f1c222bed5234ccf8fb8555" +checksum = "85f714906b72e7265c0b2077d0ad8f235dabebda513c92f1326d5d40cef0dd01" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -3668,9 +3629,9 @@ dependencies = [ [[package]] name = "sea-orm-migration" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df62369752f91b9295f8d71c146d84f818301a9ae7295106ebe8bbaa989a072" +checksum = "aa7bbfbe3bec60b5925193acc9c98b9f8ae9853f52c8004df0c1ea5193c01ea0" dependencies = [ "async-trait", "clap", @@ -3685,13 +3646,12 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5073b2cfed767511a57d18115f3b3d8bcb5690bf8c89518caec6cb22c0cd74" +checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb" dependencies = [ "bigdecimal", "chrono", - "educe", "inherent", "ordered-float", "rust_decimal", @@ -3703,9 +3663,9 @@ dependencies = [ [[package]] name = "sea-query-binder" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754965d4aee6145bec25d0898e5c931e6c22859789ce62fd85a42a15ed5a8ce3" +checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" dependencies = [ "bigdecimal", "chrono", @@ -3719,10 +3679,11 @@ dependencies = [ [[package]] name = "sea-query-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a82fcb49253abcb45cdcb2adf92956060ec0928635eb21b4f7a6d8f25ab0bc" +checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" dependencies = [ + "darling", "heck 0.4.1", "proc-macro2", "quote", @@ -3732,9 +3693,9 @@ dependencies = [ [[package]] name = "sea-schema" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad52149fc81836ea7424c3425d8f6ed8ad448dd16d2e4f6a3907ba46f3f2fd78" +checksum = "aab1592d17860a9a8584d9b549aebcd06f7bdc3ff615f71752486ba0b05b1e6e" dependencies = [ "futures", "sea-query", @@ -4038,6 +3999,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "snafu" @@ -4133,9 +4097,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -4146,11 +4110,10 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ - "ahash 0.8.11", "atoi", "bigdecimal", "byteorder", @@ -4159,12 +4122,13 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener 2.5.3", + "event-listener 5.3.1", "futures-channel", "futures-core", "futures-intrusive", "futures-io", "futures-util", + "hashbrown 0.14.5", "hashlink", "hex", "indexmap", @@ -4174,8 +4138,8 @@ dependencies = [ "paste", "percent-encoding", "rust_decimal", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls", + "rustls-pemfile", "serde", "serde_json", "sha2", @@ -4188,31 +4152,31 @@ dependencies = [ "tracing", "url", "uuid", - "webpki-roots 0.25.4", + "webpki-roots", ] [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", - "heck 0.4.1", + "heck 0.5.0", "hex", "once_cell", "proc-macro2", @@ -4224,7 +4188,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.72", "tempfile", "tokio", "url", @@ -4232,12 +4196,12 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bigdecimal", "bitflags 2.6.0", "byteorder", @@ -4279,12 +4243,12 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bigdecimal", "bitflags 2.6.0", "byteorder", @@ -4323,9 +4287,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "chrono", @@ -4339,11 +4303,11 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", "time", "tracing", "url", - "urlencoding", "uuid", ] @@ -4633,7 +4597,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls", "rustls-pki-types", "tokio", ] @@ -5051,12 +5015,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf8-width" version = "0.1.7" @@ -5257,12 +5215,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.3" @@ -5495,6 +5447,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/starters/saas/Cargo.toml b/starters/saas/Cargo.toml index 1711f7a90..8f63be914 100644 --- a/starters/saas/Cargo.toml +++ b/starters/saas/Cargo.toml @@ -11,7 +11,7 @@ default-run = "loco_starter_template-cli" [dependencies] -loco-rs = { version = "0.10.1" } +loco-rs = { version = "0.11.0" } migration = { path = "migration" } serde = { version = "1", features = ["derive"] } @@ -21,7 +21,7 @@ async-trait = "0.1.74" tracing = "0.1.40" chrono = "0.4" validator = { version = "0.18" } -sea-orm = { version = "1.0.0", features = [ +sea-orm = { version = "1.1.0", features = [ "sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", @@ -51,5 +51,5 @@ required-features = [] [dev-dependencies] serial_test = "3.1.1" rstest = "0.21.0" -loco-rs = { version = "0.10.1", features = ["testing"] } +loco-rs = { version = "0.11.0", features = ["testing"] } insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] } diff --git a/starters/saas/README.md b/starters/saas/README.md index 816ed4707..43b9bddaa 100644 --- a/starters/saas/README.md +++ b/starters/saas/README.md @@ -45,7 +45,7 @@ environment: development compilation: debug modes: server -listening on localhost:5150 +listening on http://localhost:5150 ``` ## Full Stack Serving diff --git a/starters/saas/frontend/package.json b/starters/saas/frontend/package.json index 294d4bbdc..dd7a791da 100644 --- a/starters/saas/frontend/package.json +++ b/starters/saas/frontend/package.json @@ -15,8 +15,8 @@ }, "devDependencies": { "@biomejs/biome": "^1", - "@rsbuild/core": "^0.7", - "@rsbuild/plugin-react": "^0.7", + "@rsbuild/core": "^1", + "@rsbuild/plugin-react": "^1", "@types/react": "^18", "@types/react-dom": "^18", "typescript": "^5" diff --git a/starters/saas/frontend/src/LocoSplash.tsx b/starters/saas/frontend/src/LocoSplash.tsx index 91e0bf54e..cb96ace54 100644 --- a/starters/saas/frontend/src/LocoSplash.tsx +++ b/starters/saas/frontend/src/LocoSplash.tsx @@ -58,11 +58,7 @@ export const LocoSplash = () => {

Loco: SaaS application

- Loco logo + Loco logo