From c12df9a8704d85c7c60b5d69e1eee9738d609ea3 Mon Sep 17 00:00:00 2001 From: Rainnny7 Date: Mon, 9 Sep 2024 19:05:48 -0400 Subject: [PATCH] Start on the JS SDK --- .../me/braydon/tether/model/DiscordUser.java | 17 +- JS-SDK/.gitignore | 4 + JS-SDK/.npmrc | 1 + JS-SDK/README.md | 1 + JS-SDK/build.mjs | 8 + JS-SDK/bun.lockb | Bin 0 -> 12684 bytes JS-SDK/package.json | 39 +++++ JS-SDK/src/index.ts | 5 + JS-SDK/src/lib/tether.ts | 37 +++++ JS-SDK/src/types/config.ts | 17 ++ JS-SDK/src/types/socket.ts | 7 + JS-SDK/src/types/user.ts | 148 ++++++++++++++++++ JS-SDK/tsconfig.json | 21 +++ 13 files changed, 295 insertions(+), 10 deletions(-) create mode 100644 JS-SDK/.gitignore create mode 100644 JS-SDK/.npmrc create mode 100644 JS-SDK/README.md create mode 100644 JS-SDK/build.mjs create mode 100644 JS-SDK/bun.lockb create mode 100644 JS-SDK/package.json create mode 100644 JS-SDK/src/index.ts create mode 100644 JS-SDK/src/lib/tether.ts create mode 100644 JS-SDK/src/types/config.ts create mode 100644 JS-SDK/src/types/socket.ts create mode 100644 JS-SDK/src/types/user.ts create mode 100644 JS-SDK/tsconfig.json diff --git a/API/src/main/java/me/braydon/tether/model/DiscordUser.java b/API/src/main/java/me/braydon/tether/model/DiscordUser.java index 87ec5a6..af848dc 100644 --- a/API/src/main/java/me/braydon/tether/model/DiscordUser.java +++ b/API/src/main/java/me/braydon/tether/model/DiscordUser.java @@ -4,7 +4,6 @@ import lombok.*; import net.dv8tion.jda.api.OnlineStatus; import net.dv8tion.jda.api.entities.*; -import java.text.SimpleDateFormat; import java.util.EnumSet; import java.util.List; import java.util.Objects; @@ -153,12 +152,12 @@ public final class DiscordUser { @AllArgsConstructor @Getter @EqualsAndHashCode public static class Banner { /** - * The id of the user's avatar. + * The id of the user's banner. */ @NonNull private final String id; /** - * The URL of the user's avatar. + * The URL of the user's banner. */ @NonNull private final String url; } @@ -184,14 +183,14 @@ public final class DiscordUser { @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. @@ -211,7 +210,6 @@ public final class DiscordUser { */ @NonNull @SuppressWarnings("DataFlowIssue") public static SpotifyActivity fromActivity(@NonNull RichPresence richPresence) { - SimpleDateFormat dateFormat = new SimpleDateFormat("m:ss"); long started = Objects.requireNonNull(richPresence.getTimestamps()).getStart(); long ends = richPresence.getTimestamps().getEnd(); @@ -220,8 +218,7 @@ public final class DiscordUser { return new SpotifyActivity( richPresence.getDetails(), richPresence.getState().replace(";", ","), - richPresence.getLargeImage().getText(), dateFormat.format(trackProgress), - dateFormat.format(trackLength), started, ends + richPresence.getLargeImage().getText(), trackProgress, trackLength, started, ends ); } } diff --git a/JS-SDK/.gitignore b/JS-SDK/.gitignore new file mode 100644 index 0000000..cf87e5b --- /dev/null +++ b/JS-SDK/.gitignore @@ -0,0 +1,4 @@ +node_modules +.idea/ +.vscode/ +dist \ No newline at end of file diff --git a/JS-SDK/.npmrc b/JS-SDK/.npmrc new file mode 100644 index 0000000..bd3327a --- /dev/null +++ b/JS-SDK/.npmrc @@ -0,0 +1 @@ +//registry.npmjs.org/:_authToken=${NPM_TOKEN} \ No newline at end of file diff --git a/JS-SDK/README.md b/JS-SDK/README.md new file mode 100644 index 0000000..42dfc15 --- /dev/null +++ b/JS-SDK/README.md @@ -0,0 +1 @@ +# JS-SDK \ No newline at end of file diff --git a/JS-SDK/build.mjs b/JS-SDK/build.mjs new file mode 100644 index 0000000..9f65438 --- /dev/null +++ b/JS-SDK/build.mjs @@ -0,0 +1,8 @@ +import dts from "bun-plugin-dts"; + +await Bun.build({ + entrypoints: ["./src/index.ts"], + outdir: "./dist", + minify: true, + plugins: [dts()], +}); diff --git a/JS-SDK/bun.lockb b/JS-SDK/bun.lockb new file mode 100644 index 0000000000000000000000000000000000000000..9631a5134825eefe09c310d663eeb5fda83bb72f GIT binary patch literal 12684 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 F`7bb)@dE$= literal 0 HcmV?d00001 diff --git a/JS-SDK/package.json b/JS-SDK/package.json new file mode 100644 index 0000000..29a8826 --- /dev/null +++ b/JS-SDK/package.json @@ -0,0 +1,39 @@ +{ + "name": "usetether", + "version": "1.0.0", + "author": "Braydon (Rainnny) ", + "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" + } +} \ No newline at end of file diff --git a/JS-SDK/src/index.ts b/JS-SDK/src/index.ts new file mode 100644 index 0000000..5b6562a --- /dev/null +++ b/JS-SDK/src/index.ts @@ -0,0 +1,5 @@ +export * from "@/lib/tether"; + +// Types +export * from "@/types/config"; +export * from "@/types/user"; \ No newline at end of file diff --git a/JS-SDK/src/lib/tether.ts b/JS-SDK/src/lib/tether.ts new file mode 100644 index 0000000..b56d0a6 --- /dev/null +++ b/JS-SDK/src/lib/tether.ts @@ -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(); + + 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; +} \ No newline at end of file diff --git a/JS-SDK/src/types/config.ts b/JS-SDK/src/types/config.ts new file mode 100644 index 0000000..1ce1493 --- /dev/null +++ b/JS-SDK/src/types/config.ts @@ -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; \ No newline at end of file diff --git a/JS-SDK/src/types/socket.ts b/JS-SDK/src/types/socket.ts new file mode 100644 index 0000000..29f4633 --- /dev/null +++ b/JS-SDK/src/types/socket.ts @@ -0,0 +1,7 @@ +type SocketPacket = { + /** + * The OP code for this packet. + */ + op: number; +}; +export default SocketPacket; \ No newline at end of file diff --git a/JS-SDK/src/types/user.ts b/JS-SDK/src/types/user.ts new file mode 100644 index 0000000..9dab9b2 --- /dev/null +++ b/JS-SDK/src/types/user.ts @@ -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; \ No newline at end of file diff --git a/JS-SDK/tsconfig.json b/JS-SDK/tsconfig.json new file mode 100644 index 0000000..5abdb79 --- /dev/null +++ b/JS-SDK/tsconfig.json @@ -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/*"] + } + } +}