pl-api: moar blind search and replace

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-10-14 22:50:34 +02:00
parent ea3addf388
commit 0bed543c20
32 changed files with 118 additions and 101 deletions

View file

@ -201,7 +201,7 @@ class PlApiClient {
baseURL: string;
#accessToken?: string;
#instance: Instance = instanceSchema.parse({});
#instance: Instance = v.parse(instanceSchema, {});
public request = request.bind(this) as typeof request;
public features: Features = getFeatures(this.#instance);
#socket?: {
@ -2714,9 +2714,9 @@ class PlApiClient {
return v.parse(v.array(v.object({
week: v.string(),
statuses: z.coerce.string(),
logins: z.coerce.string(),
registrations: z.coerce.string(),
statuses: v.pipe(v.unknown(), v.transform(String)),
logins: v.pipe(v.unknown(), v.transform(String)),
registrations: v.pipe(v.unknown(), v.transform(String)),
})), response.json);
},

View file

@ -7,7 +7,7 @@ import { roleSchema } from './role';
import { coerceObject, dateSchema, filteredArray } from './utils';
const filterBadges = (tags?: string[]) =>
tags?.filter(tag => tag.startsWith('badge:')).map(tag => roleSchema.parse({ id: tag, name: tag.replace(/^badge:/, '') }));
tags?.filter(tag => tag.startsWith('badge:')).map(tag => v.parse(roleSchema, { id: tag, name: tag.replace(/^badge:/, '') }));
const preprocessAccount = (account: any) => {
if (!account?.acct) return null;
@ -112,7 +112,7 @@ const baseAccountSchema = v.object({
deactivated: v.fallback(v.optional(v.boolean()), undefined),
location: v.fallback(v.optional(v.string()), undefined),
local: z.boolean().optional().catch(false),
local: v.fallback(v.optional(v.boolean()), false),
avatar_description: v.fallback(v.string(), ''),
enable_rss: v.fallback(v.boolean(), false),
@ -142,7 +142,7 @@ type Account = v.InferOutput<typeof accountWithMovedAccountSchema> & WithMoved;
const accountSchema: z.ZodType<Account> = untypedAccountSchema as any;
const untypedCredentialAccountSchema = z.preprocess(preprocessAccount, accountWithMovedAccountSchema.extend({
source: v.object({
source: v.fallback(v.nullable(v.object({
note: v.fallback(v.string(), ''),
fields: filteredArray(fieldSchema),
privacy: v.picklist(['public', 'unlisted', 'private', 'direct']),
@ -150,15 +150,15 @@ const untypedCredentialAccountSchema = z.preprocess(preprocessAccount, accountWi
language: v.fallback(v.nullable(v.string()), null),
follow_requests_count: z.number().int().nonnegative().catch(0),
show_role: z.boolean().optional().nullable().catch(undefined),
no_rich_text: z.boolean().optional().nullable().catch(undefined),
show_role: v.fallback(v.nullable(v.optional(v.boolean())), undefined),
no_rich_text: v.fallback(v.nullable(v.optional(v.boolean())), undefined),
discoverable: v.fallback(v.optional(v.boolean()), undefined),
actor_type: v.fallback(v.optional(v.string()), undefined),
show_birthday: v.fallback(v.optional(v.boolean()), undefined),
}).nullable().catch(null),
})), null),
role: v.fallback(v.nullable(roleSchema), null),
settings_store: v.record(v.string(), v.any()).optional().catch(undefined),
settings_store: v.fallback(v.optional(v.record(v.string(), v.any())), undefined),
chat_token: v.fallback(v.optional(v.string()), undefined),
allow_following_move: v.fallback(v.optional(v.boolean()), undefined),
unread_conversation_count: v.fallback(v.optional(v.number()), undefined),

View file

@ -22,9 +22,9 @@ const adminAccountSchema = z.preprocess((account: any) => {
email: account.email,
invite_request: account.registration_reason,
role: account.roles?.is_admin
? roleSchema.parse({ name: 'Admin' })
? v.parse(roleSchema, { name: 'Admin' })
: account.roles?.moderator
? roleSchema.parse({ name: 'Moderator ' }) :
? v.parse(roleSchema, { name: 'Moderator ' }) :
null,
confirmed: account.is_confirmed,
approved: account.is_approved,

View file

@ -4,7 +4,7 @@ import * as v from 'valibot';
const adminCohortSchema = v.object({
period: z.string().datetime({ offset: true }),
frequency: v.picklist(['day', 'month']),
data: z.array(v.object({
data: v.array(v.object({
date: z.string().datetime({ offset: true }),
rate: v.number(),
value: v.pipe(v.number(), v.integer()),

View file

@ -2,7 +2,7 @@ import * as v from 'valibot';
const adminDomainSchema = v.object({
domain: v.fallback(v.string(), ''),
id: z.coerce.string(),
id: v.pipe(v.unknown(), v.transform(String)),
public: v.fallback(v.boolean(), false),
resolves: v.fallback(v.boolean(), false),
last_checked_at: z.string().datetime().catch(''),

View file

@ -8,9 +8,9 @@ const adminEmailDomainBlockSchema = v.object({
domain: v.string(),
created_at: dateSchema,
history: v.array(v.object({
day: z.coerce.string(),
accounts: z.coerce.string(),
uses: z.coerce.string(),
day: v.pipe(v.unknown(), v.transform(String)),
accounts: v.pipe(v.unknown(), v.transform(String)),
uses: v.pipe(v.unknown(), v.transform(String)),
})),
});

View file

@ -4,12 +4,12 @@ import * as v from 'valibot';
const adminMeasureSchema = v.object({
key: v.string(),
unit: v.fallback(v.nullable(v.string()), null),
total: z.coerce.number(),
total: v.pipe(v.unknown(), v.transform(Number)),
human_value: v.fallback(v.optional(v.string()), undefined),
previous_total: z.coerce.string().optional().catch(undefined),
data: z.array(v.object({
previous_total: v.fallback(v.optional(v.pipe(v.unknown(), v.transform(String))), undefined),
data: v.array(v.object({
date: z.string().datetime({ offset: true }),
value: z.coerce.string(),
value: v.pipe(v.unknown(), v.transform(String)),
})),
});

View file

@ -2,7 +2,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(),
id: v.pipe(v.unknown(), v.transform(String)),
data: v.fallback(v.record(v.string(), v.any()), {}),
time: v.fallback(v.number(), 0),
message: v.fallback(v.string(), ''),

View file

@ -4,7 +4,7 @@ import { dateSchema, mimeSchema } from './utils';
/** @see {@link https://docs.pleroma.social/backend/development/API/pleroma_api/#post-apiv1pleromabackups} */
const backupSchema = v.object({
id: z.coerce.string(),
id: v.pipe(v.unknown(), v.transform(String)),
contentType: mimeSchema,
file_size: v.fallback(v.number(), 0),
inserted_at: dateSchema,

View file

@ -1,7 +1,7 @@
import * as v from 'valibot';
const bookmarkFolderSchema = v.object({
id: z.coerce.string(),
id: v.pipe(v.unknown(), v.transform(String)),
name: v.fallback(v.string(), ''),
emoji: v.fallback(v.nullable(v.string()), null),
emoji_url: v.fallback(v.nullable(v.string()), null),

View file

@ -4,8 +4,8 @@ import { statusSchema } from './status';
/** @see {@link https://docs.joinmastodon.org/entities/Context/} */
const contextSchema = v.object({
ancestors: z.array(statusSchema),
descendants: z.array(statusSchema),
ancestors: v.array(statusSchema),
descendants: v.array(statusSchema),
});
type Context = v.InferOutput<typeof contextSchema>;

View file

@ -2,7 +2,7 @@ import * as v from 'valibot';
const directoryCategorySchema = v.object({
category: v.string(),
servers_count: v.fallback(v.nullable(z.coerce.number()), null),
servers_count: v.fallback(v.nullable(v.pipe(v.unknown(), v.transform(Number))), null),
});
type DirectoryCategory = v.InferOutput<typeof directoryCategorySchema>;

View file

@ -3,7 +3,7 @@ import * as v from 'valibot';
const directoryLanguageSchema = v.object({
locale: v.string(),
language: v.string(),
servers_count: v.fallback(v.nullable(z.coerce.number()), null),
servers_count: v.fallback(v.nullable(v.pipe(v.unknown(), v.transform(Number))), null),
});
type DirectoryLanguage = v.InferOutput<typeof directoryLanguageSchema>;

View file

@ -4,13 +4,13 @@ const directoryServerSchema = v.object({
domain: v.string(),
version: v.string(),
description: v.string(),
languages: z.array(v.string()),
languages: v.array(v.string()),
region: v.string(),
categories: z.array(v.string()),
proxied_thumbnail: v.fallback(v.nullable(z.string().url()), null),
categories: v.array(v.string()),
proxied_thumbnail: v.fallback(v.nullable(v.pipe(v.string(), v.url())), null),
blurhash: v.fallback(v.nullable(v.string()), null),
total_users: z.coerce.number(),
last_week_users: z.coerce.number(),
total_users: v.pipe(v.unknown(), v.transform(Number)),
last_week_users: v.pipe(v.unknown(), v.transform(Number)),
approval_required: v.boolean(),
language: v.string(),
category: v.string(),

View file

@ -2,9 +2,9 @@ import * as v from 'valibot';
const directoryStatisticsPeriodSchema = v.object({
period: z.string().date(),
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),
server_count: v.fallback(v.nullable(v.pipe(v.unknown(), v.transform(Number))), null),
user_count: v.fallback(v.nullable(v.pipe(v.unknown(), v.transform(Number))), null),
active_user_count: v.fallback(v.nullable(v.pipe(v.unknown(), v.transform(Number))), null),
});
type DirectoryStatisticsPeriod = v.InferOutput<typeof directoryStatisticsPeriodSchema>;

View file

@ -10,10 +10,11 @@ const baseEmojiReactionSchema = v.object({
url: v.fallback(v.undefined(), undefined),
static_url: v.fallback(v.undefined(), undefined),
accounts: filteredArray(accountSchema),
account_ids: filteredArray(v.string()).catch([]),
account_ids: v.fallback(filteredArray(v.string()), []),
});
const customEmojiReactionSchema = baseEmojiReactionSchema.extend({
const customEmojiReactionSchema = v.object({
...baseEmojiReactionSchema.entries,
name: v.string(),
url: v.pipe(v.string(), v.url()),
static_url: v.pipe(v.string(), v.url()),
@ -27,7 +28,7 @@ const emojiReactionSchema = z.preprocess((reaction: any) => reaction ? {
static_url: reaction.url,
account_ids: reaction.accounts?.map((account: any) => account?.id),
...reaction,
} : null, baseEmojiReactionSchema.or(customEmojiReactionSchema));
} : null, v.union([baseEmojiReactionSchema, customEmojiReactionSchema]);
type EmojiReaction = v.InferOutput<typeof emojiReactionSchema>;

View file

@ -13,11 +13,11 @@ const groupSchema = v.object({
emojis: filteredArray(customEmojiSchema),
header: v.fallback(v.string(), ''),
header_static: v.fallback(v.string(), ''),
id: z.coerce.string(),
id: v.pipe(v.unknown(), v.transform(String)),
locked: v.fallback(v.boolean(), false),
membership_required: v.fallback(v.boolean(), false),
members_count: v.fallback(v.number(), 0),
owner: v.object({ id: v.string() }).nullable().catch(null),
owner: v.fallback(v.nullable(v.object({ id: v.string() })), 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: v.fallback(v.string(), 'public'),

View file

@ -36,7 +36,7 @@ const instanceV1ToV2 = (data: any) => {
uri,
urls,
...instance
} = instanceV1Schema.parse(data);
} = v.parse(instanceV1Schema, data);
return {
...instance,
@ -196,14 +196,14 @@ const pleromaSchema = coerceObject({
multitenancy: coerceObject({
domains: v.optional(v.array(
v.object({
domain: z.coerce.string(),
domain: v.pipe(v.unknown(), v.transform(String)),
id: v.string(),
public: v.fallback(v.boolean(), false),
}),
)),
enabled: v.fallback(v.boolean(), false),
}),
post_formats: z.string().array().optional().catch(undefined),
post_formats: v.fallback(v.optional(v.array(v.string())), undefined),
restrict_unauthenticated: coerceObject({
activities: coerceObject({
local: v.fallback(v.boolean(), false),
@ -222,8 +222,8 @@ const pleromaSchema = coerceObject({
translation: coerceObject({
allow_remote: v.fallback(v.boolean(), true),
allow_unauthenticated: v.fallback(v.boolean(), false),
source_languages: z.string().array().optional().catch(undefined),
target_languages: z.string().array().optional().catch(undefined),
source_languages: v.fallback(v.optional(v.array(v.string())), undefined),
target_languages: v.fallback(v.optional(v.array(v.string())), undefined),
}),
}),
oauth_consumer_strategies: v.fallback(v.array(v.string()), []),

View file

@ -2,7 +2,7 @@ import * as v from 'valibot';
/** @see {@link https://docs.joinmastodon.org/entities/List/} */
const listSchema = v.object({
id: z.coerce.string(),
id: v.pipe(v.unknown(), v.transform(String)),
title: v.string(),
replies_policy: v.fallback(v.optional(v.string()), undefined),
exclusive: v.fallback(v.optional(v.boolean()), undefined),

View file

@ -9,7 +9,7 @@ const markerSchema = z.preprocess((marker: any) => marker ? ({
last_read_id: v.string(),
version: v.pipe(v.number(), v.integer()),
updated_at: dateSchema,
unread_count: z.number().int().optional().catch(undefined),
unread_count: v.fallback(v.optional(v.pipe(v.number(), v.integer())), undefined),
}));
/** @see {@link https://docs.joinmastodon.org/entities/Marker/} */

View file

@ -19,7 +19,7 @@ const baseAttachmentSchema = v.object({
type: v.string(),
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),
remote_url: v.fallback(v.nullable(v.pipe(v.string(), v.url())), null),
description: v.fallback(v.string(), ''),
blurhash: v.fallback(v.nullable(blurhashSchema), null),
@ -29,11 +29,12 @@ const baseAttachmentSchema = v.object({
const imageMetaSchema = v.object({
width: v.number(),
height: v.number(),
size: z.string().regex(/\d+x\d+$/).nullable().catch(null),
size: v.fallback(v.nullable(v.pipe(v.string(), v.regex(/\d+x\d+$/))), null),
aspect: v.fallback(v.nullable(v.number()), null),
});
const imageAttachmentSchema = baseAttachmentSchema.extend({
const imageAttachmentSchema = v.object({
...baseAttachmentSchema.entries,
type: v.literal('image'),
meta: v.fallback(v.object({
original: v.fallback(v.optional(imageMetaSchema), undefined),
@ -45,7 +46,8 @@ const imageAttachmentSchema = baseAttachmentSchema.extend({
}), {}),
});
const videoAttachmentSchema = baseAttachmentSchema.extend({
const videoAttachmentSchema = v.object({
...baseAttachmentSchema.entries,
type: v.literal('video'),
meta: v.fallback(v.object({
duration: v.fallback(v.optional(v.number()), undefined),
@ -58,7 +60,8 @@ const videoAttachmentSchema = baseAttachmentSchema.extend({
}), {}),
});
const gifvAttachmentSchema = baseAttachmentSchema.extend({
const gifvAttachmentSchema = v.object({
...baseAttachmentSchema.entries,
type: v.literal('gifv'),
meta: v.fallback(v.object({
duration: v.fallback(v.optional(v.number()), undefined),
@ -66,7 +69,8 @@ const gifvAttachmentSchema = baseAttachmentSchema.extend({
}), {}),
});
const audioAttachmentSchema = baseAttachmentSchema.extend({
const audioAttachmentSchema = v.object({
...baseAttachmentSchema.entries,
type: v.literal('audio'),
meta: v.fallback(v.object({
duration: v.fallback(v.optional(v.number()), undefined),
@ -83,7 +87,8 @@ const audioAttachmentSchema = baseAttachmentSchema.extend({
}), {}),
});
const unknownAttachmentSchema = baseAttachmentSchema.extend({
const unknownAttachmentSchema = v.object({
...baseAttachmentSchema.entries,
type: v.literal('unknown'),
});
@ -96,7 +101,7 @@ const mediaAttachmentSchema = z.preprocess((data: any) => {
preview_url: data.url,
...data,
};
}, z.discriminatedUnion('type', [
}, v.variant('type', [
imageAttachmentSchema,
videoAttachmentSchema,
gifvAttachmentSchema,

View file

@ -10,7 +10,7 @@ const notificationRequestSchema = v.object({
created_at: dateSchema,
updated_at: dateSchema,
account: accountSchema,
notifications_count: z.coerce.string(),
notifications_count: v.pipe(v.unknown(), v.transform(String)),
last_status: v.fallback(v.optional(statusSchema), undefined),
});

View file

@ -17,10 +17,10 @@ const pollSchema = v.object({
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),
options: v.array(pollOptionSchema).min(2),
voters_count: v.fallback(v.number(), 0),
votes_count: v.fallback(v.number(), 0),
own_votes: v.fallback(v.nullable(z.number()).nonempty(), null),
own_votes: v.fallback(v.nullable(v.array(v.number())).nonempty(), null),
voted: v.fallback(v.boolean(), false),
non_anonymous: v.fallback(v.boolean(), false),

View file

@ -9,19 +9,19 @@ const scheduledStatusSchema = v.object({
scheduled_at: z.string().datetime({ offset: true }),
params: v.object({
text: v.fallback(v.nullable(v.string()), null),
poll: v.object({
options: z.array(v.string()),
expires_in: z.coerce.string(),
poll: v.fallback(v.nullable(v.object({
options: v.array(v.string()),
expires_in: v.pipe(v.unknown(), v.transform(String)),
multiple: v.fallback(v.optional(v.boolean()), undefined),
hide_totals: v.fallback(v.optional(v.boolean()), undefined),
}).nullable().catch(null),
})), null),
media_ids: v.fallback(v.nullable(v.string()), null),
sensitive: v.fallback(v.nullable(z.coerce.boolean()), null),
sensitive: v.fallback(v.nullable(v.pipe(v.unknown(), v.transform(Boolean))), null),
spoiler_text: v.fallback(v.nullable(v.string()), null),
visibility: z.string().catch('public'),
visibility: v.fallback(v.string(), 'public'),
in_reply_to_id: v.fallback(v.nullable(v.string()), null),
language: v.fallback(v.nullable(v.string()), null),
application_id: v.fallback(v.nullable(z.number().int()), null),
application_id: v.fallback(v.nullable(v.pipe(v.number(), v.integer())), 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),

View file

@ -6,7 +6,7 @@ const scrobbleSchema = z.preprocess((scrobble: any) => scrobble ? {
external_link: scrobble.externalLink,
...scrobble,
} : null, v.object({
id: z.coerce.string(),
id: v.pipe(v.unknown(), v.transform(String)),
account: accountSchema,
created_at: z.string().datetime({ offset: true }),
title: v.string(),

View file

@ -9,14 +9,14 @@ import { dateSchema, filteredArray } from './utils';
const statusEditSchema = v.object({
content: v.fallback(v.string(), ''),
spoiler_text: v.fallback(v.string(), ''),
sensitive: z.coerce.boolean(),
sensitive: v.pipe(v.unknown(), v.transform(Boolean)),
created_at: dateSchema,
account: accountSchema,
poll: v.object({
options: z.array(v.object({
poll: v.fallback(v.nullable(v.object({
options: v.array(v.object({
title: v.string(),
})),
}).nullable().catch(null),
})), null),
media_attachments: filteredArray(mediaAttachmentSchema),
emojis: filteredArray(customEmojiSchema),
});

View file

@ -42,13 +42,13 @@ const baseStatusSchema = v.object({
created_at: dateSchema,
account: accountSchema,
content: v.fallback(v.string(), ''),
visibility: z.string().catch('public'),
sensitive: z.coerce.boolean(),
visibility: v.fallback(v.string(), 'public'),
sensitive: v.pipe(v.unknown(), v.transform(Boolean)),
spoiler_text: v.fallback(v.string(), ''),
media_attachments: filteredArray(mediaAttachmentSchema),
application: v.fallback(v.nullable(v.object({
name: v.string(),
website: v.fallback(v.nullable(z.string().url()), null),
website: v.fallback(v.nullable(v.pipe(v.string(), v.url())), null),
})), null),
mentions: filteredArray(mentionSchema),
tags: filteredArray(tagSchema),
@ -64,11 +64,11 @@ const baseStatusSchema = v.object({
language: v.fallback(v.nullable(v.string()), null),
text: v.fallback(v.nullable(v.string()), 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(),
favourited: v.pipe(v.unknown(), v.transform(Boolean)),
reblogged: v.pipe(v.unknown(), v.transform(Boolean)),
muted: v.pipe(v.unknown(), v.transform(Boolean)),
bookmarked: v.pipe(v.unknown(), v.transform(Boolean)),
pinned: v.pipe(v.unknown(), v.transform(Boolean)),
filtered: filteredArray(filterResultSchema),
approval_status: v.fallback(v.nullable(v.picklist(['pending', 'approval', 'rejected'])), null),
group: v.fallback(v.nullable(groupSchema), null),
@ -97,7 +97,7 @@ const baseStatusSchema = v.object({
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),
disliked: v.fallback(v.pipe(v.unknown(), v.transform(Boolean)), false),
interaction_policy: interactionPolicySchema,
});

View file

@ -25,54 +25,64 @@ const followRelationshipUpdateSchema = v.object({
type FollowRelationshipUpdate = v.InferOutput<typeof followRelationshipUpdateSchema>;
const baseStreamingEventSchema = v.object({
stream: z.array(v.string()).catch([]),
stream: v.fallback(v.array(v.string()), []),
});
const statusStreamingEventSchema = baseStreamingEventSchema.extend({
const statusStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.picklist(['update', 'status.update']),
payload: z.preprocess((payload: any) => JSON.parse(payload), statusSchema),
});
const stringStreamingEventSchema = baseStreamingEventSchema.extend({
const stringStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.picklist(['delete', 'announcement.delete']),
payload: v.string(),
});
const notificationStreamingEventSchema = baseStreamingEventSchema.extend({
const notificationStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('notification'),
payload: z.preprocess((payload: any) => JSON.parse(payload), notificationSchema),
});
const emptyStreamingEventSchema = baseStreamingEventSchema.extend({
const emptyStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('filters_changed'),
});
const conversationStreamingEventSchema = baseStreamingEventSchema.extend({
const conversationStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('conversation'),
payload: z.preprocess((payload: any) => JSON.parse(payload), conversationSchema),
});
const announcementStreamingEventSchema = baseStreamingEventSchema.extend({
const announcementStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('announcement'),
payload: z.preprocess((payload: any) => JSON.parse(payload), announcementSchema),
});
const announcementReactionStreamingEventSchema = baseStreamingEventSchema.extend({
const announcementReactionStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('announcement.reaction'),
payload: z.preprocess((payload: any) => JSON.parse(payload), announcementReactionSchema),
});
const chatUpdateStreamingEventSchema = baseStreamingEventSchema.extend({
const chatUpdateStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('chat_update'),
payload: z.preprocess((payload: any) => JSON.parse(payload), chatSchema),
});
const followRelationshipsUpdateStreamingEventSchema = baseStreamingEventSchema.extend({
const followRelationshipsUpdateStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('follow_relationships_update'),
payload: z.preprocess((payload: any) => JSON.parse(payload), followRelationshipUpdateSchema),
});
const respondStreamingEventSchema = baseStreamingEventSchema.extend({
const respondStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('respond'),
payload: z.preprocess((payload: any) => JSON.parse(payload), v.object({
type: v.string(),
@ -80,7 +90,8 @@ const respondStreamingEventSchema = baseStreamingEventSchema.extend({
})),
});
const markerStreamingEventSchema = baseStreamingEventSchema.extend({
const markerStreamingEventSchema = v.object({
...baseStreamingEventSchema.entries,
event: v.literal('marker'),
payload: z.preprocess((payload: any) => JSON.parse(payload), markersSchema),
});
@ -89,7 +100,7 @@ const markerStreamingEventSchema = baseStreamingEventSchema.extend({
const streamingEventSchema: z.ZodType<StreamingEvent> = z.preprocess((event: any) => ({
...event,
event: event.event?.replace(/^pleroma:/, ''),
}), z.discriminatedUnion('event', [
}), v.variant('event', [
statusStreamingEventSchema,
stringStreamingEventSchema,
notificationStreamingEventSchema,

View file

@ -31,7 +31,7 @@ const suggestionSchema = z.preprocess((suggestion: any) => {
return suggestion;
}, v.object({
source: v.fallback(v.nullable(v.string()), null),
sources: z.array(v.string()).catch([]),
sources: v.fallback(v.array(v.string()), []),
account: accountSchema,
}));

View file

@ -1,9 +1,9 @@
import * as v from 'valibot';
const historySchema = v.object({
day: z.coerce.number(),
accounts: z.coerce.number(),
uses: z.coerce.number(),
day: v.pipe(v.unknown(), v.transform(Number)),
accounts: v.pipe(v.unknown(), v.transform(Number)),
uses: v.pipe(v.unknown(), v.transform(Number)),
});
/** @see {@link https://docs.joinmastodon.org/entities/tag} */

View file

@ -4,7 +4,7 @@ import { filteredArray } from './utils';
const translationPollSchema = v.object({
id: v.string(),
options: z.array(v.object({
options: v.array(v.object({
title: v.string(),
})),
});

View file

@ -2,9 +2,9 @@ import * as v from 'valibot';
/** @see {@link https://docs.joinmastodon.org/entities/WebPushSubscription/} */
const webPushSubscriptionSchema = v.object({
id: z.coerce.string(),
id: v.pipe(v.unknown(), v.transform(String)),
endpoint: v.string(),
alerts: v.record(v.string(), z.boolean()),
alerts: v.record(v.string(), v.boolean()),
server_key: v.string(),
});