refactor: remove useBaseFetch for @modrinth/api-client (#5596)

* Reapply "fix: start swapping useBaseFetch usages to api-client"

This reverts commit f4f33db7019ea861addb2c66c204d736800b7b6c.

* fix: bugs

* fix: analytics

* fix: lint
This commit is contained in:
Calum H.
2026-03-17 20:06:19 +00:00
committed by GitHub
parent 58c1e225c8
commit 87c86c7d0d
64 changed files with 2073 additions and 691 deletions

View File

@@ -328,6 +328,7 @@ import {
Categories,
CopyCode,
DoubleIcon,
injectModrinthClient,
injectNotificationManager,
ProjectStatusBadge,
useFormatDateTime,
@@ -341,6 +342,7 @@ import { acceptTeamInvite, removeSelfFromTeam } from '~/helpers/teams'
import ThreadSummary from './thread/ThreadSummary.vue'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
const emit = defineEmits(['update:notifications'])
const formatRelativeTime = useRelativeTime()
@@ -407,7 +409,7 @@ async function read() {
? props.notification.grouped_notifs.map((notif) => notif.id)
: []),
]
const updateNotifs = await markAsRead(ids)
const updateNotifs = await markAsRead(client, ids)
const newNotifs = updateNotifs(props.notifications)
emit('update:notifications', newNotifs)
} catch (err) {

View File

@@ -357,7 +357,7 @@ const props = withDefaults(
},
)
const projects = ref(props.projects || [])
const projects = computed(() => props.projects || [])
// const selectedChart = ref('downloads')
const selectedChart = computed({
@@ -389,6 +389,13 @@ const tinyRevenueChart = ref()
const selectedDisplayProjects = ref(props.projects || [])
watch(
() => props.projects,
(newProjects) => {
selectedDisplayProjects.value = newProjects || []
},
)
const removeProjectFromDisplay = (id: string) => {
selectedDisplayProjects.value = selectedDisplayProjects.value.filter((p) => p.id !== id)
}

View File

@@ -42,13 +42,18 @@
<script setup lang="ts">
import { MessageIcon } from '@modrinth/assets'
import { Admonition, ButtonStyled, defineMessages, useVIntl } from '@modrinth/ui'
import {
Admonition,
ButtonStyled,
defineMessages,
injectModrinthClient,
useVIntl,
} from '@modrinth/ui'
import { capitalizeString } from '@modrinth/utils'
import { useQuery } from '@tanstack/vue-query'
import { computed, watch } from 'vue'
import { useBaseFetch } from '~/composables/fetch.js'
const client = injectModrinthClient()
const { formatMessage } = useVIntl()
const messages = defineMessages({
@@ -100,33 +105,24 @@ const messages = defineMessages({
},
})
interface UserLimits {
current: number
max: number
}
const props = defineProps<{
type: 'project' | 'org' | 'collection'
}>()
const model = defineModel<boolean>()
const apiEndpoint = computed(() => {
switch (props.type) {
case 'project':
return 'limits/projects'
case 'org':
return 'limits/organizations'
case 'collection':
return 'limits/collections'
default:
return 'limits/projects'
}
})
const { data: limits } = useQuery({
queryKey: computed(() => ['limits', props.type]),
queryFn: () => useBaseFetch(apiEndpoint.value, { apiVersion: 3 }) as Promise<UserLimits>,
queryFn: () => {
switch (props.type) {
case 'org':
return client.labrinth.limits_v3.getOrganizationLimits()
case 'collection':
return client.labrinth.limits_v3.getCollectionLimits()
default:
return client.labrinth.limits_v3.getProjectLimits()
}
},
})
const typeName = computed<{ singular: string; plural: string }>(() => {

View File

@@ -107,6 +107,7 @@
</template>
<script setup lang="ts">
import type { Labrinth } from '@modrinth/api-client'
import {
ArrowLeftRightIcon,
ChevronRightIcon,
@@ -131,7 +132,6 @@ import {
getTaxThreshold,
getTaxThresholdActual,
type PaymentProvider,
type PayoutMethod,
provideWithdrawContext,
type WithdrawStage,
} from '@/providers/creator-withdraw.ts'
@@ -146,21 +146,9 @@ import MuralpayKycStage from './withdraw-stages/MuralpayKycStage.vue'
import TaxFormStage from './withdraw-stages/TaxFormStage.vue'
import TremendousDetailsStage from './withdraw-stages/TremendousDetailsStage.vue'
type FormCompletionStatus = 'unknown' | 'unrequested' | 'unsigned' | 'tin-mismatch' | 'complete'
interface UserBalanceResponse {
available: number
withdrawn_lifetime: number
withdrawn_ytd: number
pending: number
dates: Record<string, number>
requested_form_type: string | null
form_completion_status: FormCompletionStatus | null
}
const props = defineProps<{
balance: UserBalanceResponse | null
preloadedPaymentData?: { country: string; methods: PayoutMethod[] } | null
balance: Labrinth.Payout.v3.PayoutBalance | null | undefined
preloadedPaymentData?: { country: string; methods: Labrinth.Payout.v3.PayoutMethod[] } | null
}>()
const emit = defineEmits<{

View File

@@ -66,6 +66,7 @@
</template>
<script setup lang="ts">
import type { Labrinth } from '@modrinth/api-client'
import {
ArrowDownIcon,
ArrowUpIcon,
@@ -89,31 +90,7 @@ import { Tooltip } from 'floating-vue'
import { useGeneratedState } from '~/composables/generated'
import { findRail } from '~/utils/muralpay-rails'
type PayoutStatus = 'in-transit' | 'cancelling' | 'cancelled' | 'success' | 'failed'
type PayoutMethodType = 'paypal' | 'venmo' | 'tremendous' | 'muralpay'
type PayoutSource = 'creator_rewards' | 'affilites'
type WithdrawalTransaction = {
type: 'withdrawal'
id: string
status: PayoutStatus
created: string
amount: number
fee?: number | null
method_type?: PayoutMethodType | null
method?: string
method_id?: string
method_address?: string | null
}
type PayoutAvailableTransaction = {
type: 'payout_available'
created: string
payout_source: PayoutSource
amount: number
}
type Transaction = WithdrawalTransaction | PayoutAvailableTransaction
type Transaction = Labrinth.Payout.v3.TransactionItem
const props = defineProps<{
transaction: Transaction

View File

@@ -21,13 +21,13 @@
</div>
</template>
<script setup>
import { injectModrinthClient } from '@modrinth/ui'
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed } from 'vue'
import Breadcrumbs from '~/components/ui/Breadcrumbs.vue'
import ReportInfo from '~/components/ui/report/ReportInfo.vue'
import ConversationThread from '~/components/ui/thread/ConversationThread.vue'
import { useBaseFetch } from '~/composables/fetch.js'
import { addReportMessage } from '~/helpers/threads.js'
const props = defineProps({
@@ -45,16 +45,13 @@ const props = defineProps({
},
})
const client = injectModrinthClient()
const queryClient = useQueryClient()
// Fetch raw report
const { data: rawReport } = useQuery({
queryKey: computed(() => ['report', props.reportId]),
queryFn: async () => {
const data = await useBaseFetch(`report/${props.reportId}`)
data.item_id = data.item_id.replace(/"/g, '')
return data
},
queryFn: () => client.labrinth.reports_v3.get(props.reportId),
})
// Compute user IDs needed
@@ -70,7 +67,7 @@ const userIds = computed(() => {
// Fetch users
const { data: users } = useQuery({
queryKey: computed(() => ['users', userIds.value]),
queryFn: () => useBaseFetch(`users?ids=${encodeURIComponent(JSON.stringify(userIds.value))}`),
queryFn: () => client.labrinth.users_v2.getMultiple(userIds.value),
enabled: computed(() => userIds.value.length > 0),
})
@@ -82,7 +79,7 @@ const versionId = computed(() =>
// Fetch version
const { data: version } = useQuery({
queryKey: computed(() => ['version', versionId.value]),
queryFn: () => useBaseFetch(`version/${versionId.value}`),
queryFn: () => client.labrinth.versions_v2.getVersion(versionId.value),
enabled: computed(() => !!versionId.value),
})
@@ -96,7 +93,7 @@ const projectId = computed(() => {
// Fetch project
const { data: project } = useQuery({
queryKey: computed(() => ['project', projectId.value]),
queryFn: () => useBaseFetch(`project/${projectId.value}`),
queryFn: () => client.labrinth.projects_v2.get(projectId.value),
enabled: computed(() => !!projectId.value),
})
@@ -118,7 +115,7 @@ const report = computed(() => {
// Fetch thread
const { data: rawThread } = useQuery({
queryKey: computed(() => ['thread', report.value?.thread_id]),
queryFn: () => useBaseFetch(`thread/${report.value.thread_id}`),
queryFn: () => client.labrinth.threads_v3.getThread(report.value.thread_id),
enabled: computed(() => !!report.value?.thread_id),
})

View File

@@ -24,14 +24,13 @@
<p v-if="filteredReports.length === 0">You don't have any active reports.</p>
</template>
<script setup>
import { Chips } from '@modrinth/ui'
import { Chips, injectModrinthClient } from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import { computed, ref } from 'vue'
import ReportInfo from '~/components/ui/report/ReportInfo.vue'
import { useBaseFetch } from '~/composables/fetch.js'
import { addReportMessage } from '~/helpers/threads.js'
import { asEncodedJsonArray, fetchSegmented } from '~/utils/fetch-helpers.ts'
import { fetchSegmentedWith } from '~/utils/fetch-helpers.ts'
const props = defineProps({
moderation: {
@@ -44,6 +43,7 @@ const props = defineProps({
},
})
const client = injectModrinthClient()
const viewMode = ref('open')
const reasonFilter = ref('All')
@@ -51,16 +51,11 @@ const MAX_REPORTS = 1500
const { data: rawReportsData } = useQuery({
queryKey: ['reports', MAX_REPORTS],
queryFn: () => useBaseFetch(`report?count=${MAX_REPORTS}`),
queryFn: () => client.labrinth.reports_v3.list({ count: MAX_REPORTS }),
placeholderData: [],
})
const rawReports = computed(() =>
rawReportsData.value.map((report) => ({
...report,
item_id: report.item_id.replace(/"/g, ''),
})),
)
const rawReports = computed(() => rawReportsData.value)
const reporterUsers = computed(() => rawReports.value.map((report) => report.reporter))
const reportedUsers = computed(() =>
@@ -85,7 +80,8 @@ const reasons = computed(() => [
const { data: users } = useQuery({
queryKey: computed(() => ['users', userIds.value]),
queryFn: () => fetchSegmented(userIds.value, (ids) => `users?ids=${asEncodedJsonArray(ids)}`),
queryFn: () =>
fetchSegmentedWith(userIds.value, (ids) => client.labrinth.users_v2.getMultiple(ids)),
enabled: computed(() => userIds.value.length > 0),
placeholderData: [],
})
@@ -93,14 +89,15 @@ const { data: users } = useQuery({
const { data: versions } = useQuery({
queryKey: computed(() => ['versions', versionIds.value]),
queryFn: () =>
fetchSegmented(versionIds.value, (ids) => `versions?ids=${asEncodedJsonArray(ids)}`),
fetchSegmentedWith(versionIds.value, (ids) => client.labrinth.versions_v2.getVersions(ids)),
enabled: computed(() => versionIds.value.length > 0),
placeholderData: [],
})
const { data: threads } = useQuery({
queryKey: computed(() => ['threads', threadIds.value]),
queryFn: () => fetchSegmented(threadIds.value, (ids) => `threads?ids=${asEncodedJsonArray(ids)}`),
queryFn: () =>
fetchSegmentedWith(threadIds.value, (ids) => client.labrinth.threads_v3.getMultiple(ids)),
enabled: computed(() => threadIds.value.length > 0),
placeholderData: [],
})
@@ -118,7 +115,7 @@ const projectIds = computed(() => [
const { data: projects } = useQuery({
queryKey: computed(() => ['projects', projectIds.value]),
queryFn: () =>
fetchSegmented(projectIds.value, (ids) => `projects?ids=${asEncodedJsonArray(ids)}`),
fetchSegmentedWith(projectIds.value, (ids) => client.labrinth.projects_v2.getMultiple(ids)),
enabled: computed(() => projectIds.value.length > 0),
placeholderData: [],
})

View File

@@ -1,47 +1,15 @@
import type { Organization, Project, Report, User, Version } from '@modrinth/utils'
import type { AbstractModrinthClient, Labrinth } from '@modrinth/api-client'
type Thread = { id: string }
type Notification = Labrinth.Notifications.v2.Notification
export type PlatformNotificationAction = {
title: string
action_route: [string, string]
}
export type PlatformNotificationBody = {
project_id?: string
version_id?: string
report_id?: string
thread_id?: string
invited_by?: string
organization_id?: string
}
export type PlatformNotification = {
id: string
user_id: string
type: 'project_update' | 'team_invite' | 'status_change' | 'moderator_message'
title: string
text: string
link: string
read: boolean
created: string
actions: PlatformNotificationAction[]
body?: PlatformNotificationBody
export type PlatformNotification = Notification & {
extra_data?: Record<string, unknown>
grouped_notifs?: PlatformNotification[]
}
async function getBulk<T extends { id: string }>(
type: string,
ids: string[],
apiVersion = 2,
): Promise<T[]> {
if (!ids || ids.length === 0) {
return []
}
const url = `${type}?ids=${encodeURIComponent(JSON.stringify([...new Set(ids)]))}`
async function safeBulkFetch<T>(fn: () => Promise<T[]>): Promise<T[]> {
try {
const res = await useBaseFetch(url, { apiVersion })
const res = await fn()
return Array.isArray(res) ? res : []
} catch {
return []
@@ -49,6 +17,7 @@ async function getBulk<T extends { id: string }>(
}
export async function fetchExtraNotificationData(
client: AbstractModrinthClient,
notifications: PlatformNotification[],
): Promise<PlatformNotification[]> {
const bulk = {
@@ -72,7 +41,14 @@ export async function fetchExtraNotificationData(
}
}
const reports = (await getBulk<Report>('reports', bulk.reports)).filter(Boolean)
const reports = (
await safeBulkFetch(() =>
bulk.reports.length > 0
? client.labrinth.reports_v3.getMultiple([...new Set(bulk.reports)])
: Promise.resolve([]),
)
).filter(Boolean)
for (const r of reports) {
if (!r?.item_type) continue
if (r.item_type === 'project') bulk.projects.push(r.item_id)
@@ -80,16 +56,42 @@ export async function fetchExtraNotificationData(
else if (r.item_type === 'version') bulk.versions.push(r.item_id)
}
const versions = (await getBulk<Version>('versions', bulk.versions)).filter(Boolean)
const versions = (
await safeBulkFetch(() =>
bulk.versions.length > 0
? client.labrinth.versions_v2.getVersions([...new Set(bulk.versions)])
: Promise.resolve([]),
)
).filter(Boolean)
for (const v of versions) bulk.projects.push(v.project_id)
const [projects, threads, users, organizations] = await Promise.all([
getBulk<Project>('projects', bulk.projects),
getBulk<Thread>('threads', bulk.threads),
getBulk<User>('users', bulk.users),
getBulk<Organization>('organizations', bulk.organizations, 3),
safeBulkFetch(() =>
bulk.projects.length > 0
? client.labrinth.projects_v2.getMultiple([...new Set(bulk.projects)])
: Promise.resolve([]),
),
safeBulkFetch(() =>
bulk.threads.length > 0
? client.labrinth.threads_v3.getMultiple([...new Set(bulk.threads)])
: Promise.resolve([]),
),
safeBulkFetch(() =>
bulk.users.length > 0
? client.labrinth.users_v2.getMultiple([...new Set(bulk.users)])
: Promise.resolve([]),
),
safeBulkFetch(() =>
bulk.organizations.length > 0
? client.labrinth.organizations_v3.getMultiple([...new Set(bulk.organizations)])
: Promise.resolve([]),
),
])
type Report = Labrinth.Reports.v3.Report
type Version = Labrinth.Versions.v2.Version
for (const n of notifications) {
n.extra_data = {}
if (n.body) {
@@ -153,11 +155,10 @@ function isSimilar(a: PlatformNotification, b: PlatformNotification | undefined)
}
export async function markAsRead(
client: AbstractModrinthClient,
ids: string[],
): Promise<(notifications: PlatformNotification[]) => PlatformNotification[]> {
await useBaseFetch(`notifications?ids=${JSON.stringify([...new Set(ids)])}`, {
method: 'PATCH',
})
await client.labrinth.notifications_v2.markMultipleAsRead(ids)
return (notifications: PlatformNotification[]) => {
const newNotifs = notifications ?? []
newNotifs.forEach((n) => {

View File

@@ -1541,7 +1541,7 @@ async function getLicenseData(event) {
modalLicense.value.show(event)
try {
const text = await useBaseFetch(`tag/license/${project.value.license.id}`)
const text = await client.labrinth.tags_v2.getLicenseText(project.value.license.id)
licenseText.value = text.body || formatMessage(messages.licenseErrorMessage)
} catch {
licenseText.value = formatMessage(messages.licenseErrorMessage)
@@ -1895,10 +1895,7 @@ async function invalidateProject() {
// Mutation for patching project data
const patchProjectMutation = useMutation({
mutationFn: async ({ projectId, data }) => {
await useBaseFetch(`project/${projectId}`, {
method: 'PATCH',
body: data,
})
await client.labrinth.projects_v2.edit(projectId, data)
return data
},
@@ -1942,10 +1939,7 @@ const patchProjectMutation = useMutation({
// Mutation for changing project status (setProcessing)
const patchStatusMutation = useMutation({
mutationFn: async ({ projectId, status }) => {
await useBaseFetch(`project/${projectId}`, {
method: 'PATCH',
body: { status },
})
await client.labrinth.projects_v2.edit(projectId, { status })
},
onMutate: async ({ projectId, status }) => {
@@ -2038,13 +2032,8 @@ const patchProjectV3Mutation = useMutation({
// Mutation for patching project icon
const patchIconMutation = useMutation({
mutationFn: async ({ projectId, icon }) => {
await useBaseFetch(
`project/${projectId}/icon?ext=${icon.type.split('/')[icon.type.split('/').length - 1]}`,
{
method: 'PATCH',
body: icon,
},
)
const ext = icon.type.split('/')[icon.type.split('/').length - 1]
await client.labrinth.projects_v3.changeIcon(projectId, icon, ext)
},
onSuccess: () => {
@@ -2070,23 +2059,13 @@ const patchIconMutation = useMutation({
const createGalleryItemMutation = useMutation({
mutationFn: async ({ projectId, file, title, description, featured, ordering }) => {
let url = `project/${projectId}/gallery?ext=${
file.type.split('/')[file.type.split('/').length - 1]
}&featured=${featured ?? false}`
if (title != null) {
url += `&title=${encodeURIComponent(title)}`
}
if (description != null) {
url += `&description=${encodeURIComponent(description)}`
}
if (ordering !== null && ordering !== undefined) {
url += `&ordering=${ordering}`
}
await useBaseFetch(url, {
method: 'POST',
body: file,
const ext = file.type.split('/')[file.type.split('/').length - 1]
await client.labrinth.projects_v2.createGalleryImage(projectId, file, {
ext,
featured: featured ?? false,
title,
description,
ordering,
})
},
@@ -2133,20 +2112,11 @@ const createGalleryItemMutation = useMutation({
const editGalleryItemMutation = useMutation({
mutationFn: async ({ projectId, imageUrl, title, description, featured, ordering }) => {
let url = `project/${projectId}/gallery?url=${encodeURIComponent(imageUrl)}&featured=${featured ?? false}`
if (title != null) {
url += `&title=${encodeURIComponent(title)}`
}
if (description != null) {
url += `&description=${encodeURIComponent(description)}`
}
if (ordering !== null && ordering !== undefined) {
url += `&ordering=${ordering}`
}
await useBaseFetch(url, {
method: 'PATCH',
await client.labrinth.projects_v2.editGalleryImage(projectId, imageUrl, {
featured: featured ?? false,
title,
description,
ordering,
})
},
@@ -2195,9 +2165,7 @@ const editGalleryItemMutation = useMutation({
const deleteGalleryItemMutation = useMutation({
mutationFn: async ({ projectId, imageUrl }) => {
await useBaseFetch(`project/${projectId}/gallery?url=${encodeURIComponent(imageUrl)}`, {
method: 'DELETE',
})
await client.labrinth.projects_v2.deleteGalleryImage(projectId, imageUrl)
},
onMutate: async ({ imageUrl }) => {
@@ -2562,9 +2530,7 @@ async function deleteVersion(id) {
startLoading()
await useBaseFetch(`version/${id}`, {
method: 'DELETE',
})
await client.labrinth.versions_v3.deleteVersion(id)
await invalidateProject()

View File

@@ -100,12 +100,16 @@
</template>
<script setup>
import { CheckIcon, IssuesIcon, XIcon } from '@modrinth/assets'
import { Badge, injectNotificationManager, injectProjectPageContext } from '@modrinth/ui'
import {
Badge,
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
} from '@modrinth/ui'
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed } from 'vue'
import ConversationThread from '~/components/ui/thread/ConversationThread.vue'
import { useBaseFetch } from '~/composables/fetch.js'
import {
getProjectLink,
isApproved,
@@ -119,11 +123,12 @@ const { addNotification } = injectNotificationManager()
const { projectV2: project, currentMember, invalidate } = injectProjectPageContext()
const auth = await useAuth()
const client = injectModrinthClient()
const queryClient = useQueryClient()
const { data: thread } = useQuery({
queryKey: computed(() => ['thread', project.value?.thread_id]),
queryFn: () => useBaseFetch(`thread/${project.value.thread_id}`),
queryFn: () => client.labrinth.threads_v3.getThread(project.value.thread_id),
enabled: computed(() => !!project.value?.thread_id),
})
@@ -131,12 +136,7 @@ async function setStatus(status) {
startLoading()
try {
const data = {}
data.status = status
await useBaseFetch(`project/${project.value.id}`, {
method: 'PATCH',
body: data,
})
await client.labrinth.projects_v2.edit(project.value.id, { status })
project.value.status = status
await invalidate()

View File

@@ -558,6 +558,7 @@ import {
Checkbox,
Combobox,
ConfirmModal,
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
StyledInput,
@@ -566,9 +567,9 @@ import {
import { useQuery } from '@tanstack/vue-query'
import ConfirmTransferProjectModal from '~/components/ui/ConfirmTransferProjectModal.vue'
import { useBaseFetch } from '~/composables/fetch.js'
import { removeSelfFromTeam } from '~/helpers/teams.js'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
const {
projectV2: project,
@@ -623,10 +624,7 @@ const transferModal = ref(null)
const { data: organizations } = useQuery({
queryKey: computed(() => ['user', auth.value?.user?.id, 'organizations']),
queryFn: () =>
useBaseFetch('user/' + auth.value?.user.id + '/organizations', {
apiVersion: 3,
}),
queryFn: () => client.labrinth.users_v2.getOrganizations(auth.value?.user.id),
enabled: computed(() => !!auth.value?.user?.id),
})
@@ -655,12 +653,8 @@ const VIEW_PAYOUTS = 1 << 9
const onAddToOrg = useClientTry(async () => {
if (!selectedOrganizationId.value) return
await useBaseFetch(`organization/${selectedOrganizationId.value}/projects`, {
method: 'POST',
body: JSON.stringify({
project_id: project.value.id,
}),
apiVersion: 3,
await client.labrinth.organizations_v3.addProject(selectedOrganizationId.value, {
project_id: project.value.id,
})
await updateMembers()
@@ -675,13 +669,11 @@ const onAddToOrg = useClientTry(async () => {
const onRemoveFromOrg = useClientTry(async () => {
if (!project.value.organization || !auth.value?.user?.id) return
await useBaseFetch(`organization/${project.value.organization}/projects/${project.value.id}`, {
method: 'DELETE',
body: JSON.stringify({
new_owner: auth.value.user.id,
}),
apiVersion: 3,
})
await client.labrinth.organizations_v3.removeProject(
project.value.organization,
project.value.id,
{ new_owner: auth.value.user.id },
)
await updateMembers()
@@ -701,13 +693,9 @@ const inviteTeamMember = async () => {
startLoading()
try {
const user = await useBaseFetch(`user/${currentUsername.value}`)
const data = {
const user = await client.labrinth.users_v2.get(currentUsername.value)
await client.labrinth.teams_v2.addMember(project.value.team, {
user_id: user.id.trim(),
}
await useBaseFetch(`team/${project.value.team}/members`, {
method: 'POST',
body: data,
})
currentUsername.value = ''
await updateMembers()
@@ -726,11 +714,9 @@ const removeTeamMember = async (index) => {
startLoading()
try {
await useBaseFetch(
`team/${project.value.team}/members/${allTeamMembers.value[index].user.id}`,
{
method: 'DELETE',
},
await client.labrinth.teams_v2.removeMember(
project.value.team,
allTeamMembers.value[index].user.id,
)
await updateMembers()
addNotification({
@@ -764,12 +750,10 @@ const updateTeamMember = async (index) => {
role: allTeamMembers.value[index].role,
}
await useBaseFetch(
`team/${project.value.team}/members/${allTeamMembers.value[index].user.id}`,
{
method: 'PATCH',
body: data,
},
await client.labrinth.teams_v2.editMember(
project.value.team,
allTeamMembers.value[index].user.id,
data,
)
await updateMembers()
addNotification({
@@ -820,11 +804,8 @@ const transferOwnership = async (index) => {
startLoading()
try {
await useBaseFetch(`team/${project.value.team}/owner`, {
method: 'PATCH',
body: {
user_id: allTeamMembers.value[index].user.id,
},
await client.labrinth.teams_v2.transferOwnership(project.value.team, {
user_id: allTeamMembers.value[index].user.id,
})
addNotification({
title: 'Member ownership transferred',
@@ -848,32 +829,25 @@ async function updateOrgMember(index) {
try {
if (allOrgMembers.value[index].override && !allOrgMembers.value[index].oldOverride) {
await useBaseFetch(`team/${project.value.team}/members`, {
method: 'POST',
body: {
await client.labrinth.teams_v2.addMember(project.value.team, {
permissions: allOrgMembers.value[index].permissions,
role: allOrgMembers.value[index].role,
payouts_split: allOrgMembers.value[index].payouts_split,
user_id: allOrgMembers.value[index].user.id,
})
} else if (!allOrgMembers.value[index].override && allOrgMembers.value[index].oldOverride) {
await client.labrinth.teams_v2.removeMember(
project.value.team,
allOrgMembers.value[index].user.id,
)
} else {
await client.labrinth.teams_v2.editMember(
project.value.team,
allOrgMembers.value[index].user.id,
{
permissions: allOrgMembers.value[index].permissions,
role: allOrgMembers.value[index].role,
payouts_split: allOrgMembers.value[index].payouts_split,
user_id: allOrgMembers.value[index].user.id,
},
})
} else if (!allOrgMembers.value[index].override && allOrgMembers.value[index].oldOverride) {
await useBaseFetch(
`team/${project.value.team}/members/${allOrgMembers.value[index].user.id}`,
{
method: 'DELETE',
},
)
} else {
await useBaseFetch(
`team/${project.value.team}/members/${allOrgMembers.value[index].user.id}`,
{
method: 'PATCH',
body: {
permissions: allOrgMembers.value[index].permissions,
role: allOrgMembers.value[index].role,
payouts_split: allOrgMembers.value[index].payouts_split,
},
},
)
}

View File

@@ -82,6 +82,7 @@
</div>
</template>
<script setup lang="ts">
import type { Labrinth } from '@modrinth/api-client'
import { PlusIcon, SearchIcon, XCircleIcon } from '@modrinth/assets'
import {
Accordion,
@@ -91,20 +92,20 @@ import {
Avatar,
ButtonStyled,
ConfirmModal,
injectModrinthClient,
injectNotificationManager,
StyledInput,
} from '@modrinth/ui'
import type { AffiliateLink, User } from '@modrinth/utils'
import type { User } from '@modrinth/utils'
import { useQuery } from '@tanstack/vue-query'
import { computed, ref } from 'vue'
import { useBaseFetch } from '~/composables/fetch.js'
const client = injectModrinthClient()
const { handleError } = injectNotificationManager()
type UserGroup = {
user: User
affiliates: AffiliateLink[]
affiliates: Labrinth.Affiliate.Internal.AffiliateCode[]
}
const createModal = useTemplateRef<typeof AffiliateLinkCreateModal>('createModal')
@@ -116,8 +117,7 @@ const {
refetch,
} = useQuery({
queryKey: ['affiliate'],
queryFn: () =>
useBaseFetch('affiliate', { method: 'GET', internal: true }) as Promise<AffiliateLink[]>,
queryFn: () => client.labrinth.affiliate_internal.getAll(),
})
const filterQuery = ref('')
@@ -130,7 +130,9 @@ const userIds = computed(() => {
const ids = new Set<string>()
affiliateCodes.value.forEach((code) => {
ids.add(code.affiliate)
ids.add(code.created_by)
if (code.created_by) {
ids.add(code.created_by)
}
})
return Array.from(ids)
})
@@ -139,7 +141,7 @@ const { data: users } = useQuery({
queryKey: computed(() => ['users-bulk', userIds.value]),
queryFn: () => {
if (userIds.value.length === 0) return Promise.resolve([])
return useBaseFetch(`users?ids=${JSON.stringify(userIds.value)}`) as Promise<User[]>
return client.labrinth.users_v2.getMultiple(userIds.value)
},
})
@@ -189,7 +191,8 @@ const filteredGroupedAffiliates = computed(() => {
)
})
function getCreatedByUsername(createdBy: string): string {
function getCreatedByUsername(createdBy: string | null): string {
if (!createdBy) return 'Unknown'
const user = userMap.value.get(createdBy)
return user?.username || 'Unknown'
}
@@ -207,7 +210,7 @@ async function createAffiliateCode(data: { sourceName: string; username?: string
if (!user) {
try {
user = (await useBaseFetch(`user/${data.username}`)) as User
user = await client.labrinth.users_v2.get(data.username)
if (users.value) {
users.value.push(user)
@@ -218,19 +221,15 @@ async function createAffiliateCode(data: { sourceName: string; username?: string
}
}
await useBaseFetch('affiliate', {
method: 'PUT',
body: {
affiliate: user.id,
source_name: data.sourceName,
},
internal: true,
await client.labrinth.affiliate_internal.create({
affiliate: user.id,
source_name: data.sourceName,
})
await refetch()
createModal.value?.close()
} catch (err) {
handleError(err)
handleError(err as Error)
} finally {
creatingLink.value = false
}
@@ -239,7 +238,7 @@ async function createAffiliateCode(data: { sourceName: string; username?: string
const revokingAffiliateUsername = ref<string | null>(null)
const revokingAffiliateId = ref<string | null>(null)
function revokeAffiliateCode(affiliate: AffiliateLink) {
function revokeAffiliateCode(affiliate: Labrinth.Affiliate.Internal.AffiliateCode) {
const user = userMap.value.get(affiliate.affiliate)
revokingAffiliateUsername.value = user?.username || 'Unknown'
revokingAffiliateId.value = affiliate.id
@@ -252,10 +251,7 @@ async function confirmRevokeAffiliateCode() {
}
try {
await useBaseFetch(`affiliate/${revokingAffiliateId.value}`, {
method: 'DELETE',
internal: true,
})
await client.labrinth.affiliate_internal.delete(revokingAffiliateId.value)
await refetch()
revokeModal.value?.hide()

View File

@@ -328,6 +328,7 @@ import {
CopyCode,
defineMessages,
DropdownSelect,
injectModrinthClient,
injectNotificationManager,
NewModal,
StyledInput,
@@ -343,9 +344,9 @@ import { useQuery } from '@tanstack/vue-query'
import dayjs from 'dayjs'
import ModrinthServersIcon from '~/components/ui/servers/ModrinthServersIcon.vue'
import { useBaseFetch } from '~/composables/fetch.js'
const { addNotification } = injectNotificationManager()
const client = injectModrinthClient()
const formatPrice = useFormatPrice()
const formatDateTime = useFormatDateTime({
timeStyle: 'short',
@@ -374,7 +375,7 @@ const messages = defineMessages({
const { data: user, error: userError } = useQuery({
queryKey: ['user', route.params.id],
queryFn: () => useBaseFetch(`user/${route.params.id}`),
queryFn: () => client.labrinth.users_v2.get(route.params.id),
})
watch(userError, (error) => {
@@ -389,20 +390,14 @@ watch(userError, (error) => {
const { data: subscriptions } = useQuery({
queryKey: computed(() => ['billing', 'subscriptions', user.value?.id]),
queryFn: () =>
useBaseFetch(`billing/subscriptions?user_id=${user.value.id}`, {
internal: true,
}),
queryFn: () => client.labrinth.billing_internal.getSubscriptions(user.value.id),
enabled: computed(() => !!user.value?.id),
placeholderData: [],
})
const { data: charges, refetch: refreshCharges } = useQuery({
queryKey: computed(() => ['billing', 'payments', user.value?.id]),
queryFn: () =>
useBaseFetch(`billing/payments?user_id=${user.value.id}`, {
internal: true,
}),
queryFn: () => client.labrinth.billing_internal.getPayments(user.value.id),
enabled: computed(() => !!user.value?.id),
placeholderData: [],
})
@@ -463,15 +458,11 @@ async function applyCredit() {
crediting.value = true
try {
const daysParsed = Math.max(1, Math.floor(Number(creditDays.value) || 1))
await useBaseFetch('billing/credit', {
method: 'POST',
body: JSON.stringify({
subscription_ids: [selectedSubscription.value.id],
days: daysParsed,
send_email: creditSendEmail.value,
message: DEFAULT_CREDIT_EMAIL_MESSAGE,
}),
internal: true,
await client.labrinth.billing_internal.credit({
subscription_ids: [selectedSubscription.value.id],
days: daysParsed,
send_email: creditSendEmail.value,
message: DEFAULT_CREDIT_EMAIL_MESSAGE,
})
addNotification({
title: 'Credit applied',
@@ -501,11 +492,7 @@ async function refundCharge() {
? { type: 'none', unprovision: unprovision.value }
: { type: 'full', unprovision: unprovision.value }
await useBaseFetch(`billing/charge/${selectedCharge.value.id}/refund`, {
method: 'POST',
body: JSON.stringify(payload),
internal: true,
})
await client.labrinth.billing_internal.refundCharge(selectedCharge.value.id, payload)
await refreshCharges()
refundModal.value.hide()
} catch (err) {
@@ -521,12 +508,8 @@ async function refundCharge() {
async function modifyCharge() {
modifying.value = true
try {
await useBaseFetch(`billing/subscription/${selectedSubscription.value.id}`, {
method: 'PATCH',
body: JSON.stringify({
cancelled: cancel.value,
}),
internal: true,
await client.labrinth.billing_internal.editSubscription(selectedSubscription.value.id, {
cancelled: cancel.value,
})
addNotification({
title: 'Modifications made',

View File

@@ -86,6 +86,7 @@ import {
Button,
commonMessages,
defineMessages,
injectModrinthClient,
injectNotificationManager,
IntlFormatted,
normalizeChildren,
@@ -96,8 +97,8 @@ import { computed } from 'vue'
import { useAuth } from '@/composables/auth.js'
import { useScopes } from '@/composables/auth/scopes.ts'
import { useBaseFetch } from '@/composables/fetch.js'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
@@ -139,20 +140,16 @@ const scope = router.query?.scope || false
const state = router.query?.state || false
const getFlowIdAuthorization = async () => {
const query = {
const params = {
client_id: clientId,
redirect_uri: redirectUri,
scope,
}
if (state) {
query.state = state
params.state = state
}
const authorization = await useBaseFetch('oauth/authorize', {
method: 'GET',
internal: true,
query,
}) // This will contain the flow_id and oauth_client_id for accepting the oauth on behalf of the user
const authorization = await client.labrinth.oauth_internal.authorize(params)
if (typeof authorization === 'string') {
await navigateTo(authorization, {
@@ -175,21 +172,13 @@ const {
const { data: app } = useQuery({
queryKey: computed(() => ['oauth/app', clientId]),
queryFn: () =>
useBaseFetch('oauth/app/' + clientId, {
method: 'GET',
internal: true,
}),
queryFn: () => client.labrinth.oauth_internal.getApp(clientId),
enabled: computed(() => !!clientId),
})
const { data: createdBy } = useQuery({
queryKey: computed(() => ['user', app.value?.created_by]),
queryFn: () =>
useBaseFetch('user/' + app.value.created_by, {
method: 'GET',
apiVersion: 3,
}),
queryFn: () => client.labrinth.users_v2.get(app.value.created_by),
enabled: computed(() => !!app.value?.created_by),
})
@@ -199,12 +188,8 @@ const scopeDefinitions = computed(() =>
const onAuthorize = async () => {
try {
const res = await useBaseFetch('oauth/accept', {
method: 'POST',
internal: true,
body: {
flow: authorizationData.value.flow_id,
},
const res = await client.labrinth.oauth_internal.accept({
flow: authorizationData.value.flow_id,
})
if (typeof res === 'string') {
@@ -215,7 +200,7 @@ const onAuthorize = async () => {
}
throw new Error(formatMessage(messages.noRedirectUrlError))
} catch {
} catch (err) {
addNotification({
title: formatMessage(commonMessages.errorNotificationTitle),
text: err.data ? err.data.description : err,
@@ -226,11 +211,8 @@ const onAuthorize = async () => {
const onReject = async () => {
try {
const res = await useBaseFetch('oauth/reject', {
method: 'POST',
body: {
flow: authorizationData.value.flow_id,
},
const res = await client.labrinth.oauth_internal.reject({
flow: authorizationData.value.flow_id,
})
if (typeof res === 'string') {
@@ -241,7 +223,7 @@ const onReject = async () => {
}
throw new Error(formatMessage(messages.noRedirectUrlError))
} catch {
} catch (err) {
addNotification({
title: formatMessage(commonMessages.errorNotificationTitle),
text: err.data ? err.data.description : err,

View File

@@ -69,6 +69,7 @@ import { KeyIcon, MailIcon, SendIcon } from '@modrinth/assets'
import {
commonMessages,
defineMessages,
injectModrinthClient,
injectNotificationManager,
StyledInput,
useVIntl,
@@ -77,6 +78,7 @@ import { useQuery } from '@tanstack/vue-query'
import HCaptcha from '@/components/ui/HCaptcha.vue'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
@@ -167,10 +169,10 @@ const { data: globals } = useQuery({
queryKey: ['auth-globals'],
queryFn: async () => {
try {
return await useBaseFetch('globals', { internal: true })
return await client.labrinth.globals_internal.get()
} catch (err) {
console.error('Error fetching globals:', err)
return { captcha_enabled: true }
return { captcha_enabled: true, tax_compliance_thresholds: {} }
}
},
})
@@ -181,12 +183,9 @@ const token = ref('')
async function recovery() {
startLoading()
try {
await useBaseFetch('auth/password/reset', {
method: 'POST',
body: {
username: email.value,
challenge: token.value,
},
await client.labrinth.auth_v2.resetPasswordBegin({
username: email.value,
challenge: token.value,
})
addNotification({
@@ -211,12 +210,9 @@ const confirmNewPassword = ref('')
async function changePassword() {
startLoading()
try {
await useBaseFetch('auth/password', {
method: 'PATCH',
body: {
new_password: newPassword.value,
flow: route.query.flow,
},
await client.labrinth.auth_v2.changePassword({
new_password: newPassword.value,
flow: route.query.flow,
})
addNotification({

View File

@@ -139,6 +139,7 @@ import {
import {
commonMessages,
defineMessages,
injectModrinthClient,
injectNotificationManager,
IntlFormatted,
StyledInput,
@@ -149,6 +150,7 @@ import { useQuery, useQueryClient } from '@tanstack/vue-query'
import HCaptcha from '@/components/ui/HCaptcha.vue'
import { getAuthUrl, getLauncherRedirectUrl } from '@/composables/auth.js'
const client = injectModrinthClient()
const queryClient = useQueryClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
@@ -211,10 +213,10 @@ const { data: globals } = useQuery({
queryKey: ['auth-globals'],
queryFn: async () => {
try {
return await useBaseFetch('globals', { internal: true })
return await client.labrinth.globals_internal.get()
} catch (err) {
console.error('Error fetching globals:', err)
return { captcha_enabled: true }
return { captcha_enabled: true, tax_compliance_thresholds: {} }
}
},
})
@@ -228,13 +230,10 @@ const flow = ref(route.query.flow)
async function beginPasswordSignIn() {
startLoading()
try {
const res = await useBaseFetch('auth/login', {
method: 'POST',
body: {
username: email.value,
password: password.value,
challenge: token.value,
},
const res = await client.labrinth.auth_v2.login({
username: email.value,
password: password.value,
challenge: token.value,
})
if (res.flow) {
@@ -257,12 +256,9 @@ const twoFactorCode = ref(null)
async function begin2FASignIn() {
startLoading()
try {
const res = await useBaseFetch('auth/login/2fa', {
method: 'POST',
body: {
flow: flow.value,
code: twoFactorCode.value ? twoFactorCode.value.toString() : twoFactorCode.value,
},
const res = await client.labrinth.auth_v2.login2FA({
flow: flow.value,
code: twoFactorCode.value ? twoFactorCode.value.toString() : twoFactorCode.value,
})
await finishSignIn(res.session)

View File

@@ -141,6 +141,7 @@ import {
Checkbox,
commonMessages,
defineMessages,
injectModrinthClient,
injectNotificationManager,
IntlFormatted,
StyledInput,
@@ -151,6 +152,7 @@ import { useQuery } from '@tanstack/vue-query'
import HCaptcha from '@/components/ui/HCaptcha.vue'
import { getAuthUrl } from '@/composables/auth.js'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
@@ -205,10 +207,10 @@ const { data: globals } = useQuery({
queryKey: ['auth-globals'],
queryFn: async () => {
try {
return await useBaseFetch('globals', { internal: true })
return await client.labrinth.globals_internal.get()
} catch (err) {
console.error('Error fetching globals:', err)
return { captcha_enabled: true }
return { captcha_enabled: true, tax_compliance_thresholds: {} }
}
},
})
@@ -235,15 +237,12 @@ async function createAccount() {
captcha.value?.reset()
}
const res = await useBaseFetch('auth/create', {
method: 'POST',
body: {
username: username.value,
password: password.value,
email: email.value,
challenge: token.value,
sign_up_newsletter: subscribe.value,
},
const res = await client.labrinth.auth_v2.createAccount({
username: username.value,
password: password.value,
email: email.value,
challenge: token.value,
sign_up_newsletter: subscribe.value,
})
await useAuth(res.session)

View File

@@ -418,7 +418,6 @@ import dayjs from 'dayjs'
import AdPlaceholder from '~/components/ui/AdPlaceholder.vue'
import NavTabs from '~/components/ui/NavTabs.vue'
import { asEncodedJsonArray, fetchSegmented } from '~/utils/fetch-helpers.ts'
const { handleError } = injectNotificationManager()
const api = injectModrinthClient()
@@ -589,7 +588,7 @@ const refreshCollection = async () => {
// Query for creator (only for regular collections)
const { data: fetchedCreator, isPending: creatorIsPending } = useQuery({
queryKey: computed(() => ['user', collection.value?.user]),
queryFn: () => useBaseFetch(`user/${collection.value?.user}`),
queryFn: () => api.labrinth.users_v2.get(collection.value.user),
enabled: computed(() => !isFollowingCollection.value && !!collection.value?.user),
})
@@ -606,7 +605,7 @@ const {
} = useQuery({
queryKey: computed(() => ['user', auth.value.user?.id, 'follows']),
queryFn: async () => {
const projects = await useBaseFetch(`user/${auth.value.user.id}/follows`)
const projects = await api.labrinth.users_v2.getFollowedProjects(auth.value.user.id)
for (const project of projects) {
project.categories = project.categories.concat(project.loaders)
}
@@ -624,10 +623,16 @@ const {
} = useQuery({
queryKey: computed(() => ['projects', collection.value?.projects]),
queryFn: async () => {
const projects = await fetchSegmented(
collection.value.projects,
(ids) => `projects?ids=${asEncodedJsonArray(ids)}`,
const projectIds = collection.value.projects
const segmentSize = 800
const segments = []
for (let i = 0; i < projectIds.length; i += segmentSize) {
segments.push(projectIds.slice(i, i + segmentSize))
}
const results = await Promise.all(
segments.map((ids) => api.labrinth.projects_v2.getMultiple(ids)),
)
const projects = results.flat()
for (const project of projects) {
project.categories = project.categories.concat(project.loaders)
}

View File

@@ -57,6 +57,7 @@
</div>
</template>
<script setup lang="ts">
import type { Labrinth } from '@modrinth/api-client'
import { PlusIcon, SearchIcon, XCircleIcon } from '@modrinth/assets'
import {
Admonition,
@@ -65,11 +66,11 @@ import {
ButtonStyled,
ConfirmModal,
defineMessages,
injectModrinthClient,
injectNotificationManager,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import type { AffiliateLink } from '@modrinth/utils'
import { useQuery } from '@tanstack/vue-query'
const createModal = useTemplateRef<typeof AffiliateLinkCreateModal>('createModal')
@@ -77,6 +78,7 @@ const revokeModal = useTemplateRef<typeof ConfirmModal>('revokeModal')
const auth = await useAuth()
const client = injectModrinthClient()
const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl()
@@ -87,41 +89,35 @@ const {
refetch,
} = useQuery({
queryKey: ['affiliate'],
queryFn: () =>
useBaseFetch('affiliate', { method: 'GET', internal: true }) as Promise<AffiliateLink[]>,
queryFn: () => client.labrinth.affiliate_internal.getAll(),
})
const filterQuery = ref('')
const creatingLink = ref(false)
const filteredAffiliates = computed(() =>
affiliateLinks
? affiliateLinks.value?.filter(
(link: AffiliateLink) =>
link.affiliate === auth.value?.user?.id &&
(filterQuery.value.trim()
? link.source_name.trim().toLowerCase().includes(filterQuery.value.trim().toLowerCase())
: true),
)
: [],
const filteredAffiliates = computed(
() =>
affiliateLinks.value?.filter(
(link: Labrinth.Affiliate.Internal.AffiliateCode) =>
link.affiliate === auth.value?.user?.id &&
(filterQuery.value.trim()
? link.source_name.trim().toLowerCase().includes(filterQuery.value.trim().toLowerCase())
: true),
) ?? [],
)
async function createAffiliateCode(data: { sourceName: string }) {
creatingLink.value = true
try {
await useBaseFetch('affiliate', {
method: 'PUT',
body: {
source_name: data.sourceName,
},
internal: true,
await client.labrinth.affiliate_internal.create({
source_name: data.sourceName,
})
await refetch()
createModal.value?.close()
} catch (err) {
handleError(err)
handleError(err as Error)
} finally {
creatingLink.value = false
}
@@ -130,7 +126,7 @@ async function createAffiliateCode(data: { sourceName: string }) {
const revokingTitle = ref<string | null>(null)
const revokingId = ref<string | null>(null)
function revokeAffiliateLink(affiliate: AffiliateLink) {
function revokeAffiliateLink(affiliate: Labrinth.Affiliate.Internal.AffiliateCode) {
revokingTitle.value = affiliate.source_name
revokingId.value = affiliate.id
revokeModal.value?.show()
@@ -142,10 +138,7 @@ async function confirmRevokeAffiliateLink() {
}
try {
await useBaseFetch(`affiliate/${revokingId.value}`, {
method: 'DELETE',
internal: true,
})
await client.labrinth.affiliate_internal.delete(revokingId.value)
await refetch()
revokeModal.value?.hide()

View File

@@ -5,6 +5,7 @@
</template>
<script setup>
import { injectModrinthClient } from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import ChartDisplay from '~/components/ui/charts/ChartDisplay.vue'
@@ -18,11 +19,12 @@ useHead({
})
const auth = await useAuth()
const client = injectModrinthClient()
const id = auth.value?.user?.id
const { data: projects } = useQuery({
queryKey: computed(() => ['user', id, 'projects']),
queryFn: () => useBaseFetch(`user/${id}/projects`),
queryFn: () => client.labrinth.users_v2.getProjects(id),
enabled: computed(() => !!id),
})
</script>

View File

@@ -155,6 +155,7 @@ import {
commonMessages,
defineMessages,
DropdownSelect,
injectModrinthClient,
StyledInput,
useCompactNumber,
useVIntl,
@@ -162,7 +163,6 @@ import {
import { useQuery } from '@tanstack/vue-query'
import CollectionCreateModal from '~/components/ui/create/CollectionCreateModal.vue'
import { useBaseFetch } from '~/composables/fetch.js'
const { formatMessage } = useVIntl()
const { formatCompactNumber, formatCompactNumberPlural } = useCompactNumber()
@@ -216,6 +216,7 @@ useHead({
const auth = await useAuth()
const user = await useUser()
const client = injectModrinthClient()
if (import.meta.client) {
await initUserFollows()
@@ -225,7 +226,7 @@ const filterQuery = ref('')
const { data: collections } = useQuery({
queryKey: ['user', auth.value.user.id, 'collections'],
queryFn: () => useBaseFetch(`user/${auth.value.user.id}/collections`, { apiVersion: 3 }),
queryFn: () => client.labrinth.users_v2.getCollections(auth.value.user.id),
})
const route = useNativeRoute()

View File

@@ -97,7 +97,7 @@
</template>
<script setup>
import { ChevronRightIcon, HistoryIcon } from '@modrinth/assets'
import { Avatar } from '@modrinth/ui'
import { Avatar, injectModrinthClient } from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import NotificationItem from '~/components/ui/NotificationItem.vue'
@@ -108,10 +108,11 @@ useHead({
})
const auth = await useAuth()
const client = injectModrinthClient()
const { data: projects } = useQuery({
queryKey: computed(() => ['user', auth.value?.user?.id, 'projects']),
queryFn: async () => await useBaseFetch(`user/${auth.value?.user?.id}/projects`),
queryFn: () => client.labrinth.users_v2.getProjects(auth.value?.user?.id),
placeholderData: [],
})
@@ -125,12 +126,14 @@ const followersProjectCount = computed(
const { data, refetch } = useQuery({
queryKey: computed(() => ['user', auth.value?.user?.id, 'notifications']),
queryFn: async () => {
const notifications = await useBaseFetch(`user/${auth.value?.user?.id}/notifications`)
const notifications = await client.labrinth.notifications_v2.getUserNotifications(
auth.value?.user?.id,
)
const filteredNotifications = notifications.filter((notif) => !notif.read)
const slice = filteredNotifications.slice(0, 30)
return fetchExtraNotificationData(slice).then((notifications) => {
return fetchExtraNotificationData(client, slice).then((notifications) => {
notifications = groupNotifications(notifications).slice(0, 3)
return { notifications, extraNotifs: filteredNotifications.length - slice.length }
})

View File

@@ -57,7 +57,7 @@
</template>
<script setup>
import { CheckCheckIcon, HistoryIcon } from '@modrinth/assets'
import { Button, Chips, Pagination } from '@modrinth/ui'
import { Button, Chips, injectModrinthClient, Pagination } from '@modrinth/ui'
import { formatProjectType } from '@modrinth/utils'
import { useQuery } from '@tanstack/vue-query'
@@ -73,6 +73,7 @@ useHead({
title: 'Notifications - Modrinth',
})
const client = injectModrinthClient()
const auth = await useAuth()
const route = useNativeRoute()
const router = useNativeRouter()
@@ -94,7 +95,9 @@ const { data, isPending, error, refetch } = useQuery({
queryFn: async () => {
const pageNum = page.value - 1
const showRead = history.value
const notifications = await useBaseFetch(`user/${auth.value?.user?.id}/notifications`)
const notifications = await client.labrinth.notifications_v2.getUserNotifications(
auth.value?.user?.id,
)
const typesInFeed = [
...new Set(notifications.filter((n) => showRead || !n.read).map((n) => n.type)),
@@ -108,6 +111,7 @@ const { data, isPending, error, refetch } = useQuery({
const pages = Math.max(1, Math.ceil(filtered.length / perPage.value))
return fetchExtraNotificationData(
client,
filtered.slice(pageNum * perPage.value, pageNum * perPage.value + perPage.value),
).then((notifs) => ({
notifications: notifs,
@@ -121,7 +125,7 @@ const { data, isPending, error, refetch } = useQuery({
})
const notifications = computed(() =>
data.value ? groupNotifications(data.value.notifications, history.value) : [],
data.value ? groupNotifications(data.value.notifications) : [],
)
const notifTypes = computed(() => data.value?.notifTypes || [])
@@ -139,7 +143,7 @@ async function readAll() {
...(n.grouped_notifs ? n.grouped_notifs.map((g) => g.id) : []),
])
await markAsRead(ids)
await markAsRead(client, ids)
await refetch()
}

View File

@@ -50,7 +50,7 @@
<script setup>
import { PlusIcon, UsersIcon } from '@modrinth/assets'
import { Avatar } from '@modrinth/ui'
import { Avatar, injectModrinthClient } from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import OrganizationCreateModal from '~/components/ui/create/OrganizationCreateModal.vue'
@@ -59,14 +59,12 @@ import { useAuth } from '~/composables/auth.js'
const createOrgModal = ref(null)
const auth = await useAuth()
const client = injectModrinthClient()
const uid = computed(() => auth.value.user?.id || null)
const { data: orgs, error } = useQuery({
queryKey: computed(() => ['user', uid.value, 'organizations']),
queryFn: () =>
useBaseFetch('user/' + uid.value + '/organizations', {
apiVersion: 3,
}),
queryFn: () => client.labrinth.users_v2.getOrganizations(uid.value),
enabled: computed(() => !!uid.value),
})

View File

@@ -188,7 +188,7 @@
<div v-if="sortedPayouts.length > 0" class="flex flex-col gap-3 md:gap-4">
<RevenueTransaction
v-for="transaction in sortedPayouts.slice(0, 3)"
:key="transaction.id || transaction.created"
:key="('id' in transaction && transaction.id) || transaction.created"
:transaction="transaction"
@cancelled="refreshPayouts"
/>
@@ -260,13 +260,18 @@
<script setup lang="ts">
import { ArrowUpRightIcon, InProgressIcon, UnknownIcon } from '@modrinth/assets'
import { defineMessages, useFormatDateTime, useFormatMoney, useVIntl } from '@modrinth/ui'
import {
defineMessages,
injectModrinthClient,
useFormatDateTime,
useFormatMoney,
useVIntl,
} from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import dayjs from 'dayjs'
import { Tooltip } from 'floating-vue'
import { useUserCountry } from '@/composables/country.ts'
import type { PayoutMethod } from '@/providers/creator-withdraw.ts'
import CreatorWithdrawModal from '~/components/ui/dashboard/CreatorWithdrawModal.vue'
import RevenueTransaction from '~/components/ui/dashboard/RevenueTransaction.vue'
@@ -276,20 +281,7 @@ const formatDate = useFormatDateTime({ dateStyle: 'medium' })
await useAuth()
// TODO: Deduplicate these types & interfaces in @modrinth/api-client PR.
type FormCompletionStatus = 'unknown' | 'unrequested' | 'unsigned' | 'tin-mismatch' | 'complete'
type UserBalanceResponse = {
available: number
withdrawn_lifetime: number
withdrawn_ytd: number
pending: number
// ISO 8601 date string -> amount
dates: Record<string, number>
// backend returns null when not applicable
requested_form_type: string | null
form_completion_status: FormCompletionStatus | null
}
const client = injectModrinthClient()
type RevenueBarSegment = {
key: string
@@ -359,26 +351,12 @@ const messages = defineMessages({
const { data: userBalance, refetch: refreshUserBalance } = useQuery({
queryKey: ['payout', 'balance'],
queryFn: async () => {
const response = (await useBaseFetch(`payout/balance`, {
apiVersion: 3,
})) as UserBalanceResponse
return {
...response,
available: Number(response.available),
withdrawn_lifetime: Number(response.withdrawn_lifetime),
withdrawn_ytd: Number(response.withdrawn_ytd),
pending: Number(response.pending),
}
},
queryFn: () => client.labrinth.payout_v3.getBalance(),
})
const { data: payouts, refetch: refreshPayouts } = useQuery({
queryKey: ['payout', 'history'],
queryFn: () =>
useBaseFetch(`payout/history`, {
apiVersion: 3,
}),
queryFn: () => client.labrinth.payout_v3.getHistory(),
})
const userCountry = useUserCountry()
@@ -389,10 +367,7 @@ const { data: preloadedPaymentMethods } = useQuery({
try {
return {
country: defaultCountry,
methods: (await useBaseFetch('payout/methods', {
apiVersion: 3,
query: { country: defaultCountry },
})) as PayoutMethod[],
methods: await client.labrinth.payout_v3.getMethods(defaultCountry),
}
} catch {
return null

View File

@@ -92,6 +92,7 @@ import {
Combobox,
defineMessages,
EmptyState,
injectModrinthClient,
useFormatDateTime,
useFormatMoney,
useVIntl,
@@ -111,6 +112,7 @@ const formatMonth = useFormatDateTime({
month: 'long',
})
const client = injectModrinthClient()
const generatedState = useGeneratedState()
useHead({
@@ -119,10 +121,7 @@ useHead({
const { data: transactions, refetch } = useQuery({
queryKey: ['payout', 'history'],
queryFn: () =>
useBaseFetch(`payout/history`, {
apiVersion: 3,
}),
queryFn: () => client.labrinth.payout_v3.getHistory(),
})
const allTransactions = computed(() => {

View File

@@ -10,8 +10,7 @@
ref="purchaseModal"
:publishable-key="config.public.stripePublishableKey"
:initiate-payment="
async (body) =>
await useBaseFetch('billing/payment', { internal: true, method: 'POST', body })
async (body) => await client.labrinth.billing_internal.initiatePayment(body)
"
:available-products="pyroProducts"
:on-error="handleError"
@@ -641,6 +640,7 @@ import {
ButtonStyled,
commonMessages,
defineMessages,
injectModrinthClient,
injectNotificationManager,
IntlFormatted,
ModrinthServersPurchaseModal,
@@ -651,16 +651,15 @@ import { monthsInInterval } from '@modrinth/ui/src/utils/billing.ts'
import { useQuery } from '@tanstack/vue-query'
import { computed } from 'vue'
import { useBaseFetch } from '@/composables/fetch.js'
import OptionGroup from '~/components/ui/OptionGroup.vue'
import LoaderIcon from '~/components/ui/servers/icons/LoaderIcon.vue'
import MedalPlanPromotion from '~/components/ui/servers/marketing/MedalPlanPromotion.vue'
import ServerPlanSelector from '~/components/ui/servers/marketing/ServerPlanSelector.vue'
import { useServersFetch } from '~/composables/servers/servers-fetch.ts'
import { products } from '~/generated/state.json'
const route = useRoute()
const router = useRouter()
const client = injectModrinthClient()
const { setAffiliateCode, getAffiliateCode } = useAffiliates()
@@ -1017,7 +1016,7 @@ const { data: hasServers } = useQuery({
queryFn: async () => {
try {
if (!auth.value.user) return false
const response = await useServersFetch('servers')
const response = await client.archon.servers_v0.list()
return response.servers && response.servers.length > 0
} catch {
return false
@@ -1027,13 +1026,7 @@ const { data: hasServers } = useQuery({
})
function fetchStock(region, request) {
return useServersFetch(`stock?region=${region.shortcode}`, {
method: 'POST',
body: {
...request,
},
bypassAuth: true,
}).then((res) => res.available)
return client.archon.servers_v0.checkStock(region.shortcode, request).then((res) => res.available)
}
async function fetchCapacityStatuses(customProduct = null) {
@@ -1049,15 +1042,11 @@ async function fetchCapacityStatuses(customProduct = null) {
const capacityChecks = []
for (const product of productsToCheck) {
capacityChecks.push(
useServersFetch('stock', {
method: 'POST',
body: {
cpu: product.metadata.cpu,
memory_mb: product.metadata.ram,
swap_mb: product.metadata.swap,
storage_mb: product.metadata.storage,
},
bypassAuth: true,
client.archon.servers_v0.checkStockGlobal({
cpu: product.metadata.cpu,
memory_mb: product.metadata.ram,
swap_mb: product.metadata.swap,
storage_mb: product.metadata.storage,
}),
)
}
@@ -1129,8 +1118,8 @@ async function fetchPaymentData() {
if (!auth.value.user) return
try {
const [customerData, paymentMethodsData] = await Promise.all([
useBaseFetch('billing/customer', { internal: true }),
useBaseFetch('billing/payment_methods', { internal: true }),
client.labrinth.billing_internal.getCustomer(),
client.labrinth.billing_internal.getPaymentMethods(),
])
customer.value = customerData
paymentMethods.value = paymentMethodsData
@@ -1248,11 +1237,7 @@ const regions = ref([])
const regionPings = ref([])
function pingRegions() {
useServersFetch('regions', {
method: 'GET',
version: 1,
bypassAuth: true,
}).then((res) => {
client.archon.servers_v1.getRegions().then((res) => {
regions.value = res
regions.value.forEach((region) => {
runPingTest(region)

View File

@@ -118,7 +118,7 @@ import {
StyledInput,
Toggle,
} from '@modrinth/ui'
import { useMutation, useQueryClient } from '@tanstack/vue-query'
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
import Fuse from 'fuse.js'
import { computed, ref, watch } from 'vue'

View File

@@ -146,7 +146,7 @@
</thead>
<tbody>
<tr v-for="item in platformRevenueData" :key="item.time">
<td>{{ formatDate(dayjs.unix(item.time)) }}</td>
<td>{{ formatDate(dayjs.unix(item.time).toDate()) }}</td>
<td>{{ formatMoney(Number(item.revenue) + Number(item.creator_revenue)) }}</td>
<td>{{ formatMoney(Number(item.creator_revenue)) }}</td>
<td>{{ formatMoney(Number(item.revenue)) }}</td>
@@ -162,11 +162,12 @@
</template>
<script lang="ts" setup>
import { StyledInput, useFormatDateTime, useFormatMoney } from '@modrinth/ui'
import { injectModrinthClient, StyledInput, useFormatDateTime, useFormatMoney } from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import dayjs from 'dayjs'
import { computed, ref } from 'vue'
const client = injectModrinthClient()
const formatMoney = useFormatMoney()
const formatDate = useFormatDateTime({
month: 'long',
@@ -191,10 +192,7 @@ const withdrawalDate = computed(() => endOfMonthDate.value.add(60, 'days'))
const { data: transparencyInformation } = useQuery({
queryKey: ['payout', 'platform_revenue'],
queryFn: () =>
useBaseFetch('payout/platform_revenue', {
apiVersion: 3,
}),
queryFn: () => client.labrinth.payouts_v3.getPlatformRevenue(),
})
const platformRevenue = (transparencyInformation.value as any)?.all_time

View File

@@ -1,10 +1,12 @@
<script setup lang="ts">
import { injectModrinthClient } from '@modrinth/ui'
import type { Report } from '@modrinth/utils'
import { useQuery } from '@tanstack/vue-query'
import ModerationReportCard from '~/components/ui/moderation/ModerationReportCard.vue'
import { enrichReportBatch } from '~/helpers/moderation.ts'
const client = injectModrinthClient()
const { params } = useRoute()
const reportId = params.id as string
@@ -12,7 +14,7 @@ const { data: report } = useQuery({
queryKey: computed(() => ['report', reportId]),
queryFn: async () => {
try {
const report = (await useBaseFetch(`report/${reportId}`, { apiVersion: 3 })) as Report
const report = (await client.labrinth.reports_v3.get(reportId)) as Report
const enrichedReport = (await enrichReportBatch([report]))[0]
return enrichedReport
} catch (error) {

View File

@@ -327,6 +327,7 @@ import {
commonMessages,
CopyCode,
DropdownSelect,
injectModrinthClient,
injectNotificationManager,
NewModal,
ProjectStatusBadge,
@@ -341,6 +342,7 @@ import OrganizationProjectTransferModal from '~/components/ui/OrganizationProjec
import { getProjectTypeForUrl } from '~/helpers/projects.js'
import { injectOrganizationContext } from '~/providers/organization-context.ts'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
@@ -350,7 +352,7 @@ const auth = await useAuth()
const { data: userProjects, refetch: refreshUserProjects } = useQuery({
queryKey: computed(() => ['user', auth.value?.user?.id, 'projects']),
queryFn: () => useBaseFetch(`user/${auth.value.user.id}/projects`),
queryFn: () => client.labrinth.users_v2.getProjects(auth.value.user.id),
enabled: computed(() => !!auth.value?.user?.id),
placeholderData: [],
})
@@ -366,11 +368,7 @@ watch(
const projects = userProjects.value.filter((project) => project.organization === null)
const teamIds = projects.map((project) => project?.team).filter((x) => x)
// Shape of teams is member[][]
const teams = await useBaseFetch(`teams?ids=${JSON.stringify(teamIds)}`, {
apiVersion: 3,
})
// for each team id, figure out if the user is a member, and is_owner. Then filter the projects to only include those that are owned by the user
const teams = await client.labrinth.teams_v3.getMultiple(teamIds)
const ownedTeamIds = teamIds.filter((_tid, i) => {
const team = teams?.[i]
if (!team) return false
@@ -379,19 +377,15 @@ watch(
})
const ownedProjects = projects.filter((project) => ownedTeamIds.includes(project.team))
usersOwnedProjects.value = ownedProjects
}, // watch options
},
{ immediate: true, deep: true },
)
const onProjectTransferSubmit = async (projects) => {
try {
for (const project of projects) {
await useBaseFetch(`organization/${organization.value.id}/projects`, {
method: 'POST',
body: JSON.stringify({
project_id: project.id,
}),
apiVersion: 3,
await client.labrinth.organizations_v3.addProject(organization.value.id, {
project_id: project.id,
})
}
@@ -488,17 +482,17 @@ const updateDescending = () => {
const onBulkEditLinks = async () => {
try {
const baseData = {
issues_url: editLinks.value.issues.clear ? null : editLinks.value.issues.val.trim(),
source_url: editLinks.value.source.clear ? null : editLinks.value.source.val.trim(),
wiki_url: editLinks.value.wiki.clear ? null : editLinks.value.wiki.val.trim(),
discord_url: editLinks.value.discord.clear ? null : editLinks.value.discord.val.trim(),
issues_url: editLinks.issues.clear ? null : editLinks.issues.val.trim(),
source_url: editLinks.source.clear ? null : editLinks.source.val.trim(),
wiki_url: editLinks.wiki.clear ? null : editLinks.wiki.val.trim(),
discord_url: editLinks.discord.clear ? null : editLinks.discord.val.trim(),
}
const filteredData = Object.fromEntries(Object.entries(baseData).filter(([, v]) => v !== ''))
await useBaseFetch(`projects?ids=${JSON.stringify(selectedProjects.value.map((x) => x.id))}`, {
method: 'PATCH',
body: JSON.stringify(filteredData),
})
await client.labrinth.projects_v2.bulkEdit(
selectedProjects.value.map((x) => x.id),
filteredData,
)
editLinksModal.value?.hide()
addNotification({
@@ -508,14 +502,14 @@ const onBulkEditLinks = async () => {
})
selectedProjects.value = []
editLinks.value.issues.val = ''
editLinks.value.source.val = ''
editLinks.value.wiki.val = ''
editLinks.value.discord.val = ''
editLinks.value.issues.clear = false
editLinks.value.source.clear = false
editLinks.value.wiki.clear = false
editLinks.value.discord.clear = false
editLinks.issues.val = ''
editLinks.source.val = ''
editLinks.wiki.val = ''
editLinks.discord.val = ''
editLinks.issues.clear = false
editLinks.source.clear = false
editLinks.wiki.clear = false
editLinks.discord.clear = false
} catch (e) {
addNotification({
title: 'An error occurred',

View File

@@ -253,6 +253,7 @@ import {
CopyCode,
defineMessages,
FileInput,
injectModrinthClient,
injectNotificationManager,
IntlFormatted,
normalizeChildren,
@@ -272,6 +273,7 @@ import {
useScopes,
} from '~/composables/auth/scopes.ts'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
const formatDate = useFormatDateTime()
@@ -494,10 +496,7 @@ const auth = await useAuth()
const { data: usersApps, refetch: refresh } = useQuery({
queryKey: computed(() => ['user', auth.value?.user?.id, 'oauth_apps']),
queryFn: () =>
useBaseFetch(`user/${auth.value.user.id}/oauth_apps`, {
apiVersion: 3,
}),
queryFn: () => client.labrinth.oauth_internal.getUserApps(auth.value.user.id),
enabled: computed(() => !!auth.value?.user?.id),
})
@@ -551,14 +550,7 @@ async function onImageSelection(files) {
const file = files[0]
const extFromType = file.type.split('/')[1]
await useBaseFetch('oauth/app/' + editingId.value + '/icon', {
method: 'PATCH',
internal: true,
body: file,
query: {
ext: extFromType,
},
})
await client.labrinth.oauth_internal.uploadAppIcon(editingId.value, file, extFromType).promise
await refresh()
@@ -579,15 +571,10 @@ async function createApp() {
startLoading()
loading.value = true
try {
const createdAppInfo = await useBaseFetch('oauth/app', {
method: 'POST',
internal: true,
body: {
name: name.value,
icon_url: icon.value,
max_scopes: Number(scopesVal.value), // JS is 52 bit for ints so we're good for now
redirect_uris: redirectUris.value,
},
const createdAppInfo = await client.labrinth.oauth_internal.createApp({
name: name.value,
max_scopes: Number(scopesVal.value),
redirect_uris: redirectUris.value,
})
createdApps.value.push(createdAppInfo)
@@ -637,7 +624,7 @@ async function editApp() {
const body = {
name: name.value,
max_scopes: Number(scopesVal.value), // JS is 52 bit for ints so we're good for now
max_scopes: Number(scopesVal.value),
redirect_uris: redirectUris.value,
}
@@ -653,11 +640,7 @@ async function editApp() {
body.icon_url = icon.value
}
await useBaseFetch('oauth/app/' + editingId.value, {
method: 'PATCH',
internal: true,
body,
})
await client.labrinth.oauth_internal.editApp(editingId.value, body)
await refresh()
setForm(null)
@@ -681,10 +664,7 @@ async function removeApp() {
if (!editingId.value) {
throw new Error('No editing id')
}
await useBaseFetch(`oauth/app/${editingId.value}`, {
internal: true,
method: 'DELETE',
})
await client.labrinth.oauth_internal.deleteApp(editingId.value)
await refresh()
editingId.value = null
} catch (err) {

View File

@@ -95,6 +95,7 @@ import {
Button,
commonSettingsMessages,
ConfirmModal,
injectModrinthClient,
injectNotificationManager,
useVIntl,
} from '@modrinth/ui'
@@ -102,6 +103,7 @@ import { useQuery } from '@tanstack/vue-query'
import { useScopes } from '~/composables/auth/scopes.ts'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
@@ -119,32 +121,19 @@ useHead({
const { data: usersApps, refetch: refresh } = useQuery({
queryKey: ['oauth', 'authorizations'],
queryFn: () =>
useBaseFetch(`oauth/authorizations`, {
internal: true,
}),
queryFn: () => client.labrinth.oauth_internal.getAuthorizations(),
})
const { data: appInformation } = useQuery({
queryKey: computed(() => ['oauth', 'apps', usersApps.value?.map((c) => c.app_id)]),
queryFn: () =>
useBaseFetch('oauth/apps', {
internal: true,
query: {
ids: JSON.stringify(usersApps.value.map((c) => c.app_id)),
},
}),
queryFn: () => client.labrinth.oauth_internal.getApps(usersApps.value.map((c) => c.app_id)),
enabled: computed(() => !!usersApps.value?.length),
})
const { data: appCreatorsInformation } = useQuery({
queryKey: computed(() => ['users', appInformation.value?.map((c) => c.created_by)]),
queryFn: () =>
useBaseFetch('users', {
query: {
ids: JSON.stringify(appInformation.value.map((c) => c.created_by)),
},
}),
client.labrinth.users_v2.getMultiple(appInformation.value.map((c) => c.created_by)),
enabled: computed(() => !!appInformation.value?.length),
})
@@ -165,13 +154,7 @@ const appInfoLookup = computed(() => {
async function revokeApp(id) {
try {
await useBaseFetch(`oauth/authorizations`, {
internal: true,
method: 'DELETE',
query: {
client_id: id,
},
})
await client.labrinth.oauth_internal.revokeAuthorization(id)
revokingId.value = null
await refresh()
} catch (err) {

View File

@@ -38,7 +38,13 @@
</div>
</template>
<script setup>
import { Badge, Breadcrumbs, useFormatDateTime, useFormatPrice } from '@modrinth/ui'
import {
Badge,
Breadcrumbs,
injectModrinthClient,
useFormatDateTime,
useFormatPrice,
} from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import { products } from '~/generated/state.json'
@@ -47,6 +53,8 @@ definePageMeta({
middleware: 'auth',
})
const client = injectModrinthClient()
const formatPrice = useFormatPrice()
const formatDate = useFormatDateTime({
year: 'numeric',
@@ -57,7 +65,7 @@ const formatDate = useFormatDateTime({
const { data: charges } = useQuery({
queryKey: ['billing', 'payments'],
queryFn: async () => {
const charges = await useBaseFetch('billing/payments', { internal: true })
const charges = await client.labrinth.billing_internal.getPayments()
return charges
.filter((charge) => charge.status !== 'open' && charge.status !== 'cancelled')
.map((charge) => {

View File

@@ -458,8 +458,7 @@
:country="country"
:publishable-key="config.public.stripePublishableKey"
:send-billing-request="
async (body) =>
await useBaseFetch('billing/payment', { internal: true, method: 'POST', body })
async (body) => await client.labrinth.billing_internal.initiatePayment(body)
"
:on-error="
(err) =>
@@ -613,6 +612,7 @@ import {
CopyCode,
defineMessages,
getPaymentMethodIcon,
injectModrinthClient,
injectNotificationManager,
OverflowMenu,
paymentMethodMessages,
@@ -626,13 +626,12 @@ import { calculateSavings, getCurrency } from '@modrinth/utils'
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, ref } from 'vue'
import { useBaseFetch } from '@/composables/fetch.js'
import ModrinthServersIcon from '~/components/ui/servers/ModrinthServersIcon.vue'
import ServersUpgradeModalWrapper from '~/components/ui/servers/ServersUpgradeModalWrapper.vue'
import { useServersFetch } from '~/composables/servers/servers-fetch.ts'
import { products } from '~/generated/state.json'
const { addNotification, handleError } = injectNotificationManager()
const client = injectModrinthClient()
definePageMeta({
middleware: 'auth',
})
@@ -742,27 +741,27 @@ const queryClient = useQueryClient()
const { data: paymentMethods } = useQuery({
queryKey: ['billing', 'payment_methods'],
queryFn: () => useBaseFetch('billing/payment_methods', { internal: true }),
queryFn: () => client.labrinth.billing_internal.getPaymentMethods(),
})
const { data: charges } = useQuery({
queryKey: ['billing', 'payments'],
queryFn: () => useBaseFetch('billing/payments', { internal: true }),
queryFn: () => client.labrinth.billing_internal.getPayments(),
})
const { data: customer } = useQuery({
queryKey: ['billing', 'customer'],
queryFn: () => useBaseFetch('billing/customer', { internal: true }),
queryFn: () => client.labrinth.billing_internal.getCustomer(),
})
const { data: subscriptions } = useQuery({
queryKey: ['billing', 'subscriptions'],
queryFn: () => useBaseFetch('billing/subscriptions', { internal: true }),
queryFn: () => client.labrinth.billing_internal.getSubscriptions(),
})
const { data: productsData } = useQuery({
queryKey: ['billing', 'products'],
queryFn: () => useBaseFetch('billing/products', { internal: true }),
queryFn: () => client.labrinth.billing_internal.getProducts(),
})
const { data: serversData } = useQuery({
queryKey: ['servers'],
queryFn: () => useServersFetch('servers'),
queryFn: () => client.archon.servers_v0.list(),
})
const midasProduct = ref(products.find((x) => x.metadata?.type === 'midas'))
@@ -826,10 +825,7 @@ function addPaymentMethod() {
}
async function createSetupIntent() {
return await useBaseFetch('billing/payment_method', {
internal: true,
method: 'POST',
})
return await client.labrinth.billing_internal.addPaymentMethodFlow()
}
const removePaymentMethodIndex = ref()
@@ -844,12 +840,8 @@ async function switchMidasInterval(interval) {
changingInterval.value = true
startLoading()
try {
await useBaseFetch(`billing/subscription/${midasSubscription.value.id}`, {
internal: true,
method: 'PATCH',
body: {
interval,
},
await client.labrinth.billing_internal.editSubscription(midasSubscription.value.id, {
interval,
})
await refresh()
} catch (error) {
@@ -862,12 +854,8 @@ async function switchMidasInterval(interval) {
async function editPaymentMethod(index, primary) {
startLoading()
try {
await useBaseFetch(`billing/payment_method/${paymentMethods.value[index].id}`, {
internal: true,
method: 'PATCH',
data: {
primary,
},
await client.labrinth.billing_internal.editPaymentMethod(paymentMethods.value[index].id, {
primary,
})
await refresh()
} catch (err) {
@@ -883,10 +871,7 @@ async function editPaymentMethod(index, primary) {
async function removePaymentMethod(index) {
startLoading()
try {
await useBaseFetch(`billing/payment_method/${paymentMethods.value[index].id}`, {
internal: true,
method: 'DELETE',
})
await client.labrinth.billing_internal.removePaymentMethod(paymentMethods.value[index].id)
await refresh()
} catch (err) {
addNotification({
@@ -902,12 +887,8 @@ const cancelSubscriptionId = ref(null)
async function cancelSubscription(id, cancelled) {
startLoading()
try {
await useBaseFetch(`billing/subscription/${id}`, {
internal: true,
method: 'PATCH',
body: {
cancelled,
},
await client.labrinth.billing_internal.editSubscription(id, {
cancelled,
})
await refresh()
} catch (err) {
@@ -975,12 +956,8 @@ const showPyroUpgradeModal = (subscription) => {
const resubscribePyro = async (subscriptionId, wasSuspended) => {
try {
await useBaseFetch(`billing/subscription/${subscriptionId}`, {
internal: true,
method: 'PATCH',
body: {
cancelled: false,
},
await client.labrinth.billing_internal.editSubscription(subscriptionId, {
cancelled: false,
})
await refresh()
if (wasSuspended) {

View File

@@ -196,6 +196,7 @@ import {
ConfirmModal,
CopyCode,
defineMessages,
injectModrinthClient,
injectNotificationManager,
IntlFormatted,
StyledInput,
@@ -203,7 +204,7 @@ import {
useRelativeTime,
useVIntl,
} from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import Modal from '~/components/ui/Modal.vue'
import {
@@ -215,6 +216,8 @@ import {
useScopes,
} from '~/composables/auth/scopes.ts'
const client = injectModrinthClient()
const queryClient = useQueryClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
@@ -327,9 +330,9 @@ const deletePatIndex = ref(null)
const loading = ref(false)
const { data: pats, refetch: refresh } = useQuery({
const { data: pats } = useQuery({
queryKey: ['pat'],
queryFn: () => useBaseFetch('pat'),
queryFn: () => client.labrinth.pats_v2.list(),
placeholderData: [],
})
const displayPats = computed(() => {
@@ -395,13 +398,10 @@ async function createPat() {
startLoading()
loading.value = true
try {
const res = await useBaseFetch('pat', {
method: 'POST',
body: {
name: name.value,
scopes: Number(scopesVal.value),
expires: data.$dayjs(expires.value).toISOString(),
},
const res = await client.labrinth.pats_v2.create({
name: name.value,
scopes: Number(scopesVal.value),
expires: data.$dayjs(expires.value).toISOString(),
})
pats.value.push(res)
patModal.value.hide()
@@ -420,15 +420,12 @@ async function editPat() {
startLoading()
loading.value = true
try {
await useBaseFetch(`pat/${editPatId.value}`, {
method: 'PATCH',
body: {
name: name.value,
scopes: Number(scopesVal.value),
expires: data.$dayjs(expires.value).toISOString(),
},
await client.labrinth.pats_v2.modify(editPatId.value, {
name: name.value,
scopes: Number(scopesVal.value),
expires: data.$dayjs(expires.value).toISOString(),
})
await refresh()
await queryClient.invalidateQueries({ queryKey: ['pat'] })
patModal.value.hide()
} catch (err) {
addNotification({
@@ -445,10 +442,8 @@ async function removePat(id) {
startLoading()
try {
pats.value = pats.value.filter((x) => x.id !== id)
await useBaseFetch(`pat/${id}`, {
method: 'DELETE',
})
await refresh()
await client.labrinth.pats_v2.delete(id)
await queryClient.invalidateQueries({ queryKey: ['pat'] })
} catch (err) {
addNotification({
title: formatMessage(commonMessages.errorNotificationTitle),

View File

@@ -47,17 +47,20 @@ import {
commonMessages,
commonSettingsMessages,
defineMessages,
injectModrinthClient,
injectNotificationManager,
useFormatDateTime,
useRelativeTime,
useVIntl,
} from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import { useQuery, useQueryClient } from '@tanstack/vue-query'
definePageMeta({
middleware: 'auth',
})
const client = injectModrinthClient()
const queryClient = useQueryClient()
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
const formatRelativeTime = useRelativeTime()
@@ -102,19 +105,17 @@ useHead({
title: () => `${formatMessage(commonSettingsMessages.sessions)} - Modrinth`,
})
const { data: sessions, refetch: refresh } = useQuery({
const { data: sessions } = useQuery({
queryKey: ['session', 'list'],
queryFn: () => useBaseFetch('session/list'),
queryFn: () => client.labrinth.sessions_v2.list(),
})
async function revokeSession(id) {
startLoading()
try {
sessions.value = sessions.value.filter((x) => x.id !== id)
await useBaseFetch(`session/${id}`, {
method: 'DELETE',
})
await refresh()
await client.labrinth.sessions_v2.delete(id)
await queryClient.invalidateQueries({ queryKey: ['session', 'list'] })
} catch (err) {
addNotification({
title: formatMessage(commonMessages.errorNotificationTitle),

View File

@@ -1,3 +1,4 @@
import type { Labrinth } from '@modrinth/api-client'
import {
BadgeDollarSignIcon,
GiftIcon,
@@ -43,29 +44,7 @@ export type PaymentProvider = 'tremendous' | 'muralpay' | 'paypal' | 'venmo'
**/
export type PaymentMethod = 'gift_card' | 'paypal' | 'venmo' | 'bank' | 'crypto'
export interface PayoutMethod {
id: string
type: string
name: string
category?: string
image_url: string | null
image_logo_url: string | null
interval: {
standard: {
min: number
max: number
}
fixed?: {
values: number[]
}
}
config?: {
fiat?: string | null
blockchain?: string[]
}
currency_code?: string | null
exchange_rate?: number | null
}
export type PayoutMethod = Labrinth.Payout.v3.PayoutMethod
export interface PaymentOption {
value: string

View File

@@ -21,6 +21,16 @@ export function fetchSegmented<T>(
).then((results) => results.flat())
}
export function fetchSegmentedWith<TId, TResult>(
data: TId[],
fetchFn: (ids: TId[]) => Promise<TResult[]>,
segmentSize = 800,
): Promise<TResult[]> {
return Promise.all(segmentData(data, segmentSize).map((ids) => fetchFn(ids))).then((results) =>
results.flat(),
)
}
export function asEncodedJsonArray<T>(data: T[]): string {
return encodeURIComponent(JSON.stringify(data))
}