aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.cjs821
-rw-r--r--.eslintrc.json84
-rw-r--r--package.json19
-rw-r--r--src/arguments/globalUser.ts4
-rw-r--r--src/arguments/roleWithDuration.ts8
-rw-r--r--src/commands/admin/channelPermissions.ts7
-rw-r--r--src/commands/config/blacklist.ts7
-rw-r--r--src/commands/config/config.ts16
-rw-r--r--src/commands/config/disable.ts6
-rw-r--r--src/commands/config/features.ts9
-rw-r--r--src/commands/config/log.ts4
-rw-r--r--src/commands/info/icon.ts7
-rw-r--r--src/commands/info/links.ts2
-rw-r--r--src/commands/leveling/leaderboard.ts6
-rw-r--r--src/commands/leveling/level.ts5
-rw-r--r--src/commands/leveling/setLevel.ts8
-rw-r--r--src/commands/leveling/setXp.ts5
-rw-r--r--src/commands/moderation/ban.ts44
-rw-r--r--src/commands/moderation/block.ts30
-rw-r--r--src/commands/moderation/evidence.ts5
-rw-r--r--src/commands/moderation/hideCase.ts5
-rw-r--r--src/commands/moderation/kick.ts7
-rw-r--r--src/commands/moderation/massBan.ts5
-rw-r--r--src/commands/moderation/modlog.ts9
-rw-r--r--src/commands/moderation/mute.ts25
-rw-r--r--src/commands/moderation/purge.ts9
-rw-r--r--src/commands/moderation/removeReactionEmoji.ts18
-rw-r--r--src/commands/moderation/role.ts22
-rw-r--r--src/commands/moderation/slowmode.ts40
-rw-r--r--src/commands/moderation/timeout.ts22
-rw-r--r--src/commands/moderation/unban.ts7
-rw-r--r--src/commands/moderation/unblock.ts15
-rw-r--r--src/commands/moderation/unmute.ts8
-rw-r--r--src/commands/moderation/untimeout.ts3
-rw-r--r--src/commands/moderation/warn.ts8
-rw-r--r--src/commands/moulberry-bush/capePermissions.ts24
-rw-r--r--src/commands/moulberry-bush/capes.ts51
-rw-r--r--src/commands/moulberry-bush/report.ts5
-rw-r--r--src/commands/utilities/activity.ts3
-rw-r--r--src/commands/utilities/remind.ts32
-rw-r--r--src/commands/utilities/viewRaw.ts28
-rw-r--r--src/lib/common/AutoMod.ts1
-rw-r--r--src/lib/extensions/discord-akairo/BushClient.ts11
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts76
-rw-r--r--src/lib/extensions/discord.js/BushCategoryChannel.ts11
-rw-r--r--src/lib/extensions/discord.js/BushCategoryChannelChildManager.ts52
-rw-r--r--src/lib/extensions/discord.js/other.ts2
-rw-r--r--src/lib/index.ts1
-rw-r--r--src/lib/utils/CanvasProgressBar.ts2
-rw-r--r--src/listeners/ws/INTERACTION_CREATE.ts2
-rw-r--r--tsconfig.json2
-rw-r--r--yarn.lock223
52 files changed, 1302 insertions, 524 deletions
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 0000000..a5a2375
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,821 @@
+module.exports = {
+ env: {
+ es2021: true,
+ node: true
+ },
+ extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaVersion: 12,
+ sourceType: 'module',
+ project: './tsconfig.json'
+ },
+ plugins: ['@typescript-eslint', 'deprecation', 'import'],
+ ignorePatterns: ['dist'],
+ rules: {
+ 'no-return-await': 'off',
+ '@typescript-eslint/no-empty-interface': 'warn',
+ 'no-mixed-spaces-and-tabs': 'off',
+ 'no-duplicate-imports': 'warn',
+ 'no-empty-function': 'off',
+ '@typescript-eslint/no-empty-function': 'off',
+ 'no-empty': 'off',
+ '@typescript-eslint/ban-ts-comment': [
+ 'error',
+ {
+ 'ts-expect-error': 'allow-with-description',
+ 'ts-ignore': 'allow-with-description',
+ 'ts-nocheck': 'allow-with-description',
+ 'ts-check': 'allow-with-description',
+ 'minimumDescriptionLength': 5
+ }
+ ],
+ '@typescript-eslint/no-floating-promises': 'warn',
+ 'prefer-promise-reject-errors': 'warn',
+ '@typescript-eslint/no-misused-promises': 'error',
+ '@typescript-eslint/no-base-to-string': 'error',
+ 'no-loss-of-precision': 'off',
+ '@typescript-eslint/no-loss-of-precision': 'error',
+ 'no-throw-literal': 'off',
+ '@typescript-eslint/no-throw-literal': 'warn',
+ '@typescript-eslint/prefer-nullish-coalescing': 'warn',
+ '@typescript-eslint/no-explicit-any': 'off',
+ '@typescript-eslint/no-non-null-assertion': 'off',
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
+ 'prefer-template': 'warn',
+ '@typescript-eslint/no-this-alias': [
+ 'error',
+ {
+ allowDestructuring: true,
+ allowedNames: ['that']
+ }
+ ],
+ '@typescript-eslint/no-unused-vars': [
+ 'warn',
+ {
+ argsIgnorePattern: '^_'
+ }
+ ],
+ 'no-implied-eval': 'off',
+ '@typescript-eslint/no-implied-eval': ['error'],
+ 'deprecation/deprecation': 'warn',
+ '@typescript-eslint/explicit-member-accessibility': ['warn', { accessibility: 'explicit' }],
+ '@typescript-eslint/switch-exhaustiveness-check': 'warn',
+ 'import/no-commonjs': 'error',
+ 'import/extensions': ['error', 'ignorePackages'],
+ '@typescript-eslint/no-restricted-imports': [
+ 'error',
+ {
+ paths: [
+ {
+ name: 'discord-api-types',
+ message: 'Please use discord-api-types/v9 instead.',
+ allowTypeImports: true
+ },
+ {
+ name: 'discord-api-types-next',
+ message: 'Please use discord-api-types-next/v9 instead.',
+ allowTypeImports: true
+ },
+ {
+ name: 'console',
+ importNames: ['assert'],
+ message: 'Import from the assert module instead.'
+ }
+ ]
+ }
+ ],
+ 'no-restricted-globals': [
+ 'error',
+ ...[
+ 'NodeFilter',
+ 'AbortController',
+ 'AbortSignal',
+ 'AbstractRange',
+ 'AnalyserNode',
+ 'Animation',
+ 'AnimationEffect',
+ 'AnimationEvent',
+ 'AnimationPlaybackEvent',
+ 'AnimationTimeline',
+ 'Attr',
+ 'AudioBuffer',
+ 'AudioBufferSourceNode',
+ 'AudioContext',
+ 'AudioDestinationNode',
+ 'AudioListener',
+ 'AudioNode',
+ 'AudioParam',
+ 'AudioParamMap',
+ 'AudioProcessingEvent',
+ 'AudioScheduledSourceNode',
+ 'AudioWorklet',
+ 'AudioWorkletNode',
+ 'AuthenticatorAssertionResponse',
+ 'AuthenticatorAttestationResponse',
+ 'AuthenticatorResponse',
+ 'BarProp',
+ 'BaseAudioContext',
+ 'BeforeUnloadEvent',
+ 'BiquadFilterNode',
+ 'Blob',
+ 'BlobEvent',
+ 'BroadcastChannel',
+ 'ByteLengthQueuingStrategy',
+ 'CDATASection',
+ 'CSSAnimation',
+ 'CSSConditionRule',
+ 'CSSCounterStyleRule',
+ 'CSSFontFaceRule',
+ 'CSSGroupingRule',
+ 'CSSImportRule',
+ 'CSSKeyframeRule',
+ 'CSSKeyframesRule',
+ 'CSSMediaRule',
+ 'CSSNamespaceRule',
+ 'CSSPageRule',
+ 'CSSRule',
+ 'CSSStyleDeclaration',
+ 'CSSStyleRule',
+ 'CSSStyleSheet',
+ 'CSSSupportsRule',
+ 'CSSTransition',
+ 'Cache',
+ 'CacheStorage',
+ 'CanvasGradient',
+ 'CanvasPattern',
+ 'CanvasRenderingContext2D',
+ 'ChannelMergerNode',
+ 'ChannelSplitterNode',
+ 'CharacterData',
+ 'Clipboard',
+ 'ClipboardEvent',
+ 'ClipboardItem',
+ 'CloseEvent',
+ 'Comment',
+ 'CompositionEvent',
+ 'ConstantSourceNode',
+ 'ConvolverNode',
+ 'CountQueuingStrategy',
+ 'Credential',
+ 'CredentialsContainer',
+ 'Crypto',
+ 'CryptoKey',
+ 'CustomEvent',
+ 'DOMException',
+ 'DOMImplementation',
+ 'DOMMatrix',
+ 'SVGMatrix',
+ 'WebKitCSSMatrix',
+ 'DOMMatrixReadOnly',
+ 'DOMParser',
+ 'DOMPoint',
+ 'SVGPoint',
+ 'DOMPointReadOnly',
+ 'DOMQuad',
+ 'DOMRect',
+ 'SVGRect',
+ 'DOMRectList',
+ 'DOMRectReadOnly',
+ 'DOMStringList',
+ 'DOMStringMap',
+ 'DOMTokenList',
+ 'DataTransfer',
+ 'DataTransferItem',
+ 'DataTransferItemList',
+ 'DelayNode',
+ 'DeviceMotionEvent',
+ 'DeviceOrientationEvent',
+ 'Document',
+ 'DocumentFragment',
+ 'DocumentTimeline',
+ 'DocumentType',
+ 'DragEvent',
+ 'DynamicsCompressorNode',
+ 'Element',
+ 'ElementInternals',
+ 'ErrorEvent',
+ 'Event',
+ 'EventSource',
+ 'EventTarget',
+ 'External',
+ 'File',
+ 'FileList',
+ 'FileReader',
+ 'FileSystem',
+ 'FileSystemDirectoryEntry',
+ 'FileSystemDirectoryReader',
+ 'FileSystemEntry',
+ 'FileSystemFileEntry',
+ 'FocusEvent',
+ 'FontFace',
+ 'FontFaceSet',
+ 'FontFaceSetLoadEvent',
+ 'FormData',
+ 'FormDataEvent',
+ 'GainNode',
+ 'Gamepad',
+ 'GamepadButton',
+ 'GamepadEvent',
+ 'GamepadHapticActuator',
+ 'Geolocation',
+ 'GeolocationCoordinates',
+ 'GeolocationPosition',
+ 'GeolocationPositionError',
+ 'HTMLAllCollection',
+ 'HTMLAnchorElement',
+ 'HTMLAreaElement',
+ 'HTMLAudioElement',
+ 'HTMLBRElement',
+ 'HTMLBaseElement',
+ 'HTMLBodyElement',
+ 'HTMLButtonElement',
+ 'HTMLCanvasElement',
+ 'HTMLCollection',
+ 'HTMLDListElement',
+ 'HTMLDataElement',
+ 'HTMLDataListElement',
+ 'HTMLDetailsElement',
+ 'HTMLDirectoryElement',
+ 'HTMLDivElement',
+ 'HTMLDocument',
+ 'HTMLElement',
+ 'HTMLEmbedElement',
+ 'HTMLFieldSetElement',
+ 'HTMLFontElement',
+ 'HTMLFormControlsCollection',
+ 'HTMLFormElement',
+ 'HTMLFrameElement',
+ 'HTMLFrameSetElement',
+ 'HTMLHRElement',
+ 'HTMLHeadElement',
+ 'HTMLHeadingElement',
+ 'HTMLHtmlElement',
+ 'HTMLIFrameElement',
+ 'HTMLImageElement',
+ 'HTMLInputElement',
+ 'HTMLLIElement',
+ 'HTMLLabelElement',
+ 'HTMLLegendElement',
+ 'HTMLLinkElement',
+ 'HTMLMapElement',
+ 'HTMLMarqueeElement',
+ 'HTMLMediaElement',
+ 'HTMLMenuElement',
+ 'HTMLMetaElement',
+ 'HTMLMeterElement',
+ 'HTMLModElement',
+ 'HTMLOListElement',
+ 'HTMLObjectElement',
+ 'HTMLOptGroupElement',
+ 'HTMLOptionElement',
+ 'HTMLOptionsCollection',
+ 'HTMLOutputElement',
+ 'HTMLParagraphElement',
+ 'HTMLParamElement',
+ 'HTMLPictureElement',
+ 'HTMLPreElement',
+ 'HTMLProgressElement',
+ 'HTMLQuoteElement',
+ 'HTMLScriptElement',
+ 'HTMLSelectElement',
+ 'HTMLSlotElement',
+ 'HTMLSourceElement',
+ 'HTMLSpanElement',
+ 'HTMLStyleElement',
+ 'HTMLTableCaptionElement',
+ 'HTMLTableCellElement',
+ 'HTMLTableColElement',
+ 'HTMLTableElement',
+ 'HTMLTableRowElement',
+ 'HTMLTableSectionElement',
+ 'HTMLTemplateElement',
+ 'HTMLTextAreaElement',
+ 'HTMLTimeElement',
+ 'HTMLTitleElement',
+ 'HTMLTrackElement',
+ 'HTMLUListElement',
+ 'HTMLUnknownElement',
+ 'HTMLVideoElement',
+ 'HashChangeEvent',
+ 'Headers',
+ 'History',
+ 'IDBCursor',
+ 'IDBCursorWithValue',
+ 'IDBDatabase',
+ 'IDBFactory',
+ 'IDBIndex',
+ 'IDBKeyRange',
+ 'IDBObjectStore',
+ 'IDBOpenDBRequest',
+ 'IDBRequest',
+ 'IDBTransaction',
+ 'IDBVersionChangeEvent',
+ 'IIRFilterNode',
+ 'IdleDeadline',
+ 'ImageBitmap',
+ 'ImageBitmapRenderingContext',
+ 'ImageData',
+ 'InputEvent',
+ 'IntersectionObserver',
+ 'IntersectionObserverEntry',
+ 'KeyboardEvent',
+ 'KeyframeEffect',
+ 'Location',
+ 'MathMLElement',
+ 'MediaCapabilities',
+ 'MediaDeviceInfo',
+ 'MediaDevices',
+ 'MediaElementAudioSourceNode',
+ 'MediaEncryptedEvent',
+ 'MediaError',
+ 'MediaKeyMessageEvent',
+ 'MediaKeySession',
+ 'MediaKeyStatusMap',
+ 'MediaKeySystemAccess',
+ 'MediaKeys',
+ 'MediaList',
+ 'MediaMetadata',
+ 'MediaQueryList',
+ 'MediaQueryListEvent',
+ 'MediaRecorder',
+ 'MediaRecorderErrorEvent',
+ 'MediaSession',
+ 'MediaSource',
+ 'MediaStream',
+ 'MediaStreamAudioDestinationNode',
+ 'MediaStreamAudioSourceNode',
+ 'MediaStreamTrack',
+ 'MediaStreamTrackEvent',
+ 'MessageChannel',
+ 'MessageEvent',
+ 'MessagePort',
+ 'MimeType',
+ 'MimeTypeArray',
+ 'MouseEvent',
+ 'MutationEvent',
+ 'MutationObserver',
+ 'MutationRecord',
+ 'NamedNodeMap',
+ 'Navigator',
+ 'NetworkInformation',
+ 'Node',
+ 'NodeIterator',
+ 'NodeList',
+ 'Notification',
+ 'OfflineAudioCompletionEvent',
+ 'OfflineAudioContext',
+ 'OscillatorNode',
+ 'OverconstrainedError',
+ 'PageTransitionEvent',
+ 'PannerNode',
+ 'Path2D',
+ 'PaymentMethodChangeEvent',
+ 'PaymentRequest',
+ 'PaymentRequestUpdateEvent',
+ 'PaymentResponse',
+ 'Performance',
+ 'PerformanceEntry',
+ 'PerformanceEventTiming',
+ 'PerformanceMark',
+ 'PerformanceMeasure',
+ 'PerformanceNavigation',
+ 'PerformanceNavigationTiming',
+ 'PerformanceObserver',
+ 'PerformanceObserverEntryList',
+ 'PerformancePaintTiming',
+ 'PerformanceResourceTiming',
+ 'PerformanceServerTiming',
+ 'PerformanceTiming',
+ 'PeriodicWave',
+ 'PermissionStatus',
+ 'Permissions',
+ 'PictureInPictureWindow',
+ 'Plugin',
+ 'PluginArray',
+ 'PointerEvent',
+ 'PopStateEvent',
+ 'ProcessingInstruction',
+ 'ProgressEvent',
+ 'PromiseRejectionEvent',
+ 'PublicKeyCredential',
+ 'PushManager',
+ 'PushSubscription',
+ 'PushSubscriptionOptions',
+ 'RTCCertificate',
+ 'RTCDTMFSender',
+ 'RTCDTMFToneChangeEvent',
+ 'RTCDataChannel',
+ 'RTCDataChannelEvent',
+ 'RTCDtlsTransport',
+ 'RTCIceCandidate',
+ 'RTCIceTransport',
+ 'RTCPeerConnection',
+ 'RTCPeerConnectionIceErrorEvent',
+ 'RTCPeerConnectionIceEvent',
+ 'RTCRtpReceiver',
+ 'RTCRtpSender',
+ 'RTCRtpTransceiver',
+ 'RTCSessionDescription',
+ 'RTCStatsReport',
+ 'RTCTrackEvent',
+ 'RadioNodeList',
+ 'Range',
+ 'ReadableStream',
+ 'ReadableStreamDefaultController',
+ 'ReadableStreamDefaultReader',
+ 'RemotePlayback',
+ 'Request',
+ 'ResizeObserver',
+ 'ResizeObserverEntry',
+ 'ResizeObserverSize',
+ 'Response',
+ 'SVGAElement',
+ 'SVGAngle',
+ 'SVGAnimateElement',
+ 'SVGAnimateMotionElement',
+ 'SVGAnimateTransformElement',
+ 'SVGAnimatedAngle',
+ 'SVGAnimatedBoolean',
+ 'SVGAnimatedEnumeration',
+ 'SVGAnimatedInteger',
+ 'SVGAnimatedLength',
+ 'SVGAnimatedLengthList',
+ 'SVGAnimatedNumber',
+ 'SVGAnimatedNumberList',
+ 'SVGAnimatedPreserveAspectRatio',
+ 'SVGAnimatedRect',
+ 'SVGAnimatedString',
+ 'SVGAnimatedTransformList',
+ 'SVGAnimationElement',
+ 'SVGCircleElement',
+ 'SVGClipPathElement',
+ 'SVGComponentTransferFunctionElement',
+ 'SVGDefsElement',
+ 'SVGDescElement',
+ 'SVGElement',
+ 'SVGEllipseElement',
+ 'SVGFEBlendElement',
+ 'SVGFEColorMatrixElement',
+ 'SVGFEComponentTransferElement',
+ 'SVGFECompositeElement',
+ 'SVGFEConvolveMatrixElement',
+ 'SVGFEDiffuseLightingElement',
+ 'SVGFEDisplacementMapElement',
+ 'SVGFEDistantLightElement',
+ 'SVGFEDropShadowElement',
+ 'SVGFEFloodElement',
+ 'SVGFEFuncAElement',
+ 'SVGFEFuncBElement',
+ 'SVGFEFuncGElement',
+ 'SVGFEFuncRElement',
+ 'SVGFEGaussianBlurElement',
+ 'SVGFEImageElement',
+ 'SVGFEMergeElement',
+ 'SVGFEMergeNodeElement',
+ 'SVGFEMorphologyElement',
+ 'SVGFEOffsetElement',
+ 'SVGFEPointLightElement',
+ 'SVGFESpecularLightingElement',
+ 'SVGFESpotLightElement',
+ 'SVGFETileElement',
+ 'SVGFETurbulenceElement',
+ 'SVGFilterElement',
+ 'SVGForeignObjectElement',
+ 'SVGGElement',
+ 'SVGGeometryElement',
+ 'SVGGradientElement',
+ 'SVGGraphicsElement',
+ 'SVGImageElement',
+ 'SVGLength',
+ 'SVGLengthList',
+ 'SVGLineElement',
+ 'SVGLinearGradientElement',
+ 'SVGMPathElement',
+ 'SVGMarkerElement',
+ 'SVGMaskElement',
+ 'SVGMetadataElement',
+ 'SVGNumber',
+ 'SVGNumberList',
+ 'SVGPathElement',
+ 'SVGPatternElement',
+ 'SVGPointList',
+ 'SVGPolygonElement',
+ 'SVGPolylineElement',
+ 'SVGPreserveAspectRatio',
+ 'SVGRadialGradientElement',
+ 'SVGRectElement',
+ 'SVGSVGElement',
+ 'SVGScriptElement',
+ 'SVGSetElement',
+ 'SVGStopElement',
+ 'SVGStringList',
+ 'SVGStyleElement',
+ 'SVGSwitchElement',
+ 'SVGSymbolElement',
+ 'SVGTSpanElement',
+ 'SVGTextContentElement',
+ 'SVGTextElement',
+ 'SVGTextPathElement',
+ 'SVGTextPositioningElement',
+ 'SVGTitleElement',
+ 'SVGTransform',
+ 'SVGTransformList',
+ 'SVGUnitTypes',
+ 'SVGUseElement',
+ 'SVGViewElement',
+ 'Screen',
+ 'ScreenOrientation',
+ 'ScriptProcessorNode',
+ 'SecurityPolicyViolationEvent',
+ 'Selection',
+ 'ServiceWorker',
+ 'ServiceWorkerContainer',
+ 'ServiceWorkerRegistration',
+ 'ShadowRoot',
+ 'SharedWorker',
+ 'SourceBuffer',
+ 'SourceBufferList',
+ 'SpeechRecognitionAlternative',
+ 'SpeechRecognitionResult',
+ 'SpeechRecognitionResultList',
+ 'SpeechSynthesis',
+ 'SpeechSynthesisErrorEvent',
+ 'SpeechSynthesisEvent',
+ 'SpeechSynthesisUtterance',
+ 'SpeechSynthesisVoice',
+ 'StaticRange',
+ 'StereoPannerNode',
+ 'Storage',
+ 'StorageEvent',
+ 'StorageManager',
+ 'StyleSheet',
+ 'StyleSheetList',
+ 'SubmitEvent',
+ 'SubtleCrypto',
+ 'Text',
+ 'TextDecoder',
+ 'TextDecoderStream',
+ 'TextEncoder',
+ 'TextEncoderStream',
+ 'TextMetrics',
+ 'TextTrack',
+ 'TextTrackCue',
+ 'TextTrackCueList',
+ 'TextTrackList',
+ 'TimeRanges',
+ 'Touch',
+ 'TouchEvent',
+ 'TouchList',
+ 'TrackEvent',
+ 'TransformStream',
+ 'TransformStreamDefaultController',
+ 'TransitionEvent',
+ 'TreeWalker',
+ 'UIEvent',
+ 'URL',
+ 'webkitURL',
+ 'URLSearchParams',
+ 'VTTCue',
+ 'VTTRegion',
+ 'ValidityState',
+ 'VideoPlaybackQuality',
+ 'VisualViewport',
+ 'WaveShaperNode',
+ 'WebGL2RenderingContext',
+ 'WebGLActiveInfo',
+ 'WebGLBuffer',
+ 'WebGLContextEvent',
+ 'WebGLFramebuffer',
+ 'WebGLProgram',
+ 'WebGLQuery',
+ 'WebGLRenderbuffer',
+ 'WebGLRenderingContext',
+ 'WebGLSampler',
+ 'WebGLShader',
+ 'WebGLShaderPrecisionFormat',
+ 'WebGLSync',
+ 'WebGLTexture',
+ 'WebGLTransformFeedback',
+ 'WebGLUniformLocation',
+ 'WebGLVertexArrayObject',
+ 'WebSocket',
+ 'WheelEvent',
+ 'Window',
+ 'Worker',
+ 'Worklet',
+ 'WritableStream',
+ 'WritableStreamDefaultController',
+ 'WritableStreamDefaultWriter',
+ 'XMLDocument',
+ 'XMLHttpRequest',
+ 'XMLHttpRequestEventTarget',
+ 'XMLHttpRequestUpload',
+ 'XMLSerializer',
+ 'XPathEvaluator',
+ 'XPathExpression',
+ 'XPathResult',
+ 'XSLTProcessor',
+ 'CSS',
+ 'WebAssembly',
+ 'Audio',
+ 'Image',
+ 'Option',
+ 'clientInformation',
+ 'closed',
+ 'customElements',
+ 'devicePixelRatio',
+ 'document',
+ 'event',
+ 'external',
+ 'frameElement',
+ 'frames',
+ 'history',
+ 'innerHeight',
+ 'innerWidth',
+ 'length',
+ 'location',
+ 'locationbar',
+ 'menubar',
+ 'name',
+ 'navigator',
+ 'ondevicemotion',
+ 'ondeviceorientation',
+ 'onorientationchange',
+ 'opener',
+ 'orientation',
+ 'outerHeight',
+ 'outerWidth',
+ 'pageXOffset',
+ 'pageYOffset',
+ 'parent',
+ 'personalbar',
+ 'screen',
+ 'screenLeft',
+ 'screenTop',
+ 'screenX',
+ 'screenY',
+ 'scrollX',
+ 'scrollY',
+ 'scrollbars',
+ 'self',
+ 'speechSynthesis',
+ 'status',
+ 'statusbar',
+ 'toolbar',
+ 'top',
+ 'visualViewport',
+ 'window',
+ 'alert',
+ 'blur',
+ 'cancelIdleCallback',
+ 'captureEvents',
+ 'close',
+ 'confirm',
+ 'focus',
+ 'getComputedStyle',
+ 'getSelection',
+ 'matchMedia',
+ 'moveBy',
+ 'moveTo',
+ 'open',
+ 'postMessage',
+ 'print',
+ 'prompt',
+ 'releaseEvents',
+ 'requestIdleCallback',
+ 'resizeBy',
+ 'resizeTo',
+ 'scroll',
+ 'scrollBy',
+ 'scrollTo',
+ 'stop',
+ 'toString',
+ 'dispatchEvent',
+ 'cancelAnimationFrame',
+ 'requestAnimationFrame',
+ 'onabort',
+ 'onanimationcancel',
+ 'onanimationend',
+ 'onanimationiteration',
+ 'onanimationstart',
+ 'onauxclick',
+ 'onblur',
+ 'oncanplay',
+ 'oncanplaythrough',
+ 'onchange',
+ 'onclick',
+ 'onclose',
+ 'oncontextmenu',
+ 'oncuechange',
+ 'ondblclick',
+ 'ondrag',
+ 'ondragend',
+ 'ondragenter',
+ 'ondragleave',
+ 'ondragover',
+ 'ondragstart',
+ 'ondrop',
+ 'ondurationchange',
+ 'onemptied',
+ 'onended',
+ 'onerror',
+ 'onfocus',
+ 'onformdata',
+ 'ongotpointercapture',
+ 'oninput',
+ 'oninvalid',
+ 'onkeydown',
+ 'onkeypress',
+ 'onkeyup',
+ 'onload',
+ 'onloadeddata',
+ 'onloadedmetadata',
+ 'onloadstart',
+ 'onlostpointercapture',
+ 'onmousedown',
+ 'onmouseenter',
+ 'onmouseleave',
+ 'onmousemove',
+ 'onmouseout',
+ 'onmouseover',
+ 'onmouseup',
+ 'onpause',
+ 'onplay',
+ 'onplaying',
+ 'onpointercancel',
+ 'onpointerdown',
+ 'onpointerenter',
+ 'onpointerleave',
+ 'onpointermove',
+ 'onpointerout',
+ 'onpointerover',
+ 'onpointerup',
+ 'onprogress',
+ 'onratechange',
+ 'onreset',
+ 'onresize',
+ 'onscroll',
+ 'onseeked',
+ 'onseeking',
+ 'onselect',
+ 'onselectionchange',
+ 'onselectstart',
+ 'onstalled',
+ 'onsubmit',
+ 'onsuspend',
+ 'ontimeupdate',
+ 'ontoggle',
+ 'ontouchcancel',
+ 'ontouchend',
+ 'ontouchmove',
+ 'ontouchstart',
+ 'ontransitioncancel',
+ 'ontransitionend',
+ 'ontransitionrun',
+ 'ontransitionstart',
+ 'onvolumechange',
+ 'onwaiting',
+ 'onwebkitanimationend',
+ 'onwebkitanimationiteration',
+ 'onwebkitanimationstart',
+ 'onwebkittransitionend',
+ 'onwheel',
+ 'onafterprint',
+ 'onbeforeprint',
+ 'onbeforeunload',
+ 'ongamepadconnected',
+ 'ongamepaddisconnected',
+ 'onhashchange',
+ 'onlanguagechange',
+ 'onmessage',
+ 'onmessageerror',
+ 'onoffline',
+ 'ononline',
+ 'onpagehide',
+ 'onpageshow',
+ 'onpopstate',
+ 'onrejectionhandled',
+ 'onstorage',
+ 'onunhandledrejection',
+ 'onunload',
+ 'localStorage',
+ 'caches',
+ 'crossOriginIsolated',
+ 'crypto',
+ 'indexedDB',
+ 'isSecureContext',
+ 'origin',
+ 'performance',
+ 'atob',
+ 'btoa',
+ 'createImageBitmap',
+ 'fetch',
+ 'queueMicrotask',
+ 'sessionStorage',
+ 'addEventListener',
+ 'removeEventListener'
+ ].map((v) => ({ name: v, message: "Don't use DOM globals." }))
+ ]
+ }
+};
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 5209b65..0000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,84 +0,0 @@
-{
- "env": {
- "es2021": true,
- "node": true
- },
- "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "ecmaVersion": 12,
- "sourceType": "module",
- "project": "./tsconfig.json"
- },
- "plugins": ["@typescript-eslint", "deprecation", "import"],
- "ignorePatterns": ["dist"],
- "rules": {
- "no-return-await": "off",
- "@typescript-eslint/no-empty-interface": "warn",
- "no-mixed-spaces-and-tabs": "off",
- "no-duplicate-imports": "warn",
- "no-empty-function": "off",
- "@typescript-eslint/no-empty-function": "off",
- "no-empty": "off",
- "@typescript-eslint/ban-ts-comment": [
- "error",
- {
- "ts-expect-error": "allow-with-description",
- "ts-ignore": "allow-with-description",
- "ts-nocheck": "allow-with-description",
- "ts-check": "allow-with-description",
- "minimumDescriptionLength": 5
- }
- ],
- "@typescript-eslint/no-floating-promises": "warn",
- "prefer-promise-reject-errors": "warn",
- "@typescript-eslint/no-misused-promises": "error",
- "@typescript-eslint/no-base-to-string": "error",
- "no-loss-of-precision": "off",
- "@typescript-eslint/no-loss-of-precision": "error",
- "no-throw-literal": "off",
- "@typescript-eslint/no-throw-literal": "warn",
- "@typescript-eslint/prefer-nullish-coalescing": "warn",
- "@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/no-non-null-assertion": "off",
- "@typescript-eslint/explicit-module-boundary-types": "off",
- "prefer-template": "warn",
- "@typescript-eslint/no-this-alias": [
- "error",
- {
- "allowDestructuring": true,
- "allowedNames": ["that"]
- }
- ],
- "@typescript-eslint/no-unused-vars": [
- "warn",
- {
- "argsIgnorePattern": "^_"
- }
- ],
- "no-implied-eval": "off",
- "@typescript-eslint/no-implied-eval": ["error"],
- "deprecation/deprecation": "warn",
- "@typescript-eslint/explicit-member-accessibility": ["warn", { "accessibility": "explicit" }],
- "@typescript-eslint/switch-exhaustiveness-check": "warn",
- "import/no-commonjs": "error",
- "import/extensions": ["error", "ignorePackages"],
- "@typescript-eslint/no-restricted-imports": [
- "error",
- {
- "paths": [
- {
- "name": "discord-api-types",
- "message": "Please use discord-api-types/v9 instead.",
- "allowTypeImports": true
- },
- {
- "name": "discord-api-types-next",
- "message": "Please use discord-api-types-next/v9 instead.",
- "allowTypeImports": true
- }
- ]
- }
- ]
- }
-}
diff --git a/package.json b/package.json
index 424062c..63d1c60 100644
--- a/package.json
+++ b/package.json
@@ -56,14 +56,14 @@
"@notenoughupdates/humanize-duration": "^4.0.1",
"@notenoughupdates/simplify-number": "^1.0.1",
"@notenoughupdates/wolfram-alpha-api": "^1.0.1",
- "@sentry/integrations": "^6.17.8",
- "@sentry/node": "^6.17.8",
- "@sentry/tracing": "^6.17.8",
+ "@sentry/integrations": "^6.17.9",
+ "@sentry/node": "^6.17.9",
+ "@sentry/tracing": "^6.17.9",
"canvas": "^2.9.0",
"chalk": "^5.0.0",
"deep-lock": "^1.0.0",
"discord-akairo": "npm:@notenoughupdates/discord-akairo@dev",
- "discord-api-types": "0.27.1",
+ "discord-api-types": "0.27.2",
"discord-api-types-next": "npm:discord-api-types@next",
"discord.js": "npm:@notenoughupdates/discord.js@dev",
"fuse.js": "^6.5.3",
@@ -71,7 +71,7 @@
"got": "^12.0.1",
"lodash": "^4.17.21",
"mathjs": "^10.1.1",
- "nanoid": "^3.3.0",
+ "nanoid": "^3.3.1",
"node-os-utils": "^1.3.6",
"numeral": "^2.0.6",
"pg": "^8.7.3",
@@ -79,17 +79,18 @@
"prettier": "^2.5.1",
"pretty-bytes": "^6.0.0",
"rimraf": "^3.0.2",
- "sequelize": "6.16.1",
+ "sequelize": "6.16.2",
"tinycolor2": "^1.4.2",
"typescript": "^4.5.5",
- "vm2": "^3.9.7"
+ "vm2": "^3.9.8"
},
"devDependencies": {
"@sapphire/snowflake": "^3.1.0",
- "@sentry/types": "^6.17.8",
+ "@sentry/types": "^6.17.9",
"@types/eslint": "^8.4.1",
"@types/express": "^4.17.13",
"@types/lodash": "^4.14.178",
+ "@types/lodash.snakecase": "^4.1.6",
"@types/node": "^17.0.18",
"@types/node-os-utils": "^1.2.0",
"@types/numeral": "^2.0.2",
@@ -101,7 +102,7 @@
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/parser": "^5.12.0",
"eslint": "^8.9.0",
- "eslint-config-prettier": "^8.3.0",
+ "eslint-config-prettier": "^8.4.0",
"eslint-plugin-deprecation": "^1.3.2",
"eslint-plugin-import": "^2.25.4",
"node-fetch": "^3.2.0"
diff --git a/src/arguments/globalUser.ts b/src/arguments/globalUser.ts
index 69d3e89..08350d2 100644
--- a/src/arguments/globalUser.ts
+++ b/src/arguments/globalUser.ts
@@ -2,7 +2,5 @@ import { type BushArgumentTypeCaster, type BushUser } from '#lib';
// resolve non-cached users
export const globalUser: BushArgumentTypeCaster<Promise<BushUser | null>> = async (_, phrase) => {
- return client.users.cache.has(phrase)
- ? client.users.cache.get(`${phrase}`) ?? null
- : await client.users.fetch(`${phrase}`).catch(() => null);
+ return client.users.resolve(phrase) ?? (await client.users.fetch(`${phrase}`).catch(() => null));
};
diff --git a/src/arguments/roleWithDuration.ts b/src/arguments/roleWithDuration.ts
index d619b9e..5f1da98 100644
--- a/src/arguments/roleWithDuration.ts
+++ b/src/arguments/roleWithDuration.ts
@@ -3,10 +3,10 @@ import { type Role } from 'discord.js';
export const roleWithDuration: BushArgumentTypeCaster<Promise<RoleWithDuration | null>> = async (message, phrase) => {
// eslint-disable-next-line prefer-const
- let { duration, contentWithoutTime } = client.util.parseDuration(phrase);
- if (contentWithoutTime === null || contentWithoutTime === undefined) return null;
- contentWithoutTime = contentWithoutTime.trim();
- const role = await util.arg.cast('role', message, contentWithoutTime);
+ let { duration, content } = client.util.parseDuration(phrase);
+ if (content === null || content === undefined) return null;
+ content = content.trim();
+ const role = await util.arg.cast('role', message, content);
if (!role) return null;
return { duration, role };
};
diff --git a/src/commands/admin/channelPermissions.ts b/src/commands/admin/channelPermissions.ts
index e12a131..37610b3 100644
--- a/src/commands/admin/channelPermissions.ts
+++ b/src/commands/admin/channelPermissions.ts
@@ -1,4 +1,5 @@
import { BushCommand, ButtonPaginator, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, Embed, PermissionFlagsBits } from 'discord.js';
export default class ChannelPermissionsCommand extends BushCommand {
@@ -62,9 +63,7 @@ export default class ChannelPermissionsCommand extends BushCommand {
state: 'true' | 'false' | 'neutral';
}
) {
- if (!message.inGuild()) return await message.util.reply(`${util.emojis.error} This command can only be run in a server.`);
- if (!message.member!.permissions.has(PermissionFlagsBits.Administrator) && !message.member!.user.isOwner())
- return await message.util.reply(`${util.emojis.error} You must have admin perms to use this command.`);
+ assert(message.inGuild());
if (message.util.isSlashMessage(message)) await message.interaction.deferReply();
const permission = message.util.isSlashMessage(message)
@@ -72,7 +71,7 @@ export default class ChannelPermissionsCommand extends BushCommand {
: args.permission;
if (!permission) return await message.util.reply(`${util.emojis.error} Invalid permission.`);
const failedChannels = [];
- for (const [, channel] of message.guild!.channels.cache) {
+ for (const [, channel] of message.guild.channels.cache) {
try {
if (channel.isThread()) return;
if (channel.permissionsLocked) return;
diff --git a/src/commands/config/blacklist.ts b/src/commands/config/blacklist.ts
index d210472..ba2d24a 100644
--- a/src/commands/config/blacklist.ts
+++ b/src/commands/config/blacklist.ts
@@ -1,4 +1,5 @@
import { AllowedMentions, BushCommand, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, PermissionFlagsBits, User } from 'discord.js';
export default class BlacklistCommand extends BushCommand {
@@ -40,7 +41,6 @@ export default class BlacklistCommand extends BushCommand {
}
],
slash: true,
- channel: 'guild',
clientPermissions: (m) => util.clientSendAndPermCheck(m),
userPermissions: [PermissionFlagsBits.ManageGuild]
});
@@ -64,8 +64,11 @@ export default class BlacklistCommand extends BushCommand {
if (!target) return await message.util.reply(`${util.emojis.error} Choose a valid channel or user.`);
const targetID = target.id;
- if (!message.guild && global)
+ if (!message.inGuild() && !global)
return await message.util.reply(`${util.emojis.error} You have to be in a guild to disable commands.`);
+
+ if (!global) assert(message.inGuild());
+
const blacklistedUsers = global
? util.getGlobal('blacklistedUsers')
: (await message.guild!.getSetting('blacklistedChannels')) ?? [];
diff --git a/src/commands/config/config.ts b/src/commands/config/config.ts
index 2fae2fd..f860b30 100644
--- a/src/commands/config/config.ts
+++ b/src/commands/config/config.ts
@@ -208,8 +208,10 @@ export default class ConfigCommand extends BushCommand {
value: ArgType<'channel'> | ArgType<'role'> | string;
}
) {
- if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be used in servers.`);
- if (!message.member?.permissions.has(PermissionFlagsBits.ManageGuild) && !message.member?.user.isOwner())
+ assert(message.inGuild());
+ assert(message.member);
+
+ if (!message.member.permissions.has(PermissionFlagsBits.ManageGuild) && !message.member?.user.isOwner())
return await message.util.reply(`${util.emojis.error} You must have the **Manage Server** permission to run this command.`);
const setting = message.util.isSlash ? (_.camelCase(args.subcommandGroup)! as GuildSettings) : args.setting!;
const action = message.util.isSlash ? args.subcommand! : args.action!;
@@ -263,7 +265,8 @@ export default class ConfigCommand extends BushCommand {
collector.on('collect', async (interaction: MessageComponentInteraction) => {
if (interaction.user.id === message.author.id || client.config.owners.includes(interaction.user.id)) {
- if (!message.guild) throw new Error('message.guild is null');
+ assert(message.inGuild());
+
switch (interaction.customId) {
case 'command_settingsSel': {
if (!interaction.isSelectMenu()) return;
@@ -288,10 +291,11 @@ export default class ConfigCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
setting?: undefined | keyof typeof guildSettingsObj
): Promise<MessageOptions & InteractionUpdateOptions> {
- if (!message.guild) throw new Error('message.guild is null');
+ assert(message.inGuild());
+
const settingsEmbed = new Embed().setColor(util.colors.default);
if (!setting) {
- settingsEmbed.setTitle(`${message.guild!.name}'s Settings`);
+ settingsEmbed.setTitle(`${message.guild.name}'s Settings`);
const desc = settingsArr.map((s) => `:wrench: **${guildSettingsObj[s].name}**`).join('\n');
settingsEmbed.setDescription(desc);
@@ -314,7 +318,7 @@ export default class ConfigCommand extends BushCommand {
} else {
settingsEmbed.setTitle(guildSettingsObj[setting].name);
const generateCurrentValue = async (type: GuildSettingType): Promise<string> => {
- const feat = await message.guild!.getSetting(setting);
+ const feat = await message.guild.getSetting(setting);
let func = (v: string) => v;
switch (type.replace('-array', '') as BaseSettingTypes) {
case 'string': {
diff --git a/src/commands/config/disable.ts b/src/commands/config/disable.ts
index a7ebfa2..db325fc 100644
--- a/src/commands/config/disable.ts
+++ b/src/commands/config/disable.ts
@@ -57,6 +57,8 @@ export default class DisableCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
args: { action?: 'enable' | 'disable'; command: ArgType<'commandAlias'> | string; global: boolean }
) {
+ assert(message.inGuild());
+
let action = (args.action ?? message?.util?.parsed?.alias ?? 'toggle') as 'disable' | 'enable' | 'toggle';
const global = args.global && message.author.isOwner();
const commandID =
@@ -67,13 +69,13 @@ export default class DisableCommand extends BushCommand {
if (DisableCommand.blacklistedCommands.includes(commandID))
return message.util.send(`${util.emojis.error} the ${commandID} command cannot be disabled.`);
- const disabledCommands = global ? util.getGlobal('disabledCommands') : await message.guild!.getSetting('disabledCommands');
+ const disabledCommands = global ? util.getGlobal('disabledCommands') : await message.guild.getSetting('disabledCommands');
if (action === 'toggle') action = disabledCommands.includes(commandID) ? 'disable' : 'enable';
const newValue = util.addOrRemoveFromArray(action === 'disable' ? 'remove' : 'add', disabledCommands, commandID);
const success = global
? await util.setGlobal('disabledCommands', newValue).catch(() => false)
- : await message.guild!.setSetting('disabledCommands', newValue, message.member!).catch(() => false);
+ : await message.guild.setSetting('disabledCommands', newValue, message.member!).catch(() => false);
if (!success)
return await message.util.reply({
content: `${util.emojis.error} There was an error${global ? ' globally' : ''} **${action.substring(
diff --git a/src/commands/config/features.ts b/src/commands/config/features.ts
index 199f201..c9aebd3 100644
--- a/src/commands/config/features.ts
+++ b/src/commands/config/features.ts
@@ -6,6 +6,7 @@ import {
type BushSlashMessage,
type GuildFeatures
} from '#lib';
+import assert from 'assert';
import {
ActionRow,
ComponentType,
@@ -33,11 +34,11 @@ export default class FeaturesCommand extends BushCommand {
}
public override async exec(message: BushMessage | BushSlashMessage) {
- if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be used in servers.`);
+ assert(message.inGuild());
- const featureEmbed = new Embed().setTitle(`${message.guild!.name}'s Features`).setColor(util.colors.default);
+ const featureEmbed = new Embed().setTitle(`${message.guild.name}'s Features`).setColor(util.colors.default);
- const enabledFeatures = await message.guild!.getSetting('enabledFeatures');
+ const enabledFeatures = await message.guild.getSetting('enabledFeatures');
this.generateDescription(guildFeaturesArr, enabledFeatures, featureEmbed);
const components = this.generateComponents(guildFeaturesArr, false);
const msg = (await message.util.reply({ embeds: [featureEmbed], components: [components] })) as Message;
@@ -49,7 +50,7 @@ export default class FeaturesCommand extends BushCommand {
collector.on('collect', async (interaction: SelectMenuInteraction) => {
if (interaction.user.id === message.author.id || client.config.owners.includes(interaction.user.id)) {
- if (!message.guild) throw new Error('message.guild is null');
+ assert(message.inGuild());
const [selected]: GuildFeatures[] = interaction.values as GuildFeatures[];
diff --git a/src/commands/config/log.ts b/src/commands/config/log.ts
index 79f9258..f99f007 100644
--- a/src/commands/config/log.ts
+++ b/src/commands/config/log.ts
@@ -1,4 +1,5 @@
import { BushCommand, guildLogsArr, type ArgType, type BushMessage, type BushSlashMessage, type GuildLogType } from '#lib';
+import assert from 'assert';
import { ArgumentGeneratorReturn } from 'discord-akairo';
import { ApplicationCommandOptionType, ChannelType, PermissionFlagsBits } from 'discord.js';
@@ -72,7 +73,8 @@ export default class LogCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
args: { log_type: GuildLogType; channel: ArgType<'textChannel'> }
) {
- if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be used in servers.`);
+ assert(message.inGuild());
+
const currentLogs = await message.guild.getSetting('logChannels');
const oldChannel = currentLogs[args.log_type] ?? undefined;
diff --git a/src/commands/info/icon.ts b/src/commands/info/icon.ts
index 2b5b8fb..72e82d8 100644
--- a/src/commands/info/icon.ts
+++ b/src/commands/info/icon.ts
@@ -1,4 +1,5 @@
import { BushCommand, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { Embed, PermissionFlagsBits } from 'discord.js';
export default class IconCommand extends BushCommand {
@@ -17,16 +18,18 @@ export default class IconCommand extends BushCommand {
}
public override async exec(message: BushMessage | BushSlashMessage) {
+ assert(message.inGuild());
+
const embed = new Embed()
.setTimestamp()
.setColor(util.colors.default)
.setImage(
- message.guild!.iconURL({
+ message.guild.iconURL({
size: 2048,
extension: 'png'
})!
)
- .setTitle(util.discord.escapeMarkdown(message.guild!.name));
+ .setTitle(util.discord.escapeMarkdown(message.guild.name));
await message.util.reply({ embeds: [embed] });
}
}
diff --git a/src/commands/info/links.ts b/src/commands/info/links.ts
index 25b040c..d91f1e7 100644
--- a/src/commands/info/links.ts
+++ b/src/commands/info/links.ts
@@ -1,5 +1,5 @@
import { BushCommand, type BushMessage, type BushSlashMessage } from '#lib';
-import { assert } from 'console';
+import assert from 'assert';
import { ActionRow, ButtonComponent, ButtonStyle } from 'discord.js';
import packageDotJSON from '../../../package.json' assert { type: 'json' };
diff --git a/src/commands/leveling/leaderboard.ts b/src/commands/leveling/leaderboard.ts
index eb8b90c..0871811 100644
--- a/src/commands/leveling/leaderboard.ts
+++ b/src/commands/leveling/leaderboard.ts
@@ -1,4 +1,5 @@
import { BushCommand, ButtonPaginator, Level, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, Embed, PermissionFlagsBits } from 'discord.js';
export default class LeaderboardCommand extends BushCommand {
@@ -28,7 +29,8 @@ export default class LeaderboardCommand extends BushCommand {
}
public override async exec(message: BushMessage | BushSlashMessage, args: { page: ArgType<'integer'> }) {
- if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be run in a server.`);
+ assert(message.inGuild());
+
if (!(await message.guild.hasFeature('leveling')))
return await message.util.reply(
`${util.emojis.error} This command can only be run in servers with the leveling feature enabled.${
@@ -43,7 +45,7 @@ export default class LeaderboardCommand extends BushCommand {
(val, index) => `\`${index + 1}\` <@${val.user}> - Level ${val.level} (${val.xp.toLocaleString()} xp)`
);
const chunked = util.chunk(mappedRanks, 25);
- const embeds = chunked.map((c) => new Embed().setTitle(`${message.guild!.name}'s Leaderboard`).setDescription(c.join('\n')));
+ const embeds = chunked.map((c) => new Embed().setTitle(`${message.guild.name}'s Leaderboard`).setDescription(c.join('\n')));
return await ButtonPaginator.send(message, embeds, undefined, true, args?.page ?? undefined);
}
}
diff --git a/src/commands/leveling/level.ts b/src/commands/leveling/level.ts
index 271c3f6..803703e 100644
--- a/src/commands/leveling/level.ts
+++ b/src/commands/leveling/level.ts
@@ -47,7 +47,8 @@ export default class LevelCommand extends BushCommand {
}
public override async exec(message: BushMessage | BushSlashMessage, args: { user: OptionalArgType<'user'> }) {
- if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be run in a server.`);
+ assert(message.inGuild());
+
if (!(await message.guild.hasFeature('leveling')))
return await message.util.reply(
`${util.emojis.error} This command can only be run in servers with the leveling feature enabled.${
@@ -59,7 +60,7 @@ export default class LevelCommand extends BushCommand {
const user = args.user ?? message.author;
try {
return await message.util.reply({
- files: [new MessageAttachment(await this.getImage(user, message.guild!), 'level.png')]
+ files: [new MessageAttachment(await this.getImage(user, message.guild), 'level.png')]
});
} catch (e) {
if (e instanceof Error && e.message === 'User does not have a level') {
diff --git a/src/commands/leveling/setLevel.ts b/src/commands/leveling/setLevel.ts
index 1016280..e74d885 100644
--- a/src/commands/leveling/setLevel.ts
+++ b/src/commands/leveling/setLevel.ts
@@ -1,4 +1,5 @@
import { AllowedMentions, BushCommand, Level, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
export default class SetLevelCommand extends BushCommand {
@@ -38,10 +39,11 @@ export default class SetLevelCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
{ user, level }: { user: ArgType<'user'>; level: ArgType<'integer'> }
) {
- if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be run in a guild.`);
- if (!user.id) throw new Error('user.id is null');
+ assert(message.inGuild());
+ assert(user.id);
- if (isNaN(level)) return await message.util.reply(`${util.emojis.error} Provide a valid number to set the user's level to.`);
+ if (isNaN(level) || !Number.isInteger(level))
+ return await message.util.reply(`${util.emojis.error} Provide a valid number to set the user's level to.`);
if (level > 6553 || level < 0)
return await message.util.reply(`${util.emojis.error} You cannot set a level higher than \`6553\`.`);
diff --git a/src/commands/leveling/setXp.ts b/src/commands/leveling/setXp.ts
index a86c58a..7b1b432 100644
--- a/src/commands/leveling/setXp.ts
+++ b/src/commands/leveling/setXp.ts
@@ -1,4 +1,5 @@
import { AllowedMentions, BushCommand, Level, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
export default class SetXpCommand extends BushCommand {
@@ -39,8 +40,8 @@ export default class SetXpCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
{ user, xp }: { user: ArgType<'user'>; xp: ArgType<'abbreviatedNumber'> }
) {
- if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be run in a guild.`);
- if (!user.id) throw new Error('user.id is null');
+ assert(message.inGuild());
+ assert(user.id);
if (isNaN(xp)) return await message.util.reply(`${util.emojis.error} Provide a valid number.`);
if (xp > 2147483647 || xp < 0)
diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts
index 5e3350f..25102e0 100644
--- a/src/commands/moderation/ban.ts
+++ b/src/commands/moderation/ban.ts
@@ -8,7 +8,8 @@ import {
type BushSlashMessage,
type OptionalArgType
} from '#lib';
-import { ApplicationCommandOptionType, PermissionFlagsBits, type User } from 'discord.js';
+import assert from 'assert';
+import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
export default class BanCommand extends BushCommand {
public constructor() {
@@ -71,20 +72,21 @@ export default class BanCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
args: {
user: ArgType<'user'> | ArgType<'snowflake'>;
- reason_and_duration: OptionalArgType<'contentWithDuration'>;
+ reason_and_duration: OptionalArgType<'contentWithDuration'> | string;
days: OptionalArgType<'integer'>;
force: boolean;
}
) {
- if (args.reason_and_duration && typeof args.reason_and_duration === 'object') args.reason_and_duration.duration ??= 0;
- args.days ??= 0;
+ assert(message.inGuild());
+ assert(message.member);
- if (!message.guild) return message.util.reply(`${util.emojis.error} This command cannot be used in dms.`);
- const member = message.guild!.members.cache.get((args.user as User)?.id ?? args.user);
- const user = member?.user ?? (await util.resolveNonCachedUser((args.user as User)?.id ?? args.user));
+ const { duration, content } = await util.castDurationContent(args.reason_and_duration, message);
+
+ args.days ??= message.util.parsed?.alias === 'dban' ? 1 : 0;
+ const member = message.guild.members.cache.get(typeof args.user === 'string' ? args.user : args.user.id);
+ const user = member?.user ?? (await util.resolveNonCachedUser(typeof args.user === 'string' ? args.user : args.user.id));
if (!user) return message.util.reply(`${util.emojis.error} Invalid user.`);
const useForce = args.force && message.author.isOwner();
- if (!message.member) throw new Error(`message.member is null`);
const canModerateResponse = member ? await Moderation.permissionCheck(message.member, member, 'ban', true, useForce) : true;
@@ -92,35 +94,13 @@ export default class BanCommand extends BushCommand {
return await message.util.reply(canModerateResponse);
}
- if (message.util.parsed?.alias === 'dban' && !args.days) args.days = 1;
-
if (!Number.isInteger(args.days) || args.days! < 0 || args.days! > 7) {
return message.util.reply(`${util.emojis.error} The delete days must be an integer between 0 and 7.`);
}
- let time: number | null;
- if (args.reason_and_duration) {
- time =
- typeof args.reason_and_duration === 'string'
- ? await util.arg.cast('duration', message, args.reason_and_duration)
- : args.reason_and_duration.duration;
- }
- const parsedReason = args.reason_and_duration?.contentWithoutTime ?? null;
+ const opts = { reason: content, moderator: message.member, duration: duration, deleteDays: args.days };
- const responseCode = member
- ? await member.bushBan({
- reason: parsedReason,
- moderator: message.member,
- duration: time! ?? 0,
- deleteDays: args.days
- })
- : await message.guild.bushBan({
- user,
- reason: parsedReason,
- moderator: message.member,
- duration: time! ?? 0,
- deleteDays: args.days
- });
+ const responseCode = member ? await member.bushBan(opts) : await message.guild.bushBan({ user, ...opts });
const responseMessage = (): string => {
const victim = util.format.input(user.tag);
diff --git a/src/commands/moderation/block.ts b/src/commands/moderation/block.ts
index 20c6e86..e6f7849 100644
--- a/src/commands/moderation/block.ts
+++ b/src/commands/moderation/block.ts
@@ -2,8 +2,6 @@ import {
AllowedMentions,
blockResponse,
BushCommand,
- BushTextChannel,
- BushThreadChannel,
Moderation,
type ArgType,
type BushMessage,
@@ -67,21 +65,17 @@ export default class BlockCommand extends BushCommand {
}
) {
assert(message.inGuild());
- if (!(message.channel instanceof BushTextChannel || message.channel instanceof BushThreadChannel))
- return message.util.send(`${util.emojis.error} This command can only be used in text and thread channels.`);
+ assert(message.member);
+
+ if (!message.channel.isTextBased())
+ return message.util.send(`${util.emojis.error} This command can only be used in text based channels.`);
- const reason = args.reason_and_duration
- ? typeof args.reason_and_duration === 'string'
- ? await util.arg.cast('contentWithDuration', message, args.reason_and_duration)
- : args.reason_and_duration
- : { duration: null, contentWithoutTime: '' };
+ const { duration, content } = await util.castDurationContent(args.reason_and_duration, message);
- if (reason.duration === null) reason.duration = 0;
- const member = await message.guild!.members.fetch(args.user.id).catch(() => null);
+ const member = await message.guild.members.fetch(args.user.id).catch(() => null);
if (!member)
return await message.util.reply(`${util.emojis.error} The user you selected is not in the server or is not a valid user.`);
- assert(message.member);
const useForce = args.force && message.author.isOwner();
const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'block', true, useForce);
@@ -89,18 +83,10 @@ export default class BlockCommand extends BushCommand {
return message.util.reply(canModerateResponse);
}
- const time = reason
- ? typeof reason === 'string'
- ? ((await util.arg.cast('duration', message, reason)) as number)
- : reason.duration
- : undefined;
-
- const parsedReason = reason?.contentWithoutTime ?? '';
-
const responseCode = await member.bushBlock({
- reason: parsedReason,
+ reason: content,
moderator: message.member,
- duration: time ?? 0,
+ duration: duration,
channel: message.channel
});
diff --git a/src/commands/moderation/evidence.ts b/src/commands/moderation/evidence.ts
index 23ccf59..d189e89 100644
--- a/src/commands/moderation/evidence.ts
+++ b/src/commands/moderation/evidence.ts
@@ -1,4 +1,5 @@
import { BushCommand, ModLog, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { ArgumentGeneratorReturn } from 'discord-akairo';
import { ArgumentTypeCasterReturn } from 'discord-akairo/dist/src/struct/commands/arguments/Argument.js';
import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
@@ -65,9 +66,11 @@ export default class EvidenceCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
{ case_id: caseID, evidence }: { case_id: string; evidence?: string }
) {
+ assert(message.inGuild());
+
const entry = await ModLog.findByPk(caseID);
if (!entry || entry.pseudo) return message.util.send(`${util.emojis.error} Invalid modlog entry.`);
- if (entry.guild !== message.guild!.id) return message.util.reply(`${util.emojis.error} This modlog is from another server.`);
+ if (entry.guild !== message.guild.id) return message.util.reply(`${util.emojis.error} This modlog is from another server.`);
if (evidence && (message as BushMessage).attachments?.size)
return message.util.reply(`${util.emojis.error} Please either attach an image or a reason not both.`);
diff --git a/src/commands/moderation/hideCase.ts b/src/commands/moderation/hideCase.ts
index a59380f..d603953 100644
--- a/src/commands/moderation/hideCase.ts
+++ b/src/commands/moderation/hideCase.ts
@@ -1,4 +1,5 @@
import { BushCommand, ModLog, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
export default class HideCaseCommand extends BushCommand {
@@ -27,9 +28,11 @@ export default class HideCaseCommand extends BushCommand {
}
public override async exec(message: BushMessage | BushSlashMessage, { case_id: caseID }: { case_id: string }) {
+ assert(message.inGuild());
+
const entry = await ModLog.findByPk(caseID);
if (!entry || entry.pseudo) return message.util.send(`${util.emojis.error} Invalid entry.`);
- if (entry.guild !== message.guild!.id) return message.util.reply(`${util.emojis.error} This modlog is from another server.`);
+ if (entry.guild !== message.guild.id) return message.util.reply(`${util.emojis.error} This modlog is from another server.`);
const action = entry.hidden ? 'no longer hidden' : 'now hidden';
const oldEntry = entry.hidden;
entry.hidden = !entry.hidden;
diff --git a/src/commands/moderation/kick.ts b/src/commands/moderation/kick.ts
index 6dfb09b..26098b5 100644
--- a/src/commands/moderation/kick.ts
+++ b/src/commands/moderation/kick.ts
@@ -7,6 +7,7 @@ import {
type BushMessage,
type BushSlashMessage
} from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
export default class KickCommand extends BushCommand {
@@ -57,11 +58,13 @@ export default class KickCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
{ user, reason, force }: { user: ArgType<'user'>; reason: ArgType<'string'>; force: boolean }
) {
- const member = await message.guild!.members.fetch(user.id);
+ assert(message.inGuild());
+ assert(message.member);
+
+ const member = await message.guild.members.fetch(user.id);
if (!member)
return await message.util.reply(`${util.emojis.error} The user you selected is not in the server or is not a valid user.`);
- if (!message.member) throw new Error(`message.member is null`);
const useForce = force && message.author.isOwner();
const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'kick', true, useForce);
diff --git a/src/commands/moderation/massBan.ts b/src/commands/moderation/massBan.ts
index 5621011..e4aeb55 100644
--- a/src/commands/moderation/massBan.ts
+++ b/src/commands/moderation/massBan.ts
@@ -56,6 +56,9 @@ export default class MassBanCommand extends BushCommand {
args: { users: ArgType<'string'>; reason: OptionalArgType<'string'>; days: OptionalArgType<'integer'> }
) {
assert(message.inGuild());
+
+ args.days ??= message.util.parsed?.alias?.includes('dban') ? 1 : 0;
+
const ids = args.users.split(/\n| /).filter((id) => id.length > 0);
if (ids.length === 0) return message.util.send(`${util.emojis.error} You must provide at least one user id.`);
for (const id of ids) {
@@ -67,8 +70,6 @@ export default class MassBanCommand extends BushCommand {
return message.util.reply(`${util.emojis.error} The delete days must be an integer between 0 and 7.`);
}
- if (message.util.parsed?.alias?.includes('dban') && !args.days) args.days = 1;
-
const promises = ids.map((id) =>
message.guild.bushBan({
user: id,
diff --git a/src/commands/moderation/modlog.ts b/src/commands/moderation/modlog.ts
index 443ffa3..c089d40 100644
--- a/src/commands/moderation/modlog.ts
+++ b/src/commands/moderation/modlog.ts
@@ -1,4 +1,5 @@
import { BushCommand, ButtonPaginator, ModLog, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, Embed, PermissionFlagsBits, User } from 'discord.js';
export default class ModlogCommand extends BushCommand {
@@ -30,6 +31,7 @@ export default class ModlogCommand extends BushCommand {
}
],
slash: true,
+ channel: 'guild',
clientPermissions: (m) => util.clientSendAndPermCheck(m),
userPermissions: (m) => util.userGuildPermCheck(m, [PermissionFlagsBits.ManageMessages])
});
@@ -39,11 +41,13 @@ export default class ModlogCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
{ search, hidden }: { search: ArgType<'user'> | string; hidden: boolean }
) {
+ assert(message.inGuild());
+
const foundUser = search instanceof User ? search : await util.resolveUserAsync(search);
if (foundUser) {
const logs = await ModLog.findAll({
where: {
- guild: message.guild!.id,
+ guild: message.guild.id,
user: foundUser.id
},
order: [['createdAt', 'ASC']]
@@ -68,8 +72,7 @@ export default class ModlogCommand extends BushCommand {
const entry = await ModLog.findByPk(search as string);
if (!entry || entry.pseudo || (entry.hidden && !hidden))
return message.util.send(`${util.emojis.error} That modlog does not exist.`);
- if (entry.guild !== message.guild!.id)
- return message.util.reply(`${util.emojis.error} This modlog is from another server.`);
+ if (entry.guild !== message.guild.id) return message.util.reply(`${util.emojis.error} This modlog is from another server.`);
const embed = {
title: `Case ${entry.id}`,
description: ModlogCommand.generateModlogInfo(entry, true),
diff --git a/src/commands/moderation/mute.ts b/src/commands/moderation/mute.ts
index c97ceb7..e32ece2 100644
--- a/src/commands/moderation/mute.ts
+++ b/src/commands/moderation/mute.ts
@@ -64,18 +64,15 @@ export default class MuteCommand extends BushCommand {
force?: ArgType<'boolean'>;
}
) {
- const reason = args.reason_and_duration
- ? typeof args.reason_and_duration === 'string'
- ? await util.arg.cast('contentWithDuration', message, args.reason_and_duration)
- : args.reason_and_duration
- : { duration: null, contentWithoutTime: '' };
+ assert(message.inGuild());
+ assert(message.member);
+
+ const { duration, content } = await util.castDurationContent(args.reason_and_duration, message);
- if (reason.duration === null) reason.duration = 0;
- const member = await message.guild!.members.fetch(args.user.id).catch(() => null);
+ const member = await message.guild.members.fetch(args.user.id).catch(() => null);
if (!member)
return await message.util.reply(`${util.emojis.error} The user you selected is not in the server or is not a valid user.`);
- assert(message.member);
const useForce = args.force && message.author.isOwner();
const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'mute', true, useForce);
@@ -83,18 +80,10 @@ export default class MuteCommand extends BushCommand {
return message.util.reply(canModerateResponse);
}
- const time = reason
- ? typeof reason === 'string'
- ? ((await util.arg.cast('duration', message, reason)) as number)
- : reason.duration
- : undefined;
-
- const parsedReason = reason?.contentWithoutTime ?? '';
-
const responseCode = await member.bushMute({
- reason: parsedReason,
+ reason: content,
moderator: message.member,
- duration: time ?? 0
+ duration
});
const responseMessage = (): string => {
diff --git a/src/commands/moderation/purge.ts b/src/commands/moderation/purge.ts
index c882b7f..2cc9d04 100644
--- a/src/commands/moderation/purge.ts
+++ b/src/commands/moderation/purge.ts
@@ -53,8 +53,8 @@ export default class PurgeCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
args: { amount: number; bot: boolean; user: ArgType<'user'> }
) {
- assert(message.channel);
- if (!message.inGuild()) return message.util.reply(`${util.emojis.error} You cannot run this command in dms.`);
+ assert(message.inGuild());
+
if (args.amount > 100 || args.amount < 1) return message.util.reply(`${util.emojis.error} `);
const messageFilter = (filterMessage: BushMessage): boolean => {
@@ -67,13 +67,12 @@ export default class PurgeCommand extends BushCommand {
const _messages = (await message.channel.messages.fetch({ limit: 100, before: message.id }))
.filter((message) => messageFilter(message))
.first(args.amount);
- const messages = new Collection<Snowflake, BushMessage>();
- _messages.forEach((m) => messages.set(m.id, m));
+ const messages = new Collection<Snowflake, BushMessage>(_messages.map((m) => [m.id, m]));
const purged = await message.channel.bulkDelete(messages, true).catch(() => null);
if (!purged) return message.util.reply(`${util.emojis.error} Failed to purge messages.`).catch(() => null);
else {
- client.emit('bushPurge', message.author, message.guild!, message.channel, messages);
+ client.emit('bushPurge', message.author, message.guild, message.channel, messages);
await message.util.send(`${util.emojis.success} Successfully purged **${purged.size}** messages.`);
/* .then(async (purgeMessage) => {
if (!message.util.isSlashMessage(message)) {
diff --git a/src/commands/moderation/removeReactionEmoji.ts b/src/commands/moderation/removeReactionEmoji.ts
index 092b8ac..f511007 100644
--- a/src/commands/moderation/removeReactionEmoji.ts
+++ b/src/commands/moderation/removeReactionEmoji.ts
@@ -1,6 +1,6 @@
import { BushCommand, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
import assert from 'assert';
-import { ApplicationCommandOptionType, Message, PermissionFlagsBits, type Emoji } from 'discord.js';
+import { ApplicationCommandOptionType, Message, PermissionFlagsBits } from 'discord.js';
export default class RemoveReactionEmojiCommand extends BushCommand {
public constructor() {
@@ -45,23 +45,19 @@ export default class RemoveReactionEmojiCommand extends BushCommand {
assert(message.channel);
const resolvedMessage = args.message instanceof Message ? args.message : await message.channel.messages.fetch(args.message);
- const id = !(['string'] as const).includes(typeof args.emoji);
- const emojiID = !id ? `${args.emoji}` : (args.emoji as Emoji).id;
- const success = await resolvedMessage.reactions.cache
+ const emojiID = typeof args.emoji === 'string' ? `${args.emoji}` : args.emoji.id;
+ const success = !!(await resolvedMessage.reactions.cache
?.get(emojiID!)
?.remove()
- ?.catch(() => {});
+ ?.catch(() => undefined));
+
if (success) {
return await message.util.reply(
- `${util.emojis.success} Removed all reactions of \`${id ? emojiID : args.emoji}\` from the message with the id of \`${
- resolvedMessage.id
- }\`.`
+ `${util.emojis.success} Removed all reactions of \`${emojiID}\` from the message with the id of \`${resolvedMessage.id}\`.`
);
} else {
return await message.util.reply(
- `${util.emojis.error} There was an error removing all reactions of \`${
- id ? emojiID : args.emoji
- }\` from the message with the id of \`${resolvedMessage.id}\`.`
+ `${util.emojis.error} There was an error removing all reactions of \`${emojiID}\` from the message with the id of \`${resolvedMessage.id}\`.`
);
}
}
diff --git a/src/commands/moderation/role.ts b/src/commands/moderation/role.ts
index 920ef81..8580f2f 100644
--- a/src/commands/moderation/role.ts
+++ b/src/commands/moderation/role.ts
@@ -128,7 +128,7 @@ export default class RoleCommand extends BushCommand {
}
) {
if (!args.role) return await message.util.reply(`${util.emojis.error} You must specify a role.`);
- if (args.duration === null) args.duration = 0;
+ args.duration ??= 0;
if (
!message.member!.permissions.has(PermissionFlagsBits.ManageRoles) &&
message.member!.id !== message.guild?.ownerId &&
@@ -162,20 +162,12 @@ export default class RoleCommand extends BushCommand {
const shouldLog = this.punishmentRoleNames.includes(args.role.name);
- const responseCode =
- args.action === 'add'
- ? await args.member.bushAddRole({
- moderator: message.member!,
- addToModlog: shouldLog,
- role: args.role,
- duration: args.duration
- })
- : await args.member.bushRemoveRole({
- moderator: message.member!,
- addToModlog: shouldLog,
- role: args.role,
- duration: args.duration
- });
+ const responseCode = await args.member[`bush${args.action === 'add' ? 'Add' : 'Remove'}Role`]({
+ moderator: message.member!,
+ addToModlog: shouldLog,
+ role: args.role,
+ duration: args.duration
+ });
const responseMessage = (): string => {
const victim = util.format.input(args.member.user.tag);
diff --git a/src/commands/moderation/slowmode.ts b/src/commands/moderation/slowmode.ts
index fb446d1..c0511f3 100644
--- a/src/commands/moderation/slowmode.ts
+++ b/src/commands/moderation/slowmode.ts
@@ -1,6 +1,7 @@
import { BushCommand, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
+import assert from 'assert';
import { Argument } from 'discord-akairo';
-import { ApplicationCommandOptionType, ChannelType, PermissionFlagsBits, type TextChannel, type ThreadChannel } from 'discord.js';
+import { ApplicationCommandOptionType, ChannelType, PermissionFlagsBits } from 'discord.js';
export default class SlowmodeCommand extends BushCommand {
public constructor() {
@@ -42,38 +43,33 @@ export default class SlowmodeCommand extends BushCommand {
public override async exec(
message: BushMessage | BushSlashMessage,
- {
- length,
- channel
- }: {
+ args: {
length: ArgType<'duration'> | ArgType<'durationSeconds'> | 'off' | 'none' | 'disable' | null;
channel: ArgType<'channel'>;
}
) {
- if (message.channel!.type === ChannelType.DM)
- return await message.util.reply(`${util.emojis.error} This command cannot be run in dms.`);
- if (!channel) channel = message.channel as any;
- if (![ChannelType.GuildText, ChannelType.GuildPrivateThread, ChannelType.GuildPublicThread].includes(channel.type))
- return await message.util.reply(`${util.emojis.error} <#${channel.id}> is not a text or thread channel.`);
- if (length) {
- length =
- typeof length === 'string' && !(['off', 'none', 'disable'] as const).includes(length)
- ? await util.arg.cast('duration', message, length)
- : length;
- }
+ assert(message.inGuild());
+
+ args.channel ??= message.channel;
+
+ if (!args.channel.isTextBased() || args.channel.isNews())
+ return await message.util.reply(`${util.emojis.error} <#${args.channel.id}> is not a text or thread channel.`);
- const length2: number = (['off', 'none', 'disable'] as const).includes(length as string) ? 0 : (length as number);
+ args.length =
+ typeof args.length === 'string' && !(['off', 'none', 'disable'] as const).includes(args.length)
+ ? await util.arg.cast('duration', message, args.length)
+ : args.length;
- const setSlowmode = await (channel as ThreadChannel | TextChannel)
+ const length2: number = (['off', 'none', 'disable'] as const).includes(args.length) || args.length === null ? 0 : args.length;
+
+ const setSlowmode = await args.channel
.setRateLimitPerUser(length2 / 1000, `Changed by ${message.author.tag} (${message.author.id}).`)
.catch(() => {});
if (!setSlowmode)
- return await message.util.reply(
- `${util.emojis.error} There was an error changing the slowmode of <#${(channel as ThreadChannel | TextChannel).id}>.`
- );
+ return await message.util.reply(`${util.emojis.error} There was an error changing the slowmode of <#${args.channel.id}>.`);
else
return await message.util.reply(
- `${util.emojis.success} Successfully changed the slowmode of <#${channel.id}> ${
+ `${util.emojis.success} Successfully changed the slowmode of <#${args.channel.id}> ${
length2 ? `to \`${util.humanizeDuration(length2)}` : '`off'
}\`.`
);
diff --git a/src/commands/moderation/timeout.ts b/src/commands/moderation/timeout.ts
index 32fcf76..b8fb78f 100644
--- a/src/commands/moderation/timeout.ts
+++ b/src/commands/moderation/timeout.ts
@@ -58,19 +58,16 @@ export default class TimeoutCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
args: { user: ArgType<'user'>; reason_and_duration: ArgType<'contentWithDuration'> | string; force?: ArgType<'boolean'> }
) {
- const reason = args.reason_and_duration
- ? typeof args.reason_and_duration === 'string'
- ? await util.arg.cast('contentWithDuration', message, args.reason_and_duration)
- : args.reason_and_duration
- : { duration: null, contentWithoutTime: '' };
+ assert(message.inGuild());
+ assert(message.member);
+
+ const { duration, content } = await util.castDurationContent(args.reason_and_duration, message);
- if (reason.duration === null || reason.duration < 1)
- return await message.util.reply(`${util.emojis.error} You must specify a duration for timeouts.`);
- const member = await message.guild!.members.fetch(args.user.id).catch(() => null);
+ if (!duration) return await message.util.reply(`${util.emojis.error} You must specify a duration for timeouts.`);
+ const member = await message.guild.members.fetch(args.user.id).catch(() => null);
if (!member)
return await message.util.reply(`${util.emojis.error} The user you selected is not in the server or is not a valid user.`);
- assert(message.member);
const useForce = args.force && message.author.isOwner();
const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'timeout', true, useForce);
@@ -78,13 +75,10 @@ export default class TimeoutCommand extends BushCommand {
return message.util.reply(canModerateResponse);
}
- const time = reason.duration;
- const parsedReason = reason.contentWithoutTime ?? '';
-
const responseCode = await member.bushTimeout({
- reason: parsedReason,
+ reason: content,
moderator: message.member,
- duration: time
+ duration: duration
});
const responseMessage = (): string => {
diff --git a/src/commands/moderation/unban.ts b/src/commands/moderation/unban.ts
index 7bdb32e..a6afc0a 100644
--- a/src/commands/moderation/unban.ts
+++ b/src/commands/moderation/unban.ts
@@ -7,6 +7,7 @@ import {
type BushSlashMessage,
type OptionalArgType
} from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
export default class UnbanCommand extends BushCommand {
@@ -21,7 +22,7 @@ export default class UnbanCommand extends BushCommand {
{
id: 'user',
description: 'The user to unban.',
- type: 'globalUser',
+ type: util.arg.compose('user', 'globalUser'),
prompt: 'What user would you like to unban?',
retry: '{error} Choose a valid user to unban.',
slashType: ApplicationCommandOptionType.User
@@ -48,7 +49,9 @@ export default class UnbanCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
{ user, reason }: { user: ArgType<'user'>; reason: OptionalArgType<'string'> }
) {
- const responseCode = await message.guild!.bushUnban({
+ assert(message.inGuild());
+
+ const responseCode = await message.guild.bushUnban({
user,
moderator: message.author,
reason
diff --git a/src/commands/moderation/unblock.ts b/src/commands/moderation/unblock.ts
index 7d36e15..34b2075 100644
--- a/src/commands/moderation/unblock.ts
+++ b/src/commands/moderation/unblock.ts
@@ -1,8 +1,6 @@
import {
AllowedMentions,
BushCommand,
- BushTextChannel,
- BushThreadChannel,
Moderation,
unblockResponse,
type ArgType,
@@ -63,14 +61,15 @@ export default class UnblockCommand extends BushCommand {
args: { user: ArgType<'user'>; reason: OptionalArgType<'string'>; force?: ArgType<'boolean'> }
) {
assert(message.inGuild());
- if (!(message.channel instanceof BushTextChannel || message.channel instanceof BushThreadChannel))
- return message.util.send(`${util.emojis.error} This command can only be used in text and thread channels.`);
+ assert(message.member);
+
+ if (!message.channel.isTextBased())
+ return message.util.send(`${util.emojis.error} This command can only be used in text based channels.`);
- const member = await message.guild!.members.fetch(args.user.id).catch(() => null);
+ const member = await message.guild.members.fetch(args.user.id).catch(() => null);
if (!member)
return await message.util.reply(`${util.emojis.error} The user you selected is not in the server or is not a valid user.`);
- assert(message.member);
const useForce = args.force && message.author.isOwner();
const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'unblock', true, useForce);
@@ -78,10 +77,8 @@ export default class UnblockCommand extends BushCommand {
return message.util.reply(canModerateResponse);
}
- const parsedReason = args.reason ?? '';
-
const responseCode = await member.bushUnblock({
- reason: parsedReason,
+ reason: args.reason ?? '',
moderator: message.member,
channel: message.channel
});
diff --git a/src/commands/moderation/unmute.ts b/src/commands/moderation/unmute.ts
index fb4bb55..de16cb5 100644
--- a/src/commands/moderation/unmute.ts
+++ b/src/commands/moderation/unmute.ts
@@ -9,6 +9,7 @@ import {
type BushSlashMessage,
type OptionalArgType
} from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
export default class UnmuteCommand extends BushCommand {
@@ -60,10 +61,11 @@ export default class UnmuteCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
{ user, reason, force = false }: { user: ArgType<'user'>; reason: OptionalArgType<'string'>; force?: boolean }
) {
- const error = util.emojis.error;
- const member = message.guild!.members.cache.get(user.id) as BushGuildMember;
+ assert(message.inGuild());
+ assert(message.member);
- if (!message.member) throw new Error(`message.member is null`);
+ const error = util.emojis.error;
+ const member = message.guild.members.cache.get(user.id) as BushGuildMember;
const useForce = force && message.author.isOwner();
const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'unmute', true, useForce);
diff --git a/src/commands/moderation/untimeout.ts b/src/commands/moderation/untimeout.ts
index 6d3632d..636b178 100644
--- a/src/commands/moderation/untimeout.ts
+++ b/src/commands/moderation/untimeout.ts
@@ -60,9 +60,10 @@ export default class UntimeoutCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
args: { user: ArgType<'user'>; reason: OptionalArgType<'string'>; force?: ArgType<'boolean'> }
) {
+ assert(message.inGuild());
assert(message.member);
- const member = await message.guild!.members.fetch(args.user.id).catch(() => null);
+ const member = await message.guild.members.fetch(args.user.id).catch(() => null);
if (!member)
return await message.util.reply(`${util.emojis.error} The user you selected is not in the server or is not a valid user.`);
diff --git a/src/commands/moderation/warn.ts b/src/commands/moderation/warn.ts
index 27d04b3..3ab4b0b 100644
--- a/src/commands/moderation/warn.ts
+++ b/src/commands/moderation/warn.ts
@@ -4,11 +4,11 @@ import {
Moderation,
warnResponse,
type ArgType,
- type BushGuildMember,
type BushMessage,
type BushSlashMessage,
type OptionalArgType
} from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js';
export default class WarnCommand extends BushCommand {
@@ -59,10 +59,12 @@ export default class WarnCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
{ user, reason, force = false }: { user: ArgType<'user'>; reason: OptionalArgType<'string'>; force?: boolean }
) {
- const member = message.guild!.members.cache.get(user.id) as BushGuildMember;
+ assert(message.inGuild());
+ assert(message.member);
+
+ const member = message.guild.members.cache.get(user.id);
if (!member) return message.util.reply(`${util.emojis.error} I cannot warn users that are not in the server.`);
const useForce = force && message.author.isOwner();
- if (!message.member) throw new Error(`message.member is null`);
const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'warn', true, useForce);
if (canModerateResponse !== true) {
diff --git a/src/commands/moulberry-bush/capePermissions.ts b/src/commands/moulberry-bush/capePermissions.ts
index e568036..edb2836 100644
--- a/src/commands/moulberry-bush/capePermissions.ts
+++ b/src/commands/moulberry-bush/capePermissions.ts
@@ -28,21 +28,13 @@ export default class CapePermissionsCommand extends BushCommand {
}
public override async exec(message: BushMessage | BushSlashMessage, args: { ign: ArgType<'string'> }) {
- interface CapePerms {
- success: boolean;
- perms: User[];
- }
-
- interface User {
- _id: string;
- perms: string[];
- }
-
let capePerms: CapePerms | null, uuid: string;
try {
uuid = await util.mcUUID(args.ign);
} catch (e) {
- return await message.util.reply(`${util.emojis.error} \`${args.ign}\` doesn't appear to be a valid username.`);
+ return await message.util.reply(
+ `${util.emojis.error} ${util.format.input(args.ign)} doesn't appear to be a valid username.`
+ );
}
try {
@@ -77,3 +69,13 @@ export default class CapePermissionsCommand extends BushCommand {
}
}
}
+
+interface CapePerms {
+ success: boolean;
+ perms: User[];
+}
+
+interface User {
+ _id: string;
+ perms: string[];
+}
diff --git a/src/commands/moulberry-bush/capes.ts b/src/commands/moulberry-bush/capes.ts
index 47a4ea6..551a5c6 100644
--- a/src/commands/moulberry-bush/capes.ts
+++ b/src/commands/moulberry-bush/capes.ts
@@ -38,49 +38,32 @@ export default class CapesCommand extends BushCommand {
const { tree: neuFileTree }: GithubTreeApi = await got
.get('https://api.github.com/repos/Moulberry/NotEnoughUpdates/git/trees/master?recursive=1')
.json();
- const capes = neuFileTree
+ const rawCapes = neuFileTree
.map((f) => ({
match: f.path.match(/src\/main\/resources\/assets\/notenoughupdates\/capes\/(?<name>\w+)_preview\.png/),
f
}))
.filter((f) => f.match !== null);
- const capes1: { name: string; url: string; index: number; purchasable?: boolean }[] = [];
- client.consts.mappings.capes.forEach((mapCape) => {
- if (!capes.some((gitCape) => gitCape.match!.groups!.name === mapCape.name) && mapCape.custom) {
- capes1.push({
- name: mapCape.name,
- url: mapCape.custom,
- index: mapCape.index,
- purchasable: mapCape.purchasable
- });
- }
- });
- capes.forEach((gitCape) => {
- const mapCape = client.consts.mappings.capes.find((a) => a.name === gitCape.match!.groups!.name);
- const url = mapCape?.custom ?? `https://github.com/Moulberry/NotEnoughUpdates/raw/master/${gitCape.f.path}`;
- const index = mapCape?.index !== undefined ? mapCape.index : null;
- capes1.push({ name: gitCape.match!.groups!.name, url, index: index!, purchasable: mapCape?.purchasable });
- });
-
- const sortedCapes = capes1.sort((a, b) => {
- let aWeight: number | undefined = undefined,
- bWeight: number | undefined = undefined;
- aWeight ??= a?.index;
- bWeight ??= b?.index;
-
- if (aWeight !== undefined && bWeight !== undefined) {
- return aWeight - bWeight;
- } else if (aWeight === undefined) {
- return 1;
- } else if (bWeight === undefined) {
- return -1;
- }
+ const capes: { name: string; url: string; index: number; purchasable?: boolean }[] = [
+ ...client.consts.mappings.capes
+ .filter((c) => !rawCapes.some((gitCape) => gitCape.match!.groups!.name === c.name) && c.custom)
+ .map((c) => ({ name: c.name, url: c.custom!, index: c.index, purchasable: c.purchasable })),
+ ...rawCapes.map((c) => {
+ const mapCape = client.consts.mappings.capes.find((a) => a.name === c.match!.groups!.name);
+ const url = mapCape?.custom ?? `https://github.com/Moulberry/NotEnoughUpdates/raw/master/${c.f.path}`;
+ const index = mapCape?.index !== undefined ? mapCape.index : null;
+ return { name: c.match!.groups!.name, url, index: index!, purchasable: mapCape?.purchasable };
+ })
+ ].sort((a, b) => {
+ if (a?.index !== undefined && b.index !== undefined) return a.index - b?.index;
+ else if (a.index === undefined) return 1;
+ else if (b.index === undefined) return -1;
return 0;
});
if (args.cape) {
- const cape = sortedCapes.find((s_cape) => s_cape.name === args.cape);
+ const cape = capes.find((s_cape) => s_cape.name === args.cape);
if (cape) {
const embed = this.makeEmbed(cape);
await DeleteButton.send(message, { embeds: [embed] });
@@ -88,7 +71,7 @@ export default class CapesCommand extends BushCommand {
await message.util.reply(`${util.emojis.error} Cannot find a cape called \`${args.cape}\`.`);
}
} else {
- const embeds: APIEmbed[] = sortedCapes.map(this.makeEmbed);
+ const embeds: APIEmbed[] = capes.map(this.makeEmbed);
await ButtonPaginator.send(message, embeds, null);
}
}
diff --git a/src/commands/moulberry-bush/report.ts b/src/commands/moulberry-bush/report.ts
index becdeeb..fc78a7b 100644
--- a/src/commands/moulberry-bush/report.ts
+++ b/src/commands/moulberry-bush/report.ts
@@ -1,4 +1,5 @@
import { AllowedMentions, BushCommand, type ArgType, type BushMessage } from '#lib';
+import assert from 'assert';
import { ApplicationCommandOptionType, Embed, PermissionFlagsBits } from 'discord.js';
export default class ReportCommand extends BushCommand {
@@ -37,7 +38,9 @@ export default class ReportCommand extends BushCommand {
}
public override async exec(message: BushMessage, { member, evidence }: { member: ArgType<'member'>; evidence: string }) {
- if (!message.guild || !(await message.guild.hasFeature('reporting')))
+ assert(message.inGuild());
+
+ if (!(await message.guild.hasFeature('reporting')))
return await message.util.reply(
`${util.emojis.error} This command can only be used in servers where reporting is enabled.`
);
diff --git a/src/commands/utilities/activity.ts b/src/commands/utilities/activity.ts
index 882c15d..230cc81 100644
--- a/src/commands/utilities/activity.ts
+++ b/src/commands/utilities/activity.ts
@@ -155,8 +155,7 @@ export default class ActivityCommand extends BushCommand {
args: { channel: ArgType<'voiceChannel'>; activity: string }
) {
const channel = typeof args.channel === 'string' ? message.guild?.channels.cache.get(args.channel) : args.channel;
- if (!channel || channel.type !== ChannelType.GuildVoice)
- return await message.util.reply(`${util.emojis.error} Choose a valid voice channel`);
+ if (!channel || !channel.isVoice()) return await message.util.reply(`${util.emojis.error} Choose a valid voice channel`);
const target_application_id = message.util.isSlashMessage(message)
? args.activity
diff --git a/src/commands/utilities/remind.ts b/src/commands/utilities/remind.ts
index 4b7ccb9..044d4fc 100644
--- a/src/commands/utilities/remind.ts
+++ b/src/commands/utilities/remind.ts
@@ -1,4 +1,4 @@
-import { BushCommand, Reminder, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
+import { BushCommand, Reminder, Time, type ArgType, type BushMessage, type BushSlashMessage } from '#lib';
import { ApplicationCommandOptionType } from 'discord.js';
export default class RemindCommand extends BushCommand {
@@ -7,11 +7,11 @@ export default class RemindCommand extends BushCommand {
aliases: ['remind', 'remindme', 'reminder'],
category: 'utilities',
description: 'Create reminders that will be DMed to you when the time expires.',
- usage: ['remind <duration> <reason>'],
+ usage: ['remind <duration> <reminder>'],
examples: ['template 1 2'],
args: [
{
- id: 'reason_and_duration',
+ id: 'reminder',
type: 'contentWithDuration',
match: 'rest',
description: 'The reason to be reminded and the duration to remind the user in.',
@@ -29,32 +29,30 @@ export default class RemindCommand extends BushCommand {
public override async exec(
message: BushMessage | BushSlashMessage,
- args: { reason_and_duration: ArgType<'contentWithDuration'> | string }
+ args: { reminder: ArgType<'contentWithDuration'> | string }
) {
- const { duration, contentWithoutTime: reason } =
- typeof args.reason_and_duration === 'string'
- ? await util.arg.cast('contentWithDuration', message, args.reason_and_duration)
- : args.reason_and_duration;
+ const { duration, content } = await util.castDurationContent(args.reminder, message);
- if (!reason?.trim()) return await message.util.reply(`${util.emojis.error} Please enter a reason to be reminded about.`);
- if (!duration) return await message.util.reply(`${util.emojis.error} Please enter a duration.`);
+ if (!content.trim()) return await message.util.reply(`${util.emojis.error} Please enter a reason to be reminded about.`);
+ if (!duration) return await message.util.reply(`${util.emojis.error} Please enter a time to remind you in.`);
- if (duration < 30_000)
- return await message.util.reply(`${util.emojis.error} You cannot pick a duration less than 30 seconds.`);
+ if (duration < Time.Second * 30)
+ return await message.util.reply(`${util.emojis.error} You cannot be reminded in less than 30 seconds.`);
- const created = new Date();
const expires = new Date(Date.now() + duration);
- const delta = util.format.bold(util.dateDelta(expires));
const success = await Reminder.create({
- content: reason.trim(),
+ content: content.trim(),
messageUrl: message.url!,
user: message.author.id,
- created,
- expires
+ created: new Date(),
+ expires: expires
}).catch(() => false);
if (!success) return await message.util.reply(`${util.emojis.error} Could not create a reminder.`);
+
+ // This isn't technically accurate, but it prevents it from being .99 seconds
+ const delta = util.format.bold(util.dateDelta(new Date(Date.now() + duration)));
return await message.util.reply(`${util.emojis.success} I will remind you in ${delta} (${util.timestamp(expires, 'T')}).`);
}
}
diff --git a/src/commands/utilities/viewRaw.ts b/src/commands/utilities/viewRaw.ts
index ee57e2d..be79499 100644
--- a/src/commands/utilities/viewRaw.ts
+++ b/src/commands/utilities/viewRaw.ts
@@ -1,13 +1,6 @@
-import {
- BushCommand,
- type ArgType,
- type BushMessage,
- type BushNewsChannel,
- type BushSlashMessage,
- type BushTextChannel,
- type OptionalArgType
-} from '#lib';
-import { ApplicationCommandOptionType, ChannelType, Embed, Message, PermissionFlagsBits, type Snowflake } from 'discord.js';
+import { BushCommand, type ArgType, type BushMessage, type BushSlashMessage, type OptionalArgType } from '#lib';
+import assert from 'assert';
+import { ApplicationCommandOptionType, ChannelType, Embed, Message, PermissionFlagsBits } from 'discord.js';
export default class ViewRawCommand extends BushCommand {
public constructor() {
@@ -30,7 +23,7 @@ export default class ViewRawCommand extends BushCommand {
{
id: 'channel',
description: 'The channel that the message is in.',
- type: util.arg.union('textChannel', 'newsChannel'),
+ type: util.arg.union('textChannel', 'newsChannel', 'threadChannel'),
prompt: 'What channel is the message in?',
retry: '{error} Choose a valid channel.',
optional: true,
@@ -74,22 +67,23 @@ export default class ViewRawCommand extends BushCommand {
message: BushMessage | BushSlashMessage,
args: {
message: ArgType<'guildMessage'> | ArgType<'messageLink'>;
- channel: OptionalArgType<'textChannel'> | OptionalArgType<'newsChannel'>;
+ channel: OptionalArgType<'textChannel'> | OptionalArgType<'newsChannel'> | OptionalArgType<'threadChannel'>;
json: boolean;
js: boolean;
}
) {
- if (!args.channel) args.channel = (message.channel as BushTextChannel | BushNewsChannel)!;
+ assert(message.inGuild());
+
+ args.channel ??= message.channel;
+
const newMessage =
- args.message instanceof Message
- ? args.message
- : await args.channel.messages.fetch(`${args.message}` as Snowflake).catch(() => null);
+ args.message instanceof Message ? args.message : await args.channel!.messages.fetch(`${args.message}`).catch(() => null);
if (!newMessage)
return await message.util.reply(
`${util.emojis.error} There was an error fetching that message, make sure that is a valid id and if the message is not in this channel, please provide a channel.`
);
- const Embed = await ViewRawCommand.getRawData(newMessage as BushMessage, { json: args.json, js: args.js });
+ const Embed = await ViewRawCommand.getRawData(newMessage, { json: args.json, js: args.js });
return await message.util.reply({ embeds: [Embed] });
}
diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts
index fc5532b..3b22935 100644
--- a/src/lib/common/AutoMod.ts
+++ b/src/lib/common/AutoMod.ts
@@ -178,6 +178,7 @@ export class AutoMod {
}
private async checkPerspectiveApi() {
+ return;
if (!client.config.isDevelopment) return;
if (!this.message.content) return;
diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts
index 43ae139..e46e701 100644
--- a/src/lib/extensions/discord-akairo/BushClient.ts
+++ b/src/lib/extensions/discord-akairo/BushClient.ts
@@ -42,6 +42,7 @@ import {
} from 'discord.js';
import EventEmitter from 'events';
import { google } from 'googleapis';
+import snakeCase from 'lodash.snakecase';
import path from 'path';
import readline from 'readline';
import type { Options as SequelizeOptions, Sequelize as SequelizeType } from 'sequelize';
@@ -213,7 +214,9 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
allowedMentions: AllowedMentions.users(), // No everyone or role mentions by default
makeCache: Options.cacheWithLimits({}),
failIfNotExists: false,
- rest: { api: 'https://canary.discord.com/api' }
+ rest: { api: 'https://canary.discord.com/api' },
+ // todo: remove this when https://github.com/discordjs/discord.js/pull/7497 is merged
+ jsonTransformer
});
patch(this);
@@ -542,3 +545,9 @@ enum GatewayIntentBits {
DirectMessageTyping = 16384,
GuildScheduledEvents = 65536
}
+
+function jsonTransformer(obj: any): any {
+ if (typeof obj !== 'object' || !obj) return obj;
+ if (Array.isArray(obj)) return obj.map(jsonTransformer);
+ return Object.fromEntries(Object.entries(obj).map(([key, value]) => [snakeCase(key), jsonTransformer(value)]));
+}
diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts
index bf4dfaf..ecfa360 100644
--- a/src/lib/extensions/discord-akairo/BushClientUtil.ts
+++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts
@@ -1,5 +1,6 @@
import {
Arg,
+ BaseBushArgumentType,
BushConstants,
Global,
Shared,
@@ -21,7 +22,7 @@ import assert from 'assert';
import { exec } from 'child_process';
import deepLock from 'deep-lock';
import { ClientUtil, Util as AkairoUtil } from 'discord-akairo';
-import type { APIMessage } from 'discord-api-types/v9';
+import { APIMessage, OAuth2Scopes } from 'discord-api-types/v9';
import {
Constants as DiscordConstants,
GuildMember,
@@ -266,31 +267,18 @@ export class BushClientUtil extends ClientUtil {
* @returns The default options combined with the specified options.
*/
#getDefaultInspectOptions(options?: BushInspectOptions): BushInspectOptions {
- const {
- showHidden = false,
- depth = 2,
- colors = false,
- customInspect = true,
- showProxy = false,
- maxArrayLength = Infinity,
- maxStringLength = Infinity,
- breakLength = 80,
- compact = 3,
- sorted = false,
- getters = true
- } = options ?? {};
return {
- showHidden,
- depth,
- colors,
- customInspect,
- showProxy,
- maxArrayLength,
- maxStringLength,
- breakLength,
- compact,
- sorted,
- getters
+ showHidden: options?.showHidden ?? false,
+ depth: options?.depth ?? 2,
+ colors: options?.colors ?? false,
+ customInspect: options?.customInspect ?? true,
+ showProxy: options?.showProxy ?? false,
+ maxArrayLength: options?.maxArrayLength ?? Infinity,
+ maxStringLength: options?.maxStringLength ?? Infinity,
+ breakLength: options?.breakLength ?? 80,
+ compact: options?.compact ?? 3,
+ sorted: options?.sorted ?? false,
+ getters: options?.getters ?? true
};
}
@@ -556,7 +544,7 @@ export class BushClientUtil extends ClientUtil {
* @returns The {@link ParsedDuration}.
*/
public parseDuration(content: string, remove = true): ParsedDuration {
- if (!content) return { duration: 0, contentWithoutTime: null };
+ if (!content) return { duration: 0, content: null };
// eslint-disable-next-line prefer-const
let duration: number | null = null;
@@ -574,7 +562,7 @@ export class BushClientUtil extends ClientUtil {
}
// remove the space added earlier
if (contentWithoutTime.startsWith(' ')) contentWithoutTime.replace(' ', '');
- return { duration, contentWithoutTime };
+ return { duration, content: contentWithoutTime };
}
/**
@@ -716,7 +704,7 @@ export class BushClientUtil extends ClientUtil {
.catch(() => undefined)) as { pronouns: PronounCode } | undefined;
if (!apiRes) return undefined;
- if (!apiRes.pronouns) throw new Error('apiRes.pronouns is undefined');
+ assert(apiRes.pronouns);
return client.constants.pronounMapping[apiRes.pronouns!]!;
}
@@ -911,10 +899,10 @@ export class BushClientUtil extends ClientUtil {
* The link to invite the bot with all permissions.
*/
public get invite() {
- return `https://discord.com/api/oauth2/authorize?client_id=${Buffer.from(
- client.token!.split('.')[0],
- 'base64'
- ).toString()}&permissions=${PermissionsBitField.All}&scope=bot%20applications.commands`;
+ return client.generateInvite({
+ permissions: PermissionsBitField.All,
+ scopes: [OAuth2Scopes.Bot, OAuth2Scopes.ApplicationsCommands]
+ });
}
public assertAll(...args: any[]): void {
@@ -923,6 +911,23 @@ export class BushClientUtil extends ClientUtil {
}
}
+ public async castDurationContent(
+ arg: string | ParsedDuration | null,
+ message: BushMessage | BushSlashMessage
+ ): Promise<ParsedDurationRes> {
+ const res = typeof arg === 'string' ? await util.arg.cast('contentWithDuration', message, arg) : arg;
+
+ return { duration: res?.duration ?? 0, content: res?.content ?? '' };
+ }
+
+ public async cast<T extends keyof BaseBushArgumentType>(
+ type: T,
+ arg: BaseBushArgumentType[T] | string,
+ message: BushMessage | BushSlashMessage
+ ) {
+ return typeof arg === 'string' ? await util.arg.cast(type, message, arg) : arg;
+ }
+
/**
* A wrapper for the Argument class that adds custom typings.
*/
@@ -989,5 +994,10 @@ export interface HasteResults {
export interface ParsedDuration {
duration: number | null;
- contentWithoutTime: string | null;
+ content: string | null;
+}
+
+export interface ParsedDurationRes {
+ duration: number;
+ content: string;
}
diff --git a/src/lib/extensions/discord.js/BushCategoryChannel.ts b/src/lib/extensions/discord.js/BushCategoryChannel.ts
index ac82bf0..3868b54 100644
--- a/src/lib/extensions/discord.js/BushCategoryChannel.ts
+++ b/src/lib/extensions/discord.js/BushCategoryChannel.ts
@@ -2,7 +2,6 @@ import {
BushDMChannel,
BushGuildBasedChannel,
BushNewsChannel,
- BushNonThreadGuildBasedChannel,
BushStageChannel,
BushStoreChannel,
BushTextBasedChannel,
@@ -10,11 +9,11 @@ import {
BushThreadChannel,
BushVoiceBasedChannel,
BushVoiceChannel,
+ type BushCategoryChannelChildManager,
type BushClient,
- type BushGuild,
- type BushGuildMember
+ type BushGuild
} from '#lib';
-import { CategoryChannel, type Collection, type Snowflake } from 'discord.js';
+import { CategoryChannel } from 'discord.js';
import { type RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
/**
@@ -22,10 +21,8 @@ import { type RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
*/
export class BushCategoryChannel extends CategoryChannel {
public declare readonly client: BushClient;
- public declare readonly children: Collection<Snowflake, Exclude<BushNonThreadGuildBasedChannel, BushCategoryChannel>>;
+ public declare readonly children: BushCategoryChannelChildManager;
public declare guild: BushGuild;
- public declare readonly members: Collection<Snowflake, BushGuildMember>;
- public declare readonly parent: CategoryChannel | null;
public constructor(guild: BushGuild, data?: RawGuildChannelData, client?: BushClient, immediatePatch?: boolean) {
super(guild, data, client, immediatePatch);
diff --git a/src/lib/extensions/discord.js/BushCategoryChannelChildManager.ts b/src/lib/extensions/discord.js/BushCategoryChannelChildManager.ts
new file mode 100644
index 0000000..b9a7ac7
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushCategoryChannelChildManager.ts
@@ -0,0 +1,52 @@
+/* eslint-disable deprecation/deprecation */
+import type {
+ BushCategoryChannel,
+ BushGuild,
+ BushGuildChannelResolvable,
+ BushMappedChannelCategoryTypes,
+ BushNonCategoryGuildBasedChannel,
+ BushStoreChannel,
+ BushTextChannel
+} from '#lib';
+import type { CategoryChannelType, CategoryCreateChannelOptions, ChannelType, DataManager, Snowflake } from 'discord.js';
+
+export declare class BushCategoryChannelChildManager extends DataManager<
+ Snowflake,
+ BushNonCategoryGuildBasedChannel,
+ BushGuildChannelResolvable
+> {
+ private constructor(channel: BushCategoryChannel);
+
+ /**
+ * The category channel this manager belongs to
+ */
+ public channel: BushCategoryChannel;
+
+ /**
+ * The guild this manager belongs to
+ */
+ public readonly guild: BushGuild;
+
+ /**
+ * Creates a new channel within this category.
+ * <info>You cannot create a channel of type {@link ChannelType.GuildCategory} inside a CategoryChannel.</info>
+ * @param name The name of the new channel
+ * @param options Options for creating the new channel
+ */
+ public create<T extends Exclude<CategoryChannelType, ChannelType.GuildStore>>(
+ name: string,
+ options: CategoryCreateChannelOptions & { type: T }
+ ): Promise<BushMappedChannelCategoryTypes[T]>;
+ /**
+ * Creates a new channel within this category.
+ * <info>You cannot create a channel of type {@link ChannelType.GuildCategory} inside a CategoryChannel.</info>
+ * @param name The name of the new channel
+ * @param options Options for creating the new channel
+ * @deprecated See [Self-serve Game Selling Deprecation](https://support-dev.discord.com/hc/en-us/articles/4414590563479) for more information
+ */
+ public create(
+ name: string,
+ options: CategoryCreateChannelOptions & { type: ChannelType.GuildStore }
+ ): Promise<BushStoreChannel>;
+ public create(name: string, options?: CategoryCreateChannelOptions): Promise<BushTextChannel>;
+}
diff --git a/src/lib/extensions/discord.js/other.ts b/src/lib/extensions/discord.js/other.ts
index 784442d..e4bc10b 100644
--- a/src/lib/extensions/discord.js/other.ts
+++ b/src/lib/extensions/discord.js/other.ts
@@ -161,3 +161,5 @@ export enum BushInteractionType {
MessageComponent = 3,
ApplicationCommandAutocomplete = 4
}
+
+export type BushNonCategoryGuildBasedChannel = Exclude<BushGuildBasedChannel, BushCategoryChannel>;
diff --git a/src/lib/index.ts b/src/lib/index.ts
index 7a9ab5f..45d76b7 100644
--- a/src/lib/index.ts
+++ b/src/lib/index.ts
@@ -28,6 +28,7 @@ export type { BushBaseGuildEmojiManager } from './extensions/discord.js/BushBase
export type { BushBaseGuildVoiceChannel } from './extensions/discord.js/BushBaseGuildVoiceChannel.js';
export * from './extensions/discord.js/BushButtonInteraction.js';
export * from './extensions/discord.js/BushCategoryChannel.js';
+export type { BushCategoryChannelChildManager } from './extensions/discord.js/BushCategoryChannelChildManager.js';
export type { BushChannel } from './extensions/discord.js/BushChannel.js';
export type { BushChannelManager } from './extensions/discord.js/BushChannelManager.js';
export * from './extensions/discord.js/BushChatInputCommandInteraction.js';
diff --git a/src/lib/utils/CanvasProgressBar.ts b/src/lib/utils/CanvasProgressBar.ts
index 1ba0e8b..21c4e22 100644
--- a/src/lib/utils/CanvasProgressBar.ts
+++ b/src/lib/utils/CanvasProgressBar.ts
@@ -1,3 +1,5 @@
+import { CanvasRenderingContext2D } from 'canvas';
+
// I just copy pasted this code from stackoverflow don't yell at me if there is issues for it
export class CanvasProgressBar {
private readonly x: number;
diff --git a/src/listeners/ws/INTERACTION_CREATE.ts b/src/listeners/ws/INTERACTION_CREATE.ts
index f44c06c..25d9cfe 100644
--- a/src/listeners/ws/INTERACTION_CREATE.ts
+++ b/src/listeners/ws/INTERACTION_CREATE.ts
@@ -35,7 +35,7 @@ export default class WsInteractionCreateListener extends BushListener {
}
public override async exec(interaction: APIInteraction) {
- console.dir(interaction);
+ // console.dir(interaction);
const respond = (
options:
diff --git a/tsconfig.json b/tsconfig.json
index 7cee300..2816d04 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,7 +4,7 @@
"target": "ESNext",
"moduleResolution": "Node",
"outDir": "dist",
- "lib": ["esnext"],
+ "lib": ["ESNext"],
"sourceMap": true,
"incremental": true,
"experimentalDecorators": true,
diff --git a/yarn.lock b/yarn.lock
index dfcf7b4..3adab61 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15,28 +15,29 @@ __metadata:
linkType: hard
"@discordjs/builders@npm:^0.13.0-dev":
- version: 0.13.0-dev.1644969969.c1b27f8
- resolution: "@discordjs/builders@npm:0.13.0-dev.1644969969.c1b27f8"
+ version: 0.13.0-dev.1645142857.f7257f0
+ resolution: "@discordjs/builders@npm:0.13.0-dev.1645142857.f7257f0"
dependencies:
"@sindresorhus/is": ^4.4.0
discord-api-types: ^0.27.0
+ fast-deep-equal: ^3.1.3
ts-mixer: ^6.0.0
tslib: ^2.3.1
zod: ^3.11.6
- checksum: c2a534179251dba1981e8650a473b8a38215a34a158485aa0d28b1bba348f30c3a68fc2fa58196af928524cb56f7cbe8a298b3856c0533588ba6a0e5b1de0a4f
+ checksum: 258daa93ce5eac18173271d03a25a1528260dd6ed7d248ade5da7dc69db84a9608a4010fe9b3a27c75fdf8fc64c44dff6139af58434b9345cbc5b7ec5eb731d8
languageName: node
linkType: hard
"@discordjs/collection@npm:^0.6.0-dev":
- version: 0.6.0-dev.1644969966.c1b27f8
- resolution: "@discordjs/collection@npm:0.6.0-dev.1644969966.c1b27f8"
- checksum: b722795e71769c135d04e5f0fed8a2c85f85201377fc5b9e234d22486e7909b1bbaee3219d8a5b5100268ce48d38024ed34d2ae7ac6497695afbe241141ea344
+ version: 0.6.0-dev.1645142877.f7257f0
+ resolution: "@discordjs/collection@npm:0.6.0-dev.1645142877.f7257f0"
+ checksum: a9bc6a0b9dfb25c6aae3be1387c5cfc0ec44109c50fccb080840479a0b12771c7d69dfc37ffb9985868475d222d180e0b876c686d16d9f217186f6626f1ae1a9
languageName: node
linkType: hard
"@discordjs/rest@npm:^0.4.0-dev":
- version: 0.4.0-dev.1644969983.c1b27f8
- resolution: "@discordjs/rest@npm:0.4.0-dev.1644969983.c1b27f8"
+ version: 0.4.0-dev.1645142857.f7257f0
+ resolution: "@discordjs/rest@npm:0.4.0-dev.1645142857.f7257f0"
dependencies:
"@discordjs/collection": ^0.6.0-dev
"@sapphire/async-queue": ^1.2.0
@@ -46,7 +47,7 @@ __metadata:
form-data: ^4.0.0
node-fetch: ^2.6.7
tslib: ^2.3.1
- checksum: fb30cba78e38118dbdef20da3b2ee69c0ded1a3350c79ee14d08d2fbf8709a7e096629de883c7f4b4a7e6516ff1c7bf82d50bad8fc08b8c515d4915b261c9507
+ checksum: ca4273978128dc472441dacfaca75a7d284dfc1a5250e0b40627383b565ac3a7921daf1731f67c0376d480bc6b29709c688edaab9fe6fc701ef3932ec1c06488
languageName: node
linkType: hard
@@ -68,9 +69,9 @@ __metadata:
linkType: hard
"@gar/promisify@npm:^1.0.1":
- version: 1.1.2
- resolution: "@gar/promisify@npm:1.1.2"
- checksum: d05081e0887a49c178b75ee3067bd6ee086f73c154d121b854fb2e044e8a89cb1cbb6de3a0dd93a519b80f0531fda68b099dd7256205f7fbb3490324342f2217
+ version: 1.1.3
+ resolution: "@gar/promisify@npm:1.1.3"
+ checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1
languageName: node
linkType: hard
@@ -207,97 +208,97 @@ __metadata:
languageName: node
linkType: hard
-"@sentry/core@npm:6.17.8":
- version: 6.17.8
- resolution: "@sentry/core@npm:6.17.8"
+"@sentry/core@npm:6.17.9":
+ version: 6.17.9
+ resolution: "@sentry/core@npm:6.17.9"
dependencies:
- "@sentry/hub": 6.17.8
- "@sentry/minimal": 6.17.8
- "@sentry/types": 6.17.8
- "@sentry/utils": 6.17.8
+ "@sentry/hub": 6.17.9
+ "@sentry/minimal": 6.17.9
+ "@sentry/types": 6.17.9
+ "@sentry/utils": 6.17.9
tslib: ^1.9.3
- checksum: 269fe795f8feb3ed55bc4878c70467e13de080751ad1578dd9c4a4fd04b64761d5084480bab3614e042b3964f039b210d18add11aa9144381cd32e103105d614
+ checksum: 703f2ffdcbc3b34f48070d8892014b0d82ab44c837746c8f3225b32b21a0d362b130acde4d65b0ee71d2cb39b7a2a2f23d7cd92e15f27dd6e9d03d4386495065
languageName: node
linkType: hard
-"@sentry/hub@npm:6.17.8":
- version: 6.17.8
- resolution: "@sentry/hub@npm:6.17.8"
+"@sentry/hub@npm:6.17.9":
+ version: 6.17.9
+ resolution: "@sentry/hub@npm:6.17.9"
dependencies:
- "@sentry/types": 6.17.8
- "@sentry/utils": 6.17.8
+ "@sentry/types": 6.17.9
+ "@sentry/utils": 6.17.9
tslib: ^1.9.3
- checksum: c8e9588c92ab5ee9a3e07f6afe5d6e9d3351faaec0ce2883eb2d15ece6b2fa71c5eacd599f5fd1491dab953648d60bd78245bb874f9c9f1c5de23309adfbd4e2
+ checksum: 6a87435dcb17edf19ca6f04b1926f6ae19985c104a0a4c6052e05db2e04891e5c55b00b88ed93b975b1a0d9f1b3f149428fd8bf8ddb12afe39027fbbcc0362ad
languageName: node
linkType: hard
-"@sentry/integrations@npm:^6.17.8":
- version: 6.17.8
- resolution: "@sentry/integrations@npm:6.17.8"
+"@sentry/integrations@npm:^6.17.9":
+ version: 6.17.9
+ resolution: "@sentry/integrations@npm:6.17.9"
dependencies:
- "@sentry/types": 6.17.8
- "@sentry/utils": 6.17.8
+ "@sentry/types": 6.17.9
+ "@sentry/utils": 6.17.9
localforage: ^1.8.1
tslib: ^1.9.3
- checksum: b7e55b4dcc6e8d08e001c3d54bab3d788e25d86595f9cc09b39e26c605c80f1a2388c59f8926538d0e2e57812e19de24a52790c2465db333f41c9d43f75eba9f
+ checksum: 0763a4cb1df92e33f8a595fc3e0c08885ed72508a678e6a69a4988f0fe5aa109dec0d91c6c93694d298afee8dca347d4addd8f46e898865ae336e82bfa018822
languageName: node
linkType: hard
-"@sentry/minimal@npm:6.17.8":
- version: 6.17.8
- resolution: "@sentry/minimal@npm:6.17.8"
+"@sentry/minimal@npm:6.17.9":
+ version: 6.17.9
+ resolution: "@sentry/minimal@npm:6.17.9"
dependencies:
- "@sentry/hub": 6.17.8
- "@sentry/types": 6.17.8
+ "@sentry/hub": 6.17.9
+ "@sentry/types": 6.17.9
tslib: ^1.9.3
- checksum: a149284761df6230ca3589ec1839c7f6783f92a92beb48ccb4f1080a7364e46be53d7f05268147f40415a1504e7e8d5cf391a4bd765f170b5b19d61a761f6d29
+ checksum: 4cf238f2246151a00ded5639a984d20553ed6c46f68f2b7b889393d2be1477b30859535100d0b3d5fdcf4f9d3c733ce994e036703665d5e595d0837c73024bc7
languageName: node
linkType: hard
-"@sentry/node@npm:^6.17.8":
- version: 6.17.8
- resolution: "@sentry/node@npm:6.17.8"
+"@sentry/node@npm:^6.17.9":
+ version: 6.17.9
+ resolution: "@sentry/node@npm:6.17.9"
dependencies:
- "@sentry/core": 6.17.8
- "@sentry/hub": 6.17.8
- "@sentry/tracing": 6.17.8
- "@sentry/types": 6.17.8
- "@sentry/utils": 6.17.8
+ "@sentry/core": 6.17.9
+ "@sentry/hub": 6.17.9
+ "@sentry/tracing": 6.17.9
+ "@sentry/types": 6.17.9
+ "@sentry/utils": 6.17.9
cookie: ^0.4.1
https-proxy-agent: ^5.0.0
lru_map: ^0.3.3
tslib: ^1.9.3
- checksum: 34f869a8dd29cc9905c883053690dd67137309a53223586fa4154f4d57e3ec4553b9913720b84b74839c496c37788a362d3d2820d29e0e89ef7ad40484dea98a
+ checksum: 0a039900b3ac9426ebf269936cd59ff58cae65bbadea51984b07a846ed910a008ead234aa60826d209d9334c9fa5f3695ccf010bbbcc098d70fe1484cd3b4d9e
languageName: node
linkType: hard
-"@sentry/tracing@npm:6.17.8, @sentry/tracing@npm:^6.17.8":
- version: 6.17.8
- resolution: "@sentry/tracing@npm:6.17.8"
+"@sentry/tracing@npm:6.17.9, @sentry/tracing@npm:^6.17.9":
+ version: 6.17.9
+ resolution: "@sentry/tracing@npm:6.17.9"
dependencies:
- "@sentry/hub": 6.17.8
- "@sentry/minimal": 6.17.8
- "@sentry/types": 6.17.8
- "@sentry/utils": 6.17.8
+ "@sentry/hub": 6.17.9
+ "@sentry/minimal": 6.17.9
+ "@sentry/types": 6.17.9
+ "@sentry/utils": 6.17.9
tslib: ^1.9.3
- checksum: dbf4d96e4b877fc6e7f9b167a22b3a12a7316e5e24aa111156c4e6f001cca37e439d33f7ed2743aa9a0791dd2eff392d105ee75661b8d753e747336419483f78
+ checksum: 241037c2ab362b093a370018c9a8912ced1d7d22e65523eca8f6edb548153f2c65bda6c3fff2bbf910ff2fc11aec6af6953d35a13991e403112b7be62c8f9108
languageName: node
linkType: hard
-"@sentry/types@npm:6.17.8, @sentry/types@npm:^6.17.8":
- version: 6.17.8
- resolution: "@sentry/types@npm:6.17.8"
- checksum: 18b727989656cff40141f9c05ef17ec4d7f89512e08df806641fb9ef8804c04f3871db9fe6d32b5010521db772baae0f2b68f71cfcbe6e32466960c4c7899d55
+"@sentry/types@npm:6.17.9, @sentry/types@npm:^6.17.9":
+ version: 6.17.9
+ resolution: "@sentry/types@npm:6.17.9"
+ checksum: 1673f490f31212c1127fed341396bde30b6a8ea1a1482cd3cde9ba3e2af9535155d22b1a346f23394b5272abe8de3d1ee2426f00d3bd3f103c89dd029f312381
languageName: node
linkType: hard
-"@sentry/utils@npm:6.17.8":
- version: 6.17.8
- resolution: "@sentry/utils@npm:6.17.8"
+"@sentry/utils@npm:6.17.9":
+ version: 6.17.9
+ resolution: "@sentry/utils@npm:6.17.9"
dependencies:
- "@sentry/types": 6.17.8
+ "@sentry/types": 6.17.9
tslib: ^1.9.3
- checksum: daff1758a9955299deae8f5d3800f7e96fc39c05d0e593045f4afe004238c0adea74cee8c3fa45003d4e3641e56b628c9bef2056e5060cc9bfdccd37dd561e69
+ checksum: 2a272e00372020613947ae4f65546814c18c58dcf9a08648d01cf4e720c07fb46b3cd62b53e8009a2bbcbd9d4ce0c3c042b787630375c4aa7fee9ec0516c5a89
languageName: node
linkType: hard
@@ -444,7 +445,16 @@ __metadata:
languageName: node
linkType: hard
-"@types/lodash@npm:^4.14.178":
+"@types/lodash.snakecase@npm:^4.1.6":
+ version: 4.1.6
+ resolution: "@types/lodash.snakecase@npm:4.1.6"
+ dependencies:
+ "@types/lodash": "*"
+ checksum: 0be8d3b8f9b2304ad86f284587a95a3625fa121daad2a3ef00104df3b4d617165a6ff3e4d52ac1c6abaf6187a2d5a59e69ee20a369dc66b91a1e949377e2c846
+ languageName: node
+ linkType: hard
+
+"@types/lodash@npm:*, @types/lodash@npm:^4.14.178":
version: 4.14.178
resolution: "@types/lodash@npm:4.14.178"
checksum: a69a04a60bfc5257c3130a554b4efa0c383f0141b7b3db8ab7cf07ad2a46ea085fce66d0242da41da7e5647b133d5dfb2c15add9cbed8d7fef955e4a1e5b3128
@@ -579,11 +589,11 @@ __metadata:
linkType: hard
"@types/ws@npm:^8.2.2":
- version: 8.2.2
- resolution: "@types/ws@npm:8.2.2"
+ version: 8.2.3
+ resolution: "@types/ws@npm:8.2.3"
dependencies:
"@types/node": "*"
- checksum: 308957864b9a5a0378ac82f1b084fa31b1bbe85106fb0d84ed2b392e4829404f21ab6ab2c1eb782d556e59cd33d57c75ad2d0cedc4b9b9d0ca3b2311bc915578
+ checksum: 94e949ef66909334eb8d77079a28ce8fcea8780295eadab1bccdbb85adc0534d96d9a61910a80720769c6019e7bfaba90cea6f95f58e93de135b766074aa53cb
languageName: node
linkType: hard
@@ -957,13 +967,14 @@ __metadata:
"@notenoughupdates/simplify-number": ^1.0.1
"@notenoughupdates/wolfram-alpha-api": ^1.0.1
"@sapphire/snowflake": ^3.1.0
- "@sentry/integrations": ^6.17.8
- "@sentry/node": ^6.17.8
- "@sentry/tracing": ^6.17.8
- "@sentry/types": ^6.17.8
+ "@sentry/integrations": ^6.17.9
+ "@sentry/node": ^6.17.9
+ "@sentry/tracing": ^6.17.9
+ "@sentry/types": ^6.17.9
"@types/eslint": ^8.4.1
"@types/express": ^4.17.13
"@types/lodash": ^4.14.178
+ "@types/lodash.snakecase": ^4.1.6
"@types/node": ^17.0.18
"@types/node-os-utils": ^1.2.0
"@types/numeral": ^2.0.2
@@ -978,11 +989,11 @@ __metadata:
chalk: ^5.0.0
deep-lock: ^1.0.0
discord-akairo: "npm:@notenoughupdates/discord-akairo@dev"
- discord-api-types: 0.27.1
+ discord-api-types: 0.27.2
discord-api-types-next: "npm:discord-api-types@next"
discord.js: "npm:@notenoughupdates/discord.js@dev"
eslint: ^8.9.0
- eslint-config-prettier: ^8.3.0
+ eslint-config-prettier: ^8.4.0
eslint-plugin-deprecation: ^1.3.2
eslint-plugin-import: ^2.25.4
fuse.js: ^6.5.3
@@ -990,7 +1001,7 @@ __metadata:
got: ^12.0.1
lodash: ^4.17.21
mathjs: ^10.1.1
- nanoid: ^3.3.0
+ nanoid: ^3.3.1
node-fetch: ^3.2.0
node-os-utils: ^1.3.6
numeral: ^2.0.6
@@ -999,10 +1010,10 @@ __metadata:
prettier: ^2.5.1
pretty-bytes: ^6.0.0
rimraf: ^3.0.2
- sequelize: 6.16.1
+ sequelize: 6.16.2
tinycolor2: ^1.4.2
typescript: ^4.5.5
- vm2: ^3.9.7
+ vm2: ^3.9.8
languageName: unknown
linkType: soft
@@ -1335,9 +1346,9 @@ __metadata:
linkType: hard
"discord-api-types-next@npm:discord-api-types@next":
- version: 0.27.2-next.3b1acdf.1644961926
- resolution: "discord-api-types@npm:0.27.2-next.3b1acdf.1644961926"
- checksum: 18bfa28bd0330983e915560f955ab5ebaa0fc0a0a1ce7415c054aa3d1d9476833ca3cac9600bff87fddb53117883b6b54f579d67500ec4bc217594945a163ddb
+ version: 0.27.3-next.8d432f2.1645207075
+ resolution: "discord-api-types@npm:0.27.3-next.8d432f2.1645207075"
+ checksum: c324abe30ebd801379731e6be9eb30a6e201adb099e0ba3a88063f2c7750d6de93e035e4ac8cfe0ea1b2476ce0ce6e62dc2d70795ff7996758965661537b1382
languageName: node
linkType: hard
@@ -1349,8 +1360,8 @@ __metadata:
linkType: hard
"discord.js@npm:@notenoughupdates/discord.js@dev":
- version: 14.0.0-dev.1644977562.5f1fef7
- resolution: "@notenoughupdates/discord.js@npm:14.0.0-dev.1644977562.5f1fef7"
+ version: 14.0.0-dev.1645286953.320f36c
+ resolution: "@notenoughupdates/discord.js@npm:14.0.0-dev.1645286953.320f36c"
dependencies:
"@discordjs/builders": ^0.13.0-dev
"@discordjs/collection": ^0.6.0-dev
@@ -1358,9 +1369,10 @@ __metadata:
"@sapphire/snowflake": ^3.1.0
"@types/ws": ^8.2.2
discord-api-types: ^0.27.0
+ lodash.snakecase: ^4.1.1
node-fetch: ^2.6.7
ws: ^8.5.0
- checksum: 4cf690d3410f457e142031bd4c8928552369042937d3cef2e93475fde8e6f3a765ad650b863afd5f1895fda6ba46524b33eb216967d5ef4f035f9c0de235d6d8
+ checksum: 1e1ba9c75e9c2994422fdb867d54a8ba94f04d91e060a7ee7ed7c8064d1bcb4fb178e05797cd4d99d388d306a484c7aacded69999c71b5dd58f07d716c7ddd1c
languageName: node
linkType: hard
@@ -1490,14 +1502,14 @@ __metadata:
languageName: node
linkType: hard
-"eslint-config-prettier@npm:^8.3.0":
- version: 8.3.0
- resolution: "eslint-config-prettier@npm:8.3.0"
+"eslint-config-prettier@npm:^8.4.0":
+ version: 8.4.0
+ resolution: "eslint-config-prettier@npm:8.4.0"
peerDependencies:
eslint: ">=7.0.0"
bin:
eslint-config-prettier: bin/cli.js
- checksum: df4cea3032671995bb5ab07e016169072f7fa59f44a53251664d9ca60951b66cdc872683b5c6a3729c91497c11490ca44a79654b395dd6756beb0c3903a37196
+ checksum: ee8dc343f1fed15dc0658e190a966cc23644477f2331a7f56ae2bb79dd74892e3cde8ea5c142e7a3329a8291a1de041e13ca96e54d0c85ff4a2aba13390c5f10
languageName: node
linkType: hard
@@ -2048,8 +2060,8 @@ __metadata:
linkType: hard
"google-auth-library@npm:^7.0.2":
- version: 7.12.0
- resolution: "google-auth-library@npm:7.12.0"
+ version: 7.13.0
+ resolution: "google-auth-library@npm:7.13.0"
dependencies:
arrify: ^2.0.0
base64-js: ^1.3.0
@@ -2060,7 +2072,7 @@ __metadata:
gtoken: ^5.0.4
jws: ^4.0.0
lru-cache: ^6.0.0
- checksum: 0c2970ca9b2b5672c7c217e677370f66bccd757e1e70629d9287bfee220fe9ff38e65d3e8377db2abb96a7c86142c32a93a1a817b816d0ba486af84dc1af68e4
+ checksum: aff69fb3aa3a35c605dd1049afc5c076ef6b6827db29efa1d44edf6aebc94f6d089448864650bf0a051aeb8f6d6d3576c2ce06bd421fac05bbf06c0939532c90
languageName: node
linkType: hard
@@ -2623,6 +2635,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash.snakecase@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "lodash.snakecase@npm:4.1.1"
+ checksum: 1685ed3e83dda6eae5a4dcaee161a51cd210aabb3e1c09c57150e7dd8feda19e4ca0d27d0631eabe8d0f4eaa51e376da64e8c018ae5415417c5890d42feb72a8
+ languageName: node
+ linkType: hard
+
"lodash@npm:^4.17.21":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
@@ -2907,12 +2926,12 @@ __metadata:
languageName: node
linkType: hard
-"nanoid@npm:^3.3.0":
- version: 3.3.0
- resolution: "nanoid@npm:3.3.0"
+"nanoid@npm:^3.3.1":
+ version: 3.3.1
+ resolution: "nanoid@npm:3.3.1"
bin:
nanoid: bin/nanoid.cjs
- checksum: 183d7da5c910a717a6058c7d4485d69de6f50fe3eb903830fa965430c7bbd516d70b9eb523a25cf32550bebe835a7adf080b6059808d50c9a8895fa9204e7499
+ checksum: 4ef0969e1bbe866fc223eb32276cbccb0961900bfe79104fa5abe34361979dead8d0e061410a5c03bc3d47455685adf32c09d6f27790f4a6898fb51f7df7ec86
languageName: node
linkType: hard
@@ -3565,9 +3584,9 @@ __metadata:
languageName: node
linkType: hard
-"sequelize@npm:6.16.1":
- version: 6.16.1
- resolution: "sequelize@npm:6.16.1"
+"sequelize@npm:6.16.2":
+ version: 6.16.2
+ resolution: "sequelize@npm:6.16.2"
dependencies:
"@types/debug": ^4.1.7
debug: ^4.3.3
@@ -3601,7 +3620,7 @@ __metadata:
optional: true
tedious:
optional: true
- checksum: 3103cf79279b5e8bdfaefbf239c6c6cbed40c2805ced64a85ac2f450f2f554eb89b880edc79f88d8b4257065b57e90e8e0ddd678f4ceb8e267608b9588df720f
+ checksum: 43799f8bcc9b608fe941d890bae19c62dfb028267baa5facdbed15a74ea1418c8c135d059522a5952d673b74e2399b48e95a9307d25fccf1c2a30703800174a7
languageName: node
linkType: hard
@@ -4022,15 +4041,15 @@ __metadata:
languageName: node
linkType: hard
-"vm2@npm:^3.9.7":
- version: 3.9.7
- resolution: "vm2@npm:3.9.7"
+"vm2@npm:^3.9.8":
+ version: 3.9.8
+ resolution: "vm2@npm:3.9.8"
dependencies:
acorn: ^8.7.0
acorn-walk: ^8.2.0
bin:
vm2: bin/vm2
- checksum: d85dc2ea3219daed7b9ad6d3bd17e405c60155cf162d977e28d8e12f237a95d8ed2d9ad34df2c89bab40a738cc717e3f83feb206df0c1a4964d891b1e39dbd54
+ checksum: 1e665a45ce76612922368462a8b98876698e866c1f201393b0b646f07a00449dc4170e987152cf1443af664ca8f2b82bb52a0760456a71912fa63f22980de7b4
languageName: node
linkType: hard