maarcadetweet: initial commit

AT Protocol PDS + AppView + Tauri Desktop Client, 160-char post limit.

- PDS (Rust + axum + sqlx)
  - Auth: createAccount, createSession, refreshSession
  - Records: createRecord, deleteRecord (race-safe via SELECT FOR UPDATE)
  - Feed: feed.like.create, feed.repost.create
  - Sync: getRepo, getBlocks, getLatestCommit, getRecord (with MST proof), listRepos
  - Identity: resolveHandle
  - MST: spec-conformant (at-mst crate, 27 tests)
  - Repo: signed commits, TID counter (monotonic, 4096 wrap safe)

- AppView (Rust + axum + sqlx)
  - Jetstream consumer (WebSocket, exponential backoff, 38k+ events indexed)
  - REST API: timeline/home (graph-aware), profile, search, post (with thread hydration)
  - Handle-sync worker (did:plc + did:web)
  - JSONB embed storage + thread columns (migration 0003)
  - Like/repost counter cache (migration 0004)

- Tauri 2 + Svelte 5 Desktop Client
  - System tray (Show/Compose/Quit menu)
  - OS notifications (tauri-plugin-notification)
  - Auto-update (tauri-plugin-updater, placeholder endpoint)
  - Window-state (tauri-plugin-window-state)
  - 160-char compose with live counter
  - Image/Link embed rendering
  - LocalStorage-persisted like state
  - Timeline with poll (prepend new posts)
  - Custom TitleBar (transparent, no decorations)
  - Orange/IBM Plex Mono maarcade design

Tests: 231 Rust + 9 vitest = 240 passed.
This commit is contained in:
tomdebone
2026-07-05 20:01:31 +02:00
commit c586fd39c9
134 changed files with 35279 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
use crate::appview_push::AppViewPushClient;
use at_blob::S3BlobStore;
use at_identity::plc::PlcClient;
use at_lexicon::{Lex, LexRegistry};
use at_repo::blockstore::MemoryBlockstore;
use at_shared::config::AppConfig;
use sqlx::PgPool;
use std::sync::Arc;
#[derive(Clone)]
pub struct AppState {
pub cfg: AppConfig,
pub db: PgPool,
pub blob: S3BlobStore,
pub lex: Arc<LexRegistry>,
pub blockstore: Arc<MemoryBlockstore>,
pub plc: PlcClient,
pub appview: AppViewPushClient,
}
impl AppState {
pub async fn new(cfg: AppConfig, db: PgPool, blob: S3BlobStore) -> Self {
let mut lex = LexRegistry::new();
lex.lexicons.insert(
"app.twi.post".to_string(),
Lex::from_json(include_str!("../../../lexicons/app/twi/post.json")).unwrap(),
);
let plc_url = cfg.plc_directory_url.clone();
// The PDS speaks to the AppView via the cluster-internal URL —
// never the public one, because the ingest endpoint is unauth'd
// in dev mode (and uses a shared secret in prod). The base URL
// is the same as `appview_public_url` in our single-host dev
// setup, but operators can override with `APPVIEW_INTERNAL_URL`.
let appview_url = std::env::var("APPVIEW_INTERNAL_URL")
.unwrap_or_else(|_| cfg.appview_public_url.clone());
let appview = AppViewPushClient::new(appview_url, cfg.appview_ingest_secret.clone());
Self {
cfg,
db,
blob,
lex: Arc::new(lex),
blockstore: Arc::new(MemoryBlockstore::new()),
plc: PlcClient::new(plc_url),
appview,
}
}
}