Start on the JS SDK

This commit is contained in:
Braydon 2024-09-09 19:05:48 -04:00
parent 5bdda1d889
commit c12df9a870
13 changed files with 295 additions and 10 deletions

@ -4,7 +4,6 @@ import lombok.*;
import net.dv8tion.jda.api.OnlineStatus; import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.*;
import java.text.SimpleDateFormat;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -153,12 +152,12 @@ public final class DiscordUser {
@AllArgsConstructor @Getter @EqualsAndHashCode @AllArgsConstructor @Getter @EqualsAndHashCode
public static class Banner { public static class Banner {
/** /**
* The id of the user's avatar. * The id of the user's banner.
*/ */
@NonNull private final String id; @NonNull private final String id;
/** /**
* The URL of the user's avatar. * The URL of the user's banner.
*/ */
@NonNull private final String url; @NonNull private final String url;
} }
@ -184,14 +183,14 @@ public final class DiscordUser {
@NonNull private final String album; @NonNull private final String album;
/** /**
* The current progress of the track. * The current progress of the track (in millis).
*/ */
@NonNull private final String trackProgress; private final long trackProgress;
/** /**
* The total length of the track. * The total length of the track (in millis).
*/ */
@NonNull private final String trackLength; private final long trackLength;
/** /**
* The unix time of when this track started playing. * The unix time of when this track started playing.
@ -211,7 +210,6 @@ public final class DiscordUser {
*/ */
@NonNull @SuppressWarnings("DataFlowIssue") @NonNull @SuppressWarnings("DataFlowIssue")
public static SpotifyActivity fromActivity(@NonNull RichPresence richPresence) { public static SpotifyActivity fromActivity(@NonNull RichPresence richPresence) {
SimpleDateFormat dateFormat = new SimpleDateFormat("m:ss");
long started = Objects.requireNonNull(richPresence.getTimestamps()).getStart(); long started = Objects.requireNonNull(richPresence.getTimestamps()).getStart();
long ends = richPresence.getTimestamps().getEnd(); long ends = richPresence.getTimestamps().getEnd();
@ -220,8 +218,7 @@ public final class DiscordUser {
return new SpotifyActivity( return new SpotifyActivity(
richPresence.getDetails(), richPresence.getState().replace(";", ","), richPresence.getDetails(), richPresence.getState().replace(";", ","),
richPresence.getLargeImage().getText(), dateFormat.format(trackProgress), richPresence.getLargeImage().getText(), trackProgress, trackLength, started, ends
dateFormat.format(trackLength), started, ends
); );
} }
} }

4
JS-SDK/.gitignore vendored Normal file

@ -0,0 +1,4 @@
node_modules
.idea/
.vscode/
dist

1
JS-SDK/.npmrc Normal file

@ -0,0 +1 @@
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

1
JS-SDK/README.md Normal file

@ -0,0 +1 @@
# JS-SDK

8
JS-SDK/build.mjs Normal file

@ -0,0 +1,8 @@
import dts from "bun-plugin-dts";
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
minify: true,
plugins: [dts()],
});

BIN
JS-SDK/bun.lockb Normal file

Binary file not shown.

39
JS-SDK/package.json Normal file

@ -0,0 +1,39 @@
{
"name": "usetether",
"version": "1.0.0",
"author": "Braydon (Rainnny) <braydonrainnny@gmail.com>",
"description": "An API designed to provide real-time access to a user's Discord data.",
"keywords": [
"java",
"discord",
"api",
"restful",
"realtime"
],
"homepage": "https://github.com/Rainnny7/Tether",
"repository": {
"type": "git",
"url": "git+https://github.com/Rainnny7/Tether.git"
},
"license": "MIT",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "bun run build.mjs",
"prepublishOnly": "bun run build"
},
"files": [
"dist"
],
"devDependencies": {
"@types/bun": "latest",
"bun-plugin-dts": "^0.2.2"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"@types/react": "^18.3.5",
"react": "^18.3.1"
}
}

5
JS-SDK/src/index.ts Normal file

@ -0,0 +1,5 @@
export * from "@/lib/tether";
// Types
export * from "@/types/config";
export * from "@/types/user";

37
JS-SDK/src/lib/tether.ts Normal file

@ -0,0 +1,37 @@
import TetherConfig from "@/types/config";
import DiscordUser from "@/types/user";
import {useEffect, useState} from "react";
export const useTether = (snowflake: number, {endpoint = "usetether.rest", secure = true, realtime = false}: TetherConfig): DiscordUser | undefined => {
const [user] = useState<DiscordUser | undefined>();
useEffect(() => {
let socket: WebSocket; // The current WebSocket connection
/**
* Establish a connection with the API.
*/
const connect = () => {
socket = new WebSocket(`ws${secure && "s"}://${endpoint}/gateway`); // Connect to the gateway
socket.addEventListener("open", () => {
console.log("[Tether] WebSocket connection established!");
});
socket.addEventListener("close", connect);
socket.addEventListener("message", event => {
console.log("data:", event.data);
});
};
connect();
// Cleanup
return () => {
socket.removeEventListener("close", connect);
socket.close();
};
}, [endpoint, secure]);
return user;
}

@ -0,0 +1,17 @@
type TetherConfig = {
/**
* The API endpoint to connect to.
*/
endpoint?: string,
/**
* Whether the connection should be secure.
*/
secure?: boolean,
/**
* Whether the data should be fetched in real-time.
*/
realtime?: boolean,
};
export default TetherConfig;

@ -0,0 +1,7 @@
type SocketPacket = {
/**
* The OP code for this packet.
*/
op: number;
};
export default SocketPacket;

148
JS-SDK/src/types/user.ts Normal file

@ -0,0 +1,148 @@
type DiscordUser = {
/**
* The unique snowflake of this user.
*/
snowflake: number;
/**
* The username of this user.
*/
username: string;
/**
* The display name of this user, if any.
*/
displayName: string | undefined;
/**
* The flags of this user.
*/
flags: UserFlags;
/**
* The avatar of this user.
*/
avatar: Avatar;
/**
* The banner of this user, if any.
*/
banner: Banner | undefined;
/**
* The accent color of this user.
*/
accentColor: string;
/**
* The online status of this user, if known.
*/
onlineStatus: "ONLINE" | "IDLE" | "DO_NOT_DISTURB" | "OFFLINE" | "UNKNOWN" | undefined;
/**
* The clients this user is active on, if known.
*/
activeClients: "DESKTOP" | "MOBILE" | "WEB" | undefined;
/**
* The Spotify activity of this user, if known.
*/
spotify: SpotifyActivity | undefined;
/**
* Is this user a bot?
*/
bot: boolean;
/**
* The unix time of when this user joined Discord.
*/
createdAt: number;
};
/**
* A user's flags.
*/
type UserFlags = {
/**
* The list of flags the user has.
*/
list: ("STAFF" | "PARTNER" | "HYPESQUAD" | "BUG_HUNTER_LEVEL_1" | "HYPESQUAD_BRAVERY" | "HYPESQUAD_BRILLIANCE" | "HYPESQUAD_BALANCE" | "EARLY_SUPPORTER" | "TEAM_USER" | "BUGHUNTER_LEVEL_2" | "VERIFIED_BOT" | "VERIFIED_DEVELOPER" | "CERTIFIED_MODERATOR" | "BOT_HTTP_INTERACTIONS" | "ACTIVE_DEVELOPER" | "UNKNOWN")[];
/**
* The raw flags the user has.
*/
raw: number;
}
/**
* A user's avatar.
*/
type Avatar = {
/**
* The id of the user's avatar.
*/
id: string;
/**
* The URL of the user's avatar.
*/
url: string;
};
/**
* A user's banner.
*/
type Banner = {
/**
* The id of the user's avatar.
*/
id: string;
/**
* The URL of the user's avatar.
*/
url: string;
};
/**
* A user's Spotify activity data.
*/
type SpotifyActivity = {
/**
* The currently playing song.
*/
song: string;
/**
* The currently playing artist.
*/
artist: string;
/**
* The album the song is from.
*/
album: string;
/**
* The current progress of the track (in millis).
*/
trackProgress: number;
/**
* The total length of the track (in millis).
*/
trackLength: number;
/**
* The unix time of when this track started playing.
*/
started: number;
/**
* The unix time of when this track stops playing.
*/
ends: number;
};
export default DiscordUser;

21
JS-SDK/tsconfig.json Normal file

@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "es2020",
"module": "esnext",
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node",
"skipLibCheck": true,
"noUnusedLocals": true,
"noImplicitAny": true,
"allowJs": true,
"noEmit": true,
"outDir": "dist",
"resolveJsonModule": true,
"paths": {
"@/*": ["./src/*"],
"@/lib/*": ["./src/lib/*"],
"@/types/*": ["./src/types/*"]
}
}
}