| Crates.io | mikcar |
| lib.rs | mikcar |
| version | 0.1.1 |
| created_at | 2025-12-28 05:34:27.825766+00 |
| updated_at | 2025-12-28 07:00:21.776154+00 |
| description | Sidecar infrastructure services for mik (storage, kv, sql, queue) |
| homepage | https://github.com/dufeut/mikcar |
| repository | https://github.com/dufeut/mikcar |
| max_upload_size | |
| id | 2008262 |
| size | 982,801 |
Sidecar infrastructure services for mik.
mikcar provides HTTP-based infrastructure services for WASM handlers running in mik:
Same API works locally and in production. Your WASM handlers don't know or care if they're talking to MinIO or AWS S3.
Two optimized images available:
| Image | Size | Queue Support | Base |
|---|---|---|---|
mikcar |
~21MB | No | scratch (musl static) |
mikcar-all |
~65MB | Redis, RabbitMQ | distroless |
# Minimal image (no queue) - recommended for most use cases
docker pull ghcr.io/dufeut/mikcar:latest
# Full image with queue support
docker pull ghcr.io/dufeut/mikcar-all:latest
# Pull specific version
docker pull ghcr.io/dufeut/mikcar:0.1.0
docker run -p 3001:3001 \
-e SIDECAR_TOKEN=secret \
-e KV_URL=memory:// \
-e STORAGE_URL=memory:// \
ghcr.io/dufeut/mikcar:latest --kv --storage
# Minimal image (no queue)
docker build -t mikcar .
# Full image with queue support
docker build -f Dockerfile.all -t mikcar:all .
# Install with default services (storage, kv, sql, secrets, email)
cargo install mikcar
# Install with queue support
cargo install mikcar --features all
# Install specific services only
cargo install mikcar --features storage,kv
# Run storage service
STORAGE_URL=file:///data mikcar --storage --port 3001
# Run KV service (embedded redb, no external dependencies)
KV_URL=file:///data/kv.redb mikcar --kv --port 3002
# Run SQL service
DATABASE_URL=postgres://user:pass@localhost/db mikcar --sql --port 3003
# Run secrets service
SECRETS_URL=vault://localhost:8200 mikcar --secrets --port 3004
# Run email service
EMAIL_URL=smtp://localhost:1025 mikcar --email --port 3005
# Supercar mode (multiple services on one port)
mikcar --kv --storage --sql --email --port 3001
/storage/*)GET /object/{path} Get object
PUT /object/{path} Put object (body = content)
DELETE /object/{path} Delete object
HEAD /object/{path} Check exists + metadata
GET /list/{prefix} List objects
/kv/*)GET /get/{key} Get value
POST /get/batch Get multiple (body = {keys: [...]})
POST /set/{key}?ttl= Set value (body = value)
POST /set/batch Set multiple (body = {key: value, ...})
DELETE /del/{key} Delete key
GET /keys/{pattern} List keys matching pattern
POST /increment/{key} Increment (atomic)
GET /exists/{key} Check if key exists
GET /ttl/{key} Get TTL (-1 = no TTL, -2 = not found)
POST /expire/{key} Set expiration (body = {seconds: N})
/sql/*)POST /query Execute SELECT (body = {sql, params})
POST /execute Execute INSERT/UPDATE/DELETE
POST /batch Execute multiple statements in transaction
POST /script Execute JavaScript with SQL in transaction
The /sql/script endpoint executes JavaScript code with SQL operations within a single database transaction. This enables complex conditional logic, validation, and multi-step operations with automatic rollback on failure.
Request:
{
"script": "var user = sql.query('SELECT * FROM users WHERE id = $1', [input.userId]); if (!user.length) throw new Error('User not found'); return { user: user[0] };",
"input": { "userId": 42 }
}
Response:
{
"result": { "user": { "id": 42, "name": "Alice" } },
"queries_executed": 1
}
Script API:
sql.query(sql, params) - Execute SELECT, returns array of row objectssql.execute(sql, params) - Execute INSERT/UPDATE/DELETE, returns rows affectedinput - The input object from the requestreturn - Specify the response valueSupported script formats:
// 1. Export default function (recommended)
export default function(input) {
var users = sql.query("SELECT * FROM users WHERE org = $1", [input.org]);
return { count: users.length };
}
// 2. Raw code with return (simple scripts)
var users = sql.query("SELECT * FROM users");
return { count: users.length };
// 3. Raw expression (simplest)
sql.query("SELECT COUNT(*) FROM users")
Transaction semantics:
Example: Fund transfer with balance check
export default function(input) {
// Check source account
var from = sql.query("SELECT id, balance FROM accounts WHERE id = $1", [input.from]);
if (!from.length) throw new Error("Source account not found");
if (parseFloat(from[0].balance) < input.amount) throw new Error("Insufficient funds");
// Check destination account
var to = sql.query("SELECT id FROM accounts WHERE id = $1", [input.to]);
if (!to.length) throw new Error("Destination account not found");
// Perform transfer (atomic - both succeed or both fail)
sql.execute("UPDATE accounts SET balance = balance - $1 WHERE id = $2", [input.amount, input.from]);
sql.execute("UPDATE accounts SET balance = balance + $1 WHERE id = $2", [input.amount, input.to]);
return { success: true, transferred: input.amount };
}
/queue/*)POST /publish/{topic} Publish message
GET /subscribe/{topic} Long-poll for messages
POST /ack/{topic}/{id} Acknowledge message
POST /push/{queue} Push to work queue
GET /pop/{queue} Pop from work queue
/email/*)POST /send Send single email
POST /send/batch Send multiple emails
Request body (POST /send):
{
"from": "sender@example.com",
"to": ["recipient@example.com"],
"cc": ["cc@example.com"],
"bcc": ["bcc@example.com"],
"subject": "Hello",
"text": "Plain text body",
"html": "<p>HTML body</p>",
"reply_to": "reply@example.com"
}
Response:
{"id": "message-id", "success": true}
Batch request (POST /send/batch):
{
"emails": [
{"from": "...", "to": ["..."], "subject": "...", "text": "..."},
{"from": "...", "to": ["..."], "subject": "...", "text": "..."}
]
}
Set SIDECAR_TOKEN or AUTH_TOKEN environment variable. Requests must include:
Authorization: Bearer <token>
The /health endpoint is always accessible without authentication.
| Variable | Service | Example |
|---|---|---|
STORAGE_URL |
storage | file:///data, s3://bucket, memory:// |
KV_URL |
kv | file:///data/kv.redb, memory:// |
DATABASE_URL |
sql | postgres://user:pass@host/db |
QUEUE_URL |
queue | redis://host:port, amqp://user:pass@host:port |
SECRETS_URL |
secrets | vault://host:port, awssm://region, gcpsm://project |
EMAIL_URL |
smtp://host:port, smtps://user:pass@host:465 |
|
SIDECAR_TOKEN |
auth | Bearer token for API authentication |
mikcar acts as an HTTP proxy to queue infrastructure. Supported backends:
| Backend | URL Format | Platform |
|---|---|---|
| In-memory | memory:// |
All |
| Redis Streams | redis://host:port |
Linux/macOS |
| RabbitMQ | amqp://user:pass@host:port |
Linux/macOS |
Auto-creation: Queues are automatically created on first push:
XGROUP CREATE ... MKSTREAM)No manual setup required - just push and pop.
Note: Queue requires the all feature or Dockerfile.all. Windows builds only support memory://.
# Redis
QUEUE_URL=redis://localhost:6379 mikcar --queue
# RabbitMQ
QUEUE_URL=amqp://guest:guest@localhost:5672 mikcar --queue
# In-memory (dev only)
QUEUE_URL=memory:// mikcar --queue
SMTP is the universal email protocol - works with any provider.
| Provider | URL Format |
|---|---|
| Local dev (Mailpit) | smtp://localhost:1025 |
| Gmail | smtps://user:app-password@smtp.gmail.com:465 |
| SendGrid | smtps://apikey:SG.xxx@smtp.sendgrid.net:465 |
| AWS SES | smtps://AKIA...:secret@email-smtp.us-east-1.amazonaws.com:465 |
| Resend | smtps://resend:re_xxx@smtp.resend.com:465 |
Port behavior:
smtps://)smtp://)# Local development with Mailpit
EMAIL_URL=smtp://localhost:1025 mikcar --email
# Production with SendGrid
EMAIL_URL=smtps://apikey:SG.xxx@smtp.sendgrid.net:465 mikcar --email
mikcar can be used as a Rust library to embed sidecars in your own applications (e.g., Tauri, Axum, or custom servers).
[dependencies]
mikcar = { git = "https://github.com/dufeut/mikcar", features = ["all"] }
tokio = { version = "1", features = ["full"] }
use mikcar::{SidecarBuilder, StorageService};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let storage = StorageService::from_url("memory://")?;
SidecarBuilder::new()
.port(3001)
.auth_token("secret")
.serve(storage)
.await
}
use mikcar::{SidecarBuilder, KvService, StorageService, SqlService};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let kv = KvService::from_url("memory://")?;
let storage = StorageService::from_url("memory://")?;
let sql = SqlService::from_url("postgres://user:pass@localhost/db").await?;
SidecarBuilder::new()
.port(3001)
.auth_token("secret")
.add(kv)
.add(storage)
.add(sql)
.serve_many()
.await
}
use mikcar::{SidecarBuilder, KvService, StorageService};
use std::sync::Arc;
use tokio::sync::Mutex;
struct AppState {
sidecars: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
}
#[tauri::command]
async fn start_sidecars(state: tauri::State<'_, AppState>) -> Result<(), String> {
let kv = KvService::from_url("memory://").map_err(|e| e.to_string())?;
let storage = StorageService::from_url("memory://").map_err(|e| e.to_string())?;
let handle = tokio::spawn(async move {
let _ = SidecarBuilder::new()
.port(3001)
.add(kv)
.add(storage)
.serve_many()
.await;
});
*state.sidecars.lock().await = Some(handle);
Ok(())
}
use mik::runtime::HostBuilder;
use mikcar::{SidecarBuilder, KvService, StorageService};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Start sidecars on port 3001
let kv = KvService::from_url("memory://")?;
let storage = StorageService::from_url("memory://")?;
tokio::spawn(async move {
SidecarBuilder::new()
.port(3001)
.add(kv)
.add(storage)
.serve_many()
.await
.unwrap();
});
// Start WASM runtime on port 3000
let host = HostBuilder::new()
.port(3000)
.modules_dir("./modules".into())
.build()
.await?;
host.serve().await?;
Ok(())
}
| Type | Description |
|---|---|
SidecarBuilder |
Builder for configuring and starting sidecars |
StorageService |
S3/GCS/Azure/local filesystem storage |
KvService |
Embedded key-value store (redb) |
SqlService |
PostgreSQL/SQLite proxy |
QueueService |
Redis Streams/RabbitMQ queues |
SecretsService |
Vault/AWS/GCP secret managers |
EmailService |
SMTP email sending |
Sidecar trait |
Implement custom sidecars |
mikcar re-exports commonly used crates for convenience:
use mikcar::axum; // Web framework
use mikcar::tower; // Service abstractions
use mikcar::tower_http; // HTTP middleware
MIT