The great type inquisition - refactoring 99%, adding features 1%.

Please make ambient types work everywhere, more easily, Microsoft.
Ambient types are not being used because I could not manage to get them to work with the frontend, backend, and tests at once.
Most of the time, the simpler solution is better, not the lazier - i.e. ambient types allow me to avoid importing types, for the cost of intense research to get this technological feat to work (months of development).
Also symbolic links don't work (well) with Windows. Mixing Linux and Windows development combined, is not conducive to a working development environment. I know I can use Linux on Windows but that's like using Wine on Linux which is not worth the effort, in my experience.

1) Don't mix Windows and Linux features - they don't work together.
2) Don't use ambient types, unless you need to and understand the full dynamics of ambient types, or are a Microsoft TypeScript engineer.
This commit is contained in:
ADAMJR 2021-12-22 00:03:59 +00:00
parent cf223ceac5
commit bb8256a123
20 changed files with 99 additions and 150 deletions

View File

@ -1,6 +1,6 @@
FROM node:16-alpine3.14
RUN addgroup app && adduser -SG app app
RUN mkdir /app && chown app:app /app
RUN mkdir /app && chown app:app /app `
USER app
WORKDIR /app/backend

View File

@ -1,3 +1,4 @@
import { WS } from '@accord/types';
import { Socket } from 'socket.io';
import { WebSocket } from '../websocket';
import { WSEvent } from './ws-event';

View File

@ -1,25 +1,14 @@
import { Socket } from 'socket.io';
import { PermissionTypes } from '@accord/types/permission.types';
import { Role } from '../../data/models/role';
import { WSGuard } from '../modules/ws-guard';
import { WebSocket } from '../websocket';
import { WSEvent, } from './ws-event';
import { GuildMember } from '../../data/models/guild-member';
import Roles from '../../data/roles';
export default class implements WSEvent<'GUILD_ROLE_DELETE'> {
on = 'GUILD_ROLE_DELETE' as const;
constructor(
private guard = deps.wsGuard,
private roles = deps.roles,
) {}
public async invoke(ws: WebSocket, client: Socket, { guildId, roleId }: WS.Params.GuildRoleDelete) {
const role = await this.roles.get(roleId);
await this.guard.validateCan(client, guildId, 'MANAGE_ROLES');
const role = await deps.roles.get(roleId);
await deps.wsGuard.validateCan(client, guildId, 'MANAGE_ROLES');
if (role.name === '@everyone')
throw new TypeError('This role cannot be deleted');
@ -33,8 +22,10 @@ export default class implements WSEvent<'GUILD_ROLE_DELETE'> {
{ runValidators: true },
);
ws.io
.to(guildId)
.emit('GUILD_ROLE_DELETE', { guildId, roleId } as WS.Args.GuildRoleDelete);
return [{
emit: this.on,
to: [guildId],
send: { guildId, roleId },
}];
}
}

View File

@ -1,9 +1,4 @@
import { Socket } from 'socket.io';
import Invites from '../../data/invites';
import { PermissionTypes } from '@accord/types/permission.types';
import { WSGuard } from '../modules/ws-guard';
import { WebSocket } from '../websocket';
import { WSEvent, } from './ws-event';

View File

@ -2,7 +2,6 @@
"name": "accord-frontend",
"version": "0.0.0",
"private": true,
"homepage": "https://accord.app",
"dependencies": {
"@accord/types": "file:../types",
"@craco/craco": "^5.9.0",
@ -51,7 +50,7 @@
},
"scripts": {
"start": "npm run start:dev",
"start:dev": "craco start",
"start:dev": "set PORT=4200 && craco start",
"start:prod": "craco start",
"build:dev": "dotenv -e env/.env.dev craco build",
"build:prod": "dotenv -e env/.env.prod craco build",

View File

@ -1,7 +1,7 @@
import { PermissionTypes } from '@accord/types/permission.types';
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import usePerms from '../../../hooks/use-perms';
import { PermissionTypes } from '../../../services/perm-service';
import { openSaveChanges } from '../../../store/ui';
import NormalButton from '../../utils/buttons/normal-button';
import Category from '../../utils/category';

View File

@ -1,6 +1,6 @@
import { PermissionTypes } from '@accord/types/permission.types';
import { useDispatch, useSelector } from 'react-redux';
import usePerms from '../../../hooks/use-perms';
import { PermissionTypes } from '../../../services/perm-service';
import { openSaveChanges } from '../../../store/ui';
import ThreeToggle from '../../inputs/three-toggle';

View File

@ -1,11 +1,11 @@
import { UseFormSetValue, FieldValues } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import usePerms from '../../../hooks/use-perms';
import { PermissionTypes } from '../../../services/perm-service';
import { openSaveChanges } from '../../../store/ui';
import NormalButton from '../../utils/buttons/normal-button';
import Category from '../../utils/category';
import Toggle from '../../inputs/toggle';
import { PermissionTypes } from '@accord/types/permission.types';
export interface RolePermissionsProps {
setRoleValue: UseFormSetValue<FieldValues>;

View File

@ -1,4 +1,5 @@
import '@accord/types';
import { WS } from '@accord/types';
import './index.css';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/app';
@ -7,11 +8,6 @@ import { Provider } from 'react-redux';
import configureStore from './store/configure-store';
import { SnackbarProvider } from 'notistack';
import './index.css';
console.log(process.env);
ReactDOM.render(
<SnackbarProvider maxSnack={1}>
<Provider store={configureStore()}>

View File

@ -1,52 +1,9 @@
import { PermissionTypes } from '@accord/types/permission.types';
import { getChannel } from '../store/channels';
import { getGuild, getGuildRoles } from '../store/guilds';
import { getMember, getSelfMember } from '../store/members';
import { getRoles } from '../store/roles';
// FIXME: import this namespace from types
export namespace PermissionTypes {
export enum General {
VIEW_CHANNELS = 1024,
// MANAGE_NICKNAMES = 512, // change number
// CHANGE_NICKNAME = 256, // change number
MANAGE_INVITES = 256,
CREATE_INVITE = 128,
KICK_MEMBERS = 64,
// BAN_MEMBERS = 32, // change number
MANAGE_CHANNELS = 16,
MANAGE_ROLES = 8,
MANAGE_GUILD = 4,
// VIEW_AUDIT_LOG = 2, // change number
ADMINISTRATOR = 1,
}
export enum Text {
// ADD_REACTIONS = 2048 * 16,
// MENTION_EVERYONE = 2048 * 8,
READ_MESSAGES = 2048 * 4,
MANAGE_MESSAGES = 2048 * 2,
SEND_MESSAGES = 2048,
}
export enum Voice {
// MOVE_MEMBERS = 32768 * 8,
// MUTE_MEMBERS = 32768 * 4,
SPEAK = 32768 * 2,
CONNECT = 32768,
}
export const All = {
...General,
...Text,
...Voice,
}
export type Permission = General | Text | Voice;
export type PermissionString = keyof typeof All;
export const defaultPermissions =
PermissionTypes.General.VIEW_CHANNELS
| PermissionTypes.General.CREATE_INVITE
| PermissionTypes.Text.SEND_MESSAGES
| PermissionTypes.Text.READ_MESSAGES;
}
export class PermService {
public readonly description = {
general: {

View File

@ -21,7 +21,8 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"types": ["cypress", "dom-mediacapture-record"]
"types": ["cypress", "dom-mediacapture-record"],
"checkJs": false
},
"include": [
"src",

View File

@ -1,4 +1,4 @@
declare namespace Auth {
export namespace Auth {
export interface Credentials {
email?: string;
password: string;

View File

@ -18,7 +18,7 @@ import Users from '@accord/backend/data/users';
import ChannelJoin from '@accord/backend/ws/ws-events/channel-join';
import ChannelLeave from '@accord/backend/ws/ws-events/channel-leave';
declare interface Deps {
export interface Deps {
channels: Channels;
/** @deprecated */
channelJoin: ChannelJoin;

View File

@ -1,4 +1,4 @@
declare namespace Entity {
export namespace Entity {
export interface App {
id: string;
createdAt: Date;
@ -82,7 +82,7 @@ declare namespace Entity {
}
}
declare namespace ChannelTypes {
export namespace ChannelTypes {
export type Type = 'TEXT' | 'VOICE';
export interface Text extends Entity.Channel {
@ -103,20 +103,20 @@ declare namespace ChannelTypes {
}
}
declare namespace GeneralTypes {
export namespace GeneralTypes {
export interface SnowflakeEntity {
id: string;
}
}
declare namespace InviteTypes {
export namespace InviteTypes {
export interface Options {
expiresAt?: Date;
maxUses?: number;
}
}
declare namespace MessageTypes {
export namespace MessageTypes {
export interface Attachment {
id: string;
name: string;
@ -134,7 +134,7 @@ declare namespace MessageTypes {
| 'GUILD_MEMBER_LEAVE';
}
declare namespace UserTypes {
export namespace UserTypes {
export type Badge =
| 'BUG_1'
| 'BUG_2'

View File

@ -1,9 +1,9 @@
import './auth.types';
import './deps.types';
import './dotenv.types';
import './entity.types';
import './global.types';
import './rest.types';
import './store.types';
import './util.types';
import './ws.types';
export * from './auth.types';
export * from './deps.types';
export * from './dotenv.types';
export * from './entity.types';
export * from './global.types';
export * from './rest.types';
export * from './store.types';
export * from './util.types';
export * from './ws.types';

View File

@ -1,4 +1,6 @@
declare namespace REST {
import { Entity } from './entity.types';
export namespace REST {
export namespace To {
export interface Post {
'/auth/login': {

View File

@ -1,4 +1,7 @@
declare namespace Store {
import { Entity, UserTypes } from './entity.types';
import { WS } from './ws.types';
export namespace Store {
export interface AppState {
auth: {
attemptedLogin: boolean;
@ -46,7 +49,7 @@ declare namespace Store {
};
}
export interface Action<P extends WS.Params> {
export interface Action<P extends WS.To> {
type: string;
payload: P;
}

View File

@ -1,3 +1,5 @@
import { WS } from './ws.types';
declare global {
const socket: {
emit: <K extends keyof WS.To>(event: K, args: WS.To[K]) => any;

View File

@ -1,3 +1,3 @@
declare module Util {
export module Util {
export interface Dictionary { [k: string]: string };
}

View File

@ -1,56 +1,58 @@
declare namespace WS {
import { Entity, ChannelTypes, InviteTypes, MessageTypes, UserTypes } from './entity.types';
export namespace WS {
export interface To {
/** Create a channel in a guild. */
'CHANNEL_CREATE': WS.Params.ChannelCreate;
'CHANNEL_CREATE': Params.ChannelCreate;
/** Delete a channel in a guild. */
'CHANNEL_DELETE': WS.Params.ChannelDelete;
'CHANNEL_DELETE': Params.ChannelDelete;
/** Update a channel in a guild. */
'CHANNEL_UPDATE': WS.Params.ChannelUpdate;
'CHANNEL_UPDATE': Params.ChannelUpdate;
/** Join a voice channel and receive voice events. */
'CHANNEL_JOIN': WS.Params.ChannelJoin;
'CHANNEL_JOIN': Params.ChannelJoin;
/** Leave the voice channel that the client is in. */
'CHANNEL_LEAVE': WS.Params.ChannelLeave;
'CHANNEL_LEAVE': Params.ChannelLeave;
/** Create a guild. */
'GUILD_CREATE': WS.Params.GuildCreate;
'GUILD_CREATE': Params.GuildCreate;
/** Delete a guild. */
'GUILD_DELETE': WS.Params.GuildDelete;
'GUILD_DELETE': Params.GuildDelete;
/** Accept a guild invite. */
'GUILD_MEMBER_ADD': WS.Params.GuildMemberAdd;
'GUILD_MEMBER_ADD': Params.GuildMemberAdd;
/** Remove a member from a guild. */
'GUILD_MEMBER_REMOVE': WS.Params.GuildMemberRemove;
'GUILD_MEMBER_REMOVE': Params.GuildMemberRemove;
/** Update a members roles or other properties on a member. */
'GUILD_MEMBER_UPDATE': WS.Params.GuildMemberUpdate;
'GUILD_MEMBER_UPDATE': Params.GuildMemberUpdate;
/** Create a role in a guild. */
'GUILD_ROLE_CREATE': WS.Params.GuildRoleCreate;
'GUILD_ROLE_CREATE': Params.GuildRoleCreate;
/** Delete a role in a guild. */
'GUILD_ROLE_DELETE': WS.Params.GuildRoleDelete;
'GUILD_ROLE_DELETE': Params.GuildRoleDelete;
/** Update a guild role permissions or other properties. */
'GUILD_ROLE_UPDATE': WS.Params.GuildRoleUpdate;
'GUILD_ROLE_UPDATE': Params.GuildRoleUpdate;
/** Update the settings of a guild. */
'GUILD_UPDATE': WS.Params.GuildUpdate;
'GUILD_UPDATE': Params.GuildUpdate;
/** Create an invite in a guild */
'INVITE_CREATE': WS.Params.InviteCreate;
'INVITE_CREATE': Params.InviteCreate;
/** Delete an existing invite in a guild. */
'INVITE_DELETE': WS.Params.InviteDelete;
'INVITE_DELETE': Params.InviteDelete;
/** Create a message in a text-based channel. */
'MESSAGE_CREATE': WS.Params.MessageCreate;
'MESSAGE_CREATE': Params.MessageCreate;
/** Delete an existing message in a text-based channel. */
'MESSAGE_DELETE': WS.Params.MessageDelete;
'MESSAGE_DELETE': Params.MessageDelete;
/** Update an existing message in a text-based channel. */
'MESSAGE_UPDATE': WS.Params.MessageUpdate;
'MESSAGE_UPDATE': Params.MessageUpdate;
/** Bootstrap your websocket client to be able to use other websocket events.
* - Associate ws client ID with user ID.
* - Join user rooms.
* - Set online status. */
'READY': WS.Params.Ready;
'READY': Params.Ready;
/** Indicate that you are typing in a text-based channel. */
'TYPING_START': WS.Params.TypingStart;
'TYPING_START': Params.TypingStart;
/** Delete a user with a given token. */
'USER_DELETE': WS.Params.UserDelete;
'USER_DELETE': Params.UserDelete;
/** Update a user with a given token. */
'USER_UPDATE': WS.Params.UserUpdate;
'USER_UPDATE': Params.UserUpdate;
/** Send voice data to the server. */
'VOICE_DATA': WS.Params.VoiceData;
'VOICE_DATA': Params.VoiceData;
}
export interface On {
@ -61,55 +63,55 @@ declare namespace WS {
/** WS Args are what is received from the websocket. */
export interface From {
/** Called when a guild channel is created. */
'CHANNEL_CREATE': WS.Args.ChannelCreate;
'CHANNEL_CREATE': Args.ChannelCreate;
/** Called when a guild channel is deleted. */
'CHANNEL_DELETE': WS.Args.ChannelDelete;
'CHANNEL_DELETE': Args.ChannelDelete;
/** Called when a guild channel is updated. */
'CHANNEL_UPDATE': WS.Args.ChannelUpdate;
'CHANNEL_UPDATE': Args.ChannelUpdate;
/** Called when a guild is deleted, or the client leaves a guild. */
'GUILD_DELETE': WS.Args.GuildDelete;
'GUILD_DELETE': Args.GuildDelete;
/** Called when the client joins a guild. */
'GUILD_CREATE': WS.Args.GuildCreate;
'GUILD_CREATE': Args.GuildCreate;
/** Called when someone joins a guild by an invite, a bot is added, or the client joins guild. */
'GUILD_MEMBER_ADD': WS.Args.GuildMemberAdd;
'GUILD_MEMBER_ADD': Args.GuildMemberAdd;
/** Called when a guild member is removed, or leaves the guild. */
'GUILD_MEMBER_REMOVE': WS.Args.GuildMemberRemove;
'GUILD_MEMBER_REMOVE': Args.GuildMemberRemove;
/** Called when member roles are updated, or other properties. */
'GUILD_MEMBER_UPDATE': WS.Args.GuildMemberUpdate;
'GUILD_MEMBER_UPDATE': Args.GuildMemberUpdate;
/** Called when a guild role is created. */
'GUILD_ROLE_CREATE': WS.Args.GuildRoleCreate;
'GUILD_ROLE_CREATE': Args.GuildRoleCreate;
/** Called when a guild role is deleted. */
'GUILD_ROLE_DELETE': WS.Args.GuildRoleDelete;
'GUILD_ROLE_DELETE': Args.GuildRoleDelete;
/** Called when properties on a guild role are updated. */
'GUILD_ROLE_UPDATE': WS.Args.GuildRoleUpdate;
'GUILD_ROLE_UPDATE': Args.GuildRoleUpdate;
/** Called when guild settings are updated. */
'GUILD_UPDATE': WS.Args.GuildUpdate;
'GUILD_UPDATE': Args.GuildUpdate;
/** Called when a guild invite is created. */
'INVITE_CREATE': WS.Args.InviteCreate;
'INVITE_CREATE': Args.InviteCreate;
/** Called when an existing guild invite is deleted. */
'INVITE_DELETE': WS.Args.InviteDelete;
'INVITE_DELETE': Args.InviteDelete;
/** Called when a message is created in a text-based channel. */
'MESSAGE_CREATE': WS.Args.MessageCreate;
'MESSAGE_CREATE': Args.MessageCreate;
/** Called when a message is deleted in a text-based channel. */
'MESSAGE_DELETE': WS.Args.MessageDelete;
'MESSAGE_DELETE': Args.MessageDelete;
/** Called when an existing message is updated in a text-based channel. */
'MESSAGE_UPDATE': WS.Args.MessageUpdate;
'MESSAGE_UPDATE': Args.MessageUpdate;
/** Called when a message is sent in a channel you are not ignoring. */
'PING': WS.Args.Ping;
'PING': Args.Ping;
/** Called when a user goes online or offline. */
'PRESENCE_UPDATE': WS.Args.PresenceUpdate;
'PRESENCE_UPDATE': Args.PresenceUpdate;
/** Called when the websocket accepts that you are ready. */
'READY': WS.Args.Ready;
'READY': Args.Ready;
/** Called when someone is typing in a text-based channel. */
'TYPING_START': WS.Args.TypingStart;
'TYPING_START': Args.TypingStart;
/** Called the client user is deleted. */
'USER_DELETE': {};
/** Called the client user settings are updated. */
'USER_UPDATE': WS.Args.UserUpdate;
'USER_UPDATE': Args.UserUpdate;
/** Receive voice data from the server. */
'VOICE_DATA': WS.Args.VoiceData;
'VOICE_DATA': Args.VoiceData;
/** Called when a user voice state is updated in the client's voice channel. */
'VOICE_STATE_UPDATE': WS.Args.VoiceStateUpdate;
'VOICE_STATE_UPDATE': Args.VoiceStateUpdate;
'error': object;
}
@ -210,7 +212,7 @@ declare namespace WS {
embed?: MessageTypes.Embed;
}
export interface MessageCreate {
content: string;
content?: string;
}
export interface Ready {
token: string;
@ -371,7 +373,7 @@ declare namespace WS {
}
export interface VoiceData {
channelId: string;
connections: VoiceConnection[];
connections: ChannelTypes.VoiceConnection[];
}
export interface VoiceStateUpdate {
userId: string;