pl-api: add mastodon 4.5 stuff
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -25,6 +25,7 @@ import {
|
||||
announcementSchema,
|
||||
antennaSchema,
|
||||
applicationSchema,
|
||||
asyncRefreshSchema,
|
||||
authorizationServerMetadataSchema,
|
||||
backupSchema,
|
||||
bookmarkFolderSchema,
|
||||
@ -95,7 +96,7 @@ import {
|
||||
} from './entities';
|
||||
import { coerceObject, filteredArray } from './entities/utils';
|
||||
import { AKKOMA, type Features, getFeatures, GOTOSOCIAL, ICESHRIMP_NET, MITRA, PIXELFED, PLEROMA } from './features';
|
||||
import request, { getNextLink, getPrevLink, type RequestBody, type RequestMeta } from './request';
|
||||
import request, { getAsyncRefreshHeader, getNextLink, getPrevLink, type RequestBody, type RequestMeta } from './request';
|
||||
import { buildFullPath } from './utils/url';
|
||||
|
||||
import type {
|
||||
@ -2477,7 +2478,9 @@ class PlApiClient {
|
||||
getContext: async (statusId: string, params?: GetStatusContextParams) => {
|
||||
const response = await this.request(`/api/v1/statuses/${statusId}/context`, { params });
|
||||
|
||||
return v.parse(contextSchema, response.json);
|
||||
const asyncRefreshHeader = getAsyncRefreshHeader(response);
|
||||
|
||||
return { asyncRefreshHeader, ...v.parse(contextSchema, response.json) } ;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -3890,6 +3893,19 @@ class PlApiClient {
|
||||
},
|
||||
};
|
||||
|
||||
/** Experimental async refreshes API methods */
|
||||
public readonly asyncRefreshes = {
|
||||
/**
|
||||
* Get Status of Async Refresh
|
||||
* @see {@link https://docs.joinmastodon.org/methods/async_refreshes/#show}
|
||||
*/
|
||||
show: async (id: string) => {
|
||||
const response = await this.request(`/api/v1_alpha/async_refreshes/${id}`);
|
||||
|
||||
return v.parse(asyncRefreshSchema, response.json);
|
||||
},
|
||||
};
|
||||
|
||||
public readonly admin = {
|
||||
/** Perform moderation actions with accounts. */
|
||||
accounts: {
|
||||
|
||||
20
packages/pl-api/lib/entities/async-refresh.ts
Normal file
20
packages/pl-api/lib/entities/async-refresh.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import * as v from 'valibot';
|
||||
|
||||
/**
|
||||
* @category Schemas
|
||||
* @see {@link https://docs.joinmastodon.org/entities/AsyncRefresh/}
|
||||
*/
|
||||
const asyncRefreshSchema = v.object({
|
||||
async_refresh: v.object({
|
||||
id: v.string(),
|
||||
status: v.picklist(['running', 'finished']),
|
||||
result_count: v.nullable(v.number()),
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* @category Entity types
|
||||
*/
|
||||
type AsyncRefresh = v.InferOutput<typeof asyncRefreshSchema>;
|
||||
|
||||
export { asyncRefreshSchema, type AsyncRefresh };
|
||||
@ -23,6 +23,7 @@ export * from './announcement';
|
||||
export * from './announcement-reaction';
|
||||
export * from './antenna';
|
||||
export * from './application';
|
||||
export * from './async-refresh';
|
||||
export * from './authorization-server-metadata';
|
||||
export * from './backup';
|
||||
export * from './bookmark-folder';
|
||||
|
||||
@ -161,6 +161,23 @@ const configurationSchema = coerceObject({
|
||||
translation: coerceObject({
|
||||
enabled: v.fallback(v.boolean(), false),
|
||||
}),
|
||||
timelines_access: coerceObject({
|
||||
...v.entriesFromList(
|
||||
['hashtag_feeds', 'trending_link_feeds'],
|
||||
coerceObject(
|
||||
v.entriesFromList(
|
||||
['local', 'remote'],
|
||||
v.fallback(v.picklist(['public', 'authenticated', 'disabled']), 'public'),
|
||||
),
|
||||
),
|
||||
),
|
||||
live_feeds: coerceObject(
|
||||
v.entriesFromList(
|
||||
['local', 'bubble', 'remote', 'wrenched'],
|
||||
v.fallback(v.picklist(['public', 'authenticated', 'disabled']), 'public'),
|
||||
),
|
||||
),
|
||||
}),
|
||||
urls: coerceObject({
|
||||
streaming: v.fallback(v.optional(v.pipe(v.string(), v.url())), undefined),
|
||||
status: v.fallback(v.optional(v.pipe(v.string(), v.url())), undefined),
|
||||
@ -358,6 +375,23 @@ const instanceSchema = v.pipe(
|
||||
};
|
||||
}
|
||||
|
||||
if (data.pleroma?.metadata?.restrict_unauthenticated?.timelines) {
|
||||
const timelines = data.pleroma.metadata.restrict_unauthenticated.timelines;
|
||||
const features = data.pleroma.metadata.features || [];
|
||||
|
||||
if (!data.configuration) data.configuration = {};
|
||||
|
||||
data.configuration.timelines_access = {
|
||||
...data.configuration.timelines_access,
|
||||
live_feeds: {
|
||||
bubble: timelines.bubble ? 'authenticated' : features.includes('bubble_timeline') ? 'public' : 'disabled',
|
||||
local: timelines.local ? 'authenticated' : 'public',
|
||||
remote: timelines.federated ? 'authenticated' : 'public',
|
||||
wrenched: timelines.wrenched ? 'authenticated' : features.includes('pleroma:wrenched_timeline') ? 'public' : 'disabled',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (data.domain) return { account_domain: data.domain, ...data, api_versions: apiVersions };
|
||||
|
||||
return { ...instanceV1ToV2(data), api_versions: apiVersions };
|
||||
|
||||
@ -30,6 +30,47 @@ const getNextLink = (response: Pick<Response, 'headers'>): string | null =>
|
||||
const getPrevLink = (response: Pick<Response, 'headers'>): string | null =>
|
||||
getLinks(response).refs.find(link => link.rel.toLocaleLowerCase() === 'prev')?.uri || null;
|
||||
|
||||
interface AsyncRefreshHeader {
|
||||
id: string;
|
||||
retry: number;
|
||||
}
|
||||
|
||||
const isAsyncRefreshHeader = (obj: object): obj is AsyncRefreshHeader =>
|
||||
'id' in obj && 'retry' in obj;
|
||||
|
||||
const getAsyncRefreshHeader = (response: Pick<Response, 'headers'>): AsyncRefreshHeader | null => {
|
||||
const value = response.headers.get('mastodon-async-refresh');
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const asyncRefreshHeader: Record<string, unknown> = {};
|
||||
|
||||
value.split(/,\s*/).forEach((pair) => {
|
||||
const [key, val] = pair.split('=', 2);
|
||||
|
||||
let typedValue: string | number;
|
||||
|
||||
if (key && ['id', 'retry'].includes(key) && val) {
|
||||
if (val.startsWith('"')) {
|
||||
typedValue = val.slice(1, -1);
|
||||
} else {
|
||||
typedValue = parseInt(val);
|
||||
}
|
||||
|
||||
asyncRefreshHeader[key] = typedValue;
|
||||
}
|
||||
});
|
||||
|
||||
if (isAsyncRefreshHeader(asyncRefreshHeader)) {
|
||||
return asyncRefreshHeader;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
interface RequestBody<Params = Record<string, any>> {
|
||||
method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
||||
body?: any;
|
||||
@ -131,9 +172,11 @@ export {
|
||||
type Response,
|
||||
type RequestBody,
|
||||
type RequestMeta,
|
||||
type AsyncRefreshHeader,
|
||||
getLinks,
|
||||
getNextLink,
|
||||
getPrevLink,
|
||||
getAsyncRefreshHeader,
|
||||
request,
|
||||
request as default,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user