UNPKG

dissonity

Version:

Extension of the Discord Embedded App SDK that allows you to create activities alongside the Dissonity v1 Unity package

307 lines (306 loc) 10.7 kB
// src/functions.ts import { DiscordSDK } from "@discord/embedded-app-sdk"; import fetch from "cross-fetch"; var PACKAGE_VERSION = "1.2.0"; var initialized = false; function stringifyBigInt(obj) { const str = JSON.stringify(obj, (key, value) => { if (typeof value == "bigint") { return value.toString(); } return value; }); return str; } function getChildIframe() { const iframe = document.getElementById("dissonity-child"); if (iframe == null) { throw new Error("No iframe with id 'dissonity-child' found"); } return iframe; } async function initializeSdk(options) { const discordSdk = new DiscordSDK(options.clientId); await discordSdk.ready(); const { code } = await discordSdk.commands.authorize({ client_id: options.clientId, response_type: "code", state: "", prompt: "none", scope: options.scope }); const response = await fetch(`/.proxy${options.tokenRoute}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ code }) }); const data = await response.json(); if (!data.access_token) { throw new Error("No access_token field found in response data"); } const { user } = await discordSdk.commands.authenticate({ access_token: data.access_token }); user.flags = user.public_flags; user.bot = false; return { discordSdk, user }; } async function receiveMessage(discordSdk, user, messageData) { const { nonce, event, command } = messageData; let args = messageData.args ?? {}; function handleSubscribeEvent(eventData) { getChildIframe().contentWindow?.postMessage( { event, command: "DISPATCH", data: eventData }, "*" ); } switch (command) { case "SUBSCRIBE": { if (event == null) { throw new Error("SUBSCRIBE event is undefined"); } if (args.channel_id) args = { channel_id: discordSdk.channelId }; try { discordSdk.subscribe(event, handleSubscribeEvent, args); } catch (_err) { console.error(`Dissonity NPM: Error attempting to subscribe to: ${event}. You may need some scope?`); } break; } case "UNSUBSCRIBE": { if (event == null) { throw new Error("UNSUBSCRIBE event is undefined"); } if (args.channel_id) args = { channel_id: discordSdk.channelId }; discordSdk.unsubscribe(event, handleSubscribeEvent); break; } case "SET_ACTIVITY": { if (!args.activity) { throw new Error("No activity provided for SET_ACTIVITY"); } if (args.activity.assets?.large_image == "") delete args.activity.assets; if (args.activity.party?.id == "") delete args.activity.party; if (args.activity.emoji?.id == "") delete args.activity.emoji; if (args.activity.secrets?.match == "") delete args.activity.secrets; try { const data = await discordSdk.commands.setActivity(args); getChildIframe().contentWindow?.postMessage({ nonce, event, command, data }, "*"); } catch (_err) { console.error("Dissonity NPM: Error attempting to set the activity. You may need the 'rpc.activities.write' scope."); } break; } case "GET_APPLICATION_ID": { const { clientId } = discordSdk; getChildIframe().contentWindow?.postMessage({ nonce, command, data: clientId, args }, "*"); break; } case "GET_INSTANCE_ID": { const { instanceId } = discordSdk; getChildIframe().contentWindow?.postMessage({ nonce, command, data: instanceId, args }, "*"); break; } case "GET_CHANNEL_ID": { const { channelId } = discordSdk; getChildIframe().contentWindow?.postMessage({ nonce, command, data: channelId, args }, "*"); break; } case "GET_GUILD_ID": { const { guildId } = discordSdk; getChildIframe().contentWindow?.postMessage({ nonce, command, data: guildId, args }, "*"); break; } case "GET_USER_ID": { if (user == null) throw new Error("You need to be authenticated to get the current user id"); getChildIframe().contentWindow?.postMessage({ nonce, command, data: user.id, args }, "*"); break; } case "GET_USER": { if (user == null) throw new Error("You need to be authenticated to get the current user"); getChildIframe().contentWindow?.postMessage({ nonce, command, data: user, args }, "*"); break; } case "GET_INSTANCE_PARTICIPANTS": { const data = await discordSdk.commands.getInstanceConnectedParticipants(); getChildIframe().contentWindow?.postMessage({ nonce, command, data, args }, "*"); break; } case "HARDWARE_ACCELERATION": { const data = await discordSdk.commands.encourageHardwareAcceleration(); getChildIframe().contentWindow?.postMessage({ nonce, command, data, args }, "*"); break; } case "GET_CHANNEL": { if (!args.channel_id) { throw new Error("No channel id provided for GET_CHANNEL"); } try { const data = await discordSdk.commands.getChannel(args); getChildIframe().contentWindow?.postMessage({ nonce, command, data, args }, "*"); } catch (_err) { console.error("Dissonity NPM: Error attempting to get the channel. You may need the 'guilds' scope."); } break; } case "GET_CHANNEL_PERMISSIONS": { if (!args.channel_id) { throw new Error("No channel id provided for GET_CHANNEL_PERMISSIONS"); } try { const data = await discordSdk.commands.getChannelPermissions(args); getChildIframe().contentWindow?.postMessage({ nonce, command, data: stringifyBigInt(data), args }, "*"); } catch (_err) { console.error("Dissonity NPM: Error attempting to get the channel permissions. You may need the 'guilds.members.read' scope."); } break; } case "GET_ENTITLEMENTS": { throw new Error("Entitlements are not supported in Dissonity v1"); const data = await discordSdk.commands.getEntitlements(); getChildIframe().contentWindow?.postMessage({ nonce, command, data, args }, "*"); break; } case "GET_PLATFORM_BEHAVIORS": { const data = await discordSdk.commands.getPlatformBehaviors(); getChildIframe().contentWindow?.postMessage({ nonce, command, data, args }, "*"); break; } case "GET_SKUS": { throw new Error("Skus are not supported in Dissonity v1"); const data = await discordSdk.commands.getSkus(); getChildIframe().contentWindow?.postMessage({ nonce, command, data, args }, "*"); break; } case "IMAGE_UPLOAD": { try { const data = await discordSdk.commands.initiateImageUpload(); getChildIframe().contentWindow?.postMessage({ nonce, command, data: { image_url: data.image_url, canceled: false }, args }, "*"); } catch (_err) { getChildIframe().contentWindow?.postMessage({ nonce, command, data: { image_url: "", canceled: true }, args }, "*"); } break; } case "EXTERNAL_LINK": { if (!args.url) { throw new Error("No url provided for EXTERNAL_LINK"); } discordSdk.commands.openExternalLink(args); break; } case "INVITE_DIALOG": { discordSdk.commands.openInviteDialog(); break; } case "SHARE_MOMENT_DIALOG": { if (!args.mediaUrl) { throw new Error("No media url provided for SHARE_MOMENT_DIALOG"); } discordSdk.commands.openShareMomentDialog(args); break; } case "SET_ORIENTATION_LOCK_STATE": { if (!args.lock_state) { throw new Error("No lock state provided for SET_ORIENTATION_LOCK_STATE"); } try { discordSdk.commands.setOrientationLockState(args); } catch (_err) { console.error("Dissonity NPM: Error attempting to set the orientation lock state. You may need the 'guilds.members.read' scope."); } break; } case "START_PURCHASE": { throw new Error("Purchases are not supported in Dissonity v1"); discordSdk.commands.startPurchase(args); break; } case "GET_LOCALE": { try { const data = await discordSdk.commands.userSettingsGetLocale(); getChildIframe().contentWindow?.postMessage({ nonce, command, data, args }, "*"); } catch (_err) { console.error("Dissonity NPM: Error attempting to get the user locale. You may need the 'identify' scope."); } break; } case "SET_CONFIG": { if (!args.use_interactive_pip) { throw new Error("No 'use interactive pip' provided for SET_CONFIG"); } const data = await discordSdk.commands.setConfig(args); getChildIframe().contentWindow?.postMessage({ nonce, command, data, args }, "*"); break; } case "PING_LOAD": { getChildIframe().contentWindow?.postMessage({ command: "LOADED", data: PACKAGE_VERSION }, "*"); break; } } } async function setupSdk(options) { if (initialized) throw new Error("Already initialized"); initialized = true; const dataPromise = initializeSdk(options); let discordSdk = null; let user = null; async function handleMessage({ data: messageData }) { if (typeof messageData !== "object" || Array.isArray(messageData) || messageData === null) { return; } if (!discordSdk || !user) { await dataPromise; } receiveMessage(discordSdk, user, messageData); } window.addEventListener("message", handleMessage); const resolvedData = await dataPromise; discordSdk = resolvedData.discordSdk; user = resolvedData.user; getChildIframe().contentWindow?.postMessage({ command: "LOADED", data: PACKAGE_VERSION }, "*"); } async function useSdk(dataPromise) { if (initialized) throw new Error("Already initialized"); initialized = true; let discordSdk = null; let user = null; async function handleMessage({ data: messageData }) { if (typeof messageData !== "object" || Array.isArray(messageData) || messageData === null) { return; } if (!discordSdk || !user) { await dataPromise; } receiveMessage(discordSdk, user, messageData); } window.addEventListener("message", handleMessage); const resolvedData = await dataPromise; discordSdk = resolvedData.discordSdk; if (resolvedData.user != null) { user = { ...resolvedData.user }; user.flags = user.public_flags; user.bot = false; } getChildIframe().contentWindow?.postMessage({ command: "LOADED", data: PACKAGE_VERSION }, "*"); } export { DiscordSDK, setupSdk, useSdk };