···33 "dev": "deno run -A npm:vite",
44 "build": "deno run -A npm:vite build",
55 "preview": "deno run -A npm:vite preview",
66+ "check": "deno run -A npm:svelte-check --tsconfig ./tsconfig.json",
67 "test": "deno run -A npm:vitest",
78 "test:run": "deno run -A npm:vitest run",
89 "test:watch": "deno run -A npm:vitest watch",
···11-declare const __brand: unique symbol
11+declare const __brand: unique symbol;
2233-type Brand<T, B extends string> = T & { readonly [__brand]: B }
33+type Brand<T, B extends string> = T & { readonly [__brand]: B };
4455-export type Did = Brand<string, 'Did'>
66-export type DidPlc = Brand<Did, 'DidPlc'>
77-export type DidWeb = Brand<Did, 'DidWeb'>
55+export type Did = Brand<string, "Did">;
66+export type DidPlc = Brand<Did, "DidPlc">;
77+export type DidWeb = Brand<Did, "DidWeb">;
8899-export type Handle = Brand<string, 'Handle'>
1010-export type AccessToken = Brand<string, 'AccessToken'>
1111-export type RefreshToken = Brand<string, 'RefreshToken'>
1212-export type ServiceToken = Brand<string, 'ServiceToken'>
1313-export type SetupToken = Brand<string, 'SetupToken'>
99+export type Handle = Brand<string, "Handle">;
1010+export type AccessToken = Brand<string, "AccessToken">;
1111+export type RefreshToken = Brand<string, "RefreshToken">;
1212+export type ServiceToken = Brand<string, "ServiceToken">;
1313+export type SetupToken = Brand<string, "SetupToken">;
14141515-export type Cid = Brand<string, 'Cid'>
1616-export type Rkey = Brand<string, 'Rkey'>
1717-export type AtUri = Brand<string, 'AtUri'>
1818-export type Nsid = Brand<string, 'Nsid'>
1515+export type Cid = Brand<string, "Cid">;
1616+export type Rkey = Brand<string, "Rkey">;
1717+export type AtUri = Brand<string, "AtUri">;
1818+export type Nsid = Brand<string, "Nsid">;
19192020-export type ISODateString = Brand<string, 'ISODateString'>
2121-export type EmailAddress = Brand<string, 'EmailAddress'>
2222-export type InviteCode = Brand<string, 'InviteCode'>
2020+export type ISODateString = Brand<string, "ISODateString">;
2121+export type EmailAddress = Brand<string, "EmailAddress">;
2222+export type InviteCode = Brand<string, "InviteCode">;
23232424-export type PublicKeyMultibase = Brand<string, 'PublicKeyMultibase'>
2525-export type DidKeyString = Brand<string, 'DidKeyString'>
2424+export type PublicKeyMultibase = Brand<string, "PublicKeyMultibase">;
2525+export type DidKeyString = Brand<string, "DidKeyString">;
26262727-const DID_PLC_REGEX = /^did:plc:[a-z2-7]{24}$/
2828-const DID_WEB_REGEX = /^did:web:.+$/
2929-const HANDLE_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/
3030-const AT_URI_REGEX = /^at:\/\/[^/]+\/[^/]+\/[^/]+$/
3131-const CID_REGEX = /^[a-z2-7]{59}$|^baf[a-z2-7]+$/
3232-const NSID_REGEX = /^[a-z]([a-z0-9-]*[a-z0-9])?(\.[a-z]([a-z0-9-]*[a-z0-9])?)+$/
3333-const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
3434-const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/
2727+const DID_PLC_REGEX = /^did:plc:[a-z2-7]{24}$/;
2828+const DID_WEB_REGEX = /^did:web:.+$/;
2929+const HANDLE_REGEX =
3030+ /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/;
3131+const AT_URI_REGEX = /^at:\/\/[^/]+\/[^/]+\/[^/]+$/;
3232+const CID_REGEX = /^[a-z2-7]{59}$|^baf[a-z2-7]+$/;
3333+const NSID_REGEX =
3434+ /^[a-z]([a-z0-9-]*[a-z0-9])?(\.[a-z]([a-z0-9-]*[a-z0-9])?)+$/;
3535+const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3636+const ISO_DATE_REGEX =
3737+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
35383639export function isDid(s: string): s is Did {
3737- return s.startsWith('did:plc:') || s.startsWith('did:web:')
4040+ return s.startsWith("did:plc:") || s.startsWith("did:web:");
3841}
39424043export function isDidPlc(s: string): s is DidPlc {
4141- return DID_PLC_REGEX.test(s)
4444+ return DID_PLC_REGEX.test(s);
4245}
43464447export function isDidWeb(s: string): s is DidWeb {
4545- return DID_WEB_REGEX.test(s)
4848+ return DID_WEB_REGEX.test(s);
4649}
47504851export function isHandle(s: string): s is Handle {
4949- return HANDLE_REGEX.test(s) && s.length <= 253
5252+ return HANDLE_REGEX.test(s) && s.length <= 253;
5053}
51545255export function isAtUri(s: string): s is AtUri {
5353- return AT_URI_REGEX.test(s)
5656+ return AT_URI_REGEX.test(s);
5457}
55585659export function isCid(s: string): s is Cid {
5757- return CID_REGEX.test(s)
6060+ return CID_REGEX.test(s);
5861}
59626063export function isNsid(s: string): s is Nsid {
6161- return NSID_REGEX.test(s)
6464+ return NSID_REGEX.test(s);
6265}
63666467export function isEmail(s: string): s is EmailAddress {
6565- return EMAIL_REGEX.test(s)
6868+ return EMAIL_REGEX.test(s);
6669}
67706871export function isISODate(s: string): s is ISODateString {
6969- return ISO_DATE_REGEX.test(s)
7272+ return ISO_DATE_REGEX.test(s);
7073}
71747275export function asDid(s: string): Did {
7373- if (!isDid(s)) throw new TypeError(`Invalid DID: ${s}`)
7474- return s
7676+ if (!isDid(s)) throw new TypeError(`Invalid DID: ${s}`);
7777+ return s;
7578}
76797780export function asDidPlc(s: string): DidPlc {
7878- if (!isDidPlc(s)) throw new TypeError(`Invalid DID:PLC: ${s}`)
7979- return s as DidPlc
8181+ if (!isDidPlc(s)) throw new TypeError(`Invalid DID:PLC: ${s}`);
8282+ return s as DidPlc;
8083}
81848285export function asDidWeb(s: string): DidWeb {
8383- if (!isDidWeb(s)) throw new TypeError(`Invalid DID:WEB: ${s}`)
8484- return s as DidWeb
8686+ if (!isDidWeb(s)) throw new TypeError(`Invalid DID:WEB: ${s}`);
8787+ return s as DidWeb;
8588}
86898790export function asHandle(s: string): Handle {
8888- if (!isHandle(s)) throw new TypeError(`Invalid handle: ${s}`)
8989- return s
9191+ if (!isHandle(s)) throw new TypeError(`Invalid handle: ${s}`);
9292+ return s;
9093}
91949295export function asAtUri(s: string): AtUri {
9393- if (!isAtUri(s)) throw new TypeError(`Invalid AT-URI: ${s}`)
9494- return s
9696+ if (!isAtUri(s)) throw new TypeError(`Invalid AT-URI: ${s}`);
9797+ return s;
9598}
969997100export function asCid(s: string): Cid {
9898- if (!isCid(s)) throw new TypeError(`Invalid CID: ${s}`)
9999- return s
101101+ if (!isCid(s)) throw new TypeError(`Invalid CID: ${s}`);
102102+ return s;
100103}
101104102105export function asNsid(s: string): Nsid {
103103- if (!isNsid(s)) throw new TypeError(`Invalid NSID: ${s}`)
104104- return s
106106+ if (!isNsid(s)) throw new TypeError(`Invalid NSID: ${s}`);
107107+ return s;
105108}
106109107110export function asEmail(s: string): EmailAddress {
108108- if (!isEmail(s)) throw new TypeError(`Invalid email: ${s}`)
109109- return s
111111+ if (!isEmail(s)) throw new TypeError(`Invalid email: ${s}`);
112112+ return s;
110113}
111114112115export function asISODate(s: string): ISODateString {
113113- if (!isISODate(s)) throw new TypeError(`Invalid ISO date: ${s}`)
114114- return s
116116+ if (!isISODate(s)) throw new TypeError(`Invalid ISO date: ${s}`);
117117+ return s;
115118}
116119117120export function unsafeAsDid(s: string): Did {
118118- return s as Did
121121+ return s as Did;
119122}
120123121124export function unsafeAsHandle(s: string): Handle {
122122- return s as Handle
125125+ return s as Handle;
123126}
124127125128export function unsafeAsAccessToken(s: string): AccessToken {
126126- return s as AccessToken
129129+ return s as AccessToken;
127130}
128131129132export function unsafeAsRefreshToken(s: string): RefreshToken {
130130- return s as RefreshToken
133133+ return s as RefreshToken;
131134}
132135133136export function unsafeAsServiceToken(s: string): ServiceToken {
134134- return s as ServiceToken
137137+ return s as ServiceToken;
135138}
136139137140export function unsafeAsSetupToken(s: string): SetupToken {
138138- return s as SetupToken
141141+ return s as SetupToken;
139142}
140143141144export function unsafeAsCid(s: string): Cid {
142142- return s as Cid
145145+ return s as Cid;
143146}
144147145148export function unsafeAsRkey(s: string): Rkey {
146146- return s as Rkey
149149+ return s as Rkey;
147150}
148151149152export function unsafeAsAtUri(s: string): AtUri {
150150- return s as AtUri
153153+ return s as AtUri;
151154}
152155153156export function unsafeAsNsid(s: string): Nsid {
154154- return s as Nsid
157157+ return s as Nsid;
155158}
156159157160export function unsafeAsISODate(s: string): ISODateString {
158158- return s as ISODateString
161161+ return s as ISODateString;
159162}
160163164164+export const unsafeAsISODateString = unsafeAsISODate;
165165+161166export function unsafeAsEmail(s: string): EmailAddress {
162162- return s as EmailAddress
167167+ return s as EmailAddress;
163168}
164169165170export function unsafeAsInviteCode(s: string): InviteCode {
166166- return s as InviteCode
171171+ return s as InviteCode;
167172}
168173169174export function unsafeAsPublicKeyMultibase(s: string): PublicKeyMultibase {
170170- return s as PublicKeyMultibase
175175+ return s as PublicKeyMultibase;
171176}
172177173178export function unsafeAsDidKey(s: string): DidKeyString {
174174- return s as DidKeyString
179179+ return s as DidKeyString;
175180}
176181177177-export function parseAtUri(uri: AtUri): { repo: Did; collection: Nsid; rkey: Rkey } {
178178- const parts = uri.replace('at://', '').split('/')
182182+export function parseAtUri(
183183+ uri: AtUri,
184184+): { repo: Did; collection: Nsid; rkey: Rkey } {
185185+ const parts = uri.replace("at://", "").split("/");
179186 return {
180187 repo: unsafeAsDid(parts[0]),
181188 collection: unsafeAsNsid(parts[1]),
182189 rkey: unsafeAsRkey(parts[2]),
183183- }
190190+ };
184191}
185192186193export function makeAtUri(repo: Did, collection: Nsid, rkey: Rkey): AtUri {
187187- return `at://${repo}/${collection}/${rkey}` as AtUri
194194+ return `at://${repo}/${collection}/${rkey}` as AtUri;
188195}
···11-export * from './result'
22-export * from './branded'
33-export * from './exhaustive'
44-export * from './api'
55-export * from './routes'
11+export * from "./result.ts";
22+export * from "./branded.ts";
33+export * from "./exhaustive.ts";
44+export * from "./api.ts";
55+export * from "./routes.ts";
+51-34
frontend/src/lib/types/result.ts
···11export type Result<T, E = Error> =
22 | { ok: true; value: T }
33- | { ok: false; error: E }
33+ | { ok: false; error: E };
4455export function ok<T>(value: T): Result<T, never> {
66- return { ok: true, value }
66+ return { ok: true, value };
77}
8899export function err<E>(error: E): Result<never, E> {
1010- return { ok: false, error }
1010+ return { ok: false, error };
1111}
12121313-export function isOk<T, E>(result: Result<T, E>): result is { ok: true; value: T } {
1414- return result.ok
1313+export function isOk<T, E>(
1414+ result: Result<T, E>,
1515+): result is { ok: true; value: T } {
1616+ return result.ok;
1517}
16181717-export function isErr<T, E>(result: Result<T, E>): result is { ok: false; error: E } {
1818- return !result.ok
1919+export function isErr<T, E>(
2020+ result: Result<T, E>,
2121+): result is { ok: false; error: E } {
2222+ return !result.ok;
1923}
20242121-export function map<T, U, E>(result: Result<T, E>, fn: (t: T) => U): Result<U, E> {
2222- return result.ok ? ok(fn(result.value)) : result
2525+export function map<T, U, E>(
2626+ result: Result<T, E>,
2727+ fn: (t: T) => U,
2828+): Result<U, E> {
2929+ return result.ok ? ok(fn(result.value)) : result;
2330}
24312525-export function mapErr<T, E, F>(result: Result<T, E>, fn: (e: E) => F): Result<T, F> {
2626- return result.ok ? result : err(fn(result.error))
3232+export function mapErr<T, E, F>(
3333+ result: Result<T, E>,
3434+ fn: (e: E) => F,
3535+): Result<T, F> {
3636+ return result.ok ? result : err(fn(result.error));
2737}
28382929-export function flatMap<T, U, E>(result: Result<T, E>, fn: (t: T) => Result<U, E>): Result<U, E> {
3030- return result.ok ? fn(result.value) : result
3939+export function flatMap<T, U, E>(
4040+ result: Result<T, E>,
4141+ fn: (t: T) => Result<U, E>,
4242+): Result<U, E> {
4343+ return result.ok ? fn(result.value) : result;
3144}
32453346export function unwrap<T, E>(result: Result<T, E>): T {
3434- if (result.ok) return result.value
3535- throw result.error instanceof Error ? result.error : new Error(String(result.error))
4747+ if (result.ok) return result.value;
4848+ throw result.error instanceof Error
4949+ ? result.error
5050+ : new Error(String(result.error));
3651}
37523853export function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {
3939- return result.ok ? result.value : defaultValue
5454+ return result.ok ? result.value : defaultValue;
4055}
41564257export function unwrapOrElse<T, E>(result: Result<T, E>, fn: (e: E) => T): T {
4343- return result.ok ? result.value : fn(result.error)
5858+ return result.ok ? result.value : fn(result.error);
4459}
45604661export function match<T, E, U>(
4762 result: Result<T, E>,
4848- handlers: { ok: (t: T) => U; err: (e: E) => U }
6363+ handlers: { ok: (t: T) => U; err: (e: E) => U },
4964): U {
5050- return result.ok ? handlers.ok(result.value) : handlers.err(result.error)
6565+ return result.ok ? handlers.ok(result.value) : handlers.err(result.error);
5166}
52675353-export async function tryAsync<T>(fn: () => Promise<T>): Promise<Result<T, Error>> {
6868+export async function tryAsync<T>(
6969+ fn: () => Promise<T>,
7070+): Promise<Result<T, Error>> {
5471 try {
5555- return ok(await fn())
7272+ return ok(await fn());
5673 } catch (e) {
5757- return err(e instanceof Error ? e : new Error(String(e)))
7474+ return err(e instanceof Error ? e : new Error(String(e)));
5875 }
5976}
60776178export async function tryAsyncWith<T, E>(
6279 fn: () => Promise<T>,
6363- mapError: (e: unknown) => E
8080+ mapError: (e: unknown) => E,
6481): Promise<Result<T, E>> {
6582 try {
6666- return ok(await fn())
8383+ return ok(await fn());
6784 } catch (e) {
6868- return err(mapError(e))
8585+ return err(mapError(e));
6986 }
7087}
71887289export function fromNullable<T>(value: T | null | undefined): Result<T, null> {
7373- return value != null ? ok(value) : err(null)
9090+ return value != null ? ok(value) : err(null);
7491}
75927693export function toNullable<T, E>(result: Result<T, E>): T | null {
7777- return result.ok ? result.value : null
9494+ return result.ok ? result.value : null;
7895}
79968097export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
8181- const values: T[] = []
9898+ const values: T[] = [];
8299 for (const result of results) {
8383- if (!result.ok) return result
8484- values.push(result.value)
100100+ if (!result.ok) return result;
101101+ values.push(result.value);
85102 }
8686- return ok(values)
103103+ return ok(values);
87104}
8810589106export async function collectAsync<T, E>(
9090- results: Promise<Result<T, E>>[]
107107+ results: Promise<Result<T, E>>[],
91108): Promise<Result<T[], E>> {
9292- const settled = await Promise.all(results)
9393- return collect(settled)
109109+ const settled = await Promise.all(results);
110110+ return collect(settled);
94111}
···8888 . ~/.deno/env && cd frontend && deno task dev
8989frontend-build:
9090 . ~/.deno/env && cd frontend && deno task build
9191+frontend-check:
9292+ . ~/.deno/env && cd frontend && deno task check
9193frontend-clean:
9294 rm -rf frontend/dist frontend/node_modules
9395
+8-4
src/api/actor/preferences.rs
···7070 let prefs = match prefs_result {
7171 Ok(rows) => rows,
7272 Err(_) => {
7373- return ApiError::InternalError(Some("Failed to fetch preferences".into())).into_response();
7373+ return ApiError::InternalError(Some("Failed to fetch preferences".into()))
7474+ .into_response();
7475 }
7576 };
7677 let mut personal_details_pref: Option<Value> = None;
···192193 let mut tx = match state.db.begin().await {
193194 Ok(tx) => tx,
194195 Err(_) => {
195195- return ApiError::InternalError(Some("Failed to start transaction".into())).into_response();
196196+ return ApiError::InternalError(Some("Failed to start transaction".into()))
197197+ .into_response();
196198 }
197199 };
198200 let delete_result = sqlx::query!(
···225227 .await;
226228 if insert_result.is_err() {
227229 let _ = tx.rollback().await;
228228- return ApiError::InternalError(Some("Failed to save preference".into())).into_response();
230230+ return ApiError::InternalError(Some("Failed to save preference".into()))
231231+ .into_response();
229232 }
230233 }
231234 if tx.commit().await.is_err() {
232232- return ApiError::InternalError(Some("Failed to commit transaction".into())).into_response();
235235+ return ApiError::InternalError(Some("Failed to commit transaction".into()))
236236+ .into_response();
233237 }
234238 StatusCode::OK.into_response()
235239}
+12-5
src/api/admin/account/delete.rs
···11-use crate::api::error::ApiError;
21use crate::api::EmptyResponse;
22+use crate::api::error::ApiError;
33use crate::auth::BearerAuthAdmin;
44use crate::state::AppState;
55use crate::types::Did;
···4747 .await
4848 {
4949 error!("Failed to delete session tokens for {}: {:?}", did, e);
5050- return ApiError::InternalError(Some("Failed to delete session tokens".into())).into_response();
5050+ return ApiError::InternalError(Some("Failed to delete session tokens".into()))
5151+ .into_response();
5152 }
5253 if let Err(e) = sqlx::query!("DELETE FROM used_refresh_tokens WHERE session_id IN (SELECT id FROM session_tokens WHERE did = $1)", did.as_str())
5354 .execute(&mut *tx)
···8485 "Failed to delete app passwords for user {}: {:?}",
8586 user_id, e
8687 );
8787- return ApiError::InternalError(Some("Failed to delete app passwords".into())).into_response();
8888+ return ApiError::InternalError(Some("Failed to delete app passwords".into()))
8989+ .into_response();
8890 }
8991 if let Err(e) = sqlx::query!(
9092 "DELETE FROM invite_code_uses WHERE used_by_user = $1",
···128130 error!("Failed to commit account deletion transaction: {:?}", e);
129131 return ApiError::InternalError(Some("Failed to commit deletion".into())).into_response();
130132 }
131131- if let Err(e) =
132132- crate::api::repo::record::sequence_account_event(&state, did.as_str(), false, Some("deleted")).await
133133+ if let Err(e) = crate::api::repo::record::sequence_account_event(
134134+ &state,
135135+ did.as_str(),
136136+ false,
137137+ Some("deleted"),
138138+ )
139139+ .await
133140 {
134141 warn!(
135142 "Failed to sequence account deletion event for {}: {}",
+5-1
src/api/admin/account/email.rs
···7474 let result = crate::comms::enqueue_comms(&state.db, item).await;
7575 match result {
7676 Ok(_) => {
7777- tracing::info!("Admin email queued for {} ({})", handle, input.recipient_did);
7777+ tracing::info!(
7878+ "Admin email queued for {} ({})",
7979+ handle,
8080+ input.recipient_did
8181+ );
7882 (StatusCode::OK, Json(SendEmailOutput { sent: true })).into_response()
7983 }
8084 Err(e) => {
+16-7
src/api/admin/account/update.rs
···11-use crate::api::error::ApiError;
21use crate::api::EmptyResponse;
22+use crate::api::error::ApiError;
33use crate::auth::BearerAuthAdmin;
44use crate::state::AppState;
55use crate::types::{Did, PlainPassword};
···8787 if let Ok(Some(_)) = existing {
8888 return ApiError::HandleTaken.into_response();
8989 }
9090- let result = sqlx::query!("UPDATE users SET handle = $1 WHERE did = $2", handle, did.as_str())
9191- .execute(&state.db)
9292- .await;
9090+ let result = sqlx::query!(
9191+ "UPDATE users SET handle = $1 WHERE did = $2",
9292+ handle,
9393+ did.as_str()
9494+ )
9595+ .execute(&state.db)
9696+ .await;
9397 match result {
9498 Ok(r) => {
9599 if r.rows_affected() == 0 {
···99103 let _ = state.cache.delete(&format!("handle:{}", old)).await;
100104 }
101105 let _ = state.cache.delete(&format!("handle:{}", handle)).await;
102102- if let Err(e) =
103103- crate::api::repo::record::sequence_identity_event(&state, did.as_str(), Some(&handle)).await
106106+ if let Err(e) = crate::api::repo::record::sequence_identity_event(
107107+ &state,
108108+ did.as_str(),
109109+ Some(&handle),
110110+ )
111111+ .await
104112 {
105113 warn!(
106114 "Failed to sequence identity event for admin handle update: {}",
107115 e
108116 );
109117 }
110110- if let Err(e) = crate::api::identity::did::update_plc_handle(&state, did.as_str(), &handle).await
118118+ if let Err(e) =
119119+ crate::api::identity::did::update_plc_handle(&state, did.as_str(), &handle).await
111120 {
112121 warn!("Failed to update PLC handle for admin handle update: {}", e);
113122 }
+2-4
src/api/admin/status.rs
···119119 let did = match ¶ms.did {
120120 Some(d) => d,
121121 None => {
122122- return ApiError::InvalidRequest(
123123- "Must provide a did to request blob state".into(),
124124- )
125125- .into_response();
122122+ return ApiError::InvalidRequest("Must provide a did to request blob state".into())
123123+ .into_response();
126124 }
127125 };
128126 let blob = sqlx::query!(
+6-3
src/api/age_assurance.rs
···5050 }
5151 };
52525353- let row = match sqlx::query!("SELECT created_at FROM users WHERE did = $1", &auth_user.did)
5454- .fetch_optional(&state.db)
5555- .await
5353+ let row = match sqlx::query!(
5454+ "SELECT created_at FROM users WHERE did = $1",
5555+ &auth_user.did
5656+ )
5757+ .fetch_optional(&state.db)
5858+ .await
5659 {
5760 Ok(r) => {
5861 tracing::debug!(?r, "age assurance: query result");
+7-4
src/api/backup.rs
···144144 Ok(bytes) => bytes,
145145 Err(e) => {
146146 error!("Failed to fetch backup from storage: {:?}", e);
147147- return ApiError::InternalError(Some("Failed to retrieve backup".into())).into_response();
147147+ return ApiError::InternalError(Some("Failed to retrieve backup".into()))
148148+ .into_response();
148149 }
149150 };
150151···223224 Ok(bytes) => bytes,
224225 Err(e) => {
225226 error!("Failed to generate CAR: {:?}", e);
226226- return ApiError::InternalError(Some("Failed to generate backup".into())).into_response();
227227+ return ApiError::InternalError(Some("Failed to generate backup".into()))
228228+ .into_response();
227229 }
228230 };
229231···448450449451 info!(did = %auth.0.did, enabled = input.enabled, "Updated backup_enabled setting");
450452451451- EnabledResponse::new(input.enabled).into_response()
453453+ EnabledResponse::response(input.enabled).into_response()
452454}
453455454456pub async fn export_blobs(State(state): State<AppState>, auth: BearerAuth) -> Response {
···575577576578 if let Err(e) = zip.finish() {
577579 error!("Failed to finish zip: {:?}", e);
578578- return ApiError::InternalError(Some("Failed to create zip file".into())).into_response();
580580+ return ApiError::InternalError(Some("Failed to create zip file".into()))
581581+ .into_response();
579582 }
580583 }
581584
+11-4
src/api/delegation.rs
···3939 Ok(c) => c,
4040 Err(e) => {
4141 tracing::error!("Failed to list controllers: {:?}", e);
4242- return ApiError::InternalError(Some("Failed to list controllers".into())).into_response();
4242+ return ApiError::InternalError(Some("Failed to list controllers".into()))
4343+ .into_response();
4344 }
4445 };
4546···269270 Ok(false) => ApiError::DelegationNotFound.into_response(),
270271 Err(e) => {
271272 tracing::error!("Failed to update controller scopes: {:?}", e);
272272- ApiError::InternalError(Some("Failed to update controller scopes".into())).into_response()
273273+ ApiError::InternalError(Some("Failed to update controller scopes".into()))
274274+ .into_response()
273275 }
274276 }
275277}
···357359 Ok(e) => e,
358360 Err(e) => {
359361 tracing::error!("Failed to get audit log: {:?}", e);
360360- return ApiError::InternalError(Some("Failed to get audit log".into())).into_response();
362362+ return ApiError::InternalError(Some("Failed to get audit log".into()))
363363+ .into_response();
361364 }
362365 };
363366···762765763766 info!(did = %did, handle = %handle, controller = %&auth.0.did, "Delegated account created");
764767765765- Json(CreateDelegatedAccountResponse { did: did.into(), handle: handle.into() }).into_response()
768768+ Json(CreateDelegatedAccountResponse {
769769+ did: did.into(),
770770+ handle: handle.into(),
771771+ })
772772+ .into_response()
766773}
···186186) -> Response {
187187 // This layer is nested under /xrpc in an axum router so the extracted uri will look like /<method> and thus we can just strip the /
188188 let method = uri.path().trim_start_matches("/");
189189- if is_protected_method(&method) {
189189+ if is_protected_method(method) {
190190 warn!(method = %method, "Attempted to proxy protected method");
191191 return ApiError::InvalidRequest(format!("Cannot proxy protected method: {}", method))
192192 .into_response();
···226226 auth_user.is_oauth,
227227 auth_user.scope.as_deref(),
228228 &resolved.did,
229229- &method,
229229+ method,
230230 ) {
231231 return e;
232232 }
···235235 match crate::auth::create_service_token(
236236 &auth_user.did,
237237 &resolved.did,
238238- &method,
238238+ method,
239239 &key_bytes,
240240 ) {
241241 Ok(new_token) => {
+7-6
src/api/repo/blob.rs
···2929 );
3030 }
3131 detected
3232+ } else if client_hint == "*/*" || client_hint.is_empty() {
3333+ warn!(
3434+ "Could not detect MIME type and client sent invalid hint: '{}'",
3535+ client_hint
3636+ );
3737+ "application/octet-stream".to_string()
3238 } else {
3333- if client_hint == "*/*" || client_hint.is_empty() {
3434- warn!("Could not detect MIME type and client sent invalid hint: '{}'", client_hint);
3535- "application/octet-stream".to_string()
3636- } else {
3737- client_hint.to_string()
3838- }
3939+ client_hint.to_string()
3940 }
4041}
4142
+9-9
src/api/repo/import.rs
···11+use crate::api::EmptyResponse;
12use crate::api::error::ApiError;
23use crate::api::repo::record::create_signed_commit;
33-use crate::api::EmptyResponse;
44use crate::state::AppState;
55use crate::sync::import::{ImportError, apply_import, parse_car};
66use crate::sync::verify::CarVerifier;
···371371 ApiError::InvalidRequest(format!("Referenced block not found in CAR: {}", cid))
372372 .into_response()
373373 }
374374- Err(ImportError::ConcurrentModification) => ApiError::InvalidSwap(Some("Repository is being modified by another operation, please retry".into(),))
374374+ Err(ImportError::ConcurrentModification) => ApiError::InvalidSwap(Some(
375375+ "Repository is being modified by another operation, please retry".into(),
376376+ ))
375377 .into_response(),
376378 Err(ImportError::VerificationFailed(ve)) => {
377379 ApiError::InvalidRequest(format!("CAR verification failed: {}", ve)).into_response()
378380 }
379379- Err(ImportError::DidMismatch { car_did, auth_did }) => {
380380- ApiError::InvalidRequest(format!(
381381- "CAR is for {} but authenticated as {}",
382382- car_did, auth_did
383383- ))
384384- .into_response()
385385- }
381381+ Err(ImportError::DidMismatch { car_did, auth_did }) => ApiError::InvalidRequest(format!(
382382+ "CAR is for {} but authenticated as {}",
383383+ car_did, auth_did
384384+ ))
385385+ .into_response(),
386386 Err(e) => {
387387 error!("Import error: {:?}", e);
388388 ApiError::InternalError(None).into_response()
+19-15
src/api/repo/record/batch.rs
···205205 }
206206 }
207207208208- let user_id: uuid::Uuid = match sqlx::query_scalar!("SELECT id FROM users WHERE did = $1", did.as_str())
209209- .fetch_optional(&state.db)
210210- .await
211211- {
212212- Ok(Some(id)) => id,
213213- _ => return ApiError::InternalError(Some("User not found".into())).into_response(),
214214- };
208208+ let user_id: uuid::Uuid =
209209+ match sqlx::query_scalar!("SELECT id FROM users WHERE did = $1", did.as_str())
210210+ .fetch_optional(&state.db)
211211+ .await
212212+ {
213213+ Ok(Some(id)) => id,
214214+ _ => return ApiError::InternalError(Some("User not found".into())).into_response(),
215215+ };
215216 let root_cid_str: String = match sqlx::query_scalar!(
216217 "SELECT repo_root_cid FROM repos WHERE user_id = $1",
217218 user_id
···225226 let current_root_cid = match Cid::from_str(&root_cid_str) {
226227 Ok(c) => c,
227228 Err(_) => {
228228- return ApiError::InternalError(Some("Invalid repo root CID".into())).into_response()
229229+ return ApiError::InternalError(Some("Invalid repo root CID".into())).into_response();
229230 }
230231 };
231232 if let Some(swap_commit) = &input.swap_commit
···281282 Ok(c) => c,
282283 Err(_) => {
283284 return ApiError::InternalError(Some("Failed to store record".into()))
284284- .into_response()
285285+ .into_response();
285286 }
286287 };
287288 let key = format!("{}/{}", collection, rkey);
···290291 Ok(m) => m,
291292 Err(_) => {
292293 return ApiError::InternalError(Some("Failed to add to MST".into()))
293293- .into_response()
294294+ .into_response();
294295 }
295296 };
296297 let uri = AtUri::from_parts(&did, collection, &rkey);
···335336 Ok(c) => c,
336337 Err(_) => {
337338 return ApiError::InternalError(Some("Failed to store record".into()))
338338- .into_response()
339339+ .into_response();
339340 }
340341 };
341342 let key = format!("{}/{}", collection, rkey);
···345346 Ok(m) => m,
346347 Err(_) => {
347348 return ApiError::InternalError(Some("Failed to update MST".into()))
348348- .into_response()
349349+ .into_response();
349350 }
350351 };
351352 let uri = AtUri::from_parts(&did, collection, rkey);
···369370 Ok(m) => m,
370371 Err(_) => {
371372 return ApiError::InternalError(Some("Failed to delete from MST".into()))
372372- .into_response()
373373+ .into_response();
373374 }
374375 };
375376 results.push(WriteResult::DeleteResult {});
···383384 }
384385 let new_mst_root = match mst.persist().await {
385386 Ok(c) => c,
386386- Err(_) => return ApiError::InternalError(Some("Failed to persist MST".into())).into_response(),
387387+ Err(_) => {
388388+ return ApiError::InternalError(Some("Failed to persist MST".into())).into_response();
389389+ }
387390 };
388391 let mut relevant_blocks = std::collections::BTreeMap::new();
389392 for key in &modified_keys {
···432435 Ok(res) => res,
433436 Err(e) => {
434437 error!("Commit failed: {}", e);
435435- return ApiError::InternalError(Some("Failed to commit changes".into())).into_response();
438438+ return ApiError::InternalError(Some("Failed to commit changes".into()))
439439+ .into_response();
436440 }
437441 };
438442
+4-2
src/api/repo/record/delete.rs
···9797 let expected_cid = Cid::from_str(swap_record_str).ok();
9898 let actual_cid = mst.get(&key).await.ok().flatten();
9999 if expected_cid != actual_cid {
100100- return ApiError::InvalidSwap(Some("Record has been modified or does not exist".into()))
101101- .into_response();
100100+ return ApiError::InvalidSwap(Some(
101101+ "Record has been modified or does not exist".into(),
102102+ ))
103103+ .into_response();
102104 }
103105 }
104106 let prev_record_cid = mst.get(&key).await.ok().flatten();
+16-9
src/api/repo/record/write.rs
···138138 ApiError::InternalError(None).into_response()
139139 })?
140140 .ok_or_else(|| ApiError::InternalError(Some("Repo root not found".into())).into_response())?;
141141- let current_root_cid = Cid::from_str(&root_cid_str)
142142- .map_err(|_| ApiError::InternalError(Some("Invalid repo root CID".into())).into_response())?;
141141+ let current_root_cid = Cid::from_str(&root_cid_str).map_err(|_| {
142142+ ApiError::InternalError(Some("Invalid repo root CID".into())).into_response()
143143+ })?;
143144 Ok(RepoWriteAuth {
144145 did: auth_user.did.clone(),
145146 user_id,
···247248 let record_cid = match tracking_store.put(&record_bytes).await {
248249 Ok(c) => c,
249250 _ => {
250250- return ApiError::InternalError(Some("Failed to save record block".into())).into_response()
251251+ return ApiError::InternalError(Some("Failed to save record block".into()))
252252+ .into_response();
251253 }
252254 };
253255 let key = format!("{}/{}", input.collection, rkey);
···442444 let expected_cid = Cid::from_str(swap_record_str).ok();
443445 let actual_cid = mst.get(&key).await.ok().flatten();
444446 if expected_cid != actual_cid {
445445- return ApiError::InvalidSwap(Some("Record has been modified or does not exist".into()))
446446- .into_response();
447447+ return ApiError::InvalidSwap(Some(
448448+ "Record has been modified or does not exist".into(),
449449+ ))
450450+ .into_response();
447451 }
448452 }
449453 let existing_cid = mst.get(&key).await.ok().flatten();
···455459 let record_cid = match tracking_store.put(&record_bytes).await {
456460 Ok(c) => c,
457461 _ => {
458458- return ApiError::InternalError(Some("Failed to save record block".into())).into_response()
462462+ return ApiError::InternalError(Some("Failed to save record block".into()))
463463+ .into_response();
459464 }
460465 };
461466 if existing_cid == Some(record_cid) {
···474479 match mst.update(&key, record_cid).await {
475480 Ok(m) => m,
476481 Err(_) => {
477477- return ApiError::InternalError(Some("Failed to update MST".into())).into_response()
482482+ return ApiError::InternalError(Some("Failed to update MST".into()))
483483+ .into_response();
478484 }
479485 }
480486 } else {
481487 match mst.add(&key, record_cid).await {
482488 Ok(m) => m,
483489 Err(_) => {
484484- return ApiError::InternalError(Some("Failed to add to MST".into())).into_response()
490490+ return ApiError::InternalError(Some("Failed to add to MST".into()))
491491+ .into_response();
485492 }
486493 }
487494 };
488495 let new_mst_root = match new_mst.persist().await {
489496 Ok(c) => c,
490497 Err(_) => {
491491- return ApiError::InternalError(Some("Failed to persist MST".into())).into_response()
498498+ return ApiError::InternalError(Some("Failed to persist MST".into())).into_response();
492499 }
493500 };
494501 let op = if existing_cid.is_some() {
···5353 return ApiError::InvalidRequest("useCount must be at least 1".into()).into_response();
5454 }
55555656- let for_account = input.for_account.unwrap_or_else(|| auth_user.did.to_string());
5656+ let for_account = input
5757+ .for_account
5858+ .unwrap_or_else(|| auth_user.did.to_string());
5759 let code = gen_invite_code();
58605961 match sqlx::query!(
···6969 auth: BearerAuth,
7070 Json(input): Json<PasswordReauthInput>,
7171) -> Response {
7272- let user = sqlx::query!("SELECT password_hash FROM users WHERE did = $1", &*&auth.0.did)
7373- .fetch_optional(&state.db)
7474- .await;
7272+ let user = sqlx::query!(
7373+ "SELECT password_hash FROM users WHERE did = $1",
7474+ &*&auth.0.did
7575+ )
7676+ .fetch_optional(&state.db)
7777+ .await;
75787679 let password_hash = match user {
7780 Ok(Some(row)) => row.password_hash,
···138141 .await
139142 {
140143 warn!(did = %&auth.0.did, "TOTP verification rate limit exceeded");
141141- return ApiError::RateLimitExceeded(Some("Too many verification attempts. Please try again in a few minutes.".into(),))
144144+ return ApiError::RateLimitExceeded(Some(
145145+ "Too many verification attempts. Please try again in a few minutes.".into(),
146146+ ))
142147 .into_response();
143148 }
144149