Add pl-api to workspace
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
966b04fdf0
commit
036fa32cd3
114 changed files with 11923 additions and 1 deletions
|
@ -7,6 +7,6 @@
|
|||
"husky": "^9.0.0",
|
||||
"lint-staged": ">=10"
|
||||
},
|
||||
"workspaces": ["pl-fe"],
|
||||
"workspaces": ["pl-api", "pl-fe"],
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
|
7
packages/pl-api/.eslintignore
Normal file
7
packages/pl-api/.eslintignore
Normal file
|
@ -0,0 +1,7 @@
|
|||
/node_modules/**
|
||||
/dist/**
|
||||
/static/**
|
||||
/public/**
|
||||
/tmp/**
|
||||
/coverage/**
|
||||
/custom/**
|
214
packages/pl-api/.eslintrc.json
Normal file
214
packages/pl-api/.eslintrc.json
Normal file
|
@ -0,0 +1,214 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:import/typescript",
|
||||
"plugin:compat/recommended"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest": true
|
||||
},
|
||||
"globals": {
|
||||
"ATTACHMENT_HOST": false
|
||||
},
|
||||
"plugins": [
|
||||
"import",
|
||||
"promise",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
},
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"settings": {
|
||||
"import/extensions": [
|
||||
".js",
|
||||
".cjs",
|
||||
".mjs",
|
||||
".ts"
|
||||
],
|
||||
"import/ignore": [
|
||||
"node_modules",
|
||||
"\\.(css|scss|json)$"
|
||||
],
|
||||
"import/resolver": {
|
||||
"typescript": true,
|
||||
"node": true
|
||||
},
|
||||
"polyfills": [
|
||||
"es:all",
|
||||
"fetch",
|
||||
"IntersectionObserver",
|
||||
"Promise",
|
||||
"ResizeObserver",
|
||||
"URL",
|
||||
"URLSearchParams"
|
||||
],
|
||||
"tailwindcss": {
|
||||
"config": "tailwind.config.ts"
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"brace-style": "error",
|
||||
"comma-dangle": [
|
||||
"error",
|
||||
"always-multiline"
|
||||
],
|
||||
"comma-spacing": [
|
||||
"warn",
|
||||
{
|
||||
"before": false,
|
||||
"after": true
|
||||
}
|
||||
],
|
||||
"comma-style": [
|
||||
"warn",
|
||||
"last"
|
||||
],
|
||||
"import/no-duplicates": "error",
|
||||
"space-before-function-paren": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"space-infix-ops": "error",
|
||||
"space-in-parens": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"keyword-spacing": "error",
|
||||
"dot-notation": "error",
|
||||
"eqeqeq": "error",
|
||||
"indent": [
|
||||
"error",
|
||||
2,
|
||||
{
|
||||
"SwitchCase": 1,
|
||||
"ignoredNodes": [
|
||||
"TemplateLiteral"
|
||||
]
|
||||
}
|
||||
],
|
||||
"key-spacing": [
|
||||
"error",
|
||||
{
|
||||
"mode": "minimum"
|
||||
}
|
||||
],
|
||||
"no-catch-shadow": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-console": [
|
||||
"warn",
|
||||
{
|
||||
"allow": [
|
||||
"error",
|
||||
"warn"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-extra-semi": "error",
|
||||
"no-const-assign": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-loop-func": "error",
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"no-nested-ternary": "warn",
|
||||
"no-trailing-spaces": "warn",
|
||||
"no-undef": "error",
|
||||
"no-unreachable": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"vars": "all",
|
||||
"args": "none",
|
||||
"ignoreRestSiblings": true
|
||||
}
|
||||
],
|
||||
"no-useless-escape": "warn",
|
||||
"no-var": "error",
|
||||
"object-curly-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"padded-blocks": [
|
||||
"error",
|
||||
{
|
||||
"classes": "always"
|
||||
}
|
||||
],
|
||||
"prefer-const": "error",
|
||||
"quotes": [
|
||||
"error",
|
||||
"single"
|
||||
],
|
||||
"semi": "error",
|
||||
"space-unary-ops": [
|
||||
"error",
|
||||
{
|
||||
"words": true,
|
||||
"nonwords": false
|
||||
}
|
||||
],
|
||||
"strict": "off",
|
||||
"valid-typeof": "error",
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"js": "never",
|
||||
"mjs": "ignorePackages",
|
||||
"ts": "never"
|
||||
}
|
||||
],
|
||||
"import/newline-after-import": "error",
|
||||
"import/no-extraneous-dependencies": "error",
|
||||
"import/no-unresolved": "error",
|
||||
"import/no-webpack-loader-syntax": "error",
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
"builtin",
|
||||
"external",
|
||||
"internal",
|
||||
"parent",
|
||||
"sibling",
|
||||
"index",
|
||||
"object",
|
||||
"type"
|
||||
],
|
||||
"newlines-between": "always",
|
||||
"alphabetize": {
|
||||
"order": "asc"
|
||||
}
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/member-delimiter-style": "error",
|
||||
"promise/catch-or-return": "error",
|
||||
"sort-imports": [
|
||||
"error",
|
||||
{
|
||||
"ignoreCase": true,
|
||||
"ignoreDeclarationSort": true
|
||||
}
|
||||
],
|
||||
"eol-last": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.ts"],
|
||||
"rules": {
|
||||
"no-undef": "off",
|
||||
"space-before-function-paren": "off"
|
||||
},
|
||||
"parser": "@typescript-eslint/parser"
|
||||
}
|
||||
]
|
||||
}
|
24
packages/pl-api/.gitignore
vendored
Normal file
24
packages/pl-api/.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
24
packages/pl-api/README.md
Normal file
24
packages/pl-api/README.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
# `pl-api`
|
||||
|
||||
This project should be considered unstable before the 1.0.0 release. I will not provide any changelog or information on breaking changes until then.
|
||||
|
||||
## Projects using `pl-api`
|
||||
|
||||
[`pl-fe`](https://github.com/mkljczk/pl-fe) is a web client for Mastodon-compatible servers forked from Soapbox. It uses `pl-api` for API interactions.
|
||||
|
||||
## License
|
||||
|
||||
`pl-api` utilizes code from [Soapbox](https://gitlab.com/soapbox-pub/soapbox) and bases off official [Mastodon documentation](https://docs.joinmastodon.org).
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
16
packages/pl-api/index.html
Normal file
16
packages/pl-api/index.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>pl-api</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="/lib/main.ts"></script>
|
||||
<script type="module">
|
||||
import PlApiClient from './lib/client.ts';
|
||||
|
||||
window.client = PlApiClient;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
3990
packages/pl-api/lib/client.ts
Normal file
3990
packages/pl-api/lib/client.ts
Normal file
File diff suppressed because it is too large
Load diff
27
packages/pl-api/lib/entities/account-warning.ts
Normal file
27
packages/pl-api/lib/entities/account-warning.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { dateSchema } from './utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Appeal/} */
|
||||
const appealSchema = z.object({
|
||||
text: z.string(),
|
||||
state: z.enum(['approved', 'rejected', 'pending']),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/AccountWarning/} */
|
||||
const accountWarningSchema = z.object({
|
||||
id: z.string(),
|
||||
action: z.enum(['none', 'disable', 'mark_statuses_as_sensitive', 'delete_statuses', 'sensitive', 'silence', 'suspend']),
|
||||
text: z.string().catch(''),
|
||||
status_ids: z.array(z.string()).catch([]),
|
||||
target_account: accountSchema,
|
||||
appeal: appealSchema.nullable().catch(null),
|
||||
created_at: dateSchema,
|
||||
});
|
||||
|
||||
type AccountWarning = Resolve<z.infer<typeof accountWarningSchema>>;
|
||||
|
||||
export { accountWarningSchema, type AccountWarning };
|
177
packages/pl-api/lib/entities/account.ts
Normal file
177
packages/pl-api/lib/entities/account.ts
Normal file
|
@ -0,0 +1,177 @@
|
|||
import pick from 'lodash.pick';
|
||||
import z from 'zod';
|
||||
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
import { relationshipSchema } from './relationship';
|
||||
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:/, '') }));
|
||||
|
||||
const preprocessAccount = (account: any) => {
|
||||
if (!account?.acct) return null;
|
||||
|
||||
return {
|
||||
username: account.username || account.acct.split('@')[0],
|
||||
display_name: account.display_name.trim() || account.username,
|
||||
roles: account.roles?.length ? account.roles : filterBadges(account.pleroma?.tags),
|
||||
avatar_static: account.avatar_static || account.avatar,
|
||||
header_static: account.header_static || account.header,
|
||||
source: account.source
|
||||
? { ...(pick(account.pleroma?.source || {}, [
|
||||
'show_role', 'no_rich_text', 'discoverable', 'actor_type', 'show_birthday',
|
||||
])), ...account.source }
|
||||
: undefined,
|
||||
local: typeof account.pleroma?.is_local === 'boolean' ? account.pleroma.is_local : account.acct.split('@')[1] === undefined,
|
||||
discoverable: account.discoverable || account.pleroma?.source?.discoverable,
|
||||
verified: account.verified || account.pleroma?.tags?.includes('verified'),
|
||||
...(pick(account.pleroma || {}, [
|
||||
'ap_id',
|
||||
'background_image',
|
||||
'relationship',
|
||||
'is_moderator',
|
||||
'is_admin',
|
||||
'hide_favorites',
|
||||
'hide_followers',
|
||||
'hide_follows',
|
||||
'hide_followers_count',
|
||||
'hide_follows_count',
|
||||
'accepts_chat_messages',
|
||||
'favicon',
|
||||
'birthday',
|
||||
'deactivated',
|
||||
|
||||
'settings_store',
|
||||
'chat_token',
|
||||
'allow_following_move',
|
||||
'unread_conversation_count',
|
||||
'unread_notifications_count',
|
||||
'notification_settings',
|
||||
|
||||
'location',
|
||||
])),
|
||||
...(pick(account.other_settings || {}), ['birthday', 'location']),
|
||||
__meta: pick(account, ['pleroma', 'source']),
|
||||
...account,
|
||||
};
|
||||
};
|
||||
|
||||
const fieldSchema = z.object({
|
||||
name: z.string(),
|
||||
value: z.string(),
|
||||
verified_at: z.string().datetime({ offset: true }).nullable().catch(null),
|
||||
});
|
||||
|
||||
const baseAccountSchema = z.object({
|
||||
id: z.string(),
|
||||
username: z.string().catch(''),
|
||||
acct: z.string().catch(''),
|
||||
url: z.string().url(),
|
||||
display_name: z.string().catch(''),
|
||||
note: z.string().catch(''),
|
||||
avatar: z.string().catch(''),
|
||||
avatar_static: z.string().url().catch(''),
|
||||
header: z.string().url().catch(''),
|
||||
header_static: z.string().url().catch(''),
|
||||
locked: z.boolean().catch(false),
|
||||
fields: filteredArray(fieldSchema),
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
bot: z.boolean().catch(false),
|
||||
group: z.boolean().catch(false),
|
||||
discoverable: z.boolean().catch(false),
|
||||
noindex: z.boolean().nullable().catch(null),
|
||||
suspended: z.boolean().optional().catch(undefined),
|
||||
limited: z.boolean().optional().catch(undefined),
|
||||
created_at: z.string().datetime().catch(new Date().toUTCString()),
|
||||
last_status_at: z.string().date().nullable().catch(null),
|
||||
statuses_count: z.number().catch(0),
|
||||
followers_count: z.number().catch(0),
|
||||
following_count: z.number().catch(0),
|
||||
roles: filteredArray(roleSchema),
|
||||
|
||||
fqn: z.string().nullable().catch(null),
|
||||
ap_id: z.string().nullable().catch(null),
|
||||
background_image: z.string().nullable().catch(null),
|
||||
relationship: relationshipSchema.optional().catch(undefined),
|
||||
is_moderator: z.boolean().optional().catch(undefined),
|
||||
is_admin: z.boolean().optional().catch(undefined),
|
||||
is_suggested: z.boolean().optional().catch(undefined),
|
||||
hide_favorites: z.boolean().catch(true),
|
||||
hide_followers: z.boolean().optional().catch(undefined),
|
||||
hide_follows: z.boolean().optional().catch(undefined),
|
||||
hide_followers_count: z.boolean().optional().catch(undefined),
|
||||
hide_follows_count: z.boolean().optional().catch(undefined),
|
||||
accepts_chat_messages: z.boolean().nullable().catch(null),
|
||||
favicon: z.string().optional().catch(undefined),
|
||||
birthday: z.string().date().optional().catch(undefined),
|
||||
deactivated: z.boolean().optional().catch(undefined),
|
||||
|
||||
location: z.string().optional().catch(undefined),
|
||||
local: z.boolean().optional().catch(false),
|
||||
|
||||
avatar_description: z.string().catch(''),
|
||||
enable_rss: z.boolean().catch(false),
|
||||
header_description: z.string().catch(''),
|
||||
|
||||
verified: z.boolean().optional().catch(undefined),
|
||||
|
||||
__meta: coerceObject({
|
||||
pleroma: z.any().optional().catch(undefined),
|
||||
source: z.any().optional().catch(undefined),
|
||||
}),
|
||||
});
|
||||
|
||||
const accountWithMovedAccountSchema = baseAccountSchema.extend({
|
||||
moved: baseAccountSchema.optional().catch(undefined),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Account/} */
|
||||
const accountSchema = z.preprocess(preprocessAccount, accountWithMovedAccountSchema);
|
||||
|
||||
type Account = z.infer<typeof accountSchema>;
|
||||
|
||||
const credentialAccountSchema = z.preprocess(preprocessAccount, accountWithMovedAccountSchema.extend({
|
||||
source: z.object({
|
||||
note: z.string().catch(''),
|
||||
fields: filteredArray(fieldSchema),
|
||||
privacy: z.enum(['public', 'unlisted', 'private', 'direct']),
|
||||
sensitive: z.boolean().catch(false),
|
||||
language: z.string().nullable().catch(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),
|
||||
discoverable: z.boolean().optional().catch(undefined),
|
||||
actor_type: z.string().optional().catch(undefined),
|
||||
show_birthday: z.boolean().optional().catch(undefined),
|
||||
}).nullable().catch(null),
|
||||
role: roleSchema.nullable().catch(null),
|
||||
|
||||
settings_store: z.record(z.any()).optional().catch(undefined),
|
||||
chat_token: z.string().optional().catch(undefined),
|
||||
allow_following_move: z.boolean().optional().catch(undefined),
|
||||
unread_conversation_count: z.number().optional().catch(undefined),
|
||||
unread_notifications_count: z.number().optional().catch(undefined),
|
||||
notification_settings: z.object({
|
||||
block_from_strangers: z.boolean().catch(false),
|
||||
hide_notification_contents: z.boolean().catch(false),
|
||||
}).optional().catch(undefined),
|
||||
}));
|
||||
|
||||
type CredentialAccount = z.infer<typeof credentialAccountSchema>;
|
||||
|
||||
const mutedAccountSchema = z.preprocess(preprocessAccount, accountWithMovedAccountSchema.extend({
|
||||
mute_expires_at: dateSchema.nullable().catch(null),
|
||||
}));
|
||||
|
||||
type MutedAccount = z.infer<typeof mutedAccountSchema>;
|
||||
|
||||
export {
|
||||
accountSchema,
|
||||
credentialAccountSchema,
|
||||
mutedAccountSchema,
|
||||
type Account,
|
||||
type CredentialAccount,
|
||||
type MutedAccount,
|
||||
};
|
69
packages/pl-api/lib/entities/admin/account.ts
Normal file
69
packages/pl-api/lib/entities/admin/account.ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { accountSchema } from '../account';
|
||||
import { roleSchema } from '../role';
|
||||
import { dateSchema, filteredArray } from '../utils';
|
||||
|
||||
import { adminIpSchema } from './ip';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_Account/} */
|
||||
const adminAccountSchema = z.preprocess((account: any) => {
|
||||
if (!account.account) {
|
||||
/**
|
||||
* Convert Pleroma account schema
|
||||
* @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminusers}
|
||||
*/
|
||||
return {
|
||||
id: account.id,
|
||||
account: null,
|
||||
username: account.nickname,
|
||||
domain: account.nickname.split('@')[1] || null,
|
||||
created_at: account.created_at,
|
||||
email: account.email,
|
||||
invite_request: account.registration_reason,
|
||||
role: account.roles?.is_admin
|
||||
? roleSchema.parse({ name: 'Admin' })
|
||||
: account.roles?.moderator
|
||||
? roleSchema.parse({ name: 'Moderator ' }) :
|
||||
null,
|
||||
confirmed: account.is_confirmed,
|
||||
approved: account.is_approved,
|
||||
disabled: !account.is_active,
|
||||
|
||||
actor_type: account.actor_type,
|
||||
display_name: account.display_name,
|
||||
suggested: account.is_suggested,
|
||||
};
|
||||
}
|
||||
return account;
|
||||
}, z.object({
|
||||
id: z.string(),
|
||||
username: z.string(),
|
||||
domain: z.string().nullable().catch(null),
|
||||
created_at: dateSchema,
|
||||
email: z.string().nullable().catch(null),
|
||||
ip: z.string().ip().nullable().catch(null),
|
||||
ips: filteredArray(adminIpSchema),
|
||||
locale: z.string().nullable().catch(null),
|
||||
invite_request: z.string().nullable().catch(null),
|
||||
role: roleSchema.nullable().catch(null),
|
||||
confirmed: z.boolean().catch(false),
|
||||
approved: z.boolean().catch(false),
|
||||
disabled: z.boolean().catch(false),
|
||||
silenced: z.boolean().catch(false),
|
||||
suspended: z.boolean().catch(false),
|
||||
account: accountSchema.nullable().catch(null),
|
||||
created_by_application_id: z.string().optional().catch(undefined),
|
||||
invited_by_account_id: z.string().optional().catch(undefined),
|
||||
|
||||
actor_type: z.string().nullable().catch(null),
|
||||
display_name: z.string().nullable().catch(null),
|
||||
suggested: z.boolean().nullable().catch(null),
|
||||
}));
|
||||
|
||||
type AdminAccount = z.infer<typeof adminAccountSchema>;
|
||||
|
||||
export {
|
||||
adminAccountSchema,
|
||||
type AdminAccount,
|
||||
};
|
17
packages/pl-api/lib/entities/admin/announcement.ts
Normal file
17
packages/pl-api/lib/entities/admin/announcement.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import pick from 'lodash.pick';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../../utils/types';
|
||||
import { announcementSchema } from '../announcement';
|
||||
|
||||
/** @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminannouncements} */
|
||||
const adminAnnouncementSchema = z.preprocess((announcement: any) => ({
|
||||
...announcement,
|
||||
...pick(announcement.pleroma, 'raw_content'),
|
||||
}), announcementSchema.extend({
|
||||
raw_content: z.string().catch(''),
|
||||
}));
|
||||
|
||||
type AdminAnnouncement = Resolve<z.infer<typeof adminAnnouncementSchema>>;
|
||||
|
||||
export { adminAnnouncementSchema, type AdminAnnouncement };
|
14
packages/pl-api/lib/entities/admin/canonical-email-block.ts
Normal file
14
packages/pl-api/lib/entities/admin/canonical-email-block.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_CanonicalEmailBlock/} */
|
||||
const adminCanonicalEmailBlockSchema = z.object({
|
||||
id: z.string(),
|
||||
canonical_email_hash: z.string(),
|
||||
});
|
||||
|
||||
type AdminCanonicalEmailBlock = z.infer<typeof adminCanonicalEmailBlockSchema>;
|
||||
|
||||
export {
|
||||
adminCanonicalEmailBlockSchema,
|
||||
type AdminCanonicalEmailBlock,
|
||||
};
|
19
packages/pl-api/lib/entities/admin/cohort.ts
Normal file
19
packages/pl-api/lib/entities/admin/cohort.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_Cohort/} */
|
||||
const adminCohortSchema = z.object({
|
||||
period: z.string().datetime({ offset: true }),
|
||||
frequency: z.enum(['day', 'month']),
|
||||
data: z.array(z.object({
|
||||
date: z.string().datetime({ offset: true }),
|
||||
rate: z.number(),
|
||||
value: z.number().int(),
|
||||
})),
|
||||
});
|
||||
|
||||
type AdminCohort = z.infer<typeof adminCohortSchema>;
|
||||
|
||||
export {
|
||||
adminCohortSchema,
|
||||
type AdminCohort,
|
||||
};
|
20
packages/pl-api/lib/entities/admin/dimension.ts
Normal file
20
packages/pl-api/lib/entities/admin/dimension.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_Dimension/} */
|
||||
const adminDimensionSchema = z.object({
|
||||
key: z.string(),
|
||||
data: z.object({
|
||||
key: z.string(),
|
||||
human_key: z.string(),
|
||||
value: z.string(),
|
||||
unit: z.string().optional().catch(undefined),
|
||||
human_value: z.string().optional().catch(undefined),
|
||||
}),
|
||||
});
|
||||
|
||||
type AdminDimension = z.infer<typeof adminDimensionSchema>;
|
||||
|
||||
export {
|
||||
adminDimensionSchema,
|
||||
type AdminDimension,
|
||||
};
|
17
packages/pl-api/lib/entities/admin/domain-allow.ts
Normal file
17
packages/pl-api/lib/entities/admin/domain-allow.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema } from '../utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_DomainAllow/} */
|
||||
const adminDomainAllowSchema = z.object({
|
||||
id: z.string(),
|
||||
domain: z.string(),
|
||||
created_at: dateSchema,
|
||||
});
|
||||
|
||||
type AdminDomainAllow = z.infer<typeof adminDomainAllowSchema>;
|
||||
|
||||
export {
|
||||
adminDomainAllowSchema,
|
||||
type AdminDomainAllow,
|
||||
};
|
24
packages/pl-api/lib/entities/admin/domain-block.ts
Normal file
24
packages/pl-api/lib/entities/admin/domain-block.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema } from '../utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_DomainBlock/} */
|
||||
const adminDomainBlockSchema = z.object({
|
||||
id: z.string(),
|
||||
domain: z.string(),
|
||||
digest: z.string(),
|
||||
created_at: dateSchema,
|
||||
severity: z.enum(['silence', 'suspend', 'noop']),
|
||||
reject_media: z.boolean(),
|
||||
reject_reports: z.boolean(),
|
||||
private_comment: z.string().nullable().catch(null),
|
||||
public_comment: z.string().nullable().catch(null),
|
||||
obfuscate: z.boolean(),
|
||||
});
|
||||
|
||||
type AdminDomainBlock = z.infer<typeof adminDomainBlockSchema>;
|
||||
|
||||
export {
|
||||
adminDomainBlockSchema,
|
||||
type AdminDomainBlock,
|
||||
};
|
13
packages/pl-api/lib/entities/admin/domain.ts
Normal file
13
packages/pl-api/lib/entities/admin/domain.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import z from 'zod';
|
||||
|
||||
const adminDomainSchema = z.object({
|
||||
domain: z.string().catch(''),
|
||||
id: z.coerce.string(),
|
||||
public: z.boolean().catch(false),
|
||||
resolves: z.boolean().catch(false),
|
||||
last_checked_at: z.string().datetime().catch(''),
|
||||
});
|
||||
|
||||
type AdminDomain = z.infer<typeof adminDomainSchema>
|
||||
|
||||
export { adminDomainSchema, type AdminDomain };
|
22
packages/pl-api/lib/entities/admin/email-domain-block.ts
Normal file
22
packages/pl-api/lib/entities/admin/email-domain-block.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema } from '../utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_EmailDomainBlock/} */
|
||||
const adminEmailDomainBlockSchema = z.object({
|
||||
id: z.string(),
|
||||
domain: z.string(),
|
||||
created_at: dateSchema,
|
||||
history: z.array(z.object({
|
||||
day: z.coerce.string(),
|
||||
accounts: z.coerce.string(),
|
||||
uses: z.coerce.string(),
|
||||
})),
|
||||
});
|
||||
|
||||
type AdminEmailDomainBlock = z.infer<typeof adminEmailDomainBlockSchema>;
|
||||
|
||||
export {
|
||||
adminEmailDomainBlockSchema,
|
||||
type AdminEmailDomainBlock,
|
||||
};
|
20
packages/pl-api/lib/entities/admin/ip-block.ts
Normal file
20
packages/pl-api/lib/entities/admin/ip-block.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema } from '../utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_IpBlock/} */
|
||||
const adminIpBlockSchema = z.object({
|
||||
id: z.string(),
|
||||
ip: z.string().ip(),
|
||||
severity: z.enum(['sign_up_requires_approval', 'sign_up_block', 'no_access']),
|
||||
comment: z.string().catch(''),
|
||||
created_at: dateSchema,
|
||||
expires_at: z.string().datetime({ offset: true }),
|
||||
});
|
||||
|
||||
type AdminIpBlock = z.infer<typeof adminIpBlockSchema>;
|
||||
|
||||
export {
|
||||
adminIpBlockSchema,
|
||||
type AdminIpBlock,
|
||||
};
|
16
packages/pl-api/lib/entities/admin/ip.ts
Normal file
16
packages/pl-api/lib/entities/admin/ip.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema } from '../utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_Ip/} */
|
||||
const adminIpSchema = z.object({
|
||||
ip: z.string().ip(),
|
||||
used_at: dateSchema,
|
||||
});
|
||||
|
||||
type AdminIp = z.infer<typeof adminIpSchema>;
|
||||
|
||||
export {
|
||||
adminIpSchema,
|
||||
type AdminIp,
|
||||
};
|
21
packages/pl-api/lib/entities/admin/measure.ts
Normal file
21
packages/pl-api/lib/entities/admin/measure.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_Measure/} */
|
||||
const adminMeasureSchema = z.object({
|
||||
key: z.string(),
|
||||
unit: z.string().nullable().catch(null),
|
||||
total: z.coerce.number(),
|
||||
human_value: z.string().optional().catch(undefined),
|
||||
previous_total: z.coerce.string().optional().catch(undefined),
|
||||
data: z.array(z.object({
|
||||
date: z.string().datetime({ offset: true }),
|
||||
value: z.coerce.string(),
|
||||
})),
|
||||
});
|
||||
|
||||
type AdminMeasure = z.infer<typeof adminMeasureSchema>;
|
||||
|
||||
export {
|
||||
adminMeasureSchema,
|
||||
type AdminMeasure,
|
||||
};
|
13
packages/pl-api/lib/entities/admin/moderation-log-entry.ts
Normal file
13
packages/pl-api/lib/entities/admin/moderation-log-entry.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import z from 'zod';
|
||||
|
||||
/** @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminmoderation_log} */
|
||||
const adminModerationLogEntrySchema = z.object({
|
||||
id: z.coerce.string(),
|
||||
data: z.record(z.string(), z.any()).catch({}),
|
||||
time: z.number().catch(0),
|
||||
message: z.string().catch(''),
|
||||
});
|
||||
|
||||
type AdminModerationLogEntry = z.infer<typeof adminModerationLogEntrySchema>
|
||||
|
||||
export { adminModerationLogEntrySchema, type AdminModerationLogEntry };
|
11
packages/pl-api/lib/entities/admin/relay.ts
Normal file
11
packages/pl-api/lib/entities/admin/relay.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import z from 'zod';
|
||||
|
||||
const adminRelaySchema = z.preprocess((data: any) => ({ id: data.actor, ...data }), z.object({
|
||||
actor: z.string().catch(''),
|
||||
id: z.string(),
|
||||
followed_back: z.boolean().catch(false),
|
||||
}));
|
||||
|
||||
type AdminRelay = z.infer<typeof adminRelaySchema>
|
||||
|
||||
export { adminRelaySchema, type AdminRelay };
|
46
packages/pl-api/lib/entities/admin/report.ts
Normal file
46
packages/pl-api/lib/entities/admin/report.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import pick from 'lodash.pick';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ruleSchema } from '../rule';
|
||||
import { statusWithoutAccountSchema } from '../status';
|
||||
import { dateSchema, filteredArray } from '../utils';
|
||||
|
||||
import { adminAccountSchema } from './account';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Admin_Report/} */
|
||||
const adminReportSchema = z.preprocess((report: any) => {
|
||||
if (report.actor) {
|
||||
/**
|
||||
* Convert Pleroma report schema
|
||||
* @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminreports}
|
||||
*/
|
||||
return {
|
||||
action_taken: report.state !== 'open',
|
||||
comment: report.content,
|
||||
updated_at: report.created_at,
|
||||
account: report.actor,
|
||||
target_account: report.account,
|
||||
...(pick(report, ['id', 'assigned_account', 'created_at', 'rules', 'statuses'])),
|
||||
};
|
||||
}
|
||||
return report;
|
||||
}, z.object({
|
||||
id: z.string(),
|
||||
action_taken: z.boolean().optional().catch(undefined),
|
||||
action_taken_at: dateSchema.nullable().catch(null),
|
||||
category: z.string().optional().catch(undefined),
|
||||
comment: z.string().optional().catch(undefined),
|
||||
forwarded: z.boolean().optional().catch(undefined),
|
||||
created_at: dateSchema.optional().catch(undefined),
|
||||
updated_at: dateSchema.optional().catch(undefined),
|
||||
account: adminAccountSchema,
|
||||
target_account: adminAccountSchema,
|
||||
assigned_account: adminAccountSchema.nullable().catch(null),
|
||||
action_taken_by_account: adminAccountSchema.nullable().catch(null),
|
||||
statuses: filteredArray(statusWithoutAccountSchema),
|
||||
rules: filteredArray(ruleSchema),
|
||||
}));
|
||||
|
||||
type AdminReport = z.infer<typeof adminReportSchema>;
|
||||
|
||||
export { adminReportSchema, type AdminReport };
|
13
packages/pl-api/lib/entities/admin/rule.ts
Normal file
13
packages/pl-api/lib/entities/admin/rule.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminrules} */
|
||||
const adminRuleSchema = z.object({
|
||||
id: z.string(),
|
||||
text: z.string().catch(''),
|
||||
hint: z.string().catch(''),
|
||||
priority: z.number().nullable().catch(null),
|
||||
});
|
||||
|
||||
type AdminRule = z.infer<typeof adminRuleSchema>;
|
||||
|
||||
export { adminRuleSchema, type AdminRule };
|
18
packages/pl-api/lib/entities/admin/tag.ts
Normal file
18
packages/pl-api/lib/entities/admin/tag.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { tagSchema } from '../tag';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Tag/#admin} */
|
||||
const adminTagSchema = tagSchema.extend({
|
||||
id: z.string(),
|
||||
trendable: z.boolean(),
|
||||
usable: z.boolean(),
|
||||
requires_review: z.boolean(),
|
||||
});
|
||||
|
||||
type AdminTag = z.infer<typeof adminTagSchema>;
|
||||
|
||||
export {
|
||||
adminTagSchema,
|
||||
type AdminTag,
|
||||
};
|
17
packages/pl-api/lib/entities/announcement-reaction.ts
Normal file
17
packages/pl-api/lib/entities/announcement-reaction.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import type { Resolve } from '../utils/types';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/announcement/} */
|
||||
const announcementReactionSchema = z.object({
|
||||
name: z.string().catch(''),
|
||||
count: z.number().int().nonnegative().catch(0),
|
||||
me: z.boolean().catch(false),
|
||||
url: z.string().nullable().catch(null),
|
||||
static_url: z.string().nullable().catch(null),
|
||||
announcement_id: z.string().catch(''),
|
||||
});
|
||||
|
||||
type AnnouncementReaction = Resolve<z.infer<typeof announcementReactionSchema>>;
|
||||
|
||||
export { announcementReactionSchema, type AnnouncementReaction };
|
35
packages/pl-api/lib/entities/announcement.ts
Normal file
35
packages/pl-api/lib/entities/announcement.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { announcementReactionSchema } from './announcement-reaction';
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
import { mentionSchema } from './mention';
|
||||
import { tagSchema } from './tag';
|
||||
import { dateSchema, filteredArray } from './utils';
|
||||
|
||||
import type { Resolve } from '../utils/types';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/announcement/} */
|
||||
const announcementSchema = z.object({
|
||||
id: z.string(),
|
||||
content: z.string().catch(''),
|
||||
starts_at: z.string().datetime().nullable().catch(null),
|
||||
ends_at: z.string().datetime().nullable().catch(null),
|
||||
all_day: z.boolean().catch(false),
|
||||
read: z.boolean().catch(false),
|
||||
published_at: dateSchema,
|
||||
reactions: filteredArray(announcementReactionSchema),
|
||||
statuses: z.preprocess(
|
||||
(statuses: any) => Array.isArray(statuses)
|
||||
? Object.fromEntries(statuses.map((status: any) => [status.url, status.account?.acct]) || [])
|
||||
: statuses,
|
||||
z.record(z.string(), z.string()),
|
||||
),
|
||||
mentions: filteredArray(mentionSchema),
|
||||
tags: filteredArray(tagSchema),
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
updated_at: dateSchema,
|
||||
});
|
||||
|
||||
type Announcement = Resolve<z.infer<typeof announcementSchema>>;
|
||||
|
||||
export { announcementSchema, type Announcement };
|
21
packages/pl-api/lib/entities/application.ts
Normal file
21
packages/pl-api/lib/entities/application.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import type { Resolve } from '../utils/types';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Application/} */
|
||||
const applicationSchema = z.object({
|
||||
name: z.string().catch(''),
|
||||
website: z.string().optional().catch(undefined),
|
||||
client_id: z.string().optional().catch(undefined),
|
||||
client_secret: z.string().optional().catch(undefined),
|
||||
redirect_uri: z.string().optional().catch(undefined),
|
||||
|
||||
id: z.string().optional().catch(undefined),
|
||||
|
||||
/** @deprecated */
|
||||
vapid_key: z.string().optional().catch(undefined),
|
||||
});
|
||||
|
||||
type Application = Resolve<z.infer<typeof applicationSchema>>;
|
||||
|
||||
export { applicationSchema, type Application };
|
19
packages/pl-api/lib/entities/backup.ts
Normal file
19
packages/pl-api/lib/entities/backup.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema, mimeSchema } from './utils';
|
||||
|
||||
import type { Resolve } from '../utils/types';
|
||||
|
||||
/** @see {@link https://docs.pleroma.social/backend/development/API/pleroma_api/#post-apiv1pleromabackups} */
|
||||
const backupSchema = z.object({
|
||||
id: z.coerce.string(),
|
||||
contentType: mimeSchema,
|
||||
file_size: z.number().catch(0),
|
||||
inserted_at: dateSchema,
|
||||
processed: z.boolean().catch(false),
|
||||
url: z.string().catch(''),
|
||||
});
|
||||
|
||||
type Backup = Resolve<z.infer<typeof backupSchema>>;
|
||||
|
||||
export { backupSchema, type Backup };
|
14
packages/pl-api/lib/entities/bookmark-folder.ts
Normal file
14
packages/pl-api/lib/entities/bookmark-folder.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import type { Resolve } from '../utils/types';
|
||||
|
||||
const bookmarkFolderSchema = z.object({
|
||||
id: z.coerce.string(),
|
||||
name: z.string().catch(''),
|
||||
emoji: z.string().nullable().catch(null),
|
||||
emoji_url: z.string().nullable().catch(null),
|
||||
});
|
||||
|
||||
type BookmarkFolder = Resolve<z.infer<typeof bookmarkFolderSchema>>;
|
||||
|
||||
export { bookmarkFolderSchema, type BookmarkFolder };
|
23
packages/pl-api/lib/entities/chat-message.ts
Normal file
23
packages/pl-api/lib/entities/chat-message.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
import { mediaAttachmentSchema } from './media-attachment';
|
||||
import { previewCardSchema } from './preview-card';
|
||||
import { dateSchema, filteredArray } from './utils';
|
||||
|
||||
/** @see {@link https://docs.pleroma.social/backend/development/API/chats/#getting-the-messages-for-a-chat} */
|
||||
const chatMessageSchema = z.object({
|
||||
id: z.string(),
|
||||
content: z.string().catch(''),
|
||||
chat_id: z.string(),
|
||||
account_id: z.string(),
|
||||
created_at: dateSchema,
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
attachment: mediaAttachmentSchema.nullable().catch(null),
|
||||
unread: z.boolean(),
|
||||
card: previewCardSchema.nullable().catch(null),
|
||||
});
|
||||
|
||||
type ChatMessage = z.infer<typeof chatMessageSchema>;
|
||||
|
||||
export { chatMessageSchema, type ChatMessage };
|
18
packages/pl-api/lib/entities/chat.ts
Normal file
18
packages/pl-api/lib/entities/chat.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { chatMessageSchema } from './chat-message';
|
||||
import { dateSchema } from './utils';
|
||||
|
||||
/** @see {@link https://docs.pleroma.social/backend/development/API/chats/#getting-a-list-of-chats} */
|
||||
const chatSchema = z.object({
|
||||
id: z.string(),
|
||||
account: accountSchema,
|
||||
unread: z.number().int(),
|
||||
last_message: chatMessageSchema.nullable().catch(null),
|
||||
created_at: dateSchema,
|
||||
});
|
||||
|
||||
type Chat = z.infer<typeof chatSchema>;
|
||||
|
||||
export { chatSchema, type Chat };
|
15
packages/pl-api/lib/entities/context.ts
Normal file
15
packages/pl-api/lib/entities/context.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { statusSchema } from './status';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Context/} */
|
||||
const contextSchema = z.object({
|
||||
ancestors: z.array(statusSchema),
|
||||
descendants: z.array(statusSchema),
|
||||
});
|
||||
|
||||
type Context = Resolve<z.infer<typeof contextSchema>>;
|
||||
|
||||
export { contextSchema, type Context };
|
17
packages/pl-api/lib/entities/conversation.ts
Normal file
17
packages/pl-api/lib/entities/conversation.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { filteredArray } from './utils';
|
||||
|
||||
import { accountSchema, statusSchema } from '.';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Conversation} */
|
||||
const conversationSchema = z.object({
|
||||
id: z.string(),
|
||||
unread: z.boolean().catch(false),
|
||||
accounts: filteredArray(accountSchema),
|
||||
last_status: statusSchema.nullable().catch(null),
|
||||
});
|
||||
|
||||
type Conversation = z.infer<typeof conversationSchema>;
|
||||
|
||||
export { conversationSchema, type Conversation };
|
17
packages/pl-api/lib/entities/custom-emoji.ts
Normal file
17
packages/pl-api/lib/entities/custom-emoji.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import z from 'zod';
|
||||
|
||||
/**
|
||||
* Represents a custom emoji.
|
||||
* @see {@link https://docs.joinmastodon.org/entities/CustomEmoji/}
|
||||
*/
|
||||
const customEmojiSchema = z.object({
|
||||
shortcode: z.string(),
|
||||
url: z.string(),
|
||||
static_url: z.string().catch(''),
|
||||
visible_in_picker: z.boolean().catch(true),
|
||||
category: z.string().nullable().catch(null),
|
||||
});
|
||||
|
||||
type CustomEmoji = z.infer<typeof customEmojiSchema>;
|
||||
|
||||
export { customEmojiSchema, type CustomEmoji };
|
13
packages/pl-api/lib/entities/domain-block.ts
Normal file
13
packages/pl-api/lib/entities/domain-block.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/DomainBlock} */
|
||||
const domainBlockSchema = z.object({
|
||||
domain: z.string(),
|
||||
digest: z.string(),
|
||||
severity: z.enum(['silence', 'suspend']),
|
||||
comment: z.string().optional().catch(undefined),
|
||||
});
|
||||
|
||||
type DomainBlock = z.infer<typeof domainBlockSchema>;
|
||||
|
||||
export { domainBlockSchema, type DomainBlock };
|
27
packages/pl-api/lib/entities/emoji-reaction.ts
Normal file
27
packages/pl-api/lib/entities/emoji-reaction.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { emojiSchema, filteredArray } from './utils';
|
||||
|
||||
const baseEmojiReactionSchema = z.object({
|
||||
count: z.number().nullable().catch(null),
|
||||
me: z.boolean().catch(false),
|
||||
name: emojiSchema,
|
||||
url: z.literal(undefined).catch(undefined),
|
||||
accounts: filteredArray(accountSchema),
|
||||
});
|
||||
|
||||
const customEmojiReactionSchema = baseEmojiReactionSchema.extend({
|
||||
name: z.string(),
|
||||
url: z.string().url(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Pleroma emoji reaction.
|
||||
* @see {@link https://docs.pleroma.social/backend/development/API/differences_in_mastoapi_responses/#statuses}
|
||||
*/
|
||||
const emojiReactionSchema = baseEmojiReactionSchema.or(customEmojiReactionSchema);
|
||||
|
||||
type EmojiReaction = z.infer<typeof emojiReactionSchema>;
|
||||
|
||||
export { emojiReactionSchema, type EmojiReaction };
|
13
packages/pl-api/lib/entities/extended-description.ts
Normal file
13
packages/pl-api/lib/entities/extended-description.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema } from './utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/ExtendedDescription} */
|
||||
const extendedDescriptionSchema = z.object({
|
||||
updated_at: dateSchema,
|
||||
content: z.string(),
|
||||
});
|
||||
|
||||
type ExtendedDescription = z.infer<typeof extendedDescriptionSchema>;
|
||||
|
||||
export { extendedDescriptionSchema, type ExtendedDescription };
|
14
packages/pl-api/lib/entities/familiar-followers.ts
Normal file
14
packages/pl-api/lib/entities/familiar-followers.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import z from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { filteredArray } from './utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/FamiliarFollowers/} */
|
||||
const familiarFollowersSchema = z.object({
|
||||
id: z.string(),
|
||||
accounts: filteredArray(accountSchema),
|
||||
});
|
||||
|
||||
type FamiliarFollowers = z.infer<typeof familiarFollowersSchema>
|
||||
|
||||
export { familiarFollowersSchema, type FamiliarFollowers };
|
14
packages/pl-api/lib/entities/featured-tag.ts
Normal file
14
packages/pl-api/lib/entities/featured-tag.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/FeaturedTag/} */
|
||||
const featuredTagSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
url: z.string().optional().catch(undefined),
|
||||
statuses_count: z.number(),
|
||||
last_status_at: z.number(),
|
||||
});
|
||||
|
||||
type FeaturedTag = z.infer<typeof featuredTagSchema>;
|
||||
|
||||
export { featuredTagSchema, type FeaturedTag };
|
16
packages/pl-api/lib/entities/filter-result.ts
Normal file
16
packages/pl-api/lib/entities/filter-result.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { filterSchema } from './filter';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/FilterResult/} */
|
||||
const filterResultSchema = z.object({
|
||||
filter: filterSchema,
|
||||
keyword_matches: z.array(z.string()).nullable().catch(null),
|
||||
status_matches: z.array(z.string()).nullable().catch(null),
|
||||
});
|
||||
|
||||
type FilterResult = Resolve<z.infer<typeof filterResultSchema>>;
|
||||
|
||||
export { filterResultSchema, type FilterResult };
|
47
packages/pl-api/lib/entities/filter.ts
Normal file
47
packages/pl-api/lib/entities/filter.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { filteredArray } from './utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/FilterKeyword/} */
|
||||
const filterKeywordSchema = z.object({
|
||||
id: z.string(),
|
||||
keyword: z.string(),
|
||||
whole_word: z.boolean(),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/FilterStatus/} */
|
||||
const filterStatusSchema = z.object({
|
||||
id: z.string(),
|
||||
status_id: z.string(),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Filter/} */
|
||||
const filterSchema = z.preprocess((filter: any) => {
|
||||
if (filter.phrase) {
|
||||
return {
|
||||
...filter,
|
||||
title: filter.phrase,
|
||||
keywords: [{
|
||||
id: '1',
|
||||
keyword: filter.phrase,
|
||||
whole_word: filter.whole_word,
|
||||
}],
|
||||
filter_action: filter.irreversible ? 'hide' : 'warn',
|
||||
};
|
||||
}
|
||||
return filter;
|
||||
}, z.object({
|
||||
id: z.string(),
|
||||
title: z.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'),
|
||||
keywords: filteredArray(filterKeywordSchema),
|
||||
statuses: filteredArray(filterStatusSchema),
|
||||
}));
|
||||
|
||||
type Filter = Resolve<z.infer<typeof filterSchema>>;
|
||||
|
||||
export { filterKeywordSchema, filterStatusSchema, filterSchema, type Filter };
|
21
packages/pl-api/lib/entities/group-member.ts
Normal file
21
packages/pl-api/lib/entities/group-member.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import z from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
|
||||
enum GroupRoles {
|
||||
OWNER = 'owner',
|
||||
ADMIN = 'admin',
|
||||
USER = 'user'
|
||||
}
|
||||
|
||||
type GroupRole =`${GroupRoles}`;
|
||||
|
||||
const groupMemberSchema = z.object({
|
||||
id: z.string(),
|
||||
account: accountSchema,
|
||||
role: z.nativeEnum(GroupRoles),
|
||||
});
|
||||
|
||||
type GroupMember = z.infer<typeof groupMemberSchema>;
|
||||
|
||||
export { groupMemberSchema, type GroupMember, GroupRoles, type GroupRole };
|
14
packages/pl-api/lib/entities/group-relationship.ts
Normal file
14
packages/pl-api/lib/entities/group-relationship.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import z from 'zod';
|
||||
|
||||
import { GroupRoles } from './group-member';
|
||||
|
||||
const groupRelationshipSchema = z.object({
|
||||
id: z.string(),
|
||||
member: z.boolean().catch(false),
|
||||
role: z.nativeEnum(GroupRoles).catch(GroupRoles.USER),
|
||||
requested: z.boolean().catch(false),
|
||||
});
|
||||
|
||||
type GroupRelationship = z.infer<typeof groupRelationshipSchema>;
|
||||
|
||||
export { groupRelationshipSchema, type GroupRelationship };
|
33
packages/pl-api/lib/entities/group.ts
Normal file
33
packages/pl-api/lib/entities/group.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import z from 'zod';
|
||||
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
import { groupRelationshipSchema } from './group-relationship';
|
||||
import { filteredArray } from './utils';
|
||||
|
||||
const groupSchema = z.object({
|
||||
avatar: z.string().catch(''),
|
||||
avatar_static: z.string().catch(''),
|
||||
created_at: z.string().datetime().catch(new Date().toUTCString()),
|
||||
display_name: z.string().catch(''),
|
||||
domain: z.string().catch(''),
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
header: z.string().catch(''),
|
||||
header_static: z.string().catch(''),
|
||||
id: z.coerce.string(),
|
||||
locked: z.boolean().catch(false),
|
||||
membership_required: z.boolean().catch(false),
|
||||
members_count: z.number().catch(0),
|
||||
owner: z.object({ id: z.string() }).nullable().catch(null),
|
||||
note: z.string().transform(note => note === '<p></p>' ? '' : note).catch(''),
|
||||
relationship: groupRelationshipSchema.nullable().catch(null), // Dummy field to be overwritten later
|
||||
statuses_visibility: z.string().catch('public'),
|
||||
uri: z.string().catch(''),
|
||||
url: z.string().catch(''),
|
||||
|
||||
avatar_description: z.string().catch(''),
|
||||
header_description: z.string().catch(''),
|
||||
});
|
||||
|
||||
type Group = z.infer<typeof groupSchema>;
|
||||
|
||||
export { groupSchema, type Group };
|
69
packages/pl-api/lib/entities/index.ts
Normal file
69
packages/pl-api/lib/entities/index.ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
export * from './account';
|
||||
export * from './account-warning';
|
||||
export * from './admin/account';
|
||||
export * from './admin/announcement';
|
||||
export * from './admin/canonical-email-block';
|
||||
export * from './admin/cohort';
|
||||
export * from './admin/dimension';
|
||||
export * from './admin/domain';
|
||||
export * from './admin/domain-allow';
|
||||
export * from './admin/domain-block';
|
||||
export * from './admin/email-domain-block';
|
||||
export * from './admin/ip';
|
||||
export * from './admin/ip-block';
|
||||
export * from './admin/measure';
|
||||
export * from './admin/moderation-log-entry';
|
||||
export * from './admin/relay';
|
||||
export * from './admin/report';
|
||||
export * from './admin/rule';
|
||||
export * from './admin/tag';
|
||||
export * from './announcement';
|
||||
export * from './announcement-reaction';
|
||||
export * from './application';
|
||||
export * from './backup';
|
||||
export * from './bookmark-folder';
|
||||
export * from './chat';
|
||||
export * from './chat-message';
|
||||
export * from './context';
|
||||
export * from './conversation';
|
||||
export * from './custom-emoji';
|
||||
export * from './domain-block';
|
||||
export * from './emoji-reaction';
|
||||
export * from './extended-description';
|
||||
export * from './familiar-followers';
|
||||
export * from './featured-tag';
|
||||
export * from './filter';
|
||||
export * from './group';
|
||||
export * from './group-member';
|
||||
export * from './group-relationship';
|
||||
export * from './instance';
|
||||
export * from './interaction-policy';
|
||||
export * from './interaction-request';
|
||||
export * from './list';
|
||||
export * from './location';
|
||||
export * from './marker';
|
||||
export * from './media-attachment';
|
||||
export * from './mention';
|
||||
export * from './notification';
|
||||
export * from './notification-policy';
|
||||
export * from './notification-request';
|
||||
export * from './oauth-token';
|
||||
export * from './poll';
|
||||
export * from './preview-card';
|
||||
export * from './relationship';
|
||||
export * from './relationship-severance-event';
|
||||
export * from './report';
|
||||
export * from './role';
|
||||
export * from './rule';
|
||||
export * from './scheduled-status';
|
||||
export * from './search';
|
||||
export * from './status';
|
||||
export * from './status-edit';
|
||||
export * from './status-source';
|
||||
export * from './streaming-event';
|
||||
export * from './suggestion';
|
||||
export * from './tag';
|
||||
export * from './token';
|
||||
export * from './translation';
|
||||
export * from './trends-link';
|
||||
export * from './web-push-subscription';
|
325
packages/pl-api/lib/entities/instance.ts
Normal file
325
packages/pl-api/lib/entities/instance.ts
Normal file
|
@ -0,0 +1,325 @@
|
|||
/* eslint sort-keys: "error" */
|
||||
import z from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { ruleSchema } from './rule';
|
||||
import { coerceObject, filteredArray, mimeSchema } from './utils';
|
||||
|
||||
const fixVersion = (version: string) => {
|
||||
// Handle Mastodon release candidates
|
||||
if (new RegExp(/[0-9.]+rc[0-9]+/g).test(version)) {
|
||||
version = version.split('rc').join('-rc');
|
||||
}
|
||||
|
||||
// Rename Akkoma to Pleroma+akkoma
|
||||
if (version.includes('Akkoma')) {
|
||||
version = '2.7.2 (compatible; Pleroma 2.4.50+akkoma)';
|
||||
}
|
||||
|
||||
// Set Takahē version to a Pleroma-like string
|
||||
if (version.startsWith('takahe/')) {
|
||||
version = `0.0.0 (compatible; Takahe ${version.slice(7)})`;
|
||||
}
|
||||
|
||||
return version;
|
||||
};
|
||||
|
||||
const configurationSchema = coerceObject({
|
||||
accounts: z.object({
|
||||
allow_custom_css: z.boolean(),
|
||||
max_featured_tags: z.number().int(),
|
||||
max_profile_fields: z.number().int(),
|
||||
}).nullable().catch(null),
|
||||
chats: coerceObject({
|
||||
max_characters: z.number().catch(5000),
|
||||
}),
|
||||
groups: coerceObject({
|
||||
max_characters_description: z.number().catch(160),
|
||||
max_characters_name: z.number().catch(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),
|
||||
}),
|
||||
polls: coerceObject({
|
||||
max_characters_per_option: z.number().optional().catch(undefined),
|
||||
max_expiration: z.number().optional().catch(undefined),
|
||||
max_options: z.number().optional().catch(undefined),
|
||||
min_expiration: z.number().optional().catch(undefined),
|
||||
}),
|
||||
reactions: coerceObject({
|
||||
max_reactions: z.number().catch(0),
|
||||
}),
|
||||
statuses: coerceObject({
|
||||
characters_reserved_per_url: z.number().optional().catch(undefined),
|
||||
max_characters: z.number().optional().catch(undefined),
|
||||
max_media_attachments: z.number().optional().catch(undefined),
|
||||
|
||||
}),
|
||||
translation: coerceObject({
|
||||
enabled: z.boolean().catch(false),
|
||||
}),
|
||||
urls: coerceObject({
|
||||
streaming: z.string().url().optional().catch(undefined),
|
||||
}),
|
||||
});
|
||||
|
||||
const contactSchema = coerceObject({
|
||||
contact_account: accountSchema.optional().catch(undefined),
|
||||
email: z.string().email().catch(''),
|
||||
});
|
||||
|
||||
const pleromaSchema = coerceObject({
|
||||
metadata: coerceObject({
|
||||
account_activation_required: z.boolean().catch(false),
|
||||
birthday_min_age: z.number().catch(0),
|
||||
birthday_required: z.boolean().catch(false),
|
||||
description_limit: z.number().catch(1500),
|
||||
features: z.string().array().catch([]),
|
||||
federation: coerceObject({
|
||||
enabled: z.boolean().catch(true), // Assume true unless explicitly false
|
||||
mrf_policies: z.string().array().optional().catch(undefined),
|
||||
mrf_simple: coerceObject({
|
||||
accept: z.string().array().catch([]),
|
||||
avatar_removal: z.string().array().catch([]),
|
||||
banner_removal: z.string().array().catch([]),
|
||||
federated_timeline_removal: z.string().array().catch([]),
|
||||
followers_only: z.string().array().catch([]),
|
||||
media_nsfw: z.string().array().catch([]),
|
||||
media_removal: z.string().array().catch([]),
|
||||
reject: z.string().array().catch([]),
|
||||
reject_deletes: z.string().array().catch([]),
|
||||
report_removal: z.string().array().catch([]),
|
||||
}),
|
||||
}),
|
||||
fields_limits: coerceObject({
|
||||
max_fields: z.number().nonnegative().catch(4),
|
||||
name_length: z.number().nonnegative().catch(255),
|
||||
value_length: z.number().nonnegative().catch(2047),
|
||||
}),
|
||||
markup: coerceObject({
|
||||
allow_headings: z.boolean().catch(false),
|
||||
allow_inline_images: z.boolean().catch(false),
|
||||
}),
|
||||
migration_cooldown_period: z.number().optional().catch(undefined),
|
||||
multitenancy: coerceObject({
|
||||
domains: z
|
||||
.array(
|
||||
z.object({
|
||||
domain: z.coerce.string(),
|
||||
id: z.string(),
|
||||
public: z.boolean().catch(false),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
enabled: z.boolean().catch(false),
|
||||
}),
|
||||
post_formats: z.string().array().optional().catch(undefined),
|
||||
restrict_unauthenticated: coerceObject({
|
||||
activities: coerceObject({
|
||||
local: z.boolean().catch(false),
|
||||
remote: z.boolean().catch(false),
|
||||
}),
|
||||
profiles: coerceObject({
|
||||
local: z.boolean().catch(false),
|
||||
remote: z.boolean().catch(false),
|
||||
}),
|
||||
timelines: coerceObject({
|
||||
bubble: z.boolean().catch(false),
|
||||
federated: z.boolean().catch(false),
|
||||
local: z.boolean().catch(false),
|
||||
}),
|
||||
}),
|
||||
translation: coerceObject({
|
||||
allow_remote: z.boolean().catch(true),
|
||||
allow_unauthenticated: z.boolean().catch(false),
|
||||
source_languages: z.string().array().optional().catch(undefined),
|
||||
target_languages: z.string().array().optional().catch(undefined),
|
||||
}),
|
||||
}),
|
||||
oauth_consumer_strategies: z.string().array().catch([]),
|
||||
stats: coerceObject({
|
||||
mau: z.number().optional().catch(undefined),
|
||||
}),
|
||||
vapid_public_key: z.string().catch(''),
|
||||
});
|
||||
|
||||
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),
|
||||
});
|
||||
|
||||
const registrations = coerceObject({
|
||||
approval_required: z.boolean().catch(false),
|
||||
enabled: z.boolean().catch(false),
|
||||
message: z.string().optional().catch(undefined),
|
||||
});
|
||||
|
||||
const statsSchema = coerceObject({
|
||||
domain_count: z.number().optional().catch(undefined),
|
||||
status_count: z.number().optional().catch(undefined),
|
||||
user_count: z.number().optional().catch(undefined),
|
||||
});
|
||||
|
||||
const thumbnailSchema = coerceObject({
|
||||
url: z.string().catch(''),
|
||||
});
|
||||
|
||||
const usageSchema = coerceObject({
|
||||
users: coerceObject({
|
||||
active_month: z.number().catch(0),
|
||||
}),
|
||||
});
|
||||
|
||||
const instanceV1Schema = coerceObject({
|
||||
account_domain: z.string().catch(''),
|
||||
approval_required: z.boolean().catch(false),
|
||||
configuration: configurationSchema,
|
||||
contact_account: accountSchema.optional().catch(undefined),
|
||||
description: z.string().catch(''),
|
||||
description_limit: z.number().catch(1500),
|
||||
email: z.string().email().catch(''),
|
||||
feature_quote: z.boolean().catch(false),
|
||||
fedibird_capabilities: z.array(z.string()).catch([]),
|
||||
languages: z.string().array().catch([]),
|
||||
max_media_attachments: z.number().optional().catch(undefined),
|
||||
max_toot_chars: z.number().optional().catch(undefined),
|
||||
pleroma: pleromaSchema,
|
||||
poll_limits: pleromaPollLimitsSchema,
|
||||
registrations: z.boolean().catch(false),
|
||||
rules: filteredArray(ruleSchema),
|
||||
short_description: z.string().catch(''),
|
||||
stats: statsSchema,
|
||||
thumbnail: z.string().catch(''),
|
||||
title: z.string().catch(''),
|
||||
uri: z.string().catch(''),
|
||||
urls: coerceObject({
|
||||
streaming_api: z.string().url().optional().catch(undefined),
|
||||
}),
|
||||
usage: usageSchema,
|
||||
version: z.string().catch('0.0.0'),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Instance/} */
|
||||
const instanceSchema = z.preprocess((data: any) => {
|
||||
// Detect GoToSocial
|
||||
if (typeof data.configuration?.accounts?.allow_custom_css === 'boolean') {
|
||||
data.version = `0.0.0 (compatible; GoToSocial ${data.version})`;
|
||||
}
|
||||
|
||||
if (data.domain) return { account_domain: data.domain, ...data };
|
||||
|
||||
const {
|
||||
approval_required,
|
||||
configuration,
|
||||
contact_account,
|
||||
description,
|
||||
description_limit,
|
||||
email,
|
||||
max_media_attachments,
|
||||
max_toot_chars,
|
||||
poll_limits,
|
||||
pleroma,
|
||||
registrations,
|
||||
short_description,
|
||||
thumbnail,
|
||||
uri,
|
||||
urls,
|
||||
...instance
|
||||
} = instanceV1Schema.parse(data);
|
||||
|
||||
return {
|
||||
...instance,
|
||||
account_domain: instance.account_domain || uri,
|
||||
configuration: {
|
||||
...configuration,
|
||||
polls: {
|
||||
...configuration.polls,
|
||||
max_characters_per_option: configuration.polls.max_characters_per_option ?? poll_limits.max_option_chars ?? 25,
|
||||
max_expiration: configuration.polls.max_expiration ?? poll_limits.max_expiration ?? 2629746,
|
||||
max_options: configuration.polls.max_options ?? poll_limits.max_options ?? 4,
|
||||
min_expiration: configuration.polls.min_expiration ?? poll_limits.min_expiration ?? 300,
|
||||
},
|
||||
statuses: {
|
||||
...configuration.statuses,
|
||||
max_characters: configuration.statuses.max_characters ?? max_toot_chars ?? 500,
|
||||
max_media_attachments: configuration.statuses.max_media_attachments ?? max_media_attachments,
|
||||
},
|
||||
urls: {
|
||||
streaming: urls.streaming_api,
|
||||
},
|
||||
},
|
||||
contact: {
|
||||
account: contact_account,
|
||||
email: email,
|
||||
},
|
||||
description: short_description || description,
|
||||
domain: uri,
|
||||
pleroma: {
|
||||
...pleroma,
|
||||
metadata: {
|
||||
...pleroma.metadata,
|
||||
description_limit,
|
||||
},
|
||||
},
|
||||
registrations: {
|
||||
approval_required: approval_required,
|
||||
enabled: registrations,
|
||||
},
|
||||
thumbnail: { url: thumbnail },
|
||||
};
|
||||
}, coerceObject({
|
||||
account_domain: z.string().catch(''),
|
||||
configuration: configurationSchema,
|
||||
contact: contactSchema,
|
||||
description: z.string().catch(''),
|
||||
domain: z.string().catch(''),
|
||||
feature_quote: z.boolean().catch(false),
|
||||
fedibird_capabilities: z.array(z.string()).catch([]),
|
||||
languages: z.string().array().catch([]),
|
||||
pleroma: pleromaSchema,
|
||||
registrations: registrations,
|
||||
rules: filteredArray(ruleSchema),
|
||||
stats: statsSchema,
|
||||
thumbnail: thumbnailSchema,
|
||||
title: z.string().catch(''),
|
||||
usage: usageSchema,
|
||||
version: z.string().catch('0.0.0'),
|
||||
}).transform(({ configuration, ...instance }) => {
|
||||
const version = fixVersion(instance.version);
|
||||
|
||||
const polls = {
|
||||
...configuration.polls,
|
||||
max_characters_per_option: configuration.polls.max_characters_per_option ?? 25,
|
||||
max_expiration: configuration.polls.max_expiration ?? 2629746,
|
||||
max_options: configuration.polls.max_options ?? 4,
|
||||
min_expiration: configuration.polls.min_expiration ?? 300,
|
||||
};
|
||||
|
||||
const statuses = {
|
||||
...configuration.statuses,
|
||||
max_characters: configuration.statuses.max_characters ?? 500,
|
||||
max_media_attachments: configuration.statuses.max_media_attachments ?? 4,
|
||||
};
|
||||
|
||||
return {
|
||||
...instance,
|
||||
configuration: {
|
||||
...configuration,
|
||||
polls,
|
||||
statuses,
|
||||
},
|
||||
version,
|
||||
};
|
||||
}));
|
||||
|
||||
type Instance = z.infer<typeof instanceSchema>;
|
||||
|
||||
export { instanceSchema, type Instance };
|
33
packages/pl-api/lib/entities/interaction-policy.ts
Normal file
33
packages/pl-api/lib/entities/interaction-policy.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { coerceObject } from './utils';
|
||||
|
||||
const interactionPolicyEntrySchema = z.enum(['public', 'followers', 'following', 'mutuals', 'mentioned', 'author', 'me']);
|
||||
|
||||
const interactionPolicyRuleSchema = coerceObject({
|
||||
always: z.array(interactionPolicyEntrySchema).default(['public']),
|
||||
with_approval: z.array(interactionPolicyEntrySchema).default([]),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.gotosocial.org/en/latest/api/swagger/} */
|
||||
const interactionPolicySchema = coerceObject({
|
||||
can_favourite: interactionPolicyRuleSchema,
|
||||
can_reblog: interactionPolicyRuleSchema,
|
||||
can_reply: interactionPolicyRuleSchema,
|
||||
});
|
||||
|
||||
type InteractionPolicy = Resolve<z.infer<typeof interactionPolicySchema>>;
|
||||
|
||||
const interactionPoliciesSchema = coerceObject({
|
||||
public: interactionPolicySchema,
|
||||
unlisted: interactionPolicySchema,
|
||||
private: interactionPolicySchema,
|
||||
direct: interactionPolicySchema,
|
||||
});
|
||||
|
||||
type InteractionPolicies = Resolve<z.infer<typeof interactionPoliciesSchema>>;
|
||||
|
||||
export { interactionPolicySchema, interactionPoliciesSchema, type InteractionPolicy, type InteractionPolicies };
|
||||
|
23
packages/pl-api/lib/entities/interaction-request.ts
Normal file
23
packages/pl-api/lib/entities/interaction-request.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { statusSchema } from './status';
|
||||
|
||||
/** @see {@link https://docs.gotosocial.org/en/latest/api/swagger.yaml#/definitions/interactionRequest} */
|
||||
const interactionRequestSchema = z.object({
|
||||
accepted_at: z.string().datetime().nullable().catch(null),
|
||||
account: accountSchema,
|
||||
created_at: z.string().datetime(),
|
||||
id: z.string(),
|
||||
rejected_at: z.string().datetime().nullable().catch(null),
|
||||
reply: statusSchema.nullable().catch(null),
|
||||
status: statusSchema.nullable().catch(null),
|
||||
type: z.enum(['favourite', 'reply', 'reblog']),
|
||||
uri: z.string().nullable().catch(null),
|
||||
});
|
||||
|
||||
type InteractionRequest = Resolve<z.infer<typeof interactionRequestSchema>>;
|
||||
|
||||
export { interactionRequestSchema, type InteractionRequest };
|
13
packages/pl-api/lib/entities/list.ts
Normal file
13
packages/pl-api/lib/entities/list.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/List/} */
|
||||
const listSchema = z.object({
|
||||
id: z.coerce.string(),
|
||||
title: z.string(),
|
||||
replies_policy: z.string().optional().catch(undefined),
|
||||
exclusive: z.boolean().optional().catch(undefined),
|
||||
});
|
||||
|
||||
type List = z.infer<typeof listSchema>;
|
||||
|
||||
export { listSchema, type List };
|
23
packages/pl-api/lib/entities/location.ts
Normal file
23
packages/pl-api/lib/entities/location.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
const locationSchema = z.object({
|
||||
url: z.string().url().catch(''),
|
||||
description: z.string().catch(''),
|
||||
country: z.string().catch(''),
|
||||
locality: z.string().catch(''),
|
||||
region: z.string().catch(''),
|
||||
postal_code: z.string().catch(''),
|
||||
street: z.string().catch(''),
|
||||
origin_id: z.string().catch(''),
|
||||
origin_provider: z.string().catch(''),
|
||||
type: z.string().catch(''),
|
||||
timezone: z.string().catch(''),
|
||||
geom: z.object({
|
||||
coordinates: z.tuple([z.number(), z.number()]).nullable().catch(null),
|
||||
srid: z.string().catch(''),
|
||||
}).nullable().catch(null),
|
||||
});
|
||||
|
||||
type Location = z.infer<typeof locationSchema>;
|
||||
|
||||
export { locationSchema, type Location };
|
27
packages/pl-api/lib/entities/marker.ts
Normal file
27
packages/pl-api/lib/entities/marker.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema } from './utils';
|
||||
|
||||
const markerSchema = z.preprocess((marker: any) => ({
|
||||
unread_count: marker.pleroma?.unread_count,
|
||||
...marker,
|
||||
}), z.object({
|
||||
last_read_id: z.string(),
|
||||
version: z.number().int(),
|
||||
updated_at: dateSchema,
|
||||
unread_count: z.number().int().optional().catch(undefined),
|
||||
}));
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Marker/} */
|
||||
type Marker = z.infer<typeof markerSchema>;
|
||||
|
||||
const markersSchema = z.record(markerSchema);
|
||||
|
||||
type Markers = z.infer<typeof markersSchema>;
|
||||
|
||||
export {
|
||||
markerSchema,
|
||||
markersSchema,
|
||||
type Marker,
|
||||
type Markers,
|
||||
};
|
105
packages/pl-api/lib/entities/media-attachment.ts
Normal file
105
packages/pl-api/lib/entities/media-attachment.ts
Normal file
|
@ -0,0 +1,105 @@
|
|||
import { isBlurhashValid } from 'blurhash';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { mimeSchema } from './utils';
|
||||
|
||||
const blurhashSchema = z.string().superRefine((value, ctx) => {
|
||||
const r = isBlurhashValid(value);
|
||||
|
||||
if (!r.result) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: r.errorReason,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const baseAttachmentSchema = z.object({
|
||||
id: z.string(),
|
||||
type: z.string(),
|
||||
url: z.string().url().catch(''),
|
||||
preview_url: z.string().url().catch(''),
|
||||
remote_url: z.string().url().nullable().catch(null),
|
||||
description: z.string().catch(''),
|
||||
blurhash: blurhashSchema.nullable().catch(null),
|
||||
|
||||
mime_type: mimeSchema.nullable().catch(null),
|
||||
});
|
||||
|
||||
const imageMetaSchema = z.object({
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
size: z.string().regex(/\d+x\d+$/).nullable().catch(null),
|
||||
aspect: z.number().nullable().catch(null),
|
||||
});
|
||||
|
||||
const imageAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('image'),
|
||||
meta: z.object({
|
||||
original: imageMetaSchema.optional().catch(undefined),
|
||||
small: imageMetaSchema.optional().catch(undefined),
|
||||
focus: z.object({
|
||||
x: z.number().min(-1).max(1),
|
||||
y: z.number().min(-1).max(1),
|
||||
}).optional().catch(undefined),
|
||||
}).catch({}),
|
||||
});
|
||||
|
||||
const videoAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('video'),
|
||||
meta: z.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),
|
||||
// WIP: add rest
|
||||
}).catch({}),
|
||||
});
|
||||
|
||||
const gifvAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('gifv'),
|
||||
meta: z.object({
|
||||
duration: z.number().optional().catch(undefined),
|
||||
original: imageMetaSchema.optional().catch(undefined),
|
||||
}).catch({}),
|
||||
});
|
||||
|
||||
const audioAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('audio'),
|
||||
meta: z.object({
|
||||
duration: z.number().optional().catch(undefined),
|
||||
colors: z.object({
|
||||
background: z.string().optional().catch(undefined),
|
||||
foreground: z.string().optional().catch(undefined),
|
||||
accent: z.string().optional().catch(undefined),
|
||||
duration: z.number().optional().catch(undefined),
|
||||
}).optional().catch(undefined),
|
||||
original: z.object({
|
||||
duration: z.number().optional().catch(undefined),
|
||||
bitrate: z.number().nonnegative().optional().catch(undefined),
|
||||
}).optional().catch(undefined),
|
||||
}).catch({}),
|
||||
});
|
||||
|
||||
const unknownAttachmentSchema = baseAttachmentSchema.extend({
|
||||
type: z.literal('unknown'),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/MediaAttachment} */
|
||||
const mediaAttachmentSchema = z.preprocess((data: any) => ({
|
||||
mime_type: data.pleroma?.mime_type,
|
||||
preview_url: data.url,
|
||||
...data,
|
||||
}), z.discriminatedUnion('type', [
|
||||
imageAttachmentSchema,
|
||||
videoAttachmentSchema,
|
||||
gifvAttachmentSchema,
|
||||
audioAttachmentSchema,
|
||||
unknownAttachmentSchema,
|
||||
]));
|
||||
|
||||
type MediaAttachment = z.infer<typeof mediaAttachmentSchema>;
|
||||
|
||||
export { blurhashSchema, mediaAttachmentSchema, type MediaAttachment };
|
19
packages/pl-api/lib/entities/mention.ts
Normal file
19
packages/pl-api/lib/entities/mention.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Status/#Mention} */
|
||||
const mentionSchema = z.object({
|
||||
id: z.string(),
|
||||
username: z.string().catch(''),
|
||||
url: z.string().url().catch(''),
|
||||
acct: z.string(),
|
||||
}).transform((mention) => {
|
||||
if (!mention.username) {
|
||||
mention.username = mention.acct.split('@')[0];
|
||||
}
|
||||
|
||||
return mention;
|
||||
});
|
||||
|
||||
type Mention = z.infer<typeof mentionSchema>;
|
||||
|
||||
export { mentionSchema, type Mention };
|
17
packages/pl-api/lib/entities/notification-policy.ts
Normal file
17
packages/pl-api/lib/entities/notification-policy.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/NotificationPolicy} */
|
||||
const notificationPolicySchema = z.object({
|
||||
filter_not_following: z.boolean(),
|
||||
filter_not_followers: z.boolean(),
|
||||
filter_new_accounts: z.boolean(),
|
||||
filter_private_mentions: z.boolean(),
|
||||
summary: z.object({
|
||||
pending_requests_count: z.number().int(),
|
||||
pending_notifications_count: z.number().int(),
|
||||
}),
|
||||
});
|
||||
|
||||
type NotificationPolicy = z.infer<typeof notificationPolicySchema>;
|
||||
|
||||
export { notificationPolicySchema, type NotificationPolicy };
|
19
packages/pl-api/lib/entities/notification-request.ts
Normal file
19
packages/pl-api/lib/entities/notification-request.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { dateSchema } from './utils';
|
||||
|
||||
import { accountSchema, statusSchema } from '.';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/NotificationRequest} */
|
||||
const notificationRequestSchema = z.object({
|
||||
id: z.string(),
|
||||
created_at: dateSchema,
|
||||
updated_at: dateSchema,
|
||||
account: accountSchema,
|
||||
notifications_count: z.coerce.string(),
|
||||
last_status: statusSchema.optional().catch(undefined),
|
||||
});
|
||||
|
||||
type NotificationRequest = z.infer<typeof notificationRequestSchema>;
|
||||
|
||||
export { notificationRequestSchema, type NotificationRequest };
|
100
packages/pl-api/lib/entities/notification.ts
Normal file
100
packages/pl-api/lib/entities/notification.ts
Normal file
|
@ -0,0 +1,100 @@
|
|||
import pick from 'lodash.pick';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { accountWarningSchema } from './account-warning';
|
||||
import { chatMessageSchema } from './chat-message';
|
||||
import { relationshipSeveranceEventSchema } from './relationship-severance-event';
|
||||
import { reportSchema } from './report';
|
||||
import { statusSchema } from './status';
|
||||
import { dateSchema } from './utils';
|
||||
|
||||
const baseNotificationSchema = z.object({
|
||||
account: accountSchema,
|
||||
created_at: dateSchema,
|
||||
id: z.string(),
|
||||
type: z.string(),
|
||||
|
||||
is_muted: z.boolean().optional().catch(undefined),
|
||||
is_seen: z.boolean().optional().catch(undefined),
|
||||
});
|
||||
|
||||
const accountNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.enum(['follow', 'follow_request', 'admin.sign_up', 'bite']),
|
||||
});
|
||||
|
||||
const statusNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.enum(['mention', 'status', 'reblog', 'favourite', 'poll', 'update', 'event_reminder']),
|
||||
status: statusSchema,
|
||||
});
|
||||
|
||||
const reportNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('admin.report'),
|
||||
report: reportSchema,
|
||||
});
|
||||
|
||||
const severedRelationshipNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('severed_relationships'),
|
||||
relationship_severance_event: relationshipSeveranceEventSchema,
|
||||
});
|
||||
|
||||
const moderationWarningNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('moderation_warning'),
|
||||
moderation_warning: accountWarningSchema,
|
||||
});
|
||||
|
||||
const moveNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('move'),
|
||||
target: accountSchema,
|
||||
});
|
||||
|
||||
const emojiReactionNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('emoji_reaction'),
|
||||
emoji: z.string(),
|
||||
emoji_url: z.string().nullable().catch(null),
|
||||
status: statusSchema,
|
||||
});
|
||||
|
||||
const chatMentionNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.literal('chat_mention'),
|
||||
chat_message: chatMessageSchema,
|
||||
});
|
||||
|
||||
const eventParticipationRequestNotificationSchema = baseNotificationSchema.extend({
|
||||
type: z.enum(['participation_accepted', 'participation_request']),
|
||||
status: statusSchema,
|
||||
participation_message: z.string().nullable().catch(null),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Notification/} */
|
||||
const notificationSchema: z.ZodType<Notification> = z.preprocess((notification: any) => ({
|
||||
...pick(notification.pleroma || {}, ['is_muted', 'is_seen']),
|
||||
...notification,
|
||||
type: notification.type === 'pleroma:report'
|
||||
? 'admin.report'
|
||||
: notification.type?.replace(/^pleroma:/, ''),
|
||||
}), z.discriminatedUnion('type', [
|
||||
accountNotificationSchema,
|
||||
statusNotificationSchema,
|
||||
reportNotificationSchema,
|
||||
severedRelationshipNotificationSchema,
|
||||
moderationWarningNotificationSchema,
|
||||
moveNotificationSchema,
|
||||
emojiReactionNotificationSchema,
|
||||
chatMentionNotificationSchema,
|
||||
eventParticipationRequestNotificationSchema,
|
||||
])) as any;
|
||||
|
||||
type Notification = z.infer<
|
||||
| typeof accountNotificationSchema
|
||||
| typeof statusNotificationSchema
|
||||
| typeof reportNotificationSchema
|
||||
| typeof severedRelationshipNotificationSchema
|
||||
| typeof moderationWarningNotificationSchema
|
||||
| typeof moveNotificationSchema
|
||||
| typeof emojiReactionNotificationSchema
|
||||
| typeof chatMentionNotificationSchema
|
||||
| typeof eventParticipationRequestNotificationSchema
|
||||
>;
|
||||
|
||||
export { notificationSchema, type Notification };
|
15
packages/pl-api/lib/entities/oauth-token.ts
Normal file
15
packages/pl-api/lib/entities/oauth-token.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.pleroma.social/backend/development/API/pleroma_api/#get-apioauth_tokens} */
|
||||
const oauthTokenSchema = z.preprocess((token: any) => ({
|
||||
...token,
|
||||
valid_until: token?.valid_until?.padEnd(27, 'Z'),
|
||||
}), z.object({
|
||||
app_name: z.string(),
|
||||
id: z.number(),
|
||||
valid_until: z.string().datetime({ offset: true }),
|
||||
}));
|
||||
|
||||
type OauthToken = z.infer<typeof oauthTokenSchema>;
|
||||
|
||||
export { oauthTokenSchema, type OauthToken };
|
32
packages/pl-api/lib/entities/poll.ts
Normal file
32
packages/pl-api/lib/entities/poll.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
import { filteredArray } from './utils';
|
||||
|
||||
const pollOptionSchema = z.object({
|
||||
title: z.string().catch(''),
|
||||
votes_count: z.number().catch(0),
|
||||
|
||||
title_map: z.record(z.string()).nullable().catch(null),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Poll/} */
|
||||
const pollSchema = z.object({
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
expired: z.boolean().catch(false),
|
||||
expires_at: z.string().datetime().nullable().catch(null),
|
||||
id: z.string(),
|
||||
multiple: z.boolean().catch(false),
|
||||
options: z.array(pollOptionSchema).min(2),
|
||||
voters_count: z.number().catch(0),
|
||||
votes_count: z.number().catch(0),
|
||||
own_votes: z.array(z.number()).nonempty().nullable().catch(null),
|
||||
voted: z.boolean().catch(false),
|
||||
|
||||
non_anonymous: z.boolean().catch(false),
|
||||
});
|
||||
|
||||
type Poll = z.infer<typeof pollSchema>;
|
||||
type PollOption = Poll['options'][number];
|
||||
|
||||
export { pollSchema, type Poll, type PollOption };
|
24
packages/pl-api/lib/entities/preview-card.ts
Normal file
24
packages/pl-api/lib/entities/preview-card.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/PreviewCard/} */
|
||||
const previewCardSchema = z.object({
|
||||
author_name: z.string().catch(''),
|
||||
author_url: z.string().url().catch(''),
|
||||
blurhash: z.string().nullable().catch(null),
|
||||
description: z.string().catch(''),
|
||||
embed_url: z.string().url().catch(''),
|
||||
height: z.number().catch(0),
|
||||
html: z.string().catch(''),
|
||||
image: z.string().nullable().catch(null),
|
||||
image_description: z.string().catch(''),
|
||||
provider_name: z.string().catch(''),
|
||||
provider_url: z.string().url().catch(''),
|
||||
title: z.string().catch(''),
|
||||
type: z.enum(['link', 'photo', 'video', 'rich']).catch('link'),
|
||||
url: z.string().url(),
|
||||
width: z.number().catch(0),
|
||||
});
|
||||
|
||||
type PreviewCard = z.infer<typeof previewCardSchema>;
|
||||
|
||||
export { previewCardSchema, type PreviewCard };
|
18
packages/pl-api/lib/entities/relationship-severance-event.ts
Normal file
18
packages/pl-api/lib/entities/relationship-severance-event.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { dateSchema } from './utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/RelationshipSeveranceEvent/} */
|
||||
const relationshipSeveranceEventSchema = z.object({
|
||||
id: z.string(),
|
||||
type: z.enum(['domain_block', 'user_domain_block', 'account_suspension']),
|
||||
purged: z.string(),
|
||||
relationships_count: z.number().optional().catch(undefined),
|
||||
created_at: dateSchema,
|
||||
});
|
||||
|
||||
type RelationshipSeveranceEvent = Resolve<z.infer<typeof relationshipSeveranceEventSchema>>;
|
||||
|
||||
export { relationshipSeveranceEventSchema, type RelationshipSeveranceEvent };
|
22
packages/pl-api/lib/entities/relationship.ts
Normal file
22
packages/pl-api/lib/entities/relationship.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import z from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Relationship/} */
|
||||
const relationshipSchema = z.object({
|
||||
blocked_by: z.boolean().catch(false),
|
||||
blocking: z.boolean().catch(false),
|
||||
domain_blocking: z.boolean().catch(false),
|
||||
endorsed: z.boolean().catch(false),
|
||||
followed_by: z.boolean().catch(false),
|
||||
following: z.boolean().catch(false),
|
||||
id: z.string(),
|
||||
muting: z.boolean().catch(false),
|
||||
muting_notifications: z.boolean().catch(false),
|
||||
note: z.string().catch(''),
|
||||
notifying: z.boolean().catch(false),
|
||||
requested: z.boolean().catch(false),
|
||||
showing_reblogs: z.boolean().catch(false),
|
||||
});
|
||||
|
||||
type Relationship = z.infer<typeof relationshipSchema>;
|
||||
|
||||
export { relationshipSchema, type Relationship };
|
22
packages/pl-api/lib/entities/report.ts
Normal file
22
packages/pl-api/lib/entities/report.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { dateSchema } from './utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Report/} */
|
||||
const reportSchema = z.object({
|
||||
id: z.string(),
|
||||
action_taken: z.boolean().optional().catch(undefined),
|
||||
action_taken_at: dateSchema.nullable().catch(null),
|
||||
category: z.string().optional().catch(undefined),
|
||||
comment: z.string().optional().catch(undefined),
|
||||
forwarded: z.boolean().optional().catch(undefined),
|
||||
created_at: dateSchema.optional().catch(undefined),
|
||||
status_ids: z.array(z.string()).nullable().catch(null),
|
||||
rule_ids: z.array(z.string()).nullable().catch(null),
|
||||
target_account: accountSchema,
|
||||
});
|
||||
|
||||
type Report = z.infer<typeof reportSchema>;
|
||||
|
||||
export { reportSchema, type Report };
|
18
packages/pl-api/lib/entities/role.ts
Normal file
18
packages/pl-api/lib/entities/role.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
const hexSchema = z.string().regex(/^#[a-f0-9]{6}$/i);
|
||||
|
||||
const roleSchema = z.object({
|
||||
id: z.string().catch(''),
|
||||
name: z.string().catch(''),
|
||||
color: hexSchema.catch(''),
|
||||
permissions: z.string().catch(''),
|
||||
highlighted: z.boolean().catch(true),
|
||||
});
|
||||
|
||||
type Role = z.infer<typeof roleSchema>;
|
||||
|
||||
export {
|
||||
roleSchema,
|
||||
type Role,
|
||||
};
|
17
packages/pl-api/lib/entities/rule.ts
Normal file
17
packages/pl-api/lib/entities/rule.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
const baseRuleSchema = z.object({
|
||||
id: z.string(),
|
||||
text: z.string().catch(''),
|
||||
hint: z.string().catch(''),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Rule/} */
|
||||
const ruleSchema = z.preprocess((data: any) => ({
|
||||
...data,
|
||||
hint: data.hint || data.subtext,
|
||||
}), baseRuleSchema);
|
||||
|
||||
type Rule = z.infer<typeof ruleSchema>;
|
||||
|
||||
export { ruleSchema, type Rule };
|
38
packages/pl-api/lib/entities/scheduled-status.ts
Normal file
38
packages/pl-api/lib/entities/scheduled-status.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { mediaAttachmentSchema } from './media-attachment';
|
||||
import { filteredArray } from './utils';
|
||||
|
||||
import type { Resolve } from '../utils/types';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/ScheduledStatus/} */
|
||||
const scheduledStatusSchema = z.object({
|
||||
id: z.string(),
|
||||
scheduled_at: z.string().datetime({ offset: true }),
|
||||
params: z.object({
|
||||
text: z.string().nullable().catch(null),
|
||||
poll: z.object({
|
||||
options: z.array(z.string()),
|
||||
expires_in: z.coerce.string(),
|
||||
multiple: z.boolean().optional().catch(undefined),
|
||||
hide_totals: z.boolean().optional().catch(undefined),
|
||||
}).nullable().catch(null),
|
||||
media_ids: z.array(z.string()).nullable().catch(null),
|
||||
sensitive: z.coerce.boolean().nullable().catch(null),
|
||||
spoiler_text: z.string().nullable().catch(null),
|
||||
visibility: z.string().catch('public'),
|
||||
in_reply_to_id: z.string().nullable().catch(null),
|
||||
language: z.string().nullable().catch(null),
|
||||
application_id: z.number().int().nullable().catch(null),
|
||||
scheduled_at: z.string().datetime({ offset: true }).nullable().catch(null),
|
||||
idempotency: z.string().nullable().catch(null),
|
||||
with_rate_limit: z.boolean().catch(false),
|
||||
|
||||
expires_in: z.number().nullable().catch(null),
|
||||
}),
|
||||
media_attachments: filteredArray(mediaAttachmentSchema),
|
||||
});
|
||||
|
||||
type ScheduledStatus = Resolve<z.infer<typeof scheduledStatusSchema>>;
|
||||
|
||||
export { scheduledStatusSchema, type ScheduledStatus };
|
17
packages/pl-api/lib/entities/search.ts
Normal file
17
packages/pl-api/lib/entities/search.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { filteredArray } from './utils';
|
||||
|
||||
import { accountSchema, groupSchema, statusSchema, tagSchema } from '.';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Search} */
|
||||
const searchSchema = z.object({
|
||||
accounts: filteredArray(accountSchema),
|
||||
statuses: filteredArray(statusSchema),
|
||||
hashtags: filteredArray(tagSchema),
|
||||
groups: filteredArray(groupSchema),
|
||||
});
|
||||
|
||||
type Search = z.infer<typeof searchSchema>;
|
||||
|
||||
export { searchSchema, type Search };
|
28
packages/pl-api/lib/entities/status-edit.ts
Normal file
28
packages/pl-api/lib/entities/status-edit.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
import { mediaAttachmentSchema } from './media-attachment';
|
||||
import { dateSchema, filteredArray } from './utils';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/StatusEdit/} */
|
||||
const statusEditSchema = z.object({
|
||||
content: z.string().catch(''),
|
||||
spoiler_text: z.string().catch(''),
|
||||
sensitive: z.coerce.boolean(),
|
||||
created_at: dateSchema,
|
||||
account: accountSchema,
|
||||
poll: z.object({
|
||||
options: z.array(z.object({
|
||||
title: z.string(),
|
||||
})),
|
||||
}).nullable().catch(null),
|
||||
media_attachments: filteredArray(mediaAttachmentSchema),
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
});
|
||||
|
||||
type StatusEdit = Resolve<z.infer<typeof statusEditSchema>>;
|
||||
|
||||
export { statusEditSchema, type StatusEdit };
|
22
packages/pl-api/lib/entities/status-source.ts
Normal file
22
packages/pl-api/lib/entities/status-source.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { locationSchema } from './location';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/StatusSource/} */
|
||||
const statusSourceSchema = z.object({
|
||||
id: z.string(),
|
||||
text: z.string().catch(''),
|
||||
spoiler_text: z.string().catch(''),
|
||||
|
||||
content_type: z.string().catch('text/plain'),
|
||||
location: locationSchema.nullable().catch(null),
|
||||
|
||||
text_map: z.record(z.string()).nullable().catch(null),
|
||||
spoiler_text_map: z.record(z.string()).nullable().catch(null),
|
||||
});
|
||||
|
||||
type StatusSource = Resolve<z.infer<typeof statusSourceSchema>>;
|
||||
|
||||
export { statusSourceSchema, type StatusSource };
|
151
packages/pl-api/lib/entities/status.ts
Normal file
151
packages/pl-api/lib/entities/status.ts
Normal file
|
@ -0,0 +1,151 @@
|
|||
import pick from 'lodash.pick';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
import { emojiReactionSchema } from './emoji-reaction';
|
||||
import { filterResultSchema } from './filter-result';
|
||||
import { groupSchema } from './group';
|
||||
import { interactionPolicySchema } from './interaction-policy';
|
||||
import { mediaAttachmentSchema } from './media-attachment';
|
||||
import { mentionSchema } from './mention';
|
||||
import { pollSchema } from './poll';
|
||||
import { previewCardSchema } from './preview-card';
|
||||
import { tagSchema } from './tag';
|
||||
import { translationSchema } from './translation';
|
||||
import { dateSchema, filteredArray } from './utils';
|
||||
|
||||
import type { Resolve } from '../utils/types';
|
||||
|
||||
const statusEventSchema = z.object({
|
||||
name: z.string().catch(''),
|
||||
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),
|
||||
participants_count: z.number().catch(0),
|
||||
location: z.object({
|
||||
name: z.string().catch(''),
|
||||
url: z.string().url().catch(''),
|
||||
latitude: z.number().catch(0),
|
||||
longitude: z.number().catch(0),
|
||||
street: z.string().catch(''),
|
||||
postal_code: z.string().catch(''),
|
||||
locality: z.string().catch(''),
|
||||
region: z.string().catch(''),
|
||||
country: z.string().catch(''),
|
||||
}).nullable().catch(null),
|
||||
join_state: z.enum(['pending', 'reject', 'accept']).nullable().catch(null),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Status/} */
|
||||
const baseStatusSchema = z.object({
|
||||
id: z.string(),
|
||||
uri: z.string().url().catch(''),
|
||||
created_at: dateSchema,
|
||||
account: accountSchema,
|
||||
content: z.string().catch(''),
|
||||
visibility: z.string().catch('public'),
|
||||
sensitive: z.coerce.boolean(),
|
||||
spoiler_text: z.string().catch(''),
|
||||
media_attachments: filteredArray(mediaAttachmentSchema),
|
||||
application: z.object({
|
||||
name: z.string(),
|
||||
website: z.string().url().nullable().catch(null),
|
||||
}).nullable().catch(null),
|
||||
mentions: filteredArray(mentionSchema),
|
||||
tags: filteredArray(tagSchema),
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
reblogs_count: z.number().catch(0),
|
||||
favourites_count: z.number().catch(0),
|
||||
replies_count: z.number().catch(0),
|
||||
url: z.string().url().catch(''),
|
||||
in_reply_to_id: z.string().nullable().catch(null),
|
||||
in_reply_to_account_id: z.string().nullable().catch(null),
|
||||
poll: pollSchema.nullable().catch(null),
|
||||
card: previewCardSchema.nullable().catch(null),
|
||||
language: z.string().nullable().catch(null),
|
||||
text: z.string().nullable().catch(null),
|
||||
edited_at: z.string().datetime().nullable().catch(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),
|
||||
group: groupSchema.nullable().catch(null),
|
||||
scheduled_at: z.null().catch(null),
|
||||
|
||||
local: z.boolean().optional().catch(undefined),
|
||||
conversation_id: z.string().optional().catch(undefined),
|
||||
direct_conversation_id: z.string().optional().catch(undefined),
|
||||
in_reply_to_account_acct: z.string().optional().catch(undefined),
|
||||
expires_at: z.string().datetime({ offset: true }).optional().catch(undefined),
|
||||
thread_muted: z.boolean().optional().catch(undefined),
|
||||
emoji_reactions: filteredArray(emojiReactionSchema),
|
||||
parent_visible: z.boolean().optional().catch(undefined),
|
||||
pinned_at: z.string().datetime({ offset: true }).nullable().catch(null),
|
||||
quote_visible: z.boolean().optional().catch(undefined),
|
||||
quote_url: z.string().optional().catch(undefined),
|
||||
quotes_count: z.number().catch(0),
|
||||
bookmark_folder: z.string().nullable().catch(null),
|
||||
|
||||
event: statusEventSchema.nullable().catch(null),
|
||||
translation: translationSchema.nullable().or(z.literal(false)).catch(null),
|
||||
|
||||
content_map: z.record(z.string()).nullable().catch(null),
|
||||
text_map: z.record(z.string()).nullable().catch(null),
|
||||
spoiler_text_map: z.record(z.string()).nullable().catch(null),
|
||||
|
||||
dislikes_count: z.number().catch(0),
|
||||
disliked: z.coerce.boolean().catch(false),
|
||||
|
||||
interaction_policy: interactionPolicySchema,
|
||||
});
|
||||
|
||||
const preprocess = (status: any) => {
|
||||
if (!status) return null;
|
||||
status = {
|
||||
...(pick(status.pleroma || {}, [
|
||||
'quote',
|
||||
'local',
|
||||
'conversation_id',
|
||||
'direct_conversation_id',
|
||||
'in_reply_to_account_acct',
|
||||
'expires_at',
|
||||
'thread_muted',
|
||||
'emoji_reactions',
|
||||
'parent_visible',
|
||||
'pinned_at',
|
||||
'quotes_count',
|
||||
'bookmark_folder',
|
||||
|
||||
'event',
|
||||
'translation',
|
||||
])),
|
||||
...(pick(status.friendica || {}, [
|
||||
'dislikes_count',
|
||||
'disliked',
|
||||
])),
|
||||
...status,
|
||||
};
|
||||
|
||||
return status;
|
||||
};
|
||||
|
||||
const statusSchema = z.preprocess(preprocess, baseStatusSchema.extend({
|
||||
reblog: z.lazy(() => baseStatusSchema).nullable().catch(null),
|
||||
|
||||
quote: z.lazy(() => baseStatusSchema).nullable().catch(null),
|
||||
}));
|
||||
|
||||
const statusWithoutAccountSchema = z.preprocess(preprocess, baseStatusSchema.omit({ account: true }).extend({
|
||||
account: accountSchema.nullable().catch(null),
|
||||
reblog: z.lazy(() => baseStatusSchema).nullable().catch(null),
|
||||
|
||||
quote: z.lazy(() => baseStatusSchema).nullable().catch(null),
|
||||
}));
|
||||
|
||||
type Status = Resolve<z.infer<typeof statusSchema>>;
|
||||
|
||||
export { statusSchema, statusWithoutAccountSchema, type Status };
|
117
packages/pl-api/lib/entities/streaming-event.ts
Normal file
117
packages/pl-api/lib/entities/streaming-event.ts
Normal file
|
@ -0,0 +1,117 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { announcementSchema } from './announcement';
|
||||
import { announcementReactionSchema } from './announcement-reaction';
|
||||
import { chatSchema } from './chat';
|
||||
import { conversationSchema } from './conversation';
|
||||
import { notificationSchema } from './notification';
|
||||
import { statusSchema } from './status';
|
||||
|
||||
const followRelationshipUpdateSchema = z.object({
|
||||
state: z.enum(['follow_pending', 'follow_accept', 'follow_reject']),
|
||||
follower: z.object({
|
||||
id: z.string(),
|
||||
follower_count: z.number().nullable().catch(null),
|
||||
following_count: z.number().nullable().catch(null),
|
||||
}),
|
||||
following: z.object({
|
||||
id: z.string(),
|
||||
follower_count: z.number().nullable().catch(null),
|
||||
following_count: z.number().nullable().catch(null),
|
||||
}),
|
||||
});
|
||||
|
||||
type FollowRelationshipUpdate = z.infer<typeof followRelationshipUpdateSchema>;
|
||||
|
||||
const baseStreamingEventSchema = z.object({
|
||||
stream: z.array(z.string()).catch([]),
|
||||
});
|
||||
|
||||
const statusStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.enum(['update', 'status.update']),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), statusSchema),
|
||||
});
|
||||
|
||||
const stringStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.enum(['delete', 'announcement.delete']),
|
||||
payload: z.string(),
|
||||
});
|
||||
|
||||
const notificationStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('notification'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), notificationSchema),
|
||||
});
|
||||
|
||||
const emptyStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('filters_changed'),
|
||||
});
|
||||
|
||||
const conversationStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('conversation'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), conversationSchema),
|
||||
});
|
||||
|
||||
const announcementStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('announcement'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), announcementSchema),
|
||||
});
|
||||
|
||||
const announcementReactionStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('announcement.reaction'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), announcementReactionSchema),
|
||||
});
|
||||
|
||||
const chatUpdateStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('chat_update'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), chatSchema),
|
||||
});
|
||||
|
||||
const followRelationshipsUpdateStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('follow_relationships_update'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), followRelationshipUpdateSchema),
|
||||
});
|
||||
|
||||
const respondStreamingEventSchema = baseStreamingEventSchema.extend({
|
||||
event: z.literal('respond'),
|
||||
payload: z.preprocess((payload: any) => JSON.parse(payload), z.object({
|
||||
type: z.string(),
|
||||
result: z.enum(['success', 'ignored', 'error']),
|
||||
})),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/methods/streaming/#events} */
|
||||
const streamingEventSchema: z.ZodType<StreamingEvent> = z.preprocess((event: any) => ({
|
||||
...event,
|
||||
event: event.event?.replace(/^pleroma:/, ''),
|
||||
}), z.discriminatedUnion('event', [
|
||||
statusStreamingEventSchema,
|
||||
stringStreamingEventSchema,
|
||||
notificationStreamingEventSchema,
|
||||
emptyStreamingEventSchema,
|
||||
conversationStreamingEventSchema,
|
||||
announcementStreamingEventSchema,
|
||||
announcementReactionStreamingEventSchema,
|
||||
chatUpdateStreamingEventSchema,
|
||||
followRelationshipsUpdateStreamingEventSchema,
|
||||
respondStreamingEventSchema,
|
||||
])) as any;
|
||||
|
||||
type StreamingEvent = z.infer<
|
||||
| typeof statusStreamingEventSchema
|
||||
| typeof stringStreamingEventSchema
|
||||
| typeof notificationStreamingEventSchema
|
||||
| typeof emptyStreamingEventSchema
|
||||
| typeof conversationStreamingEventSchema
|
||||
| typeof announcementStreamingEventSchema
|
||||
| typeof announcementReactionStreamingEventSchema
|
||||
| typeof chatUpdateStreamingEventSchema
|
||||
| typeof followRelationshipsUpdateStreamingEventSchema
|
||||
| typeof respondStreamingEventSchema
|
||||
>;
|
||||
|
||||
export {
|
||||
followRelationshipUpdateSchema,
|
||||
streamingEventSchema,
|
||||
type FollowRelationshipUpdate,
|
||||
type StreamingEvent,
|
||||
};
|
25
packages/pl-api/lib/entities/suggestion.ts
Normal file
25
packages/pl-api/lib/entities/suggestion.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { accountSchema } from './account';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Suggestion} */
|
||||
const suggestionSchema = z.preprocess((suggestion: any) => {
|
||||
/**
|
||||
* Support `/api/v1/suggestions`
|
||||
* @see {@link https://docs.joinmastodon.org/methods/suggestions/#v1}
|
||||
*/
|
||||
if (suggestion?.acct) return {
|
||||
source: 'staff',
|
||||
sources: 'featured',
|
||||
account: suggestion,
|
||||
};
|
||||
return suggestion;
|
||||
}, z.object({
|
||||
source: z.string(),
|
||||
sources: z.array(z.string()),
|
||||
account: accountSchema,
|
||||
}));
|
||||
|
||||
type Suggestion = z.infer<typeof suggestionSchema>;
|
||||
|
||||
export { suggestionSchema, type Suggestion };
|
19
packages/pl-api/lib/entities/tag.ts
Normal file
19
packages/pl-api/lib/entities/tag.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
const historySchema = z.object({
|
||||
day: z.coerce.number(),
|
||||
accounts: z.coerce.number(),
|
||||
uses: z.coerce.number(),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/tag} */
|
||||
const tagSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
url: z.string().url().catch(''),
|
||||
history: z.array(historySchema).nullable().catch(null),
|
||||
following: z.boolean().optional().catch(undefined),
|
||||
});
|
||||
|
||||
type Tag = z.infer<typeof tagSchema>;
|
||||
|
||||
export { historySchema, tagSchema, type Tag };
|
18
packages/pl-api/lib/entities/token.ts
Normal file
18
packages/pl-api/lib/entities/token.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Token/} */
|
||||
const tokenSchema = z.object({
|
||||
access_token: z.string(),
|
||||
token_type: z.string(),
|
||||
scope: z.string(),
|
||||
created_at: z.number().optional().catch(undefined),
|
||||
|
||||
id: z.number().optional().catch(undefined),
|
||||
refresh_token: z.string().optional().catch(undefined),
|
||||
expires_in: z.number().optional().catch(undefined),
|
||||
me: z.string().optional().catch(undefined),
|
||||
});
|
||||
|
||||
type Token = z.infer<typeof tokenSchema>;
|
||||
|
||||
export { tokenSchema, type Token };
|
43
packages/pl-api/lib/entities/translation.ts
Normal file
43
packages/pl-api/lib/entities/translation.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { Resolve } from '../utils/types';
|
||||
|
||||
import { filteredArray } from './utils';
|
||||
|
||||
const translationPollSchema = z.object({
|
||||
id: z.string(),
|
||||
options: z.array(z.object({
|
||||
title: z.string(),
|
||||
})),
|
||||
});
|
||||
|
||||
const translationMediaAttachment = z.object({
|
||||
id: z.string(),
|
||||
description: z.string().catch(''),
|
||||
});
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/Translation/} */
|
||||
const translationSchema = z.preprocess((translation: any) => {
|
||||
/**
|
||||
* handle Akkoma
|
||||
* @see {@link https://akkoma.dev/AkkomaGang/akkoma/src/branch/develop/lib/pleroma/web/mastodon_api/controllers/status_controller.ex#L504}
|
||||
*/
|
||||
if (translation?.text) return {
|
||||
content: translation.text,
|
||||
detected_source_language: translation.detected_language,
|
||||
provider: '',
|
||||
};
|
||||
|
||||
return translation;
|
||||
}, z.object({
|
||||
content: z.string().catch(''),
|
||||
spoiler_text: z.string().catch(''),
|
||||
poll: translationPollSchema.optional().catch(undefined),
|
||||
media_attachments: filteredArray(translationMediaAttachment),
|
||||
detected_source_language: z.string(),
|
||||
provider: z.string(),
|
||||
}));
|
||||
|
||||
type Translation = Resolve<z.infer<typeof translationSchema>>;
|
||||
|
||||
export { translationSchema, type Translation };
|
29
packages/pl-api/lib/entities/trends-link.ts
Normal file
29
packages/pl-api/lib/entities/trends-link.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { blurhashSchema } from './media-attachment';
|
||||
import { historySchema } from './tag';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/PreviewCard/#trends-link} */
|
||||
const trendsLinkSchema = z.preprocess((link: any) => ({ ...link, id: link.url }), z.object({
|
||||
id: z.string().catch(''),
|
||||
url: z.string().url().catch(''),
|
||||
title: z.string().catch(''),
|
||||
description: z.string().catch(''),
|
||||
type: z.enum(['link', 'photo', 'video', 'rich']).catch('link'),
|
||||
author_name: z.string().catch(''),
|
||||
author_url: z.string().catch(''),
|
||||
provider_name: z.string().catch(''),
|
||||
provider_url: z.string().catch(''),
|
||||
html: z.string().catch(''),
|
||||
width: z.number().nullable().catch(null),
|
||||
height: z.number().nullable().catch(null),
|
||||
image: z.string().nullable().catch(null),
|
||||
image_description: z.string().nullable().catch(null),
|
||||
embed_url: z.string().catch(''),
|
||||
blurhash: blurhashSchema.nullable().catch(null),
|
||||
history: z.array(historySchema).nullable().catch(null),
|
||||
}));
|
||||
|
||||
type TrendsLink = z.infer<typeof trendsLinkSchema>;
|
||||
|
||||
export { trendsLinkSchema, type TrendsLink };
|
26
packages/pl-api/lib/entities/utils.ts
Normal file
26
packages/pl-api/lib/entities/utils.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import z from 'zod';
|
||||
|
||||
/** Validate to Mastodon's date format, or use the current date. */
|
||||
const dateSchema = z.string().datetime({ offset: true }).catch(new Date().toUTCString());
|
||||
|
||||
/** Validates individual items in an array, dropping any that aren't valid. */
|
||||
const filteredArray = <T extends z.ZodTypeAny>(schema: T) =>
|
||||
z.any().array().catch([])
|
||||
.transform((arr) => (
|
||||
arr.map((item) => {
|
||||
const parsed = schema.safeParse(item);
|
||||
return parsed.success ? parsed.data : undefined;
|
||||
}).filter((item): item is z.infer<T> => Boolean(item))
|
||||
));
|
||||
|
||||
/** Validates the string as an emoji. */
|
||||
const emojiSchema = z.string().refine((v) => /\p{Extended_Pictographic}|[\u{1F1E6}-\u{1F1FF}]{2}/u.test(v));
|
||||
|
||||
/** MIME schema, eg `image/png`. */
|
||||
const mimeSchema = z.string().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) =>
|
||||
z.object({}).passthrough().catch({}).pipe(z.object(shape));
|
||||
|
||||
export { filteredArray, emojiSchema, dateSchema, mimeSchema, coerceObject };
|
13
packages/pl-api/lib/entities/web-push-subscription.ts
Normal file
13
packages/pl-api/lib/entities/web-push-subscription.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/** @see {@link https://docs.joinmastodon.org/entities/WebPushSubscription/} */
|
||||
const webPushSubscriptionSchema = z.object({
|
||||
id: z.coerce.string(),
|
||||
endpoint: z.string(),
|
||||
alerts: z.record(z.boolean()),
|
||||
server_key: z.string(),
|
||||
});
|
||||
|
||||
type WebPushSubscription = z.infer<typeof webPushSubscriptionSchema>;
|
||||
|
||||
export { webPushSubscriptionSchema, type WebPushSubscription };
|
1188
packages/pl-api/lib/features.ts
Normal file
1188
packages/pl-api/lib/features.ts
Normal file
File diff suppressed because it is too large
Load diff
6
packages/pl-api/lib/main.ts
Normal file
6
packages/pl-api/lib/main.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export { PlApiClient } from './client';
|
||||
export { type Response as PlApiResponse } from './request';
|
||||
export * from './entities';
|
||||
export * from './features';
|
||||
export * from './params';
|
||||
export * from './responses';
|
67
packages/pl-api/lib/params/accounts.ts
Normal file
67
packages/pl-api/lib/params/accounts.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
import type { LanguageParam, OnlyEventsParam, OnlyMediaParam, PaginationParams, WithMutedParam, WithRelationshipsParam } from './common';
|
||||
|
||||
type GetAccountParams = WithMutedParam;
|
||||
|
||||
interface GetAccountStatusesParams extends PaginationParams, WithMutedParam, OnlyEventsParam, OnlyMediaParam, LanguageParam {
|
||||
/** Boolean. Filter out statuses in reply to a different account. */
|
||||
exclude_replies?: boolean;
|
||||
/** Boolean. Filter for pinned statuses only. Defaults to false, which includes all statuses. Pinned statuses do not receive special priority in the order of the returned results. */
|
||||
pinned?: boolean;
|
||||
/** String. Filter for statuses using a specific hashtag. */
|
||||
tagged?: string;
|
||||
}
|
||||
|
||||
type GetAccountFollowersParams = PaginationParams & WithRelationshipsParam;
|
||||
type GetAccountFollowingParams = PaginationParams & WithRelationshipsParam;
|
||||
|
||||
interface FollowAccountParams {
|
||||
/** Boolean. Receive this account’s reblogs in home timeline? Defaults to true. */
|
||||
reblogs?: boolean;
|
||||
/** Boolean. Receive notifications when this account posts a status? Defaults to false. */
|
||||
notify?: boolean;
|
||||
/**
|
||||
* Array of String (ISO 639-1 language two-letter code). Filter received statuses for these languages. If not provided, you will receive this account’s posts in all languages.
|
||||
* Requires `features.followAccountLangugaes`.
|
||||
*/
|
||||
languages?: string[];
|
||||
}
|
||||
|
||||
interface GetRelationshipsParams {
|
||||
/** Boolean. Whether relationships should be returned for suspended users, defaults to false. */
|
||||
with_suspended?: boolean;
|
||||
}
|
||||
|
||||
interface SearchAccountParams {
|
||||
/** Integer. Maximum number of results. Defaults to 40 accounts. Max 80 accounts. */
|
||||
limit?: number;
|
||||
/** Integer. Skip the first n results. */
|
||||
offset?: number;
|
||||
/** Boolean. Attempt WebFinger lookup. Defaults to false. Use this when `q` is an exact address. */
|
||||
resolve?: boolean;
|
||||
/** Boolean. Limit the search to users you are following. Defaults to false. */
|
||||
following?: boolean;
|
||||
}
|
||||
|
||||
interface ReportAccountParams {
|
||||
status_ids?: string[];
|
||||
comment?: string;
|
||||
forward?: boolean;
|
||||
category?: 'spam' | 'legal' | 'violation' | 'other';
|
||||
rule_ids?: string[];
|
||||
}
|
||||
|
||||
type GetAccountEndorsementsParams = WithRelationshipsParam;
|
||||
type GetAccountFavouritesParams = PaginationParams;
|
||||
|
||||
export type {
|
||||
GetAccountParams,
|
||||
GetAccountStatusesParams,
|
||||
GetAccountFollowersParams,
|
||||
GetAccountFollowingParams,
|
||||
FollowAccountParams,
|
||||
GetRelationshipsParams,
|
||||
SearchAccountParams,
|
||||
ReportAccountParams,
|
||||
GetAccountEndorsementsParams,
|
||||
GetAccountFavouritesParams,
|
||||
};
|
200
packages/pl-api/lib/params/admin.ts
Normal file
200
packages/pl-api/lib/params/admin.ts
Normal file
|
@ -0,0 +1,200 @@
|
|||
import type { PaginationParams } from './common';
|
||||
|
||||
interface AdminGetAccountsParams extends PaginationParams {
|
||||
/** String. Filter for `local` or `remote` accounts. */
|
||||
origin?: 'local' | 'remote';
|
||||
/** String. Filter for `active`, `pending`, `disabled`, `silenced`, or suspended accounts. */
|
||||
status?: 'active' | 'pending' | 'disabled' | 'silenced' | 'suspended';
|
||||
/** String. Filter for accounts with `staff` permissions (users that can manage reports). */
|
||||
permissions?: 'staff';
|
||||
/** Array of String. Filter for users with these roles. */
|
||||
role_ids?: string[];
|
||||
/** String. Lookup users invited by the account with this ID. */
|
||||
invited_by?: string;
|
||||
/** String. Search for the given username. */
|
||||
username?: string;
|
||||
/** String. Search for the given display name */
|
||||
display_name?: string;
|
||||
/** String. Filter by the given domain */
|
||||
by_domain?: string;
|
||||
/** String. Lookup a user with this email */
|
||||
email?: string;
|
||||
/** String. Lookup users with this IP address */
|
||||
ip?: string;
|
||||
}
|
||||
|
||||
type AdminAccountAction = 'none' | 'sensitive' | 'disable' | 'silence' | 'suspend';
|
||||
|
||||
interface AdminPerformAccountActionParams {
|
||||
/** String. The ID of an associated report that caused this action to be taken. */
|
||||
report_id?: string;
|
||||
/** String. The ID of a preset warning. */
|
||||
warning_preset_id?: string;
|
||||
/** String. Additional clarification for why this action was taken. */
|
||||
text?: string;
|
||||
/** Boolean. Should an email be sent to the user with the above information? */
|
||||
send_email_notification?: boolean;
|
||||
}
|
||||
|
||||
type AdminGetDomainBlocksParams = PaginationParams;
|
||||
|
||||
interface AdminCreateDomainBlockParams {
|
||||
/** String. Whether to apply a `silence`, `suspend`, or `noop` to the domain. Defaults to `silence` */
|
||||
severity?: 'silence' | 'suspend' | 'noop';
|
||||
/** Boolean. Whether media attachments should be rejected. Defaults to false */
|
||||
reject_media?: boolean;
|
||||
/** Boolean. Whether reports from this domain should be rejected. Defaults to false */
|
||||
reject_reports?: boolean;
|
||||
/** String. A private note about this domain block, visible only to admins. */
|
||||
private_comment?: string;
|
||||
/** String. A public note about this domain block, optionally shown on the about page. */
|
||||
public_comment?: string;
|
||||
/** Boolean. Whether to partially censor the domain when shown in public. Defaults to false */
|
||||
obfuscate?: boolean;
|
||||
}
|
||||
|
||||
type AdminUpdateDomainBlockParams = AdminCreateDomainBlockParams;
|
||||
|
||||
interface AdminGetReportsParams extends PaginationParams {
|
||||
/** Boolean. Filter for resolved reports? */
|
||||
resolved?: boolean;
|
||||
/** String. Filter for reports filed by this account. */
|
||||
account_id?: string;
|
||||
/** String. Filter for reports targeting this account. */
|
||||
target_account_id?: string;
|
||||
}
|
||||
|
||||
interface AdminUpdateReportParams {
|
||||
/** String. Change the classification of the report to `spam`, `violation`, or `other`. */
|
||||
category?: 'spam' | 'violation' | 'other';
|
||||
/** Array of Integer. For `violation` category reports, specify the ID of the exact rules broken. Rules and their IDs are available via [GET /api/v1/instance/rules](https://docs.joinmastodon.org/methods/instance/#rules) and [GET /api/v1/instance](https://docs.joinmastodon.org/methods/instance/#get). */
|
||||
rule_ids?: string[];
|
||||
}
|
||||
|
||||
interface AdminGetStatusesParams {
|
||||
limit?: number;
|
||||
local_only?: boolean;
|
||||
with_reblogs?: boolean;
|
||||
with_private?: boolean;
|
||||
}
|
||||
|
||||
interface AdminUpdateStatusParams {
|
||||
sensitive?: boolean;
|
||||
visibility?: 'public' | 'private' | 'unlisted';
|
||||
}
|
||||
|
||||
type AdminGetCanonicalEmailBlocks = PaginationParams;
|
||||
|
||||
type AdminDimensionKey = 'languages' | 'sources' | 'servers' | 'space_usage' | 'software_versions' | 'tag_servers' | 'tag_languages' | 'instance_accounts' | 'instance_languages';
|
||||
|
||||
interface AdminGetDimensionsParams {
|
||||
/** String (ISO 8601 Datetime). The start date for the time period. If a time is provided, it will be ignored. */
|
||||
start_at?: string;
|
||||
/** String (ISO 8601 Datetime). The end date for the time period. If a time is provided, it will be ignored. */
|
||||
end_at?: string;
|
||||
/** Integer. The maximum number of results to return for sources, servers, languages, tag or instance dimensions. */
|
||||
limit?: number;
|
||||
tag_servers?: {
|
||||
/** String. When tag_servers is one of the requested keys, you must provide a trending tag ID to obtain information about which servers are posting the tag. */
|
||||
id?: string;
|
||||
};
|
||||
tag_languages?: {
|
||||
/** String. When tag_languages is one of the requested keys, you must provide a trending tag ID to obtain information about which languages are posting the tag. */
|
||||
id?: string;
|
||||
};
|
||||
instance_accounts?: {
|
||||
/** String. When instance_accounts is one of the requested keys, you must provide a domain to obtain information about popular accounts from that server. */
|
||||
domain?: string;
|
||||
};
|
||||
instance_languages?: {
|
||||
/** String. When instance_accounts is one of the requested keys, you must provide a domain to obtain information about popular languages from that server. */
|
||||
domain?: string;
|
||||
};
|
||||
}
|
||||
|
||||
type AdminGetDomainAllowsParams = PaginationParams;
|
||||
|
||||
type AdminGetEmailDomainBlocksParams = PaginationParams;
|
||||
|
||||
type AdminGetIpBlocksParams = PaginationParams;
|
||||
|
||||
interface AdminCreateIpBlockParams {
|
||||
/** String. The IP address and prefix to block. Defaults to 0.0.0.0/32 */
|
||||
ip?: string;
|
||||
/** String. The policy to apply to this IP range: sign_up_requires_approval, sign_up_block, or no_access */
|
||||
severity: string;
|
||||
/** String. The reason for this IP block. */
|
||||
comment?: string;
|
||||
/** Integer. The number of seconds in which this IP block will expire. */
|
||||
expires_in?: number;
|
||||
}
|
||||
|
||||
type AdminUpdateIpBlockParams = Partial<AdminCreateIpBlockParams>;
|
||||
|
||||
type AdminMeasureKey = 'active_users' | 'new_users' | 'interactions' | 'opened_reports' | 'resolved_reports' | 'tag_accounts' | 'tag_uses' | 'tag_servers' | 'instance_accounts' | 'instance_media_attachments' | 'instance_reports' | 'instance_statuses' | 'instance_follows' | 'instance_followers';
|
||||
|
||||
interface AdminGetMeasuresParams {
|
||||
tag_accounts?: {
|
||||
/** String. When `tag_accounts` is one of the requested keys, you must provide a tag ID to obtain the measure of how many accounts used that hashtag in at least one status within the given time period. */
|
||||
id?: string;
|
||||
};
|
||||
tag_uses?: {
|
||||
/** String. When `tag_uses` is one of the requested keys, you must provide a tag ID to obtain the measure of how many statuses used that hashtag within the given time period. */
|
||||
id?: string;
|
||||
};
|
||||
tag_servers?: {
|
||||
/** String. When `tag_servers` is one of the requested keys, you must provide a tag ID to obtain the measure of how many servers used that hashtag in at least one status within the given time period. */
|
||||
id?: string;
|
||||
};
|
||||
instance_accounts?: {
|
||||
/** String. When `instance_accounts` is one of the requested keys, you must provide a remote domain to obtain the measure of how many accounts have been discovered from that server within the given time period. */
|
||||
domain?: string;
|
||||
};
|
||||
instance_media_attachments?: {
|
||||
/** String. When `instance_media_attachments` is one of the requested keys, you must provide a remote domain to obtain the measure of how much space is used by media attachments from that server within the given time period. */
|
||||
domain?: string;
|
||||
};
|
||||
instance_reports?: {
|
||||
/** String. When `instance_reports` is one of the requested keys, you must provide a remote domain to obtain the measure of how many reports have been filed against accounts from that server within the given time period. */
|
||||
domain?: string;
|
||||
};
|
||||
instance_statuses?: {
|
||||
/** String. When `instance_statuses` is one of the requested keys, you must provide a remote domain to obtain the measure of how many statuses originate from that server within the given time period. */
|
||||
domain?: string;
|
||||
};
|
||||
instance_follows?: {
|
||||
/** String. When `instance_follows` is one of the requested keys, you must provide a remote domain to obtain the measure of how many follows were performed on accounts from that server by local accounts within the given time period. */
|
||||
domain?: string;
|
||||
};
|
||||
instance_followers?: {
|
||||
/** String. When `instance_followers` is one of the requested keys, you must provide a remote domain to obtain the measure of how many follows were performed by accounts from that server on local accounts within the given time period. */
|
||||
domain?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface AdminGetGroupsParams {
|
||||
}
|
||||
|
||||
export type {
|
||||
AdminGetAccountsParams,
|
||||
AdminAccountAction,
|
||||
AdminPerformAccountActionParams,
|
||||
AdminGetDomainBlocksParams,
|
||||
AdminCreateDomainBlockParams,
|
||||
AdminUpdateDomainBlockParams,
|
||||
AdminGetReportsParams,
|
||||
AdminUpdateReportParams,
|
||||
AdminGetStatusesParams,
|
||||
AdminUpdateStatusParams,
|
||||
AdminGetCanonicalEmailBlocks,
|
||||
AdminDimensionKey,
|
||||
AdminGetDimensionsParams,
|
||||
AdminGetDomainAllowsParams,
|
||||
AdminGetEmailDomainBlocksParams,
|
||||
AdminGetIpBlocksParams,
|
||||
AdminCreateIpBlockParams,
|
||||
AdminUpdateIpBlockParams,
|
||||
AdminMeasureKey,
|
||||
AdminGetMeasuresParams,
|
||||
AdminGetGroupsParams,
|
||||
};
|
14
packages/pl-api/lib/params/apps.ts
Normal file
14
packages/pl-api/lib/params/apps.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
interface CreateApplicationParams {
|
||||
/** String. A name for your application */
|
||||
client_name: string;
|
||||
/** String. Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter. */
|
||||
redirect_uris: string;
|
||||
/** String. Space separated list of scopes. If none is provided, defaults to `read`. See [OAuth Scopes](https://docs.joinmastodon.org/api/oauth-scopes/) for a list of possible scopes. */
|
||||
scopes?: string;
|
||||
/** String. A URL to the homepage of your app */
|
||||
website?: string;
|
||||
}
|
||||
|
||||
export type {
|
||||
CreateApplicationParams,
|
||||
};
|
18
packages/pl-api/lib/params/chats.ts
Normal file
18
packages/pl-api/lib/params/chats.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { PaginationParams, WithMutedParam } from './common';
|
||||
|
||||
type GetChatsParams = PaginationParams & WithMutedParam;
|
||||
type GetChatMessagesParams = PaginationParams;
|
||||
|
||||
type CreateChatMessageParams = {
|
||||
content?: string;
|
||||
media_id: string;
|
||||
} | {
|
||||
content: string;
|
||||
media_id?: string;
|
||||
};
|
||||
|
||||
export type {
|
||||
GetChatsParams,
|
||||
GetChatMessagesParams,
|
||||
CreateChatMessageParams,
|
||||
};
|
59
packages/pl-api/lib/params/common.ts
Normal file
59
packages/pl-api/lib/params/common.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
interface PaginationParams {
|
||||
/** String. All results returned will be lesser than this ID. In effect, sets an upper bound on results. */
|
||||
max_id?: string;
|
||||
/** String. All results returned will be greater than this ID. In effect, sets a lower bound on results. */
|
||||
since_id?: string;
|
||||
/** Integer. Maximum number of results to return. */
|
||||
limit?: number;
|
||||
/** String. Returns results immediately newer than this ID. In effect, sets a cursor at this ID and paginates forward. */
|
||||
min_id?: string;
|
||||
}
|
||||
|
||||
interface WithMutedParam {
|
||||
/**
|
||||
* Boolean. Also show statuses from muted users. Default to false.
|
||||
*
|
||||
* Requires `features.timelinesWithMuted`.
|
||||
*/
|
||||
with_muted?: boolean;
|
||||
}
|
||||
|
||||
interface WithRelationshipsParam {
|
||||
/**
|
||||
* Embed relationships into accounts.
|
||||
* Supported by Pleroma.
|
||||
*/
|
||||
with_relationships?: boolean;
|
||||
}
|
||||
|
||||
interface OnlyMediaParam {
|
||||
/** Boolean. Show only statuses with media attached? Defaults to false. */
|
||||
only_media?: boolean;
|
||||
}
|
||||
|
||||
interface OnlyEventsParam {
|
||||
/**
|
||||
* Boolean. Filter out statuses without events.
|
||||
*
|
||||
* Requires `features.events`.
|
||||
*/
|
||||
only_events?: boolean;
|
||||
}
|
||||
|
||||
interface LanguageParam {
|
||||
/**
|
||||
* Fetch a translation in given language
|
||||
*
|
||||
* Requires `features.fetchStatusesWithTranslation`.
|
||||
*/
|
||||
language?: string;
|
||||
}
|
||||
|
||||
export type {
|
||||
PaginationParams,
|
||||
WithMutedParam,
|
||||
WithRelationshipsParam,
|
||||
OnlyMediaParam,
|
||||
OnlyEventsParam,
|
||||
LanguageParam,
|
||||
};
|
33
packages/pl-api/lib/params/events.ts
Normal file
33
packages/pl-api/lib/params/events.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { PaginationParams } from './common';
|
||||
|
||||
interface CreateEventParams {
|
||||
/** name of the event */
|
||||
name: string;
|
||||
/** optional, description of the event */
|
||||
status?: string;
|
||||
/** optional, event banner attachment ID */
|
||||
banner_id?: string;
|
||||
/** start time of the event */
|
||||
start_time?: string;
|
||||
/** optional, end time of the event */
|
||||
end_time?: string;
|
||||
/** optional, event join mode, either free or restricted, defaults to free */
|
||||
join_mode?: 'free' | 'restricted';
|
||||
/** optional, location ID from the location provider used by server */
|
||||
location_id?: string;
|
||||
/** string, contain the MIME type of the status. */
|
||||
content_type?: string;
|
||||
}
|
||||
|
||||
type EditEventParams = Partial<Omit<CreateEventParams, 'join_mode'>>;
|
||||
type GetJoinedEventsParams = PaginationParams;
|
||||
type GetEventParticipationsParams = PaginationParams;
|
||||
type GetEventParticipationRequestsParams = PaginationParams;
|
||||
|
||||
export type {
|
||||
CreateEventParams,
|
||||
EditEventParams,
|
||||
GetJoinedEventsParams,
|
||||
GetEventParticipationsParams,
|
||||
GetEventParticipationRequestsParams,
|
||||
};
|
48
packages/pl-api/lib/params/filtering.ts
Normal file
48
packages/pl-api/lib/params/filtering.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import type { PaginationParams, WithRelationshipsParam } from './common';
|
||||
|
||||
interface MuteAccountParams {
|
||||
/** Boolean. Mute notifications in addition to statuses? Defaults to true. */
|
||||
notifications?: boolean;
|
||||
/** Number. How long the mute should last, in seconds. Defaults to 0 (indefinite). */
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
type GetMutesParams = Omit<PaginationParams, 'min_id'> & WithRelationshipsParam;
|
||||
type GetBlocksParams = PaginationParams & WithRelationshipsParam;
|
||||
type GetDomainBlocksParams = PaginationParams;
|
||||
|
||||
type FilterContext = 'home' | 'notifications' | 'public' | 'thread' | 'account';
|
||||
|
||||
interface CreateFilterParams {
|
||||
title: string;
|
||||
context: Array<FilterContext>;
|
||||
filter_action?: 'warn' | 'hide';
|
||||
expires_in?: number;
|
||||
keywords_attributes: Array<{
|
||||
keyword: string;
|
||||
whole_word?: boolean;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface UpdateFilterParams {
|
||||
title?: string;
|
||||
context?: Array<FilterContext>;
|
||||
filter_action?: 'warn' | 'hide';
|
||||
expires_in?: number;
|
||||
keywords_attributes?: Array<{
|
||||
keyword: string;
|
||||
whole_word?: boolean;
|
||||
id?: string;
|
||||
_destroy?: boolean;
|
||||
}>;
|
||||
}
|
||||
|
||||
export type {
|
||||
MuteAccountParams,
|
||||
GetMutesParams,
|
||||
GetBlocksParams,
|
||||
GetDomainBlocksParams,
|
||||
FilterContext,
|
||||
CreateFilterParams,
|
||||
UpdateFilterParams,
|
||||
};
|
27
packages/pl-api/lib/params/groups.ts
Normal file
27
packages/pl-api/lib/params/groups.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import type { PaginationParams } from './common';
|
||||
|
||||
interface CreateGroupParams {
|
||||
display_name: string;
|
||||
note?: string;
|
||||
avatar?: File;
|
||||
header?: File;
|
||||
}
|
||||
|
||||
interface UpdateGroupParams {
|
||||
display_name?: string;
|
||||
note?: string;
|
||||
avatar?: File | '';
|
||||
header?: File | '';
|
||||
}
|
||||
|
||||
type GetGroupMembershipsParams = Omit<PaginationParams, 'min_id'>;
|
||||
type GetGroupMembershipRequestsParams = Omit<PaginationParams, 'min_id'>;
|
||||
type GetGroupBlocksParams = Omit<PaginationParams, 'min_id'>;
|
||||
|
||||
export type {
|
||||
CreateGroupParams,
|
||||
UpdateGroupParams,
|
||||
GetGroupMembershipsParams,
|
||||
GetGroupMembershipRequestsParams,
|
||||
GetGroupBlocksParams,
|
||||
};
|
21
packages/pl-api/lib/params/index.ts
Normal file
21
packages/pl-api/lib/params/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
export * from './accounts';
|
||||
export * from './admin';
|
||||
export * from './apps';
|
||||
export * from './chats';
|
||||
export * from './events';
|
||||
export * from './filtering';
|
||||
export * from './groups';
|
||||
export * from './instance';
|
||||
export * from './interaction-requests';
|
||||
export * from './lists';
|
||||
export * from './media';
|
||||
export * from './my-account';
|
||||
export * from './notifications';
|
||||
export * from './oauth';
|
||||
export * from './push-notifications';
|
||||
export * from './scheduled-statuses';
|
||||
export * from './search';
|
||||
export * from './settings';
|
||||
export * from './statuses';
|
||||
export * from './timelines';
|
||||
export * from './trends';
|
14
packages/pl-api/lib/params/instance.ts
Normal file
14
packages/pl-api/lib/params/instance.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
interface ProfileDirectoryParams {
|
||||
/** Number. Skip the first n results. */
|
||||
offset?: number;
|
||||
/** Number. How many accounts to load. Defaults to 40 accounts. Max 80 accounts. */
|
||||
limit?: number;
|
||||
/** String. Use active to sort by most recently posted statuses (default) or new to sort by most recently created profiles. */
|
||||
order?: string;
|
||||
/** Boolean. If true, returns only local accounts. */
|
||||
local?: boolean;
|
||||
}
|
||||
|
||||
export type {
|
||||
ProfileDirectoryParams,
|
||||
};
|
16
packages/pl-api/lib/params/interaction-requests.ts
Normal file
16
packages/pl-api/lib/params/interaction-requests.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { PaginationParams } from './common';
|
||||
|
||||
interface GetInteractionRequestsParams extends PaginationParams {
|
||||
/** If set, then only interactions targeting the given status_id will be included in the results. */
|
||||
status_id?: string;
|
||||
/** If true or not set, pending favourites will be included in the results. At least one of favourites, replies, and reblogs must be true. */
|
||||
favourites?: boolean;
|
||||
/** If true or not set, pending replies will be included in the results. At least one of favourites, replies, and reblogs must be true. */
|
||||
replies?: boolean;
|
||||
/** If true or not set, pending reblogs will be included in the results. At least one of favourites, replies, and reblogs must be true. */
|
||||
reblogs?: boolean;
|
||||
}
|
||||
|
||||
export type {
|
||||
GetInteractionRequestsParams,
|
||||
};
|
19
packages/pl-api/lib/params/lists.ts
Normal file
19
packages/pl-api/lib/params/lists.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import type { PaginationParams } from './common';
|
||||
|
||||
interface CreateListParams {
|
||||
/** String. The title of the list to be created. */
|
||||
title: string;
|
||||
/** String. One of followed, list, or none. Defaults to list. */
|
||||
replies_policy?: 'followed' | 'list' | 'none';
|
||||
/** Boolean. Whether members of this list need to get removed from the “Home” feed */
|
||||
exclusive?: boolean;
|
||||
}
|
||||
|
||||
type UpdateListParams = CreateListParams;
|
||||
type GetListAccountsParams = PaginationParams;
|
||||
|
||||
export type {
|
||||
CreateListParams,
|
||||
UpdateListParams,
|
||||
GetListAccountsParams,
|
||||
};
|
30
packages/pl-api/lib/params/media.ts
Normal file
30
packages/pl-api/lib/params/media.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
interface UploadMediaParams {
|
||||
/** Object. The file to be attached, encoded using multipart form data. The file must have a MIME type. */
|
||||
file: File;
|
||||
/** Object. The custom thumbnail of the media to be attached, encoded using multipart form data. */
|
||||
thumbnail?: File;
|
||||
/** String. A plain-text description of the media, for accessibility purposes. */
|
||||
description?: string;
|
||||
/**
|
||||
* String. Two floating points (x,y), comma-delimited, ranging from -1.0 to 1.0. See Focal points for cropping media thumbnails for more information.
|
||||
* @see {@link https://docs.joinmastodon.org/api/guidelines/#focal-points}
|
||||
*/
|
||||
focus?: string;
|
||||
}
|
||||
|
||||
interface UpdateMediaParams {
|
||||
/** Object. The custom thumbnail of the media to be attached, encoded using multipart form data. */
|
||||
thumbnail?: File;
|
||||
/** String. A plain-text description of the media, for accessibility purposes. */
|
||||
description?: string;
|
||||
/**
|
||||
* String. Two floating points (x,y), comma-delimited, ranging from -1.0 to 1.0. See Focal points for cropping media thumbnails for more information.
|
||||
* @see {@link https://docs.joinmastodon.org/api/guidelines/#focal-points}
|
||||
*/
|
||||
focus?: string;
|
||||
}
|
||||
|
||||
export type {
|
||||
UploadMediaParams,
|
||||
UpdateMediaParams,
|
||||
};
|
31
packages/pl-api/lib/params/my-account.ts
Normal file
31
packages/pl-api/lib/params/my-account.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import type { PaginationParams } from './common';
|
||||
|
||||
interface GetBookmarksParams extends PaginationParams {
|
||||
/**
|
||||
* Bookmark folder ID
|
||||
* Requires `features.bookmarkFolders`.
|
||||
*/
|
||||
folder_id?: string;
|
||||
}
|
||||
|
||||
type GetFavouritesParams = PaginationParams;
|
||||
type GetFollowRequestsParams = Omit<PaginationParams, 'min_id'>;
|
||||
type GetEndorsementsParams = Omit<PaginationParams, 'min_id'>;
|
||||
type GetFollowedTagsParams = PaginationParams;
|
||||
|
||||
interface CreateBookmarkFolderParams {
|
||||
name: string;
|
||||
emoji?: string;
|
||||
}
|
||||
|
||||
type UpdateBookmarkFolderParams = Partial<CreateBookmarkFolderParams>;
|
||||
|
||||
export type {
|
||||
GetBookmarksParams,
|
||||
GetFavouritesParams,
|
||||
GetFollowRequestsParams,
|
||||
GetEndorsementsParams,
|
||||
GetFollowedTagsParams,
|
||||
CreateBookmarkFolderParams,
|
||||
UpdateBookmarkFolderParams,
|
||||
};
|
34
packages/pl-api/lib/params/notifications.ts
Normal file
34
packages/pl-api/lib/params/notifications.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import type { PaginationParams } from './common';
|
||||
|
||||
interface GetNotificationParams extends PaginationParams {
|
||||
/** Array of String. Types to include in the result. */
|
||||
types?: string[];
|
||||
/** Array of String. Types to exclude from the results. */
|
||||
exclude_types?: string[];
|
||||
/** String. Return only notifications received from the specified account. */
|
||||
account_id?: string;
|
||||
/**
|
||||
* will exclude the notifications for activities with the given visibilities. The parameter accepts an array of visibility types (`public`, `unlisted`, `private`, `direct`).
|
||||
* Requires `features.notificationsExcludeVisibilities`.
|
||||
*/
|
||||
exclude_visibilities?: string[];
|
||||
}
|
||||
|
||||
interface UpdateNotificationPolicyRequest {
|
||||
/** Boolean. Whether to filter notifications from accounts the user is not following. */
|
||||
filter_not_following?: boolean;
|
||||
/** Boolean. Whether to filter notifications from accounts that are not following the user. */
|
||||
filter_not_followers?: boolean;
|
||||
/** Boolean. Whether to filter notifications from accounts created in the past 30 days. */
|
||||
filter_new_accounts?: boolean;
|
||||
/** Boolean. Whether to filter notifications from private mentions. Replies to private mentions initiated by the user, as well as accounts the user follows, are never filtered. */
|
||||
filter_private_mentions?: boolean;
|
||||
}
|
||||
|
||||
type GetNotificationRequestsParams = PaginationParams;
|
||||
|
||||
export type {
|
||||
GetNotificationParams,
|
||||
UpdateNotificationPolicyRequest,
|
||||
GetNotificationRequestsParams,
|
||||
};
|
54
packages/pl-api/lib/params/oauth.ts
Normal file
54
packages/pl-api/lib/params/oauth.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
interface OauthAuthorizeParams {
|
||||
/** String. Should be set equal to `code`. */
|
||||
response_type: string;
|
||||
/** String. The client ID, obtained during app registration. */
|
||||
client_id: string;
|
||||
/** String. Set a URI to redirect the user to. If this parameter is set to `urn:ietf:wg:oauth:2.0:oob` then the authorization code will be shown instead. Must match one of the `redirect_uris` declared during app registration. */
|
||||
redirect_uri: string;
|
||||
/** String. List of requested OAuth scopes, separated by spaces (or by pluses, if using query parameters). Must be a subset of `scopes` declared during app registration. If not provided, defaults to `read`. */
|
||||
scope?: string;
|
||||
/** Boolean. Forces the user to re-login, which is necessary for authorizing with multiple accounts from the same instance. */
|
||||
force_login?: boolean;
|
||||
/** String. The ISO 639-1 two-letter language code to use while rendering the authorization form. */
|
||||
lang?: string;
|
||||
}
|
||||
|
||||
interface GetTokenParams {
|
||||
/** String. Set equal to `authorization_code` if `code` is provided in order to gain user-level access. Otherwise, set equal to `client_credentials` to obtain app-level access only. */
|
||||
grant_type: string;
|
||||
/** String. A user authorization code, obtained via [GET /oauth/authorize](https://docs.joinmastodon.org/methods/oauth/#authorize). */
|
||||
code?: string;
|
||||
/** String. The client ID, obtained during app registration. */
|
||||
client_id: string;
|
||||
/** String. The client secret, obtained during app registration. */
|
||||
client_secret: string;
|
||||
/** String. Set a URI to redirect the user to. If this parameter is set to urn:ietf:wg:oauth:2.0:oob then the token will be shown instead. Must match one of the `redirect_uris` declared during app registration. */
|
||||
redirect_uri: string;
|
||||
/** String. List of requested OAuth scopes, separated by spaces (or by pluses, if using query parameters). If `code` was provided, then this must be equal to the `scope` requested from the user. Otherwise, it must be a subset of `scopes` declared during app registration. If not provided, defaults to `read`. */
|
||||
scope?: string;
|
||||
}
|
||||
|
||||
interface RevokeTokenParams {
|
||||
/** String. The client ID, obtained during app registration. */
|
||||
client_id: string;
|
||||
/** String. The client secret, obtained during app registration. */
|
||||
client_secret: string;
|
||||
/** String. The previously obtained token, to be invalidated. */
|
||||
token: string;
|
||||
}
|
||||
|
||||
interface MfaChallengeParams {
|
||||
client_id: string;
|
||||
client_secret: string;
|
||||
/** access token to check second step of mfa */
|
||||
mfa_token: string;
|
||||
challenge_type: 'totp' | 'recovery';
|
||||
code: string;
|
||||
}
|
||||
|
||||
export type {
|
||||
OauthAuthorizeParams,
|
||||
GetTokenParams,
|
||||
RevokeTokenParams,
|
||||
MfaChallengeParams,
|
||||
};
|
30
packages/pl-api/lib/params/push-notifications.ts
Normal file
30
packages/pl-api/lib/params/push-notifications.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
interface CreatePushNotificationsSubscriptionParams {
|
||||
subscription: {
|
||||
/** String. The endpoint URL that is called when a notification event occurs. */
|
||||
endpoint: string;
|
||||
keys?: {
|
||||
/** String. User agent public key. Base64 encoded string of a public key from a ECDH keypair using the prime256v1 curve. */
|
||||
p256dh: string;
|
||||
/** String. Auth secret. Base64 encoded string of 16 bytes of random data. */
|
||||
auth: string;
|
||||
};
|
||||
};
|
||||
data?: {
|
||||
alerts?: Record<string, boolean>;
|
||||
/** String. Specify whether to receive push notifications from `all`, `followed`, `follower`, or `none` users. */
|
||||
policy?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface UpdatePushNotificationsSubscriptionParams {
|
||||
data?: {
|
||||
alerts?: Record<string, boolean>;
|
||||
};
|
||||
/** String. Specify whether to receive push notifications from `all`, `followed`, `follower`, or `none` users. */
|
||||
policy?: string;
|
||||
}
|
||||
|
||||
export type {
|
||||
CreatePushNotificationsSubscriptionParams,
|
||||
UpdatePushNotificationsSubscriptionParams,
|
||||
};
|
7
packages/pl-api/lib/params/scheduled-statuses.ts
Normal file
7
packages/pl-api/lib/params/scheduled-statuses.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import type { PaginationParams } from './common';
|
||||
|
||||
type GetScheduledStatusesParams = PaginationParams;
|
||||
|
||||
export type {
|
||||
GetScheduledStatusesParams,
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue