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
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
[]
= "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", "template_views"]
= ["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"]
# Test-only constructors for downstream live tests. Currently
# unlocks `Tenant::for_test(org, conn)` so tenancy-aware crates
# (rustango-cms, etc.) can build a Tenant without booting a full
# axum server with TenantContext. v0.30.26+.
= []
# 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"]
# Database-backed job queue (`rustango::jobs::pg::PgJobQueue`).
# v0.38 — tri-dialect: PostgreSQL + MySQL 8.0+ use `FOR UPDATE SKIP
# LOCKED` for safe multi-process pickup; SQLite uses a transaction
# around `UPDATE … RETURNING` (SQLite serializes writers globally so
# the pickup is implicitly mutually-exclusive). The feature name is
# `jobs-postgres` for back-compat with v0.37 — the queue itself is
# no longer PG-only. The struct is still `PgJobQueue` for the same
# back-compat reason; new code can use `PgJobQueue::new_pool(pool)`.
= ["jobs"]
# 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 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. v0.38 — tri-dialect: every query dispatches per
# backend (PG / MySQL 8+ / SQLite), so `media` now only requires
# `storage` + at least one database backend feature
# (postgres / mysql / sqlite).
= ["storage"]
# 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"]
# Generic class-based views for HTML templates (`rustango::template_views`)
# — Django-shape `ListView` / `DetailView` / `CreateView` / `UpdateView` /
# `DeleteView` over `#[derive(Model)]` types, rendered through Tera.
# The JSON-API counterpart is `rustango::viewset` (always on).
= ["forms", "dep:axum", "dep:tera", "dep:tokio"]
# 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.
#
# v0.37 — admin is **fully tri-dialect**: every fetch goes through
# `select_*_as_json_pool`, every audit + permissions path is on
# `_pool` companions, and SQL is rendered via the dialect's
# `quote_ident` + `placeholder` emitters. The admin feature no
# longer implies `postgres`; pick whichever of `postgres` / `mysql`
# / `sqlite` your project needs and the admin works against it.
= [
"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.
= [
# v0.38 — `tenancy` no longer implies `postgres`. Database-per-tenant
# mode (`DatabasePools<DB>`, since v0.33) works on Postgres, MySQL,
# and SQLite alike. Schema-mode tenancy is still Postgres-only by
# language semantics (uses `SET search_path`); the framework's
# tenancy/migrate + tenancy/pools code paths keep their
# `#[cfg(feature = "postgres")]` gates around schema-mode-specific
# logic, and the runtime returns a clear error when a non-PG
# registry is asked to serve a schema-mode tenant.
#
# Picking a backend: add `--features sqlite,tenancy,admin`,
# `--features mysql,tenancy`, or `--features postgres,tenancy,admin`
# depending on the target deployment. Apps that *also* want
# schema-mode tenants get `postgres` automatically by including it.
"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.
#
# v0.31.1 (#4): `dep:tokio` so the macro can emit
# `#[::rustango::__private_runtime::tokio::main]` and user crates no
# longer need to add tokio to their own Cargo.toml just to use the
# rustango entrypoint shim.
= ["dep:tracing-subscriber", "dep:tracing-appender", "dep:tokio"]
# 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.38.0", = "../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).
# Uses the PG-only `Tenant` extractor / `viewset` / `server::ApiRouter`
# stack — requires postgres feature alongside tenancy. Auto-discovered
# by Cargo because it lives under `examples/blog_demo/` with a
# `main.rs`; gated so sqlite/mysql builds skip it cleanly.
[[]]
= "blog_demo"
= "examples/blog_demo/main.rs"
= ["tenancy", "postgres"]
# SQLite ORM demo — single-file example, gated on the `sqlite` feature
# so default `cargo build --examples` doesn't try to compile it.
# Also requires postgres because it derives Model unconditionally
# (macro emits PG paths).
[[]]
= "sqlite_orm_demo"
= "examples/sqlite_orm_demo.rs"
= ["sqlite", "postgres"]
# AppBuilder + SQLite — minimal runnable bootstrap shape.
[[]]
= "sqlite_app_demo"
= "examples/sqlite_app_demo.rs"
= ["sqlite", "runserver"]
# Multi-tenant SQLite demo (v0.33) — wires the DatabaseTenant<Sqlite>
# extractor for per-tenant-file SQLite databases. Pairs with the
# `database_pools_sqlite_*_live.rs` tests; this is the manual-running
# shape downstream apps consume until the Cli builder lands.
# Also requires postgres for the operator_console types it imports.
[[]]
= "sqlite_tenant_demo"
= "examples/sqlite_tenant_demo.rs"
= ["sqlite", "tenancy", "runtime", "postgres"]