Files
gerbeur/mod.ts
khannurien 563daa720c
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 50s
Build and Deploy Static Documentation Site / build-and-push (push) Successful in 22s
v3: src/ is documented like api/ and shared/, and the reference covers the whole repository — the frontend had no module docs, JSDoc on some components and hooks and not on others, props typed inline in half the components and in private interfaces in the rest, // comments on declarations, and no return types on 147 exported functions, so deno doc --lint over src/ found 637 errors. The rule api/ follows is applied to every non-test module of src/: a /** … @module */ block, JSDoc on every export and every field of an exported interface, /** */ for declarations and // for notes, verbs for functions ("Renders…" for a component), parameters named in the prose, {@link} only for symbols in scope, and a page's JSDoc names its route and who may see it (App.tsx's module doc lists the route table). For deno doc to show them, every exported function states its return type: components React.JSX.Element (or | null, or a portal), memo and forwardRef components their exotic types, contexts React.Context<…>, and a hook returning several things a documented Use<Name>Result interface (useAuth, useRequiredAuth, useFading, useEmojiTrigger, useMentionAutocomplete, useDumpCardLink, usePlayRichContent; FeedCacheResult, YouTubePlaylistControls and UseApiFormReturn are renamed to match). Every component that takes props takes an exported, documented <Name>Props interface — the 64 inline prop types are lifted into one, DumpFeed gets DumpFeedProps extending MainFeedProps. React types go through the global React namespace: the four default imports of react are gone, since deno doc can't follow them. Two duplicates go too: useMentionAutocomplete's UserResult was shared/'s UserSuggestion, and JournalCard re-exported JournalShape for no one; i18n.ts no longer re-exports Lingui's i18n, which its three users now import from @lingui/core. deno task doc and doc:lint now take src/ (but its tests and the generated locales), the index page gains a Frontend section linking every module by layer and domain, mod.test.ts walks src/ as well, and the docs workflow runs on changes to src/. deno doc doesn't document npm packages, so it takes a type imported from one — react-hook-form's FieldValues in the form fields, frimousse's SkinTone — for a private one; doc:lint now goes through doc-lint.ts, which fails on every diagnostic but those, 25 of them. The README states the frontend's part of the rule. No behaviour changes; 205 backend and 628 frontend tests pass, and tsc, deno check and deno lint are clean.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 07:31:22 +00:00

357 lines
21 KiB
TypeScript

/**
* # gerbeur
*
* A small invite-only social platform for sharing links and files. The
* repository holds three parts: the backend in `api/`, the frontend in `src/`,
* and in `shared/` whatever crosses the wire between them. This reference
* documents all three.
*
* ## Backend — `api/`
*
* An Oak server over SQLite that answers the API and the WebSocket, and serves
* the built frontend. A request goes through a route, which parses it and
* answers. The route calls services, which hold the logic and every SQL query;
* they read rows through the model, and reach other sites only through
* `remote/`.
*
* - **Entry point** — builds the application and listens:
* [main](./api/main.ts/index.html).
* - **Routes** — the HTTP API; each router's page lists its endpoints:
* [attachments](./api/routes/attachments.ts/index.html),
* [avatars](./api/routes/avatars.ts/index.html),
* [bandcamp](./api/routes/bandcamp.ts/index.html),
* [categories](./api/routes/categories.ts/index.html),
* [chat](./api/routes/chat.ts/index.html),
* [comments](./api/routes/comments.ts/index.html),
* [dumps](./api/routes/dumps.ts/index.html),
* [files](./api/routes/files.ts/index.html),
* [follows](./api/routes/follows.ts/index.html),
* [invites](./api/routes/invites.ts/index.html),
* [notifications](./api/routes/notifications.ts/index.html),
* [playlists](./api/routes/playlists.ts/index.html),
* [preview](./api/routes/preview.ts/index.html),
* [search](./api/routes/search.ts/index.html),
* [thumbnails](./api/routes/thumbnails.ts/index.html),
* [users](./api/routes/users.ts/index.html),
* [ws](./api/routes/ws.ts/index.html),
* [youtube](./api/routes/youtube.ts/index.html).
* - **Middleware** — what runs around every route:
* [auth](./api/middleware/auth.ts/index.html),
* [error](./api/middleware/error.ts/index.html),
* [og](./api/middleware/og.ts/index.html).
* - **Services** — the logic and every SQL query, one module per domain:
* [attachment-service](./api/services/attachment-service.ts/index.html),
* [backlink-service](./api/services/backlink-service.ts/index.html),
* [category-service](./api/services/category-service.ts/index.html),
* [chat-service](./api/services/chat-service.ts/index.html),
* [comment-like-service](./api/services/comment-like-service.ts/index.html),
* [comment-service](./api/services/comment-service.ts/index.html),
* [dump-service](./api/services/dump-service.ts/index.html),
* [email-service](./api/services/email-service.ts/index.html),
* [follow-service](./api/services/follow-service.ts/index.html),
* [invite-service](./api/services/invite-service.ts/index.html),
* [notification-service](./api/services/notification-service.ts/index.html),
* [password-reset-service](./api/services/password-reset-service.ts/index.html),
* [playlist-service](./api/services/playlist-service.ts/index.html),
* [rich-content-service](./api/services/rich-content-service.ts/index.html),
* [user-service](./api/services/user-service.ts/index.html),
* [vote-service](./api/services/vote-service.ts/index.html),
* [ws-service](./api/services/ws-service.ts/index.html).
* - **Model** — per table, its row type, guard and mappers:
* [auth](./api/model/auth.ts/index.html),
* [category](./api/model/category.ts/index.html),
* [chat](./api/model/chat.ts/index.html),
* [comment](./api/model/comment.ts/index.html),
* [dump](./api/model/dump.ts/index.html),
* [follow](./api/model/follow.ts/index.html),
* [invite](./api/model/invite.ts/index.html),
* [notification](./api/model/notification.ts/index.html),
* [password-reset](./api/model/password-reset.ts/index.html),
* [playlist](./api/model/playlist.ts/index.html),
* [user](./api/model/user.ts/index.html).
* - **Validators** — the request-body guards:
* [category](./api/validators/category.ts/index.html),
* [comment](./api/validators/comment.ts/index.html),
* [dump](./api/validators/dump.ts/index.html),
* [playlist](./api/validators/playlist.ts/index.html),
* [user](./api/validators/user.ts/index.html).
* - **Remote** — the only place that fetches from other sites:
* [bandcamp-streams](./api/remote/bandcamp-streams.ts/index.html),
* [bandcamp-tralbum](./api/remote/bandcamp-tralbum.ts/index.html),
* [fetch](./api/remote/fetch.ts/index.html),
* [html](./api/remote/html.ts/index.html),
* [image-proxy](./api/remote/image-proxy.ts/index.html),
* [public-address](./api/remote/public-address.ts/index.html),
* [twemoji](./api/remote/twemoji.ts/index.html),
* [youtube-playlist](./api/remote/youtube-playlist.ts/index.html).
* - **Link providers** — the previews of each kind of site:
* [bandcamp](./api/remote/providers/bandcamp.ts/index.html),
* [generic](./api/remote/providers/generic.ts/index.html),
* [provider](./api/remote/providers/provider.ts/index.html),
* [self](./api/remote/providers/self.ts/index.html),
* [soundcloud](./api/remote/providers/soundcloud.ts/index.html),
* [youtube](./api/remote/providers/youtube.ts/index.html).
* - **Lib** — helpers that belong to no layer:
* [api-exception](./api/lib/api-exception.ts/index.html),
* [auth](./api/lib/auth.ts/index.html),
* [canonical-url](./api/lib/canonical-url.ts/index.html),
* [index-html](./api/lib/index-html.ts/index.html),
* [jwt](./api/lib/jwt.ts/index.html),
* [pagination](./api/lib/pagination.ts/index.html),
* [permissions](./api/lib/permissions.ts/index.html),
* [playlist-members](./api/lib/playlist-members.ts/index.html),
* [rate-limit](./api/lib/rate-limit.ts/index.html),
* [reserved-slugs](./api/lib/reserved-slugs.ts/index.html),
* [self-url](./api/lib/self-url.ts/index.html),
* [serve-file](./api/lib/serve-file.ts/index.html),
* [site-icons](./api/lib/site-icons.ts/index.html),
* [slugify](./api/lib/slugify.ts/index.html),
* [static](./api/lib/static.ts/index.html),
* [upload](./api/lib/upload.ts/index.html).
* - **Database** — the handle, its creation, migration and startup
* housekeeping: [connection](./api/db/connection.ts/index.html),
* [init](./api/db/init.ts/index.html),
* [migrate](./api/db/migrate.ts/index.html),
* [startup](./api/db/startup.ts/index.html).
* - **Migrations** — applied in order, each once:
* [0001_comment_likes](./api/db/migrations/0001_comment_likes.ts/index.html),
* [0002_dump_thumbnail](./api/db/migrations/0002_dump_thumbnail.ts/index.html),
* [0003_dump_backlinks](./api/db/migrations/0003_dump_backlinks.ts/index.html),
* [0004_user_roles](./api/db/migrations/0004_user_roles.ts/index.html),
* [0005_drop_is_admin](./api/db/migrations/0005_drop_is_admin.ts/index.html),
* [0006_categories](./api/db/migrations/0006_categories.ts/index.html),
* [0007_password_reset_tokens](./api/db/migrations/0007_password_reset_tokens.ts/index.html),
* [0008_chat_messages](./api/db/migrations/0008_chat_messages.ts/index.html),
* [0009_chat_reply](./api/db/migrations/0009_chat_reply.ts/index.html),
* [0010_youtube_embed_start](./api/db/migrations/0010_youtube_embed_start.ts/index.html),
* [0011_split_favicon_thumbnail](./api/db/migrations/0011_split_favicon_thumbnail.ts/index.html),
* [0012_fix_favicon_reclassification](./api/db/migrations/0012_fix_favicon_reclassification.ts/index.html),
* [0013_dump_url_canonical](./api/db/migrations/0013_dump_url_canonical.ts/index.html),
* [0014_chat_read_state](./api/db/migrations/0014_chat_read_state.ts/index.html),
* [0015_token_revocation](./api/db/migrations/0015_token_revocation.ts/index.html),
* [0016_performance_indexes](./api/db/migrations/0016_performance_indexes.ts/index.html).
* - **Settings and scripts**: [config](./api/config.ts/index.html),
* [generate-icons](./api/scripts/generate-icons.ts/index.html).
*
* ## Shared — `shared/`
*
* The types and constants both halves use: the API envelope, each domain's
* types and request bodies, the socket protocol, the validation limits and the
* role permissions. It imports nothing from either half.
*
* Modules: [api](./shared/api.ts/index.html),
* [category](./shared/category.ts/index.html),
* [chat](./shared/chat.ts/index.html),
* [comment](./shared/comment.ts/index.html),
* [dump](./shared/dump.ts/index.html), [follow](./shared/follow.ts/index.html),
* [mention](./shared/mention.ts/index.html),
* [notification](./shared/notification.ts/index.html),
* [permissions](./shared/permissions.ts/index.html),
* [player](./shared/player.ts/index.html),
* [playlist](./shared/playlist.ts/index.html),
* [search](./shared/search.ts/index.html), [user](./shared/user.ts/index.html),
* [validation](./shared/validation.ts/index.html),
* [ws](./shared/ws.ts/index.html).
*
* ## Frontend — `src/`
*
* The React app, built with Vite and translated with Lingui. Each layer holds
* one kind of module, and every layer but pages/ is split into the same domains
* (auth, category, chat, comment, dump, editor, feed, form, layout, player,
* playlist, profile, social, theme, ws, and shared for what belongs to no one
* domain). A page reads the API and the socket through contexts and hooks, and
* draws with components; utils hold what isn't React at all.
*
* - **Entry point and app** — mounting, the providers and the route table, the
* language: [App](./src/App.tsx/index.html),
* [i18n](./src/i18n.ts/index.html), [main](./src/main.tsx/index.html).
* - **Pages** — one component per route, each naming it, and the two guards
* that wrap the routes for the signed in and the signed out:
* [Dump](./src/pages/Dump.tsx/index.html),
* [DumpEdit](./src/pages/DumpEdit.tsx/index.html),
* [Index](./src/pages/Index.tsx/index.html),
* [NotFound](./src/pages/NotFound.tsx/index.html),
* [Notifications](./src/pages/Notifications.tsx/index.html),
* [PlaylistDetail](./src/pages/PlaylistDetail.tsx/index.html),
* [ResetPassword](./src/pages/ResetPassword.tsx/index.html),
* [RestrictedGuest](./src/pages/RestrictedGuest.tsx/index.html),
* [RestrictedLoggedIn](./src/pages/RestrictedLoggedIn.tsx/index.html),
* [Search](./src/pages/Search.tsx/index.html),
* [UserDumps](./src/pages/UserDumps.tsx/index.html),
* [UserLogin](./src/pages/UserLogin.tsx/index.html),
* [UserPlaylists](./src/pages/UserPlaylists.tsx/index.html),
* [UserPublicProfile](./src/pages/UserPublicProfile.tsx/index.html),
* [UserRegister](./src/pages/UserRegister.tsx/index.html),
* [UserUpvoted](./src/pages/UserUpvoted.tsx/index.html).
* - **Config** — settings read at startup:
* [api](./src/config/api.ts/index.html),
* [feedTabs](./src/config/feedTabs.ts/index.html),
* [playerMode](./src/config/playerMode.ts/index.html).
* - **Contexts** — a FooContext holding the state and its FooProvider, by
* domain:
* - auth: [AuthContext](./src/contexts/auth/AuthContext.ts/index.html),
* [AuthProvider](./src/contexts/auth/AuthProvider.tsx/index.html).
* - category:
* [CategoriesContext](./src/contexts/category/CategoriesContext.ts/index.html),
* [CategoriesProvider](./src/contexts/category/CategoriesProvider.tsx/index.html).
* - chat: [ChatContext](./src/contexts/chat/ChatContext.ts/index.html),
* [ChatProvider](./src/contexts/chat/ChatProvider.tsx/index.html).
* - player:
* [PlayerContext](./src/contexts/player/PlayerContext.ts/index.html),
* [PlayerProvider](./src/contexts/player/PlayerProvider.tsx/index.html).
* - social:
* [FollowContext](./src/contexts/social/FollowContext.ts/index.html),
* [FollowProvider](./src/contexts/social/FollowProvider.tsx/index.html).
* - theme: [ThemeContext](./src/contexts/theme/ThemeContext.ts/index.html),
* [ThemeProvider](./src/contexts/theme/ThemeProvider.tsx/index.html).
* - ws:
* [AvatarOverrideContext](./src/contexts/ws/AvatarOverrideContext.ts/index.html),
* [WSContext](./src/contexts/ws/WSContext.ts/index.html),
* [WSProvider](./src/contexts/ws/WSProvider.tsx/index.html).
* - **Hooks** — every hook, by domain:
* - auth: [useAuth](./src/hooks/auth/useAuth.ts/index.html).
* - category:
* [useCategories](./src/hooks/category/useCategories.ts/index.html).
* - chat: [useChat](./src/hooks/chat/useChat.ts/index.html).
* - dump: [useDumpCardLink](./src/hooks/dump/useDumpCardLink.ts/index.html),
* [useDumpListSync](./src/hooks/dump/useDumpListSync.ts/index.html),
* [useUserDumpFeed](./src/hooks/dump/useUserDumpFeed.ts/index.html).
* - editor:
* [useEmojiTrigger](./src/hooks/editor/useEmojiTrigger.ts/index.html),
* [useMentionAutocomplete](./src/hooks/editor/useMentionAutocomplete.ts/index.html).
* - feed:
* [useDefaultFeedTab](./src/hooks/feed/useDefaultFeedTab.ts/index.html),
* [useFading](./src/hooks/feed/useFading.ts/index.html),
* [useFeedCache](./src/hooks/feed/useFeedCache.ts/index.html),
* [useInfiniteScroll](./src/hooks/feed/useInfiniteScroll.ts/index.html),
* [usePositionAwareSync](./src/hooks/feed/usePositionAwareSync.ts/index.html),
* [useScrollSave](./src/hooks/feed/useScrollSave.ts/index.html).
* - form: [useApiForm](./src/hooks/form/useApiForm.ts/index.html).
* - player:
* [usePlayRichContent](./src/hooks/player/usePlayRichContent.ts/index.html),
* [useYouTubePlaylist](./src/hooks/player/useYouTubePlaylist.ts/index.html).
* - playlist:
* [usePlaylistListSync](./src/hooks/playlist/usePlaylistListSync.ts/index.html).
* - shared:
* [useAnchoredFloat](./src/hooks/shared/useAnchoredFloat.ts/index.html),
* [useDocumentTitle](./src/hooks/shared/useDocumentTitle.ts/index.html),
* [useHeightTransition](./src/hooks/shared/useHeightTransition.ts/index.html),
* [useRoomBeside](./src/hooks/shared/useRoomBeside.ts/index.html),
* [useScrollLock](./src/hooks/shared/useScrollLock.ts/index.html),
* [useSoundsEnabled](./src/hooks/shared/useSoundsEnabled.ts/index.html),
* [useTabParam](./src/hooks/shared/useTabParam.ts/index.html).
* - social: [useFollows](./src/hooks/social/useFollows.ts/index.html).
* - theme: [useTheme](./src/hooks/theme/useTheme.ts/index.html).
* - ws: [useWS](./src/hooks/ws/useWS.ts/index.html).
* - **Components** — only components, by domain:
* - category:
* [CategoryManager](./src/components/category/CategoryManager.tsx/index.html),
* [CategorySelect](./src/components/category/CategorySelect.tsx/index.html),
* [CategorySwitcher](./src/components/category/CategorySwitcher.tsx/index.html).
* - chat: [ChatEditBox](./src/components/chat/ChatEditBox.tsx/index.html),
* [ChatMessageItem](./src/components/chat/ChatMessageItem.tsx/index.html),
* [ChatModal](./src/components/chat/ChatModal.tsx/index.html),
* [PendingItem](./src/components/chat/PendingItem.tsx/index.html),
* [ReplyRef](./src/components/chat/ReplyRef.tsx/index.html).
* - comment:
* [CommentForm](./src/components/comment/CommentForm.tsx/index.html),
* [CommentNode](./src/components/comment/CommentNode.tsx/index.html),
* [CommentThread](./src/components/comment/CommentThread.tsx/index.html).
* - dump: [DumpCard](./src/components/dump/DumpCard.tsx/index.html),
* [FilePreview](./src/components/dump/FilePreview.tsx/index.html),
* [JournalCard](./src/components/dump/JournalCard.tsx/index.html),
* [RichContentCard](./src/components/dump/RichContentCard.tsx/index.html),
* [DumpCreateModal](./src/components/dump/create/DumpCreateModal.tsx/index.html),
* [DuplicateNotice](./src/components/dump/create/DuplicateNotice.tsx/index.html),
* [LocalFilePreview](./src/components/dump/create/LocalFilePreview.tsx/index.html),
* [StepIndicator](./src/components/dump/create/StepIndicator.tsx/index.html),
* [TitleField](./src/components/dump/create/TitleField.tsx/index.html).
* - editor:
* [EmojiPickerPopup](./src/components/editor/EmojiPickerPopup.tsx/index.html),
* [Markdown](./src/components/editor/Markdown.tsx/index.html),
* [MentionDropdown](./src/components/editor/MentionDropdown.tsx/index.html),
* [TextEditor](./src/components/editor/TextEditor.tsx/index.html).
* - feed: [DumpFeed](./src/components/feed/DumpFeed.tsx/index.html),
* [FeedTabBar](./src/components/feed/FeedTabBar.tsx/index.html),
* [FollowedFeed](./src/components/feed/FollowedFeed.tsx/index.html),
* [JournalFeed](./src/components/feed/JournalFeed.tsx/index.html),
* [PresenceRow](./src/components/feed/PresenceRow.tsx/index.html).
* - form: [FileDropZone](./src/components/form/FileDropZone.tsx/index.html),
* [FileField](./src/components/form/FileField.tsx/index.html),
* [FormActions](./src/components/form/FormActions.tsx/index.html),
* [FormError](./src/components/form/FormError.tsx/index.html),
* [RichTextField](./src/components/form/RichTextField.tsx/index.html),
* [SegmentedField](./src/components/form/SegmentedField.tsx/index.html),
* [SubmitButton](./src/components/form/SubmitButton.tsx/index.html),
* [TextField](./src/components/form/TextField.tsx/index.html).
* - layout: [AppHeader](./src/components/layout/AppHeader.tsx/index.html),
* [ChatButton](./src/components/layout/ChatButton.tsx/index.html),
* [ChatFab](./src/components/layout/ChatFab.tsx/index.html),
* [DumpFab](./src/components/layout/DumpFab.tsx/index.html),
* [NotificationBell](./src/components/layout/NotificationBell.tsx/index.html),
* [PageError](./src/components/layout/PageError.tsx/index.html),
* [PageShell](./src/components/layout/PageShell.tsx/index.html),
* [SearchBar](./src/components/layout/SearchBar.tsx/index.html),
* [UserMenu](./src/components/layout/UserMenu.tsx/index.html).
* - player:
* [GlobalPlayer](./src/components/player/GlobalPlayer.tsx/index.html),
* [MediaPlayer](./src/components/player/MediaPlayer.tsx/index.html),
* [PlayerIcons](./src/components/player/PlayerIcons.tsx/index.html),
* [SeekBar](./src/components/player/SeekBar.tsx/index.html),
* [Waveform](./src/components/player/Waveform.tsx/index.html).
* - playlist:
* [AddToPlaylistModal](./src/components/playlist/AddToPlaylistModal.tsx/index.html),
* [NewPlaylistButton](./src/components/playlist/NewPlaylistButton.tsx/index.html),
* [PlaylistCard](./src/components/playlist/PlaylistCard.tsx/index.html),
* [PlaylistCreateForm](./src/components/playlist/PlaylistCreateForm.tsx/index.html),
* [PlaylistMembershipPanel](./src/components/playlist/PlaylistMembershipPanel.tsx/index.html).
* - profile:
* [ChangePasswordModal](./src/components/profile/ChangePasswordModal.tsx/index.html),
* [ProfileSubpageHeader](./src/components/profile/ProfileSubpageHeader.tsx/index.html).
* - shared: [Avatar](./src/components/shared/Avatar.tsx/index.html),
* [ConfirmModal](./src/components/shared/ConfirmModal.tsx/index.html),
* [CountedInput](./src/components/shared/CountedInput.tsx/index.html),
* [ErrorCard](./src/components/shared/ErrorCard.tsx/index.html),
* [ImagePicker](./src/components/shared/ImagePicker.tsx/index.html),
* [Modal](./src/components/shared/Modal.tsx/index.html),
* [TabBar](./src/components/shared/TabBar.tsx/index.html),
* [Thumbnail](./src/components/shared/Thumbnail.tsx/index.html),
* [ThumbnailPlaceholder](./src/components/shared/ThumbnailPlaceholder.tsx/index.html),
* [Tooltip](./src/components/shared/Tooltip.tsx/index.html).
* - social:
* [FollowButton](./src/components/social/FollowButton.tsx/index.html),
* [LikeButton](./src/components/social/LikeButton.tsx/index.html),
* [UserListPopover](./src/components/social/UserListPopover.tsx/index.html),
* [VoteButton](./src/components/social/VoteButton.tsx/index.html).
* - **Utils** — every module that isn't React, by domain:
* - auth: [permissions](./src/utils/auth/permissions.ts/index.html),
* [storage](./src/utils/auth/storage.ts/index.html).
* - chat: [draft](./src/utils/chat/draft.ts/index.html),
* [message](./src/utils/chat/message.ts/index.html),
* [text](./src/utils/chat/text.ts/index.html),
* [time](./src/utils/chat/time.ts/index.html).
* - dump: [draft](./src/utils/dump/draft.ts/index.html).
* - editor: [skinTone](./src/utils/editor/skinTone.ts/index.html),
* [text](./src/utils/editor/text.ts/index.html).
* - feed: [hotScore](./src/utils/feed/hotScore.ts/index.html),
* [journalLayout](./src/utils/feed/journalLayout.ts/index.html).
* - player: [bandcamp](./src/utils/player/bandcamp.ts/index.html),
* [duration](./src/utils/player/duration.ts/index.html),
* [streamSources](./src/utils/player/streamSources.ts/index.html),
* [volume](./src/utils/player/volume.ts/index.html),
* [waveform](./src/utils/player/waveform.ts/index.html),
* [youtube](./src/utils/player/youtube.ts/index.html).
* - shared: [api](./src/utils/shared/api.ts/index.html),
* [charCount](./src/utils/shared/charCount.ts/index.html),
* [deserialize](./src/utils/shared/deserialize.ts/index.html),
* [format](./src/utils/shared/format.ts/index.html),
* [proxyImage](./src/utils/shared/proxyImage.ts/index.html),
* [relativeTime](./src/utils/shared/relativeTime.ts/index.html),
* [sound](./src/utils/shared/sound.ts/index.html),
* [thumbnailTint](./src/utils/shared/thumbnailTint.ts/index.html),
* [urls](./src/utils/shared/urls.ts/index.html),
* [visited](./src/utils/shared/visited.ts/index.html).
*
* @module
*/