* feat: implement instance share page + search_users backend call * feat: invite players modal * feat: use tanstack queries for friends sync across app pages * feat: base shared instances implementation * fix: admon style * feat: impl instance admonitions like server panel * fix: impl get + del usage * feat: support modpack links * feat: invite notif accepting * fix: lint + fmt * feat: impl install to play * feat: impl usage of UpdateToPlayModal * feat: warnings on deleting/disabling shared-instance version content * fix: send instance name * feat: align with backend * feat: shared instances qa * feat: wrong account protection * feat: qa * fix: smartly apply updates * fix: install bug * fix: 401/404 differentiation * fix: fmt+prepr * feat: qa * feat: qa * fix: signing out messes up revoke/deleted checks * feat: qa * fix: fmt + lint * feat: lock content if part of shared instance * fix: lint * [do not merge] feat: rough invite links impl temp (#6666) * fix: wrong cmd * feat: invite page * fix: server-manager DTO mismatch * fix: drop anonymous invite link acceptance * refactor: structured shared-instance unavailable errors * refactor: centralise error presentations * refactor: dedupe shared instance diff detection * fix: logging in reqwests * refactor: move app.vue shared instances into handler * refactor: break up Share.vue * refactor: split up shared instances state outside of instance index * refactor: dedicated shared instances install/update modals + split up page * refactor: centralized managed content * refactor: split up install shared to own runner + shared.rs split up * refactor: dedupe sql for instance metadata enrichmnt * refactor: friends composable + dedupe friends logic across usages * chore: reduced unused code * fix: align with backend * fix: lint * fix: file sha changes * fix: invite links not working due to icon signed * feat: qa * feat: reporting frontend dummy * fix: try use header * remove: file hash field * fix: pin box * feat: malware warning for shared instances * fix: cache rule * feat: config files syncing * feat: disable config sharing * fix: header * fix: use mark ready * fix: dont cause push update for configs * fix: lint * feat: sharing page in settings * feat: move config + change flow * fix: qa * fix: lint prepr * feat: proxy file upload thru shared instances backend * fix: use collapisible * fix: push config * fix: config * feat: swap out sign in modal for new one * fix: report flow * fix: exclude configs.zip from external warnings * fix: nuxi init * fix: config bundle downloading * fix: error notif * fix: polling * fix: qa * fix: lint + prepr * feat: shared instances moderation frontend + hook up report flow * fix: report copy * fix: lint * fix: lint * fix: modrinth ids being undefined * feat: instance quarantining * fix: prepr + fmt * fix: quarantined -> locked terminology * fix: missing endpoint impls + fmt * fix: missing api in build.rs * fix: share tab jittery * fix: fmt *PT bug * fix: invites count as users even if pending * fix: prepr * fix: invite page owner in users list * fix: lint * fix: qa * fix: lint * fix: members stale not clearing * fix: invite use joined_at field * fix: lint * fix: qa --------- Co-authored-by: sychic <47618543+Sychic@users.noreply.github.com>
@modrinth/api-client
Platform-agnostic TypeScript client for Modrinth's API across Node.js, browsers, Nuxt, and Tauri.
⚠️ We use this internally to power modrinth.com, Modrinth App, and Modrinth Hosting frontends. It may break without any notice, but you are welcome to use it.
Installation
pnpm add @modrinth/api-client
Tauri apps also need the optional peer dependency:
pnpm add @modrinth/api-client @tauri-apps/plugin-http
Usage
Generic Node.js or Browser Client
import { AuthFeature, GenericModrinthClient, type Labrinth } from '@modrinth/api-client'
const client = new GenericModrinthClient({
userAgent: 'my-app/1.0.0',
features: [new AuthFeature({ token: process.env.MODRINTH_TOKEN })],
})
const project: Labrinth.Projects.v2.Project = await client.labrinth.projects_v2.get('sodium')
const members = await client.labrinth.projects_v3.getMembers(project.id)
You can still make direct requests through the same platform layer:
const project = await client.request<Labrinth.Projects.v2.Project>('/project/sodium', {
api: 'labrinth',
version: 2,
})
Nuxt
import { AuthFeature, CircuitBreakerFeature, NuxtCircuitBreakerStorage, NuxtModrinthClient } from '@modrinth/api-client'
export const useModrinthClient = async () => {
const config = useRuntimeConfig()
return new NuxtModrinthClient({
userAgent: 'my-nuxt-app/1.0.0',
rateLimitKey: import.meta.server ? config.rateLimitKey : undefined,
features: [
new AuthFeature({
token: process.env.MODRINTH_TOKEN,
}),
new CircuitBreakerFeature({
storage: new NuxtCircuitBreakerStorage(),
}),
],
})
}
Tauri
import { getVersion } from '@tauri-apps/api/app'
import { AuthFeature, TauriModrinthClient } from '@modrinth/api-client'
const client = new TauriModrinthClient({
userAgent: async () => `modrinth/theseus/${await getVersion()} (support@modrinth.com)`,
features: [new AuthFeature({ token: process.env.MODRINTH_TOKEN })],
})
const project = await client.labrinth.projects_v2.get('sodium')
API Modules
Modules are available as nested properties on the client:
client.labrinth.projects_v2
client.labrinth.projects_v3
client.labrinth.versions_v3
Types are exported from the package root:
import type { Labrinth } from '@modrinth/api-client'
const project: Labrinth.Projects.v3.Project = await client.labrinth.projects_v3.get('sodium')
Modrinth Hosting API Modules
- These modules are internal to Modrinth and are only supported inside the Modrinth Hosting panel in Modrinth App and on modrinth.com. They should not be expected to work in third-party clients today. We are discussing how to safely expose access to your own server through these APIs in the future.
Base URLs
By default, the client uses Modrinth production services:
labrinthBaseUrl:https://api.modrinth.com
Override them for staging or custom deployments:
const client = new GenericModrinthClient({
userAgent: 'my-app/1.0.0',
labrinthBaseUrl: 'https://staging-api.modrinth.com',
})
External APIs can be targeted per request by passing a full URL as api and disabling auth:
await client.request('/endpoint', {
api: 'https://example.com',
version: 1,
skipAuth: true,
})
Features
Features wrap requests before they reach the platform implementation:
import { AuthFeature, CircuitBreakerFeature, RetryFeature } from '@modrinth/api-client'
const client = new GenericModrinthClient({
features: [new AuthFeature({ token: async () => process.env.MODRINTH_TOKEN }), new RetryFeature({ maxAttempts: 3, backoffStrategy: 'exponential' }), new CircuitBreakerFeature({ maxFailures: 3, resetTimeout: 30_000 })],
})
Built-in features include authentication, node auth, retries, circuit breaking, panel version headers, and verbose logging.
Uploads
Upload endpoints return an UploadHandle<T> with progress and cancellation support:
const upload = client.kyros.files_v0.uploadFile(path, file)
upload.onProgress(({ progress }) => {
console.log(Math.round(progress * 100))
})
await upload.promise
Uploads use XMLHttpRequest for progress tracking and are only available in browser-capable contexts. NuxtModrinthClient.upload() throws during SSR.
Third-Party API Typings
- This package also includes some third-party API modules and typings used by Modrinth internals. They are not part of the stable public API surface and should be used at your own risk.
Development
pnpm --filter @modrinth/api-client build
pnpm --filter @modrinth/api-client lint
# or pnpm prepr:frontend:lib in turborepo root.
When adding a module, add it to src/modules/index.ts so it is included in the typed client structure.
License
Licensed under LGPL-3.0. See LICENSE.