Skip to content

Commit

Permalink
feat: add support for user-installable apps (#782)
Browse files Browse the repository at this point in the history
* refactor: update discord.js

Signed-off-by: Seren_Modz 21 <[email protected]>

* fix: correct the ordering of the use external apps permission

Signed-off-by: Seren_Modz 21 <[email protected]>

* feat: add in compute difference for new fields

* chore: failed my own code writing

---------

Signed-off-by: Seren_Modz 21 <[email protected]>
Co-authored-by: Vlad Frangu <[email protected]>
  • Loading branch information
SerenModz21 and vladfrangu authored Sep 8, 2024
1 parent 40967b3 commit e783074
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 52 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"prepack:esm": "rollup-type-bundler -d dist/esm -t .mts"
},
"dependencies": {
"@discordjs/builders": "^1.8.2",
"@sapphire/discord-utilities": "^3.4.0",
"@discordjs/builders": "^1.9.0",
"@sapphire/discord-utilities": "^3.4.1",
"@sapphire/discord.js-utilities": "^7.3.0",
"@sapphire/lexure": "^1.1.7",
"@sapphire/pieces": "^4.3.1",
Expand All @@ -60,7 +60,7 @@
"@vitest/coverage-v8": "^2.0.5",
"concurrently": "^8.2.2",
"cz-conventional-changelog": "^3.3.0",
"discord.js": "^14.15.3",
"discord.js": "^14.16.1",
"esbuild-plugin-file-path-extensions": "^2.1.2",
"esbuild-plugin-version-injector": "^1.2.1",
"eslint": "^8.57.0",
Expand Down
54 changes: 54 additions & 0 deletions src/lib/utils/application-commands/compute-differences/contexts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { InteractionContextType } from 'discord.js';
import type { CommandDifference } from './_shared';

export function* checkInteractionContextTypes(
existingContexts?: InteractionContextType[],
newContexts?: InteractionContextType[]
): Generator<CommandDifference> {
// 0. No existing contexts and now we have contexts
if (!existingContexts && newContexts?.length) {
yield {
key: 'contexts',
original: 'no contexts present',
expected: 'contexts present'
};
}
// 1. Existing contexts and now we have no contexts
else if (existingContexts?.length && !newContexts?.length) {
yield {
key: 'contexts',
original: 'contexts present',
expected: 'no contexts present'
};
}
// 2. Maybe changes in order or additions, log
else if (newContexts?.length) {
let index = 0;

for (const newContext of newContexts) {
const currentIndex = index++;

if (existingContexts![currentIndex] !== newContext) {
yield {
key: `contexts[${currentIndex}]`,
original: `contexts type ${existingContexts?.[currentIndex]}`,
expected: `contexts type ${newContext}`
};
}
}

if (index < existingContexts!.length) {
let type: InteractionContextType;

while ((type = existingContexts![index]) !== undefined) {
yield {
key: `contexts[${index}]`,
original: `context ${type} present`,
expected: `no context present`
};

index++;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { ApplicationIntegrationType } from 'discord.js';
import type { CommandDifference } from './_shared';

export function* checkIntegrationTypes(
existingIntegrationTypes?: ApplicationIntegrationType[],
newIntegrationTypes?: ApplicationIntegrationType[]
): Generator<CommandDifference> {
// 0. No existing integration types and now we have integration types
if (!existingIntegrationTypes?.length && newIntegrationTypes?.length) {
yield {
key: 'integrationTypes',
original: 'no integration types present',
expected: 'integration types present'
};
}
// 1. Existing integration types and now we have no integration types
else if (existingIntegrationTypes?.length && !newIntegrationTypes?.length) {
yield {
key: 'integrationTypes',
original: 'integration types present',
expected: 'no integration types present'
};
}
// 2. Maybe changes in order or additions, log
else if (newIntegrationTypes?.length) {
let index = 0;

for (const newIntegrationType of newIntegrationTypes) {
const currentIndex = index++;

if (existingIntegrationTypes![currentIndex] !== newIntegrationType) {
yield {
key: `integrationTypes[${currentIndex}]`,
original: `integration type ${existingIntegrationTypes?.[currentIndex]}`,
expected: `integration type ${newIntegrationType}`
};
}
}

if (index < existingIntegrationTypes!.length) {
let type: ApplicationIntegrationType;

while ((type = existingIntegrationTypes![index]) !== undefined) {
yield {
key: `integrationTypes[${index}]`,
original: `integration type ${type} present`,
expected: 'no integration type present'
};

index++;
}
}
}
}
14 changes: 14 additions & 0 deletions src/lib/utils/application-commands/computeDifferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { checkDMPermission } from './compute-differences/dm_permission';
import { checkLocalizations } from './compute-differences/localizations';
import { checkName } from './compute-differences/name';
import { checkOptions } from './compute-differences/options';
import { checkIntegrationTypes } from './compute-differences/integration_types';
import { checkInteractionContextTypes } from './compute-differences/contexts';

/**
* @returns `true` if there are differences, `false` otherwise
Expand Down Expand Up @@ -61,6 +63,12 @@ export function* getCommandDifferences(
originalLocalizedDescriptions: originalLocalizedNames,
expectedLocalizedDescriptions: expectedLocalizedNames
});

// Check integration types
yield* checkIntegrationTypes(existingCommand.integration_types, casted.integration_types);

// Check contexts
yield* checkInteractionContextTypes(existingCommand.contexts, casted.contexts);
}

return;
Expand Down Expand Up @@ -106,5 +114,11 @@ export function* getCommandDifferences(
expectedLocalizedDescriptions
});

// Check integration types
yield* checkIntegrationTypes(existingCommand.integration_types, casted.integration_types);

// Check contexts
yield* checkInteractionContextTypes(existingCommand.contexts, casted.contexts);

yield* checkOptions(existingCommand.options, casted.options);
}
14 changes: 11 additions & 3 deletions src/lib/utils/application-commands/normalizeInputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import {
import {
ApplicationCommand,
PermissionsBitField,
type ApplicationIntegrationType,
type ChatInputApplicationCommandData,
type InteractionContextType,
type MessageApplicationCommandData,
type UserApplicationCommandData
} from 'discord.js';
Expand Down Expand Up @@ -71,7 +73,9 @@ export function normalizeChatInputCommand(
description_localizations: command.descriptionLocalizations,
type: ApplicationCommandType.ChatInput,
dm_permission: command.dmPermission,
nsfw: command.nsfw
nsfw: command.nsfw,
integration_types: command.integrationTypes as ApplicationIntegrationType[] | undefined,
contexts: command.contexts as InteractionContextType[] | undefined
};

if (typeof command.defaultMemberPermissions !== 'undefined') {
Expand Down Expand Up @@ -108,7 +112,9 @@ export function normalizeContextMenuCommand(
name_localizations: command.nameLocalizations,
type: command.type,
dm_permission: command.dmPermission,
nsfw: command.nsfw
nsfw: command.nsfw,
integration_types: command.integrationTypes as ApplicationIntegrationType[] | undefined,
contexts: command.contexts as InteractionContextType[] | undefined
};

if (typeof command.defaultMemberPermissions !== 'undefined') {
Expand All @@ -125,7 +131,9 @@ export function convertApplicationCommandToApiData(command: ApplicationCommand):
name_localizations: command.nameLocalizations,
dm_permission: command.dmPermission,

Check warning on line 132 in src/lib/utils/application-commands/normalizeInputs.ts

View workflow job for this annotation

GitHub Actions / Linting / Linting / Run yarn job

'dmPermission' is deprecated. Use {@link ApplicationCommand.contexts } instead
nsfw: command.nsfw,
default_member_permissions: command.defaultMemberPermissions?.bitfield.toString() ?? null
default_member_permissions: command.defaultMemberPermissions?.bitfield.toString() ?? null,
integration_types: command.integrationTypes,
contexts: command.contexts
} as RESTPostAPIApplicationCommandsJSONBody;

if (command.type === ApplicationCommandType.ChatInput) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isStageChannel } from '@sapphire/discord.js-utilities';
import type { Message } from 'discord.js';
import { ChannelType, type Message } from 'discord.js';
import { Listener } from '../../lib/structures/Listener';
import type { MessageCommand } from '../../lib/types/CommandTypes';
import { Events, type MessageCommandRunPayload } from '../../lib/types/Events';
Expand All @@ -15,6 +15,10 @@ export class CoreListener extends Listener<typeof Events.MessageCommandRun> {
return;
}

if (message.channel.type === ChannelType.GroupDM) {
return;
}

try {
await message.channel.sendTyping();
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isDMChannel } from '@sapphire/discord.js-utilities';
import { PermissionFlagsBits, PermissionsBitField, type Message } from 'discord.js';
import { ChannelType, PermissionFlagsBits, PermissionsBitField, type Message } from 'discord.js';
import { Listener } from '../../lib/structures/Listener';
import { Events } from '../../lib/types/Events';

Expand Down Expand Up @@ -40,6 +40,7 @@ export class CoreListener extends Listener<typeof Events.PreMessageParsed> {
}

private async canRunInChannel(message: Message): Promise<boolean> {
if (message.channel.type === ChannelType.GroupDM) return false;
if (isDMChannel(message.channel)) return true;

const me = await message.guild?.members.fetchMe();
Expand Down
1 change: 1 addition & 0 deletions src/preconditions/ClientPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export class CorePrecondition extends AllFlowsPrecondition {
Stream: 'Stream',
UseApplicationCommands: 'Use Application Commands',
UseEmbeddedActivities: 'Start Activities',
UseExternalApps: 'Use External Apps',
UseExternalEmojis: 'Use External Emojis',
UseExternalSounds: 'Use External Sounds',
UseExternalStickers: 'Use External Stickers',
Expand Down
Loading

0 comments on commit e783074

Please sign in to comment.