From 27de1ddb70cd7961be5cf77591737d4e63d0c804 Mon Sep 17 00:00:00 2001
From: naskya <m@naskya.net>
Date: Tue, 28 May 2024 19:42:52 +0900
Subject: [PATCH] chore (backend-rs): add comments

---
 packages/backend-rs/index.d.ts                | 200 +++++++++---------
 packages/backend-rs/index.js                  |  14 +-
 packages/backend-rs/src/database/cache.rs     |  46 ++--
 packages/backend-rs/src/database/mod.rs       |   3 +
 packages/backend-rs/src/federation/mod.rs     |   1 +
 .../{service => federation}/nodeinfo/fetch.rs |   2 +-
 .../nodeinfo/generate.rs                      |   2 +-
 .../{service => federation}/nodeinfo/mod.rs   |   0
 .../nodeinfo/schema.rs                        |   0
 packages/backend-rs/src/lib.rs                |  10 +-
 packages/backend-rs/src/service/mod.rs        |   1 -
 .../src/service/push_notification.rs          |   4 +-
 packages/backend-rs/src/util/http_client.rs   |  16 ++
 packages/backend-rs/src/util/id.rs            |   2 -
 packages/backend-rs/src/util/mod.rs           |   3 +
 15 files changed, 166 insertions(+), 138 deletions(-)
 rename packages/backend-rs/src/{service => federation}/nodeinfo/fetch.rs (99%)
 rename packages/backend-rs/src/{service => federation}/nodeinfo/generate.rs (99%)
 rename packages/backend-rs/src/{service => federation}/nodeinfo/mod.rs (100%)
 rename packages/backend-rs/src/{service => federation}/nodeinfo/schema.rs (100%)

diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts
index 7be4b269e6..30e59f5353 100644
--- a/packages/backend-rs/index.d.ts
+++ b/packages/backend-rs/index.d.ts
@@ -207,6 +207,106 @@ export interface Acct {
 }
 export function stringToAcct(acct: string): Acct
 export function acctToString(acct: Acct): string
+export function fetchNodeinfo(host: string): Promise<Nodeinfo>
+export function nodeinfo_2_1(): Promise<any>
+export function nodeinfo_2_0(): Promise<any>
+/** NodeInfo schema version 2.0. <https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.0> */
+export interface Nodeinfo {
+  /** The schema version, must be 2.0. */
+  version: string
+  /** Metadata about server software in use. */
+  software: Software20
+  /** The protocols supported on this server. */
+  protocols: Array<Protocol>
+  /** The third party sites this server can connect to via their application API. */
+  services: Services
+  /** Whether this server allows open self-registration. */
+  openRegistrations: boolean
+  /** Usage statistics for this server. */
+  usage: Usage
+  /** Free form key value pairs for software specific values. Clients should not rely on any specific key present. */
+  metadata: Record<string, any>
+}
+/** Metadata about server software in use (version 2.0). */
+export interface Software20 {
+  /** The canonical name of this server software. */
+  name: string
+  /** The version of this server software. */
+  version: string
+}
+export enum Protocol {
+  Activitypub = 'activitypub',
+  Buddycloud = 'buddycloud',
+  Dfrn = 'dfrn',
+  Diaspora = 'diaspora',
+  Libertree = 'libertree',
+  Ostatus = 'ostatus',
+  Pumpio = 'pumpio',
+  Tent = 'tent',
+  Xmpp = 'xmpp',
+  Zot = 'zot'
+}
+/** The third party sites this server can connect to via their application API. */
+export interface Services {
+  /** The third party sites this server can retrieve messages from for combined display with regular traffic. */
+  inbound: Array<Inbound>
+  /** The third party sites this server can publish messages to on the behalf of a user. */
+  outbound: Array<Outbound>
+}
+/** The third party sites this server can retrieve messages from for combined display with regular traffic. */
+export enum Inbound {
+  Atom1 = 'atom1',
+  Gnusocial = 'gnusocial',
+  Imap = 'imap',
+  Pnut = 'pnut',
+  Pop3 = 'pop3',
+  Pumpio = 'pumpio',
+  Rss2 = 'rss2',
+  Twitter = 'twitter'
+}
+/** The third party sites this server can publish messages to on the behalf of a user. */
+export enum Outbound {
+  Atom1 = 'atom1',
+  Blogger = 'blogger',
+  Buddycloud = 'buddycloud',
+  Diaspora = 'diaspora',
+  Dreamwidth = 'dreamwidth',
+  Drupal = 'drupal',
+  Facebook = 'facebook',
+  Friendica = 'friendica',
+  Gnusocial = 'gnusocial',
+  Google = 'google',
+  Insanejournal = 'insanejournal',
+  Libertree = 'libertree',
+  Linkedin = 'linkedin',
+  Livejournal = 'livejournal',
+  Mediagoblin = 'mediagoblin',
+  Myspace = 'myspace',
+  Pinterest = 'pinterest',
+  Pnut = 'pnut',
+  Posterous = 'posterous',
+  Pumpio = 'pumpio',
+  Redmatrix = 'redmatrix',
+  Rss2 = 'rss2',
+  Smtp = 'smtp',
+  Tent = 'tent',
+  Tumblr = 'tumblr',
+  Twitter = 'twitter',
+  Wordpress = 'wordpress',
+  Xmpp = 'xmpp'
+}
+/** Usage statistics for this server. */
+export interface Usage {
+  users: Users
+  localPosts: number | null
+  localComments: number | null
+}
+/** statistics about the users of this server. */
+export interface Users {
+  total: number | null
+  activeHalfyear: number | null
+  activeMonth: number | null
+}
 export function greet(): void
 export function initializeRustLogger(): void
 export function showServerInfo(): void
@@ -1179,106 +1279,6 @@ export interface Webhook {
   latestStatus: number | null
 }
 export function updateAntennasOnNewNote(note: Note, noteAuthor: Acct, noteMutedUsers: Array<string>): Promise<void>
-export function fetchNodeinfo(host: string): Promise<Nodeinfo>
-export function nodeinfo_2_1(): Promise<any>
-export function nodeinfo_2_0(): Promise<any>
-/** NodeInfo schema version 2.0. <https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.0> */
-export interface Nodeinfo {
-  /** The schema version, must be 2.0. */
-  version: string
-  /** Metadata about server software in use. */
-  software: Software20
-  /** The protocols supported on this server. */
-  protocols: Array<Protocol>
-  /** The third party sites this server can connect to via their application API. */
-  services: Services
-  /** Whether this server allows open self-registration. */
-  openRegistrations: boolean
-  /** Usage statistics for this server. */
-  usage: Usage
-  /** Free form key value pairs for software specific values. Clients should not rely on any specific key present. */
-  metadata: Record<string, any>
-}
-/** Metadata about server software in use (version 2.0). */
-export interface Software20 {
-  /** The canonical name of this server software. */
-  name: string
-  /** The version of this server software. */
-  version: string
-}
-export enum Protocol {
-  Activitypub = 'activitypub',
-  Buddycloud = 'buddycloud',
-  Dfrn = 'dfrn',
-  Diaspora = 'diaspora',
-  Libertree = 'libertree',
-  Ostatus = 'ostatus',
-  Pumpio = 'pumpio',
-  Tent = 'tent',
-  Xmpp = 'xmpp',
-  Zot = 'zot'
-}
-/** The third party sites this server can connect to via their application API. */
-export interface Services {
-  /** The third party sites this server can retrieve messages from for combined display with regular traffic. */
-  inbound: Array<Inbound>
-  /** The third party sites this server can publish messages to on the behalf of a user. */
-  outbound: Array<Outbound>
-}
-/** The third party sites this server can retrieve messages from for combined display with regular traffic. */
-export enum Inbound {
-  Atom1 = 'atom1',
-  Gnusocial = 'gnusocial',
-  Imap = 'imap',
-  Pnut = 'pnut',
-  Pop3 = 'pop3',
-  Pumpio = 'pumpio',
-  Rss2 = 'rss2',
-  Twitter = 'twitter'
-}
-/** The third party sites this server can publish messages to on the behalf of a user. */
-export enum Outbound {
-  Atom1 = 'atom1',
-  Blogger = 'blogger',
-  Buddycloud = 'buddycloud',
-  Diaspora = 'diaspora',
-  Dreamwidth = 'dreamwidth',
-  Drupal = 'drupal',
-  Facebook = 'facebook',
-  Friendica = 'friendica',
-  Gnusocial = 'gnusocial',
-  Google = 'google',
-  Insanejournal = 'insanejournal',
-  Libertree = 'libertree',
-  Linkedin = 'linkedin',
-  Livejournal = 'livejournal',
-  Mediagoblin = 'mediagoblin',
-  Myspace = 'myspace',
-  Pinterest = 'pinterest',
-  Pnut = 'pnut',
-  Posterous = 'posterous',
-  Pumpio = 'pumpio',
-  Redmatrix = 'redmatrix',
-  Rss2 = 'rss2',
-  Smtp = 'smtp',
-  Tent = 'tent',
-  Tumblr = 'tumblr',
-  Twitter = 'twitter',
-  Wordpress = 'wordpress',
-  Xmpp = 'xmpp'
-}
-/** Usage statistics for this server. */
-export interface Usage {
-  users: Users
-  localPosts: number | null
-  localComments: number | null
-}
-/** statistics about the users of this server. */
-export interface Users {
-  total: number | null
-  activeHalfyear: number | null
-  activeMonth: number | null
-}
 export function watchNote(watcherId: string, noteAuthorId: string, noteId: string): Promise<void>
 export function unwatchNote(watcherId: string, noteId: string): Promise<void>
 export enum PushNotificationKind {
diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js
index 3fd0fc95eb..1da5b752d7 100644
--- a/packages/backend-rs/index.js
+++ b/packages/backend-rs/index.js
@@ -310,7 +310,7 @@ if (!nativeBinding) {
   throw new Error(`Failed to load native binding`)
 }
 
-const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, greet, initializeRustLogger, showServerInfo, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, isQuote, isSafeUrl, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, cpuInfo, cpuUsage, memoryUsage, storageUsage, AntennaSrc, DriveFileUsageHint, MutedNoteReason, NoteVisibility, NotificationType, PageVisibility, PollNoteVisibility, RelayStatus, UserEmojiModPerm, UserProfileFfvisibility, UserProfileMutingNotificationTypes, updateAntennasOnNewNote, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, watchNote, unwatchNote, PushNotificationKind, sendPushNotification, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, generateSecureRandomString, generateUserToken } = nativeBinding
+const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, greet, initializeRustLogger, showServerInfo, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, isQuote, isSafeUrl, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, cpuInfo, cpuUsage, memoryUsage, storageUsage, AntennaSrc, DriveFileUsageHint, MutedNoteReason, NoteVisibility, NotificationType, PageVisibility, PollNoteVisibility, RelayStatus, UserEmojiModPerm, UserProfileFfvisibility, UserProfileMutingNotificationTypes, updateAntennasOnNewNote, watchNote, unwatchNote, PushNotificationKind, sendPushNotification, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, generateSecureRandomString, generateUserToken } = nativeBinding
 
 module.exports.SECOND = SECOND
 module.exports.MINUTE = MINUTE
@@ -323,6 +323,12 @@ module.exports.loadEnv = loadEnv
 module.exports.loadConfig = loadConfig
 module.exports.stringToAcct = stringToAcct
 module.exports.acctToString = acctToString
+module.exports.fetchNodeinfo = fetchNodeinfo
+module.exports.nodeinfo_2_1 = nodeinfo_2_1
+module.exports.nodeinfo_2_0 = nodeinfo_2_0
+module.exports.Protocol = Protocol
+module.exports.Inbound = Inbound
+module.exports.Outbound = Outbound
 module.exports.greet = greet
 module.exports.initializeRustLogger = initializeRustLogger
 module.exports.showServerInfo = showServerInfo
@@ -372,12 +378,6 @@ module.exports.UserEmojiModPerm = UserEmojiModPerm
 module.exports.UserProfileFfvisibility = UserProfileFfvisibility
 module.exports.UserProfileMutingNotificationTypes = UserProfileMutingNotificationTypes
 module.exports.updateAntennasOnNewNote = updateAntennasOnNewNote
-module.exports.fetchNodeinfo = fetchNodeinfo
-module.exports.nodeinfo_2_1 = nodeinfo_2_1
-module.exports.nodeinfo_2_0 = nodeinfo_2_0
-module.exports.Protocol = Protocol
-module.exports.Inbound = Inbound
-module.exports.Outbound = Outbound
 module.exports.watchNote = watchNote
 module.exports.unwatchNote = unwatchNote
 module.exports.PushNotificationKind = PushNotificationKind
diff --git a/packages/backend-rs/src/database/cache.rs b/packages/backend-rs/src/database/cache.rs
index abc90ef2d1..29b02f2335 100644
--- a/packages/backend-rs/src/database/cache.rs
+++ b/packages/backend-rs/src/database/cache.rs
@@ -46,13 +46,13 @@ fn wildcard(category: Category) -> String {
 ///
 /// This overwrites the exsisting cache with the same key.
 ///
-/// ## Arguments
+/// # Arguments
 ///
-/// * `key` - key (will be prefixed automatically)
-/// * `value` - (de)serializable value
-/// * `expire_seconds` - TTL
+/// - `key` : key (prefixed automatically)
+/// - `value` : (de)serializable value
+/// - `expire_seconds` : TTL
 ///
-/// ## Example
+/// # Example
 ///
 /// ```
 /// # use backend_rs::database::cache;
@@ -89,11 +89,11 @@ pub async fn set<V: for<'a> Deserialize<'a> + Serialize>(
 /// If the Redis connection is fine, this returns `Ok(data)` where `data`
 /// is the cached value. Returns `Ok(None)` if there is no value corresponding to `key`.
 ///
-/// ## Arguments
+/// # Argument
 ///
-/// * `key` - key (will be prefixed automatically)
+/// - `key` : key (will be prefixed automatically)
 ///
-/// ## Example
+/// # Example
 ///
 /// ```
 /// # use backend_rs::database::cache;
@@ -126,9 +126,9 @@ pub async fn get<V: for<'a> Deserialize<'a> + Serialize>(key: &str) -> Result<Op
 /// If the Redis connection is fine, this returns `Ok(())`
 /// regardless of whether the cache exists.
 ///
-/// ## Arguments
+/// # Argument
 ///
-/// * `key` - key (will be prefixed automatically)
+/// - `key` : key (prefixed automatically)
 ///
 /// ## Example
 ///
@@ -159,12 +159,12 @@ pub async fn delete(key: &str) -> Result<(), Error> {
 /// The usage is the same as [set], except that you need to
 /// use [get_one] and [delete_one] to get/delete the cache.
 ///
-/// ## Arguments
+/// # Arguments
 ///
-/// * `category` - one of [Category]
-/// * `key` - key (will be prefixed automatically)
-/// * `value` - (de)serializable value
-/// * `expire_seconds` - TTL
+/// - `category` : one of [Category]
+/// - `key` : key (prefixed automatically)
+/// - `value` : (de)serializable value
+/// - `expire_seconds` : TTL
 pub async fn set_one<V: for<'a> Deserialize<'a> + Serialize>(
     category: Category,
     key: &str,
@@ -178,10 +178,10 @@ pub async fn set_one<V: for<'a> Deserialize<'a> + Serialize>(
 ///
 /// The usage is basically the same as [get].
 ///
-/// ## Arguments
+/// # Arguments
 ///
-/// * `category` - one of [Category]
-/// * `key` - key (will be prefixed automatically)
+/// - `category` : one of [Category]
+/// - `key` : key (prefixed automatically)
 pub async fn get_one<V: for<'a> Deserialize<'a> + Serialize>(
     category: Category,
     key: &str,
@@ -193,19 +193,19 @@ pub async fn get_one<V: for<'a> Deserialize<'a> + Serialize>(
 ///
 /// The usage is basically the same as [delete].
 ///
-/// ## Arguments
+/// # Arguments
 ///
-/// * `category` - one of [Category]
-/// * `key` - key (will be prefixed automatically)
+/// - `category` : one of [Category]
+/// - `key` : key (prefixed automatically)
 pub async fn delete_one(category: Category, key: &str) -> Result<(), Error> {
     delete(&categorize(category, key)).await
 }
 
 /// Deletes all Redis caches under a `category`.
 ///
-/// ## Arguments
+/// # Argument
 ///
-/// * `category` - one of [Category]
+/// - `category` : one of [Category]
 pub async fn delete_all(category: Category) -> Result<(), Error> {
     let mut redis = redis_conn().await?;
     let keys: Vec<Vec<u8>> = redis.keys(wildcard(category)).await?;
diff --git a/packages/backend-rs/src/database/mod.rs b/packages/backend-rs/src/database/mod.rs
index 428bc17435..e80c3c74a2 100644
--- a/packages/backend-rs/src/database/mod.rs
+++ b/packages/backend-rs/src/database/mod.rs
@@ -3,6 +3,9 @@ pub use redis::key as redis_key;
 pub use redis::redis_conn;
 pub use redis::RedisConnError;
 
+/// Utilities for using Redis cache
 pub mod cache;
+/// PostgreSQL interface
 pub mod postgresql;
+/// Redis interface
 pub mod redis;
diff --git a/packages/backend-rs/src/federation/mod.rs b/packages/backend-rs/src/federation/mod.rs
index 93a92c008b..4251d784bf 100644
--- a/packages/backend-rs/src/federation/mod.rs
+++ b/packages/backend-rs/src/federation/mod.rs
@@ -1 +1,2 @@
 pub mod acct;
+pub mod nodeinfo;
diff --git a/packages/backend-rs/src/service/nodeinfo/fetch.rs b/packages/backend-rs/src/federation/nodeinfo/fetch.rs
similarity index 99%
rename from packages/backend-rs/src/service/nodeinfo/fetch.rs
rename to packages/backend-rs/src/federation/nodeinfo/fetch.rs
index 7c781cd73d..b68b222626 100644
--- a/packages/backend-rs/src/service/nodeinfo/fetch.rs
+++ b/packages/backend-rs/src/federation/nodeinfo/fetch.rs
@@ -1,4 +1,4 @@
-use crate::service::nodeinfo::schema::*;
+use crate::federation::nodeinfo::schema::*;
 use crate::util::http_client;
 use isahc::AsyncReadResponseExt;
 use serde::{Deserialize, Serialize};
diff --git a/packages/backend-rs/src/service/nodeinfo/generate.rs b/packages/backend-rs/src/federation/nodeinfo/generate.rs
similarity index 99%
rename from packages/backend-rs/src/service/nodeinfo/generate.rs
rename to packages/backend-rs/src/federation/nodeinfo/generate.rs
index 8976dc6a13..804dd3213c 100644
--- a/packages/backend-rs/src/service/nodeinfo/generate.rs
+++ b/packages/backend-rs/src/federation/nodeinfo/generate.rs
@@ -1,8 +1,8 @@
 use crate::config::CONFIG;
 use crate::database::{cache, db_conn};
+use crate::federation::nodeinfo::schema::*;
 use crate::misc::meta::fetch_meta;
 use crate::model::entity::{note, user};
-use crate::service::nodeinfo::schema::*;
 use sea_orm::{ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter};
 use serde_json::json;
 use std::collections::HashMap;
diff --git a/packages/backend-rs/src/service/nodeinfo/mod.rs b/packages/backend-rs/src/federation/nodeinfo/mod.rs
similarity index 100%
rename from packages/backend-rs/src/service/nodeinfo/mod.rs
rename to packages/backend-rs/src/federation/nodeinfo/mod.rs
diff --git a/packages/backend-rs/src/service/nodeinfo/schema.rs b/packages/backend-rs/src/federation/nodeinfo/schema.rs
similarity index 100%
rename from packages/backend-rs/src/service/nodeinfo/schema.rs
rename to packages/backend-rs/src/federation/nodeinfo/schema.rs
diff --git a/packages/backend-rs/src/lib.rs b/packages/backend-rs/src/lib.rs
index 9152a81543..ed601b9f51 100644
--- a/packages/backend-rs/src/lib.rs
+++ b/packages/backend-rs/src/lib.rs
@@ -1,10 +1,18 @@
-pub use macro_rs::{export, ts_export};
+use macro_rs::{export, ts_export};
 
+/// Server configurations and environment variables
 pub mod config;
+/// Interfaces for accessing PostgreSQL and Redis
 pub mod database;
+/// Services used to federate with other servers
 pub mod federation;
+/// Initializers
 pub mod init;
+/// Miscellaneous utilities
 pub mod misc;
+/// Database structure, auto-generated by [sea_orm]
 pub mod model;
+/// Services provided for local users
 pub mod service;
+/// Basic utilities such as ID generator and HTTP client
 pub mod util;
diff --git a/packages/backend-rs/src/service/mod.rs b/packages/backend-rs/src/service/mod.rs
index 4a5a0a7311..abbd7fd7c4 100644
--- a/packages/backend-rs/src/service/mod.rs
+++ b/packages/backend-rs/src/service/mod.rs
@@ -1,5 +1,4 @@
 pub mod antenna;
-pub mod nodeinfo;
 pub mod note;
 pub mod push_notification;
 pub mod stream;
diff --git a/packages/backend-rs/src/service/push_notification.rs b/packages/backend-rs/src/service/push_notification.rs
index 797b4cf5c1..09edb4fff9 100644
--- a/packages/backend-rs/src/service/push_notification.rs
+++ b/packages/backend-rs/src/service/push_notification.rs
@@ -4,7 +4,7 @@ use crate::misc::meta::fetch_meta;
 use crate::model::entity::sw_subscription;
 use crate::util::http_client;
 use once_cell::sync::OnceCell;
-use sea_orm::{prelude::*, DbErr};
+use sea_orm::prelude::*;
 use web_push::{
     ContentEncoding, IsahcWebPushClient, SubscriptionInfo, SubscriptionKeys, VapidSignatureBuilder,
     WebPushClient, WebPushError, WebPushMessageBuilder,
@@ -102,7 +102,7 @@ fn compact_content(
 }
 
 async fn handle_web_push_failure(
-    db: &DatabaseConnection,
+    db: &DbConn,
     err: WebPushError,
     subscription_id: &str,
     error_message: &str,
diff --git a/packages/backend-rs/src/util/http_client.rs b/packages/backend-rs/src/util/http_client.rs
index bc5976c283..c2c917964d 100644
--- a/packages/backend-rs/src/util/http_client.rs
+++ b/packages/backend-rs/src/util/http_client.rs
@@ -13,6 +13,22 @@ pub enum Error {
 
 static CLIENT: OnceCell<HttpClient> = OnceCell::new();
 
+/// Returns an [HttpClient] that takes the proxy configuration into account.
+///
+/// # Example
+/// ```no_run
+/// # use backend_rs::util::http_client::client;
+/// use isahc::ReadResponseExt;
+///
+/// # fn f() -> Result<(), Box<dyn std::error::Error>> {
+/// let mut response = client()?.get("https://example.com/")?;
+///
+/// if response.status().is_success() {
+///     println!("{}", response.text()?);
+/// }
+/// # Ok(())
+/// # }
+/// ```
 pub fn client() -> Result<HttpClient, Error> {
     CLIENT
         .get_or_try_init(|| {
diff --git a/packages/backend-rs/src/util/id.rs b/packages/backend-rs/src/util/id.rs
index 39e4c34045..fb0c25b7d3 100644
--- a/packages/backend-rs/src/util/id.rs
+++ b/packages/backend-rs/src/util/id.rs
@@ -1,5 +1,3 @@
-//! ID generation utility based on [cuid2]
-
 use crate::config::CONFIG;
 use basen::BASE36;
 use chrono::{DateTime, NaiveDateTime, Utc};
diff --git a/packages/backend-rs/src/util/mod.rs b/packages/backend-rs/src/util/mod.rs
index 93a5fc5ce7..21e9b157a4 100644
--- a/packages/backend-rs/src/util/mod.rs
+++ b/packages/backend-rs/src/util/mod.rs
@@ -1,3 +1,6 @@
+/// Shared [isahc] HTTP client
 pub mod http_client;
+/// ID generation utility based on [cuid2]
 pub mod id;
+/// Secure random string generator
 pub mod random;