···11{
22 "db_name": "PostgreSQL",
33- "query": "\n SELECT rb.blob_cid, rb.record_uri\n FROM record_blobs rb\n LEFT JOIN blobs b ON rb.blob_cid = b.cid AND b.created_by_user = rb.repo_id\n WHERE rb.repo_id = $1 AND b.cid IS NULL AND rb.blob_cid > $2\n ORDER BY rb.blob_cid\n LIMIT $3\n ",
33+ "query": "\n SELECT rb.blob_cid, rb.record_uri\n FROM record_blobs rb\n LEFT JOIN blobs b ON rb.blob_cid = b.cid\n WHERE rb.repo_id = $1 AND b.cid IS NULL AND rb.blob_cid > $2\n ORDER BY rb.blob_cid\n LIMIT $3\n ",
44 "describe": {
55 "columns": [
66 {
···2626 false
2727 ]
2828 },
2929- "hash": "6f88c5e63c1beb47733daed5295492d59c649a35ef78414c62dcdf4d0b2a3115"
2929+ "hash": "ec51d224b9fcd73fd04eebaf2215423d7b1d528b5aba87a0d2f5fe4636af0adf"
3030}
···14141515This software isn't an afterthought by a company with limited resources.
16161717-It is a superset of the reference PDS, including: passkeys and 2FA (WebAuthn/FIDO2, TOTP, backup codes, trusted devices), did:web support (PDS-hosted subdomains or bring-your-own), multi-channel communication (email, discord, telegram, signal) for verification and alerts, granular OAuth scopes with a consent UI showing human-readable descriptions, app passwords with granular permissions (read-only, post-only, or custom scopes), account delegation (letting others manage an account with configurable permission levels), and a built-in web UI for account management, OAuth consent, repo browsing, and admin.
1717+It is a superset of the reference PDS, including: passkeys and 2FA (WebAuthn/FIDO2, TOTP, backup codes, trusted devices), did:web support (PDS-hosted subdomains or bring-your-own), multi-channel communication (email, discord, telegram, signal) for verification and alerts, granular OAuth scopes with a consent UI showing human-readable descriptions, app passwords with granular permissions (read-only, post-only, or custom scopes), account delegation (letting others manage an account with configurable permission levels), automatic backups to s3-compatible object storage (configurable retention and frequency, one-click restore), and a built-in web UI for account management, OAuth consent, repo browsing, and admin.
18181919The PDS itself is a single small binary with no node/npm runtime. It does require postgres, valkey, and s3-compatible storage, which makes setup heavier than the reference PDS's sqlite. The tradeoff is that these are battle-tested pieces of infra that we already know how to scale, back up, and monitor.
2020
···2233## Active development
4455-### Migration tool
66-Seamless account migration built into the UI, inspired by pdsmoover. Users shouldn't need external tools or brain surgery on half-done account states.
77-88-- [x] Inbound UI wizard: login to old PDS -> choose handle -> import -> PLC token flow
99-- [x] Support `createAccount` with existing DID + service auth token
1010-- [x] Progress tracking with resume capability
1111-- [ ] Scheduled automatic backups (CAR export)
1212-- [ ] One-click restore from backup
1313-1414-Outbound migration wizard exists but is disabled. Rethinking the approach: instead of a managed flow with `migratingTo` state, pds-hosted did:web users should just have direct control over their DID document. They can independently update serviceEndpoint, add/remove keys, export their repo, deactivate their account.
1515-1616-- [ ] Remove `migratingTo` field and related state machine
1717-- [ ] Let did:web users edit their DID doc fields (serviceEndpoint, keys) whenever
1818-- [ ] Repo export as standalone feature, not tied to migration wizard
1919-205### Plugin system
216Extensible architecture allowing third-party plugins to add functionality. Going with wasm-based rather than scripting language.
227···6954App password scopes: Granular permissions for app passwords using the same scope system as OAuth. Preset buttons for common use cases (full access, read-only, post-only), scope stored in session and preserved across token refresh, explicit RPC/repo/blob scope enforcement for restricted passwords.
70557156Account Delegation: Delegated accounts controlled by other accounts instead of passwords. OAuth delegation flow (authenticate as controller), scope-based permissions (owner/admin/editor/viewer presets), scope intersection (tokens limited to granted permissions), `act` claim for delegation tracking, creating delegated account flow, controller management UI, "act as" account switcher, comprehensive audit logging with actor/controller tracking, delegation-aware OAuth consent with permission limitation notices.
5757+5858+Migration: OAuth-based inbound migration wizard with PLC token flow, offline restore from CAR file + rotation key for disaster recovery, scheduled automatic backups, standalone repo/blob export, did:web DID document editor for self-service identity management.
···1717 "dashboard": "Dashboard",
1818 "backToDashboard": "← Dashboard",
1919 "copied": "Copied!",
2020- "copyToClipboard": "Copy to Clipboard"
2020+ "copyToClipboard": "Copy to Clipboard",
2121+2222+ "verifying": "Verifying...",
2323+ "saving": "Saving...",
2424+ "creating": "Creating...",
2525+ "updating": "Updating...",
2626+ "sending": "Sending...",
2727+ "authenticating": "Authenticating...",
2828+ "checking": "Checking...",
2929+ "redirecting": "Redirecting...",
3030+3131+ "signIn": "Sign In",
3232+ "verify": "Verify",
3333+ "remove": "Remove",
3434+ "revoke": "Revoke",
3535+ "resendCode": "Resend Code",
3636+ "startOver": "Start Over",
3737+ "tryAgain": "Try Again",
3838+3939+ "password": "Password",
4040+ "email": "Email",
4141+ "emailAddress": "Email Address",
4242+ "handle": "Handle",
4343+ "did": "DID",
4444+ "verificationCode": "Verification Code",
4545+ "inviteCode": "Invite Code",
4646+ "newPassword": "New Password",
4747+ "confirmPassword": "Confirm Password",
4848+4949+ "enterSixDigitCode": "Enter 6-digit code",
5050+ "passwordHint": "At least 8 characters",
5151+ "enterPassword": "Enter your password",
5252+ "emailPlaceholder": "you@example.com",
5353+5454+ "verified": "Verified",
5555+ "disabled": "Disabled",
5656+ "available": "Available",
5757+ "deactivated": "Deactivated",
5858+ "unverified": "Unverified",
5959+6060+ "backToLogin": "Back to Login",
6161+ "backToSettings": "Back to Settings",
6262+ "alreadyHaveAccount": "Already have an account?",
6363+ "createAccount": "Create account",
6464+6565+ "passwordsMismatch": "Passwords do not match",
6666+ "passwordTooShort": "Password must be at least 8 characters"
2167 },
2268 "login": {
2369 "title": "Sign In",
···4995 "codeLabel": "Verification Code",
5096 "codePlaceholder": "Enter 6-digit code",
5197 "verifyButton": "Verify Account",
5252- "verifying": "Verifying...",
5353- "resendButton": "Resend Code",
5454- "resending": "Resending...",
5555- "resent": "Verification code resent!",
5656- "backToLogin": "Back to Login"
9898+ "resent": "Verification code resent!"
5799 },
58100 "register": {
59101 "title": "Create Account",
···124166 "inviteCodePlaceholder": "Enter your invite code",
125167 "inviteCodeRequired": "required",
126168 "createButton": "Create Account",
127127- "creating": "Creating account...",
128169 "alreadyHaveAccount": "Already have an account?",
129170 "signIn": "Sign in",
130171 "wantPasswordless": "Want passwordless security?",
···179220 "navAdminDesc": "Server stats and admin operations",
180221 "navDidDocument": "DID Document",
181222 "navDidDocumentDesc": "Manage your DID document for external migrations",
223223+ "navDidDocumentDescActive": "Edit your DID document settings",
224224+ "navBackup": "Download Backup",
225225+ "navBackupDesc": "Download your repository as a CAR file",
226226+ "downloadingBackup": "Downloading...",
227227+ "backupFailed": "Failed to download backup",
182228 "migrated": "Migrated",
183229 "migratedTitle": "Account Migrated",
184230 "migratedMessage": "Your account has migrated to {pds}. Your DID document is still hosted here, and you can update it for future migrations.",
···208254 "serviceEndpointDesc": "The PDS that currently hosts your account data. Update this when migrating.",
209255 "currentPds": "Current PDS URL",
210256 "save": "Save Changes",
211211- "saving": "Saving...",
212257 "success": "DID document updated successfully",
213258 "saveFailed": "Failed to save DID document",
214259 "loadFailed": "Failed to load DID document",
···246291 "yourDomain": "Your Domain",
247292 "yourDomainPlaceholder": "example.com",
248293 "verifyAndUpdate": "Verify & Update Handle",
249249- "verifying": "Verifying...",
250294 "newHandle": "New Handle",
251295 "newHandlePlaceholder": "yourhandle",
252296 "changeHandleButton": "Change Handle",
···262306 "exportData": "Export Data",
263307 "exportDataDescription": "Download your entire repository as a CAR (Content Addressable Archive) file. This includes all your posts, likes, follows, and other data.",
264308 "downloadRepo": "Download Repository",
309309+ "downloadBlobs": "Download Media",
265310 "exporting": "Exporting...",
311311+ "backups": {
312312+ "title": "Backups",
313313+ "description": "Your repository is automatically backed up daily. You can also create manual backups or restore from a previous backup.",
314314+ "enableAutomatic": "Enable automatic backups",
315315+ "enabled": "Automatic backups enabled",
316316+ "disabled": "Automatic backups disabled",
317317+ "toggleFailed": "Failed to update backup setting",
318318+ "noBackups": "No backups available yet.",
319319+ "blocks": "blocks",
320320+ "download": "Download",
321321+ "delete": "Delete",
322322+ "createNow": "Create Backup Now",
323323+ "created": "Backup created successfully",
324324+ "createFailed": "Failed to create backup",
325325+ "downloadFailed": "Failed to download backup",
326326+ "deleted": "Backup deleted",
327327+ "deleteFailed": "Failed to delete backup",
328328+ "restoreTitle": "Restore from Backup",
329329+ "restoreDescription": "Upload a CAR file to restore your repository. This will overwrite your current data.",
330330+ "selectFile": "Select CAR file",
331331+ "selectedFile": "Selected file",
332332+ "restore": "Restore",
333333+ "restoring": "Restoring...",
334334+ "restored": "Repository restored successfully",
335335+ "restoreFailed": "Failed to restore repository"
336336+ },
266337 "deleteAccount": "Delete Account",
267338 "deleteWarning": "This action is irreversible. All your data will be permanently deleted.",
268339 "requestDeletion": "Request Account Deletion",
···291362 "deleteConfirmation": "Are you absolutely sure you want to delete your account? This cannot be undone.",
292363 "deletionFailed": "Failed to delete account",
293364 "repoExported": "Repository exported successfully",
294294- "exportFailed": "Failed to export repository",
365365+ "blobsExported": "Media files exported successfully",
366366+ "noBlobsToExport": "No media files to export",
367367+ "exportFailed": "Failed to export",
295368 "confirmDelete": "Are you absolutely sure you want to delete your account? This cannot be undone."
296369 }
297370 },
···306379 "noPasswords": "No app passwords yet",
307380 "revoke": "Revoke",
308381 "revoking": "Revoking...",
309309- "creating": "Creating...",
310382 "revokeConfirm": "Revoke app password \"{name}\"? Apps using this password will no longer be able to access your account.",
311383 "saveWarningTitle": "Important: Save this app password!",
312384 "saveWarningMessage": "This password is required to sign into apps that don't support passkeys or OAuth. You will only see it once.",
···354426 "used": "Used by @{handle}",
355427 "disabled": "Disabled",
356428 "usedBy": "Used by",
357357- "creating": "Creating...",
358429 "disableConfirm": "Disable this invite code? It can no longer be used.",
359430 "created": "Invite Code Created",
360431 "copy": "Copy",
···482553 "verifyButton": "Verify",
483554 "verifyCodePlaceholder": "Enter verification code",
484555 "submit": "Submit",
485485- "saving": "Saving...",
486556 "savePreferences": "Save Preferences",
487557 "preferencesSaved": "Communication preferences saved",
488558 "verifiedSuccess": "{channel} verified successfully",
···521591 "noCollectionsYet": "No collections yet. Create your first record to get started.",
522592 "loadMore": "Load More",
523593 "recordJson": "Record JSON",
524524- "saving": "Saving...",
525594 "updateRecord": "Update Record",
526595 "collectionNsid": "Collection (NSID)",
527596 "recordKeyOptional": "Record Key (optional)",
528597 "autoGenerated": "Auto-generated if empty (TID)",
529598 "autoGeneratedHint": "Leave empty to auto-generate a TID-based key",
530530- "creating": "Creating...",
531599 "demoPostText": "Hello from my PDS! This is my first post.",
532600 "demoDisplayName": "Your Display Name",
533601 "demoBio": "A short bio about yourself."
···551619 "secondaryLight": "Secondary (Light Mode)",
552620 "secondaryDark": "Secondary (Dark Mode)",
553621 "configSaved": "Server configuration saved",
554554- "saving": "Saving...",
555622 "saveConfig": "Save Configuration",
556623 "serverStats": "Server Statistics",
557624 "users": "Users",
···639706 "title": "Two-Factor Authentication",
640707 "subtitle": "Additional verification is required",
641708 "usePasskey": "Use Passkey",
642642- "useTotp": "Use Authenticator App",
643643- "verifying": "Verifying..."
709709+ "useTotp": "Use Authenticator App"
644710 },
645711 "twoFactorCode": {
646712 "title": "Two-Factor Authentication",
647713 "subtitle": "A verification code has been sent to your {channel}. Enter the code below to continue.",
648714 "codeLabel": "Verification Code",
649715 "codePlaceholder": "Enter 6-digit code",
650650- "verify": "Verify",
651651- "verifying": "Verifying...",
652716 "errors": {
653717 "missingRequestUri": "Missing request_uri parameter",
654718 "verificationFailed": "Verification failed",
···660724 "title": "Enter Authenticator Code",
661725 "subtitle": "Enter the 6-digit code from your authenticator app",
662726 "codePlaceholder": "Enter 6-digit code",
663663- "verify": "Verify",
664664- "verifying": "Verifying...",
665727 "useBackupCode": "Use backup code instead",
666728 "backupCodePlaceholder": "Enter backup code",
667729 "trustDevice": "Trust this device for 30 days",
···691753 "codeLabel": "Verification Code",
692754 "codeHelp": "Copy the entire code from your message, including dashes",
693755 "verifyButton": "Verify Account",
694694- "verify": "Verify",
695695- "verifying": "Verifying...",
696756 "pleaseWait": "Please wait...",
697697- "resendCode": "Resend Code",
698698- "resending": "Resending...",
699699- "sending": "Sending...",
700757 "codeResent": "Verification code resent!",
701758 "codeResentDetail": "Verification code sent! Check your inbox.",
702702- "backToLogin": "Back to Login",
703703- "backToSettings": "Back to Settings",
704759 "verifyingAccount": "Verifying account: @{handle}",
705760 "startOver": "Start over with a different account",
706761 "noPending": "No pending verification found.",
···746801 "resetButton": "Reset Password",
747802 "resetting": "Resetting...",
748803 "success": "Password reset successfully!",
749749- "backToLogin": "Back to Sign In",
750804 "requestNewCode": "Request New Code",
751805 "passwordsMismatch": "Passwords do not match",
752806 "passwordLength": "Password must be at least 8 characters"
···790844 "howItWorks": "How it works",
791845 "howItWorksDetail": "We'll send a secure link to your registered notification channel. Click the link to set a temporary password. Then you can sign in and add a new passkey.",
792846 "sendRecoveryLink": "Send Recovery Link",
793793- "sending": "Sending...",
794794- "backToLogin": "Back to Sign In"
847847+ "sending": "Sending..."
795848 },
796849 "registerPasskey": {
797850 "title": "Create Passkey Account",
···814867 "inviteCode": "Invite Code",
815868 "inviteCodePlaceholder": "Enter your invite code",
816869 "createButton": "Create Account",
817817- "creating": "Creating...",
818870 "continue": "Continue",
819871 "back": "Back",
820872 "alreadyHaveAccount": "Already have an account?",
···911963 "useTotp": "Use Authenticator",
912964 "passwordPlaceholder": "Enter your password",
913965 "totpPlaceholder": "Enter 6-digit code",
914914- "verify": "Verify",
915915- "verifying": "Verifying...",
916966 "authenticating": "Authenticating...",
917967 "passkeyPrompt": "Click the button below to authenticate with your passkey.",
918968 "cancel": "Cancel"
···947997 "handle": "Handle",
948998 "emailOptional": "Email (optional)",
949999 "yourAccessLevel": "Your Access Level",
950950- "creating": "Creating...",
9511000 "createAccount": "Create Account",
9521001 "createDelegatedAccountButton": "+ Create Delegated Account",
9531002 "accountCreated": "Created delegated account: {handle}",
···10591108 "navDesc": "Move your account to or from another PDS",
10601109 "migrateHere": "Migrate Here",
10611110 "migrateHereDesc": "Move your existing AT Protocol account to this PDS from another server.",
10621062- "migrateAway": "Migrate Away",
10631063- "migrateAwayDesc": "Move your account from this PDS to another server.",
10641064- "loginRequired": "Login required",
10651111 "bringDid": "Bring your DID and identity",
10661112 "transferData": "Transfer all your data",
10671113 "keepFollowers": "Keep your followers",
10681068- "exportRepo": "Export your repository",
10691069- "transferToPds": "Transfer to new PDS",
10701070- "updateIdentity": "Update your identity",
10711114 "whatIsMigration": "What is account migration?",
10721115 "whatIsMigrationDesc": "Account migration allows you to move your AT Protocol identity between Personal Data Servers (PDSes). Your DID (decentralized identifier) stays the same, so your followers and social connections are preserved.",
10731116 "beforeMigrate": "Before you migrate",
···10771120 "beforeMigrate4": "Your old PDS will be notified to deactivate your account",
10781121 "importantWarning": "Account migration is a significant action. Make sure you trust the destination PDS and understand that your data will be moved. If something goes wrong, recovery may require manual intervention.",
10791122 "learnMore": "Learn more about migration risks",
10801080- "comingSoon": "Coming soon",
11231123+ "offlineRestore": "Offline Restore",
11241124+ "offlineRestoreDesc": "Restore from backup when your old PDS is unavailable.",
11251125+ "offlineFeature1": "Use a CAR file backup",
11261126+ "offlineFeature2": "Prove ownership with rotation key",
11271127+ "offlineFeature3": "Recovery for shutdown servers",
10811128 "oauthCompleting": "Completing authentication...",
10821129 "oauthFailed": "Authentication Failed",
10831130 "tryAgain": "Try Again",
···10861133 "incomplete": "You have an incomplete migration in progress:",
10871134 "direction": "Direction",
10881135 "migratingHere": "Migrating here",
10891089- "migratingAway": "Migrating away",
10901136 "from": "From",
10911137 "to": "To",
10921138 "progress": "Progress",
···12291275 "error": {
12301276 "title": "Migration Error",
12311277 "desc": "An error occurred during migration.",
12321232- "startOver": "Start Over"
12781278+ "startOver": "Start Over",
12791279+ "unknown": "An unknown error occurred."
12331280 },
12341281 "common": {
12351282 "back": "Back",
···12471294 "warning3": "Your old account will be deactivated after migration"
12481295 }
12491296 },
12501250- "outbound": {
12971297+ "offline": {
12511298 "welcome": {
12521252- "title": "Migrate Away from This PDS",
12531253- "desc": "Move your account to another Personal Data Server.",
12541254- "warning": "After migration, your account here will be deactivated.",
12551255- "didWebNotice": "did:web Migration Notice",
12561256- "didWebNoticeDesc": "Your account uses a did:web identifier ({did}). After migrating, this PDS will continue to serve your DID document pointing to the new PDS. Your identity will remain functional as long as this server is online.",
12571257- "understand": "I understand the risks and want to proceed"
12991299+ "title": "Offline Restore",
13001300+ "desc": "Restore your account when your old PDS is unavailable. This is for disaster recovery when you cannot contact your previous server.",
13011301+ "warningTitle": "Advanced Recovery Method",
13021302+ "warningDesc": "This method requires your rotation key private key. Only use this if your previous PDS has shut down or you cannot access it.",
13031303+ "requirementsTitle": "You will need:",
13041304+ "requirement1": "Your DID (did:plc:...)",
13051305+ "requirement2": "A CAR file backup of your repository",
13061306+ "requirement3": "Your rotation key (private key in hex, base58, or JWK format)",
13071307+ "understand": "I understand this is for offline recovery only"
12581308 },
12591259- "targetPds": {
12601260- "title": "Choose Target PDS",
12611261- "desc": "Enter the URL of the PDS you want to migrate to.",
12621262- "url": "PDS URL",
12631263- "urlPlaceholder": "https://pds.example.com",
12641264- "validate": "Validate & Continue",
13091309+ "provideDid": {
13101310+ "title": "Enter Your DID",
13111311+ "desc": "Enter the DID of the account you want to restore.",
13121312+ "label": "Your DID",
13131313+ "hint": "Your decentralized identifier (e.g., did:plc:abc123...)"
13141314+ },
13151315+ "uploadCar": {
13161316+ "title": "Upload Repository Backup",
13171317+ "desc": "Upload the CAR file containing your repository data.",
13181318+ "label": "CAR File",
13191319+ "hint": "This should be a .car file from a previous backup of your repository",
13201320+ "reuploadWarningTitle": "CAR File Required",
13211321+ "reuploadWarning": "Your session was restored, but you need to re-upload your CAR file. For security reasons, file contents are not stored between sessions."
13221322+ },
13231323+ "rotationKey": {
13241324+ "title": "Provide Rotation Key",
13251325+ "desc": "Enter your rotation key to prove ownership of this DID.",
13261326+ "securityWarningTitle": "Security Warning",
13271327+ "securityWarning1": "Your rotation key is extremely sensitive - anyone with it can take over your identity",
13281328+ "securityWarning2": "Only enter it on trusted devices and connections",
13291329+ "securityWarning3": "The key will not be stored after migration",
13301330+ "label": "Rotation Key",
13311331+ "placeholder": "Paste your rotation key (hex, base58, or JWK)...",
13321332+ "hint": "Supports 64-character hex, base58, or JWK format",
13331333+ "valid": "Rotation key verified! You have control of this DID.",
13341334+ "invalid": "This key is not a valid rotation key for this DID.",
12651335 "validating": "Validating...",
12661266- "connected": "Connected to {name}",
12671267- "inviteRequired": "Invite code required",
12681268- "privacyPolicy": "Privacy Policy",
12691269- "termsOfService": "Terms of Service"
13361336+ "validate": "Validate Key"
12701337 },
12711271- "newAccount": {
12721272- "title": "New Account Details",
12731273- "desc": "Set up your account on the new PDS.",
12741274- "handle": "Handle",
12751275- "availableDomains": "Available domains",
12761276- "email": "Email",
12771277- "password": "Password",
12781278- "confirmPassword": "Confirm Password",
12791279- "inviteCode": "Invite Code"
13381338+ "chooseHandle": {
13391339+ "migratingDid": "Restoring DID"
12801340 },
12811341 "review": {
12821282- "title": "Review Migration",
12831283- "desc": "Please review and confirm your migration details.",
12841284- "currentHandle": "Current Handle",
12851285- "newHandle": "New Handle",
12861286- "sourcePds": "This PDS",
12871287- "targetPds": "Target PDS",
12881288- "confirm": "I confirm I want to migrate my account",
12891289- "startMigration": "Start Migration"
13421342+ "desc": "Please confirm the details of your offline restoration.",
13431343+ "carFile": "CAR File",
13441344+ "rotationKey": "Rotation Key",
13451345+ "warning": "After you click \"Start Migration\", your repository will be imported and your DID will be updated to point to this PDS.",
13461346+ "plcWarningTitle": "Point of No Return",
13471347+ "plcWarning": "Once you start, your DID document will be updated to point to this PDS. If something goes wrong, you can use your rotation key to recover, but you should complete the migration to avoid a broken identity state."
12901348 },
12911349 "migrating": {
12921292- "title": "Migrating Your Account",
12931293- "desc": "Please wait while we transfer your data..."
12941294- },
12951295- "plcToken": {
12961296- "title": "Verify Your Identity",
12971297- "desc": "A verification code has been sent to your email."
13501350+ "title": "Restoring Account",
13511351+ "desc": "Please wait while your account is being restored...",
13521352+ "creating": "Creating account",
13531353+ "importing": "Importing repository",
13541354+ "plcSigning": "Signing identity update",
13551355+ "activating": "Activating account"
12981356 },
12991299- "finalizing": {
13001300- "title": "Finalizing Migration",
13011301- "desc": "Please wait while we complete the migration...",
13021302- "updatingForwarding": "Updating DID document forwarding..."
13571357+ "blobs": {
13581358+ "title": "Migrating Blobs",
13591359+ "desc": "Attempting to recover images and media from your old PDS...",
13601360+ "migrating": "Migrating blobs",
13611361+ "failedTitle": "Some blobs could not be migrated",
13621362+ "failedDesc": "{count} blobs could not be fetched from your old PDS. This may happen if the server is unreachable or the files were deleted.",
13631363+ "sourceUnreachableTitle": "Source PDS Unreachable",
13641364+ "sourceUnreachable": "Could not connect to your old PDS to fetch media files. This is common when migrating from a shut-down server. Your posts will work, but some images may be missing."
13031365 },
13041366 "success": {
13051305- "title": "Migration Complete!",
13061306- "desc": "Your account has been successfully migrated to your new PDS.",
13071307- "newHandle": "New Handle",
13081308- "newPds": "New PDS",
13091309- "nextSteps": "Next Steps",
13101310- "nextSteps1": "Sign in to your new PDS",
13111311- "nextSteps2": "Update any apps with your new credentials",
13121312- "nextSteps3": "Your followers will automatically see your new location",
13131313- "loggingOut": "Logging you out in {seconds} seconds..."
13671367+ "desc": "Your account has been successfully restored to this PDS."
13141368 }
13151369 },
13161370 "progress": {
···1717 "dashboard": "Kontrollpanel",
1818 "backToDashboard": "← Kontrollpanel",
1919 "copied": "Kopierat!",
2020- "copyToClipboard": "Kopiera"
2020+ "copyToClipboard": "Kopiera",
2121+ "verifying": "Verifierar...",
2222+ "saving": "Sparar...",
2323+ "creating": "Skapar...",
2424+ "updating": "Uppdaterar...",
2525+ "sending": "Skickar...",
2626+ "authenticating": "Autentiserar...",
2727+ "checking": "Kontrollerar...",
2828+ "redirecting": "Omdirigerar...",
2929+ "signIn": "Logga in",
3030+ "verify": "Verifiera",
3131+ "remove": "Ta bort",
3232+ "revoke": "Återkalla",
3333+ "resendCode": "Skicka kod igen",
3434+ "startOver": "Börja om",
3535+ "tryAgain": "Försök igen",
3636+ "password": "Lösenord",
3737+ "email": "E-post",
3838+ "emailAddress": "E-postadress",
3939+ "handle": "Användarnamn",
4040+ "did": "DID",
4141+ "verificationCode": "Verifieringskod",
4242+ "inviteCode": "Inbjudningskod",
4343+ "newPassword": "Nytt lösenord",
4444+ "confirmPassword": "Bekräfta lösenord",
4545+ "enterSixDigitCode": "Ange 6-siffrig kod",
4646+ "passwordHint": "Minst 8 tecken",
4747+ "enterPassword": "Ange ditt lösenord",
4848+ "emailPlaceholder": "du@exempel.se",
4949+ "verified": "Verifierad",
5050+ "disabled": "Inaktiverad",
5151+ "available": "Tillgänglig",
5252+ "deactivated": "Avaktiverad",
5353+ "unverified": "Overifierad",
5454+ "backToLogin": "Tillbaka till inloggning",
5555+ "backToSettings": "Tillbaka till inställningar",
5656+ "alreadyHaveAccount": "Har du redan ett konto?",
5757+ "createAccount": "Skapa konto",
5858+ "passwordsMismatch": "Lösenorden matchar inte",
5959+ "passwordTooShort": "Lösenordet måste vara minst 8 tecken"
2160 },
2261 "login": {
2362 "title": "Logga in",
···4988 "codeLabel": "Verifieringskod",
5089 "codePlaceholder": "Ange 6-siffrig kod",
5190 "verifyButton": "Verifiera konto",
5252- "verifying": "Verifierar...",
5353- "resendButton": "Skicka kod igen",
5454- "resending": "Skickar igen...",
5555- "resent": "Verifieringskod skickad igen!",
5656- "backToLogin": "Tillbaka till inloggning"
9191+ "resent": "Verifieringskod skickad igen!"
5792 },
5893 "register": {
5994 "title": "Skapa konto",
···124159 "inviteCodePlaceholder": "Ange din inbjudningskod",
125160 "inviteCodeRequired": "krävs",
126161 "createButton": "Skapa konto",
127127- "creating": "Skapar konto...",
128162 "alreadyHaveAccount": "Har du redan ett konto?",
129163 "signIn": "Logga in",
130164 "wantPasswordless": "Vill du ha lösenordsfri säkerhet?",
···179213 "navAdminDesc": "Serverstatistik och administratörsoperationer",
180214 "navDidDocument": "DID-dokument",
181215 "navDidDocumentDesc": "Hantera ditt DID-dokument och nycklar",
216216+ "navDidDocumentDescActive": "Redigera dina DID-dokumentinställningar",
217217+ "navBackup": "Ladda ner säkerhetskopia",
218218+ "navBackupDesc": "Ladda ner ditt dataförvar som en CAR-fil",
219219+ "downloadingBackup": "Laddar ner...",
220220+ "backupFailed": "Kunde inte ladda ner säkerhetskopia",
182221 "migrated": "Flyttad",
183222 "migratedTitle": "Konto flyttat",
184223 "migratedMessage": "Ditt konto har flyttats till {pds}. Ditt DID-dokument finns fortfarande här.",
···208247 "serviceEndpointDesc": "PDS som för närvarande lagrar din kontodata. Uppdatera detta vid migrering.",
209248 "currentPds": "Nuvarande PDS-URL",
210249 "save": "Spara ändringar",
211211- "saving": "Sparar...",
212250 "success": "DID-dokumentet har uppdaterats",
213251 "saveFailed": "Kunde inte spara DID-dokument",
214252 "loadFailed": "Kunde inte ladda DID-dokument",
···246284 "yourDomain": "Din domän",
247285 "yourDomainPlaceholder": "exempel.se",
248286 "verifyAndUpdate": "Verifiera och uppdatera användarnamn",
249249- "verifying": "Verifierar...",
250287 "newHandle": "Nytt användarnamn",
251288 "newHandlePlaceholder": "dittanvändarnamn",
252289 "changeHandleButton": "Ändra användarnamn",
···262299 "exportData": "Exportera data",
263300 "exportDataDescription": "Ladda ner hela ditt arkiv som en CAR-fil (Content Addressable Archive). Detta inkluderar alla dina inlägg, gillanden, följningar och annan data.",
264301 "downloadRepo": "Ladda ner arkiv",
302302+ "downloadBlobs": "Ladda ner media",
265303 "exporting": "Exporterar...",
304304+ "backups": {
305305+ "title": "Säkerhetskopior",
306306+ "description": "Hantera automatiska säkerhetskopior och återställ din kontodata. Säkerhetskopior inkluderar alla poster och blobbar.",
307307+ "enableAutomatic": "Automatiska säkerhetskopior",
308308+ "enabled": "Aktiverad",
309309+ "disabled": "Inaktiverad",
310310+ "toggleFailed": "Kunde inte ändra säkerhetskopieringsinställning",
311311+ "noBackups": "Inga säkerhetskopior ännu",
312312+ "blocks": "block",
313313+ "download": "Ladda ner",
314314+ "delete": "Radera",
315315+ "createNow": "Skapa säkerhetskopia nu",
316316+ "created": "Säkerhetskopia skapad",
317317+ "createFailed": "Kunde inte skapa säkerhetskopia",
318318+ "downloadFailed": "Kunde inte ladda ner säkerhetskopia",
319319+ "deleted": "Säkerhetskopia raderad",
320320+ "deleteFailed": "Kunde inte radera säkerhetskopia",
321321+ "restoreTitle": "Återställ från säkerhetskopia",
322322+ "restoreDescription": "Återställ din kontodata från en tidigare exporterad CAR-fil. Detta ersätter ditt nuvarande dataförvar med den uppladdade säkerhetskopian.",
323323+ "selectFile": "Välj CAR-fil",
324324+ "selectedFile": "Vald fil",
325325+ "restore": "Återställ säkerhetskopia",
326326+ "restoring": "Återställer...",
327327+ "restored": "Säkerhetskopia återställd",
328328+ "restoreFailed": "Kunde inte återställa säkerhetskopia"
329329+ },
266330 "deleteAccount": "Radera konto",
267331 "deleteWarning": "Denna åtgärd är oåterkallelig. All din data kommer att raderas permanent.",
268332 "requestDeletion": "Begär kontoradering",
···291355 "deleteConfirmation": "Är du helt säker på att du vill radera ditt konto? Detta kan inte ångras.",
292356 "deletionFailed": "Kunde inte radera kontot",
293357 "repoExported": "Arkiv exporterat",
294294- "exportFailed": "Kunde inte exportera arkiv",
358358+ "blobsExported": "Mediafiler exporterade",
359359+ "noBlobsToExport": "Inga mediafiler att exportera",
360360+ "exportFailed": "Export misslyckades",
295361 "confirmDelete": "Är du helt säker på att du vill radera ditt konto? Detta kan inte ångras."
296362 }
297363 },
···306372 "noPasswords": "Inga applösenord ännu",
307373 "revoke": "Återkalla",
308374 "revoking": "Återkallar...",
309309- "creating": "Skapar...",
310375 "revokeConfirm": "Återkalla applösenord \"{name}\"? Appar som använder detta lösenord kommer inte längre att kunna komma åt ditt konto.",
311376 "saveWarningTitle": "Viktigt: Spara detta applösenord!",
312377 "saveWarningMessage": "Detta lösenord krävs för att logga in i appar som inte stöder passkeys eller OAuth. Du ser det bara en gång.",
···354419 "used": "Använd av @{handle}",
355420 "disabled": "Inaktiverad",
356421 "usedBy": "Använd av",
357357- "creating": "Skapar...",
358422 "disableConfirm": "Inaktivera denna inbjudningskod? Den kan inte längre användas.",
359423 "created": "Inbjudningskod skapad",
360424 "copy": "Kopiera",
···482546 "verifyButton": "Verifiera",
483547 "verifyCodePlaceholder": "Ange verifieringskod",
484548 "submit": "Skicka",
485485- "saving": "Sparar...",
486549 "savePreferences": "Spara inställningar",
487550 "preferencesSaved": "Kommunikationsinställningar sparade",
488551 "verifiedSuccess": "{channel} verifierad",
···521584 "noCollectionsYet": "Inga samlingar ännu. Skapa din första post för att komma igång.",
522585 "loadMore": "Ladda fler",
523586 "recordJson": "Post-JSON",
524524- "saving": "Sparar...",
525587 "updateRecord": "Uppdatera post",
526588 "collectionNsid": "Samling (NSID)",
527589 "recordKeyOptional": "Postnyckel (valfri)",
528590 "autoGenerated": "Genereras automatiskt om tom (TID)",
529591 "autoGeneratedHint": "Lämna tom för att automatiskt generera en TID-baserad nyckel",
530530- "creating": "Skapar...",
531592 "demoPostText": "Hej från min PDS! Detta är mitt första inlägg.",
532593 "demoDisplayName": "Ditt visningsnamn",
533594 "demoBio": "En kort presentation om dig själv."
···548609 "primaryLight": "Primär (ljust läge)",
549610 "primaryDark": "Primär (mörkt läge)",
550611 "configSaved": "Serverkonfiguration sparad",
551551- "saving": "Sparar...",
552612 "saveConfig": "Spara konfiguration",
553613 "serverStats": "Serverstatistik",
554614 "users": "Användare",
···639699 "title": "Tvåfaktorsautentisering",
640700 "subtitle": "Ytterligare verifiering krävs",
641701 "usePasskey": "Använd nyckel",
642642- "useTotp": "Använd autentiseringsapp",
643643- "verifying": "Verifierar..."
702702+ "useTotp": "Använd autentiseringsapp"
644703 },
645704 "twoFactorCode": {
646705 "title": "Tvåfaktorsautentisering",
647706 "subtitle": "En verifieringskod har skickats till din {channel}. Ange koden nedan för att fortsätta.",
648707 "codeLabel": "Verifieringskod",
649708 "codePlaceholder": "Ange 6-siffrig kod",
650650- "verify": "Verifiera",
651651- "verifying": "Verifierar...",
652709 "errors": {
653710 "missingRequestUri": "Saknar request_uri-parameter",
654711 "verificationFailed": "Verifiering misslyckades",
···660717 "title": "Ange autentiseringskod",
661718 "subtitle": "Ange den 6-siffriga koden från din autentiseringsapp",
662719 "codePlaceholder": "Ange 6-siffrig kod",
663663- "verify": "Verifiera",
664664- "verifying": "Verifierar...",
665720 "useBackupCode": "Använd reservkod istället",
666721 "backupCodePlaceholder": "Ange reservkod",
667722 "trustDevice": "Lita på denna enhet i 30 dagar",
···691746 "codeLabel": "Verifieringskod",
692747 "codeHelp": "Kopiera hela koden från ditt meddelande, inklusive bindestreck",
693748 "verifyButton": "Verifiera konto",
694694- "verify": "Verifiera",
695695- "verifying": "Verifierar...",
696749 "pleaseWait": "Vänta...",
697697- "sending": "Skickar...",
698698- "resendCode": "Skicka kod igen",
699699- "resending": "Skickar igen...",
700750 "codeResent": "Verifieringskod skickad igen!",
701751 "codeResentDetail": "Verifieringskod skickad! Kontrollera din inkorg.",
702752 "verified": "Verifierad!",
···706756 "identifierLabel": "E-post eller identifierare",
707757 "identifierPlaceholder": "du@exempel.se",
708758 "identifierHelp": "E-postadressen eller identifieraren koden skickades till",
709709- "backToLogin": "Tillbaka till inloggning",
710759 "verifyingAccount": "Verifierar konto: @{handle}",
711760 "startOver": "Börja om med ett annat konto",
712761 "noPending": "Ingen väntande verifiering hittades.",
713762 "noPendingInfo": "Om du nyligen skapade ett konto och behöver verifiera det kan du behöva skapa ett nytt konto. Om du redan verifierat ditt konto kan du logga in.",
714763 "createAccount": "Skapa konto",
715764 "signIn": "Logga in",
716716- "backToSettings": "Tillbaka till inställningar",
717765 "emailUpdateCodeHelp": "Koden skickades till din nuvarande e-postadress",
718766 "emailUpdateFailed": "Kunde inte uppdatera e-postadress",
719767 "emailUpdateRequiresAuth": "Du måste vara inloggad för att uppdatera din e-postadress.",
···746794 "resetButton": "Återställ lösenord",
747795 "resetting": "Återställer...",
748796 "success": "Lösenord återställt!",
749749- "backToLogin": "Tillbaka till inloggning",
750797 "requestNewCode": "Begär ny kod",
751798 "passwordsMismatch": "Lösenorden matchar inte",
752799 "passwordLength": "Lösenordet måste vara minst 8 tecken"
···790837 "howItWorks": "Så fungerar det",
791838 "howItWorksDetail": "Vi skickar en säker länk till din registrerade meddelandekanal. Klicka på länken för att ställa in ett tillfälligt lösenord. Sedan kan du logga in och lägga till en ny nyckel.",
792839 "sendRecoveryLink": "Skicka återställningslänk",
793793- "sending": "Skickar...",
794794- "backToLogin": "Tillbaka till inloggning"
840840+ "sending": "Skickar..."
795841 },
796842 "registerPasskey": {
797843 "title": "Skapa nyckelkonto",
···812858 "externalDid": "Din did:web",
813859 "externalDidPlaceholder": "did:web:dindomän.se",
814860 "createButton": "Skapa konto",
815815- "creating": "Skapar...",
816861 "alreadyHaveAccount": "Har du redan ett konto?",
817862 "signIn": "Logga in",
818863 "wantPassword": "Vill du använda ett lösenord?",
···911956 "useTotp": "Använd autentiserare",
912957 "passwordPlaceholder": "Ange ditt lösenord",
913958 "totpPlaceholder": "Ange 6-siffrig kod",
914914- "verify": "Verifiera",
915915- "verifying": "Verifierar...",
916959 "authenticating": "Autentiserar...",
917960 "passkeyPrompt": "Klicka på knappen nedan för att autentisera med din passkey.",
918961 "cancel": "Avbryt"
···9851028 "createAccount": "Skapa konto",
9861029 "createDelegatedAccount": "Skapa delegerat konto",
9871030 "createDelegatedAccountButton": "+ Skapa delegerat konto",
988988- "creating": "Skapar...",
9891031 "emailOptional": "E-post (valfritt)",
9901032 "failedToAddController": "Kunde inte lägga till kontrollant",
9911033 "failedToCreateAccount": "Kunde inte skapa delegerat konto",
···10591101 "navDesc": "Flytta ditt konto till eller från en annan PDS",
10601102 "migrateHere": "Flytta hit",
10611103 "migrateHereDesc": "Flytta ditt befintliga AT Protocol-konto till denna PDS från en annan server.",
10621062- "migrateAway": "Flytta bort",
10631063- "migrateAwayDesc": "Flytta ditt konto från denna PDS till en annan server.",
10641064- "loginRequired": "Inloggning krävs",
10651104 "bringDid": "Ta med din DID och identitet",
10661105 "transferData": "Överför all din data",
10671106 "keepFollowers": "Behåll dina följare",
10681068- "exportRepo": "Exportera ditt arkiv",
10691069- "transferToPds": "Överför till ny PDS",
10701070- "updateIdentity": "Uppdatera din identitet",
10711107 "whatIsMigration": "Vad är kontoflyttning?",
10721108 "whatIsMigrationDesc": "Kontoflyttning låter dig flytta din AT Protocol-identitet mellan personliga dataservrar (PDS). Din DID (decentraliserad identifierare) förblir densamma, så dina följare och sociala kopplingar bevaras.",
10731109 "beforeMigrate": "Innan du flyttar",
···10771113 "beforeMigrate4": "Din gamla PDS kommer att meddelas om kontoinaktivering",
10781114 "importantWarning": "Kontoflyttning är en betydande åtgärd. Se till att du litar på mål-PDS och förstår att din data kommer att flyttas. Om något går fel kan manuell återställning krävas.",
10791115 "learnMore": "Läs mer om flyttningsrisker",
10801080- "comingSoon": "Kommer snart",
11161116+ "offlineRestore": "Offline-återställning",
11171117+ "offlineRestoreDesc": "Återställ från backup när din gamla PDS inte är tillgänglig.",
11181118+ "offlineFeature1": "Använd en CAR-fil backup",
11191119+ "offlineFeature2": "Bevisa ägande med rotationsnyckel",
11201120+ "offlineFeature3": "Återställning för nedstängda servrar",
10811121 "oauthCompleting": "Slutför autentisering...",
10821122 "oauthFailed": "Autentisering misslyckades",
10831123 "tryAgain": "Försök igen",
···10861126 "incomplete": "Du har en ofullständig flytt pågående:",
10871127 "direction": "Riktning",
10881128 "migratingHere": "Flyttar hit",
10891089- "migratingAway": "Flyttar bort",
10901129 "from": "Från",
10911130 "to": "Till",
10921131 "progress": "Framsteg",
···12291268 "error": {
12301269 "title": "Flyttfel",
12311270 "desc": "Ett fel uppstod under flytten.",
12321232- "startOver": "Börja om"
12711271+ "startOver": "Börja om",
12721272+ "unknown": "Ett okänt fel uppstod."
12331273 },
12341274 "common": {
12351275 "back": "Tillbaka",
···12471287 "warning3": "Ditt gamla konto kommer att inaktiveras efter flytten"
12481288 }
12491289 },
12501250- "outbound": {
12901290+ "offline": {
12511291 "welcome": {
12521252- "title": "Flytta från denna PDS",
12531253- "desc": "Flytta ditt konto till en annan personlig dataserver.",
12541254- "warning": "Efter flytten kommer ditt konto här att inaktiveras.",
12551255- "didWebNotice": "did:web-flyttmeddelande",
12561256- "didWebNoticeDesc": "Ditt konto använder en did:web-identifierare ({did}). Efter flytten kommer denna PDS att fortsätta servera ditt DID-dokument som pekar till den nya PDS. Din identitet kommer att fungera så länge denna server är online.",
12571257- "understand": "Jag förstår riskerna och vill fortsätta"
12921292+ "title": "Återställ från backup",
12931293+ "desc": "Återställ ditt konto med en CAR-fil backup och rotationsnyckel. Använd detta när din tidigare PDS inte är tillgänglig.",
12941294+ "warningTitle": "När du ska använda denna metod",
12951295+ "warningDesc": "Denna offline-återställning är för katastrofåterställning när din gamla PDS har stängts ner, är oåtkomlig eller du blev utelåst. Om din gamla PDS fortfarande är tillgänglig, använd standardflytten istället.",
12961296+ "requirementsTitle": "Du behöver",
12971297+ "requirement1": "En CAR-fil backup av ditt arkiv",
12981298+ "requirement2": "Din rotationsnyckel (privat nyckel för ditt DID)",
12991299+ "requirement3": "Ditt DID (did:plc:xxx)",
13001300+ "understand": "Jag förstår och vill fortsätta"
12581301 },
12591259- "targetPds": {
12601260- "title": "Välj mål-PDS",
12611261- "desc": "Ange URL:en för PDS du vill flytta till.",
12621262- "url": "PDS URL",
12631263- "urlPlaceholder": "https://pds.example.com",
12641264- "validate": "Validera och fortsätt",
12651265- "validating": "Validerar...",
12661266- "connected": "Ansluten till {name}",
12671267- "inviteRequired": "Inbjudningskod krävs",
12681268- "privacyPolicy": "Integritetspolicy",
12691269- "termsOfService": "Användarvillkor"
13021302+ "provideDid": {
13031303+ "title": "Ange ditt DID",
13041304+ "desc": "Ange DID för kontot du vill återställa.",
13051305+ "label": "Ditt DID",
13061306+ "hint": "Din decentraliserade identifierare (t.ex. did:plc:abc123)"
12701307 },
12711271- "newAccount": {
12721272- "title": "Nya kontouppgifter",
12731273- "desc": "Konfigurera ditt konto på den nya PDS.",
12741274- "handle": "Användarnamn",
12751275- "availableDomains": "Tillgängliga domäner",
12761276- "email": "E-post",
12771277- "password": "Lösenord",
12781278- "confirmPassword": "Bekräfta lösenord",
12791279- "inviteCode": "Inbjudningskod"
13081308+ "uploadCar": {
13091309+ "title": "Ladda upp CAR-fil",
13101310+ "desc": "Ladda upp din arkiv-backupfil.",
13111311+ "label": "CAR-fil",
13121312+ "hint": "Välj .car-filen från din backup",
13131313+ "reuploadWarningTitle": "CAR-fil krävs",
13141314+ "reuploadWarning": "Din session har återställts, men du måste ladda upp din CAR-fil igen. Av säkerhetsskäl lagras inte filinnehåll mellan sessioner."
12801315 },
12811281- "review": {
12821282- "title": "Granska flytt",
12831283- "desc": "Granska och bekräfta dina flyttdetaljer.",
12841284- "currentHandle": "Nuvarande användarnamn",
12851285- "newHandle": "Nytt användarnamn",
12861286- "sourcePds": "Denna PDS",
12871287- "targetPds": "Mål-PDS",
12881288- "confirm": "Jag bekräftar att jag vill flytta mitt konto",
12891289- "startMigration": "Starta flytt"
13161316+ "rotationKey": {
13171317+ "title": "Ange rotationsnyckel",
13181318+ "desc": "Ange din rotationsnyckel för att bevisa ägande av detta DID.",
13191319+ "securityWarningTitle": "Säkerhetsvarning",
13201320+ "securityWarning1": "Din rotationsnyckel är extremt känslig - behandla den som ett huvudlösenord",
13211321+ "securityWarning2": "Ange den endast på betrodda enheter och nätverk",
13221322+ "securityWarning3": "Denna nyckel kommer inte att lagras efter att flytten slutförts",
13231323+ "label": "Rotationsnyckel",
13241324+ "placeholder": "Ange privat nyckel (hex, base58 eller JWK)",
13251325+ "hint": "Den privata nyckeln som motsvarar en av rotationsnycklarna i ditt DID-dokument",
13261326+ "valid": "Nyckeln är giltig och matchar en rotationsnyckel i ditt DID",
13271327+ "invalid": "Nyckeln matchar inte någon rotationsnyckel i ditt DID-dokument",
13281328+ "validating": "Validerar nyckel...",
13291329+ "validate": "Validera nyckel"
12901330 },
12911291- "migrating": {
12921292- "title": "Flyttar ditt konto",
12931293- "desc": "Vänta medan vi överför din data..."
13311331+ "chooseHandle": {
13321332+ "migratingDid": "Återställer DID"
12941333 },
12951295- "plcToken": {
12961296- "title": "Verifiera din identitet",
12971297- "desc": "En verifieringskod har skickats till din e-post."
13341334+ "review": {
13351335+ "desc": "Granska dina offline-återställningsuppgifter.",
13361336+ "carFile": "CAR-fil",
13371337+ "rotationKey": "Rotationsnyckel",
13381338+ "warning": "När du startar återställningen kommer din identitet att uppdateras för att peka på denna PDS. Detta kan inte enkelt ångras.",
13391339+ "plcWarningTitle": "Ingen återvändo",
13401340+ "plcWarning": "När du startar kommer ditt DID-dokument att uppdateras för att peka på denna PDS. Om något går fel kan du använda din rotationsnyckel för att återställa, men du bör slutföra flytten för att undvika ett trasigt identitetstillstånd."
12981341 },
12991299- "finalizing": {
13001300- "title": "Slutför flytt",
13011301- "desc": "Vänta medan vi slutför flytten...",
13021302- "updatingForwarding": "Uppdaterar DID-dokumentvidarebefordran..."
13421342+ "migrating": {
13431343+ "title": "Återställer konto",
13441344+ "desc": "Vänta medan ditt konto återställs...",
13451345+ "creating": "Skapar konto",
13461346+ "importing": "Importerar arkiv",
13471347+ "plcSigning": "Uppdaterar identitet",
13481348+ "activating": "Aktiverar konto"
13031349 },
13041350 "success": {
13051305- "title": "Flytt klar!",
13061306- "desc": "Ditt konto har framgångsrikt flyttats till din nya PDS.",
13071307- "newHandle": "Nytt användarnamn",
13081308- "newPds": "Ny PDS",
13091309- "nextSteps": "Nästa steg",
13101310- "nextSteps1": "Logga in på din nya PDS",
13111311- "nextSteps2": "Uppdatera dina appar med nya uppgifter",
13121312- "nextSteps3": "Dina följare kommer automatiskt se din nya plats",
13131313- "loggingOut": "Loggar ut om {seconds} sekunder..."
13511351+ "desc": "Ditt konto har framgångsrikt återställts till denna PDS."
13521352+ },
13531353+ "blobs": {
13541354+ "title": "Flyttar blobbar",
13551355+ "desc": "Försöker återställa bilder och media från din gamla PDS...",
13561356+ "migrating": "Flyttar blobbar",
13571357+ "failedTitle": "Vissa blobbar kunde inte flyttas",
13581358+ "failedDesc": "{count} blobbar kunde inte hämtas från din gamla PDS. Detta kan hända om servern är otillgänglig eller om filerna raderades.",
13591359+ "sourceUnreachableTitle": "Käll-PDS otillgänglig",
13601360+ "sourceUnreachable": "Kunde inte ansluta till din gamla PDS för att hämta mediafiler. Detta är vanligt vid flytt från en nedstängd server. Dina inlägg kommer att fungera, men vissa bilder kan saknas."
13141361 }
13151362 },
13161363 "progress": {
···183183 <h3>Delegate without sharing passwords</h3>
184184 <p>Let team members or tools manage your account with specific permission levels. They authenticate with their own credentials, you see everything they do in an audit log.</p>
185185 </div>
186186+187187+ <div class="feature">
188188+ <h3>Automatic backups</h3>
189189+ <p>Your repository is backed up daily to object storage. Download any backup or restore with one click. You own your data, even if the worst happens.</p>
190190+ </div>
186191 </div>
187192188193 <h2>Everything in one place</h2>
···11+ALTER TABLE users ADD COLUMN backup_enabled BOOLEAN NOT NULL DEFAULT TRUE;
22+33+CREATE TABLE account_backups (
44+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
55+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
66+ storage_key TEXT NOT NULL,
77+ repo_root_cid TEXT NOT NULL,
88+ repo_rev TEXT NOT NULL,
99+ block_count INT NOT NULL,
1010+ size_bytes BIGINT NOT NULL,
1111+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
1212+);
1313+1414+CREATE INDEX idx_account_backups_user_id ON account_backups(user_id);
1515+CREATE INDEX idx_account_backups_created_at ON account_backups(created_at);
···312312 r#"
313313 SELECT rb.blob_cid, rb.record_uri
314314 FROM record_blobs rb
315315- LEFT JOIN blobs b ON rb.blob_cid = b.cid AND b.created_by_user = rb.repo_id
315315+ LEFT JOIN blobs b ON rb.blob_cid = b.cid
316316 WHERE rb.repo_id = $1 AND b.cid IS NULL AND rb.blob_cid > $2
317317 ORDER BY rb.blob_cid
318318 LIMIT $3