pl-api: More blind search and replace before actual testing
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
@ -380,7 +380,7 @@ class PlApiClient {
|
||||
|
||||
return v.parse(v.intersect([v.object({
|
||||
type: v.string(),
|
||||
}), z.record(v.any())]), response.json);
|
||||
}), v.record(v.string(), v.any())]), response.json);
|
||||
},
|
||||
|
||||
mfaChallenge: async (params: MfaChallengeParams) => {
|
||||
@ -2773,7 +2773,7 @@ class PlApiClient {
|
||||
|
||||
const response = await this.request('/api/v1/instance/translation_languages');
|
||||
|
||||
return v.parse(z.record(v.array(v.string())), response.json);
|
||||
return v.parse(v.record(v.string(), v.array(v.string())), response.json);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2806,7 +2806,7 @@ class PlApiClient {
|
||||
getFrontendConfigurations: async () => {
|
||||
const response = await this.request('/api/pleroma/frontend_configurations');
|
||||
|
||||
return v.parse(z.record(z.record(v.any())).catch({}), response.json);
|
||||
return v.parse(v.fallback(v.record(v.string(), v.record(v.string(), v.any())), {}), response.json);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -64,31 +64,31 @@ const preprocessAccount = (account: any) => {
|
||||
const fieldSchema = v.object({
|
||||
name: v.string(),
|
||||
value: v.string(),
|
||||
verified_at: z.string().datetime({ offset: true }).nullable().catch(null),
|
||||
verified_at: v.fallback(v.nullable(z.string().datetime({ offset: true })), null),
|
||||
});
|
||||
|
||||
const baseAccountSchema = v.object({
|
||||
id: v.string(),
|
||||
username: v.fallback(v.string(), ''),
|
||||
acct: v.fallback(v.string(), ''),
|
||||
url: z.string().url(),
|
||||
url: v.pipe(v.string(), v.url()),
|
||||
display_name: v.fallback(v.string(), ''),
|
||||
note: v.fallback(v.string(), ''),
|
||||
avatar: v.fallback(v.string(), ''),
|
||||
avatar_static: z.string().url().catch(''),
|
||||
header: z.string().url().catch(''),
|
||||
header_static: z.string().url().catch(''),
|
||||
avatar_static: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
header: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
header_static: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
locked: v.fallback(v.boolean(), false),
|
||||
fields: filteredArray(fieldSchema),
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
bot: v.fallback(v.boolean(), false),
|
||||
group: v.fallback(v.boolean(), false),
|
||||
discoverable: v.fallback(v.boolean(), false),
|
||||
noindex: v.fallback(v.optional(v.nullable()), null),
|
||||
noindex: v.fallback(v.nullable(v.boolean()), null),
|
||||
suspended: v.fallback(v.optional(v.boolean()), undefined),
|
||||
limited: v.fallback(v.optional(v.boolean()), undefined),
|
||||
created_at: z.string().datetime().catch(new Date().toUTCString()),
|
||||
last_status_at: z.string().date().nullable().catch(null),
|
||||
last_status_at: v.fallback(v.nullable(z.string().date()), null),
|
||||
statuses_count: v.fallback(v.number(), 0),
|
||||
followers_count: v.fallback(v.number(), 0),
|
||||
following_count: v.fallback(v.number(), 0),
|
||||
@ -97,7 +97,7 @@ const baseAccountSchema = v.object({
|
||||
fqn: v.fallback(v.nullable(v.string()), null),
|
||||
ap_id: v.fallback(v.nullable(v.string()), null),
|
||||
background_image: v.fallback(v.nullable(v.string()), null),
|
||||
relationship: relationshipSchema.optional().catch(undefined),
|
||||
relationship: v.fallback(v.optional(relationshipSchema), undefined),
|
||||
is_moderator: v.fallback(v.optional(v.boolean()), undefined),
|
||||
is_admin: v.fallback(v.optional(v.boolean()), undefined),
|
||||
is_suggested: v.fallback(v.optional(v.boolean()), undefined),
|
||||
@ -106,7 +106,7 @@ const baseAccountSchema = v.object({
|
||||
hide_follows: v.fallback(v.optional(v.boolean()), undefined),
|
||||
hide_followers_count: v.fallback(v.optional(v.boolean()), undefined),
|
||||
hide_follows_count: v.fallback(v.optional(v.boolean()), undefined),
|
||||
accepts_chat_messages: v.fallback(v.optional(v.nullable()), null),
|
||||
accepts_chat_messages: v.fallback(v.nullable(v.boolean()), null),
|
||||
favicon: v.fallback(v.optional(v.string()), undefined),
|
||||
birthday: z.string().date().optional().catch(undefined),
|
||||
deactivated: v.fallback(v.optional(v.boolean()), undefined),
|
||||
@ -121,13 +121,13 @@ const baseAccountSchema = v.object({
|
||||
verified: v.fallback(v.optional(v.boolean()), undefined),
|
||||
|
||||
__meta: coerceObject({
|
||||
pleroma: z.any().optional().catch(undefined),
|
||||
source: z.any().optional().catch(undefined),
|
||||
pleroma: v.fallback(v.any(), undefined),
|
||||
source: v.fallback(v.any(), undefined),
|
||||
}),
|
||||
});
|
||||
|
||||
const accountWithMovedAccountSchema = baseAccountSchema.extend({
|
||||
moved: z.lazy((): typeof baseAccountSchema => accountWithMovedAccountSchema as any).nullable().catch(null),
|
||||
moved: v.fallback(v.nullable(z.lazy((): typeof baseAccountSchema => accountWithMovedAccountSchema as any)), null),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Account/} */
|
||||
@ -145,7 +145,7 @@ const untypedCredentialAccountSchema = z.preprocess(preprocessAccount, accountWi
|
||||
source: v.object({
|
||||
note: v.fallback(v.string(), ''),
|
||||
fields: filteredArray(fieldSchema),
|
||||
privacy: z.enum(['public', 'unlisted', 'private', 'direct']),
|
||||
privacy: v.picklist(['public', 'unlisted', 'private', 'direct']),
|
||||
sensitive: v.fallback(v.boolean(), false),
|
||||
language: v.fallback(v.nullable(v.string()), null),
|
||||
follow_requests_count: z.number().int().nonnegative().catch(0),
|
||||
@ -158,15 +158,15 @@ const untypedCredentialAccountSchema = z.preprocess(preprocessAccount, accountWi
|
||||
}).nullable().catch(null),
|
||||
role: v.fallback(v.nullable(roleSchema), null),
|
||||
|
||||
settings_store: z.record(z.any()).optional().catch(undefined),
|
||||
settings_store: v.record(v.string(), v.any()).optional().catch(undefined),
|
||||
chat_token: v.fallback(v.optional(v.string()), undefined),
|
||||
allow_following_move: v.fallback(v.optional(v.boolean()), undefined),
|
||||
unread_conversation_count: z.number().optional().catch(undefined),
|
||||
unread_notifications_count: z.number().optional().catch(undefined),
|
||||
notification_settings: v.object({
|
||||
unread_conversation_count: v.fallback(v.optional(v.number()), undefined),
|
||||
unread_notifications_count: v.fallback(v.optional(v.number()), undefined),
|
||||
notification_settings: v.fallback(v.optional(v.object({
|
||||
block_from_strangers: v.fallback(v.boolean(), false),
|
||||
hide_notification_contents: v.fallback(v.boolean(), false),
|
||||
}).optional().catch(undefined),
|
||||
})), undefined),
|
||||
}));
|
||||
|
||||
type CredentialAccount = v.InferOutput<typeof untypedCredentialAccountSchema> & WithMoved;
|
||||
|
||||
@ -42,7 +42,7 @@ const adminAccountSchema = z.preprocess((account: any) => {
|
||||
domain: v.fallback(v.nullable(v.string()), null),
|
||||
created_at: dateSchema,
|
||||
email: v.fallback(v.nullable(v.string()), null),
|
||||
ip: z.string().ip().nullable().catch(null),
|
||||
ip: v.fallback(v.nullable(z.string().ip()), null),
|
||||
ips: filteredArray(adminIpSchema),
|
||||
locale: v.fallback(v.nullable(v.string()), null),
|
||||
invite_request: v.fallback(v.nullable(v.string()), null),
|
||||
@ -58,7 +58,7 @@ const adminAccountSchema = z.preprocess((account: any) => {
|
||||
|
||||
actor_type: v.fallback(v.nullable(v.string()), null),
|
||||
display_name: v.fallback(v.nullable(v.string()), null),
|
||||
suggested: v.fallback(v.optional(v.nullable()), null),
|
||||
suggested: v.fallback(v.nullable(v.boolean()), null),
|
||||
}));
|
||||
|
||||
type AdminAccount = v.InferOutput<typeof adminAccountSchema>;
|
||||
|
||||
@ -3,11 +3,11 @@ import * as v from 'valibot';
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_Cohort/} */
|
||||
const adminCohortSchema = v.object({
|
||||
period: z.string().datetime({ offset: true }),
|
||||
frequency: z.enum(['day', 'month']),
|
||||
frequency: v.picklist(['day', 'month']),
|
||||
data: z.array(v.object({
|
||||
date: z.string().datetime({ offset: true }),
|
||||
rate: z.number(),
|
||||
value: z.number().int(),
|
||||
rate: v.number(),
|
||||
value: v.pipe(v.number(), v.integer()),
|
||||
})),
|
||||
});
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ const adminDomainBlockSchema = v.object({
|
||||
domain: v.string(),
|
||||
digest: v.string(),
|
||||
created_at: dateSchema,
|
||||
severity: z.enum(['silence', 'suspend', 'noop']),
|
||||
severity: v.picklist(['silence', 'suspend', 'noop']),
|
||||
reject_media: v.boolean(),
|
||||
reject_reports: v.boolean(),
|
||||
private_comment: v.fallback(v.nullable(v.string()), null),
|
||||
|
||||
@ -6,7 +6,7 @@ import { dateSchema } from '../utils';
|
||||
const adminIpBlockSchema = v.object({
|
||||
id: v.string(),
|
||||
ip: z.string().ip(),
|
||||
severity: z.enum(['sign_up_requires_approval', 'sign_up_block', 'no_access']),
|
||||
severity: v.picklist(['sign_up_requires_approval', 'sign_up_block', 'no_access']),
|
||||
comment: v.fallback(v.string(), ''),
|
||||
created_at: dateSchema,
|
||||
expires_at: z.string().datetime({ offset: true }),
|
||||
|
||||
@ -3,7 +3,7 @@ import * as v from 'valibot';
|
||||
/** @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminmoderation_log} */
|
||||
const adminModerationLogEntrySchema = v.object({
|
||||
id: z.coerce.string(),
|
||||
data: z.record(v.string(), z.any()).catch({}),
|
||||
data: v.fallback(v.record(v.string(), v.any()), {}),
|
||||
time: v.fallback(v.number(), 0),
|
||||
message: v.fallback(v.string(), ''),
|
||||
});
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import * as v from 'valibot';
|
||||
|
||||
const pleromaConfigSchema = v.object({
|
||||
configs: z.array(v.object({
|
||||
value: z.any(),
|
||||
configs: v.array(v.object({
|
||||
value: v.any(),
|
||||
group: v.string(),
|
||||
key: v.string(),
|
||||
})),
|
||||
|
||||
@ -31,8 +31,8 @@ const adminReportSchema = z.preprocess((report: any) => {
|
||||
category: v.fallback(v.optional(v.string()), undefined),
|
||||
comment: v.fallback(v.optional(v.string()), undefined),
|
||||
forwarded: v.fallback(v.optional(v.boolean()), undefined),
|
||||
created_at: dateSchema.optional().catch(undefined),
|
||||
updated_at: dateSchema.optional().catch(undefined),
|
||||
created_at: v.fallback(v.optional(dateSchema), undefined),
|
||||
updated_at: v.fallback(v.optional(dateSchema), undefined),
|
||||
account: adminAccountSchema,
|
||||
target_account: adminAccountSchema,
|
||||
assigned_account: v.fallback(v.nullable(adminAccountSchema), null),
|
||||
|
||||
@ -10,8 +10,8 @@ import { dateSchema, filteredArray } from './utils';
|
||||
const announcementSchema = v.object({
|
||||
id: v.string(),
|
||||
content: v.fallback(v.string(), ''),
|
||||
starts_at: z.string().datetime().nullable().catch(null),
|
||||
ends_at: z.string().datetime().nullable().catch(null),
|
||||
starts_at: v.fallback(v.nullable(z.string().datetime()), null),
|
||||
ends_at: v.fallback(v.nullable(z.string().datetime()), null),
|
||||
all_day: v.fallback(v.boolean(), false),
|
||||
read: v.fallback(v.boolean(), false),
|
||||
published_at: dateSchema,
|
||||
@ -20,7 +20,7 @@ const announcementSchema = v.object({
|
||||
(statuses: any) => Array.isArray(statuses)
|
||||
? Object.fromEntries(statuses.map((status: any) => [status.url, status.account?.acct]) || [])
|
||||
: statuses,
|
||||
z.record(v.string(), v.string()),
|
||||
v.record(v.string(), v.string(), v.string()),
|
||||
),
|
||||
mentions: filteredArray(mentionSchema),
|
||||
tags: filteredArray(tagSchema),
|
||||
|
||||
@ -8,7 +8,7 @@ import { dateSchema } from './utils';
|
||||
const chatSchema = v.object({
|
||||
id: v.string(),
|
||||
account: accountSchema,
|
||||
unread: z.number().int(),
|
||||
unread: v.pipe(v.number(), v.integer()),
|
||||
last_message: v.fallback(v.nullable(chatMessageSchema), null),
|
||||
created_at: dateSchema,
|
||||
});
|
||||
|
||||
@ -2,7 +2,7 @@ import * as v from 'valibot';
|
||||
|
||||
const directoryCategorySchema = v.object({
|
||||
category: v.string(),
|
||||
servers_count: z.coerce.number().nullable().catch(null),
|
||||
servers_count: v.fallback(v.nullable(z.coerce.number()), null),
|
||||
});
|
||||
|
||||
type DirectoryCategory = v.InferOutput<typeof directoryCategorySchema>;
|
||||
|
||||
@ -3,7 +3,7 @@ import * as v from 'valibot';
|
||||
const directoryLanguageSchema = v.object({
|
||||
locale: v.string(),
|
||||
language: v.string(),
|
||||
servers_count: z.coerce.number().nullable().catch(null),
|
||||
servers_count: v.fallback(v.nullable(z.coerce.number()), null),
|
||||
});
|
||||
|
||||
type DirectoryLanguage = v.InferOutput<typeof directoryLanguageSchema>;
|
||||
|
||||
@ -7,7 +7,7 @@ const directoryServerSchema = v.object({
|
||||
languages: z.array(v.string()),
|
||||
region: v.string(),
|
||||
categories: z.array(v.string()),
|
||||
proxied_thumbnail: z.string().url().nullable().catch(null),
|
||||
proxied_thumbnail: v.fallback(v.nullable(z.string().url()), null),
|
||||
blurhash: v.fallback(v.nullable(v.string()), null),
|
||||
total_users: z.coerce.number(),
|
||||
last_week_users: z.coerce.number(),
|
||||
|
||||
@ -2,9 +2,9 @@ import * as v from 'valibot';
|
||||
|
||||
const directoryStatisticsPeriodSchema = v.object({
|
||||
period: z.string().date(),
|
||||
server_count: z.coerce.number().nullable().catch(null),
|
||||
user_count: z.coerce.number().nullable().catch(null),
|
||||
active_user_count: z.coerce.number().nullable().catch(null),
|
||||
server_count: v.fallback(v.nullable(z.coerce.number()), null),
|
||||
user_count: v.fallback(v.nullable(z.coerce.number()), null),
|
||||
active_user_count: v.fallback(v.nullable(z.coerce.number()), null),
|
||||
});
|
||||
|
||||
type DirectoryStatisticsPeriod = v.InferOutput<typeof directoryStatisticsPeriodSchema>;
|
||||
|
||||
@ -4,7 +4,7 @@ import * as v from 'valibot';
|
||||
const domainBlockSchema = v.object({
|
||||
domain: v.string(),
|
||||
digest: v.string(),
|
||||
severity: z.enum(['silence', 'suspend']),
|
||||
severity: v.picklist(['silence', 'suspend']),
|
||||
comment: v.fallback(v.optional(v.string()), undefined),
|
||||
});
|
||||
|
||||
|
||||
@ -7,16 +7,16 @@ const baseEmojiReactionSchema = v.object({
|
||||
count: v.fallback(v.nullable(v.number()), null),
|
||||
me: v.fallback(v.boolean(), false),
|
||||
name: emojiSchema,
|
||||
url: z.literal(undefined).catch(undefined),
|
||||
static_url: z.literal(undefined).catch(undefined),
|
||||
url: v.fallback(v.undefined(), undefined),
|
||||
static_url: v.fallback(v.undefined(), undefined),
|
||||
accounts: filteredArray(accountSchema),
|
||||
account_ids: filteredArray(v.string()).catch([]),
|
||||
});
|
||||
|
||||
const customEmojiReactionSchema = baseEmojiReactionSchema.extend({
|
||||
name: v.string(),
|
||||
url: z.string().url(),
|
||||
static_url: z.string().url(),
|
||||
url: v.pipe(v.string(), v.url()),
|
||||
static_url: v.pipe(v.string(), v.url()),
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@ -5,8 +5,8 @@ const featuredTagSchema = v.object({
|
||||
id: v.string(),
|
||||
name: v.string(),
|
||||
url: v.fallback(v.optional(v.string()), undefined),
|
||||
statuses_count: z.number(),
|
||||
last_status_at: z.number(),
|
||||
statuses_count: v.number(),
|
||||
last_status_at: v.number(),
|
||||
});
|
||||
|
||||
type FeaturedTag = v.InferOutput<typeof featuredTagSchema>;
|
||||
|
||||
@ -5,8 +5,8 @@ import { filterSchema } from './filter';
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/FilterResult/} */
|
||||
const filterResultSchema = v.object({
|
||||
filter: filterSchema,
|
||||
keyword_matches: z.array(v.string()).nullable().catch(null),
|
||||
status_matches: z.array(v.string()).nullable().catch(null),
|
||||
keyword_matches: v.fallback(v.nullable(v.string()), null),
|
||||
status_matches: v.fallback(v.nullable(v.string()), null),
|
||||
});
|
||||
|
||||
type FilterResult = v.InferOutput<typeof filterResultSchema>;
|
||||
|
||||
@ -33,9 +33,9 @@ const filterSchema = z.preprocess((filter: any) => {
|
||||
}, v.object({
|
||||
id: v.string(),
|
||||
title: v.string(),
|
||||
context: z.array(z.enum(['home', 'notifications', 'public', 'thread', 'account'])),
|
||||
expires_at: z.string().datetime({ offset: true }).nullable().catch(null),
|
||||
filter_action: z.enum(['warn', 'hide']).catch('warn'),
|
||||
context: v.array(v.picklist(['home', 'notifications', 'public', 'thread', 'account'])),
|
||||
expires_at: v.fallback(v.nullable(z.string().datetime({ offset: true })), null),
|
||||
filter_action: v.fallback(v.picklist(['warn', 'hide']), 'warn'),
|
||||
keywords: filteredArray(filterKeywordSchema),
|
||||
statuses: filteredArray(filterStatusSchema),
|
||||
}));
|
||||
|
||||
@ -17,10 +17,10 @@ const groupSchema = v.object({
|
||||
locked: v.fallback(v.boolean(), false),
|
||||
membership_required: v.fallback(v.boolean(), false),
|
||||
members_count: v.fallback(v.number(), 0),
|
||||
owner: v.object({ id: z.string() }).nullable().catch(null),
|
||||
owner: v.object({ id: v.string() }).nullable().catch(null),
|
||||
note: z.string().transform(note => note === '<p></p>' ? '' : note).catch(''),
|
||||
relationship: v.fallback(v.nullable(groupRelationshipSchema), null), // Dummy field to be overwritten later
|
||||
statuses_visibility: z.string().catch('public'),
|
||||
statuses_visibility: v.fallback(v.string(), 'public'),
|
||||
uri: v.fallback(v.string(), ''),
|
||||
url: v.fallback(v.string(), ''),
|
||||
|
||||
|
||||
@ -108,47 +108,47 @@ const fixVersion = (version: string) => {
|
||||
};
|
||||
|
||||
const configurationSchema = coerceObject({
|
||||
accounts: v.object({
|
||||
accounts: v.fallback(v.nullable(v.object({
|
||||
allow_custom_css: v.boolean(),
|
||||
max_featured_tags: z.number().int(),
|
||||
max_profile_fields: z.number().int(),
|
||||
}).nullable().catch(null),
|
||||
max_featured_tags: v.pipe(v.number(), v.integer()),
|
||||
max_profile_fields: v.pipe(v.number(), v.integer()),
|
||||
})), null),
|
||||
chats: coerceObject({
|
||||
max_characters: z.number().catch(5000),
|
||||
max_characters: v.fallback(v.number(), 5000),
|
||||
}),
|
||||
groups: coerceObject({
|
||||
max_characters_description: z.number().catch(160),
|
||||
max_characters_name: z.number().catch(50),
|
||||
max_characters_description: v.fallback(v.number(), 160),
|
||||
max_characters_name: v.fallback(v.number(), 50),
|
||||
}),
|
||||
media_attachments: coerceObject({
|
||||
image_matrix_limit: z.number().optional().catch(undefined),
|
||||
image_size_limit: z.number().optional().catch(undefined),
|
||||
supported_mime_types: mimeSchema.array().optional().catch(undefined),
|
||||
video_duration_limit: z.number().optional().catch(undefined),
|
||||
video_frame_rate_limit: z.number().optional().catch(undefined),
|
||||
video_matrix_limit: z.number().optional().catch(undefined),
|
||||
video_size_limit: z.number().optional().catch(undefined),
|
||||
image_matrix_limit: v.fallback(v.optional(v.number()), undefined),
|
||||
image_size_limit: v.fallback(v.optional(v.number()), undefined),
|
||||
supported_mime_types: v.fallback(v.optional(v.array(mimeSchema)), undefined),
|
||||
video_duration_limit: v.fallback(v.optional(v.number()), undefined),
|
||||
video_frame_rate_limit: v.fallback(v.optional(v.number()), undefined),
|
||||
video_matrix_limit: v.fallback(v.optional(v.number()), undefined),
|
||||
video_size_limit: v.fallback(v.optional(v.number()), undefined),
|
||||
}),
|
||||
polls: coerceObject({
|
||||
max_characters_per_option: z.number().catch(25),
|
||||
max_expiration: z.number().catch(2629746),
|
||||
max_options: z.number().catch(4),
|
||||
min_expiration: z.number().catch(300),
|
||||
max_characters_per_option: v.fallback(v.number(), 25),
|
||||
max_expiration: v.fallback(v.number(), 2629746),
|
||||
max_options: v.fallback(v.number(), 4),
|
||||
min_expiration: v.fallback(v.number(), 300),
|
||||
}),
|
||||
reactions: coerceObject({
|
||||
max_reactions: v.fallback(v.number(), 0),
|
||||
}),
|
||||
statuses: coerceObject({
|
||||
characters_reserved_per_url: z.number().optional().catch(undefined),
|
||||
max_characters: z.number().catch(500),
|
||||
max_media_attachments: z.number().catch(4),
|
||||
characters_reserved_per_url: v.fallback(v.optional(v.number()), undefined),
|
||||
max_characters: v.fallback(v.number(), 500),
|
||||
max_media_attachments: v.fallback(v.number(), 4),
|
||||
|
||||
}),
|
||||
translation: coerceObject({
|
||||
enabled: v.fallback(v.boolean(), false),
|
||||
}),
|
||||
urls: coerceObject({
|
||||
streaming: z.string().url().optional().catch(undefined),
|
||||
streaming: v.fallback(v.optional(v.pipe(v.string(), v.url())), undefined),
|
||||
}),
|
||||
vapid: coerceObject({
|
||||
public_key: v.fallback(v.string(), ''),
|
||||
@ -156,8 +156,8 @@ const configurationSchema = coerceObject({
|
||||
});
|
||||
|
||||
const contactSchema = coerceObject({
|
||||
contact_account: accountSchema.optional().catch(undefined),
|
||||
email: z.string().email().catch(''),
|
||||
contact_account: v.fallback(v.optional(accountSchema), undefined),
|
||||
email: v.fallback(v.pipe(v.string(), v.email()), ''),
|
||||
});
|
||||
|
||||
const pleromaSchema = coerceObject({
|
||||
@ -165,11 +165,11 @@ const pleromaSchema = coerceObject({
|
||||
account_activation_required: v.fallback(v.boolean(), false),
|
||||
birthday_min_age: v.fallback(v.number(), 0),
|
||||
birthday_required: v.fallback(v.boolean(), false),
|
||||
description_limit: z.number().catch(1500),
|
||||
description_limit: v.fallback(v.number(), 1500),
|
||||
features: v.fallback(v.array(v.string()), []),
|
||||
federation: coerceObject({
|
||||
enabled: v.fallback(v.boolean(), true), // Assume true unless explicitly false
|
||||
mrf_policies: z.string().array().optional().catch(undefined),
|
||||
mrf_policies: v.fallback(v.optional(v.array(v.string())), undefined),
|
||||
mrf_simple: coerceObject({
|
||||
accept: v.fallback(v.array(v.string()), []),
|
||||
avatar_removal: v.fallback(v.array(v.string()), []),
|
||||
@ -192,17 +192,15 @@ const pleromaSchema = coerceObject({
|
||||
allow_headings: v.fallback(v.boolean(), false),
|
||||
allow_inline_images: v.fallback(v.boolean(), false),
|
||||
}),
|
||||
migration_cooldown_period: z.number().optional().catch(undefined),
|
||||
migration_cooldown_period: v.fallback(v.optional(v.number()), undefined),
|
||||
multitenancy: coerceObject({
|
||||
domains: z
|
||||
.array(
|
||||
v.object({
|
||||
domain: z.coerce.string(),
|
||||
id: v.string(),
|
||||
public: v.fallback(v.boolean(), false),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
domains: v.optional(v.array(
|
||||
v.object({
|
||||
domain: z.coerce.string(),
|
||||
id: v.string(),
|
||||
public: v.fallback(v.boolean(), false),
|
||||
}),
|
||||
)),
|
||||
enabled: v.fallback(v.boolean(), false),
|
||||
}),
|
||||
post_formats: z.string().array().optional().catch(undefined),
|
||||
@ -230,16 +228,16 @@ const pleromaSchema = coerceObject({
|
||||
}),
|
||||
oauth_consumer_strategies: v.fallback(v.array(v.string()), []),
|
||||
stats: coerceObject({
|
||||
mau: z.number().optional().catch(undefined),
|
||||
mau: v.fallback(v.optional(v.number()), undefined),
|
||||
}),
|
||||
vapid_public_key: v.fallback(v.string(), ''),
|
||||
});
|
||||
|
||||
const pleromaPollLimitsSchema = coerceObject({
|
||||
max_expiration: z.number().optional().catch(undefined),
|
||||
max_option_chars: z.number().optional().catch(undefined),
|
||||
max_options: z.number().optional().catch(undefined),
|
||||
min_expiration: z.number().optional().catch(undefined),
|
||||
max_expiration: v.fallback(v.optional(v.number()), undefined),
|
||||
max_option_chars: v.fallback(v.optional(v.number()), undefined),
|
||||
max_options: v.fallback(v.optional(v.number()), undefined),
|
||||
min_expiration: v.fallback(v.optional(v.number()), undefined),
|
||||
});
|
||||
|
||||
const registrations = coerceObject({
|
||||
@ -249,9 +247,9 @@ const registrations = coerceObject({
|
||||
});
|
||||
|
||||
const statsSchema = coerceObject({
|
||||
domain_count: z.number().optional().catch(undefined),
|
||||
status_count: z.number().optional().catch(undefined),
|
||||
user_count: z.number().optional().catch(undefined),
|
||||
domain_count: v.fallback(v.optional(v.number()), undefined),
|
||||
status_count: v.fallback(v.optional(v.number()), undefined),
|
||||
user_count: v.fallback(v.optional(v.number()), undefined),
|
||||
});
|
||||
|
||||
const thumbnailSchema = coerceObject({
|
||||
@ -268,15 +266,15 @@ const instanceV1Schema = coerceObject({
|
||||
account_domain: v.fallback(v.string(), ''),
|
||||
approval_required: v.fallback(v.boolean(), false),
|
||||
configuration: configurationSchema,
|
||||
contact_account: accountSchema.optional().catch(undefined),
|
||||
contact_account: v.fallback(v.optional(accountSchema), undefined),
|
||||
description: v.fallback(v.string(), ''),
|
||||
description_limit: z.number().catch(1500),
|
||||
email: z.string().email().catch(''),
|
||||
description_limit: v.fallback(v.number(), 1500),
|
||||
email: v.fallback(v.pipe(v.string(), v.email()), ''),
|
||||
feature_quote: v.fallback(v.boolean(), false),
|
||||
fedibird_capabilities: z.array(v.string()).catch([]),
|
||||
fedibird_capabilities: v.fallback(v.array(v.string()), []),
|
||||
languages: v.fallback(v.array(v.string()), []),
|
||||
max_media_attachments: z.number().optional().catch(undefined),
|
||||
max_toot_chars: z.number().optional().catch(undefined),
|
||||
max_media_attachments: v.fallback(v.optional(v.number()), undefined),
|
||||
max_toot_chars: v.fallback(v.optional(v.number()), undefined),
|
||||
pleroma: pleromaSchema,
|
||||
poll_limits: pleromaPollLimitsSchema,
|
||||
registrations: v.fallback(v.boolean(), false),
|
||||
@ -285,13 +283,13 @@ const instanceV1Schema = coerceObject({
|
||||
stats: statsSchema,
|
||||
thumbnail: v.fallback(v.string(), ''),
|
||||
title: v.fallback(v.string(), ''),
|
||||
upload_limit: z.number().optional().catch(undefined),
|
||||
upload_limit: v.fallback(v.optional(v.number()), undefined),
|
||||
uri: v.fallback(v.string(), ''),
|
||||
urls: coerceObject({
|
||||
streaming_api: z.string().url().optional().catch(undefined),
|
||||
streaming_api: v.fallback(v.optional(v.pipe(v.string(), v.url())), undefined),
|
||||
}),
|
||||
usage: usageSchema,
|
||||
version: z.string().catch('0.0.0'),
|
||||
version: v.fallback(v.string(), '0.0.0'),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Instance/} */
|
||||
@ -308,13 +306,13 @@ const instanceSchema = z.preprocess((data: any) => {
|
||||
return instanceV1ToV2({ ...data, api_versions: apiVersions });
|
||||
}, coerceObject({
|
||||
account_domain: v.fallback(v.string(), ''),
|
||||
api_versions: z.record(z.number()).catch({}),
|
||||
api_versions: v.fallback(v.record(v.string(), v.number()), {}),
|
||||
configuration: configurationSchema,
|
||||
contact: contactSchema,
|
||||
description: v.fallback(v.string(), ''),
|
||||
domain: v.fallback(v.string(), ''),
|
||||
feature_quote: v.fallback(v.boolean(), false),
|
||||
fedibird_capabilities: z.array(v.string()).catch([]),
|
||||
fedibird_capabilities: v.fallback(v.array(v.string()), []),
|
||||
languages: v.fallback(v.array(v.string()), []),
|
||||
pleroma: pleromaSchema,
|
||||
registrations: registrations,
|
||||
@ -323,7 +321,7 @@ const instanceSchema = z.preprocess((data: any) => {
|
||||
thumbnail: thumbnailSchema,
|
||||
title: v.fallback(v.string(), ''),
|
||||
usage: usageSchema,
|
||||
version: z.string().catch('0.0.0'),
|
||||
version: v.fallback(v.string(), '0.0.0'),
|
||||
}).transform((instance) => {
|
||||
const version = fixVersion(instance.version);
|
||||
|
||||
|
||||
@ -2,11 +2,11 @@ import * as v from 'valibot';
|
||||
|
||||
import { coerceObject } from './utils';
|
||||
|
||||
const interactionPolicyEntrySchema = z.enum(['public', 'followers', 'following', 'mutuals', 'mentioned', 'author', 'me']);
|
||||
const interactionPolicyEntrySchema = v.picklist(['public', 'followers', 'following', 'mutuals', 'mentioned', 'author', 'me']);
|
||||
|
||||
const interactionPolicyRuleSchema = coerceObject({
|
||||
always: z.array(interactionPolicyEntrySchema).default(['public']),
|
||||
with_approval: z.array(interactionPolicyEntrySchema).default([]),
|
||||
always: v.fallback(v.array(interactionPolicyEntrySchema), ['public']),
|
||||
with_approval: v.fallback(v.array(interactionPolicyEntrySchema), []),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.gotosocial.org/en/latest/api/swagger/} */
|
||||
|
||||
@ -5,14 +5,14 @@ import { statusSchema } from './status';
|
||||
|
||||
/** @see {@link https://docs.gotosocial.org/en/latest/api/swagger.yaml#/definitions/interactionRequest} */
|
||||
const interactionRequestSchema = v.object({
|
||||
accepted_at: z.string().datetime().nullable().catch(null),
|
||||
accepted_at: v.fallback(v.nullable(z.string().datetime()), null),
|
||||
account: accountSchema,
|
||||
created_at: z.string().datetime(),
|
||||
id: v.string(),
|
||||
rejected_at: z.string().datetime().nullable().catch(null),
|
||||
rejected_at: v.fallback(v.nullable(z.string().datetime()), null),
|
||||
reply: v.fallback(v.nullable(statusSchema), null),
|
||||
status: v.fallback(v.nullable(statusSchema), null),
|
||||
type: z.enum(['favourite', 'reply', 'reblog']),
|
||||
type: v.picklist(['favourite', 'reply', 'reblog']),
|
||||
uri: v.fallback(v.nullable(v.string()), null),
|
||||
});
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import * as v from 'valibot';
|
||||
|
||||
const locationSchema = v.object({
|
||||
url: z.string().url().catch(''),
|
||||
url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
description: v.fallback(v.string(), ''),
|
||||
country: v.fallback(v.string(), ''),
|
||||
locality: v.fallback(v.string(), ''),
|
||||
@ -12,10 +12,10 @@ const locationSchema = v.object({
|
||||
origin_provider: v.fallback(v.string(), ''),
|
||||
type: v.fallback(v.string(), ''),
|
||||
timezone: v.fallback(v.string(), ''),
|
||||
geom: v.object({
|
||||
coordinates: z.tuple([z.number(), z.number()]).nullable().catch(null),
|
||||
geom: v.fallback(v.nullable(v.object({
|
||||
coordinates: v.fallback(v.nullable(z.tuple([v.number(), v.number()])), null),
|
||||
srid: v.fallback(v.string(), ''),
|
||||
}).nullable().catch(null),
|
||||
})), null),
|
||||
});
|
||||
|
||||
type Location = v.InferOutput<typeof locationSchema>;
|
||||
|
||||
@ -7,7 +7,7 @@ const markerSchema = z.preprocess((marker: any) => marker ? ({
|
||||
...marker,
|
||||
}) : null, v.object({
|
||||
last_read_id: v.string(),
|
||||
version: z.number().int(),
|
||||
version: v.pipe(v.number(), v.integer()),
|
||||
updated_at: dateSchema,
|
||||
unread_count: z.number().int().optional().catch(undefined),
|
||||
}));
|
||||
@ -15,7 +15,7 @@ const markerSchema = z.preprocess((marker: any) => marker ? ({
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Marker/} */
|
||||
type Marker = v.InferOutput<typeof markerSchema>;
|
||||
|
||||
const markersSchema = z.record(markerSchema);
|
||||
const markersSchema = v.record(v.string(), markerSchema);
|
||||
|
||||
type Markers = v.InferOutput<typeof markersSchema>;
|
||||
|
||||
|
||||
@ -17,9 +17,9 @@ const blurhashSchema = z.string().superRefine((value, ctx) => {
|
||||
const baseAttachmentSchema = v.object({
|
||||
id: v.string(),
|
||||
type: v.string(),
|
||||
url: z.string().url().catch(''),
|
||||
preview_url: z.string().url().catch(''),
|
||||
remote_url: z.string().url().nullable().catch(null),
|
||||
url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
preview_url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
remote_url: v.fallback(v.nullable(z.string().url()), null),
|
||||
description: v.fallback(v.string(), ''),
|
||||
blurhash: v.fallback(v.nullable(blurhashSchema), null),
|
||||
|
||||
@ -27,64 +27,64 @@ const baseAttachmentSchema = v.object({
|
||||
});
|
||||
|
||||
const imageMetaSchema = v.object({
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
width: v.number(),
|
||||
height: v.number(),
|
||||
size: z.string().regex(/\d+x\d+$/).nullable().catch(null),
|
||||
aspect: v.fallback(v.nullable(v.number()), null),
|
||||
});
|
||||
|
||||
const imageAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('image'),
|
||||
meta: v.object({
|
||||
original: imageMetaSchema.optional().catch(undefined),
|
||||
small: imageMetaSchema.optional().catch(undefined),
|
||||
focus: v.object({
|
||||
type: v.literal('image'),
|
||||
meta: v.fallback(v.object({
|
||||
original: v.fallback(v.optional(imageMetaSchema), undefined),
|
||||
small: v.fallback(v.optional(imageMetaSchema), undefined),
|
||||
focus: v.fallback(v.optional(v.object({
|
||||
x: z.number().min(-1).max(1),
|
||||
y: z.number().min(-1).max(1),
|
||||
}).optional().catch(undefined),
|
||||
}).catch({}),
|
||||
})), undefined),
|
||||
}), {}),
|
||||
});
|
||||
|
||||
const videoAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('video'),
|
||||
meta: v.object({
|
||||
duration: z.number().optional().catch(undefined),
|
||||
original: imageMetaSchema.extend({
|
||||
frame_rate: z.string().regex(/\d+\/\d+$/).nullable().catch(null),
|
||||
duration: z.number().nonnegative().nullable().catch(null),
|
||||
}).optional().catch(undefined),
|
||||
small: imageMetaSchema.optional().catch(undefined),
|
||||
type: v.literal('video'),
|
||||
meta: v.fallback(v.object({
|
||||
duration: v.fallback(v.optional(v.number()), undefined),
|
||||
original: v.fallback(v.optional(imageMetaSchema.extend({
|
||||
frame_rate: v.fallback(v.nullable(v.pipe(v.string(), v.regex(/\d+\/\d+$/))), null),
|
||||
duration: v.fallback(v.nullable(z.number().nonnegative()), null),
|
||||
})), undefined),
|
||||
small: v.fallback(v.optional(imageMetaSchema), undefined),
|
||||
// WIP: add rest
|
||||
}).catch({}),
|
||||
}), {}),
|
||||
});
|
||||
|
||||
const gifvAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('gifv'),
|
||||
meta: v.object({
|
||||
duration: z.number().optional().catch(undefined),
|
||||
original: imageMetaSchema.optional().catch(undefined),
|
||||
}).catch({}),
|
||||
type: v.literal('gifv'),
|
||||
meta: v.fallback(v.object({
|
||||
duration: v.fallback(v.optional(v.number()), undefined),
|
||||
original: v.fallback(v.optional(imageMetaSchema), undefined),
|
||||
}), {}),
|
||||
});
|
||||
|
||||
const audioAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('audio'),
|
||||
meta: v.object({
|
||||
duration: z.number().optional().catch(undefined),
|
||||
colors: v.object({
|
||||
type: v.literal('audio'),
|
||||
meta: v.fallback(v.object({
|
||||
duration: v.fallback(v.optional(v.number()), undefined),
|
||||
colors: v.fallback(v.optional(v.object({
|
||||
background: v.fallback(v.optional(v.string()), undefined),
|
||||
foreground: v.fallback(v.optional(v.string()), undefined),
|
||||
accent: v.fallback(v.optional(v.string()), undefined),
|
||||
duration: z.number().optional().catch(undefined),
|
||||
}).optional().catch(undefined),
|
||||
original: v.object({
|
||||
duration: z.number().optional().catch(undefined),
|
||||
duration: v.fallback(v.optional(v.number()), undefined),
|
||||
})), undefined),
|
||||
original: v.fallback(v.optional(v.object({
|
||||
duration: v.fallback(v.optional(v.number()), undefined),
|
||||
bitrate: z.number().nonnegative().optional().catch(undefined),
|
||||
}).optional().catch(undefined),
|
||||
}).catch({}),
|
||||
})), undefined),
|
||||
}), {}),
|
||||
});
|
||||
|
||||
const unknownAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('unknown'),
|
||||
type: v.literal('unknown'),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/MediaAttachment} */
|
||||
|
||||
@ -4,7 +4,7 @@ import * as v from 'valibot';
|
||||
const mentionSchema = v.object({
|
||||
id: v.string(),
|
||||
username: v.fallback(v.string(), ''),
|
||||
url: z.string().url().catch(''),
|
||||
url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
acct: v.string(),
|
||||
}).transform((mention) => {
|
||||
if (!mention.username) {
|
||||
|
||||
@ -7,8 +7,8 @@ const notificationPolicySchema = v.object({
|
||||
filter_new_accounts: v.boolean(),
|
||||
filter_private_mentions: v.boolean(),
|
||||
summary: v.object({
|
||||
pending_requests_count: z.number().int(),
|
||||
pending_notifications_count: z.number().int(),
|
||||
pending_requests_count: v.pipe(v.number(), v.integer()),
|
||||
pending_notifications_count: v.pipe(v.number(), v.integer()),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ const notificationRequestSchema = v.object({
|
||||
updated_at: dateSchema,
|
||||
account: accountSchema,
|
||||
notifications_count: z.coerce.string(),
|
||||
last_status: statusSchema.optional().catch(undefined),
|
||||
last_status: v.fallback(v.optional(statusSchema), undefined),
|
||||
});
|
||||
|
||||
type NotificationRequest = v.InferOutput<typeof notificationRequestSchema>;
|
||||
|
||||
@ -21,54 +21,54 @@ const baseNotificationSchema = v.object({
|
||||
});
|
||||
|
||||
const accountNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.enum(['follow', 'follow_request', 'admin.sign_up', 'bite']),
|
||||
type: v.picklist(['follow', 'follow_request', 'admin.sign_up', 'bite']),
|
||||
});
|
||||
|
||||
const mentionNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('mention'),
|
||||
subtype: z.enum(['reply']).nullable().catch(null),
|
||||
type: v.literal('mention'),
|
||||
subtype: v.fallback(v.nullable(v.picklist(['reply'])), null),
|
||||
status: statusSchema,
|
||||
});
|
||||
|
||||
const statusNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.enum(['status', 'reblog', 'favourite', 'poll', 'update', 'event_reminder']),
|
||||
type: v.picklist(['status', 'reblog', 'favourite', 'poll', 'update', 'event_reminder']),
|
||||
status: statusSchema,
|
||||
});
|
||||
|
||||
const reportNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('admin.report'),
|
||||
type: v.literal('admin.report'),
|
||||
report: reportSchema,
|
||||
});
|
||||
|
||||
const severedRelationshipNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('severed_relationships'),
|
||||
type: v.literal('severed_relationships'),
|
||||
relationship_severance_event: relationshipSeveranceEventSchema,
|
||||
});
|
||||
|
||||
const moderationWarningNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('moderation_warning'),
|
||||
type: v.literal('moderation_warning'),
|
||||
moderation_warning: accountWarningSchema,
|
||||
});
|
||||
|
||||
const moveNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('move'),
|
||||
type: v.literal('move'),
|
||||
target: accountSchema,
|
||||
});
|
||||
|
||||
const emojiReactionNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('emoji_reaction'),
|
||||
type: v.literal('emoji_reaction'),
|
||||
emoji: v.string(),
|
||||
emoji_url: v.fallback(v.nullable(v.string()), null),
|
||||
status: statusSchema,
|
||||
});
|
||||
|
||||
const chatMentionNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('chat_mention'),
|
||||
type: v.literal('chat_mention'),
|
||||
chat_message: chatMessageSchema,
|
||||
});
|
||||
|
||||
const eventParticipationRequestNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.enum(['participation_accepted', 'participation_request']),
|
||||
type: v.picklist(['participation_accepted', 'participation_request']),
|
||||
status: statusSchema,
|
||||
participation_message: v.fallback(v.nullable(v.string()), null),
|
||||
});
|
||||
|
||||
@ -6,7 +6,7 @@ const oauthTokenSchema = z.preprocess((token: any) => ({
|
||||
valid_until: token?.valid_until?.padEnd(27, 'Z'),
|
||||
}), v.object({
|
||||
app_name: v.string(),
|
||||
id: z.number(),
|
||||
id: v.number(),
|
||||
valid_until: z.string().datetime({ offset: true }),
|
||||
}));
|
||||
|
||||
|
||||
@ -7,20 +7,20 @@ const pollOptionSchema = v.object({
|
||||
title: v.fallback(v.string(), ''),
|
||||
votes_count: v.fallback(v.number(), 0),
|
||||
|
||||
title_map: z.record(v.string()).nullable().catch(null),
|
||||
title_map: v.record(v.string(), v.string()).nullable().catch(null),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Poll/} */
|
||||
const pollSchema = v.object({
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
expired: v.fallback(v.boolean(), false),
|
||||
expires_at: z.string().datetime().nullable().catch(null),
|
||||
expires_at: v.fallback(v.nullable(z.string().datetime()), null),
|
||||
id: v.string(),
|
||||
multiple: v.fallback(v.boolean(), false),
|
||||
options: z.array(pollOptionSchema).min(2),
|
||||
voters_count: v.fallback(v.number(), 0),
|
||||
votes_count: v.fallback(v.number(), 0),
|
||||
own_votes: z.array(z.number()).nonempty().nullable().catch(null),
|
||||
own_votes: v.fallback(v.nullable(z.number()).nonempty(), null),
|
||||
voted: v.fallback(v.boolean(), false),
|
||||
|
||||
non_anonymous: v.fallback(v.boolean(), false),
|
||||
|
||||
@ -3,19 +3,19 @@ import * as v from 'valibot';
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/PreviewCard/} */
|
||||
const previewCardSchema = v.object({
|
||||
author_name: v.fallback(v.string(), ''),
|
||||
author_url: z.string().url().catch(''),
|
||||
author_url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
blurhash: v.fallback(v.nullable(v.string()), null),
|
||||
description: v.fallback(v.string(), ''),
|
||||
embed_url: z.string().url().catch(''),
|
||||
embed_url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
height: v.fallback(v.number(), 0),
|
||||
html: v.fallback(v.string(), ''),
|
||||
image: v.fallback(v.nullable(v.string()), null),
|
||||
image_description: v.fallback(v.string(), ''),
|
||||
provider_name: v.fallback(v.string(), ''),
|
||||
provider_url: z.string().url().catch(''),
|
||||
provider_url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
title: v.fallback(v.string(), ''),
|
||||
type: z.enum(['link', 'photo', 'video', 'rich']).catch('link'),
|
||||
url: z.string().url(),
|
||||
type: v.fallback(v.picklist(['link', 'photo', 'video', 'rich']), 'link'),
|
||||
url: v.pipe(v.string(), v.url()),
|
||||
width: v.fallback(v.number(), 0),
|
||||
});
|
||||
|
||||
|
||||
@ -5,9 +5,9 @@ import { dateSchema } from './utils';
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/RelationshipSeveranceEvent/} */
|
||||
const relationshipSeveranceEventSchema = v.object({
|
||||
id: v.string(),
|
||||
type: z.enum(['domain_block', 'user_domain_block', 'account_suspension']),
|
||||
type: v.picklist(['domain_block', 'user_domain_block', 'account_suspension']),
|
||||
purged: v.string(),
|
||||
relationships_count: z.number().optional().catch(undefined),
|
||||
relationships_count: v.fallback(v.optional(v.number()), undefined),
|
||||
created_at: dateSchema,
|
||||
});
|
||||
|
||||
|
||||
@ -11,9 +11,9 @@ const reportSchema = v.object({
|
||||
category: v.fallback(v.optional(v.string()), undefined),
|
||||
comment: v.fallback(v.optional(v.string()), undefined),
|
||||
forwarded: v.fallback(v.optional(v.boolean()), undefined),
|
||||
created_at: dateSchema.optional().catch(undefined),
|
||||
status_ids: z.array(v.string()).nullable().catch(null),
|
||||
rule_ids: z.array(v.string()).nullable().catch(null),
|
||||
created_at: v.fallback(v.optional(dateSchema), undefined),
|
||||
status_ids: v.fallback(v.nullable(v.string()), null),
|
||||
rule_ids: v.fallback(v.nullable(v.string()), null),
|
||||
target_account: v.fallback(v.nullable(accountSchema), null),
|
||||
});
|
||||
|
||||
|
||||
@ -15,14 +15,14 @@ const scheduledStatusSchema = v.object({
|
||||
multiple: v.fallback(v.optional(v.boolean()), undefined),
|
||||
hide_totals: v.fallback(v.optional(v.boolean()), undefined),
|
||||
}).nullable().catch(null),
|
||||
media_ids: z.array(v.string()).nullable().catch(null),
|
||||
sensitive: z.coerce.boolean().nullable().catch(null),
|
||||
media_ids: v.fallback(v.nullable(v.string()), null),
|
||||
sensitive: v.fallback(v.nullable(z.coerce.boolean()), null),
|
||||
spoiler_text: v.fallback(v.nullable(v.string()), null),
|
||||
visibility: z.string().catch('public'),
|
||||
in_reply_to_id: v.fallback(v.nullable(v.string()), null),
|
||||
language: v.fallback(v.nullable(v.string()), null),
|
||||
application_id: z.number().int().nullable().catch(null),
|
||||
scheduled_at: z.string().datetime({ offset: true }).nullable().catch(null),
|
||||
application_id: v.fallback(v.nullable(z.number().int()), null),
|
||||
scheduled_at: v.fallback(v.nullable(z.string().datetime({ offset: true })), null),
|
||||
idempotency: v.fallback(v.nullable(v.string()), null),
|
||||
with_rate_limit: v.fallback(v.boolean(), false),
|
||||
|
||||
|
||||
@ -11,8 +11,8 @@ const statusSourceSchema = v.object({
|
||||
content_type: z.string().catch('text/plain'),
|
||||
location: v.fallback(v.nullable(locationSchema), null),
|
||||
|
||||
text_map: z.record(v.string()).nullable().catch(null),
|
||||
spoiler_text_map: z.record(v.string()).nullable().catch(null),
|
||||
text_map: v.record(v.string(), v.string()).nullable().catch(null),
|
||||
spoiler_text_map: v.record(v.string(), v.string()).nullable().catch(null),
|
||||
});
|
||||
|
||||
type StatusSource = v.InferOutput<typeof statusSourceSchema>;
|
||||
|
||||
@ -17,13 +17,13 @@ import { dateSchema, filteredArray } from './utils';
|
||||
|
||||
const statusEventSchema = v.object({
|
||||
name: v.fallback(v.string(), ''),
|
||||
start_time: z.string().datetime().nullable().catch(null),
|
||||
end_time: z.string().datetime().nullable().catch(null),
|
||||
join_mode: z.enum(['free', 'restricted', 'invite']).nullable().catch(null),
|
||||
start_time: v.fallback(v.nullable(z.string().datetime()), null),
|
||||
end_time: v.fallback(v.nullable(z.string().datetime()), null),
|
||||
join_mode: v.fallback(v.nullable(v.picklist(['free', 'restricted', 'invite'])), null),
|
||||
participants_count: v.fallback(v.number(), 0),
|
||||
location: v.object({
|
||||
location: v.fallback(v.nullable(v.object({
|
||||
name: v.fallback(v.string(), ''),
|
||||
url: z.string().url().catch(''),
|
||||
url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
latitude: v.fallback(v.number(), 0),
|
||||
longitude: v.fallback(v.number(), 0),
|
||||
street: v.fallback(v.string(), ''),
|
||||
@ -31,14 +31,14 @@ const statusEventSchema = v.object({
|
||||
locality: v.fallback(v.string(), ''),
|
||||
region: v.fallback(v.string(), ''),
|
||||
country: v.fallback(v.string(), ''),
|
||||
}).nullable().catch(null),
|
||||
join_state: z.enum(['pending', 'reject', 'accept']).nullable().catch(null),
|
||||
})), null),
|
||||
join_state: v.fallback(v.nullable(v.picklist(['pending', 'reject', 'accept'])), null),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Status/} */
|
||||
const baseStatusSchema = v.object({
|
||||
id: v.string(),
|
||||
uri: z.string().url().catch(''),
|
||||
uri: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
created_at: dateSchema,
|
||||
account: accountSchema,
|
||||
content: v.fallback(v.string(), ''),
|
||||
@ -46,55 +46,55 @@ const baseStatusSchema = v.object({
|
||||
sensitive: z.coerce.boolean(),
|
||||
spoiler_text: v.fallback(v.string(), ''),
|
||||
media_attachments: filteredArray(mediaAttachmentSchema),
|
||||
application: v.object({
|
||||
application: v.fallback(v.nullable(v.object({
|
||||
name: v.string(),
|
||||
website: z.string().url().nullable().catch(null),
|
||||
}).nullable().catch(null),
|
||||
website: v.fallback(v.nullable(z.string().url()), null),
|
||||
})), null),
|
||||
mentions: filteredArray(mentionSchema),
|
||||
tags: filteredArray(tagSchema),
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
reblogs_count: v.fallback(v.number(), 0),
|
||||
favourites_count: v.fallback(v.number(), 0),
|
||||
replies_count: v.fallback(v.number(), 0),
|
||||
url: z.string().url().catch(''),
|
||||
url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
in_reply_to_id: v.fallback(v.nullable(v.string()), null),
|
||||
in_reply_to_account_id: v.fallback(v.nullable(v.string()), null),
|
||||
poll: v.fallback(v.nullable(pollSchema), null),
|
||||
card: v.fallback(v.nullable(previewCardSchema), null),
|
||||
language: v.fallback(v.nullable(v.string()), null),
|
||||
text: v.fallback(v.nullable(v.string()), null),
|
||||
edited_at: z.string().datetime().nullable().catch(null),
|
||||
edited_at: v.fallback(v.nullable(z.string().datetime()), null),
|
||||
favourited: z.coerce.boolean(),
|
||||
reblogged: z.coerce.boolean(),
|
||||
muted: z.coerce.boolean(),
|
||||
bookmarked: z.coerce.boolean(),
|
||||
pinned: z.coerce.boolean(),
|
||||
filtered: filteredArray(filterResultSchema),
|
||||
approval_status: z.enum(['pending', 'approval', 'rejected']).nullable().catch(null),
|
||||
approval_status: v.fallback(v.nullable(v.picklist(['pending', 'approval', 'rejected'])), null),
|
||||
group: v.fallback(v.nullable(groupSchema), null),
|
||||
scheduled_at: z.null().catch(null),
|
||||
scheduled_at: v.fallback(v.null(), null),
|
||||
|
||||
quote_id: v.fallback(v.nullable(v.string()), null),
|
||||
local: v.fallback(v.optional(v.boolean()), undefined),
|
||||
conversation_id: v.fallback(v.optional(v.string()), undefined),
|
||||
direct_conversation_id: v.fallback(v.optional(v.string()), undefined),
|
||||
in_reply_to_account_acct: v.fallback(v.optional(v.string()), undefined),
|
||||
expires_at: z.string().datetime({ offset: true }).optional().catch(undefined),
|
||||
expires_at: v.fallback(v.optional(z.string().datetime({ offset: true })), undefined),
|
||||
thread_muted: v.fallback(v.optional(v.boolean()), undefined),
|
||||
emoji_reactions: filteredArray(emojiReactionSchema),
|
||||
parent_visible: v.fallback(v.optional(v.boolean()), undefined),
|
||||
pinned_at: z.string().datetime({ offset: true }).nullable().catch(null),
|
||||
pinned_at: v.fallback(v.nullable(z.string().datetime({ offset: true })), null),
|
||||
quote_visible: v.fallback(v.optional(v.boolean()), undefined),
|
||||
quote_url: v.fallback(v.optional(v.string()), undefined),
|
||||
quotes_count: v.fallback(v.number(), 0),
|
||||
bookmark_folder: v.fallback(v.nullable(v.string()), null),
|
||||
|
||||
event: v.fallback(v.nullable(statusEventSchema), null),
|
||||
translation: translationSchema.nullable().or(z.literal(false)).catch(null),
|
||||
translation: translationSchema.nullable().or(v.literal(false)).catch(null),
|
||||
|
||||
content_map: z.record(v.string()).nullable().catch(null),
|
||||
text_map: z.record(v.string()).nullable().catch(null),
|
||||
spoiler_text_map: z.record(v.string()).nullable().catch(null),
|
||||
content_map: v.fallback(v.nullable(v.record(v.string(), v.string())), null),
|
||||
text_map: v.fallback(v.nullable(v.record(v.string(), v.string())), null),
|
||||
spoiler_text_map: v.fallback(v.nullable(v.record(v.string(), v.string())), null),
|
||||
|
||||
dislikes_count: v.fallback(v.number(), 0),
|
||||
disliked: z.coerce.boolean().catch(false),
|
||||
@ -135,16 +135,16 @@ const preprocess = (status: any) => {
|
||||
};
|
||||
|
||||
const statusSchema: z.ZodType<Status> = z.preprocess(preprocess, baseStatusSchema.extend({
|
||||
reblog: z.lazy(() => statusSchema).nullable().catch(null),
|
||||
reblog: v.fallback(v.nullable(z.lazy(() => statusSchema)), null),
|
||||
|
||||
quote: z.lazy(() => statusSchema).nullable().catch(null),
|
||||
quote: v.fallback(v.nullable(z.lazy(() => statusSchema)), null),
|
||||
})) as any;
|
||||
|
||||
const statusWithoutAccountSchema = z.preprocess(preprocess, baseStatusSchema.omit({ account: true }).extend({
|
||||
account: v.fallback(v.nullable(accountSchema), null),
|
||||
reblog: z.lazy(() => statusSchema).nullable().catch(null),
|
||||
reblog: v.fallback(v.nullable(z.lazy(() => statusSchema)), null),
|
||||
|
||||
quote: z.lazy(() => statusSchema).nullable().catch(null),
|
||||
quote: v.fallback(v.nullable(z.lazy(() => statusSchema)), null),
|
||||
}));
|
||||
|
||||
type Status = v.InferOutput<typeof baseStatusSchema> & {
|
||||
|
||||
@ -9,7 +9,7 @@ import { notificationSchema } from './notification';
|
||||
import { statusSchema } from './status';
|
||||
|
||||
const followRelationshipUpdateSchema = v.object({
|
||||
state: z.enum(['follow_pending', 'follow_accept', 'follow_reject']),
|
||||
state: v.picklist(['follow_pending', 'follow_accept', 'follow_reject']),
|
||||
follower: v.object({
|
||||
id: v.string(),
|
||||
follower_count: v.fallback(v.nullable(v.number()), null),
|
||||
@ -29,59 +29,59 @@ const baseStreamingEventSchema = v.object({
|
||||
});
|
||||
|
||||
const statusStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.enum(['update', 'status.update']),
|
||||
event: v.picklist(['update', 'status.update']),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), statusSchema),
|
||||
});
|
||||
|
||||
const stringStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.enum(['delete', 'announcement.delete']),
|
||||
event: v.picklist(['delete', 'announcement.delete']),
|
||||
payload: v.string(),
|
||||
});
|
||||
|
||||
const notificationStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('notification'),
|
||||
event: v.literal('notification'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), notificationSchema),
|
||||
});
|
||||
|
||||
const emptyStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('filters_changed'),
|
||||
event: v.literal('filters_changed'),
|
||||
});
|
||||
|
||||
const conversationStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('conversation'),
|
||||
event: v.literal('conversation'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), conversationSchema),
|
||||
});
|
||||
|
||||
const announcementStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('announcement'),
|
||||
event: v.literal('announcement'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), announcementSchema),
|
||||
});
|
||||
|
||||
const announcementReactionStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('announcement.reaction'),
|
||||
event: v.literal('announcement.reaction'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), announcementReactionSchema),
|
||||
});
|
||||
|
||||
const chatUpdateStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('chat_update'),
|
||||
event: v.literal('chat_update'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), chatSchema),
|
||||
});
|
||||
|
||||
const followRelationshipsUpdateStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('follow_relationships_update'),
|
||||
event: v.literal('follow_relationships_update'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), followRelationshipUpdateSchema),
|
||||
});
|
||||
|
||||
const respondStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('respond'),
|
||||
event: v.literal('respond'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), v.object({
|
||||
type: v.string(),
|
||||
result: z.enum(['success', 'ignored', 'error']),
|
||||
result: v.picklist(['success', 'ignored', 'error']),
|
||||
})),
|
||||
});
|
||||
|
||||
const markerStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('marker'),
|
||||
event: v.literal('marker'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), markersSchema),
|
||||
});
|
||||
|
||||
|
||||
@ -9,8 +9,8 @@ const historySchema = v.object({
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/tag} */
|
||||
const tagSchema = v.object({
|
||||
name: z.string().min(1),
|
||||
url: z.string().url().catch(''),
|
||||
history: z.array(historySchema).nullable().catch(null),
|
||||
url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
history: v.fallback(v.nullable(historySchema), null),
|
||||
following: v.fallback(v.optional(v.boolean()), undefined),
|
||||
});
|
||||
|
||||
|
||||
@ -5,11 +5,11 @@ const tokenSchema = v.object({
|
||||
access_token: v.string(),
|
||||
token_type: v.string(),
|
||||
scope: v.string(),
|
||||
created_at: z.number().optional().catch(undefined),
|
||||
created_at: v.fallback(v.optional(v.number()), undefined),
|
||||
|
||||
id: z.number().optional().catch(undefined),
|
||||
id: v.fallback(v.optional(v.number()), undefined),
|
||||
refresh_token: v.fallback(v.optional(v.string()), undefined),
|
||||
expires_in: z.number().optional().catch(undefined),
|
||||
expires_in: v.fallback(v.optional(v.number()), undefined),
|
||||
me: v.fallback(v.optional(v.string()), undefined),
|
||||
});
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ const translationSchema = z.preprocess((translation: any) => {
|
||||
id: v.fallback(v.nullable(v.string()), null),
|
||||
content: v.fallback(v.string(), ''),
|
||||
spoiler_text: v.fallback(v.string(), ''),
|
||||
poll: translationPollSchema.optional().catch(undefined),
|
||||
poll: v.fallback(v.optional(translationPollSchema), undefined),
|
||||
media_attachments: filteredArray(translationMediaAttachment),
|
||||
detected_source_language: v.string(),
|
||||
provider: v.string(),
|
||||
|
||||
@ -6,10 +6,10 @@ import { historySchema } from './tag';
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/PreviewCard/#trends-link} */
|
||||
const trendsLinkSchema = z.preprocess((link: any) => ({ ...link, id: link.url }), v.object({
|
||||
id: v.fallback(v.string(), ''),
|
||||
url: z.string().url().catch(''),
|
||||
url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
||||
title: v.fallback(v.string(), ''),
|
||||
description: v.fallback(v.string(), ''),
|
||||
type: z.enum(['link', 'photo', 'video', 'rich']).catch('link'),
|
||||
type: v.fallback(v.picklist(['link', 'photo', 'video', 'rich']), 'link'),
|
||||
author_name: v.fallback(v.string(), ''),
|
||||
author_url: v.fallback(v.string(), ''),
|
||||
provider_name: v.fallback(v.string(), ''),
|
||||
@ -21,7 +21,7 @@ const trendsLinkSchema = z.preprocess((link: any) => ({ ...link, id: link.url })
|
||||
image_description: v.fallback(v.nullable(v.string()), null),
|
||||
embed_url: v.fallback(v.string(), ''),
|
||||
blurhash: v.fallback(v.nullable(blurhashSchema), null),
|
||||
history: z.array(historySchema).nullable().catch(null),
|
||||
history: v.fallback(v.nullable(historySchema), null),
|
||||
}));
|
||||
|
||||
type TrendsLink = v.InferOutput<typeof trendsLinkSchema>;
|
||||
|
||||
@ -14,13 +14,17 @@ const filteredArray = <T extends z.ZodTypeAny>(schema: T) =>
|
||||
));
|
||||
|
||||
/** Validates the string as an emoji. */
|
||||
const emojiSchema = z.string().refine((v) => /\p{Extended_Pictographic}|[\u{1F1E6}-\u{1F1FF}]{2}/u.test(v));
|
||||
const emojiSchema = v.pipe(v.string(), v.emoji());
|
||||
|
||||
/** MIME schema, eg `image/png`. */
|
||||
const mimeSchema = z.string().regex(/^\w+\/[-+.\w]+$/);
|
||||
const mimeSchema = v.pipe(v.string(), v.regex(/^\w+\/[-+.\w]+$/));
|
||||
|
||||
/** zod schema to force the value into an object, if it isn't already. */
|
||||
const coerceObject = <T extends z.ZodRawShape>(shape: T) =>
|
||||
v.object({}).passthrough().catch({}).pipe(z.object(shape));
|
||||
/** valibot schema to force the value into an object, if it isn't already. */
|
||||
const coerceObject = <T extends v.ObjectEntries>(shape: T) =>
|
||||
v.pipe(
|
||||
v.any(),
|
||||
v.transform((input) => typeof input === 'object' ? input : {}),
|
||||
v.object(shape),
|
||||
);
|
||||
|
||||
export { filteredArray, emojiSchema, dateSchema, mimeSchema, coerceObject };
|
||||
|
||||
@ -4,7 +4,7 @@ import * as v from 'valibot';
|
||||
const webPushSubscriptionSchema = v.object({
|
||||
id: z.coerce.string(),
|
||||
endpoint: v.string(),
|
||||
alerts: z.record(z.boolean()),
|
||||
alerts: v.record(v.string(), z.boolean()),
|
||||
server_key: v.string(),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user