+ Storage belongs to your account rather than this node. That keeps your media available if you move your account elsewhere. +
+ +{error}
} +diff --git a/.env.example b/.env.example index 1d720c4..0712b12 100644 --- a/.env.example +++ b/.env.example @@ -18,6 +18,9 @@ ADMIN_EMAILS=admin@example.com NEXT_PUBLIC_NODE_DOMAIN=localhost:43821 NEXT_PUBLIC_APP_URL=http://localhost:43821 +# Recommended: Stuffbox instance offered as the default user-owned media provider +# STUFFBOX_URL=https://stuffbox.example.com + # Optional: node metadata shown before a node record exists in the database # NEXT_PUBLIC_NODE_NAME=Synapsis Local # NEXT_PUBLIC_NODE_DESCRIPTION=Local development node diff --git a/README.md b/README.md index 08f950e..5925d6b 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,11 @@ Uninstalling preserves the database and environment by default. Pass `--purge-da ## Storage and account portability -The node database is a local embedded Turso/SQLite file. Media remains in each user's S3-compatible bucket so exported accounts can retain portable media URLs and move between Synapsis nodes without requiring the old node to transfer a shared upload directory. +The node database is a local embedded Turso/SQLite file. Media remains in storage controlled by each user, so exported accounts retain portable media URLs and can move between Synapsis nodes without requiring the old node to transfer a shared upload directory. -Supported S3-compatible providers include AWS S3, Cloudflare R2, Backblaze B2, Wasabi, and Contabo. Synapsis stores each user's credentials encrypted with `AUTH_SECRET`. +Stuffbox is the default integration. Set `STUFFBOX_URL` to the public URL of the Stuffbox service users should connect. Synapsis uses a consent and PKCE flow, keeps the resulting tokens encrypted with `AUTH_SECRET`, and sends file bytes directly from the user's browser to Stuffbox. + +User-owned S3-compatible storage remains available as an advanced fallback. Supported providers include AWS S3, Cloudflare R2, Backblaze B2, Wasabi, and Contabo. ## Development @@ -77,7 +79,7 @@ npm run build - **Framework:** Next.js 16 and React 19 - **Database:** embedded Turso with Drizzle ORM's relational-query v2 API - **Identity:** DIDs and per-user signing keys -- **Media:** user-owned S3-compatible storage +- **Media:** user-owned Stuffbox or S3-compatible storage - **Federation:** Synapsis Swarm discovery and signed interactions - **Deployment:** native Node.js process managed by systemd diff --git a/drizzle/20260715035425_fresh_sunfire/migration.sql b/drizzle/20260715035425_fresh_sunfire/migration.sql new file mode 100644 index 0000000..4c78a9c --- /dev/null +++ b/drizzle/20260715035425_fresh_sunfire/migration.sql @@ -0,0 +1,15 @@ +CREATE TABLE `stuffbox_connections` ( + `user_id` text PRIMARY KEY, + `base_url` text NOT NULL, + `access_token_encrypted` text NOT NULL, + `access_token_expires_at` integer NOT NULL, + `refresh_token_encrypted` text NOT NULL, + `refresh_token_expires_at` integer, + `scopes` text NOT NULL, + `connected_at` integer DEFAULT (unixepoch()) NOT NULL, + `updated_at` integer DEFAULT (unixepoch()) NOT NULL, + CONSTRAINT `fk_stuffbox_connections_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE +); +--> statement-breakpoint +ALTER TABLE `media` ADD `storage_provider` text;--> statement-breakpoint +ALTER TABLE `media` ADD `storage_asset_id` text; \ No newline at end of file diff --git a/drizzle/20260715035425_fresh_sunfire/snapshot.json b/drizzle/20260715035425_fresh_sunfire/snapshot.json new file mode 100644 index 0000000..b707da8 --- /dev/null +++ b/drizzle/20260715035425_fresh_sunfire/snapshot.json @@ -0,0 +1,6463 @@ +{ + "version": "7", + "dialect": "sqlite", + "id": "1a33ed5b-1bd9-454e-ad3b-fdcf2fc48b43", + "prevIds": [ + "f7179b64-ec71-42e4-9b56-8c19657cea92" + ], + "ddl": [ + { + "name": "blocks", + "entityType": "tables" + }, + { + "name": "bot_activity_logs", + "entityType": "tables" + }, + { + "name": "bot_content_items", + "entityType": "tables" + }, + { + "name": "bot_content_sources", + "entityType": "tables" + }, + { + "name": "bot_mentions", + "entityType": "tables" + }, + { + "name": "bot_rate_limits", + "entityType": "tables" + }, + { + "name": "bots", + "entityType": "tables" + }, + { + "name": "chat_conversations", + "entityType": "tables" + }, + { + "name": "chat_messages", + "entityType": "tables" + }, + { + "name": "chat_typing_indicators", + "entityType": "tables" + }, + { + "name": "follows", + "entityType": "tables" + }, + { + "name": "handle_registry", + "entityType": "tables" + }, + { + "name": "likes", + "entityType": "tables" + }, + { + "name": "media", + "entityType": "tables" + }, + { + "name": "muted_nodes", + "entityType": "tables" + }, + { + "name": "mutes", + "entityType": "tables" + }, + { + "name": "nodes", + "entityType": "tables" + }, + { + "name": "notifications", + "entityType": "tables" + }, + { + "name": "posts", + "entityType": "tables" + }, + { + "name": "remote_followers", + "entityType": "tables" + }, + { + "name": "remote_follows", + "entityType": "tables" + }, + { + "name": "remote_identity_cache", + "entityType": "tables" + }, + { + "name": "remote_likes", + "entityType": "tables" + }, + { + "name": "remote_posts", + "entityType": "tables" + }, + { + "name": "remote_reposts", + "entityType": "tables" + }, + { + "name": "reports", + "entityType": "tables" + }, + { + "name": "sessions", + "entityType": "tables" + }, + { + "name": "signed_action_dedupe", + "entityType": "tables" + }, + { + "name": "stuffbox_connections", + "entityType": "tables" + }, + { + "name": "swarm_nodes", + "entityType": "tables" + }, + { + "name": "swarm_seeds", + "entityType": "tables" + }, + { + "name": "swarm_sync_log", + "entityType": "tables" + }, + { + "name": "user_swarm_likes", + "entityType": "tables" + }, + { + "name": "user_swarm_reposts", + "entityType": "tables" + }, + { + "name": "users", + "entityType": "tables" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "blocks" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "blocks" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "blocked_user_id", + "entityType": "columns", + "table": "blocks" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "blocks" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "bot_activity_logs" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "bot_id", + "entityType": "columns", + "table": "bot_activity_logs" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "action", + "entityType": "columns", + "table": "bot_activity_logs" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "details", + "entityType": "columns", + "table": "bot_activity_logs" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "success", + "entityType": "columns", + "table": "bot_activity_logs" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "error_message", + "entityType": "columns", + "table": "bot_activity_logs" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "bot_activity_logs" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "source_id", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "external_id", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "title", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "published_at", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "fetched_at", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_processed", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "processed_at", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_id", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "interest_score", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "interest_reason", + "entityType": "columns", + "table": "bot_content_items" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "bot_id", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "subreddit", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "api_key_encrypted", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "source_config", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "keywords", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "is_active", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_fetch_at", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_error", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "consecutive_errors", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "bot_content_sources" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "bot_id", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_id", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_id", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_processed", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "processed_at", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "response_post_id", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_remote", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "remote_actor_url", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "bot_mentions" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "bot_rate_limits" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "bot_id", + "entityType": "columns", + "table": "bot_rate_limits" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "window_start", + "entityType": "columns", + "table": "bot_rate_limits" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "window_type", + "entityType": "columns", + "table": "bot_rate_limits" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "post_count", + "entityType": "columns", + "table": "bot_rate_limits" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "reply_count", + "entityType": "columns", + "table": "bot_rate_limits" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "bot_rate_limits" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "owner_id", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "personality_config", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "llm_provider", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "llm_model", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "llm_endpoint", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "llm_api_key_encrypted", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "schedule_config", + "entityType": "columns", + "table": "bots" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "autonomous_mode", + "entityType": "columns", + "table": "bots" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "is_active", + "entityType": "columns", + "table": "bots" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_suspended", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "suspension_reason", + "entityType": "columns", + "table": "bots" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "suspended_at", + "entityType": "columns", + "table": "bots" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_post_at", + "entityType": "columns", + "table": "bots" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "bots" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "bots" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "chat_conversations" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'direct'", + "generated": null, + "name": "type", + "entityType": "columns", + "table": "chat_conversations" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "participant1_id", + "entityType": "columns", + "table": "chat_conversations" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "participant2_handle", + "entityType": "columns", + "table": "chat_conversations" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_message_at", + "entityType": "columns", + "table": "chat_conversations" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_message_preview", + "entityType": "columns", + "table": "chat_conversations" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "chat_conversations" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "chat_conversations" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "conversation_id", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sender_handle", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sender_display_name", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sender_avatar_url", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sender_node_domain", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sender_did", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "swarm_message_id", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "delivered_at", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "read_at", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "chat_messages" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "chat_typing_indicators" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "conversation_id", + "entityType": "columns", + "table": "chat_typing_indicators" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_handle", + "entityType": "columns", + "table": "chat_typing_indicators" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "expires_at", + "entityType": "columns", + "table": "chat_typing_indicators" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "chat_typing_indicators" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "follows" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "follower_id", + "entityType": "columns", + "table": "follows" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "following_id", + "entityType": "columns", + "table": "follows" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ap_id", + "entityType": "columns", + "table": "follows" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "pending", + "entityType": "columns", + "table": "follows" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "follows" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "handle", + "entityType": "columns", + "table": "handle_registry" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "did", + "entityType": "columns", + "table": "handle_registry" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "node_domain", + "entityType": "columns", + "table": "handle_registry" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "registered_at", + "entityType": "columns", + "table": "handle_registry" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "handle_registry" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_id", + "entityType": "columns", + "table": "likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ap_id", + "entityType": "columns", + "table": "likes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "media" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "media" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_id", + "entityType": "columns", + "table": "media" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "media" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_provider", + "entityType": "columns", + "table": "media" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_asset_id", + "entityType": "columns", + "table": "media" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "alt_text", + "entityType": "columns", + "table": "media" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "mime_type", + "entityType": "columns", + "table": "media" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "width", + "entityType": "columns", + "table": "media" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "height", + "entityType": "columns", + "table": "media" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "media" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "muted_nodes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "muted_nodes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "node_domain", + "entityType": "columns", + "table": "muted_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "muted_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "mutes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "mutes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "muted_user_id", + "entityType": "columns", + "table": "mutes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "mutes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "domain", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "description", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "long_description", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "rules", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "banner_url", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "logo_url", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "favicon_url", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "logo_data", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "favicon_data", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": "'#FFFFFF'", + "generated": null, + "name": "accent_color", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "public_key", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "private_key_encrypted", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_nsfw", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "turnstile_site_key", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "turnstile_secret_key", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_id", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_handle", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_display_name", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_avatar_url", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_node_domain", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_handle", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_display_name", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_avatar_url", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_node_domain", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_is_bot", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_id", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_content", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "read_at", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "notifications" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "bot_id", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "reply_to_id", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "repost_of_id", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "swarm_reply_to_id", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "swarm_reply_to_content", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "swarm_reply_to_author", + "entityType": "columns", + "table": "posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "likes_count", + "entityType": "columns", + "table": "posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "reposts_count", + "entityType": "columns", + "table": "posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "replies_count", + "entityType": "columns", + "table": "posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_nsfw", + "entityType": "columns", + "table": "posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_removed", + "entityType": "columns", + "table": "posts" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "removed_at", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "removed_by", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "removed_reason", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ap_id", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ap_url", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_url", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_title", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_description", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_image", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_type", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_video_url", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_media_json", + "entityType": "columns", + "table": "posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "remote_followers" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "remote_followers" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_url", + "entityType": "columns", + "table": "remote_followers" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "inbox_url", + "entityType": "columns", + "table": "remote_followers" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "shared_inbox_url", + "entityType": "columns", + "table": "remote_followers" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "handle", + "entityType": "columns", + "table": "remote_followers" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "activity_id", + "entityType": "columns", + "table": "remote_followers" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "remote_followers" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "follower_id", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_handle", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_actor_url", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "inbox_url", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "activity_id", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "display_name", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "bio", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "avatar_url", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "remote_follows" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "did", + "entityType": "columns", + "table": "remote_identity_cache" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "public_key", + "entityType": "columns", + "table": "remote_identity_cache" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "fetched_at", + "entityType": "columns", + "table": "remote_identity_cache" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "expires_at", + "entityType": "columns", + "table": "remote_identity_cache" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "remote_likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_id", + "entityType": "columns", + "table": "remote_likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_handle", + "entityType": "columns", + "table": "remote_likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_node_domain", + "entityType": "columns", + "table": "remote_likes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "remote_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ap_id", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_handle", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_actor_url", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_display_name", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_avatar_url", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "published_at", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_url", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_title", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_description", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_image", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_type", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_video_url", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_media_json", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "media_json", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "fetched_at", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "remote_posts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "remote_reposts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_id", + "entityType": "columns", + "table": "remote_reposts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_handle", + "entityType": "columns", + "table": "remote_reposts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "actor_node_domain", + "entityType": "columns", + "table": "remote_reposts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "remote_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "reports" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "reporter_id", + "entityType": "columns", + "table": "reports" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_type", + "entityType": "columns", + "table": "reports" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "target_id", + "entityType": "columns", + "table": "reports" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "reason", + "entityType": "columns", + "table": "reports" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'open'", + "generated": null, + "name": "status", + "entityType": "columns", + "table": "reports" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "resolved_at", + "entityType": "columns", + "table": "reports" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "resolved_by", + "entityType": "columns", + "table": "reports" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "resolution_note", + "entityType": "columns", + "table": "reports" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "reports" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "sessions" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "sessions" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token", + "entityType": "columns", + "table": "sessions" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "expires_at", + "entityType": "columns", + "table": "sessions" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "sessions" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "action_id", + "entityType": "columns", + "table": "signed_action_dedupe" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "did", + "entityType": "columns", + "table": "signed_action_dedupe" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "nonce", + "entityType": "columns", + "table": "signed_action_dedupe" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ts", + "entityType": "columns", + "table": "signed_action_dedupe" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "signed_action_dedupe" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "base_url", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token_encrypted", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token_expires_at", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token_encrypted", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token_expires_at", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "scopes", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "connected_at", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "stuffbox_connections" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "domain", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "description", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "logo_url", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "public_key", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "software_version", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_count", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_count", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_nsfw", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "discovered_via", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "discovered_at", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "last_seen_at", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_sync_at", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "consecutive_failures", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "is_active", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "50", + "generated": null, + "name": "trust_score", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_blocked", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "block_reason", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "blocked_at", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "capabilities", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "swarm_nodes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "swarm_seeds" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "domain", + "entityType": "columns", + "table": "swarm_seeds" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "100", + "generated": null, + "name": "priority", + "entityType": "columns", + "table": "swarm_seeds" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "is_enabled", + "entityType": "columns", + "table": "swarm_seeds" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_contact_at", + "entityType": "columns", + "table": "swarm_seeds" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "consecutive_failures", + "entityType": "columns", + "table": "swarm_seeds" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "swarm_seeds" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "remote_domain", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "direction", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "nodes_received", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "nodes_sent", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "handles_received", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "handles_sent", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "success", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "error_message", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "duration_ms", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "swarm_sync_log" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "node_domain", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "original_post_id", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_handle", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_display_name", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_avatar_url", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_created_at", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "likes_count", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "reposts_count", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "replies_count", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_url", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_title", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_description", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_image", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_type", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_video_url", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_media_json", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "media_json", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "liked_at", + "entityType": "columns", + "table": "user_swarm_likes" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "node_domain", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "original_post_id", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_handle", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_display_name", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "author_avatar_url", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "post_created_at", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "likes_count", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "reposts_count", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "replies_count", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_url", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_title", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_description", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_image", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_type", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_video_url", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "link_preview_media_json", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "media_json", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "reposted_at", + "entityType": "columns", + "table": "user_swarm_reposts" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "did", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "handle", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "password_hash", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "display_name", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "bio", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "avatar_url", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "header_url", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "private_key_encrypted", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "public_key", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "node_id", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_bot", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "bot_owner_id", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_nsfw", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "nsfw_enabled", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "age_verified_at", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_suspended", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "suspension_reason", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "suspended_at", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "is_silenced", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "silence_reason", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "silenced_at", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "moved_to", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "moved_from", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "migrated_at", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_provider", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_endpoint", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_public_base_url", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_region", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_bucket", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_access_key_encrypted", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "storage_secret_key_encrypted", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "followers_count", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "following_count", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "posts_count", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "website", + "entityType": "columns", + "table": "users" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'everyone'", + "generated": null, + "name": "dm_privacy", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "users" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "users" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_blocks_user_id_users_id_fk", + "entityType": "fks", + "table": "blocks" + }, + { + "columns": [ + "blocked_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_blocks_blocked_user_id_users_id_fk", + "entityType": "fks", + "table": "blocks" + }, + { + "columns": [ + "bot_id" + ], + "tableTo": "bots", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_bot_activity_logs_bot_id_bots_id_fk", + "entityType": "fks", + "table": "bot_activity_logs" + }, + { + "columns": [ + "source_id" + ], + "tableTo": "bot_content_sources", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_bot_content_items_source_id_bot_content_sources_id_fk", + "entityType": "fks", + "table": "bot_content_items" + }, + { + "columns": [ + "post_id" + ], + "tableTo": "posts", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "nameExplicit": false, + "name": "fk_bot_content_items_post_id_posts_id_fk", + "entityType": "fks", + "table": "bot_content_items" + }, + { + "columns": [ + "bot_id" + ], + "tableTo": "bots", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_bot_content_sources_bot_id_bots_id_fk", + "entityType": "fks", + "table": "bot_content_sources" + }, + { + "columns": [ + "bot_id" + ], + "tableTo": "bots", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_bot_mentions_bot_id_bots_id_fk", + "entityType": "fks", + "table": "bot_mentions" + }, + { + "columns": [ + "post_id" + ], + "tableTo": "posts", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_bot_mentions_post_id_posts_id_fk", + "entityType": "fks", + "table": "bot_mentions" + }, + { + "columns": [ + "author_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "NO ACTION", + "nameExplicit": false, + "name": "fk_bot_mentions_author_id_users_id_fk", + "entityType": "fks", + "table": "bot_mentions" + }, + { + "columns": [ + "response_post_id" + ], + "tableTo": "posts", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "NO ACTION", + "nameExplicit": false, + "name": "fk_bot_mentions_response_post_id_posts_id_fk", + "entityType": "fks", + "table": "bot_mentions" + }, + { + "columns": [ + "bot_id" + ], + "tableTo": "bots", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_bot_rate_limits_bot_id_bots_id_fk", + "entityType": "fks", + "table": "bot_rate_limits" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_bots_user_id_users_id_fk", + "entityType": "fks", + "table": "bots" + }, + { + "columns": [ + "owner_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_bots_owner_id_users_id_fk", + "entityType": "fks", + "table": "bots" + }, + { + "columns": [ + "participant1_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_chat_conversations_participant1_id_users_id_fk", + "entityType": "fks", + "table": "chat_conversations" + }, + { + "columns": [ + "conversation_id" + ], + "tableTo": "chat_conversations", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_chat_messages_conversation_id_chat_conversations_id_fk", + "entityType": "fks", + "table": "chat_messages" + }, + { + "columns": [ + "conversation_id" + ], + "tableTo": "chat_conversations", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_chat_typing_indicators_conversation_id_chat_conversations_id_fk", + "entityType": "fks", + "table": "chat_typing_indicators" + }, + { + "columns": [ + "follower_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_follows_follower_id_users_id_fk", + "entityType": "fks", + "table": "follows" + }, + { + "columns": [ + "following_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_follows_following_id_users_id_fk", + "entityType": "fks", + "table": "follows" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_likes_user_id_users_id_fk", + "entityType": "fks", + "table": "likes" + }, + { + "columns": [ + "post_id" + ], + "tableTo": "posts", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_likes_post_id_posts_id_fk", + "entityType": "fks", + "table": "likes" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_media_user_id_users_id_fk", + "entityType": "fks", + "table": "media" + }, + { + "columns": [ + "post_id" + ], + "tableTo": "posts", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_media_post_id_posts_id_fk", + "entityType": "fks", + "table": "media" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_muted_nodes_user_id_users_id_fk", + "entityType": "fks", + "table": "muted_nodes" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_mutes_user_id_users_id_fk", + "entityType": "fks", + "table": "mutes" + }, + { + "columns": [ + "muted_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_mutes_muted_user_id_users_id_fk", + "entityType": "fks", + "table": "mutes" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_notifications_user_id_users_id_fk", + "entityType": "fks", + "table": "notifications" + }, + { + "columns": [ + "actor_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_notifications_actor_id_users_id_fk", + "entityType": "fks", + "table": "notifications" + }, + { + "columns": [ + "post_id" + ], + "tableTo": "posts", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_notifications_post_id_posts_id_fk", + "entityType": "fks", + "table": "notifications" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_posts_user_id_users_id_fk", + "entityType": "fks", + "table": "posts" + }, + { + "columns": [ + "bot_id" + ], + "tableTo": "bots", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "nameExplicit": false, + "name": "fk_posts_bot_id_bots_id_fk", + "entityType": "fks", + "table": "posts" + }, + { + "columns": [ + "removed_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "NO ACTION", + "nameExplicit": false, + "name": "fk_posts_removed_by_users_id_fk", + "entityType": "fks", + "table": "posts" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_remote_followers_user_id_users_id_fk", + "entityType": "fks", + "table": "remote_followers" + }, + { + "columns": [ + "follower_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_remote_follows_follower_id_users_id_fk", + "entityType": "fks", + "table": "remote_follows" + }, + { + "columns": [ + "post_id" + ], + "tableTo": "posts", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_remote_likes_post_id_posts_id_fk", + "entityType": "fks", + "table": "remote_likes" + }, + { + "columns": [ + "post_id" + ], + "tableTo": "posts", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_remote_reposts_post_id_posts_id_fk", + "entityType": "fks", + "table": "remote_reposts" + }, + { + "columns": [ + "reporter_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "nameExplicit": false, + "name": "fk_reports_reporter_id_users_id_fk", + "entityType": "fks", + "table": "reports" + }, + { + "columns": [ + "resolved_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "NO ACTION", + "nameExplicit": false, + "name": "fk_reports_resolved_by_users_id_fk", + "entityType": "fks", + "table": "reports" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_sessions_user_id_users_id_fk", + "entityType": "fks", + "table": "sessions" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_stuffbox_connections_user_id_users_id_fk", + "entityType": "fks", + "table": "stuffbox_connections" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_user_swarm_likes_user_id_users_id_fk", + "entityType": "fks", + "table": "user_swarm_likes" + }, + { + "columns": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_user_swarm_reposts_user_id_users_id_fk", + "entityType": "fks", + "table": "user_swarm_reposts" + }, + { + "columns": [ + "node_id" + ], + "tableTo": "nodes", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "NO ACTION", + "nameExplicit": false, + "name": "fk_users_node_id_nodes_id_fk", + "entityType": "fks", + "table": "users" + }, + { + "columns": [ + "bot_owner_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": true, + "name": "users_bot_owner_id_users_id_fk", + "entityType": "fks", + "table": "users" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "blocks_pk", + "table": "blocks", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "bot_activity_logs_pk", + "table": "bot_activity_logs", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "bot_content_items_pk", + "table": "bot_content_items", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "bot_content_sources_pk", + "table": "bot_content_sources", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "bot_mentions_pk", + "table": "bot_mentions", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "bot_rate_limits_pk", + "table": "bot_rate_limits", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "bots_pk", + "table": "bots", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "chat_conversations_pk", + "table": "chat_conversations", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "chat_messages_pk", + "table": "chat_messages", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "chat_typing_indicators_pk", + "table": "chat_typing_indicators", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "follows_pk", + "table": "follows", + "entityType": "pks" + }, + { + "columns": [ + "handle" + ], + "nameExplicit": false, + "name": "handle_registry_pk", + "table": "handle_registry", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "likes_pk", + "table": "likes", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "media_pk", + "table": "media", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "muted_nodes_pk", + "table": "muted_nodes", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "mutes_pk", + "table": "mutes", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "nodes_pk", + "table": "nodes", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "notifications_pk", + "table": "notifications", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "posts_pk", + "table": "posts", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "remote_followers_pk", + "table": "remote_followers", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "remote_follows_pk", + "table": "remote_follows", + "entityType": "pks" + }, + { + "columns": [ + "did" + ], + "nameExplicit": false, + "name": "remote_identity_cache_pk", + "table": "remote_identity_cache", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "remote_likes_pk", + "table": "remote_likes", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "remote_posts_pk", + "table": "remote_posts", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "remote_reposts_pk", + "table": "remote_reposts", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "reports_pk", + "table": "reports", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "sessions_pk", + "table": "sessions", + "entityType": "pks" + }, + { + "columns": [ + "action_id" + ], + "nameExplicit": false, + "name": "signed_action_dedupe_pk", + "table": "signed_action_dedupe", + "entityType": "pks" + }, + { + "columns": [ + "user_id" + ], + "nameExplicit": false, + "name": "stuffbox_connections_pk", + "table": "stuffbox_connections", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "swarm_nodes_pk", + "table": "swarm_nodes", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "swarm_seeds_pk", + "table": "swarm_seeds", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "swarm_sync_log_pk", + "table": "swarm_sync_log", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "user_swarm_likes_pk", + "table": "user_swarm_likes", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "user_swarm_reposts_pk", + "table": "user_swarm_reposts", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "users_pk", + "table": "users", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "blocks_user_idx", + "entityType": "indexes", + "table": "blocks" + }, + { + "columns": [ + { + "value": "blocked_user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "blocks_blocked_user_idx", + "entityType": "indexes", + "table": "blocks" + }, + { + "columns": [ + { + "value": "bot_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_activity_logs_bot_idx", + "entityType": "indexes", + "table": "bot_activity_logs" + }, + { + "columns": [ + { + "value": "action", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_activity_logs_action_idx", + "entityType": "indexes", + "table": "bot_activity_logs" + }, + { + "columns": [ + { + "value": "created_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_activity_logs_created_idx", + "entityType": "indexes", + "table": "bot_activity_logs" + }, + { + "columns": [ + { + "value": "source_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_content_items_source_idx", + "entityType": "indexes", + "table": "bot_content_items" + }, + { + "columns": [ + { + "value": "is_processed", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_content_items_processed_idx", + "entityType": "indexes", + "table": "bot_content_items" + }, + { + "columns": [ + { + "value": "external_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_content_items_external_idx", + "entityType": "indexes", + "table": "bot_content_items" + }, + { + "columns": [ + { + "value": "bot_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_content_sources_bot_idx", + "entityType": "indexes", + "table": "bot_content_sources" + }, + { + "columns": [ + { + "value": "type", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_content_sources_type_idx", + "entityType": "indexes", + "table": "bot_content_sources" + }, + { + "columns": [ + { + "value": "bot_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_mentions_bot_idx", + "entityType": "indexes", + "table": "bot_mentions" + }, + { + "columns": [ + { + "value": "is_processed", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_mentions_processed_idx", + "entityType": "indexes", + "table": "bot_mentions" + }, + { + "columns": [ + { + "value": "created_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_mentions_created_idx", + "entityType": "indexes", + "table": "bot_mentions" + }, + { + "columns": [ + { + "value": "bot_id", + "isExpression": false + }, + { + "value": "window_start", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bot_rate_limits_bot_window_idx", + "entityType": "indexes", + "table": "bot_rate_limits" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bots_user_id_idx", + "entityType": "indexes", + "table": "bots" + }, + { + "columns": [ + { + "value": "owner_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bots_owner_id_idx", + "entityType": "indexes", + "table": "bots" + }, + { + "columns": [ + { + "value": "is_active", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "bots_active_idx", + "entityType": "indexes", + "table": "bots" + }, + { + "columns": [ + { + "value": "participant1_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "chat_conversations_participant1_idx", + "entityType": "indexes", + "table": "chat_conversations" + }, + { + "columns": [ + { + "value": "last_message_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "chat_conversations_last_message_idx", + "entityType": "indexes", + "table": "chat_conversations" + }, + { + "columns": [ + { + "value": "participant1_id", + "isExpression": false + }, + { + "value": "participant2_handle", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "chat_conversations_unique", + "entityType": "indexes", + "table": "chat_conversations" + }, + { + "columns": [ + { + "value": "conversation_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "chat_messages_conversation_idx", + "entityType": "indexes", + "table": "chat_messages" + }, + { + "columns": [ + { + "value": "created_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "chat_messages_created_idx", + "entityType": "indexes", + "table": "chat_messages" + }, + { + "columns": [ + { + "value": "swarm_message_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "chat_messages_swarm_id_idx", + "entityType": "indexes", + "table": "chat_messages" + }, + { + "columns": [ + { + "value": "conversation_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "chat_typing_conversation_idx", + "entityType": "indexes", + "table": "chat_typing_indicators" + }, + { + "columns": [ + { + "value": "expires_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "chat_typing_expires_idx", + "entityType": "indexes", + "table": "chat_typing_indicators" + }, + { + "columns": [ + { + "value": "conversation_id", + "isExpression": false + }, + { + "value": "user_handle", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "chat_typing_unique", + "entityType": "indexes", + "table": "chat_typing_indicators" + }, + { + "columns": [ + { + "value": "follower_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "follows_follower_idx", + "entityType": "indexes", + "table": "follows" + }, + { + "columns": [ + { + "value": "following_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "follows_following_idx", + "entityType": "indexes", + "table": "follows" + }, + { + "columns": [ + { + "value": "updated_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "handle_registry_updated_idx", + "entityType": "indexes", + "table": "handle_registry" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + }, + { + "value": "post_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "likes_user_post_idx", + "entityType": "indexes", + "table": "likes" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "media_user_idx", + "entityType": "indexes", + "table": "media" + }, + { + "columns": [ + { + "value": "post_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "media_post_idx", + "entityType": "indexes", + "table": "media" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "muted_nodes_user_idx", + "entityType": "indexes", + "table": "muted_nodes" + }, + { + "columns": [ + { + "value": "node_domain", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "muted_nodes_domain_idx", + "entityType": "indexes", + "table": "muted_nodes" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "mutes_user_idx", + "entityType": "indexes", + "table": "mutes" + }, + { + "columns": [ + { + "value": "muted_user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "mutes_muted_user_idx", + "entityType": "indexes", + "table": "mutes" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "notifications_user_idx", + "entityType": "indexes", + "table": "notifications" + }, + { + "columns": [ + { + "value": "created_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "notifications_created_idx", + "entityType": "indexes", + "table": "notifications" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "posts_user_id_idx", + "entityType": "indexes", + "table": "posts" + }, + { + "columns": [ + { + "value": "bot_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "posts_bot_id_idx", + "entityType": "indexes", + "table": "posts" + }, + { + "columns": [ + { + "value": "created_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "posts_created_at_idx", + "entityType": "indexes", + "table": "posts" + }, + { + "columns": [ + { + "value": "reply_to_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "posts_reply_to_idx", + "entityType": "indexes", + "table": "posts" + }, + { + "columns": [ + { + "value": "is_removed", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "posts_removed_idx", + "entityType": "indexes", + "table": "posts" + }, + { + "columns": [ + { + "value": "is_nsfw", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "posts_nsfw_idx", + "entityType": "indexes", + "table": "posts" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_followers_user_idx", + "entityType": "indexes", + "table": "remote_followers" + }, + { + "columns": [ + { + "value": "actor_url", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_followers_actor_idx", + "entityType": "indexes", + "table": "remote_followers" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + }, + { + "value": "actor_url", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "remote_followers_user_actor_unique", + "entityType": "indexes", + "table": "remote_followers" + }, + { + "columns": [ + { + "value": "follower_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_follows_follower_idx", + "entityType": "indexes", + "table": "remote_follows" + }, + { + "columns": [ + { + "value": "target_handle", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_follows_target_idx", + "entityType": "indexes", + "table": "remote_follows" + }, + { + "columns": [ + { + "value": "post_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_likes_post_idx", + "entityType": "indexes", + "table": "remote_likes" + }, + { + "columns": [ + { + "value": "actor_handle", + "isExpression": false + }, + { + "value": "actor_node_domain", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_likes_actor_idx", + "entityType": "indexes", + "table": "remote_likes" + }, + { + "columns": [ + { + "value": "post_id", + "isExpression": false + }, + { + "value": "actor_handle", + "isExpression": false + }, + { + "value": "actor_node_domain", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "remote_likes_unique", + "entityType": "indexes", + "table": "remote_likes" + }, + { + "columns": [ + { + "value": "author_handle", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_posts_author_idx", + "entityType": "indexes", + "table": "remote_posts" + }, + { + "columns": [ + { + "value": "published_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_posts_published_idx", + "entityType": "indexes", + "table": "remote_posts" + }, + { + "columns": [ + { + "value": "ap_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_posts_ap_id_idx", + "entityType": "indexes", + "table": "remote_posts" + }, + { + "columns": [ + { + "value": "post_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_reposts_post_idx", + "entityType": "indexes", + "table": "remote_reposts" + }, + { + "columns": [ + { + "value": "actor_handle", + "isExpression": false + }, + { + "value": "actor_node_domain", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "remote_reposts_actor_idx", + "entityType": "indexes", + "table": "remote_reposts" + }, + { + "columns": [ + { + "value": "post_id", + "isExpression": false + }, + { + "value": "actor_handle", + "isExpression": false + }, + { + "value": "actor_node_domain", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "remote_reposts_unique", + "entityType": "indexes", + "table": "remote_reposts" + }, + { + "columns": [ + { + "value": "status", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "reports_status_idx", + "entityType": "indexes", + "table": "reports" + }, + { + "columns": [ + { + "value": "target_type", + "isExpression": false + }, + { + "value": "target_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "reports_target_idx", + "entityType": "indexes", + "table": "reports" + }, + { + "columns": [ + { + "value": "reporter_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "reports_reporter_idx", + "entityType": "indexes", + "table": "reports" + }, + { + "columns": [ + { + "value": "token", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "sessions_token_idx", + "entityType": "indexes", + "table": "sessions" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "sessions_user_idx", + "entityType": "indexes", + "table": "sessions" + }, + { + "columns": [ + { + "value": "created_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "signed_action_dedupe_created_idx", + "entityType": "indexes", + "table": "signed_action_dedupe" + }, + { + "columns": [ + { + "value": "domain", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_nodes_domain_idx", + "entityType": "indexes", + "table": "swarm_nodes" + }, + { + "columns": [ + { + "value": "is_active", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_nodes_active_idx", + "entityType": "indexes", + "table": "swarm_nodes" + }, + { + "columns": [ + { + "value": "last_seen_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_nodes_last_seen_idx", + "entityType": "indexes", + "table": "swarm_nodes" + }, + { + "columns": [ + { + "value": "trust_score", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_nodes_trust_idx", + "entityType": "indexes", + "table": "swarm_nodes" + }, + { + "columns": [ + { + "value": "is_nsfw", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_nodes_nsfw_idx", + "entityType": "indexes", + "table": "swarm_nodes" + }, + { + "columns": [ + { + "value": "is_blocked", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_nodes_blocked_idx", + "entityType": "indexes", + "table": "swarm_nodes" + }, + { + "columns": [ + { + "value": "is_enabled", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_seeds_enabled_idx", + "entityType": "indexes", + "table": "swarm_seeds" + }, + { + "columns": [ + { + "value": "priority", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_seeds_priority_idx", + "entityType": "indexes", + "table": "swarm_seeds" + }, + { + "columns": [ + { + "value": "remote_domain", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_sync_log_remote_idx", + "entityType": "indexes", + "table": "swarm_sync_log" + }, + { + "columns": [ + { + "value": "created_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "swarm_sync_log_created_idx", + "entityType": "indexes", + "table": "swarm_sync_log" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + }, + { + "value": "liked_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "user_swarm_likes_user_idx", + "entityType": "indexes", + "table": "user_swarm_likes" + }, + { + "columns": [ + { + "value": "node_domain", + "isExpression": false + }, + { + "value": "original_post_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "user_swarm_likes_post_idx", + "entityType": "indexes", + "table": "user_swarm_likes" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + }, + { + "value": "node_domain", + "isExpression": false + }, + { + "value": "original_post_id", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "user_swarm_likes_unique", + "entityType": "indexes", + "table": "user_swarm_likes" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + }, + { + "value": "reposted_at", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "user_swarm_reposts_user_idx", + "entityType": "indexes", + "table": "user_swarm_reposts" + }, + { + "columns": [ + { + "value": "node_domain", + "isExpression": false + }, + { + "value": "original_post_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "user_swarm_reposts_post_idx", + "entityType": "indexes", + "table": "user_swarm_reposts" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + }, + { + "value": "node_domain", + "isExpression": false + }, + { + "value": "original_post_id", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "user_swarm_reposts_unique", + "entityType": "indexes", + "table": "user_swarm_reposts" + }, + { + "columns": [ + { + "value": "handle", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "users_handle_idx", + "entityType": "indexes", + "table": "users" + }, + { + "columns": [ + { + "value": "did", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "users_did_idx", + "entityType": "indexes", + "table": "users" + }, + { + "columns": [ + { + "value": "is_suspended", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "users_suspended_idx", + "entityType": "indexes", + "table": "users" + }, + { + "columns": [ + { + "value": "is_silenced", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "users_silenced_idx", + "entityType": "indexes", + "table": "users" + }, + { + "columns": [ + { + "value": "is_bot", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "users_is_bot_idx", + "entityType": "indexes", + "table": "users" + }, + { + "columns": [ + { + "value": "bot_owner_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "users_bot_owner_idx", + "entityType": "indexes", + "table": "users" + }, + { + "columns": [ + { + "value": "is_nsfw", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "users_nsfw_idx", + "entityType": "indexes", + "table": "users" + }, + { + "columns": [ + "ap_id" + ], + "nameExplicit": false, + "name": "follows_ap_id_unique", + "entityType": "uniques", + "table": "follows" + }, + { + "columns": [ + "ap_id" + ], + "nameExplicit": false, + "name": "likes_ap_id_unique", + "entityType": "uniques", + "table": "likes" + }, + { + "columns": [ + "domain" + ], + "nameExplicit": false, + "name": "nodes_domain_unique", + "entityType": "uniques", + "table": "nodes" + }, + { + "columns": [ + "ap_id" + ], + "nameExplicit": false, + "name": "posts_ap_id_unique", + "entityType": "uniques", + "table": "posts" + }, + { + "columns": [ + "domain" + ], + "nameExplicit": false, + "name": "swarm_seeds_domain_unique", + "entityType": "uniques", + "table": "swarm_seeds" + }, + { + "columns": [ + "email" + ], + "nameExplicit": false, + "name": "users_email_unique", + "entityType": "uniques", + "table": "users" + } + ], + "renames": [] +} \ No newline at end of file diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 99a6fca..4253309 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -8,6 +8,7 @@ import { StorageConfigurationPrompt } from '@/components/StorageConfigurationPro import { useToast } from '@/lib/contexts/ToastContext'; import { useAccentColor } from '@/lib/contexts/AccentColorContext'; import { refreshStorageSession } from '@/lib/storage/client'; +import { MediaUploadError, uploadMediaFile } from '@/lib/stuffbox/browser-upload'; export default function AdminPage() { const { showToast } = useToast(); @@ -105,33 +106,11 @@ export default function AdminPage() { setIsUploadingBanner(true); try { - const formData = new FormData(); - formData.append('file', file); - const res = await fetch('/api/media/upload', { - method: 'POST', - body: formData, - }); - const data = await res.json(); - - if (!res.ok || !data.url) { - if (data.code === 'STORAGE_NOT_CONFIGURED' && allowPrompt) { - setPendingBannerFile(file); - setShowBannerStorageConfiguration(true); - return; - } - if (res.status === 401 && allowPrompt) { - setPendingBannerFile(file); - setBannerPromptError(''); - setShowBannerSessionPrompt(true); - return; - } - - throw new Error(data.error || 'Upload failed'); - } + const media = await uploadMediaFile(file); const nextSettings = { ...nodeSettings, - bannerUrl: data.media?.url || data.url, + bannerUrl: media.url, }; setNodeSettings(nextSettings); await handleSaveSettings(nextSettings); @@ -140,6 +119,17 @@ export default function AdminPage() { setBannerPassword(''); setBannerPromptError(''); } catch (error) { + if (error instanceof MediaUploadError && error.code === 'STORAGE_NOT_CONFIGURED' && allowPrompt) { + setPendingBannerFile(file); + setShowBannerStorageConfiguration(true); + return; + } + if (error instanceof MediaUploadError && error.status === 401 && allowPrompt) { + setPendingBannerFile(file); + setBannerPromptError(''); + setShowBannerSessionPrompt(true); + return; + } console.error('Banner upload failed', error); setBannerUploadError(error instanceof Error ? error.message : 'Upload failed. Please try again.'); } finally { diff --git a/src/app/api/media/stuffbox/uploads/[uploadId]/complete/route.ts b/src/app/api/media/stuffbox/uploads/[uploadId]/complete/route.ts new file mode 100644 index 0000000..f582b93 --- /dev/null +++ b/src/app/api/media/stuffbox/uploads/[uploadId]/complete/route.ts @@ -0,0 +1,46 @@ +import { NextResponse } from 'next/server'; +import { z } from 'zod'; +import { db, media } from '@/db'; +import { requireAuth } from '@/lib/auth'; +import { completeUpload, StuffboxApiError } from '@/lib/stuffbox/client'; +import { getStuffboxAccess } from '@/lib/stuffbox/tokens'; + +const bodySchema = z.object({ alt: z.string().max(1500).nullable().optional() }); +type Context = { params: Promise<{ uploadId: string }> }; + +export async function POST(request: Request, context: Context) { + try { + const user = await requireAuth(); + const body = bodySchema.parse(await request.json().catch(() => ({}))); + const { uploadId } = await context.params; + const { baseUrl, accessToken } = await getStuffboxAccess(user.id); + const asset = await completeUpload(baseUrl, accessToken, uploadId); + const [record] = await db.insert(media).values({ + userId: user.id, + postId: null, + url: asset.url, + storageProvider: 'stuffbox', + storageAssetId: asset.id, + altText: body.alt ?? null, + mimeType: asset.mimeType, + width: 0, + height: 0, + }).returning(); + return NextResponse.json({ success: true, media: record, asset }); + } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json({ error: 'Invalid upload completion' }, { status: 400 }); + } + if (error instanceof Error && error.message === 'Authentication required') { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }); + } + if (error instanceof Error && error.message === 'STUFFBOX_NOT_CONNECTED') { + return NextResponse.json({ error: 'Stuffbox is disconnected', code: 'STORAGE_NOT_CONFIGURED' }, { status: 409 }); + } + if (error instanceof StuffboxApiError) { + return NextResponse.json({ error: error.message, code: error.code }, { status: error.status || 502 }); + } + console.error('Stuffbox upload completion error:', error); + return NextResponse.json({ error: 'Unable to complete upload' }, { status: 500 }); + } +} diff --git a/src/app/api/media/stuffbox/uploads/route.ts b/src/app/api/media/stuffbox/uploads/route.ts new file mode 100644 index 0000000..85ae247 --- /dev/null +++ b/src/app/api/media/stuffbox/uploads/route.ts @@ -0,0 +1,47 @@ +import { NextResponse } from 'next/server'; +import { z } from 'zod'; +import { requireAuth } from '@/lib/auth'; +import { createUpload, StuffboxApiError } from '@/lib/stuffbox/client'; +import { getStuffboxAccess } from '@/lib/stuffbox/tokens'; + +const uploadSchema = z.object({ + filename: z.string().min(1).max(255), + mimeType: z.enum([ + 'image/jpeg', 'image/png', 'image/gif', 'image/webp', + 'video/mp4', 'video/webm', 'video/quicktime', + ]), + size: z.number().int().positive().max(100 * 1024 * 1024), + sha256: z.string().regex(/^[a-f0-9]{64}$/).optional(), +}).superRefine((upload, context) => { + if (upload.mimeType.startsWith('image/') && upload.size > 10 * 1024 * 1024) { + context.addIssue({ code: 'too_big', maximum: 10 * 1024 * 1024, origin: 'number', inclusive: true, path: ['size'], message: 'Images must be 10MB or smaller' }); + } +}); + +export async function POST(request: Request) { + try { + const user = await requireAuth(); + const input = uploadSchema.parse(await request.json()); + const { baseUrl, accessToken } = await getStuffboxAccess(user.id); + const upload = await createUpload(baseUrl, accessToken, input); + return NextResponse.json(upload, { status: 201 }); + } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json({ error: 'Invalid upload', details: error.issues }, { status: 400 }); + } + if (error instanceof Error && error.message === 'Authentication required') { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }); + } + if (error instanceof Error && error.message === 'STUFFBOX_NOT_CONNECTED') { + return NextResponse.json({ + error: 'Connect Stuffbox before uploading media.', + code: 'STORAGE_NOT_CONFIGURED', + }, { status: 409 }); + } + if (error instanceof StuffboxApiError) { + return NextResponse.json({ error: error.message, code: error.code }, { status: error.status || 502 }); + } + console.error('Stuffbox upload-session error:', error); + return NextResponse.json({ error: 'Unable to create upload session' }, { status: 500 }); + } +} diff --git a/src/app/api/storage/configuration/route.ts b/src/app/api/storage/configuration/route.ts index c77c854..48403e4 100644 --- a/src/app/api/storage/configuration/route.ts +++ b/src/app/api/storage/configuration/route.ts @@ -6,6 +6,8 @@ import { requireAuth, verifyPassword } from '@/lib/auth'; import { encryptPrivateKey, serializeEncryptedKey } from '@/lib/crypto/private-key'; import { testS3Credentials, type StorageProvider } from '@/lib/storage/s3'; import { createStorageSession } from '@/lib/storage/session'; +import { configuredStuffboxUrl } from '@/lib/stuffbox/client'; +import { getStuffboxConnection } from '@/lib/stuffbox/tokens'; const configurationSchema = z.object({ password: z.string().min(1), @@ -18,6 +20,25 @@ const configurationSchema = z.object({ secretKey: z.string().min(10), }); +export async function GET() { + try { + const user = await requireAuth(); + const stuffbox = await getStuffboxConnection(user.id); + return NextResponse.json({ + provider: stuffbox ? 'stuffbox' : user.storageProvider ? 's3' : null, + stuffboxAvailable: Boolean(configuredStuffboxUrl()), + stuffboxBaseUrl: stuffbox?.baseUrl ?? null, + s3Provider: user.storageProvider ?? null, + }); + } catch (error) { + if (error instanceof Error && error.message === 'Authentication required') { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }); + } + console.error('Storage status error:', error); + return NextResponse.json({ error: 'Failed to load storage status' }, { status: 500 }); + } +} + export async function POST(request: Request) { try { const user = await requireAuth(); diff --git a/src/app/api/storage/stuffbox/callback/route.ts b/src/app/api/storage/stuffbox/callback/route.ts new file mode 100644 index 0000000..2180c2e --- /dev/null +++ b/src/app/api/storage/stuffbox/callback/route.ts @@ -0,0 +1,53 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { requireAuth } from '@/lib/auth'; +import { exchangeAuthorizationCode, StuffboxApiError } from '@/lib/stuffbox/client'; +import { consumeStuffboxConnectionState } from '@/lib/stuffbox/connection-state'; +import { saveStuffboxTokens } from '@/lib/stuffbox/tokens'; + +function popupResponse(origin: string, success: boolean, message: string): NextResponse { + const safeJson = (value: unknown) => JSON.stringify(value).replace(/
${success ? 'Stuffbox connected. You can close this window.' : 'Stuffbox could not be connected.'}
+ + `; + return new NextResponse(html, { + status: success ? 200 : 400, + headers: { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' }, + }); +} + +export async function GET(request: NextRequest) { + const origin = request.nextUrl.origin; + try { + const user = await requireAuth(); + const pending = await consumeStuffboxConnectionState(); + const code = request.nextUrl.searchParams.get('code'); + const state = request.nextUrl.searchParams.get('state'); + const denied = request.nextUrl.searchParams.get('error'); + + if (denied) return popupResponse(origin, false, 'Stuffbox access was not approved.'); + if (!pending || pending.userId !== user.id || !code || state !== pending.state) { + return popupResponse(origin, false, 'The Stuffbox connection request is invalid or expired.'); + } + + const tokens = await exchangeAuthorizationCode(pending.baseUrl, { + code, + codeVerifier: pending.verifier, + redirectUri: pending.redirectUri, + }); + await saveStuffboxTokens(user.id, pending.baseUrl, tokens); + return popupResponse(new URL(pending.redirectUri).origin, true, 'Stuffbox connected.'); + } catch (error) { + if (error instanceof StuffboxApiError) { + return popupResponse(origin, false, error.message); + } + console.error('Stuffbox callback error:', error); + return popupResponse(origin, false, 'Stuffbox could not be connected.'); + } +} diff --git a/src/app/api/storage/stuffbox/connect/route.ts b/src/app/api/storage/stuffbox/connect/route.ts new file mode 100644 index 0000000..5669b1c --- /dev/null +++ b/src/app/api/storage/stuffbox/connect/route.ts @@ -0,0 +1,63 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { db } from '@/db'; +import { requireAuth } from '@/lib/auth'; +import { configuredStuffboxUrl, createConnectionRequest, StuffboxApiError } from '@/lib/stuffbox/client'; +import { saveStuffboxConnectionState } from '@/lib/stuffbox/connection-state'; +import { generatePkce } from '@/lib/stuffbox/crypto'; +import { STUFFBOX_SCOPES } from '@/lib/stuffbox/types'; + +function nodeOrigin(request: NextRequest): string { + const appUrl = process.env.NEXT_PUBLIC_APP_URL?.trim(); + if (appUrl) return new URL(appUrl).origin; + const configured = process.env.NEXT_PUBLIC_NODE_DOMAIN?.trim(); + if (!configured) return request.nextUrl.origin; + const protocol = /^(localhost|127\.0\.0\.1)(:|$)/.test(configured) ? 'http' : 'https'; + return new URL(configured.includes('://') ? configured : `${protocol}://${configured}`).origin; +} + +export async function POST(request: NextRequest) { + try { + const user = await requireAuth(); + const baseUrl = configuredStuffboxUrl(); + if (!baseUrl) { + return NextResponse.json({ + error: 'Stuffbox is not configured on this node.', + code: 'STUFFBOX_UNAVAILABLE', + }, { status: 503 }); + } + + const origin = nodeOrigin(request); + const redirectUri = `${origin}/api/storage/stuffbox/callback`; + const node = user.nodeId + ? await db.query.nodes.findFirst({ where: { id: user.nodeId } }) + : null; + const pkce = generatePkce(); + const connection = await createConnectionRequest(baseUrl, { + nodeName: node?.name || new URL(origin).host, + callbackUrl: redirectUri, + codeChallenge: pkce.challenge, + state: pkce.state, + scopes: STUFFBOX_SCOPES, + }); + + await saveStuffboxConnectionState({ + userId: user.id, + baseUrl, + verifier: pkce.verifier, + state: pkce.state, + redirectUri, + expiresAt: Math.min(Date.parse(connection.expiresAt) || Date.now() + 10 * 60_000, Date.now() + 10 * 60_000), + }); + + return NextResponse.json({ authorizationUrl: connection.authorizationUrl }); + } catch (error) { + if (error instanceof Error && error.message === 'Authentication required') { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }); + } + if (error instanceof StuffboxApiError) { + return NextResponse.json({ error: error.message, code: error.code }, { status: error.status || 502 }); + } + console.error('Stuffbox connection error:', error); + return NextResponse.json({ error: 'Unable to start Stuffbox connection' }, { status: 500 }); + } +} diff --git a/src/app/api/storage/stuffbox/disconnect/route.ts b/src/app/api/storage/stuffbox/disconnect/route.ts new file mode 100644 index 0000000..d86d5d8 --- /dev/null +++ b/src/app/api/storage/stuffbox/disconnect/route.ts @@ -0,0 +1,30 @@ +import { NextResponse } from 'next/server'; +import { requireAuth } from '@/lib/auth'; +import { revokeToken } from '@/lib/stuffbox/client'; +import { + getStuffboxConnection, + readStuffboxRefreshToken, + removeStuffboxConnection, +} from '@/lib/stuffbox/tokens'; + +export async function POST() { + try { + const user = await requireAuth(); + const connection = await getStuffboxConnection(user.id); + if (connection) { + try { + await revokeToken(connection.baseUrl, readStuffboxRefreshToken(connection)); + } catch (error) { + console.warn('Stuffbox token revocation failed; removing local connection:', error); + } + await removeStuffboxConnection(user.id); + } + return NextResponse.json({ success: true }); + } catch (error) { + if (error instanceof Error && error.message === 'Authentication required') { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }); + } + console.error('Stuffbox disconnect error:', error); + return NextResponse.json({ error: 'Unable to disconnect Stuffbox' }, { status: 500 }); + } +} diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index 971fd30..063c6a9 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -2,7 +2,7 @@ import Link from 'next/link'; -import { Rocket, Shield, Bell, Eye, UserX } from 'lucide-react'; +import { Rocket, Shield, Bell, Eye, UserX, HardDrive } from 'lucide-react'; export default function SettingsPage() { return ( @@ -26,6 +26,23 @@ export default function SettingsPage() {+ Storage belongs to your account rather than this node. That keeps your media available if you move your account elsewhere. +
+ +{error}
} +- Synapsis keeps media in your own S3-compatible bucket. This is only required when you upload a photo or video. + Your media lives outside this Synapsis node, so your account stays portable.
-