feat: build new API library / request builder

This commit is contained in:
Paul Makles
2022-03-20 00:18:41 +00:00
parent c357434a66
commit 5163e1b552
34 changed files with 12039 additions and 24598 deletions
+8022 -19364
View File
File diff suppressed because it is too large Load Diff
+11 -16
View File
@@ -1,6 +1,6 @@
{
"name": "revolt-api",
"version": "0.5.3-alpha.12",
"version": "0.5.3-rc.1",
"description": "Revolt API typings",
"main": "dist/index.js",
"type": "module",
@@ -9,23 +9,18 @@
"author": "Paul Makles <insrt.uk>",
"license": "MIT",
"scripts": {
"build:generator": "tsc",
"start:generator": "node .",
"watch:generator": "tsc-watch",
"redoc": "docker run --network host -e SPEC_URL=http://localhost:5500/OpenAPI.json redocly/redoc",
"preview": "sirv . --port 5500 --host",
"dev": "concurrently \"yarn redoc\" \"nodemon --exec \\\"yarn build:generator && yarn start:generator && yarn preview\\\"\"",
"open": "concurrently \"yarn redoc\" \"yarn preview\" \"open-cli http://localhost:80\""
"build": "tsc",
"watch": "tsc-watch --onSuccess \"node --experimental-specifier-resolution=node dist\"",
"routes": "node scripts/generate_routes.js",
"exports": "node scripts/generate_exports.js",
"convert": "openapi-typescript OpenAPI.json --output src/schema.ts && node scripts/generate_routes.js && node scripts/generate_exports.js"
},
"devDependencies": {
"@openapi-contrib/json-schema-to-openapi-schema": "^2.0.0",
"concurrently": "^6.2.0",
"nodemon": "^2.0.12",
"open-cli": "^7.0.0",
"openapi-types": "^9.1.0",
"sirv-cli": "^1.0.12",
"tsc-watch": "^4.4.0",
"typescript": "^4.3.5",
"typescript-json-schema": "^0.50.1"
"typescript": "^4.3.5"
},
"dependencies": {
"axios": "^0.26.1",
"openapi-typescript": "^5.2.0"
}
}
+17
View File
@@ -0,0 +1,17 @@
import { readFile, writeFile } from 'fs/promises';
const NOTICE = `// This file was auto-generated!\n`;
readFile('OpenAPI.json')
.then(data => {
const entries = ["import { components } from './schema';"];
const spec = JSON.parse(data);
const schemas = spec.components.schemas;
for (const schema of Object.keys(schemas)) {
entries.push(`export type ${schema} = components['schemas']['${schema}'];`);
}
writeFile('src/types.ts', NOTICE + entries.join('\n') + ";");
});
+81
View File
@@ -0,0 +1,81 @@
import { readFile, writeFile } from 'fs/promises';
const NOTICE = `// This file was auto-generated!\n`;
readFile('OpenAPI.json')
.then(data => {
const entries = ["import { paths } from './schema';", "export type APIRoutes ="];
const spec = JSON.parse(data);
const paths = Object.keys(spec.paths);
const queryData = {};
for (const path of paths) {
const data = spec.paths[path];
const methods = Object.keys(data);
const template = path.replace(/\{\w+\}/g, '${string}');
for (const method of methods) {
const OPERATION = `paths['${path}']['${method}']`;
const route = data[method];
const response = Object.keys(route['responses']).find(x => x !== 'default') ?? 'default';
const contentType = Object.keys(route['responses'][response]['content'] ?? {})[0];
const RESPONSE = response === '204' || !contentType ? 'undefined' : `${OPERATION}['responses']['${response}']['content']['${contentType}']`;
let queryParams = [];
let hasBody = false;
if (route['parameters']) {
for (const parameter of route['parameters']) {
if (parameter.in === 'query') {
queryParams.push(parameter.name);
}
}
}
if (route['requestBody']?.['content']?.['application/json']) {
hasBody = true;
}
let params = 'undefined';
if (hasBody || queryParams.length > 0) {
let entries = [];
if (queryParams.length > 0) {
entries.push(`${OPERATION}['parameters']['query']`);
}
if (hasBody) {
entries.push(`${OPERATION}['requestBody']['content']['application/json']`);
}
params = entries.join('|');
}
const object = `{ method: '${method}', path: \`${template}\`, params: ${params}, response: ${RESPONSE} }`;
entries.push(`| ${object}`);
queryData[path] = {
...queryData[path],
[method]: queryParams,
};
}
}
const pathResolve = {};
for (const path of paths) {
const segments = path.split('/');
segments.shift();
pathResolve[segments.length] = [
...(pathResolve[segments.length] ?? []),
segments.map(key => /\{.*\}/.test(key) ? [key] : key)
];
}
writeFile('src/routes.ts', NOTICE + entries.join('\n') + ";");
writeFile('src/params.ts', NOTICE
+ "export const pathResolve = " + JSON.stringify(pathResolve) + ";\n"
+ "export const queryParams = " + JSON.stringify(queryData) + ";");
});
+215 -43
View File
@@ -1,52 +1,224 @@
import { writeFile } from 'fs/promises';
import type { OpenAPIV3 } from "openapi-types";
import type * as TJS from "typescript-json-schema";
export * from './types';
type Document = OpenAPIV3.Document & { definitions?: TJS.Definition };
import type { Session } from './types';
import type { APIRoutes } from './routes';
import Axios, { AxiosRequestConfig } from 'axios';
import info from './openapi/info.js';
import definitions from './openapi/definitions.js';
import paths, { group, tags } from './openapi/paths.js';
import { pathResolve, queryParams } from './params';
import './routes/index.js';
/**
* Get the specific path name of any given path.
* @param anyPath Any path
* @returns Specific path
*/
export function getPathName(anyPath: string) {
const segments = anyPath.split('/');
async function generate(): Promise<Document> {
return {
['__comment' as any]: "THIS FILE WAS AUTO-GENERATED USING https://github.com/revoltchat/api. DO NOT EDIT.",
openapi: "3.0.0",
info: await info(),
tags,
// Redoc tag groups
['x-tagGroups' as any]: group(),
paths: await paths(),
definitions: await definitions(),
servers: [
{
"url": "https://api.revolt.chat",
"description": "Production instance of the Revolt API"
}
],
components: {
securitySchemes: {
'Session Token': {
type: "apiKey",
in: "header",
name: "x-session-token",
description: "Session is created by calling `/session/login`.\n"
},
'Bot Token': {
type: "apiKey",
in: "header",
name: "x-bot-token",
description: "Generate a bot token in-app by going to [\"My Bots\"](https://app.revolt.chat/settings/bots) in user settings.\n"
}
const list = (pathResolve as unknown as Record<string, (string | [string])[]>)[(segments.length - 1).toString()] ?? [];
for (const entry of list) {
let i = 1;
let copy = [...segments];
for (i;i<segments.length;i++) {
if (Array.isArray(entry[i - 1])) {
copy[i] = entry[i - 1];
continue;
}
else if (entry[i - 1] !== segments[i]) break;
}
if (i === segments.length) return copy.join('/');
}
}
generate()
.then(v =>
writeFile('OpenAPI.json', JSON.stringify(v, undefined, 2))
);
type Methods = APIRoutes['method'];
type PickRoutes<Method extends Methods> = APIRoutes & { method: Method };
type GetRoutes = PickRoutes<'get'>;
type PatchRoutes = PickRoutes<'patch'>;
type PutRoutes = PickRoutes<'put'>;
type DeleteRoutes = PickRoutes<'delete'>;
type PostRoutes = PickRoutes<'post'>;
/**
* Client configuration options
*/
export interface Options {
/**
* Base URL of the Revolt node
*/
baseURL: string;
/**
* Authentication used for requests
*/
authentication: Session | string | undefined;
}
/**
* Revolt API Client
*/
export class RevoltAPI {
private baseURL: string;
private authentication: Session | string | undefined;
constructor({ baseURL, authentication }: Partial<Options> = { }) {
this.baseURL = baseURL ?? 'https://api.revolt.chat';
this.authentication = authentication;
}
/**
* Generate config to pass through to API.
*/
get config(): AxiosRequestConfig {
return {
baseURL: this.baseURL,
headers: typeof this.authentication === 'string'
? { 'X-Bot-Token': this.authentication }
: typeof this.authentication === 'object'
? { 'X-Session-Token': this.authentication.token }
: undefined
};
}
/**
* Send any arbitrary request.
* @param method HTTP Method
* @param path Path
* @param params Body or Query Parameters
* @param config Axios configuration
* @returns Typed Response Data
*/
req<Method extends Methods, Routes extends PickRoutes<Method>, Path extends Routes['path'], Route extends Routes & { path: Path }>(method: Method, path: Path, params: Route['params'], config?: AxiosRequestConfig): Promise<Route['response']> {
let query, body;
let named = getPathName(path);
// If we are aware of this route, then match the parameters given.
if (named && typeof params === 'object') {
const route = queryParams[named as keyof typeof queryParams];
const allowed_query = (route as unknown as Record<Method, string[]>)[method];
// Map each parameter to the correct object.
for (const parameter of Object.keys(params)) {
if (allowed_query.includes(parameter)) {
query = {
...(query ?? {}),
[parameter]: (params as Record<any, any>)[parameter]
};
} else {
body = {
...(body ?? {}),
[parameter]: (params as Record<any, any>)[parameter]
};
}
}
}
return Axios(path, {
...this.config,
...config,
method,
params: query,
data: body
})
.then(res => res.data);
}
/**
* Send HTTP GET request.
* @param path Path
* @param params Body or Query Parameters
* @param config Axios configuration
* @returns Typed Response Data
*/
get<Path extends GetRoutes['path'], Route extends GetRoutes & { path: Path }>(path: Path, params: Route['params'], config?: AxiosRequestConfig): Promise<Route['response']>;
/**
* Send HTTP GET request.
* @param path Path
* @returns Typed Response Data
*/
get<Path extends (GetRoutes & { params: undefined })['path'], Route extends GetRoutes & { path: Path }>(path: Path): Promise<Route['response']>;
get(path: any, params?: any, config?: AxiosRequestConfig): Promise<any> {
return this.req('get', path, params, config);
}
/**
* Send HTTP GET request.
* @param path Path
* @param params Body or Query Parameters
* @param config Axios configuration
* @returns Typed Response Data
*/
patch<Path extends PatchRoutes['path'], Route extends PatchRoutes & { path: Path }>(path: Path, params: Route['params'], config?: AxiosRequestConfig): Promise<Route['response']>;
/**
* Send HTTP PATCH request.
* @param path Path
* @returns Typed Response Data
*/
patch<Path extends (PatchRoutes & { params: undefined })['path'], Route extends PatchRoutes & { path: Path }>(path: Path): Promise<Route['response']>;
patch(path: any, params?: any, config?: AxiosRequestConfig): Promise<any> {
return this.req('patch', path, params, config);
}
/**
* Send HTTP PUT request.
* @param path Path
* @param params Body or Query Parameters
* @param config Axios configuration
* @returns Typed Response Data
*/
put<Path extends PutRoutes['path'], Route extends PutRoutes & { path: Path }>(path: Path, params: Route['params'], config?: AxiosRequestConfig): Promise<Route['response']>;
/**
* Send HTTP PUT request.
* @param path Path
* @returns Typed Response Data
*/
put<Path extends (PutRoutes & { params: undefined })['path'], Route extends PutRoutes & { path: Path }>(path: Path): Promise<Route['response']>;
put(path: any, params?: any, config?: AxiosRequestConfig): Promise<any> {
return this.req('put', path, params, config);
}
/**
* Send HTTP DELETE request.
* @param path Path
* @param params Body or Query Parameters
* @param config Axios configuration
* @returns Typed Response Data
*/
delete<Path extends DeleteRoutes['path'], Route extends DeleteRoutes & { path: Path }>(path: Path, config?: AxiosRequestConfig): Promise<Route['response']>;
/**
* Send HTTP DELETE request.
* @param path Path
* @returns Typed Response Data
*/
delete<Path extends (DeleteRoutes & { params: undefined })['path'], Route extends DeleteRoutes & { path: Path }>(path: Path): Promise<Route['response']>;
delete(path: any, config?: AxiosRequestConfig): Promise<any> {
return this.req('delete', path, undefined, config);
}
/**
* Send HTTP POST request.
* @param path Path
* @param params Body or Query Parameters
* @param config Axios configuration
* @returns Typed Response Data
*/
post<Path extends PostRoutes['path'], Route extends PostRoutes & { path: Path }>(path: Path, params: Route['params'], config?: AxiosRequestConfig): Promise<Route['response']>;
/**
* Send HTTP POST request.
* @param path Path
* @returns Typed Response Data
*/
post<Path extends (PostRoutes & { params: undefined })['path'], Route extends PostRoutes & { path: Path }>(path: Path): Promise<Route['response']>;
post(path: any, params?: any, config?: AxiosRequestConfig): Promise<any> {
return this.req('post', path, params, config);
}
}
-25
View File
@@ -1,25 +0,0 @@
import convert from '@openapi-contrib/json-schema-to-openapi-schema';
import { generator, type_files } from '../typescript.js';
import * as TJS from "typescript-json-schema";
import { readFileSync } from "fs";
const TYPE_RE = /(?:type|enum|interface) (\w+)/g
export default async function() {
let types: string[] = [];
for (const path of type_files) {
const f = readFileSync(path).toString();
types = types.concat([...f.matchAll(TYPE_RE)].map(x => x[1]));
}
let definitions: { [key: string]: TJS.Definition } = {};
for (let type of types) {
try {
const defn = generator.getSchemaForSymbol(type);
if (defn) {
definitions[type] = await convert(defn);
}
} catch (err) {}
}
return definitions;
}
-54
View File
@@ -1,54 +0,0 @@
import { OpenAPIV3 } from "openapi-types";
export async function success(description: string, json?: Promise<OpenAPIV3.MediaTypeObject> | OpenAPIV3.MediaTypeObject | OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject): Promise<{ responses: OpenAPIV3.ResponsesObject }> {
const response: OpenAPIV3.ResponseObject = {
description
};
if (json) {
response.content = {
"application/json": {
schema: await json
}
}
}
return { responses: { "200": response } };
}
export async function noContent(description: string): Promise<{ responses: OpenAPIV3.ResponsesObject }> {
const response: OpenAPIV3.ResponseObject = {
description
};
return { responses: { "204": response } };
}
export async function body(description: string, json: Promise<OpenAPIV3.MediaTypeObject> | OpenAPIV3.MediaTypeObject | OpenAPIV3.ReferenceObject): Promise<{ requestBody: OpenAPIV3.RequestBodyObject }> {
return {
requestBody: {
description,
content: {
"application/json": {
"schema": await json
}
}
}
};
}
export async function parameter(name: string, description: string, json: Promise<OpenAPIV3.SchemaObject> | OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject): Promise<OpenAPIV3.ParameterObject> {
return {
name,
in: 'path',
required: true,
description,
schema: await json
}
}
export function ref(id: string) {
return {
$ref: `#/definitions/${id}`
}
}
-27
View File
@@ -1,27 +0,0 @@
import { OpenAPIV3 } from "openapi-types";
import { readFile } from "fs/promises";
export default async function(): Promise<OpenAPIV3.InfoObject> {
return {
"title": "Revolt API",
"version": await readFile('package.json').then(v => JSON.parse(v.toString()).version),
"description": `User-first privacy focused chat platform built with modern web technologies.
# Authentication
Currently all relevant requests are authenticated by the use of two headers which identify a session.
<SecurityDefinitions />`,
"termsOfService": "https://revolt.chat/terms",
"contact": {
"name": "API Support",
"email": "contact@revolt.chat",
"url": "https://revolt.chat"
},
// Redoc logo
["x-logo" as any]: {
"url": "https://revolt.chat/header.png",
"altText": "Revolt Header"
},
}
}
-73
View File
@@ -1,73 +0,0 @@
import { OpenAPIV3 } from "openapi-types";
export var tags: OpenAPIV3.TagObject[] = [];
var groups: { name: string, tags: string[] }[] = [];
var resources: OpenAPIV3.PathsObject<{}> = {};
var currentTag: string | undefined;
var accumulatedTags: string[] = [];
var currentGroup: string | undefined;
export function group(name?: string) {
if (accumulatedTags.length > 0) {
if (currentGroup) {
groups.push({
name: currentGroup,
tags: accumulatedTags
});
}
accumulatedTags = [];
}
if (name) {
currentGroup = name;
} else {
return groups;
}
}
export function tag(name: string, description: string) {
accumulatedTags.push(name);
currentTag = name;
tags.push({
name,
description
});
}
export function resource(path: string, methods: OpenAPIV3.PathItemObject) {
console.info(`Generating resource ${path}.`);
if (resources[path]) throw `Resource ${path} already exists!`;
resources[path] = methods;
}
export function route(summary: string, description: string, obj: Omit<OpenAPIV3.OperationObject, 'summary' | 'tags'>): OpenAPIV3.OperationObject {
return {
summary,
description,
tags: currentTag ? [ currentTag ] : [ ],
...obj
}
}
export function routeAuthenticated(summary: string, description: string, obj: Omit<OpenAPIV3.OperationObject, 'summary' | 'tags'>, disallowBots?: boolean): OpenAPIV3.OperationObject {
return {
...route(summary, description, obj),
security: disallowBots ? [
{
'Session Token': []
}
] : [
{
'Session Token': []
},
{
'Bot Token': []
}
]
}
}
export default async function(): Promise<OpenAPIV3.PathsObject<{}>> {
return resources;
}
+3
View File
@@ -0,0 +1,3 @@
// This file was auto-generated!
export const pathResolve = {"1":[[""]],"2":[["users","@me"],["users",["{target}"]],["users","dms"],["bots","create"],["bots",["{target}"]],["bots","@me"],["channels",["{target}"]],["channels","create"],["servers","create"],["servers",["{target}"]],["invites",["{target}"]],["onboard","hello"],["onboard","complete"],["push","subscribe"],["push","unsubscribe"],["sync","unreads"]],"3":[["users","@me","username"],["users",["{target}"],"default_avatar"],["users",["{target}"],"profile"],["users",["{target}"],"dm"],["users",["{target}"],"mutual"],["users",["{username}"],"friend"],["users",["{target}"],"friend"],["users",["{target}"],"block"],["bots",["{target}"],"invite"],["channels",["{target}"],"members"],["channels",["{target}"],"invites"],["channels",["{target}"],"messages"],["channels",["{target}"],"search"],["channels",["{_target}"],"join_call"],["servers",["{target}"],"ack"],["servers",["{target}"],"channels"],["servers",["{target}"],"members"],["servers",["{target}"],"bans"],["servers",["{target}"],"invites"],["servers",["{target}"],"roles"],["auth","account","create"],["auth","account","reverify"],["auth","account",""],["auth","account","reset_password"],["auth","session","login"],["auth","session","logout"],["auth","session","all"],["auth","session",["{id}"]],["sync","settings","fetch"],["sync","settings","set"]],"4":[["channels",["{target}"],"ack",["{message}"]],["channels",["{_target}"],"messages","stale"],["channels",["{target}"],"messages",["{msg}"]],["channels",["{target}"],"recipients",["{member}"]],["channels",["{target}"],"permissions",["{role_id}"]],["channels",["{target}"],"permissions","default"],["servers",["{target}"],"members",["{member}"]],["servers",["{server}"],"members",["{target}"]],["servers",["{server}"],"bans",["{target}"]],["servers",["{target}"],"roles",["{role_id}"]],["servers",["{target}"],"permissions",["{role_id}"]],["servers",["{target}"],"permissions","default"],["auth","account","change","password"],["auth","account","change","email"],["auth","account","verify",["{code}"]]]};
export const queryParams = {"/":{"get":[]},"/users/@me":{"get":[],"patch":[]},"/users/{target}":{"get":[]},"/users/@me/username":{"patch":[]},"/users/{target}/default_avatar":{"get":[]},"/users/{target}/profile":{"get":[]},"/users/dms":{"get":[]},"/users/{target}/dm":{"get":[]},"/users/{target}/mutual":{"get":[]},"/users/{username}/friend":{"put":[]},"/users/{target}/friend":{"delete":[]},"/users/{target}/block":{"put":[],"delete":[]},"/bots/create":{"post":[]},"/bots/{target}/invite":{"get":[],"post":[]},"/bots/{target}":{"get":[],"delete":[],"patch":[]},"/bots/@me":{"get":[]},"/channels/{target}/ack/{message}":{"put":[]},"/channels/{target}":{"get":[],"delete":[],"patch":[]},"/channels/{target}/members":{"get":[]},"/channels/{target}/invites":{"post":[]},"/channels/{target}/messages":{"get":["limit","before","after","sort","nearby","include_users"],"post":[]},"/channels/{target}/search":{"post":[]},"/channels/{_target}/messages/stale":{"post":[]},"/channels/{target}/messages/{msg}":{"get":[],"delete":[],"patch":[]},"/channels/create":{"post":[]},"/channels/{target}/recipients/{member}":{"put":[],"delete":[]},"/channels/{_target}/join_call":{"post":[]},"/channels/{target}/permissions/{role_id}":{"put":[]},"/channels/{target}/permissions/default":{"put":[]},"/servers/create":{"post":[]},"/servers/{target}":{"get":[],"delete":[],"patch":[]},"/servers/{target}/ack":{"put":[]},"/servers/{target}/channels":{"post":[]},"/servers/{target}/members":{"get":[]},"/servers/{target}/members/{member}":{"get":[],"delete":[]},"/servers/{server}/members/{target}":{"patch":[]},"/servers/{server}/bans/{target}":{"put":[],"delete":[]},"/servers/{target}/bans":{"get":[]},"/servers/{target}/invites":{"get":[]},"/servers/{target}/roles":{"post":[]},"/servers/{target}/roles/{role_id}":{"delete":[],"patch":[]},"/servers/{target}/permissions/{role_id}":{"put":[]},"/servers/{target}/permissions/default":{"put":[]},"/invites/{target}":{"get":[],"post":[],"delete":[]},"/auth/account/create":{"post":[]},"/auth/account/reverify":{"post":[]},"/auth/account/":{"get":[]},"/auth/account/change/password":{"patch":[]},"/auth/account/change/email":{"patch":[]},"/auth/account/verify/{code}":{"post":[]},"/auth/account/reset_password":{"post":[],"patch":[]},"/auth/session/login":{"post":[]},"/auth/session/logout":{"post":[]},"/auth/session/all":{"get":[],"delete":["revoke_self"]},"/auth/session/{id}":{"delete":[],"patch":[]},"/onboard/hello":{"get":[]},"/onboard/complete":{"post":[]},"/push/subscribe":{"post":[]},"/push/unsubscribe":{"post":[]},"/sync/settings/fetch":{"post":[]},"/sync/settings/set":{"post":["timestamp"]},"/sync/unreads":{"get":[]}};
+86
View File
@@ -0,0 +1,86 @@
// This file was auto-generated!
import { paths } from './schema';
export type APIRoutes =
| { method: 'get', path: `/`, params: undefined, response: paths['/']['get']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/users/@me`, params: undefined, response: paths['/users/@me']['get']['responses']['200']['content']['application/json'] }
| { method: 'patch', path: `/users/@me`, params: paths['/users/@me']['patch']['requestBody']['content']['application/json'], response: paths['/users/@me']['patch']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/users/${string}`, params: undefined, response: paths['/users/{target}']['get']['responses']['200']['content']['application/json'] }
| { method: 'patch', path: `/users/@me/username`, params: paths['/users/@me/username']['patch']['requestBody']['content']['application/json'], response: paths['/users/@me/username']['patch']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/users/${string}/default_avatar`, params: undefined, response: paths['/users/{target}/default_avatar']['get']['responses']['200']['content']['image/png'] }
| { method: 'get', path: `/users/${string}/profile`, params: undefined, response: paths['/users/{target}/profile']['get']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/users/dms`, params: undefined, response: paths['/users/dms']['get']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/users/${string}/dm`, params: undefined, response: paths['/users/{target}/dm']['get']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/users/${string}/mutual`, params: undefined, response: paths['/users/{target}/mutual']['get']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/users/${string}/friend`, params: undefined, response: paths['/users/{username}/friend']['put']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/users/${string}/friend`, params: undefined, response: paths['/users/{target}/friend']['delete']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/users/${string}/block`, params: undefined, response: paths['/users/{target}/block']['put']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/users/${string}/block`, params: undefined, response: paths['/users/{target}/block']['delete']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/bots/create`, params: paths['/bots/create']['post']['requestBody']['content']['application/json'], response: paths['/bots/create']['post']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/bots/${string}/invite`, params: undefined, response: paths['/bots/{target}/invite']['get']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/bots/${string}/invite`, params: paths['/bots/{target}/invite']['post']['requestBody']['content']['application/json'], response: undefined }
| { method: 'get', path: `/bots/${string}`, params: undefined, response: paths['/bots/{target}']['get']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/bots/${string}`, params: undefined, response: undefined }
| { method: 'patch', path: `/bots/${string}`, params: paths['/bots/{target}']['patch']['requestBody']['content']['application/json'], response: paths['/bots/{target}']['patch']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/bots/@me`, params: undefined, response: paths['/bots/@me']['get']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/channels/${string}/ack/${string}`, params: undefined, response: undefined }
| { method: 'get', path: `/channels/${string}`, params: undefined, response: paths['/channels/{target}']['get']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/channels/${string}`, params: undefined, response: undefined }
| { method: 'patch', path: `/channels/${string}`, params: paths['/channels/{target}']['patch']['requestBody']['content']['application/json'], response: paths['/channels/{target}']['patch']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/channels/${string}/members`, params: undefined, response: paths['/channels/{target}/members']['get']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/channels/${string}/invites`, params: undefined, response: paths['/channels/{target}/invites']['post']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/channels/${string}/messages`, params: paths['/channels/{target}/messages']['get']['parameters']['query'], response: paths['/channels/{target}/messages']['get']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/channels/${string}/messages`, params: paths['/channels/{target}/messages']['post']['requestBody']['content']['application/json'], response: paths['/channels/{target}/messages']['post']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/channels/${string}/search`, params: paths['/channels/{target}/search']['post']['requestBody']['content']['application/json'], response: paths['/channels/{target}/search']['post']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/channels/${string}/messages/stale`, params: paths['/channels/{_target}/messages/stale']['post']['requestBody']['content']['application/json'], response: undefined }
| { method: 'get', path: `/channels/${string}/messages/${string}`, params: undefined, response: paths['/channels/{target}/messages/{msg}']['get']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/channels/${string}/messages/${string}`, params: undefined, response: undefined }
| { method: 'patch', path: `/channels/${string}/messages/${string}`, params: paths['/channels/{target}/messages/{msg}']['patch']['requestBody']['content']['application/json'], response: paths['/channels/{target}/messages/{msg}']['patch']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/channels/create`, params: paths['/channels/create']['post']['requestBody']['content']['application/json'], response: paths['/channels/create']['post']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/channels/${string}/recipients/${string}`, params: undefined, response: undefined }
| { method: 'delete', path: `/channels/${string}/recipients/${string}`, params: undefined, response: undefined }
| { method: 'post', path: `/channels/${string}/join_call`, params: undefined, response: paths['/channels/{_target}/join_call']['post']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/channels/${string}/permissions/${string}`, params: paths['/channels/{target}/permissions/{role_id}']['put']['requestBody']['content']['application/json'], response: paths['/channels/{target}/permissions/{role_id}']['put']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/channels/${string}/permissions/default`, params: paths['/channels/{target}/permissions/default']['put']['requestBody']['content']['application/json'], response: paths['/channels/{target}/permissions/default']['put']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/servers/create`, params: paths['/servers/create']['post']['requestBody']['content']['application/json'], response: paths['/servers/create']['post']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/servers/${string}`, params: undefined, response: paths['/servers/{target}']['get']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/servers/${string}`, params: undefined, response: undefined }
| { method: 'patch', path: `/servers/${string}`, params: paths['/servers/{target}']['patch']['requestBody']['content']['application/json'], response: paths['/servers/{target}']['patch']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/servers/${string}/ack`, params: undefined, response: undefined }
| { method: 'post', path: `/servers/${string}/channels`, params: paths['/servers/{target}/channels']['post']['requestBody']['content']['application/json'], response: paths['/servers/{target}/channels']['post']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/servers/${string}/members`, params: undefined, response: paths['/servers/{target}/members']['get']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/servers/${string}/members/${string}`, params: undefined, response: paths['/servers/{target}/members/{member}']['get']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/servers/${string}/members/${string}`, params: undefined, response: undefined }
| { method: 'patch', path: `/servers/${string}/members/${string}`, params: paths['/servers/{server}/members/{target}']['patch']['requestBody']['content']['application/json'], response: paths['/servers/{server}/members/{target}']['patch']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/servers/${string}/bans/${string}`, params: paths['/servers/{server}/bans/{target}']['put']['requestBody']['content']['application/json'], response: paths['/servers/{server}/bans/{target}']['put']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/servers/${string}/bans/${string}`, params: undefined, response: undefined }
| { method: 'get', path: `/servers/${string}/bans`, params: undefined, response: paths['/servers/{target}/bans']['get']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/servers/${string}/invites`, params: undefined, response: paths['/servers/{target}/invites']['get']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/servers/${string}/roles`, params: paths['/servers/{target}/roles']['post']['requestBody']['content']['application/json'], response: paths['/servers/{target}/roles']['post']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/servers/${string}/roles/${string}`, params: undefined, response: undefined }
| { method: 'patch', path: `/servers/${string}/roles/${string}`, params: paths['/servers/{target}/roles/{role_id}']['patch']['requestBody']['content']['application/json'], response: paths['/servers/{target}/roles/{role_id}']['patch']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/servers/${string}/permissions/${string}`, params: paths['/servers/{target}/permissions/{role_id}']['put']['requestBody']['content']['application/json'], response: paths['/servers/{target}/permissions/{role_id}']['put']['responses']['200']['content']['application/json'] }
| { method: 'put', path: `/servers/${string}/permissions/default`, params: paths['/servers/{target}/permissions/default']['put']['requestBody']['content']['application/json'], response: paths['/servers/{target}/permissions/default']['put']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/invites/${string}`, params: undefined, response: paths['/invites/{target}']['get']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/invites/${string}`, params: undefined, response: paths['/invites/{target}']['post']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/invites/${string}`, params: undefined, response: undefined }
| { method: 'post', path: `/auth/account/create`, params: paths['/auth/account/create']['post']['requestBody']['content']['application/json'], response: undefined }
| { method: 'post', path: `/auth/account/reverify`, params: paths['/auth/account/reverify']['post']['requestBody']['content']['application/json'], response: undefined }
| { method: 'get', path: `/auth/account/`, params: undefined, response: paths['/auth/account/']['get']['responses']['200']['content']['application/json'] }
| { method: 'patch', path: `/auth/account/change/password`, params: paths['/auth/account/change/password']['patch']['requestBody']['content']['application/json'], response: undefined }
| { method: 'patch', path: `/auth/account/change/email`, params: paths['/auth/account/change/email']['patch']['requestBody']['content']['application/json'], response: undefined }
| { method: 'post', path: `/auth/account/verify/${string}`, params: undefined, response: undefined }
| { method: 'post', path: `/auth/account/reset_password`, params: paths['/auth/account/reset_password']['post']['requestBody']['content']['application/json'], response: undefined }
| { method: 'patch', path: `/auth/account/reset_password`, params: paths['/auth/account/reset_password']['patch']['requestBody']['content']['application/json'], response: undefined }
| { method: 'post', path: `/auth/session/login`, params: paths['/auth/session/login']['post']['requestBody']['content']['application/json'], response: paths['/auth/session/login']['post']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/auth/session/logout`, params: undefined, response: undefined }
| { method: 'get', path: `/auth/session/all`, params: undefined, response: paths['/auth/session/all']['get']['responses']['200']['content']['application/json'] }
| { method: 'delete', path: `/auth/session/all`, params: paths['/auth/session/all']['delete']['parameters']['query'], response: undefined }
| { method: 'delete', path: `/auth/session/${string}`, params: undefined, response: undefined }
| { method: 'patch', path: `/auth/session/${string}`, params: paths['/auth/session/{id}']['patch']['requestBody']['content']['application/json'], response: paths['/auth/session/{id}']['patch']['responses']['200']['content']['application/json'] }
| { method: 'get', path: `/onboard/hello`, params: undefined, response: paths['/onboard/hello']['get']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/onboard/complete`, params: paths['/onboard/complete']['post']['requestBody']['content']['application/json'], response: undefined }
| { method: 'post', path: `/push/subscribe`, params: paths['/push/subscribe']['post']['requestBody']['content']['application/json'], response: undefined }
| { method: 'post', path: `/push/unsubscribe`, params: undefined, response: undefined }
| { method: 'post', path: `/sync/settings/fetch`, params: paths['/sync/settings/fetch']['post']['requestBody']['content']['application/json'], response: paths['/sync/settings/fetch']['post']['responses']['200']['content']['application/json'] }
| { method: 'post', path: `/sync/settings/set`, params: paths['/sync/settings/set']['post']['parameters']['query']|paths['/sync/settings/set']['post']['requestBody']['content']['application/json'], response: undefined }
| { method: 'get', path: `/sync/unreads`, params: undefined, response: paths['/sync/unreads']['get']['responses']['200']['content']['application/json'] };
-310
View File
@@ -1,310 +0,0 @@
import { body, noContent, parameter, ref, success } from "../openapi/generators.js";
import { group, resource, route, routeAuthenticated, tag } from "../openapi/paths.js";
import { schema } from "../typescript.js";
group("Auth");
//#region Account
tag("Account", "Manage your account.");
resource('/auth/account', {
get: routeAuthenticated(
"Fetch Account",
"Fetch account information.",
await success("Account Information", ref("Account")),
true
)
});
resource('/auth/account/create', {
post: route(
"Create Account",
"Create a new account.",
{
...await body("Create Data", schema`
interface ${'CreateData'} {
/**
* Valid email address
*/
email: string;
/**
* Password
* @minLength 8
* @maxLength 1024
*/
password: string;
/**
* Invite Code
*/
invite?: string;
/**
* Captcha verification code
*/
captcha?: string;
}
`),
...await noContent("Created account.")
}
)
});
resource('/auth/account/reverify', {
post: route(
"Resend Verification",
"Resend account creation verification email.",
{
...await body("Resend Data", schema`
interface ${'ResendData'} {
/**
* Email
*/
email: string;
/**
* Captcha verification token
*/
captcha?: string;
}
`),
...await noContent("Resent verification.")
}
)
});
resource('/auth/account/verify/:code', {
post: route(
"Verify Email",
"Verifies an email with code.",
{
parameters: [
await parameter("code", "Verification Code", ref("Id"))
],
...await noContent("Verified email.")
}
)
});
resource('/auth/account/reset_password', {
post: route(
"Send Password Reset",
"Send password reset email.",
{
...await body("Reset Data", schema`
interface ${'ResetData'} {
/**
* Email
*/
email: string;
/**
* Captcha verification token
*/
captcha?: string;
}
`),
...await noContent("Sent password reset.")
}
),
patch: route(
"Password Reset",
"Confirm password reset.",
{
...await body("Reset Data", schema`
interface ${'ResetData'} {
/**
* Password
* @minLength 8
* @maxLength 1024
*/
password: string;
/**
* Password reset token
*/
token: string;
}
`),
...await noContent("Password was changed.")
}
)
});
resource('/auth/account/change/password', {
patch: routeAuthenticated(
"Change Password",
"Change account password.",
{
...await body("Change Data", schema`
interface ${'ChangeData'} {
/**
* Password
* @minLength 8
* @maxLength 1024
*/
password: string;
/**
* Current Password
* @minLength 8
* @maxLength 1024
*/
current_password: string;
}
`),
...await noContent("Password changed.")
},
true
)
});
resource('/auth/account/change/email', {
patch: routeAuthenticated(
"Change Email",
"Change account email.",
{
...await body("Change Data", schema`
interface ${'ChangeData'} {
/**
* Current Password
* @minLength 8
* @maxLength 1024
*/
current_password: string;
/**
* Valid email
*/
email: string;
}
`),
...await noContent("Email changed.")
},
true
)
});
//#endregion
//#region Session
tag("Session", "Create and manage sessions.");
resource('/auth/session/login', {
post: route(
"Login",
"Login to an account.",
{
...await body("Login Data", schema`
interface ${'LoginData'} {
/**
* Valid email address
*/
email: string;
/**
* Password
* @minLength 8
* @maxLength 1024
*/
password?: string;
/**
* Security Key Challenge
*/
challenge?: string;
/**
* Session Friendly Name
* @minLength 0
* @maxLength 72
*/
friendly_name?: string;
/**
* Captcha verification code
*/
captcha?: string;
}
`),
...await success("Logged in.", ref("Session"))
}
)
});
resource('/auth/session/logout', {
post: routeAuthenticated(
"Logout",
"Close current session.",
await noContent("Logged out."),
true
)
});
resource('/auth/session/:session', {
patch: routeAuthenticated(
"Edit Session",
"Edit session information.",
{
parameters: [
await parameter("session", "Session ID", ref("Id"))
],
...await body("Edit Data", schema`
interface ${'SessionEditData'} {
/**
* Session Friendly Name
* @minLength 0
* @maxLength 72
*/
friendly_name: string;
}
`),
...await noContent("Edited session.")
},
true
),
delete: routeAuthenticated(
"Delete Session",
"Delete a specific session.",
{
parameters: [
await parameter("session", "Session ID", ref("Id"))
],
...await noContent("Deleted session.")
},
true
)
});
resource('/auth/session/all', {
get: routeAuthenticated(
"Fetch Sessions",
"Fetch all sessions.",
await success("Sessions", schema`
import type { Id } from './_common';
import type { SessionInfo } from './Auth';
type ${'Sessions'} = SessionInfo[];
`),
true
),
delete: routeAuthenticated(
"Delete All Sessions",
"Delete all active sesssions.",
{
parameters: [
{
name: 'revoke_self',
in: 'query',
description: "Whether to revoke current session too.",
schema: {
type: 'boolean'
}
}
],
...await noContent("Deleted session.")
},
true
)
});
//#endregion
-162
View File
@@ -1,162 +0,0 @@
import { body, noContent, parameter, ref, success } from "../openapi/generators.js";
import { group, resource, routeAuthenticated, tag } from "../openapi/paths.js";
import { schema } from "../typescript.js";
group("Bots");
//#region Bots
tag("Bots", "Create and edit bots.");
resource('/bots/create', {
post: routeAuthenticated(
"Create Bot",
"Create a new Revolt bot.",
{
...await body("Bot Details", schema`
import type { Username } from './Users';
interface ${'BotDetails'} {
/**
* Bot username
**/
name: Username;
}
`),
...await success(
"Succesfully created a new bot.",
ref("Bot")
)
},
true
)
});
resource('/bots/@me', {
get: routeAuthenticated(
"Fetch Owned Bots",
"Fetch all of your bots.",
{
...await success("Array of bot objects.", schema`
import type { Bot } from './Bots';
import type { User } from './Users';
type ${'MyBots'} = {
bots: Bot[],
users: User[]
};
`)
},
true
)
});
const botParams = {
parameters: [
await parameter('bot', 'Bot ID', ref("Id"))
]
}
resource('/bots/:bot', {
get: routeAuthenticated(
"Fetch Bot",
"Fetch details of an owned bot.",
{
...botParams,
...await success("Bot", schema`
import type { Bot } from './Bots';
import type { User } from './Users';
type ${'MyBot'} = {
bot: Bot,
user: User
};
`)
},
true
),
patch: routeAuthenticated(
"Edit Bot",
"Edit bot details.",
{
...await body("Requested changes to bot object.", schema`
import type { Username } from './Users';
interface ${'EditBot'} {
/**
* Bot username
*/
name?: Username;
/**
* Whether the bot can be added by anyone
**/
public?: boolean;
/**
* Interactions URL
* @minLength 1
* @maxLength 2048
**/
interactions_url?: string;
/**
* Field to remove from bot object
*/
remove?: 'InteractionsURL';
}
`),
...await noContent("Succesfully changed bot object.")
},
true
),
delete: routeAuthenticated(
"Delete Bot",
"Delete a bot.",
{
...botParams,
...await noContent("Deleted bot.")
},
true
)
});
resource('/bots/:bot/invite', {
get: routeAuthenticated(
"Fetch Public Bot",
"Fetch details of a public (or owned) bot.",
{
...botParams,
...await success("Public Bot", ref('PublicBot'))
},
true
),
post: routeAuthenticated(
"Invite Public Bot",
"Invite a bot to a server or group.",
{
...botParams,
...await body("Information about where to invite the bot.", schema`
import type { Id } from './_common';
type ${'InvitePublicBot'} = (
{
/**
* Server ID to add the bot to.
*/
server: Id
} |
{
/**
* Group channel ID to add the bot to.
*/
group: Id
}
)
`),
...await noContent("Added bot to server / group.")
},
true
)
});
//#endregion
//#region Human Interactions
//#endregion
-523
View File
@@ -1,523 +0,0 @@
import { body, noContent, parameter, ref, success } from "../openapi/generators.js";
import { group, resource, routeAuthenticated, tag } from "../openapi/paths.js";
import { schema } from "../typescript.js";
group("Channels");
//#region Channel Information
tag("Channel Information", "Query and fetch channels on Revolt");
const channelParams = {
parameters: [
await parameter('channel', 'Channel ID', ref("Id"))
]
}
resource('/channels/:channel', {
get: routeAuthenticated(
"Fetch Channel",
"Retrieve a channel.",
{
...channelParams,
...await success(
"Retrieved channel.",
ref("Channel")
)
}
),
patch: routeAuthenticated(
"Edit Channel",
"Edit a channel object.",
{
...channelParams,
...await body("Requested changes to channel object.", schema`
import type { Status } from './Users';
import type { AutumnId } from './_common';
interface ${'EditChannel'} {
/**
* Channel name
* @minLength 1
* @maxLength 32
**/
name?: string;
/**
* Channel description
* @minLength 0
* @maxLength 1024
**/
description?: string;
icon?: AutumnId;
/**
* Whether this channel is not safe for work
*/
nsfw?: boolean;
/**
* Field to remove from channel object
*/
remove?: 'Icon' | 'Description';
}
`),
...await noContent("Succesfully changed channel object.")
}
),
delete: routeAuthenticated(
"Close Channel",
"Deletes a server channel, leaves a group or closes a DM.",
{
...channelParams,
...await noContent("Deleted Channel")
}
)
});
//#endregion
//#region Channel Invites
tag("Channel Invites", "Create and manage invites for channels");
resource('/channels/:channel/invites', {
post: routeAuthenticated(
"Create Invite",
"Creates an invite to this channel.\n\nChannel must be a `TextChannel`.",
{
...channelParams,
...await success("Invite", schema`
interface ${'InviteCode'} {
/**
* Invite Code
*/
code: string;
}
`)
}
)
});
//#endregion
//#region Channel Permissions
tag("Channel Permissions", "Manage permissions for channels");
const roleParams = {
parameters: [
await parameter('channel', 'Channel ID', ref("Id")),
await parameter('role', 'Role ID', ref("Id"))
]
}
const channelPermissions = await body("Channel Permissions", schema`
interface ${'ChannelPermissions'} {
permissions: number
}
`)
resource('/channels/:channel/permissions/:role', {
put: routeAuthenticated(
"Set Role Permission",
"Sets permissions for the specified role in this channel.\n\nChannel must be a `TextChannel` or `VoiceChannel`.",
{
...roleParams,
...channelPermissions,
...await noContent("Successfully updated permissions.")
}
)
});
resource('/channels/:channel/permissions/default', {
put: routeAuthenticated(
"Set Default Permission",
"Sets permissions for the default role in this channel.\n\nChannel must be a `Group`, `TextChannel` or `VoiceChannel`.",
{
...channelParams,
...channelPermissions,
...await noContent("Successfully updated permissions.")
}
)
});
//#endregion
//#region Messaging
tag("Messaging", "Send and manipulate messages");
const messageParams = {
parameters: [
await parameter('channel', 'Channel ID', ref("Id")),
await parameter('message', 'Message ID', ref("Id"))
]
}
const retrievedMessages = await success("Message array or object with requested data.", schema`
import { Message } from './Channels';
import { User } from './Users';
import { Member } from './Servers';
type ${'RetrievedMessages'} = Message[] | {
messages: Message[],
users: User[],
members?: Member[]
}
`);
resource('/channels/:channel/messages', {
post: routeAuthenticated(
"Send Message",
"Sends a message to the given channel.",
{
...channelParams,
...await body("Message to be sent.", schema`
import type { Id, AutumnId } from './_common';
import type { Masquerade, SendableEmbed } from './Channels';
interface ${'SendMessage'} {
/**
* Message content to send.
* @minLength 0
* @maxLength 2000
*/
content: string;
/**
* Attachments to include in message.
*/
attachments?: AutumnId[];
/**
* Embeds to include in the message
* @minLength 1
* @maxLength 10
*/
embeds?: SendableEmbed[];
/**
* Messages to reply to.
*/
replies?: {
/**
* Message Id
*/
id: Id;
/**
* Whether this reply should mention the message's author.
*/
mention: boolean;
}[]
masquerade?: Masquerade;
}
`),
...await success(
"Sent message.",
ref("Message")
)
}
),
get: routeAuthenticated(
"Fetch Messages",
"Fetches multiple messages.",
{
...channelParams,
...await body("Fetch Options", schema`
import { Id } from './_common';
interface ${'FetchOptions'} {
/**
* Maximum number of messages to fetch.
*
* For fetching nearby messages, this is \`(limit + 1)\`.
*
* @minimum 1
* @maximum 100
*/
limit?: number;
/**
* Message id before which messages should be fetched.
*/
before?: Id;
/**
* Message id after which messages should be fetched.
*/
after?: Id;
/**
* Message sort direction
*/
sort: 'Latest' | 'Oldest';
/**
* Message id to fetch around, this will ignore 'before', 'after' and 'sort' options.
* Limits in each direction will be half of the specified limit.
* It also fetches the specified message ID.
*/
nearby?: Id;
/**
* Whether to include user (and member, if server channel) objects.
*/
include_users?: boolean;
}
`),
...retrievedMessages
}
)
});
resource('/channels/:channel/messages/:message', {
get: routeAuthenticated(
"Fetch Message",
"Retrieves a message by ID.",
{
...messageParams,
...await success(
"Message",
ref("Message")
)
}
),
patch: routeAuthenticated(
"Edit Message",
"Edits a message that you've previously sent.",
{
...messageParams,
...await body("Message edit data.", schema`
import type { SendableEmbed } from './Channels';
interface ${'MessageEdit'} {
/**
* Message content
* @minLength 1
* @maxLength 2000
*/
content: string;
/**
* Embeds to include in the message.
* @minLength 0
* @maxLength 10
*/
embeds?: SendableEmbed[];
}
`),
...await noContent("Message was changed.")
}
),
delete: routeAuthenticated(
"Delete Message",
"Delete a message you've sent or one you have permission to delete.",
{
...messageParams,
...await noContent("Message was deleted.")
}
)
});
resource('/channels/:channel/messages/stale', {
post: routeAuthenticated(
"Poll Message Changes",
"This route returns any changed message objects and tells you if any have been deleted.\n\nDon't actually poll this route, instead use this to update your local database.",
{
...channelParams,
...await body("Poll Options", schema`
import { Id } from './_common';
interface ${'PollOptions'} {
/**
* Array of message IDs.
*
* @maxItems 150
*/
ids: Id[];
}
`),
...await success("Polled Information", schema`
import { Message } from './Channels';
interface ${'PolledInformation'} {
/**
* Changed message objects.
*/
changed: Message[],
/**
* Array of deleted message IDs.
*/
deleted: string[]
}
`)
}
)
});
resource('/channels/:channel/messages/search', {
post: routeAuthenticated(
"Search for Messages",
"This route searches for messages within the given parameters.",
{
...channelParams,
...await body("Search Options", schema`
import { Id } from './_common';
interface ${'SearchOptions'} {
/**
* Full-text search query.
*
* See [MongoDB documentation](https://docs.mongodb.com/manual/text-search/#-text-operator) for more information.
*
* @minLength 1
* @maxLength 64
*/
query: string;
/**
* Maximum number of messages to fetch.
*
* @minimum 1
* @maximum 100
*/
limit?: number;
/**
* Message id before which messages should be fetched.
*/
before?: Id;
/**
* Message id after which messages should be fetched.
*/
after?: Id;
/**
* Message sort direction, by default it will be sorted by relevance.
*/
sort?: 'Relevance' | 'Latest' | 'Oldest';
/**
* Whether to include user (and member, if server channel) objects.
*/
include_users?: boolean;
}
`),
...retrievedMessages
}
)
});
resource('/channels/:channel/ack/:message', {
put: routeAuthenticated(
"Acknowledge Message",
"Lets the server and all other clients know that we've seen this message id in this channel.",
{
...messageParams,
...await noContent("Acknowledged message.")
},
true
)
});
//#endregion
//#region Groups
tag("Groups", "Create, invite users and manipulate groups");
resource('/channels/create', {
post: routeAuthenticated(
"Create Group",
"Create a new group with friends.",
{
...await body("Group Data", schema`
import { Id } from './_common';
interface ${'GroupData'} {
/**
* Group name
* @minLength 1
* @maxLength 32
*/
name: string;
/**
* Group description
* @minLength 0
* @maxLength 1024
*/
description?: string;
/**
* Array of user IDs to add to the group.
*
* Must be friends with them.
*
* @maxItems 49
*/
users?: string[];
/**
* Whether this group is not safe for work
*/
nsfw?: boolean;
}
`),
...await success('Group', ref("GroupChannel"))
},
true
)
});
resource('/channels/:channel/members', {
get: routeAuthenticated(
"Fetch Group Members",
"Retrieves users who are part of this group.",
{
...messageParams,
...await success("Members", schema`
import { User } from './Users';
type ${'Members'} = User[];
`)
}
),
put: routeAuthenticated(
"Add Group Member",
"Adds another user to the group.",
{
...messageParams,
...await noContent("User was added to the group.")
},
true
),
delete: routeAuthenticated(
"Remove Group Member",
"Removes a user from the group.",
{
...messageParams,
...await noContent("User was removed from the group.")
},
true
)
});
//#endregion
//#region Voice
tag("Voice", "Join and talk with other users");
resource('/channels/:channel/join_call', {
post: routeAuthenticated(
"Join Call",
"Asks the voice server for a token to join the call.",
{
...channelParams,
...await success("Join Data", schema`
interface ${'JoinData'} {
/**
* Voso Token
*/
token: string;
}
`)
}
)
});
//#endregion
-55
View File
@@ -1,55 +0,0 @@
import { group, resource, route, routeAuthenticated, tag } from "../openapi/paths.js";
import { body, noContent, ref, success } from "../openapi/generators.js";
import { schema } from "../typescript.js";
group("Chat Platform");
tag("Core", "Use in your applications to determine information about the Revolt node.");
resource('/', {
get: route(
"Query Node",
"This returns information about which features are enabled on the remote node.",
await success(
"Server node information.",
ref("RevoltConfiguration")
)
)
});
tag("Onboarding", "After signing up to Revolt, users must pick a unique username.");
resource('/onboard/hello', {
get: routeAuthenticated(
"Check Onboarding Status",
"This will tell you whether the current account requires onboarding or whether you can continue to send requests as usual. You may skip calling this if you're restoring an existing session.",
await success(
"Onboarding information.",
ref("OnboardingInformation")
),
true
)
});
resource('/onboard/complete', {
post: routeAuthenticated(
"Complete Onboarding",
"This sets a new username, completes onboarding and allows a user to start using Revolt.",
{
...await body("Data about wanted user information.", schema`
interface ${'OnboardingComplete'} {
/**
* An alphanumeric username which is used to identify the user on the platform.
* @example insert
* @minLength 2
* @maxLength 32
* @pattern ^[a-zA-Z0-9-_]+$
*/
username: string;
}
`),
...await noContent("Successfully set username")
},
true
)
});
-11
View File
@@ -1,11 +0,0 @@
export async function load() {
await import('./core.js');
await import('./auth.js');
await import('./users.js');
await import('./channels.js');
await import('./servers.js');
await import('./bots.js');
await import('./misc.js');
}
await load();
-143
View File
@@ -1,143 +0,0 @@
import { body, noContent, parameter, ref, success } from "../openapi/generators.js";
import { group, resource, route, routeAuthenticated, tag } from "../openapi/paths.js";
import { schema } from "../typescript.js";
group("Miscellaneous");
//#region Invites
tag("Invites", "View, join and delete invites");
const inviteParams = {
parameters: [
await parameter("invite", "Invite Code", { type: 'string' })
]
}
resource('/invites/:invite', {
get: routeAuthenticated(
"Fetch Invite",
"Fetch an invite by its ID.",
{
...inviteParams,
...await success("Invite", ref("RetrievedInvite"))
}
),
post: routeAuthenticated(
"Join Invite",
"Join an invite by its ID.",
{
...inviteParams,
...await success("Invite", schema`
import { Channel } from './Channels';
import { Server } from './Servers';
interface ${'InviteData'} {
type: 'Server',
channel: Channel,
server: Server
}
`)
},
true
),
delete: routeAuthenticated(
"Delete Invite",
"Delete an invite by its ID.",
{
...inviteParams,
...await noContent("Deleted invite.")
}
),
});
//#endregion
//#region Sync
tag("Sync", "Upload and retrieve any JSON data between clients");
resource('/sync/settings/fetch', {
post: routeAuthenticated(
"Fetch Settings",
"Fetch settings from server filtered by keys.\n\nThis will return an object with the requested keys, each value is a tuple of `(timestamp, value)`, the value is the previously uploaded data.",
{
...await body("Options", schema`
interface ${'FetchSettingsOptions'} {
/**
* Keys to fetch
*/
keys: string[]
}
`),
...await success("Settings Data", schema`
type ${'SettingsData'} = { [key: string]: [ number, string ] };
`)
},
true
)
});
resource('/sync/settings/set', {
post: routeAuthenticated(
"Set Settings",
"Upload data to save to settings.",
{
parameters: [
{
name: 'timestamp',
in: 'query',
description: "Timestamp of settings change. Useful to prevent a feedback loop.",
schema: {
type: 'number'
}
}
],
...await body("Settings Data", schema`
interface ${'SetSettingsData'} {
[key: string]: string
}
`),
...await noContent("Successfully synced data.")
},
true
)
});
resource('/sync/unreads', {
post: routeAuthenticated(
"Fetch Unreads",
"Fetch information about unread state on channels.",
await success(
"Array of Unreads Data",
schema`
import type { ChannelUnread } from "./Sync";
type ${'FetchUnreads'} = ChannelUnread[];
`
),
true
)
});
//#endregion
//#region Web Push
tag("Web Push", "Subscribe to and receive Revolt push notifications while offline");
resource('/push/subscribe', {
post: routeAuthenticated(
"Subscribe",
"Create a new Web Push subscription.\n\nIf an existing subscription exists on this session, it will be removed.",
{
...await body("Web Push Subscription", ref("WebPushSubscription")),
...await noContent("Subscribed successfully.")
},
true
)
});
resource('/push/unsubscribe', {
post: routeAuthenticated(
"Unsubscribe",
"Remove the Web Push subscription associated with the current session.",
await noContent("Unsubscribed successfully."),
true
)
});
//#endregion
-467
View File
@@ -1,467 +0,0 @@
import { body, noContent, parameter, ref, success } from "../openapi/generators.js";
import { group, resource, route, routeAuthenticated, tag } from "../openapi/paths.js";
import { schema } from "../typescript.js";
group("Servers");
//#region Server Information
tag("Server Information", "Query and fetch servers on Revolt");
const serverParams = {
parameters: [
await parameter('server', 'Server ID', ref("Id"))
]
}
resource('/servers/:server', {
get: routeAuthenticated(
"Fetch Server",
"Retrieve a server.",
{
...serverParams,
...await success(
"Retrieved server.",
ref("Server")
)
}
),
patch: routeAuthenticated(
"Edit Server",
"Edit a server object.",
{
...serverParams,
...await body("Requested changes to server object.", schema`
import type { Category, SystemMessageChannels } from './Servers';
import type { AutumnId } from './_common';
interface ${'EditServer'} {
/**
* Server name
* @minLength 1
* @maxLength 32
**/
name?: string;
/**
* Server description
* @minLength 0
* @maxLength 1024
**/
description?: string;
icon?: AutumnId;
banner?: AutumnId;
/**
* Server categories
*/
categories?: Category[];
/**
* System message channels
*/
system_messages?: SystemMessageChannels;
/**
* Whether this server is not safe for work
*/
nsfw?: boolean;
/**
* Field to remove from channel object
*/
remove?: 'Icon' | 'Banner' | 'Description';
}
`),
...await noContent("Succesfully changed channel object.")
}
),
delete: routeAuthenticated(
"Delete / Leave Server",
"Deletes a server if owner otherwise leaves.",
{
...serverParams,
...await noContent("Deleted Server")
}
)
});
resource('/servers/create', {
post: routeAuthenticated(
"Create Server",
"Create a new server.",
{
...await body("Server Data", schema`
import { Id } from './_common';
interface ${'ServerData'} {
/**
* Server name
* @minLength 1
* @maxLength 32
*/
name: string;
/**
* Server description
* @minLength 0
* @maxLength 1024
*/
description?: string;
/**
* Whether this server is not safe for work
*/
nsfw?: boolean;
}
`),
...await success('Server', ref("Server"))
},
true
)
});
resource('/servers/:server/channels', {
post: routeAuthenticated(
"Create Channel",
"Create a new Text or Voice channel.",
{
...serverParams,
...await body("Channel Data", schema`
import { Id } from './_common';
interface ${'ChannelData'} {
/**
* Channel type
*/
type: 'Text' | 'Voice';
/**
* Channel name
* @minLength 1
* @maxLength 32
*/
name: string;
/**
* Channel description
* @minLength 0
* @maxLength 1024
*/
description?: string;
/**
* Whether this channel is not safe for work
*/
nsfw?: boolean;
}
`),
...success("Channel", ref("Channel"))
}
)
});
resource('/servers/:server/invites', {
get: routeAuthenticated(
"Fetch Invites",
"Fetch all server invites.",
{
...serverParams,
...success("Server Invites", schema`
import { Id } from './_common';
type ${'ServerInvites'} = {
/**
* Invite Code
*/
code: string;
/**
* ID of the user who created this invite.
*/
creator: Id;
/**
* ID of the channel this invite is for.
*/
channel: Id;
}
`)
}
)
});
resource('/servers/:server/ack', {
put: routeAuthenticated(
"Mark Server As Read",
"Mark all channels in a server as read.",
{
...serverParams,
...await noContent("Marked as read.")
},
true
),
});
//#endregion
//#region Server Members
tag("Server Members", "Find and edit server members");
const memberParams = {
parameters: [
await parameter('server', 'Server ID', ref("Id")),
await parameter('member', 'Member ID', ref("Id"))
]
}
resource('/servers/:server/members/:member', {
get: routeAuthenticated(
"Fetch Member",
"Retrieve a member.",
{
...memberParams,
...await success(
"Retrieved member.",
ref("Member")
)
}
),
patch: routeAuthenticated(
"Edit Member",
"Edit a member object.",
{
...serverParams,
...await body("Requested changes to member object.", schema`
import type { AutumnId, Id } from './_common';
interface ${'EditMember'} {
/**
* Member nickname
* @minLength 1
* @maxLength 32
**/
nickname?: string;
avatar?: AutumnId;
/**
* Array of role IDs
*/
roles?: Id[];
/**
* Field to remove from channel object
*/
remove?: 'Nickname' | 'Avatar';
}
`),
...await noContent("Succesfully changed member object.")
}
),
delete: routeAuthenticated(
"Kick Member",
"Removes a member from the server.",
await noContent("Removed Member")
)
});
resource('/servers/:server/members', {
get: route(
"Fetch Members",
"Fetch all server members.",
{
...serverParams,
...await success(
"Server Members",
schema`
import { Member } from './Servers';
import { User } from './Users';
interface ${'ServerMembers'} {
members: Member[],
users: User[]
}
`
)
}
)
});
resource('/servers/:server/bans/:member', {
put: routeAuthenticated(
"Ban User",
"Ban a user by their ID.",
{
...memberParams,
...await body("Ban Data", schema`
interface ${'BanData'} {
/**
* Ban reason
* @minLength 1
* @maxLength 1024
*/
reason?: string
}
`),
...await noContent("Banned user.")
}
),
delete: routeAuthenticated(
"Unban User",
"Removes a user's ban.",
{
...memberParams,
...await noContent("Unbanned user.")
}
)
});
resource('/servers/:server/bans', {
get: routeAuthenticated(
"Fetch Bans",
"Fetch all bans on server.",
{
...serverParams,
...await success("Bans", schema`
import type { Id } from './_common';
import type { Ban } from './Servers';
import type { Username } from './Users';
import type { Attachment } from './Autumn';
type ${'ServerBans'} = {
/**
* Just enough user information to list bans.
*/
users: {
_id: Id
username: Username
avatar?: Attachment
}[]
/**
* Ban List
*/
bans: Ban[]
};
`)
}
)
});
//#endregion
//#region Server Permissions
tag("Server Permissions", "Manage permissions for servers");
const roleParams = {
parameters: [
await parameter('server', 'Server ID', ref("Id")),
await parameter('role', 'Role ID', ref("Id"))
]
}
const serverPermissions = await body("Server Permissions", schema`
interface ${'ServerPermissions'} {
/**
* Permission values
*/
permissions: {
/**
* Server permission
*/
server: number,
/**
* Channel permission
*/
channel: number
}
}
`)
resource('/servers/:server/permissions/:role', {
put: routeAuthenticated(
"Set Role Permission",
"Sets permissions for the specified role in this server.",
{
...roleParams,
...serverPermissions,
...await noContent("Successfully updated permissions.")
}
)
});
resource('/servers/:server/permissions/default', {
put: routeAuthenticated(
"Set Default Permission",
"Sets permissions for the default role in this server.",
{
...serverParams,
...serverPermissions,
...await noContent("Successfully updated permissions.")
}
)
});
resource('/servers/:server/roles', {
post: routeAuthenticated(
"Create Role",
"Creates a new server role.",
{
...serverParams,
...await body("Role Data", schema`
interface ${'RoleData'} {
/**
* Role name
* @minLength 1
* @maxLength 32
*/
name: string;
}
`),
...await success("New Role", schema`
import { Id } from './_common';
import { PermissionTuple } from './Servers';
interface ${'NewRole'} {
/**
* Role ID
*/
id: Id;
permissions: PermissionTuple;
}
`)
}
)
});
resource('/servers/:server/roles/:role', {
patch: routeAuthenticated(
"Edit Role",
"Edit a role object.",
{
...roleParams,
...await body("Requested changes to role object.", schema`
import type { RoleInformation, Colour } from './Servers';
type ${'EditRole'} = RoleInformation & {
/**
* Field to remove from role object
*/
remove?: 'Colour';
}
`),
...await noContent("Succesfully changed role object.")
}
),
delete: routeAuthenticated(
"Delete Role",
"Deletes a server role by ID.",
{
...roleParams,
...await noContent("Successfully deleted role.")
}
)
});
//#endregion
-298
View File
@@ -1,298 +0,0 @@
import { body, noContent, parameter, ref, success } from "../openapi/generators.js";
import { group, resource, route, routeAuthenticated, tag } from "../openapi/paths.js";
import { schema } from "../typescript.js";
group("Users");
//#region User Information
tag("User Information", "Query and fetch users on Revolt");
const userParams = {
parameters: [
await parameter('user', 'User ID', ref("Id"))
]
}
resource('/users/:user', {
get: routeAuthenticated(
"Fetch User",
"Retrieve a user's information.",
{
...userParams,
...await success(
"User information.",
ref("User")
)
}
)
});
resource('/users/@me', {
patch: routeAuthenticated(
"Edit User",
"Edit your user object.",
{
...await body("Requested changes to user object.", schema`
import type { Status } from './Users';
import type { AutumnId } from './_common';
interface ${'EditUser'} {
status?: Status;
/**
* User profile data
**/
profile?: {
/**
* Text to set as user profile description
* @maxLength 2000
*/
content?: string;
background?: AutumnId;
}
avatar?: AutumnId;
/**
* Field to remove from user object
*/
remove?: 'ProfileContent' | 'ProfileBackground' | 'StatusText' | 'Avatar';
}
`),
...await noContent("Succesfully changed user object.")
}
),
get: routeAuthenticated(
"Fetch Self",
"Retrieve your user information.",
{
...userParams,
...await success(
"User information.",
ref("User")
)
}
)
});
resource('/users/@me/username', {
patch: routeAuthenticated(
"Change Username",
"Change your username.",
{
...await body("Requested change to username.", schema`
interface ${'ChangeUsername'} {
/**
* New username
* @minLength 2
* @maxLength 32
* @pattern ^[a-zA-Z0-9_.]+$
*/
username: string;
/**
* Current account password
* @minLength 8
* @maxLength 1024
*/
password: string;
}
`),
...await noContent("Succesfully changed user object.")
},
true
)
});
resource('/users/:user/profile', {
get: routeAuthenticated(
"Fetch User Profile",
"Retrieve a user's profile data.",
{
...userParams,
...await success(
"User profile.",
ref("Profile")
)
}
)
});
resource('/users/:user/default_avatar', {
get: route(
"Fetch Default Avatar",
"This returns a default avatar based on the given id.",
{
...userParams,
responses: {
'200': {
description: "Default avatar in PNG format",
content: {
"image/png": {
schema: {
type: 'string',
format: 'binary'
}
}
}
}
}
}
)
});
resource('/users/:user/mutual', {
get: routeAuthenticated(
"Fetch Mutual Friends And Servers",
"Retrieve a list of mutual friends and servers with another user.",
{
...userParams,
...await success(
"Mutual friends and servers.",
schema`
interface ${'MutualFriends'} {
/**
* Array of user IDs who both you and the other user are friends with.
*/
users: string[]
/**
* Array of server IDs who both you and the other user are members of.
*/
servers: string[]
}
`
)
}
)
});
//#endregion
//#region Direct Messaging
tag("Direct Messaging", "Direct message other users on Revolt");
resource('/users/dms', {
get: routeAuthenticated(
"Fetch Direct Message Channels",
"This fetches your direct messages, including any DM and group DM conversations.",
await success(
"Your DM conversations.",
schema`
import type { DirectMessageChannel, GroupChannel } from "./Channels";
/**
* Channel objects.
*/
type ${'FetchDMs'} = (DirectMessageChannel | GroupChannel)[];
`
)
)
});
resource('/users/:user/dm', {
get: routeAuthenticated(
"Open Direct Message",
"Open a DM with another user.",
{
...userParams,
...await success(
"DM channel with user.",
ref("DirectMessageChannel")
)
}
)
});
//#endregion
//#region Relationships
tag("Relationships", "Manage your friendships and block list on the platform");
resource('/users/relationships', {
get: routeAuthenticated(
"Fetch Relationships",
"Fetch all of your relationships with other users.",
await success(
"Array of relationships.",
schema`
import type { Relationship } from "./Users";
type ${'FetchRelationships'} = Relationship[];
`
),
true
)
});
resource('/users/:user/relationship', {
get: routeAuthenticated(
"Fetch Relationship",
"Fetch your relationship with another other user.",
{
...userParams,
...await success(
"Your relationship with the user.",
ref("RelationshipOnly")
)
},
true
)
});
const friendParams = {
parameters: [
await parameter('username', 'Username', ref("Username"))
],
}
resource('/users/:username/friend', {
put: routeAuthenticated(
"Send Friend Request / Accept Request",
"Send a friend request to another user or accept another user's friend request.",
{
...friendParams,
...await success(
"Sent friend request / added user as friend.",
ref("RelationshipOnly")
)
},
true
),
delete: routeAuthenticated(
"Deny Friend Request / Remove Friend",
"Denies another user's friend request or removes an existing friend.",
{
...friendParams,
...await success(
"Deleted friend request / removed user from friends.",
ref("RelationshipOnly")
)
},
true
)
});
resource('/users/:user/block', {
put: routeAuthenticated(
"Block User",
"Block another user.",
{
...userParams,
...await success(
"Blocked user.",
ref("RelationshipOnly")
)
},
true
),
delete: routeAuthenticated(
"Unblock User",
"Unblock another user.",
{
...userParams,
...await success(
"Unblocked user.",
ref("RelationshipOnly")
)
},
true
)
});
//#endregion
+3447
View File
File diff suppressed because it is too large Load Diff
+100
View File
@@ -0,0 +1,100 @@
import { components } from './schema';
export type RevoltConfig = components['schemas']['RevoltConfig'];
export type RevoltFeatures = components['schemas']['RevoltFeatures'];
export type CaptchaFeature = components['schemas']['CaptchaFeature'];
export type Feature = components['schemas']['Feature'];
export type VoiceFeature = components['schemas']['VoiceFeature'];
export type Permission = components['schemas']['Permission'];
export type UserPermission = components['schemas']['UserPermission'];
export type Error = components['schemas']['Error'];
export type User = components['schemas']['User'];
export type File = components['schemas']['File'];
export type Metadata = components['schemas']['Metadata'];
export type Relationship = components['schemas']['Relationship'];
export type RelationshipStatus = components['schemas']['RelationshipStatus'];
export type UserStatus = components['schemas']['UserStatus'];
export type Presence = components['schemas']['Presence'];
export type UserProfile = components['schemas']['UserProfile'];
export type BotInformation = components['schemas']['BotInformation'];
export type Id = components['schemas']['Id'];
export type DataEditUser = components['schemas']['DataEditUser'];
export type UserProfileData = components['schemas']['UserProfileData'];
export type FieldsUser = components['schemas']['FieldsUser'];
export type DataChangeUsername = components['schemas']['DataChangeUsername'];
export type Channel = components['schemas']['Channel'];
export type OverrideField = components['schemas']['OverrideField'];
export type Bot = components['schemas']['Bot'];
export type DataCreateBot = components['schemas']['DataCreateBot'];
export type InviteBotDestination = components['schemas']['InviteBotDestination'];
export type PublicBot = components['schemas']['PublicBot'];
export type DataEditBot = components['schemas']['DataEditBot'];
export type FieldsBot = components['schemas']['FieldsBot'];
export type DataEditChannel = components['schemas']['DataEditChannel'];
export type FieldsChannel = components['schemas']['FieldsChannel'];
export type Invite = components['schemas']['Invite'];
export type Message = components['schemas']['Message'];
export type Content = components['schemas']['Content'];
export type SystemMessage = components['schemas']['SystemMessage'];
export type DateTimeContainer = components['schemas']['DateTimeContainer'];
export type DateTime = components['schemas']['DateTime'];
export type Embed = components['schemas']['Embed'];
export type Special = components['schemas']['Special'];
export type TwitchType = components['schemas']['TwitchType'];
export type BandcampType = components['schemas']['BandcampType'];
export type Image = components['schemas']['Image'];
export type ImageSize = components['schemas']['ImageSize'];
export type Video = components['schemas']['Video'];
export type Masquerade = components['schemas']['Masquerade'];
export type DataMessageSend = components['schemas']['DataMessageSend'];
export type Reply = components['schemas']['Reply'];
export type SendableEmbed = components['schemas']['SendableEmbed'];
export type BulkMessageResponse = components['schemas']['BulkMessageResponse'];
export type Member = components['schemas']['Member'];
export type MemberCompositeKey = components['schemas']['MemberCompositeKey'];
export type MessageSort = components['schemas']['MessageSort'];
export type OptionsMessageSearch = components['schemas']['OptionsMessageSearch'];
export type OptionsQueryStale = components['schemas']['OptionsQueryStale'];
export type DataEditMessage = components['schemas']['DataEditMessage'];
export type DataCreateGroup = components['schemas']['DataCreateGroup'];
export type Data = components['schemas']['Data'];
export type Override = components['schemas']['Override'];
export type DataDefaultChannelPermissions = components['schemas']['DataDefaultChannelPermissions'];
export type Server = components['schemas']['Server'];
export type Category = components['schemas']['Category'];
export type SystemMessageChannels = components['schemas']['SystemMessageChannels'];
export type Role = components['schemas']['Role'];
export type DataCreateServer = components['schemas']['DataCreateServer'];
export type DataEditServer = components['schemas']['DataEditServer'];
export type FieldsServer = components['schemas']['FieldsServer'];
export type DataCreateChannel = components['schemas']['DataCreateChannel'];
export type ChannelType = components['schemas']['ChannelType'];
export type DataMemberEdit = components['schemas']['DataMemberEdit'];
export type FieldsMember = components['schemas']['FieldsMember'];
export type ServerBan = components['schemas']['ServerBan'];
export type DataBanCreate = components['schemas']['DataBanCreate'];
export type BanListResult = components['schemas']['BanListResult'];
export type BannedUser = components['schemas']['BannedUser'];
export type DataCreateRole = components['schemas']['DataCreateRole'];
export type DataEditRole = components['schemas']['DataEditRole'];
export type FieldsRole = components['schemas']['FieldsRole'];
export type DataSetServerRolePermission = components['schemas']['DataSetServerRolePermission'];
export type DataSetServerDefaultPermission = components['schemas']['DataSetServerDefaultPermission'];
export type InviteResponse = components['schemas']['InviteResponse'];
export type DataCreateAccount = components['schemas']['DataCreateAccount'];
export type DataResendVerification = components['schemas']['DataResendVerification'];
export type AccountInfo = components['schemas']['AccountInfo'];
export type DataChangePassword = components['schemas']['DataChangePassword'];
export type DataChangeEmail = components['schemas']['DataChangeEmail'];
export type DataPasswordReset = components['schemas']['DataPasswordReset'];
export type DataSendPasswordReset = components['schemas']['DataSendPasswordReset'];
export type ResponseLogin = components['schemas']['ResponseLogin'];
export type WebPushSubscription = components['schemas']['WebPushSubscription'];
export type DataLogin = components['schemas']['DataLogin'];
export type SessionInfo = components['schemas']['SessionInfo'];
export type Session = components['schemas']['Session'];
export type DataEditSession = components['schemas']['DataEditSession'];
export type DataHello = components['schemas']['DataHello'];
export type DataOnboard = components['schemas']['DataOnboard'];
export type OptionsFetchSettings = components['schemas']['OptionsFetchSettings'];
export type ChannelUnread = components['schemas']['ChannelUnread'];
export type ChannelCompositeKey = components['schemas']['ChannelCompositeKey'];;
-28
View File
@@ -1,28 +0,0 @@
import { resolve } from "path";
import * as TJS from "typescript-json-schema";
import { readdirSync, writeFileSync } from "fs";
import convert from '@openapi-contrib/json-schema-to-openapi-schema';
export const type_files = readdirSync('types')
.filter(x => x !== '__temp')
.map(x => resolve('types', x));
export function createProgram(files = type_files) {
return TJS.getProgramFromFiles(files);
}
const settings = {
required: true
};
export const generator = TJS.buildGenerator(createProgram(), settings)!;
export async function schema(str: TemplateStringsArray, name: string) {
console.info(`Processing schema ${name}.`);
let fn = resolve('types', '__temp.ts')
writeFileSync(fn, str.join(name));
const program = createProgram([ fn ]);
const schema = TJS.generateSchema(program, name, settings, [])!;
return await convert(schema);
}
-52
View File
@@ -1,52 +0,0 @@
import type { Id } from "./_common";
export interface Account {
/**
* User ID
*/
_id: Id;
/**
* User Email
*/
email: string;
}
export interface Session {
/**
* Session ID
*/
_id?: Id;
/**
* User ID
*/
user_id: Id;
/**
* @maxLength 64
*/
token: string;
/**
* Device name
*/
name: string;
/**
* Web Push subscription
*/
subscription?: string;
}
export interface SessionInfo {
/**
* Session ID
*/
_id: Id;
/**
* Device name
*/
name: string;
}
-70
View File
@@ -1,70 +0,0 @@
/**
* Attachment ID
* @minLength 1
* @maxLength 128
*/
export type AttachmentId = string;
export type AttachmentMetadata = (
{ type: 'File' } |
{ type: 'Text' } |
{ type: 'Audio' } |
{ type: 'Image', width: number, height: number } |
{ type: 'Video', width: number, height: number }
);
/**
* Attachment tag
*/
export type AttachmentTag = 'attachments' | 'avatars' | 'backgrounds' | 'icons' | 'banners';
export type Attachment = {
_id: AttachmentId
tag: AttachmentTag
/**
* File size (in bytes)
*/
size: number
/**
* File name
*/
filename: string
/**
* Metadata
*/
metadata: AttachmentMetadata
/**
* Content type
*/
content_type: string
}
/**
* File serving parameters
*/
export interface SizeOptions {
/**
* Width of resized image
*/
width?: number
/**
* Height of resized image
*/
height?: number
/**
* Width and height of resized image
*/
size?: number
/**
* Maximum resized image side length
*/
max_side?: number
}
-67
View File
@@ -1,67 +0,0 @@
import type { Attachment } from "./Autumn";
import type { Username } from "./Users";
import type { Id } from "./_common";
export interface Bot {
/**
* Bot ID
*
* This matches the bot's User ID.
*/
_id: Id
/**
* Bot owner's User ID
*/
owner: Id
/**
* Bot authentication token
*/
token: string
/**
* Whether the bot can be added by anyone
*/
public: boolean
/**
* Whether to collect analytics on this bot
* Enabled if bot is discoverable
*/
analytics?: boolean
/**
* Whether this bot is discoverable
*/
discoverable?: boolean
/**
* Interactions endpoint URL
*
* Required for dynamic interactions such as bot commands and message actions. Events will be sent over HTTP and a response may be generated directly.
*/
interactions_url?: string
}
export interface PublicBot {
/**
* Bot ID
*/
_id: Id
/**
* Bot username
*/
username: Username
/**
* Bot avatar
*/
avatar?: Attachment
/**
* Bot description, taken from profile text
*/
description?: string
}
-252
View File
@@ -1,252 +0,0 @@
import type { Attachment } from "./Autumn"
import type { Id, Nonce, OverrideField } from "./_common"
import type { JanuaryEmbed } from "./January"
/**
* Saved Messages channel has only one participant, the user who created it.
*/
export type SavedMessagesChannel = {
/**
* Channel Id
*/
_id: Id
channel_type: 'SavedMessages'
/**
* User Id
*/
user: Id
}
export type DirectMessageChannel = {
/**
* Channel Id
*/
_id: Id
channel_type: 'DirectMessage'
/**
* Whether this DM is active
*/
active: boolean
/**
* List of user IDs who are participating in this DM
*/
recipients: Id[]
/**
* Id of the last message in this channel
*/
last_message_id?: Id
}
export type GroupChannel = {
/**
* Channel Id
*/
_id: Id,
channel_type: 'Group',
/**
* List of user IDs who are participating in this group
*/
recipients: Id[],
/**
* Group name
*/
name: string,
/**
* User ID of group owner
*/
owner: Id,
/**
* Group description
*/
description?: string,
/**
* Id of the last message in this channel
*/
last_message_id?: Id
/**
* Group icon
*/
icon?: Attachment,
/**
* Permissions given to group members
*/
permissions?: number
/**
* Whether this channel is marked as not safe for work
*/
nsfw?: boolean
}
export type ServerChannel = {
/**
* Channel Id
*/
_id: Id
/**
* Server Id
*/
server: Id
/**
* Channel name
*/
name: string
/**
* Channel description
*/
description?: string
icon?: Attachment
/**
* Permissions given to all users
*/
default_permissions?: OverrideField
/**
* Permissions given to roles
*/
role_permissions?: {
[key: string]: OverrideField
}
/**
* Whether this channel is marked as not safe for work
*/
nsfw?: boolean
}
export type TextChannel = ServerChannel & {
channel_type: 'TextChannel'
/**
* Id of the last message in this channel
*/
last_message_id?: Id
}
export type VoiceChannel = ServerChannel & {
channel_type: 'VoiceChannel'
}
export type Channel = (SavedMessagesChannel | DirectMessageChannel | GroupChannel | TextChannel | VoiceChannel)
/**
* Masquerade displayed for a message.
* Replaces user's name and avatar.
*/
export type Masquerade = {
/**
* Nickname to display
*/
name?: string
/**
* Avatar URL
*/
avatar?: string
}
export type Message = {
/**
* Message Id
*/
_id: Id
nonce?: Nonce
/**
* Channel Id
*/
channel: Id
/**
* Author Id
*/
author: Id
/**
* Message content, can be an object *only* if sent by the system user.
*/
content: string | SystemMessage
/**
* Message attachments
*/
attachments?: Attachment[]
/**
* Unix timestamp of when message was last edited
*/
edited?: { $date: string }
/**
* Message link embeds
*/
embeds?: Embed[]
/**
* Array of user IDs mentioned in message
*/
mentions?: Id[]
/**
* Array of message IDs replied to
*/
replies?: Id[]
masquerade?: Masquerade
}
export type SystemMessage =
| { type: "text"; content: string }
| { type: "user_added"; id: Id; by: Id }
| { type: "user_remove"; id: Id; by: Id }
| { type: "user_joined"; id: Id }
| { type: "user_left"; id: Id }
| { type: "user_kicked"; id: Id }
| { type: "user_banned"; id: Id }
| { type: "channel_renamed"; name: string, by: Id }
| { type: "channel_description_changed"; by: Id }
| { type: "channel_icon_changed"; by: Id };
export type TextEmbed = {
type: "Text",
icon_url?: string,
url?: string,
title?: string,
description?: string,
media?: Attachment,
colour?: string
}
export type Embed = TextEmbed | JanuaryEmbed | { type: "None" }
export type SendableEmbed = {
type: "Text",
icon_url?: string,
url?: string,
title?: string,
description?: string,
media?: string,
colour?: string
}
-105
View File
@@ -1,105 +0,0 @@
export interface RevoltConfiguration {
/**
* Revolt API version string
*/
revolt: string
/**
* Available features exposed by the API
*/
features: {
/**
* hCaptcha options
*/
captcha: {
/**
* Whether hCaptcha is enabled
*/
enabled: boolean
/**
* hCaptcha site key
*/
key: string
}
/**
* Whether email verification is enabled
*/
email: boolean
/**
* Whether an invite code is required to register
*/
invite_only: boolean
/**
* Autumn (file server) options
*/
autumn: {
/**
* Whether file uploads are enabled
*/
enabled: boolean
/**
* Autumn API URL
*/
url: string
}
/**
* January (proxy server) options
*/
january: {
/**
* Whether link embeds are enabled
*/
enabled: boolean,
/**
* January API URL
*/
url: string
}
/**
* Legacy voice server options
*/
voso: {
/**
* Whether voice is available (using voso)
*/
enabled: boolean
/**
* Voso API URL
*/
url: string
/**
* Voso WebSocket URL
*/
ws: string
}
}
/**
* WebSocket URL
*/
ws: string
/**
* URL to web app associated with this instance
*/
app: string
/**
* Web Push VAPID key
*/
vapid: string
}
export interface OnboardingInformation {
onboarding: boolean
}
-42
View File
@@ -1,42 +0,0 @@
import type { Attachment } from "./Autumn";
import type { Id } from "./_common";
export type ServerInvite = {
type: 'Server'
/**
* Invite Code
*/
_id: Id
/**
* ID of the server this invite is for.
*/
server: Id
/**
* ID of the user who created this invite.
*/
creator: Id
/**
* ID of the channel this invite is for.
*/
channel: Id
}
export type Invite = ServerInvite;
export type RetrievedInvite = {
type: 'Server'
server_id: Id
server_name: string
server_icon?: Attachment
server_banner?: Attachment
channel_id: Id
channel_name: string
channel_description?: string
user_name: string
user_avatar?: Attachment,
member_count: number
}
-64
View File
@@ -1,64 +0,0 @@
/**
* An embedded image
*/
export type EmbedImage = {
url: string
width: number
height: number
size: 'Large' | 'Preview'
}
/**
* An embedded video
*/
export type EmbedVideo = {
url: string
width: number
height: number
}
/**
* A special 3rd party embed
*/
export type EmbedSpecial = (
{ type: 'None' } |
{ type: 'YouTube', id: string, timestamp?: string } |
{ type: 'Twitch', content_type: 'Channel' | 'Video' | 'Clip', id: string } |
{ type: 'Spotify', content_type: string, id: string } |
{ type: 'Soundcloud' } |
{ type: 'Bandcamp', content_type: 'Album' | 'Track', id: string }
)
/**
* Message url embed
*/
export type JanuaryEmbed = (
{
type: 'Website'
url?: string
special?: EmbedSpecial
title?: string
description?: string
image?: EmbedImage
video?: EmbedVideo
site_name?: string
icon_url?: string
colour?: string
} | ({
type: 'Image'
} & EmbedImage)
);
-167
View File
@@ -1,167 +0,0 @@
import type { Attachment } from './Autumn';
import type { Id, OverrideField } from './_common';
export type MemberCompositeKey = {
server: Id
user: Id
}
export type Member = {
_id: MemberCompositeKey
nickname?: string
avatar?: Attachment
roles?: Id[]
}
export type Ban = {
_id: MemberCompositeKey
reason?: string
}
/**
* Valid HTML colour
*
* Warning: This is untrusted input, do not simply insert this anywhere.
*
* **Example usage:**
* ```js
* document.body.style.color = role.colour;
* ```
*
* @minLength 1
* @maxLength 32
*/
export type Colour = string;
export type Role = {
/**
* Role name
* @minLength 1
* @maxLength 32
**/
name: string
permissions: OverrideField
colour?: Colour
/**
* Whether to display this role separately on the members list
*/
hoist?: boolean
/**
* Role ranking
*
* A role with a smaller number will have permissions over roles with larger numbers.
*/
rank?: number
}
export type RoleInformation = Pick<Role, 'name' | 'colour' | 'hoist' | 'rank'>
export type Category = {
id: Id
title: string
channels: string[]
}
export type SystemMessageChannels = {
/** Channel ID where user join events should be sent */
user_joined?: Id
/** Channel ID where user leave events should be sent */
user_left?: Id
/** Channel ID where user kick events should be sent */
user_kicked?: Id
/** Channel ID where user ban events should be sent */
user_banned?: Id
}
export type Server = {
/**
* Server ID
*/
_id: Id
/**
* User ID of server owner
*/
owner: Id
/**
* Server name
*/
name: string
/**
* Server description
*/
description?: string
/**
* Array of server channel IDs
*/
channels: Id[]
/**
* Array of server categories
*/
categories?: Category[]
/**
* System message channels
*
* Each type of system message will be sent into the respective channel ID.
*/
system_messages?: SystemMessageChannels
/**
* Server roles
*/
roles?: { [key: string]: Role }
/**
* Default permissions for all members
*/
default_permissions: number
/**
* Server icon
*/
icon?: Attachment
/**
* Server banner
*/
banner?: Attachment
/**
* Whether this server is marked as not safe for work
*/
nsfw?: boolean
/**
* Server flags
*
* `1`: Official Revolt server
* `2`: Verified community server
*/
flags?: number
/**
* Whether to collect analytics on this server
* Enabled if server is discoverable
*/
analytics?: boolean
/**
* Whether this server is discoverable
*/
discoverable?: boolean
}
-23
View File
@@ -1,23 +0,0 @@
import type { Id } from "./_common"
export type UserSettings = {
[key: string]: [ number, string ]
}
export type ChannelCompositeKey = {
channel: Id,
user: Id
}
export interface ChannelUnread {
_id: ChannelCompositeKey,
last_id: string,
mentions?: string[]
}
export interface WebPushSubscription {
endpoint: String,
p256dh: String,
auth: String,
}
-157
View File
@@ -1,157 +0,0 @@
import type { Attachment } from './Autumn';
import type { Id } from './_common';
/**
* Username
* @minLength 2
* @maxLength 32
* @pattern ^[a-zA-Z0-9_.]+$
*/
export type Username = string;
/**
* Your relationship with the user
*/
export enum RelationshipStatus {
None = "None",
User = "User",
Friend = "Friend",
Outgoing = "Outgoing",
Incoming = "Incoming",
Blocked = "Blocked",
BlockedOther = "BlockedOther"
}
export type RelationshipOnly = {
status: RelationshipStatus
};
export type Relationship = RelationshipOnly & {
/**
* Other user's ID
*/
_id: Id
};
/**
* User presence
*/
export enum Presence {
Online = "Online",
Idle = "Idle",
Busy = "Busy",
Invisible = "Invisible"
}
/**
* User status
*/
export type Status = {
/**
* Custom status text
* @minLength 1
* @maxLength 128
*/
text?: string
presence?: Presence
}
export enum Badges {
Developer = 1,
Translator = 2,
Supporter = 4,
ResponsibleDisclosure = 8,
Founder = 16,
PlatformModeration = 32,
ActiveSupporter = 64,
Paw = 128,
EarlyAdopter = 256,
ReservedRelevantJokeBadge1 = 512,
}
/**
* Bot information
*/
export interface BotInformation {
/**
* The User ID of the owner of this bot
*/
owner: Id
}
export interface User {
/**
* User ID
*/
_id: Id
username: Username
/**
* User avatar
*/
avatar?: Attachment
/**
* Relationships with other known users
* Only present if fetching self
*/
relations?: Relationship[]
/**
* Bitfield of user's badges
*
* `1`: Developer
* `2`: Translator
* `4`: Supporter
* `8`: Responsible Disclosure
* `16`: Founder
* `32`: Platform Moderation
* `64`: Active Supporter
* `128`: Paw
* `256`: Early Adopter
* `512`: Reserved Relevant Joke Badge 1
*/
badges?: number
status?: Status
/**
* Relationship to user
*/
relationship?: RelationshipStatus
/**
* Whether the user is online
*/
online?: boolean
/**
* User flags
*
* `1`: Account is suspended
* `2`: Account was deleted
* `4`: Account is banned
*/
flags?: number
/**
* Bot information, present if user is a bot.
*/
bot?: BotInformation
}
export interface Profile {
/**
* Profile content
* @minLength 0
* @maxLength 2000
*/
content?: string
/**
* Profile background
*/
background?: Attachment
}
-42
View File
@@ -1,42 +0,0 @@
/**
* Id
* @pattern [0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}
*/
export type Id = string;
/**
* Nonce value, prefer to use ULIDs here for better feature support.
*
* Used to prevent double requests to create objects.
*
* @minLength 1
* @maxLength 36
*/
export type Nonce = string;
/**
* Autumn file ID, [learn more](https://example.com/TODO).
* @minLength 1
* @maxLength 128
*/
export type AutumnId = string;
/**
* Permission override as it is processed.
*/
export type Override = {
// Allowed permission values
allow: number,
// Denied permission values
deny: number
};
/**
* Permission override as it is stored in the database.
*/
export type OverrideField = {
// Allowed permission values
a: number,
// Denied permission values
d: number
};
+57 -1958
View File
File diff suppressed because it is too large Load Diff