1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
[]
= "rustango"
= "Django-shaped batteries-included web framework for Rust: ORM + migrations + auto-admin + multi-tenancy + audit log + auth (sessions, JWT, OAuth2/OIDC, HMAC) + APIs (ViewSet, OpenAPI auto-derive, JSON:API) + jobs (in-mem + Postgres) + email + media (S3 / R2 / B2 / MinIO + presigned uploads + collections + tags) + production middleware (CSRF, CSP, rate-limiting, compression, idempotency, etc.)."
= true
= true
= true
= true
= true
= true
= true
= true
= true
# Drop runnable demos + integration-test files from the published
# tarball. `src/admin/templates/` and `src/tenancy/{templates,static}/`
# stay — they're baked into the binary via include_str! / include_bytes!.
= ["examples/", "tests/"]
[]
= true
[]
# Out of the box: ORM + auto-admin + Postgres + layered config +
# public forms framework. Opt in to multi-tenancy with
# `features = ["tenancy"]`. Drop `default-features` for the bare
# ORM (core + query + sql + migrate).
= ["postgres", "manage", "admin", "config", "forms", "serializer", "cache", "signals", "email", "storage", "scheduler", "secrets", "totp", "webhook", "webhook-delivery", "api_keys", "passwords", "signed_url", "notifications", "jobs", "jobs-postgres", "auth_flows", "sse", "websocket", "oauth2", "http-client", "compression", "openapi", "csp-nonce", "sessions", "hmac-auth", "jwt", "uploads", "storage-s3", "media", "runserver"]
= ["sqlx/postgres"]
# Unified `cargo run` / `cargo run -- <verb>` dispatcher. Pulls the
# minimum axum + tokio surface so bare-API projects (without admin)
# can still use `rustango::manage::Cli::new().api(...).run().await`.
# v0.16+. Default-on so `cargo rustango new` projects work with no
# extra opt-ins.
= ["dep:axum", "dep:tokio", "runtime"]
# MySQL 8.4+ backend. Lands fully in rustango v0.23.0-batch2 (when the
# `MySqlDialect` impl + DDL writer dispatch ship); the `mysql` feature
# in v0.23.0-batch1 wires the sqlx side so apps can already opt-in.
# Trying to actually `Pool::connect("mysql://...")` in batch1 returns a
# clear "not yet implemented in this version" error — apps building
# against `mysql` ahead of batch2 get a soft-error, not a panic.
= ["sqlx/mysql"]
# SQLite 3.35+ backend. v0.27 Phase 1 ships the `Sqlite` dialect impl
# + writer support — every SQL writer in `crate::sql::writers` produces
# valid SQLite SQL through the dialect seam. Pool::Sqlite variant +
# bi-dialect macro `__rustango_from_sqlite_row` decoder land in
# subsequent phases (mirroring the v0.23 MySQL rollout); apps building
# against the `sqlite` feature today get the dialect for SQL emission +
# DDL but must execute statements through their own `sqlx::SqlitePool`
# until Phase 2 ships.
= ["sqlx/sqlite"]
# Layered TOML config (`rustango::config`). Loads `config/default.toml`
# → `config/{env}.toml` → env-var overrides. Slice 8.3.
= ["dep:toml"]
# Public forms framework (`rustango::forms`) — value parsing for HTML
# form payloads, shared between admin and user route handlers. Slice
# 8.4A ships the parsers; slice 8.4B added `#[derive(Form)]`. Slice
# 8.4C lights up CSRF protection behind the `csrf` sub-feature so
# parser-only users don't pay the cookie/rand cost.
= []
# Serializer layer (`rustango::serializer`) — `#[derive(Serializer)]` +
# `ModelSerializer` trait. Produces typed JSON output from model instances
# with field control (read_only, write_only, source, skip) and cross-field
# validation. Implies `forms` so serializer errors share `FormErrors`.
= ["forms"]
# Caching layer (`rustango::cache`) — pluggable `Cache` trait with
# `NullCache` (no-op) and `InMemoryCache` (tokio RwLock + TTL). Redis
# backend is behind the separate `cache-redis` feature.
= ["dep:async-trait", "dep:tokio"]
# Signals layer (`rustango::signals`) — Django-shape pre_save / post_save
# / pre_delete / post_delete async dispatch. Receivers register globally
# per model type; senders fire signals after write paths.
= ["dep:tokio"]
# Email backends (`rustango::email`) — Mailer trait + ConsoleMailer +
# InMemoryMailer + NullMailer. SMTP and external transports plug in via
# the trait.
= ["dep:async-trait"]
# Multi-channel notifications layer (`rustango::notifications`) — Laravel-shape
# fan-out across mail / database / log / broadcast. Implies email + cache.
= ["email", "cache"]
# Background job queue (`rustango::jobs`) — Job trait, in-memory queue,
# worker pool, retry with exponential backoff, dead-letter callback.
= ["dep:async-trait", "dep:tokio"]
# Postgres-backed job queue (`rustango::jobs::pg::PgJobQueue`) using
# `SELECT … FOR UPDATE SKIP LOCKED` for safe multi-process / multi-replica
# pickup. Implies `jobs` + `postgres` and the always-on `chrono` workspace dep.
= ["jobs", "postgres"]
# Pre-built auth flows (`rustango::auth_flows`) — password reset, email
# verification, magic-link login. Composes signed_url + email helpers.
= ["signed_url"]
# Broadcast event bus (`rustango::sse`) — fan-out for SSE / WebSocket /
# signal-driven push. tokio::sync::broadcast under the hood.
= ["dep:tokio"]
# WebSocket handler scaffold (`rustango::ws`) — fan-out via the SSE
# EventBus, axum upgrade handler with auto JSON encode/decode + ping/pong
# keep-alive. Implies `admin` (axum) + `sse` (broadcast bus). Adds
# tokio-tungstenite via the `axum/ws` feature.
= ["admin", "sse", "axum/ws"]
# OAuth2 / OIDC swiss-knife (`rustango::oauth2`) — works for pure OAuth2
# providers (GitHub, Discord) AND OIDC providers (Google, Microsoft,
# Apple, Keycloak) via the `/userinfo` endpoint as identity source.
# Per-tenant via `OAuth2Registry`. Pulls reqwest (rustls — no openssl).
= ["dep:reqwest", "dep:urlencoding", "dep:tokio", "dep:hmac", "dep:sha2", "dep:base64", "dep:rand", "dep:subtle", "dep:async-trait"]
# Opinionated HTTP client (`rustango::http_client`) — reqwest wrapper
# with sane timeouts, exponential-backoff retry on idempotent verbs +
# 5xx/timeout/connect failures, and a default User-Agent. Standalone
# wrapper that any rustango app can use directly.
= ["dep:reqwest", "dep:tokio"]
# Response compression middleware (`rustango::compression`) — gzip +
# deflate via flate2 (miniz_oxide by default, no C deps). Honors the
# client's `Accept-Encoding`, skips already-compressed and binary
# content-types. Implies `admin` (axum-only).
= ["admin", "dep:flate2"]
# Per-request CSP nonce middleware (`rustango::csp_nonce`) — generates
# a fresh CSPRNG nonce per request, stuffs it into request extensions
# for handlers to consume, and substitutes it into the
# Content-Security-Policy header so inline `<script nonce="…">` blocks
# pass strict CSP. Implies `admin` (axum-only) + rand for the nonce.
= ["admin", "dep:rand"]
# Server-side sessions (`rustango::sessions`) — opaque cookie ID
# backed by any `Cache` implementation. Implies `cache` + rand for
# the ID + base64 for encoding it.
= ["cache", "dep:rand", "dep:base64"]
# HMAC-signed request authentication (`rustango::hmac_auth`) for
# service-to-service traffic. AWS-style canonical request signed with
# SHA-256, replay-bounded by an X-Date tolerance window. Implies
# `admin` (axum) + the existing webhook crypto deps.
= ["admin", "dep:hmac", "dep:sha2", "dep:subtle", "dep:base64"]
# Standalone HS256 JWT (`rustango::jwt`) — sign / verify / decode for
# magic links, microservice tokens, third-party SSO. Standalone
# alternative to `tenancy::jwt_lifecycle` (which adds refresh +
# blacklist + sliding rotation but is gated on tenancy).
= ["dep:hmac", "dep:sha2", "dep:subtle", "dep:base64"]
# Multipart file upload helper (`rustango::uploads`) — wraps
# axum's multipart extractor + the `storage::Storage` trait so file
# uploads are a one-call API with size + extension guards. Pulls
# `multer` transitively via `axum/multipart`.
= ["admin", "storage", "axum/multipart"]
# First-class media model (`rustango::media`) — a Postgres-backed
# Media row that references a file in the Storage layer. Handles
# direct browser upload (via S3 presigning), CDN-aware URLs,
# soft delete + orphan purge sweep. Implies `storage` + `postgres`.
= ["storage", "postgres"]
# S3-compatible storage backend (`rustango::storage::s3::S3Storage`).
# Hand-rolled SigV4 over reqwest — works for AWS S3, Cloudflare R2,
# Backblaze B2, MinIO, and any other S3-compatible API. No
# `aws-sdk-s3` dependency.
= ["storage", "dep:reqwest", "dep:hmac", "dep:sha2"]
# OpenAPI 3.1 spec builder + Swagger UI router (`rustango::openapi`).
# Pure-Rust types you assemble into a spec, serialized to JSON via serde.
# Optional axum mount at `/openapi.json` + `/docs` (Swagger UI from a
# CDN). Forwards through to the proc-macro so `#[derive(Serializer)]`
# also emits an `OpenApiSchema` impl.
= ["rustango-macros/openapi"]
# File storage backends (`rustango::storage`) — Storage trait + LocalStorage
# (filesystem) + InMemoryStorage (tests). S3/GCS/Azure plug in via the trait.
= ["dep:async-trait", "dep:tokio"]
# In-process scheduled task runner (`rustango::scheduler`) — fire async jobs
# at fixed intervals with panic isolation per task.
= ["dep:tokio"]
# Secrets manager (`rustango::secrets`) — Secrets trait + EnvSecrets +
# InMemorySecrets. Vault / AWS / GCP plug in via the trait.
= ["dep:async-trait"]
# TOTP / 2FA (`rustango::totp`) — RFC 6238 time-based one-time passwords
# for second-factor authentication. SHA-1 (Google Authenticator default).
= ["dep:hmac", "dep:sha1", "dep:rand", "dep:subtle"]
# Webhook signature verification (`rustango::webhook`) — HMAC-SHA256
# constant-time verification for inbound webhooks (Stripe, GitHub, etc.).
= ["dep:hmac", "dep:sha2", "dep:subtle", "dep:base64"]
# Outbound webhook delivery (`rustango::webhook_delivery`) — POSTs an
# HMAC-signed JSON payload to a subscriber URL via the background job
# queue (so retries with exponential backoff are free). Implies
# `webhook` (signing format) + `jobs` (retry machinery) + reqwest.
= ["webhook", "jobs", "dep:reqwest"]
# API keys (`rustango::api_keys`) — standalone generate/hash/verify
# helpers for `{prefix}.{secret}` keys with argon2id hashing.
= ["dep:argon2", "dep:password-hash", "dep:rand"]
# Generic password helpers (`rustango::passwords`) — argon2id hash/verify
# + minimal strength check. Standalone alternative to tenancy::password.
= ["dep:argon2", "dep:password-hash"]
# Signed URL helpers (`rustango::signed_url`) — HMAC-SHA256 signed URLs
# with optional expiry. For magic-link login, password resets, etc.
= ["dep:hmac", "dep:sha2", "dep:subtle", "dep:base64"]
# Redis cache backend (`rustango::cache::RedisCache`). Adds the `redis`
# async connection-manager client. Implies `cache`.
= ["cache", "dep:redis"]
# CSRF protection (`rustango::forms::csrf`) — double-submit-cookie
# axum middleware. Lives behind its own flag so `forms`-only users
# (parsers without CSRF) don't pull cookie + rand + tower
# transitively.
= ["forms", "dep:axum", "dep:base64", "dep:cookie", "dep:rand", "dep:tower"]
# Auto-admin HTTP layer (`rustango::admin`). Pulls in axum + Tera +
# the supporting middleware deps. Implies `forms` + `csrf` so the
# admin's CRUD handlers reuse the shared parsers and ship CSRF on
# every mutation by default.
= [
"forms",
"csrf",
"dep:axum",
"dep:tera",
"dep:base64",
"dep:http",
"dep:http-body-util",
"dep:serde_urlencoded",
"dep:tokio",
]
# Multi-tenancy module (`rustango::tenancy`). Implies `admin` (the
# tenant admin builder wraps `rustango::admin`). Pulls in Argon2 +
# HMAC-SHA256 + cookie + tower for the per-tenant + operator
# authentication paths. Implies `storage` + `uploads` so the operator
# console can persist per-tenant brand assets (logo / favicon) on
# disk and serve them via the tenancy router.
= [
"admin",
"runtime",
"storage",
"uploads",
"dep:async-trait",
"dep:argon2",
"dep:cookie",
"dep:hmac",
"dep:password-hash",
"dep:rand",
"dep:rpassword",
"dep:serde_urlencoded",
"dep:sha2",
"dep:subtle",
"dep:tokio",
"dep:tower",
]
# `#[rustango::main]` runserver shim (slice 9.0 / 0.8.2). Pulls in
# `tracing-subscriber` so the macro can install the default
# `info,sqlx=warn` env-filter logger before the user body runs. Apps
# that don't want this dep can opt out by skipping the macro and
# using `#[tokio::main]` directly.
= ["dep:tracing-subscriber", "dep:tracing-appender"]
# Minimal axum runserver — `rustango::server::AppBuilder`. Bi-dialect
# single-pool bootstrap (SQLite / Postgres / MySQL). Implies axum +
# tokio. The full multi-tenant `Builder` lives behind `tenancy` and
# pulls in much more.
= ["dep:axum", "dep:tokio"]
[]
# Proc-macros — separate by Rust language requirement.
= { = "0.28.4", = "../rustango-macros" }
# Always-on: core ORM + query layer + SQL writer + migration runner.
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
# `config` feature dep — optional.
= { = true, = true }
# `admin` feature deps — optional.
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
# `tenancy` feature deps — optional.
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
= { = true, = true }
# `oauth2` feature deps — optional.
= { = true, = true }
= { = true, = true }
# `compression` feature dep — optional.
= { = true, = true }
# `runtime` feature dep — used by `#[rustango::main]` to install a
# default tracing subscriber (env-filter) before the user body runs.
= { = "0.3", = false, = ["fmt", "env-filter", "json"], = true }
= { = true, = true }
[]
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= { = true }
= "3"
# All example crates removed. Single-file examples are auto-detected
# by Cargo; multi-file or required-features examples are declared
# here.
# Multi-tenant blog demo (operator console + tenant admin + viewsets).
# Auto-discovered by Cargo because it lives under `examples/blog_demo/`
# with a `main.rs`, but its imports (rustango::tenancy, ::extractors,
# #[viewset(...)]) require the `tenancy` feature — without this gate,
# bare `cargo test` would compile it under default features and fail.
[[]]
= "blog_demo"
= "examples/blog_demo/main.rs"
= ["tenancy"]
# SQLite ORM demo — single-file example, gated on the `sqlite` feature
# so default `cargo build --examples` doesn't try to compile it.
[[]]
= "sqlite_orm_demo"
= "examples/sqlite_orm_demo.rs"
= ["sqlite"]
# AppBuilder + SQLite — minimal runnable bootstrap shape.
[[]]
= "sqlite_app_demo"
= "examples/sqlite_app_demo.rs"
= ["sqlite", "runserver"]