mirror of
https://github.com/stoatchat/javascript-client-api.git
synced 2026-08-26 12:35:48 -04:00
Add OpenAPI generators, automation, and user routes.
This commit is contained in:
Vendored
+2
-1
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"emeraldwalk.runonsave"
|
||||
"awwsky.regionmarker",
|
||||
"txava.region-marker"
|
||||
]
|
||||
}
|
||||
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"emeraldwalk.runonsave": {
|
||||
"commands": [
|
||||
{
|
||||
"match": ".md$",
|
||||
"isAsync": true,
|
||||
"cmd": "yarn build"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "npm: build",
|
||||
"detail": "yarn generate:apib && yarn generate:html"
|
||||
}
|
||||
]
|
||||
}
|
||||
+1339
-47
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/nodemon.json",
|
||||
"watch": [
|
||||
"**/*.ts"
|
||||
],
|
||||
"ext": "ts",
|
||||
"ignore": [
|
||||
"__temp.ts"
|
||||
]
|
||||
}
|
||||
+10
-5
@@ -1,18 +1,23 @@
|
||||
{
|
||||
"name": "api",
|
||||
"version": "0.0.0",
|
||||
"main": "index.js",
|
||||
"version": "0.5.1-alpha.7",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"repository": "https://gitlab.insrt.uk/revolt/api.git",
|
||||
"author": "Paul <paulmakles@gmail.com>",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build:generator": "tsc",
|
||||
"start:generator": "node dist",
|
||||
"watch:generator": "tsc-watch --onSuccess \"node dist\"",
|
||||
"preview": "sirv out"
|
||||
"start:generator": "node .",
|
||||
"watch:generator": "tsc-watch",
|
||||
"redoc": "docker run --network host -e SPEC_URL=http://127.0.0.1:5500/OpenAPI.json redocly/redoc",
|
||||
"preview": "sirv . --port 5500 --host",
|
||||
"dev": "concurrently \"yarn redoc\" \"nodemon --exec \\\"yarn build:generator && yarn start:generator && yarn preview\\\"\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openapi-contrib/json-schema-to-openapi-schema": "^2.0.0",
|
||||
"concurrently": "^6.2.0",
|
||||
"nodemon": "^2.0.12",
|
||||
"openapi-types": "^9.1.0",
|
||||
"sirv-cli": "^1.0.12",
|
||||
"tsc-watch": "^4.4.0",
|
||||
|
||||
+44
-63
@@ -1,71 +1,52 @@
|
||||
import { resolve } from "path";
|
||||
import * as TJS from "typescript-json-schema";
|
||||
import { readdirSync, readFileSync, writeFileSync } from "fs";
|
||||
import convert from '@openapi-contrib/json-schema-to-openapi-schema';
|
||||
import { writeFile } from 'fs/promises';
|
||||
import type { OpenAPIV3 } from "openapi-types";
|
||||
import type * as TJS from "typescript-json-schema";
|
||||
|
||||
const files = readdirSync('types')
|
||||
.map(x => resolve('types', x));
|
||||
type Document = OpenAPIV3.Document & { definitions?: TJS.Definition };
|
||||
|
||||
const program = TJS.getProgramFromFiles(
|
||||
files,
|
||||
{ }
|
||||
);
|
||||
import info from './openapi/info.js';
|
||||
import definitions from './openapi/definitions.js';
|
||||
import paths, { group, tags } from './openapi/paths.js';
|
||||
|
||||
const generator = TJS.buildGenerator(program, {
|
||||
required: true,
|
||||
// titles: true
|
||||
});
|
||||
import './routes/index.js';
|
||||
|
||||
const TYPE_RE = /(?:type|enum|interface) (\w+)/g
|
||||
|
||||
let types: string[] = [];
|
||||
for (const path of files) {
|
||||
const f = readFileSync(path).toString();
|
||||
types = types.concat([...f.matchAll(TYPE_RE)].map(x => x[1]));
|
||||
}
|
||||
|
||||
const pkg = require('../package.json');
|
||||
import { OpenAPIV3 } from 'openapi-types';
|
||||
|
||||
(async () => {
|
||||
let definitions: { [key: string]: TJS.Definition } = {};
|
||||
for (let type of types) {
|
||||
const defn = generator?.getSchemaForSymbol(type);
|
||||
if (defn) {
|
||||
definitions[type] = await convert(defn);
|
||||
}
|
||||
}
|
||||
|
||||
// import { inspect } from 'util';
|
||||
// console.log(inspect(definitions, false, 10, true));
|
||||
|
||||
const OpenAPI: (OpenAPIV3.Document & { definitions: typeof definitions }) = {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Revolt API",
|
||||
version: pkg.version
|
||||
},
|
||||
paths: {
|
||||
"/": {
|
||||
get: {
|
||||
summary: "test",
|
||||
responses: {
|
||||
"200": {
|
||||
"description": "bro",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
$ref: "#/definitions/Channel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
async function generate(): Promise<Document> {
|
||||
return {
|
||||
['__comment' as any]: "THIS FILE WAS AUTO-GENERATED USING https://gitlab.insrt.uk/revolt/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: {
|
||||
userId: {
|
||||
type: "apiKey",
|
||||
in: "header",
|
||||
name: "x-user-id",
|
||||
description: "User ID is found when calling `/auth/login`.\n"
|
||||
},
|
||||
sessionToken: {
|
||||
type: "apiKey",
|
||||
in: "header",
|
||||
name: "x-session-token",
|
||||
description: "Session is created by calling `/auth/login`.\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
definitions
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
writeFileSync('OpenAPI.json', JSON.stringify(OpenAPI, undefined, 2));
|
||||
})();
|
||||
generate()
|
||||
.then(v =>
|
||||
writeFile('OpenAPI.json', JSON.stringify(v, undefined, 2))
|
||||
);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
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) {
|
||||
const defn = generator?.getSchemaForSymbol(type);
|
||||
if (defn) {
|
||||
definitions[type] = await convert(defn);
|
||||
}
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { OpenAPIV3 } from "openapi-types";
|
||||
|
||||
export async function success(description: string, json?: Promise<OpenAPIV3.MediaTypeObject> | OpenAPIV3.MediaTypeObject | 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 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}`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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"
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
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}.`);
|
||||
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'>): OpenAPIV3.OperationObject {
|
||||
return {
|
||||
...route(summary, description, obj),
|
||||
security: [
|
||||
{
|
||||
userId: [],
|
||||
sessionToken: []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export default async function(): Promise<OpenAPIV3.PathsObject<{}>> {
|
||||
return resources;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { group, resource, route, routeAuthenticated, tag } from "../openapi/paths.js";
|
||||
import { body, 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")
|
||||
)
|
||||
)
|
||||
});
|
||||
|
||||
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 success("Successfully set username")
|
||||
}
|
||||
)
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
export async function load() {
|
||||
await import('./core.js');
|
||||
await import('./users.js');
|
||||
}
|
||||
|
||||
await load();
|
||||
@@ -0,0 +1,284 @@
|
||||
import { body, parameter, ref, success } from "../openapi/generators.js";
|
||||
import { group, resource, 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");
|
||||
|
||||
resource('/users/:user', {
|
||||
get: routeAuthenticated(
|
||||
"Fetch User",
|
||||
"Retrieve a user's information.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref("Id"))
|
||||
],
|
||||
...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 success("Succesfully changed user object.")
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
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 success("Succesfully changed user object.")
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
resource('/users/:user/profile', {
|
||||
get: routeAuthenticated(
|
||||
"Fetch User Profile",
|
||||
"Retrieve a user's profile data.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref("Id"))
|
||||
],
|
||||
...await success(
|
||||
"User profile.",
|
||||
ref("Profile")
|
||||
)
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
resource('/users/:user/default_avatar', {
|
||||
get: routeAuthenticated(
|
||||
"Fetch Default Avatar",
|
||||
"This returns a default avatar based on the given id.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref("Id"))
|
||||
],
|
||||
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",
|
||||
"Retrieve a list of mutual friends with another user.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref("Id"))
|
||||
],
|
||||
...await success(
|
||||
"Mutual friends.",
|
||||
schema`
|
||||
interface ${'MutualFriends'} {
|
||||
/**
|
||||
* Array of user IDs who both you and the other user are friends with.
|
||||
*/
|
||||
users: 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.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref('Id'))
|
||||
],
|
||||
...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[];
|
||||
`
|
||||
)
|
||||
)
|
||||
});
|
||||
|
||||
resource('/users/:user/relationship', {
|
||||
get: routeAuthenticated(
|
||||
"Fetch Relationship",
|
||||
"Fetch your relationship with another other user.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref('Id'))
|
||||
],
|
||||
...await success(
|
||||
"Your relationship with the user.",
|
||||
ref("RelationshipOnly")
|
||||
)
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
resource('/users/:user/friend', {
|
||||
put: routeAuthenticated(
|
||||
"Send Friend Request / Accept Request",
|
||||
"Send a friend request to another user or accept another user's friend request.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref('Id'))
|
||||
],
|
||||
...await success(
|
||||
"Sent friend request / added user as friend.",
|
||||
ref("RelationshipOnly")
|
||||
)
|
||||
}
|
||||
),
|
||||
delete: routeAuthenticated(
|
||||
"Deny Friend Request / Remove Friend",
|
||||
"Denies another user's friend request or removes an existing friend.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref('Id'))
|
||||
],
|
||||
...await success(
|
||||
"Deleted friend request / removed user from friends.",
|
||||
ref("RelationshipOnly")
|
||||
)
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
resource('/users/:user/block', {
|
||||
put: routeAuthenticated(
|
||||
"Block User",
|
||||
"Block another user.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref('Id'))
|
||||
],
|
||||
...await success(
|
||||
"Blocked user.",
|
||||
ref("RelationshipOnly")
|
||||
)
|
||||
}
|
||||
),
|
||||
delete: routeAuthenticated(
|
||||
"Unblock User",
|
||||
"Unblock another user.",
|
||||
{
|
||||
parameters: [
|
||||
await parameter('user', 'User ID', ref('Id'))
|
||||
],
|
||||
...await success(
|
||||
"Unblocked user.",
|
||||
ref("RelationshipOnly")
|
||||
)
|
||||
}
|
||||
)
|
||||
});
|
||||
//#endregion
|
||||
@@ -0,0 +1,28 @@
|
||||
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);
|
||||
}
|
||||
+3
-3
@@ -3,9 +3,9 @@
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"incremental": true, /* Enable incremental compilation */
|
||||
"target": "es2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
"module": "ESNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
@@ -44,7 +44,7 @@
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -104,3 +104,7 @@ export interface RevoltConfiguration {
|
||||
*/
|
||||
vapid: string
|
||||
}
|
||||
|
||||
export interface OnboardingInformation {
|
||||
onboarding: boolean
|
||||
}
|
||||
|
||||
+16
-3
@@ -14,13 +14,15 @@ export enum RelationshipStatus {
|
||||
BlockedOther = "BlockedOther"
|
||||
}
|
||||
|
||||
export type Relationship = {
|
||||
export type RelationshipOnly = {
|
||||
status: RelationshipStatus
|
||||
};
|
||||
|
||||
export type Relationship = RelationshipOnly & {
|
||||
/**
|
||||
* Other user's ID
|
||||
*/
|
||||
_id: Id
|
||||
|
||||
status: RelationshipStatus
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -33,6 +35,9 @@ export enum Presence {
|
||||
Invisible = "Invisible"
|
||||
}
|
||||
|
||||
/**
|
||||
* User status
|
||||
*/
|
||||
export type Status = {
|
||||
/**
|
||||
* Custom status text
|
||||
@@ -60,12 +65,16 @@ export interface User {
|
||||
_id: Id
|
||||
|
||||
/**
|
||||
* Username
|
||||
* @minLength 2
|
||||
* @maxLength 32
|
||||
* @pattern ^[a-zA-Z0-9_.]+$
|
||||
*/
|
||||
username: string
|
||||
|
||||
/**
|
||||
* User avatar
|
||||
*/
|
||||
avatar?: Attachment
|
||||
|
||||
/**
|
||||
@@ -94,10 +103,14 @@ export interface User {
|
||||
|
||||
export interface Profile {
|
||||
/**
|
||||
* Profile content
|
||||
* @minLength 0
|
||||
* @maxLength 2000
|
||||
*/
|
||||
content?: string
|
||||
|
||||
/**
|
||||
* Profile background
|
||||
*/
|
||||
background?: Attachment
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
import type { Relationship } from "./Users";
|
||||
type FetchRelationships = Relationship[];
|
||||
|
||||
@@ -10,3 +10,8 @@ export type Id = string;
|
||||
* @maxLength 36
|
||||
*/
|
||||
export type Nonce = string;
|
||||
|
||||
/**
|
||||
* Autumn file ID, [learn more](https://example.com/TODO).
|
||||
*/
|
||||
export type AutumnId = string;
|
||||
|
||||
Reference in New Issue
Block a user