Replace axios with fetch
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
@@ -2,43 +2,41 @@ import MockAdapter from 'axios-mock-adapter';
|
||||
import LinkHeader from 'http-link-header';
|
||||
import { vi } from 'vitest';
|
||||
|
||||
import type { AxiosInstance, AxiosResponse } from 'axios';
|
||||
|
||||
const api = await vi.importActual('../index') as Record<string, Function>;
|
||||
let mocks: Array<Function> = [];
|
||||
|
||||
export const __stub = (func: (mock: MockAdapter) => void) => mocks.push(func);
|
||||
export const __clear = (): Function[] => mocks = [];
|
||||
|
||||
const setupMock = (axios: AxiosInstance) => {
|
||||
const mock = new MockAdapter(axios, { onNoMatch: 'throwException' });
|
||||
mocks.map(func => func(mock));
|
||||
};
|
||||
// const setupMock = (axios: AxiosInstance) => {
|
||||
// const mock = new MockAdapter(axios, { onNoMatch: 'throwException' });
|
||||
// mocks.map(func => func(mock));
|
||||
// };
|
||||
|
||||
export const staticClient = api.staticClient;
|
||||
|
||||
export const getLinks = (response: AxiosResponse): LinkHeader => {
|
||||
return new LinkHeader(response.headers?.link);
|
||||
export const getLinks = (response: Response): LinkHeader => {
|
||||
return new LinkHeader(response.headers?.get('link') || undefined);
|
||||
};
|
||||
|
||||
export const getNextLink = (response: AxiosResponse) => {
|
||||
const nextLink = new LinkHeader(response.headers?.link);
|
||||
export const getNextLink = (response: Response) => {
|
||||
const nextLink = new LinkHeader(response.headers?.get('link') || undefined);
|
||||
return nextLink.refs.find(link => link.rel === 'next')?.uri;
|
||||
};
|
||||
|
||||
export const getPrevLink = (response: AxiosResponse) => {
|
||||
const prevLink = new LinkHeader(response.headers?.link);
|
||||
export const getPrevLink = (response: Response) => {
|
||||
const prevLink = new LinkHeader(response.headers?.get('link') || undefined);
|
||||
return prevLink.refs.find(link => link.rel === 'prev')?.uri;
|
||||
};
|
||||
|
||||
export const baseClient = (...params: any[]) => {
|
||||
const axios = api.baseClient(...params);
|
||||
setupMock(axios);
|
||||
// setupMock(axios);
|
||||
return axios;
|
||||
};
|
||||
|
||||
export default (...params: any[]) => {
|
||||
const axios = api.default(...params);
|
||||
setupMock(axios);
|
||||
// setupMock(axios);
|
||||
return axios;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ function useAccount(accountId?: string, opts: UseAccountOpts = {}) {
|
||||
|
||||
const { entity, isUnauthorized, ...result } = useEntity<Account>(
|
||||
[Entities.ACCOUNTS, accountId!],
|
||||
() => api.get(`/api/v1/accounts/${accountId}`),
|
||||
() => api(`/api/v1/accounts/${accountId}`),
|
||||
{ schema: accountSchema, enabled: !!accountId },
|
||||
);
|
||||
|
||||
|
||||
@@ -33,12 +33,12 @@ function useAccountList(listKey: string[], entityFn: EntityFn<void>, opts: useAc
|
||||
|
||||
function useBlocks() {
|
||||
const api = useApi();
|
||||
return useAccountList(['blocks'], () => api.get('/api/v1/blocks'));
|
||||
return useAccountList(['blocks'], () => api('/api/v1/blocks'));
|
||||
}
|
||||
|
||||
function useMutes() {
|
||||
const api = useApi();
|
||||
return useAccountList(['mutes'], () => api.get('/api/v1/mutes'));
|
||||
return useAccountList(['mutes'], () => api('/api/v1/mutes'));
|
||||
}
|
||||
|
||||
function useFollowing(accountId: string | undefined) {
|
||||
@@ -46,7 +46,7 @@ function useFollowing(accountId: string | undefined) {
|
||||
|
||||
return useAccountList(
|
||||
[accountId!, 'following'],
|
||||
() => api.get(`/api/v1/accounts/${accountId}/following`),
|
||||
() => api(`/api/v1/accounts/${accountId}/following`),
|
||||
{ enabled: !!accountId },
|
||||
);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ function useFollowers(accountId: string | undefined) {
|
||||
|
||||
return useAccountList(
|
||||
[accountId!, 'followers'],
|
||||
() => api.get(`/api/v1/accounts/${accountId}/followers`),
|
||||
() => api(`/api/v1/accounts/${accountId}/followers`),
|
||||
{ enabled: !!accountId },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ function useAccountLookup(acct: string | undefined, opts: UseAccountLookupOpts =
|
||||
const { entity: account, isUnauthorized, ...result } = useEntityLookup<Account>(
|
||||
Entities.ACCOUNTS,
|
||||
(account) => account.acct.toLowerCase() === acct?.toLowerCase(),
|
||||
() => api.get(`/api/v1/accounts/lookup?acct=${acct}`),
|
||||
() => api(`/api/v1/accounts/lookup?acct=${acct}`),
|
||||
{ schema: accountSchema, enabled: !!acct },
|
||||
);
|
||||
|
||||
|
||||
@@ -56,8 +56,11 @@ function useFollow() {
|
||||
followEffect(accountId);
|
||||
|
||||
try {
|
||||
const response = await api.post(`/api/v1/accounts/${accountId}/follow`, options);
|
||||
const result = relationshipSchema.safeParse(response.data);
|
||||
const response = await api(`/api/v1/accounts/${accountId}/follow`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(options),
|
||||
});
|
||||
const result = relationshipSchema.safeParse(response.json);
|
||||
if (result.success) {
|
||||
dispatch(importEntities([result.data], Entities.RELATIONSHIPS));
|
||||
}
|
||||
@@ -71,7 +74,7 @@ function useFollow() {
|
||||
unfollowEffect(accountId);
|
||||
|
||||
try {
|
||||
await api.post(`/api/v1/accounts/${accountId}/unfollow`);
|
||||
await api(`/api/v1/accounts/${accountId}/unfollow`, { method: 'POST' });
|
||||
} catch (e) {
|
||||
followEffect(accountId);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ function usePatronUser(url?: string) {
|
||||
|
||||
const { entity: patronUser, ...result } = useEntity<PatronUser>(
|
||||
[Entities.PATRON_USERS, url || ''],
|
||||
() => api.get(`/api/patron/v1/accounts/${encodeURIComponent(url!)}`),
|
||||
() => api(`/api/patron/v1/accounts/${encodeURIComponent(url!)}`),
|
||||
{ schema: patronUserSchema, enabled: !!url },
|
||||
);
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ function useRelationship(accountId: string | undefined, opts: UseRelationshipOpt
|
||||
|
||||
const { entity: relationship, ...result } = useEntity<Relationship>(
|
||||
[Entities.RELATIONSHIPS, accountId!],
|
||||
() => api.get(`/api/v1/accounts/relationships?id[]=${accountId}`),
|
||||
() => api(`/api/v1/accounts/relationships?id[]=${accountId}`),
|
||||
{
|
||||
enabled: enabled && !!accountId,
|
||||
schema: z.array(relationshipSchema).nonempty().transform(arr => arr[0]),
|
||||
|
||||
@@ -9,8 +9,7 @@ function useRelationships(listKey: string[], ids: string[]) {
|
||||
const { isLoggedIn } = useLoggedIn();
|
||||
|
||||
function fetchRelationships(ids: string[]) {
|
||||
const q = ids.map((id) => `id[]=${id}`).join('&');
|
||||
return api.get(`/api/v1/accounts/relationships?${q}`);
|
||||
return api('/api/v1/accounts/relationships', { params: { ids } });
|
||||
}
|
||||
|
||||
const { entityMap: relationships, ...result } = useBatchedEntities<Relationship>(
|
||||
|
||||
@@ -6,8 +6,6 @@ import { adminAnnouncementSchema, type AdminAnnouncement } from 'soapbox/schemas
|
||||
|
||||
import { useAnnouncements as useUserAnnouncements } from '../announcements';
|
||||
|
||||
import type { AxiosResponse } from 'axios';
|
||||
|
||||
interface CreateAnnouncementParams {
|
||||
content: string;
|
||||
starts_at?: string | null;
|
||||
@@ -24,7 +22,7 @@ const useAnnouncements = () => {
|
||||
const userAnnouncements = useUserAnnouncements();
|
||||
|
||||
const getAnnouncements = async () => {
|
||||
const { data } = await api.get<AdminAnnouncement[]>('/api/v1/pleroma/admin/announcements');
|
||||
const { json: data } = await api<AdminAnnouncement[]>('/api/v1/pleroma/admin/announcements');
|
||||
|
||||
const normalizedData = data.map((announcement) => adminAnnouncementSchema.parse(announcement));
|
||||
return normalizedData;
|
||||
@@ -40,9 +38,12 @@ const useAnnouncements = () => {
|
||||
mutate: createAnnouncement,
|
||||
isPending: isCreating,
|
||||
} = useMutation({
|
||||
mutationFn: (params: CreateAnnouncementParams) => api.post('/api/v1/pleroma/admin/announcements', params),
|
||||
mutationFn: (params: CreateAnnouncementParams) => api('/api/v1/pleroma/admin/announcements', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(params),
|
||||
}),
|
||||
retry: false,
|
||||
onSuccess: ({ data }: AxiosResponse) =>
|
||||
onSuccess: ({ json: data }) =>
|
||||
queryClient.setQueryData(['admin', 'announcements'], (prevResult: ReadonlyArray<AdminAnnouncement>) =>
|
||||
[...prevResult, adminAnnouncementSchema.parse(data)],
|
||||
),
|
||||
@@ -53,9 +54,12 @@ const useAnnouncements = () => {
|
||||
mutate: updateAnnouncement,
|
||||
isPending: isUpdating,
|
||||
} = useMutation({
|
||||
mutationFn: ({ id, ...params }: UpdateAnnouncementParams) => api.patch(`/api/v1/pleroma/admin/announcements/${id}`, params),
|
||||
mutationFn: ({ id, ...params }: UpdateAnnouncementParams) => api(`/api/v1/pleroma/admin/announcements/${id}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(params),
|
||||
}),
|
||||
retry: false,
|
||||
onSuccess: ({ data }: AxiosResponse) =>
|
||||
onSuccess: ({ json: data }) =>
|
||||
queryClient.setQueryData(['admin', 'announcements'], (prevResult: ReadonlyArray<AdminAnnouncement>) =>
|
||||
prevResult.map((announcement) => announcement.id === data.id ? adminAnnouncementSchema.parse(data) : announcement),
|
||||
),
|
||||
@@ -66,7 +70,7 @@ const useAnnouncements = () => {
|
||||
mutate: deleteAnnouncement,
|
||||
isPending: isDeleting,
|
||||
} = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/api/v1/pleroma/admin/announcements/${id}`),
|
||||
mutationFn: (id: string) => api(`/api/v1/pleroma/admin/announcements/${id}`, { method: 'DELETE' }),
|
||||
retry: false,
|
||||
onSuccess: (_, id) =>
|
||||
queryClient.setQueryData(['admin', 'announcements'], (prevResult: ReadonlyArray<AdminAnnouncement>) =>
|
||||
|
||||
@@ -4,8 +4,6 @@ import { useApi } from 'soapbox/hooks';
|
||||
import { queryClient } from 'soapbox/queries/client';
|
||||
import { domainSchema, type Domain } from 'soapbox/schemas';
|
||||
|
||||
import type { AxiosResponse } from 'axios';
|
||||
|
||||
interface CreateDomainParams {
|
||||
domain: string;
|
||||
public: boolean;
|
||||
@@ -20,7 +18,7 @@ const useDomains = () => {
|
||||
const api = useApi();
|
||||
|
||||
const getDomains = async () => {
|
||||
const { data } = await api.get<Domain[]>('/api/v1/pleroma/admin/domains');
|
||||
const { json: data } = await api<Domain[]>('/api/v1/pleroma/admin/domains');
|
||||
|
||||
const normalizedData = data.map((domain) => domainSchema.parse(domain));
|
||||
return normalizedData;
|
||||
@@ -36,9 +34,12 @@ const useDomains = () => {
|
||||
mutate: createDomain,
|
||||
isPending: isCreating,
|
||||
} = useMutation({
|
||||
mutationFn: (params: CreateDomainParams) => api.post('/api/v1/pleroma/admin/domains', params),
|
||||
mutationFn: (params: CreateDomainParams) => api('/api/v1/pleroma/admin/domains', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(params),
|
||||
}),
|
||||
retry: false,
|
||||
onSuccess: ({ data }: AxiosResponse) =>
|
||||
onSuccess: ({ data }) =>
|
||||
queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray<Domain>) =>
|
||||
[...prevResult, domainSchema.parse(data)],
|
||||
),
|
||||
@@ -48,9 +49,12 @@ const useDomains = () => {
|
||||
mutate: updateDomain,
|
||||
isPending: isUpdating,
|
||||
} = useMutation({
|
||||
mutationFn: ({ id, ...params }: UpdateDomainParams) => api.patch(`/api/v1/pleroma/admin/domains/${id}`, params),
|
||||
mutationFn: ({ id, ...params }: UpdateDomainParams) => api(`/api/v1/pleroma/admin/domains/${id}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(params),
|
||||
}),
|
||||
retry: false,
|
||||
onSuccess: ({ data }: AxiosResponse) =>
|
||||
onSuccess: ({ json: data }) =>
|
||||
queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray<Domain>) =>
|
||||
prevResult.map((domain) => domain.id === data.id ? domainSchema.parse(data) : domain),
|
||||
),
|
||||
@@ -60,7 +64,7 @@ const useDomains = () => {
|
||||
mutate: deleteDomain,
|
||||
isPending: isDeleting,
|
||||
} = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/api/v1/pleroma/admin/domains/${id}`),
|
||||
mutationFn: (id: string) => api(`/api/v1/pleroma/admin/domains/${id}`, { method: 'DELETE' }),
|
||||
retry: false,
|
||||
onSuccess: (_, id) =>
|
||||
queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray<Domain>) =>
|
||||
|
||||
@@ -14,7 +14,7 @@ const useModerationLog = () => {
|
||||
const api = useApi();
|
||||
|
||||
const getModerationLog = async (page: number): Promise<ModerationLogResult> => {
|
||||
const { data } = await api.get<ModerationLogResult>('/api/v1/pleroma/admin/moderation_log', { params: { page } });
|
||||
const { json: data } = await api<ModerationLogResult>('/api/v1/pleroma/admin/moderation_log', { params: { page } });
|
||||
|
||||
const normalizedData = data.items.map((domain) => moderationLogEntrySchema.parse(domain));
|
||||
|
||||
|
||||
@@ -4,13 +4,11 @@ import { useApi } from 'soapbox/hooks';
|
||||
import { queryClient } from 'soapbox/queries/client';
|
||||
import { relaySchema, type Relay } from 'soapbox/schemas';
|
||||
|
||||
import type { AxiosResponse } from 'axios';
|
||||
|
||||
const useRelays = () => {
|
||||
const api = useApi();
|
||||
|
||||
const getRelays = async () => {
|
||||
const { data } = await api.get<{ relays: Relay[] }>('/api/v1/pleroma/admin/relay');
|
||||
const { json: data } = await api<{ relays: Relay[] }>('/api/v1/pleroma/admin/relay');
|
||||
|
||||
const normalizedData = data.relays?.map((relay) => relaySchema.parse(relay));
|
||||
return normalizedData;
|
||||
@@ -26,9 +24,12 @@ const useRelays = () => {
|
||||
mutate: followRelay,
|
||||
isPending: isPendingFollow,
|
||||
} = useMutation({
|
||||
mutationFn: (relayUrl: string) => api.post('/api/v1/pleroma/admin/relays', { relay_url: relayUrl }),
|
||||
mutationFn: (relayUrl: string) => api('/api/v1/pleroma/admin/relays', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ relay_url: relayUrl }),
|
||||
}),
|
||||
retry: false,
|
||||
onSuccess: ({ data }: AxiosResponse) =>
|
||||
onSuccess: ({ json: data }) =>
|
||||
queryClient.setQueryData(['admin', 'relays'], (prevResult: ReadonlyArray<Relay>) =>
|
||||
[...prevResult, relaySchema.parse(data)],
|
||||
),
|
||||
@@ -38,8 +39,9 @@ const useRelays = () => {
|
||||
mutate: unfollowRelay,
|
||||
isPending: isPendingUnfollow,
|
||||
} = useMutation({
|
||||
mutationFn: (relayUrl: string) => api.delete('/api/v1/pleroma/admin/relays', {
|
||||
data: { relay_url: relayUrl },
|
||||
mutationFn: (relayUrl: string) => api('/api/v1/pleroma/admin/relays', {
|
||||
method: 'DELETE',
|
||||
body: JSON.stringify({ relay_url: relayUrl }),
|
||||
}),
|
||||
retry: false,
|
||||
onSuccess: (_, relayUrl) =>
|
||||
|
||||
@@ -4,8 +4,6 @@ import { useApi } from 'soapbox/hooks';
|
||||
import { queryClient } from 'soapbox/queries/client';
|
||||
import { adminRuleSchema, type AdminRule } from 'soapbox/schemas';
|
||||
|
||||
import type { AxiosResponse } from 'axios';
|
||||
|
||||
interface CreateRuleParams {
|
||||
priority?: number;
|
||||
text: string;
|
||||
@@ -23,7 +21,7 @@ const useRules = () => {
|
||||
const api = useApi();
|
||||
|
||||
const getRules = async () => {
|
||||
const { data } = await api.get<AdminRule[]>('/api/v1/pleroma/admin/rules');
|
||||
const { json: data } = await api<AdminRule[]>('/api/v1/pleroma/admin/rules');
|
||||
|
||||
const normalizedData = data.map((rule) => adminRuleSchema.parse(rule));
|
||||
return normalizedData;
|
||||
@@ -39,9 +37,12 @@ const useRules = () => {
|
||||
mutate: createRule,
|
||||
isPending: isCreating,
|
||||
} = useMutation({
|
||||
mutationFn: (params: CreateRuleParams) => api.post('/api/v1/pleroma/admin/rules', params),
|
||||
mutationFn: (params: CreateRuleParams) => api('/api/v1/pleroma/admin/rules', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(params),
|
||||
}),
|
||||
retry: false,
|
||||
onSuccess: ({ data }: AxiosResponse) =>
|
||||
onSuccess: ({ json: data }) =>
|
||||
queryClient.setQueryData(['admin', 'rules'], (prevResult: ReadonlyArray<AdminRule>) =>
|
||||
[...prevResult, adminRuleSchema.parse(data)],
|
||||
),
|
||||
@@ -51,9 +52,12 @@ const useRules = () => {
|
||||
mutate: updateRule,
|
||||
isPending: isUpdating,
|
||||
} = useMutation({
|
||||
mutationFn: ({ id, ...params }: UpdateRuleParams) => api.patch(`/api/v1/pleroma/admin/rules/${id}`, params),
|
||||
mutationFn: ({ id, ...params }: UpdateRuleParams) => api(`/api/v1/pleroma/admin/rules/${id}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(params),
|
||||
}),
|
||||
retry: false,
|
||||
onSuccess: ({ data }: AxiosResponse) =>
|
||||
onSuccess: ({ json: data }) =>
|
||||
queryClient.setQueryData(['admin', 'rules'], (prevResult: ReadonlyArray<AdminRule>) =>
|
||||
prevResult.map((rule) => rule.id === data.id ? adminRuleSchema.parse(data) : rule),
|
||||
),
|
||||
@@ -63,7 +67,7 @@ const useRules = () => {
|
||||
mutate: deleteRule,
|
||||
isPending: isDeleting,
|
||||
} = useMutation({
|
||||
mutationFn: (id: string) => api.delete(`/api/v1/pleroma/admin/rules/${id}`),
|
||||
mutationFn: (id: string) => api(`/api/v1/pleroma/admin/rules/${id}`, { method: 'DELETE' }),
|
||||
retry: false,
|
||||
onSuccess: (_, id) =>
|
||||
queryClient.setQueryData(['admin', 'rules'], (prevResult: ReadonlyArray<AdminRule>) =>
|
||||
|
||||
@@ -29,7 +29,10 @@ function useSuggest() {
|
||||
const accts = accountIdsToAccts(getState(), accountIds);
|
||||
suggestEffect(accountIds, true);
|
||||
try {
|
||||
await api.patch('/api/v1/pleroma/admin/users/suggest', { nicknames: accts });
|
||||
await api('/api/v1/pleroma/admin/users/suggest', {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify({ nicknames: accts }),
|
||||
});
|
||||
callbacks?.onSuccess?.();
|
||||
} catch (e) {
|
||||
callbacks?.onError?.(e);
|
||||
@@ -41,7 +44,10 @@ function useSuggest() {
|
||||
const accts = accountIdsToAccts(getState(), accountIds);
|
||||
suggestEffect(accountIds, false);
|
||||
try {
|
||||
await api.patch('/api/v1/pleroma/admin/users/unsuggest', { nicknames: accts });
|
||||
await api('/api/v1/pleroma/admin/users/unsuggest', {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify({ nicknames: accts }),
|
||||
});
|
||||
callbacks?.onSuccess?.();
|
||||
} catch (e) {
|
||||
callbacks?.onError?.(e);
|
||||
|
||||
@@ -34,7 +34,10 @@ function useVerify() {
|
||||
const accts = accountIdsToAccts(getState(), accountIds);
|
||||
verifyEffect(accountIds, true);
|
||||
try {
|
||||
await api.put('/api/v1/pleroma/admin/users/tag', { nicknames: accts, tags: ['verified'] });
|
||||
await api('/api/v1/pleroma/admin/users/tag', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ nicknames: accts, tags: ['verified'] }),
|
||||
});
|
||||
callbacks?.onSuccess?.();
|
||||
} catch (e) {
|
||||
callbacks?.onError?.(e);
|
||||
@@ -46,7 +49,10 @@ function useVerify() {
|
||||
const accts = accountIdsToAccts(getState(), accountIds);
|
||||
verifyEffect(accountIds, false);
|
||||
try {
|
||||
await api.delete('/api/v1/pleroma/admin/users/tag', { data: { nicknames: accts, tags: ['verified'] } });
|
||||
await api('/api/v1/pleroma/admin/users/tag', {
|
||||
method: 'DELETE',
|
||||
body: JSON.stringify({ nicknames: accts, tags: ['verified'] }),
|
||||
});
|
||||
callbacks?.onSuccess?.();
|
||||
} catch (e) {
|
||||
callbacks?.onError?.(e);
|
||||
|
||||
@@ -24,7 +24,7 @@ const useAnnouncements = () => {
|
||||
const api = useApi();
|
||||
|
||||
const getAnnouncements = async () => {
|
||||
const { data } = await api.get<Announcement[]>('/api/v1/announcements');
|
||||
const { json: data } = await api<Announcement[]>('/api/v1/announcements');
|
||||
|
||||
const normalizedData = data?.map((announcement) => announcementSchema.parse(announcement));
|
||||
return normalizedData;
|
||||
@@ -40,7 +40,7 @@ const useAnnouncements = () => {
|
||||
mutate: addReaction,
|
||||
} = useMutation({
|
||||
mutationFn: ({ announcementId, name }: { announcementId: string; name: string }) =>
|
||||
api.put<Announcement>(`/api/v1/announcements/${announcementId}/reactions/${name}`),
|
||||
api(`/api/v1/announcements/${announcementId}/reactions/${name}`, { method: 'PUT' }),
|
||||
retry: false,
|
||||
onMutate: ({ announcementId: id, name }) => {
|
||||
queryClient.setQueryData(['announcements'], (prevResult: Announcement[]) =>
|
||||
@@ -64,7 +64,7 @@ const useAnnouncements = () => {
|
||||
mutate: removeReaction,
|
||||
} = useMutation({
|
||||
mutationFn: ({ announcementId, name }: { announcementId: string; name: string }) =>
|
||||
api.delete<Announcement>(`/api/v1/announcements/${announcementId}/reactions/${name}`),
|
||||
api<Announcement>(`/api/v1/announcements/${announcementId}/reactions/${name}`, { method: 'DELETE' }),
|
||||
retry: false,
|
||||
onMutate: ({ announcementId: id, name }) => {
|
||||
queryClient.setQueryData(['announcements'], (prevResult: Announcement[]) =>
|
||||
|
||||
@@ -10,7 +10,7 @@ function useCancelMembershipRequest(group: Group) {
|
||||
|
||||
const { createEntity, isSubmitting } = useCreateEntity(
|
||||
[Entities.GROUP_RELATIONSHIPS],
|
||||
() => api.post(`/api/v1/groups/${group.id}/membership_requests/${me?.id}/reject`),
|
||||
() => api(`/api/v1/groups/${group.id}/membership_requests/${me?.id}/reject`, { method: 'POST' }),
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -17,10 +17,16 @@ function useCreateGroup() {
|
||||
const api = useApi();
|
||||
|
||||
const { createEntity, ...rest } = useCreateEntity([Entities.GROUPS, 'search', ''], (params: CreateGroupParams) => {
|
||||
return api.post('/api/v1/groups', params, {
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(params).forEach(([key, value]) => formData.append(key, value));
|
||||
|
||||
return api('/api/v1/groups', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
}, { schema: groupSchema });
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ function useDeleteGroupStatus(group: Group, statusId: string) {
|
||||
const api = useApi();
|
||||
const { deleteEntity, isSubmitting } = useDeleteEntity(
|
||||
Entities.STATUSES,
|
||||
() => api.delete(`/api/v1/groups/${group.id}/statuses/${statusId}`),
|
||||
() => api(`/api/v1/groups/${group.id}/statuses/${statusId}`, { method: 'DELETE' }),
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -14,7 +14,7 @@ function useGroup(groupId: string, refetch = true) {
|
||||
|
||||
const { entity: group, isUnauthorized, ...result } = useEntity<Group>(
|
||||
[Entities.GROUPS, groupId],
|
||||
() => api.get(`/api/v1/groups/${groupId}`),
|
||||
() => api(`/api/v1/groups/${groupId}`),
|
||||
{
|
||||
schema: groupSchema,
|
||||
refetch,
|
||||
|
||||
@@ -10,7 +10,7 @@ function useGroupMedia(groupId: string) {
|
||||
const api = useApi();
|
||||
|
||||
return useEntities([Entities.STATUSES, 'groupMedia', groupId], () => {
|
||||
return api.get(`/api/v1/timelines/group/${groupId}?only_media=true`);
|
||||
return api(`/api/v1/timelines/group/${groupId}?only_media=true`);
|
||||
}, { schema: statusSchema });
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ function useGroupMembers(groupId: string, role: GroupRoles) {
|
||||
|
||||
const { entities, ...result } = useEntities<GroupMember>(
|
||||
[Entities.GROUP_MEMBERSHIPS, groupId, role],
|
||||
() => api.get(`/api/v1/groups/${groupId}/memberships?role=${role}`),
|
||||
() => api(`/api/v1/groups/${groupId}/memberships?role=${role}`),
|
||||
{ schema: groupMemberSchema },
|
||||
);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ function useGroupMembershipRequests(groupId: string) {
|
||||
|
||||
const { entities, invalidate, fetchEntities, ...rest } = useEntities(
|
||||
path,
|
||||
() => api.get(`/api/v1/groups/${groupId}/membership_requests`),
|
||||
() => api(`/api/v1/groups/${groupId}/membership_requests`),
|
||||
{
|
||||
schema: accountSchema,
|
||||
enabled: relationship?.role === GroupRoles.OWNER || relationship?.role === GroupRoles.ADMIN,
|
||||
@@ -24,13 +24,13 @@ function useGroupMembershipRequests(groupId: string) {
|
||||
);
|
||||
|
||||
const { dismissEntity: authorize } = useDismissEntity(path, async (accountId: string) => {
|
||||
const response = await api.post(`/api/v1/groups/${groupId}/membership_requests/${accountId}/authorize`);
|
||||
const response = await api(`/api/v1/groups/${groupId}/membership_requests/${accountId}/authorize`, { method: 'POST' });
|
||||
invalidate();
|
||||
return response;
|
||||
});
|
||||
|
||||
const { dismissEntity: reject } = useDismissEntity(path, async (accountId: string) => {
|
||||
const response = await api.post(`/api/v1/groups/${groupId}/membership_requests/${accountId}/reject`);
|
||||
const response = await api(`/api/v1/groups/${groupId}/membership_requests/${accountId}/reject`, { method: 'POST' });
|
||||
invalidate();
|
||||
return response;
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ function useGroupRelationship(groupId: string | undefined) {
|
||||
|
||||
const { entity: groupRelationship, ...result } = useEntity<GroupRelationship>(
|
||||
[Entities.GROUP_RELATIONSHIPS, groupId!],
|
||||
() => api.get(`/api/v1/groups/relationships?id[]=${groupId}`),
|
||||
() => api(`/api/v1/groups/relationships?id[]=${groupId}`),
|
||||
{
|
||||
enabled: !!groupId,
|
||||
schema: z.array(groupRelationshipSchema).nonempty().transform(arr => arr[0]),
|
||||
|
||||
@@ -8,8 +8,7 @@ function useGroupRelationships(listKey: string[], ids: string[]) {
|
||||
const { isLoggedIn } = useLoggedIn();
|
||||
|
||||
function fetchGroupRelationships(ids: string[]) {
|
||||
const q = ids.map((id) => `id[]=${id}`).join('&');
|
||||
return api.get(`/api/v1/groups/relationships?${q}`);
|
||||
return api('/api/v1/groups/relationships', { params: { ids } });
|
||||
}
|
||||
|
||||
const { entityMap: relationships, ...result } = useBatchedEntities<GroupRelationship>(
|
||||
|
||||
@@ -12,7 +12,7 @@ function useGroups() {
|
||||
|
||||
const { entities, ...result } = useEntities<Group>(
|
||||
[Entities.GROUPS, 'search', ''],
|
||||
() => api.get('/api/v1/groups'),
|
||||
() => api('/api/v1/groups'),
|
||||
{ enabled: features.groups, schema: groupSchema },
|
||||
);
|
||||
const { relationships } = useGroupRelationships(
|
||||
|
||||
@@ -16,10 +16,16 @@ function useUpdateGroup(groupId: string) {
|
||||
const api = useApi();
|
||||
|
||||
const { createEntity, ...rest } = useCreateEntity([Entities.GROUPS], (params: UpdateGroupParams) => {
|
||||
return api.put(`/api/v1/groups/${groupId}`, params, {
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(params).forEach(([key, value]) => formData.append(key, value));
|
||||
|
||||
return api(`/api/v1/groups/${groupId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
}, { schema: groupSchema });
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ function useBookmarkFolders() {
|
||||
|
||||
const { entities, ...result } = useEntities<BookmarkFolder>(
|
||||
[Entities.BOOKMARK_FOLDERS],
|
||||
() => api.get('/api/v1/pleroma/bookmark_folders'),
|
||||
() => api('/api/v1/pleroma/bookmark_folders'),
|
||||
{ enabled: features.bookmarkFolders, schema: bookmarkFolderSchema },
|
||||
);
|
||||
|
||||
|
||||
@@ -14,10 +14,9 @@ function useCreateBookmarkFolder() {
|
||||
const { createEntity, ...rest } = useCreateEntity(
|
||||
[Entities.BOOKMARK_FOLDERS],
|
||||
(params: CreateBookmarkFolderParams) =>
|
||||
api.post('/api/v1/pleroma/bookmark_folders', params, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
api('/api/v1/pleroma/bookmark_folders', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(params),
|
||||
}),
|
||||
{ schema: bookmarkFolderSchema },
|
||||
);
|
||||
|
||||
@@ -14,10 +14,9 @@ function useUpdateBookmarkFolder(folderId: string) {
|
||||
const { createEntity, ...rest } = useCreateEntity(
|
||||
[Entities.BOOKMARK_FOLDERS],
|
||||
(params: UpdateBookmarkFolderParams) =>
|
||||
api.patch(`/api/v1/pleroma/bookmark_folders/${folderId}`, params, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
api(`/api/v1/pleroma/bookmark_folders/${folderId}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(params),
|
||||
}),
|
||||
{ schema: bookmarkFolderSchema },
|
||||
);
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/**
|
||||
* API: HTTP client and utilities.
|
||||
* @see {@link https://github.com/axios/axios}
|
||||
* @module soapbox/api
|
||||
*/
|
||||
|
||||
import axios, { type AxiosInstance, type AxiosResponse } from 'axios';
|
||||
import LinkHeader from 'http-link-header';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
@@ -12,24 +9,22 @@ import * as BuildConfig from 'soapbox/build-config';
|
||||
import { selectAccount } from 'soapbox/selectors';
|
||||
import { RootState } from 'soapbox/store';
|
||||
import { getAccessToken, getAppToken, isURL, parseBaseURL } from 'soapbox/utils/auth';
|
||||
|
||||
import type MockAdapter from 'axios-mock-adapter';
|
||||
import { buildFullPath } from 'soapbox/utils/url';
|
||||
|
||||
/**
|
||||
Parse Link headers, mostly for pagination.
|
||||
@see {@link https://www.npmjs.com/package/http-link-header}
|
||||
@param {object} response - Axios response object
|
||||
@param {object} response - Fetch API response object
|
||||
@returns {object} Link object
|
||||
*/
|
||||
export const getLinks = (response: AxiosResponse): LinkHeader => {
|
||||
return new LinkHeader(response.headers?.link);
|
||||
export const getLinks = (response: Pick<Response, 'headers'>): LinkHeader => {
|
||||
return new LinkHeader(response.headers?.get('link') || undefined);
|
||||
};
|
||||
|
||||
export const getNextLink = (response: AxiosResponse): string | undefined => {
|
||||
export const getNextLink = (response: Pick<Response, 'headers'>): string | undefined => {
|
||||
return getLinks(response).refs.find(link => link.rel === 'next')?.uri;
|
||||
};
|
||||
|
||||
export const getPrevLink = (response: AxiosResponse): string | undefined => {
|
||||
export const getPrevLink = (response: Pick<Response, 'headers'>): string | undefined => {
|
||||
return getLinks(response).refs.find(link => link.rel === 'prev')?.uri;
|
||||
};
|
||||
|
||||
@@ -37,14 +32,6 @@ const getToken = (state: RootState, authType: string) => {
|
||||
return authType === 'app' ? getAppToken(state) : getAccessToken(state);
|
||||
};
|
||||
|
||||
const maybeParseJSON = (data: string) => {
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch (Exception) {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
const getAuthBaseURL = createSelector([
|
||||
(state: RootState, me: string | false | null) => me ? selectAccount(state, me)?.url : undefined,
|
||||
(state: RootState, _me: string | false | null) => state.auth.me,
|
||||
@@ -53,39 +40,55 @@ const getAuthBaseURL = createSelector([
|
||||
return baseURL !== window.location.origin ? baseURL : '';
|
||||
});
|
||||
|
||||
/**
|
||||
* Base client for HTTP requests.
|
||||
* @param {string} accessToken
|
||||
* @param {string} baseURL
|
||||
* @returns {object} Axios instance
|
||||
*/
|
||||
export const baseClient = (
|
||||
accessToken?: string | null,
|
||||
baseURL: string = '',
|
||||
): AxiosInstance => {
|
||||
const headers: Record<string, string> = {};
|
||||
export const getFetch = (accessToken?: string | null, baseURL: string = '') =>
|
||||
<T = any>(input: URL | RequestInfo, init?: RequestInit & { params?: Record<string, any>} | undefined) => {
|
||||
const fullPath = buildFullPath(input.toString(), isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : baseURL, init?.params);
|
||||
|
||||
if (accessToken) {
|
||||
headers.Authorization = `Bearer ${accessToken}`;
|
||||
}
|
||||
const headers = new Headers(init?.headers);
|
||||
const contentType = headers.get('Content-Type') || 'application/json';
|
||||
|
||||
return axios.create({
|
||||
// When BACKEND_URL is set, always use it.
|
||||
baseURL: isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : baseURL,
|
||||
headers,
|
||||
transformResponse: [maybeParseJSON],
|
||||
});
|
||||
};
|
||||
if (accessToken) {
|
||||
headers.set('Authorization', `Bearer ${accessToken}`);
|
||||
}
|
||||
|
||||
headers.set('Content-Type', contentType);
|
||||
|
||||
return fetch(fullPath, {
|
||||
...init,
|
||||
headers,
|
||||
}).then(async (response) => {
|
||||
if (!response.ok) throw { response };
|
||||
const data = await response.text();
|
||||
let json: T = undefined!;
|
||||
try {
|
||||
json = JSON.parse(data);
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
return { ...response, data, json };
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Dumb client for grabbing static files.
|
||||
* It uses FE_SUBDIRECTORY and parses JSON if possible.
|
||||
* No authorization is needed.
|
||||
*/
|
||||
export const staticClient = axios.create({
|
||||
baseURL: BuildConfig.FE_SUBDIRECTORY,
|
||||
transformResponse: [maybeParseJSON],
|
||||
});
|
||||
export const staticFetch = (input: URL | RequestInfo, init?: RequestInit | undefined) => {
|
||||
const fullPath = buildFullPath(input.toString(), BuildConfig.FE_SUBDIRECTORY);
|
||||
|
||||
return fetch(fullPath, init).then(async (response) => {
|
||||
if (!response.ok) throw { response };
|
||||
const data = await response.text();
|
||||
let json: any = undefined!;
|
||||
try {
|
||||
json = JSON.parse(data);
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
return { ...response, data, json };
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Stateful API client.
|
||||
@@ -94,15 +97,13 @@ export const staticClient = axios.create({
|
||||
* @param {string} authType - Either 'user' or 'app'
|
||||
* @returns {object} Axios instance
|
||||
*/
|
||||
export default (getState: () => RootState, authType: string = 'user'): AxiosInstance => {
|
||||
export const api = (getState: () => RootState, authType: string = 'user') => {
|
||||
const state = getState();
|
||||
const accessToken = getToken(state, authType);
|
||||
const me = state.me;
|
||||
const baseURL = me ? getAuthBaseURL(state, me) : '';
|
||||
|
||||
return baseClient(accessToken, baseURL);
|
||||
return getFetch(accessToken, baseURL);
|
||||
};
|
||||
|
||||
// The Jest mock exports these, so they're needed for TypeScript.
|
||||
export const __stub = (_func: (mock: MockAdapter) => void) => 0;
|
||||
export const __clear = (): Function[] => [];
|
||||
export default api;
|
||||
Reference in New Issue
Block a user