@erinjs/core 1.0.0 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{core/LICENSE → LICENSE} +203 -203
- package/README.md +46 -0
- package/dist/index.d.mts +2084 -0
- package/dist/index.d.ts +2084 -0
- package/dist/index.js +3867 -0
- package/dist/index.mjs +3809 -0
- package/package.json +50 -15
- package/core/.changeset/README.md +0 -8
- package/core/.changeset/community-bootstrap-release.md +0 -17
- package/core/.changeset/config.json +0 -11
- package/core/.changeset/no-changelog.js +0 -16
- package/core/.changeset/pre.json +0 -17
- package/core/.editorconfig +0 -13
- package/core/.gitattributes +0 -2
- package/core/.github/CODE_OF_CONDUCT.md +0 -23
- package/core/.github/FUNDING.yml +0 -7
- package/core/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
- package/core/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
- package/core/.github/PULL_REQUEST_TEMPLATE.md +0 -16
- package/core/.github/dependabot.yml +0 -16
- package/core/.github/workflows/autoapp.yml +0 -16
- package/core/.github/workflows/ci.yml +0 -187
- package/core/.github/workflows/codeql.yml +0 -30
- package/core/.github/workflows/deploy-docs.yml +0 -54
- package/core/.github/workflows/publish.yml +0 -43
- package/core/.lintstagedrc.json +0 -4
- package/core/.nvmrc +0 -1
- package/core/.prettierignore +0 -8
- package/core/.prettierrc +0 -11
- package/core/CONTRIBUTING.md +0 -70
- package/core/README.md +0 -61
- package/core/SECURITY.md +0 -21
- package/core/apps/docs/index.html +0 -28
- package/core/apps/docs/middleware.ts +0 -21
- package/core/apps/docs/package.json +0 -33
- package/core/apps/docs/public/@flux.png +0 -0
- package/core/apps/docs/public/docs/latest/guides.json +0 -1420
- package/core/apps/docs/public/docs/latest/main.json +0 -14981
- package/core/apps/docs/public/docs/latest/rag-index.json +0 -1
- package/core/apps/docs/public/docs/v1.0.5/guides.json +0 -226
- package/core/apps/docs/public/docs/v1.0.5/main.json +0 -7920
- package/core/apps/docs/public/docs/v1.0.6/guides.json +0 -226
- package/core/apps/docs/public/docs/v1.0.6/main.json +0 -7920
- package/core/apps/docs/public/docs/v1.0.7/guides.json +0 -259
- package/core/apps/docs/public/docs/v1.0.7/main.json +0 -8652
- package/core/apps/docs/public/docs/v1.0.8/guides.json +0 -313
- package/core/apps/docs/public/docs/v1.0.8/main.json +0 -9618
- package/core/apps/docs/public/docs/v1.0.9/guides.json +0 -319
- package/core/apps/docs/public/docs/v1.0.9/main.json +0 -10694
- package/core/apps/docs/public/docs/v1.1.0/guides.json +0 -589
- package/core/apps/docs/public/docs/v1.1.0/main.json +0 -12576
- package/core/apps/docs/public/docs/v1.1.2/guides.json +0 -650
- package/core/apps/docs/public/docs/v1.1.2/main.json +0 -13239
- package/core/apps/docs/public/docs/v1.1.3/guides.json +0 -650
- package/core/apps/docs/public/docs/v1.1.3/main.json +0 -13239
- package/core/apps/docs/public/docs/v1.1.4/guides.json +0 -708
- package/core/apps/docs/public/docs/v1.1.4/main.json +0 -13231
- package/core/apps/docs/public/docs/v1.1.5/guides.json +0 -1035
- package/core/apps/docs/public/docs/v1.1.5/main.json +0 -13838
- package/core/apps/docs/public/docs/v1.1.6/guides.json +0 -1041
- package/core/apps/docs/public/docs/v1.1.6/main.json +0 -14313
- package/core/apps/docs/public/docs/v1.1.8/guides.json +0 -1047
- package/core/apps/docs/public/docs/v1.1.8/main.json +0 -14421
- package/core/apps/docs/public/docs/v1.1.9/guides.json +0 -1047
- package/core/apps/docs/public/docs/v1.1.9/main.json +0 -14421
- package/core/apps/docs/public/docs/v1.2.0/guides.json +0 -1212
- package/core/apps/docs/public/docs/v1.2.0/main.json +0 -14663
- package/core/apps/docs/public/docs/v1.2.1/guides.json +0 -1293
- package/core/apps/docs/public/docs/v1.2.1/main.json +0 -14828
- package/core/apps/docs/public/docs/v1.2.2/guides.json +0 -1293
- package/core/apps/docs/public/docs/v1.2.2/main.json +0 -15025
- package/core/apps/docs/public/docs/v1.2.3/guides.json +0 -1420
- package/core/apps/docs/public/docs/v1.2.3/main.json +0 -14954
- package/core/apps/docs/public/docs/v1.2.4/guides.json +0 -1420
- package/core/apps/docs/public/docs/v1.2.4/main.json +0 -14981
- package/core/apps/docs/public/docs/versions.json +0 -24
- package/core/apps/docs/public/flux.png +0 -0
- package/core/apps/docs/public/locales/en.json +0 -50
- package/core/apps/docs/public/locales/guides-en.json +0 -512
- package/core/apps/docs/public/robots.txt +0 -4
- package/core/apps/docs/public/sitemap.xml +0 -33
- package/core/apps/docs/src/App.vue +0 -538
- package/core/apps/docs/src/components/ApiCategorySection.vue +0 -42
- package/core/apps/docs/src/components/ApiDiscordCompat.vue +0 -65
- package/core/apps/docs/src/components/ApiEndpointCard.vue +0 -313
- package/core/apps/docs/src/components/ApiSchemaBlock.vue +0 -131
- package/core/apps/docs/src/components/CodeBlock.vue +0 -177
- package/core/apps/docs/src/components/CommunityCallout.vue +0 -90
- package/core/apps/docs/src/components/ConstructorSection.vue +0 -82
- package/core/apps/docs/src/components/DocDescription.vue +0 -40
- package/core/apps/docs/src/components/FluxerLogo.vue +0 -3
- package/core/apps/docs/src/components/Footer.vue +0 -106
- package/core/apps/docs/src/components/GuideCodeBlock.vue +0 -102
- package/core/apps/docs/src/components/GuideDiscordCompat.vue +0 -77
- package/core/apps/docs/src/components/GuideDiscordCompatCallout.vue +0 -83
- package/core/apps/docs/src/components/GuideTable.vue +0 -77
- package/core/apps/docs/src/components/GuideTip.vue +0 -38
- package/core/apps/docs/src/components/MethodsSection.vue +0 -195
- package/core/apps/docs/src/components/ParamsTable.vue +0 -70
- package/core/apps/docs/src/components/PropertiesSection.vue +0 -143
- package/core/apps/docs/src/components/SearchBar.vue +0 -76
- package/core/apps/docs/src/components/SearchModal.vue +0 -361
- package/core/apps/docs/src/components/SidebarNav.vue +0 -225
- package/core/apps/docs/src/components/SponsorBanner.vue +0 -153
- package/core/apps/docs/src/components/TypeSignature.vue +0 -187
- package/core/apps/docs/src/components/VersionPicker.vue +0 -191
- package/core/apps/docs/src/composables/useSearchIndex.ts +0 -144
- package/core/apps/docs/src/composables/useVersionedPath.ts +0 -20
- package/core/apps/docs/src/data/apiEndpoints.ts +0 -1073
- package/core/apps/docs/src/data/changelog.ts +0 -717
- package/core/apps/docs/src/data/guides.ts +0 -2362
- package/core/apps/docs/src/env.d.ts +0 -7
- package/core/apps/docs/src/locales/guides-en.json +0 -512
- package/core/apps/docs/src/main.ts +0 -27
- package/core/apps/docs/src/pages/ApiReferenceLayout.vue +0 -175
- package/core/apps/docs/src/pages/ApiReferencePage.vue +0 -128
- package/core/apps/docs/src/pages/Changelog.vue +0 -288
- package/core/apps/docs/src/pages/ClassPage.vue +0 -319
- package/core/apps/docs/src/pages/ClassesList.vue +0 -100
- package/core/apps/docs/src/pages/DocsLayout.vue +0 -127
- package/core/apps/docs/src/pages/GuidePage.vue +0 -279
- package/core/apps/docs/src/pages/GuidesIndex.vue +0 -166
- package/core/apps/docs/src/pages/GuidesLayout.vue +0 -245
- package/core/apps/docs/src/pages/Home.vue +0 -125
- package/core/apps/docs/src/pages/NotFound.vue +0 -57
- package/core/apps/docs/src/pages/TypedefPage.vue +0 -230
- package/core/apps/docs/src/pages/TypedefsList.vue +0 -168
- package/core/apps/docs/src/pages/VersionLayout.vue +0 -15
- package/core/apps/docs/src/router.ts +0 -73
- package/core/apps/docs/src/stores/docs.ts +0 -54
- package/core/apps/docs/src/stores/guides.ts +0 -53
- package/core/apps/docs/src/stores/version.ts +0 -67
- package/core/apps/docs/src/styles/main.css +0 -278
- package/core/apps/docs/src/styles/prism.css +0 -95
- package/core/apps/docs/src/types/doc-schema.ts +0 -112
- package/core/apps/docs/tsconfig.json +0 -17
- package/core/apps/docs/tsconfig.node.json +0 -10
- package/core/apps/docs/vite.config.d.ts +0 -2
- package/core/apps/docs/vite.config.js +0 -26
- package/core/apps/docs/vite.config.ts +0 -28
- package/core/apps/docs-vitepress/.vitepress/config.ts +0 -141
- package/core/apps/docs-vitepress/api-data/latest/main.json +0 -15035
- package/core/apps/docs-vitepress/api-data/v1.2.4/main.json +0 -15035
- package/core/apps/docs-vitepress/api-data/versions.json +0 -6
- package/core/apps/docs-vitepress/index.md +0 -15
- package/core/apps/docs-vitepress/package-lock.json +0 -2924
- package/core/apps/docs-vitepress/package.json +0 -20
- package/core/apps/docs-vitepress/public/CNAME +0 -1
- package/core/apps/docs-vitepress/scripts/generate-api.ts +0 -243
- package/core/apps/docs-vitepress/scripts/migrate-guides.ts +0 -129
- package/core/apps/docs-vitepress/tsconfig.json +0 -11
- package/core/apps/docs-vitepress/v/latest/guides/attachments-by-url.md +0 -57
- package/core/apps/docs-vitepress/v/latest/guides/attachments.md +0 -62
- package/core/apps/docs-vitepress/v/latest/guides/basic-bot.md +0 -49
- package/core/apps/docs-vitepress/v/latest/guides/channels.md +0 -180
- package/core/apps/docs-vitepress/v/latest/guides/deprecated-apis.md +0 -58
- package/core/apps/docs-vitepress/v/latest/guides/discord-js-compatibility.md +0 -42
- package/core/apps/docs-vitepress/v/latest/guides/editing-embeds.md +0 -65
- package/core/apps/docs-vitepress/v/latest/guides/embed-media.md +0 -87
- package/core/apps/docs-vitepress/v/latest/guides/embeds.md +0 -166
- package/core/apps/docs-vitepress/v/latest/guides/emojis.md +0 -77
- package/core/apps/docs-vitepress/v/latest/guides/events.md +0 -202
- package/core/apps/docs-vitepress/v/latest/guides/gifs.md +0 -47
- package/core/apps/docs-vitepress/v/latest/guides/installation.md +0 -10
- package/core/apps/docs-vitepress/v/latest/guides/moderation.md +0 -89
- package/core/apps/docs-vitepress/v/latest/guides/permissions.md +0 -130
- package/core/apps/docs-vitepress/v/latest/guides/prefix-commands.md +0 -41
- package/core/apps/docs-vitepress/v/latest/guides/profile-urls.md +0 -58
- package/core/apps/docs-vitepress/v/latest/guides/reactions.md +0 -69
- package/core/apps/docs-vitepress/v/latest/guides/roles.md +0 -130
- package/core/apps/docs-vitepress/v/latest/guides/sending-without-reply.md +0 -172
- package/core/apps/docs-vitepress/v/latest/guides/voice.md +0 -109
- package/core/apps/docs-vitepress/v/latest/guides/wait-for-guilds.md +0 -37
- package/core/apps/docs-vitepress/v/latest/guides/webhook-attachments-embeds.md +0 -73
- package/core/apps/docs-vitepress/v/latest/guides/webhooks.md +0 -131
- package/core/eslint.config.js +0 -80
- package/core/examples/.env.example +0 -22
- package/core/examples/README.md +0 -68
- package/core/examples/first-steps-bot.js +0 -118
- package/core/examples/minimal-bot.js +0 -17
- package/core/examples/moderation-bot.js +0 -209
- package/core/examples/package.json +0 -14
- package/core/examples/ping-bot.js +0 -1146
- package/core/examples/reaction-bot.js +0 -70
- package/core/examples/reaction-roles-bot.js +0 -140
- package/core/examples/webhook-bot.js +0 -239
- package/core/flux.png +0 -0
- package/core/package.json +0 -78
- package/core/packages/builders/package.json +0 -51
- package/core/packages/builders/src/index.ts +0 -13
- package/core/packages/builders/src/messages/AttachmentBuilder.test.ts +0 -79
- package/core/packages/builders/src/messages/AttachmentBuilder.ts +0 -69
- package/core/packages/builders/src/messages/EmbedBuilder.test.ts +0 -266
- package/core/packages/builders/src/messages/EmbedBuilder.ts +0 -239
- package/core/packages/builders/src/messages/MessagePayload.test.ts +0 -118
- package/core/packages/builders/src/messages/MessagePayload.ts +0 -122
- package/core/packages/builders/tsconfig.json +0 -9
- package/core/packages/builders/tsup.config.ts +0 -9
- package/core/packages/builders/vitest.config.ts +0 -9
- package/core/packages/collection/package.json +0 -47
- package/core/packages/collection/src/Collection.test.ts +0 -232
- package/core/packages/collection/src/Collection.ts +0 -196
- package/core/packages/collection/src/index.ts +0 -1
- package/core/packages/collection/tsconfig.json +0 -9
- package/core/packages/collection/tsup.config.ts +0 -9
- package/core/packages/collection/vitest.config.ts +0 -9
- package/core/packages/docgen/package.json +0 -26
- package/core/packages/docgen/src/extract.ts +0 -262
- package/core/packages/docgen/src/formatType.ts +0 -24
- package/core/packages/docgen/src/index.ts +0 -103
- package/core/packages/docgen/src/schema.ts +0 -100
- package/core/packages/docgen/src/visitor.ts +0 -147
- package/core/packages/docgen/tsconfig.json +0 -9
- package/core/packages/docgen/tsup.config.ts +0 -9
- package/core/packages/fluxer-core/README.md +0 -26
- package/core/packages/fluxer-core/package.json +0 -60
- package/core/packages/fluxer-core/src/client/ChannelManager.ts +0 -143
- package/core/packages/fluxer-core/src/client/Client.gateway.test.ts +0 -84
- package/core/packages/fluxer-core/src/client/Client.resolveEmoji.test.ts +0 -45
- package/core/packages/fluxer-core/src/client/Client.ts +0 -558
- package/core/packages/fluxer-core/src/client/ClientUser.ts +0 -40
- package/core/packages/fluxer-core/src/client/EventHandlerRegistry.ts +0 -469
- package/core/packages/fluxer-core/src/client/GuildManager.ts +0 -79
- package/core/packages/fluxer-core/src/client/GuildMemberManager.ts +0 -91
- package/core/packages/fluxer-core/src/client/MessageManager.ts +0 -58
- package/core/packages/fluxer-core/src/client/UsersManager.ts +0 -122
- package/core/packages/fluxer-core/src/errors/ErrorCodes.test.ts +0 -19
- package/core/packages/fluxer-core/src/errors/ErrorCodes.ts +0 -12
- package/core/packages/fluxer-core/src/errors/FluxerError.test.ts +0 -32
- package/core/packages/fluxer-core/src/errors/FluxerError.ts +0 -15
- package/core/packages/fluxer-core/src/index.ts +0 -85
- package/core/packages/fluxer-core/src/structures/Base.ts +0 -7
- package/core/packages/fluxer-core/src/structures/Channel.ts +0 -508
- package/core/packages/fluxer-core/src/structures/Guild.test.ts +0 -189
- package/core/packages/fluxer-core/src/structures/Guild.ts +0 -734
- package/core/packages/fluxer-core/src/structures/GuildBan.ts +0 -35
- package/core/packages/fluxer-core/src/structures/GuildEmoji.ts +0 -57
- package/core/packages/fluxer-core/src/structures/GuildMember.test.ts +0 -203
- package/core/packages/fluxer-core/src/structures/GuildMember.ts +0 -213
- package/core/packages/fluxer-core/src/structures/GuildMemberRoleManager.ts +0 -121
- package/core/packages/fluxer-core/src/structures/GuildSticker.ts +0 -56
- package/core/packages/fluxer-core/src/structures/Invite.test.ts +0 -103
- package/core/packages/fluxer-core/src/structures/Invite.ts +0 -121
- package/core/packages/fluxer-core/src/structures/Message.test.ts +0 -109
- package/core/packages/fluxer-core/src/structures/Message.ts +0 -397
- package/core/packages/fluxer-core/src/structures/MessageReaction.ts +0 -72
- package/core/packages/fluxer-core/src/structures/PartialMessage.ts +0 -12
- package/core/packages/fluxer-core/src/structures/Role.test.ts +0 -77
- package/core/packages/fluxer-core/src/structures/Role.ts +0 -112
- package/core/packages/fluxer-core/src/structures/User.test.ts +0 -110
- package/core/packages/fluxer-core/src/structures/User.ts +0 -109
- package/core/packages/fluxer-core/src/structures/Webhook.test.ts +0 -109
- package/core/packages/fluxer-core/src/structures/Webhook.ts +0 -258
- package/core/packages/fluxer-core/src/util/Constants.test.ts +0 -16
- package/core/packages/fluxer-core/src/util/Constants.ts +0 -7
- package/core/packages/fluxer-core/src/util/Events.ts +0 -46
- package/core/packages/fluxer-core/src/util/MessageCollector.ts +0 -87
- package/core/packages/fluxer-core/src/util/Options.ts +0 -33
- package/core/packages/fluxer-core/src/util/ReactionCollector.ts +0 -116
- package/core/packages/fluxer-core/src/util/cdn.test.ts +0 -108
- package/core/packages/fluxer-core/src/util/cdn.ts +0 -130
- package/core/packages/fluxer-core/src/util/guildUtils.ts +0 -33
- package/core/packages/fluxer-core/src/util/messageUtils.test.ts +0 -74
- package/core/packages/fluxer-core/src/util/messageUtils.ts +0 -119
- package/core/packages/fluxer-core/src/util/permissions.test.ts +0 -95
- package/core/packages/fluxer-core/src/util/permissions.ts +0 -43
- package/core/packages/fluxer-core/tsconfig.json +0 -9
- package/core/packages/fluxer-core/tsup.config.ts +0 -9
- package/core/packages/fluxer-core/vitest.config.ts +0 -9
- package/core/packages/rest/package.json +0 -52
- package/core/packages/rest/src/REST.test.ts +0 -64
- package/core/packages/rest/src/REST.ts +0 -90
- package/core/packages/rest/src/RateLimitManager.test.ts +0 -71
- package/core/packages/rest/src/RateLimitManager.ts +0 -60
- package/core/packages/rest/src/RequestManager.test.ts +0 -87
- package/core/packages/rest/src/RequestManager.ts +0 -172
- package/core/packages/rest/src/errors/FluxerAPIError.test.ts +0 -57
- package/core/packages/rest/src/errors/FluxerAPIError.ts +0 -21
- package/core/packages/rest/src/errors/HTTPError.test.ts +0 -55
- package/core/packages/rest/src/errors/HTTPError.ts +0 -25
- package/core/packages/rest/src/errors/RateLimitError.test.ts +0 -41
- package/core/packages/rest/src/errors/RateLimitError.ts +0 -15
- package/core/packages/rest/src/errors/index.ts +0 -3
- package/core/packages/rest/src/index.ts +0 -6
- package/core/packages/rest/src/utils/constants.test.ts +0 -31
- package/core/packages/rest/src/utils/constants.ts +0 -5
- package/core/packages/rest/src/utils/files.test.ts +0 -37
- package/core/packages/rest/src/utils/files.ts +0 -75
- package/core/packages/rest/tsconfig.json +0 -9
- package/core/packages/rest/tsup.config.ts +0 -9
- package/core/packages/rest/vitest.config.ts +0 -9
- package/core/packages/types/package.json +0 -46
- package/core/packages/types/src/api/ban.ts +0 -8
- package/core/packages/types/src/api/channel.ts +0 -65
- package/core/packages/types/src/api/embed.ts +0 -82
- package/core/packages/types/src/api/emoji.ts +0 -12
- package/core/packages/types/src/api/errors.ts +0 -68
- package/core/packages/types/src/api/gateway.ts +0 -14
- package/core/packages/types/src/api/guild.ts +0 -123
- package/core/packages/types/src/api/index.ts +0 -15
- package/core/packages/types/src/api/instance.ts +0 -32
- package/core/packages/types/src/api/interaction.ts +0 -26
- package/core/packages/types/src/api/invite.ts +0 -28
- package/core/packages/types/src/api/message.ts +0 -140
- package/core/packages/types/src/api/role.ts +0 -41
- package/core/packages/types/src/api/sticker.ts +0 -14
- package/core/packages/types/src/api/user.ts +0 -79
- package/core/packages/types/src/api/webhook.ts +0 -41
- package/core/packages/types/src/common/index.ts +0 -1
- package/core/packages/types/src/common/snowflake.test.ts +0 -9
- package/core/packages/types/src/common/snowflake.ts +0 -8
- package/core/packages/types/src/gateway/events.ts +0 -189
- package/core/packages/types/src/gateway/index.ts +0 -3
- package/core/packages/types/src/gateway/opcodes.ts +0 -17
- package/core/packages/types/src/gateway/payloads.ts +0 -481
- package/core/packages/types/src/index.ts +0 -4
- package/core/packages/types/src/rest/index.ts +0 -1
- package/core/packages/types/src/rest/routes.test.ts +0 -169
- package/core/packages/types/src/rest/routes.ts +0 -109
- package/core/packages/types/tsconfig.json +0 -9
- package/core/packages/types/tsup.config.ts +0 -9
- package/core/packages/types/vitest.config.ts +0 -9
- package/core/packages/util/package.json +0 -51
- package/core/packages/util/src/BitField.test.ts +0 -96
- package/core/packages/util/src/BitField.ts +0 -105
- package/core/packages/util/src/MessageFlagsBitField.test.ts +0 -42
- package/core/packages/util/src/MessageFlagsBitField.ts +0 -20
- package/core/packages/util/src/PermissionsBitField.test.ts +0 -79
- package/core/packages/util/src/PermissionsBitField.ts +0 -97
- package/core/packages/util/src/SnowflakeUtil.test.ts +0 -69
- package/core/packages/util/src/SnowflakeUtil.ts +0 -65
- package/core/packages/util/src/UserFlagsBitField.test.ts +0 -39
- package/core/packages/util/src/UserFlagsBitField.ts +0 -48
- package/core/packages/util/src/deprecation.test.ts +0 -44
- package/core/packages/util/src/deprecation.ts +0 -28
- package/core/packages/util/src/emojiShortcodes.generated.ts +0 -5
- package/core/packages/util/src/emojiShortcodes.test.ts +0 -41
- package/core/packages/util/src/emojiShortcodes.ts +0 -22
- package/core/packages/util/src/formatters.test.ts +0 -65
- package/core/packages/util/src/formatters.ts +0 -35
- package/core/packages/util/src/index.ts +0 -34
- package/core/packages/util/src/resolvers.test.ts +0 -198
- package/core/packages/util/src/resolvers.ts +0 -127
- package/core/packages/util/src/tenorUtils.test.ts +0 -75
- package/core/packages/util/src/tenorUtils.ts +0 -86
- package/core/packages/util/tsconfig.json +0 -9
- package/core/packages/util/tsup.config.ts +0 -9
- package/core/packages/util/vitest.config.ts +0 -9
- package/core/packages/voice/README.md +0 -42
- package/core/packages/voice/package.json +0 -67
- package/core/packages/voice/src/LiveKitRtcConnection.receive.test.ts +0 -24
- package/core/packages/voice/src/LiveKitRtcConnection.ts +0 -1767
- package/core/packages/voice/src/VoiceConnection.ts +0 -413
- package/core/packages/voice/src/VoiceManager.receive.test.ts +0 -61
- package/core/packages/voice/src/VoiceManager.test.ts +0 -44
- package/core/packages/voice/src/VoiceManager.ts +0 -503
- package/core/packages/voice/src/exports.test.ts +0 -38
- package/core/packages/voice/src/index.ts +0 -51
- package/core/packages/voice/src/livekit.test.ts +0 -48
- package/core/packages/voice/src/livekit.ts +0 -33
- package/core/packages/voice/src/mp4box.d.ts +0 -32
- package/core/packages/voice/src/opusUtils.test.ts +0 -29
- package/core/packages/voice/src/opusUtils.ts +0 -86
- package/core/packages/voice/src/streamPreviewPlaceholder.test.ts +0 -16
- package/core/packages/voice/src/streamPreviewPlaceholder.ts +0 -8
- package/core/packages/voice/src/ws.d.ts +0 -1
- package/core/packages/voice/tsconfig.json +0 -5
- package/core/packages/voice/tsup.config.ts +0 -10
- package/core/packages/voice/vitest.config.ts +0 -9
- package/core/packages/ws/package.json +0 -52
- package/core/packages/ws/src/WebSocketManager.ts +0 -130
- package/core/packages/ws/src/WebSocketShard.ts +0 -296
- package/core/packages/ws/src/index.ts +0 -12
- package/core/packages/ws/src/utils/constants.test.ts +0 -46
- package/core/packages/ws/src/utils/constants.ts +0 -22
- package/core/packages/ws/src/utils/getWebSocket.ts +0 -55
- package/core/packages/ws/src/ws.d.ts +0 -10
- package/core/packages/ws/tsconfig.json +0 -9
- package/core/packages/ws/tsup.config.ts +0 -9
- package/core/pnpm-lock.yaml +0 -7033
- package/core/pnpm-workspace.yaml +0 -4
- package/core/scripts/generate-ai-rag.ts +0 -240
- package/core/scripts/generate-docs.ts +0 -143
- package/core/scripts/generate-emoji-shortcodes.ts +0 -58
- package/core/scripts/generate-types.ts +0 -6
- package/core/scripts/publish-ordered.js +0 -63
- package/core/scripts/test-cjs-require.mjs +0 -43
- package/core/scripts/test-esm-imports.mjs +0 -42
- package/core/scripts/test-package-exports.mjs +0 -98
- package/core/scripts/test-smoke.mjs +0 -103
- package/core/tsconfig.json +0 -18
- package/core/turbo.json +0 -30
- package/core/vitest.config.ts +0 -17
- package/core/wrangler.jsonc +0 -9
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { getUnicodeFromShortcode, UNICODE_EMOJI_SHORTCODES } from './emojiShortcodes.js';
|
|
3
|
-
|
|
4
|
-
describe('getUnicodeFromShortcode', () => {
|
|
5
|
-
it('resolves :heart: to unicode', () => {
|
|
6
|
-
const r = getUnicodeFromShortcode('heart');
|
|
7
|
-
expect(r).toBeDefined();
|
|
8
|
-
expect(typeof r).toBe('string');
|
|
9
|
-
expect(r!.length).toBeGreaterThan(0);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('is case-insensitive', () => {
|
|
13
|
-
const a = getUnicodeFromShortcode('heart');
|
|
14
|
-
const b = getUnicodeFromShortcode('HEART');
|
|
15
|
-
const c = getUnicodeFromShortcode('Heart');
|
|
16
|
-
expect(a).toBe(b);
|
|
17
|
-
expect(b).toBe(c);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('trims whitespace', () => {
|
|
21
|
-
const r = getUnicodeFromShortcode(' heart ');
|
|
22
|
-
expect(r).toBe(UNICODE_EMOJI_SHORTCODES['heart']);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('returns undefined for empty or invalid', () => {
|
|
26
|
-
expect(getUnicodeFromShortcode('')).toBeUndefined();
|
|
27
|
-
expect(getUnicodeFromShortcode(' ')).toBeUndefined();
|
|
28
|
-
expect(getUnicodeFromShortcode('nonexistent_emoji_xyz')).toBeUndefined();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('returns undefined for null/undefined input', () => {
|
|
32
|
-
expect(getUnicodeFromShortcode(null as unknown as string)).toBeUndefined();
|
|
33
|
-
expect(getUnicodeFromShortcode(undefined as unknown as string)).toBeUndefined();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('resolves common shortcodes', () => {
|
|
37
|
-
expect(getUnicodeFromShortcode('thumbsup')).toBeDefined();
|
|
38
|
-
expect(getUnicodeFromShortcode('smile')).toBeDefined();
|
|
39
|
-
expect(getUnicodeFromShortcode('fire')).toBeDefined();
|
|
40
|
-
});
|
|
41
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Maps Unicode emoji shortcodes (:name:) to their Unicode characters.
|
|
3
|
-
* Used to resolve shortcodes like :arrow_backward: and :flag_ad: for message.react()
|
|
4
|
-
* without requiring guild context. Custom emojis use guild lookup; known Unicode shortcodes
|
|
5
|
-
* resolve here so they work in DMs and guild channels alike.
|
|
6
|
-
*
|
|
7
|
-
* Data is generated from Discord's emoji data (anyascii/discord-emojis).
|
|
8
|
-
* Run: pnpm exec tsx scripts/generate-emoji-shortcodes.ts
|
|
9
|
-
*/
|
|
10
|
-
import { UNICODE_EMOJI_SHORTCODES as SHORTCODES } from './emojiShortcodes.generated.js';
|
|
11
|
-
|
|
12
|
-
export const UNICODE_EMOJI_SHORTCODES = SHORTCODES;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Get the Unicode character for a known shortcode name.
|
|
16
|
-
* Case-insensitive. Returns undefined if the shortcode is not in the map.
|
|
17
|
-
*/
|
|
18
|
-
export function getUnicodeFromShortcode(name: string): string | undefined {
|
|
19
|
-
if (!name || typeof name !== 'string') return undefined;
|
|
20
|
-
const key = name.toLowerCase().trim();
|
|
21
|
-
return UNICODE_EMOJI_SHORTCODES[key];
|
|
22
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { formatColor, escapeMarkdown, formatTimestamp, truncate } from './formatters.js';
|
|
3
|
-
|
|
4
|
-
describe('formatColor', () => {
|
|
5
|
-
it('formats color as hex', () => {
|
|
6
|
-
expect(formatColor(0xff0000)).toBe('#ff0000');
|
|
7
|
-
expect(formatColor(0)).toBe('#000000');
|
|
8
|
-
expect(formatColor(0xffffff)).toBe('#ffffff');
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
describe('escapeMarkdown', () => {
|
|
13
|
-
it('escapes markdown characters', () => {
|
|
14
|
-
expect(escapeMarkdown('*bold*')).toBe('\\*bold\\*');
|
|
15
|
-
expect(escapeMarkdown('_italic_')).toBe('\\_italic\\_');
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
describe('formatTimestamp', () => {
|
|
20
|
-
it('formats timestamp', () => {
|
|
21
|
-
const ts = 1609459200000; // 2021-01-01 00:00:00 UTC
|
|
22
|
-
expect(formatTimestamp(ts)).toBe('<t:1609459200>');
|
|
23
|
-
expect(formatTimestamp(ts, 'R')).toBe('<t:1609459200:R>');
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('truncate', () => {
|
|
28
|
-
it('returns unchanged if under limit', () => {
|
|
29
|
-
expect(truncate('hello', 10)).toBe('hello');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('truncates with suffix', () => {
|
|
33
|
-
expect(truncate('hello world', 8)).toBe('hello...');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('uses custom suffix', () => {
|
|
37
|
-
expect(truncate('hello world', 9, '..')).toBe('hello w..');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('handles exact length', () => {
|
|
41
|
-
expect(truncate('hello', 5)).toBe('hello');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('handles length smaller than suffix', () => {
|
|
45
|
-
expect(truncate('hi', 1, '...')).toBe('...');
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe('escapeMarkdown edge cases', () => {
|
|
50
|
-
it('escapes backtick', () => {
|
|
51
|
-
expect(escapeMarkdown('`code`')).toBe('\\`code\\`');
|
|
52
|
-
});
|
|
53
|
-
it('escapes pipe', () => {
|
|
54
|
-
expect(escapeMarkdown('a|b')).toBe('a\\|b');
|
|
55
|
-
});
|
|
56
|
-
it('escapes tilde', () => {
|
|
57
|
-
expect(escapeMarkdown('~strikethrough~')).toBe('\\~strikethrough\\~');
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe('formatColor edge cases', () => {
|
|
62
|
-
it('pads short hex', () => {
|
|
63
|
-
expect(formatColor(0x000001)).toBe('#000001');
|
|
64
|
-
});
|
|
65
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Format a number as a hex color string.
|
|
3
|
-
*/
|
|
4
|
-
export function formatColor(color: number): string {
|
|
5
|
-
const hex = color.toString(16).padStart(6, '0');
|
|
6
|
-
return `#${hex}`;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Escape markdown formatting characters in a string.
|
|
11
|
-
*/
|
|
12
|
-
export function escapeMarkdown(text: string): string {
|
|
13
|
-
return text.replace(/([\\*_`~|])/g, '\\$1');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Format a Unix timestamp for Fluxer/Discord style timestamps.
|
|
18
|
-
* @param timestamp - Unix timestamp in seconds
|
|
19
|
-
* @param style - t, T, d, D, f, F, R, etc.
|
|
20
|
-
*/
|
|
21
|
-
export function formatTimestamp(
|
|
22
|
-
timestamp: number,
|
|
23
|
-
style?: 't' | 'T' | 'd' | 'D' | 'f' | 'F' | 'R',
|
|
24
|
-
): string {
|
|
25
|
-
const suffix = style ? `:${style}` : '';
|
|
26
|
-
return `<t:${Math.floor(timestamp / 1000)}${suffix}>`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Truncate a string to a maximum length with an optional suffix.
|
|
31
|
-
*/
|
|
32
|
-
export function truncate(str: string, maxLength: number, suffix = '...'): string {
|
|
33
|
-
if (str.length <= maxLength) return str;
|
|
34
|
-
return str.slice(0, maxLength - suffix.length) + suffix;
|
|
35
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export { BitField, type BitFieldResolvable } from './BitField.js';
|
|
2
|
-
export { SnowflakeUtil, FLUXER_EPOCH } from './SnowflakeUtil.js';
|
|
3
|
-
export {
|
|
4
|
-
PermissionsBitField,
|
|
5
|
-
PermissionFlags,
|
|
6
|
-
ALL_PERMISSIONS_BIGINT,
|
|
7
|
-
resolvePermissionsToBitfield,
|
|
8
|
-
type PermissionString,
|
|
9
|
-
type PermissionResolvable,
|
|
10
|
-
} from './PermissionsBitField.js';
|
|
11
|
-
export {
|
|
12
|
-
MessageFlagsBitField,
|
|
13
|
-
MessageFlagsBits,
|
|
14
|
-
type MessageFlagsString,
|
|
15
|
-
type MessageFlagsResolvable,
|
|
16
|
-
} from './MessageFlagsBitField.js';
|
|
17
|
-
export {
|
|
18
|
-
UserFlagsBitField,
|
|
19
|
-
UserFlagsBits,
|
|
20
|
-
type UserFlagsString,
|
|
21
|
-
type UserFlagsResolvable,
|
|
22
|
-
} from './UserFlagsBitField.js';
|
|
23
|
-
export { formatColor, escapeMarkdown, formatTimestamp, truncate } from './formatters.js';
|
|
24
|
-
export {
|
|
25
|
-
resolveColor,
|
|
26
|
-
parseEmoji,
|
|
27
|
-
formatEmoji,
|
|
28
|
-
parseUserMention,
|
|
29
|
-
parseRoleMention,
|
|
30
|
-
parsePrefixCommand,
|
|
31
|
-
} from './resolvers.js';
|
|
32
|
-
export { getUnicodeFromShortcode } from './emojiShortcodes.js';
|
|
33
|
-
export { resolveTenorToImageUrl, type TenorMediaResult } from './tenorUtils.js';
|
|
34
|
-
export { emitDeprecationWarning } from './deprecation.js';
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
parseEmoji,
|
|
4
|
-
formatEmoji,
|
|
5
|
-
parseUserMention,
|
|
6
|
-
parseRoleMention,
|
|
7
|
-
parsePrefixCommand,
|
|
8
|
-
resolveColor,
|
|
9
|
-
} from './resolvers.js';
|
|
10
|
-
|
|
11
|
-
describe('parseEmoji', () => {
|
|
12
|
-
it('returns null for null/undefined/non-string', () => {
|
|
13
|
-
expect(parseEmoji(null as unknown as string)).toBeNull();
|
|
14
|
-
expect(parseEmoji(undefined as unknown as string)).toBeNull();
|
|
15
|
-
expect(parseEmoji(123 as unknown as string)).toBeNull();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('returns null for empty or whitespace-only string', () => {
|
|
19
|
-
expect(parseEmoji('')).toBeNull();
|
|
20
|
-
expect(parseEmoji(' ')).toBeNull();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('parses <:name:id> mention format', () => {
|
|
24
|
-
const r = parseEmoji('<:custom:123456789012345678>');
|
|
25
|
-
expect(r).toEqual({ id: '123456789012345678', name: 'custom', animated: false });
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('parses <a:name:id> animated mention format', () => {
|
|
29
|
-
const r = parseEmoji('<a:wiggle:987654321098765432>');
|
|
30
|
-
expect(r).toEqual({ id: '987654321098765432', name: 'wiggle', animated: true });
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('parses name:id API format', () => {
|
|
34
|
-
const r = parseEmoji('CustomEmoji:123456789012345678');
|
|
35
|
-
expect(r).toEqual({ id: '123456789012345678', name: 'CustomEmoji' });
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('parses :name: shortcode format (unicode or guild lookup)', () => {
|
|
39
|
-
const r = parseEmoji(':heart:');
|
|
40
|
-
expect(r).toEqual({ id: null, name: 'heart' });
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('parses :name: with surrounding whitespace', () => {
|
|
44
|
-
const r = parseEmoji(' :heart: ');
|
|
45
|
-
expect(r).toEqual({ id: null, name: 'heart' });
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('returns plain unicode as name when no pattern matches', () => {
|
|
49
|
-
const r = parseEmoji('❤️');
|
|
50
|
-
expect(r).toEqual({ id: null, name: '❤️' });
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('rejects name:id with short id (less than 17 digits)', () => {
|
|
54
|
-
const r = parseEmoji('emoji:123456');
|
|
55
|
-
expect(r?.id).toBeNull();
|
|
56
|
-
expect(r?.name).toBe('emoji:123456'); // falls through to plain
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe('formatEmoji', () => {
|
|
61
|
-
it('formats custom emoji as name:id', () => {
|
|
62
|
-
expect(formatEmoji({ id: '123456789012345678', name: 'custom' })).toBe(
|
|
63
|
-
':custom:123456789012345678',
|
|
64
|
-
);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('formats animated custom emoji with a prefix', () => {
|
|
68
|
-
expect(formatEmoji({ id: '123456789012345678', name: 'wiggle', animated: true })).toBe(
|
|
69
|
-
'a:wiggle:123456789012345678',
|
|
70
|
-
);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('encodes unicode emoji for API (id null)', () => {
|
|
74
|
-
const r = formatEmoji({ id: null, name: '❤' });
|
|
75
|
-
expect(r).toBe(encodeURIComponent('❤'));
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe('parseUserMention', () => {
|
|
80
|
-
it('extracts user ID from <@id> mention', () => {
|
|
81
|
-
expect(parseUserMention('<@123456789012345678>')).toBe('123456789012345678');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('extracts user ID from <@!id> mention', () => {
|
|
85
|
-
expect(parseUserMention('<@!123456789012345678>')).toBe('123456789012345678');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('returns raw snowflake when valid 17–19 digits', () => {
|
|
89
|
-
expect(parseUserMention('123456789012345678')).toBe('123456789012345678');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('returns null for invalid formats', () => {
|
|
93
|
-
expect(parseUserMention('<@&123>')).toBeNull();
|
|
94
|
-
expect(parseUserMention('invalid')).toBeNull();
|
|
95
|
-
expect(parseUserMention('')).toBeNull();
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('trims whitespace', () => {
|
|
99
|
-
expect(parseUserMention(' <@!123456789012345678> ')).toBe('123456789012345678');
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('parsePrefixCommand', () => {
|
|
104
|
-
it('parses command with no args', () => {
|
|
105
|
-
expect(parsePrefixCommand('!ping', '!')).toEqual({ command: 'ping', args: [] });
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('parses command with args', () => {
|
|
109
|
-
expect(parsePrefixCommand('!hello world', '!')).toEqual({ command: 'hello', args: ['world'] });
|
|
110
|
-
expect(parsePrefixCommand('!ban 123 reason here', '!')).toEqual({
|
|
111
|
-
command: 'ban',
|
|
112
|
-
args: ['123', 'reason', 'here'],
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('returns null when content does not start with prefix', () => {
|
|
117
|
-
expect(parsePrefixCommand('hello', '!')).toBeNull();
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('returns null for prefix only with no command', () => {
|
|
121
|
-
expect(parsePrefixCommand('!', '!')).toBeNull();
|
|
122
|
-
expect(parsePrefixCommand('! ', '!')).toBeNull();
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('handles multiple spaces between args', () => {
|
|
126
|
-
expect(parsePrefixCommand('!cmd a b', '!')).toEqual({
|
|
127
|
-
command: 'cmd',
|
|
128
|
-
args: ['a', 'b'],
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('lowercases command', () => {
|
|
133
|
-
expect(parsePrefixCommand('!PING', '!')).toEqual({ command: 'ping', args: [] });
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('returns null for null or non-string content', () => {
|
|
137
|
-
expect(parsePrefixCommand(null as unknown as string, '!')).toBeNull();
|
|
138
|
-
expect(parsePrefixCommand(123 as unknown as string, '!')).toBeNull();
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
describe('parseRoleMention', () => {
|
|
143
|
-
it('extracts role ID from valid mention', () => {
|
|
144
|
-
expect(parseRoleMention('<@&123456789012345678>')).toBe('123456789012345678');
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('returns null for invalid formats', () => {
|
|
148
|
-
expect(parseRoleMention('<@123>')).toBeNull();
|
|
149
|
-
expect(parseRoleMention('@&123')).toBeNull();
|
|
150
|
-
expect(parseRoleMention('')).toBeNull();
|
|
151
|
-
expect(parseRoleMention(' ')).toBeNull();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('returns null for null or non-string', () => {
|
|
155
|
-
expect(parseRoleMention(null as unknown as string)).toBeNull();
|
|
156
|
-
expect(parseRoleMention(undefined as unknown as string)).toBeNull();
|
|
157
|
-
expect(parseRoleMention(123 as unknown as string)).toBeNull();
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('trims whitespace', () => {
|
|
161
|
-
expect(parseRoleMention(' <@&123456789012345678> ')).toBe('123456789012345678');
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
describe('resolveColor', () => {
|
|
166
|
-
it('accepts valid number 0-16777215', () => {
|
|
167
|
-
expect(resolveColor(0)).toBe(0);
|
|
168
|
-
expect(resolveColor(0xff0000)).toBe(0xff0000);
|
|
169
|
-
expect(resolveColor(0xffffff)).toBe(0xffffff);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('throws for number out of range', () => {
|
|
173
|
-
expect(() => resolveColor(-1)).toThrow(RangeError);
|
|
174
|
-
expect(() => resolveColor(0x1000000)).toThrow(RangeError);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('parses hex string', () => {
|
|
178
|
-
expect(resolveColor('#ff0000')).toBe(0xff0000);
|
|
179
|
-
expect(resolveColor('#FFFFFF')).toBe(0xffffff);
|
|
180
|
-
expect(resolveColor('000000')).toBe(0);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('throws for invalid hex', () => {
|
|
184
|
-
expect(() => resolveColor('#gggggg')).toThrow(RangeError);
|
|
185
|
-
expect(() => resolveColor('#fff')).toThrow(RangeError);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('parses RGB array', () => {
|
|
189
|
-
expect(resolveColor([255, 0, 0])).toBe(0xff0000);
|
|
190
|
-
expect(resolveColor([0, 0, 0])).toBe(0);
|
|
191
|
-
expect(resolveColor([255, 255, 255])).toBe(0xffffff);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('throws for non-color types', () => {
|
|
195
|
-
expect(() => resolveColor({} as unknown as number)).toThrow(TypeError);
|
|
196
|
-
expect(() => resolveColor(true as unknown as number)).toThrow(TypeError);
|
|
197
|
-
});
|
|
198
|
-
});
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolve a color from various input types to a number (0-16777215).
|
|
3
|
-
*/
|
|
4
|
-
export function resolveColor(color: number | string | [number, number, number]): number {
|
|
5
|
-
if (typeof color === 'number') {
|
|
6
|
-
if (color < 0 || color > 0xffffff) throw new RangeError('Color must be between 0 and 16777215');
|
|
7
|
-
return color;
|
|
8
|
-
}
|
|
9
|
-
if (Array.isArray(color)) {
|
|
10
|
-
const [r, g, b] = color;
|
|
11
|
-
return (r! << 16) | (g! << 8) | b!;
|
|
12
|
-
}
|
|
13
|
-
if (typeof color === 'string') {
|
|
14
|
-
const hex = color.replace(/^#/, '');
|
|
15
|
-
if (!/^[0-9a-fA-F]{6}$/.test(hex)) throw new RangeError('Invalid hex color');
|
|
16
|
-
return parseInt(hex, 16);
|
|
17
|
-
}
|
|
18
|
-
throw new TypeError('Color must be a number, hex string, or RGB array');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Parse an emoji string into id and name.
|
|
23
|
-
* Supports: <a?:name:id> (mention), :name: (colons), name:id (API format), unicode.
|
|
24
|
-
*/
|
|
25
|
-
export function parseEmoji(
|
|
26
|
-
emoji: string,
|
|
27
|
-
): { id: string | null; name: string; animated?: boolean } | null {
|
|
28
|
-
if (emoji == null || typeof emoji !== 'string') return null;
|
|
29
|
-
const trimmed = emoji.trim();
|
|
30
|
-
if (trimmed.length === 0) return null;
|
|
31
|
-
// <a?:name:id> mention format
|
|
32
|
-
const mention = /^<(a?):(\w+):(\d+)>$/;
|
|
33
|
-
const mentionMatch = trimmed.match(mention);
|
|
34
|
-
if (mentionMatch) {
|
|
35
|
-
return {
|
|
36
|
-
id: mentionMatch[3],
|
|
37
|
-
name: mentionMatch[2],
|
|
38
|
-
animated: mentionMatch[1] === 'a',
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
// name:id API format (custom emoji)
|
|
42
|
-
const nameId = /^(\w+):(\d{17,19})$/;
|
|
43
|
-
const nameIdMatch = trimmed.match(nameId);
|
|
44
|
-
if (nameIdMatch) {
|
|
45
|
-
return { id: nameIdMatch[2], name: nameIdMatch[1] };
|
|
46
|
-
}
|
|
47
|
-
// :name: format (colons, no id - needs guild lookup)
|
|
48
|
-
const colons = /^:(\w+):$/;
|
|
49
|
-
const colonsMatch = trimmed.match(colons);
|
|
50
|
-
if (colonsMatch) {
|
|
51
|
-
return { id: null, name: colonsMatch[1] };
|
|
52
|
-
}
|
|
53
|
-
// Plain name (possibly unicode) - id null
|
|
54
|
-
return { id: null, name: trimmed };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Parse a user mention string or raw snowflake and extract the user ID.
|
|
59
|
-
* Supports: <@123456789012345678>, <@!123456789012345678>, or raw 17–19 digit snowflake.
|
|
60
|
-
* @param arg - String that may contain a user mention or raw user ID
|
|
61
|
-
* @returns The user ID if valid, otherwise null
|
|
62
|
-
* @example
|
|
63
|
-
* parseUserMention('<@!123456789012345678>'); // '123456789012345678'
|
|
64
|
-
* parseUserMention('<@123456789012345678>'); // '123456789012345678'
|
|
65
|
-
* parseUserMention('123456789012345678'); // '123456789012345678'
|
|
66
|
-
*/
|
|
67
|
-
export function parseUserMention(arg: string): string | null {
|
|
68
|
-
if (arg == null || typeof arg !== 'string') return null;
|
|
69
|
-
const trimmed = arg.trim();
|
|
70
|
-
if (trimmed.length === 0) return null;
|
|
71
|
-
const mentionMatch = trimmed.match(/^<@!?(\d{17,19})>$/);
|
|
72
|
-
if (mentionMatch) return mentionMatch[1];
|
|
73
|
-
if (/^\d{17,19}$/.test(trimmed)) return trimmed;
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Parse prefix command content into command name and args.
|
|
79
|
-
* Returns null if content does not start with the prefix.
|
|
80
|
-
* @param content - Raw message content
|
|
81
|
-
* @param prefix - Command prefix (e.g. '!')
|
|
82
|
-
* @returns { command, args } or null
|
|
83
|
-
* @example
|
|
84
|
-
* parsePrefixCommand('!ping', '!'); // { command: 'ping', args: [] }
|
|
85
|
-
* parsePrefixCommand('!hello world', '!'); // { command: 'hello', args: ['world'] }
|
|
86
|
-
*/
|
|
87
|
-
export function parsePrefixCommand(
|
|
88
|
-
content: string,
|
|
89
|
-
prefix: string,
|
|
90
|
-
): { command: string; args: string[] } | null {
|
|
91
|
-
if (content == null || typeof content !== 'string') return null;
|
|
92
|
-
const trimmed = content.trim();
|
|
93
|
-
if (!trimmed.startsWith(prefix)) return null;
|
|
94
|
-
const rest = trimmed.slice(prefix.length).trim();
|
|
95
|
-
if (rest.length === 0) return null;
|
|
96
|
-
const parts = rest.split(/\s+/);
|
|
97
|
-
const command = parts[0]?.toLowerCase() ?? '';
|
|
98
|
-
const args = parts.slice(1);
|
|
99
|
-
return { command, args };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Parse a role mention string (e.g. <@&123456>) and extract the role ID.
|
|
104
|
-
* @param arg - String that may contain a role mention
|
|
105
|
-
* @returns The role ID if valid mention, otherwise null
|
|
106
|
-
*/
|
|
107
|
-
export function parseRoleMention(arg: string): string | null {
|
|
108
|
-
if (arg == null || typeof arg !== 'string') return null;
|
|
109
|
-
const match = arg.trim().match(/^<@&(\d{17,19})>$/);
|
|
110
|
-
return match?.[1] ?? null;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Convert emoji to the format used in API (for reactions etc).
|
|
115
|
-
* Custom: "name:id", Unicode: "unicode"
|
|
116
|
-
*/
|
|
117
|
-
export function formatEmoji(emoji: {
|
|
118
|
-
id: string | null;
|
|
119
|
-
name: string;
|
|
120
|
-
animated?: boolean;
|
|
121
|
-
}): string {
|
|
122
|
-
if (emoji.id) {
|
|
123
|
-
const prefix = emoji.animated ? 'a' : '';
|
|
124
|
-
return `${prefix}:${emoji.name}:${emoji.id}`;
|
|
125
|
-
}
|
|
126
|
-
return encodeURIComponent(emoji.name);
|
|
127
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { resolveTenorToImageUrl } from './tenorUtils.js';
|
|
3
|
-
|
|
4
|
-
describe('resolveTenorToImageUrl', () => {
|
|
5
|
-
beforeEach(() => {
|
|
6
|
-
vi.stubGlobal(
|
|
7
|
-
'fetch',
|
|
8
|
-
vi.fn((url: string) => {
|
|
9
|
-
if (url.includes('tenor.com/view')) {
|
|
10
|
-
const html = `<html><script class="dynamic" type="application/ld+json">
|
|
11
|
-
{"@type":"VideoObject","contentUrl":"https://media.tenor.com/abc123/stressed.gif","thumbnailUrl":"https://media.tenor.com/abc123/stressed.png"}
|
|
12
|
-
</script></html>`;
|
|
13
|
-
return Promise.resolve({
|
|
14
|
-
ok: true,
|
|
15
|
-
text: () => Promise.resolve(html),
|
|
16
|
-
} as Response);
|
|
17
|
-
}
|
|
18
|
-
if (url.includes('oembed')) {
|
|
19
|
-
return Promise.resolve({
|
|
20
|
-
ok: true,
|
|
21
|
-
json: () =>
|
|
22
|
-
Promise.resolve({
|
|
23
|
-
thumbnail_url: 'https://media.tenor.com/xyz/stressed.png',
|
|
24
|
-
}),
|
|
25
|
-
} as Response);
|
|
26
|
-
}
|
|
27
|
-
return Promise.reject(new Error('Unexpected URL'));
|
|
28
|
-
}),
|
|
29
|
-
);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterEach(() => {
|
|
33
|
-
vi.unstubAllGlobals();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('returns null for empty or non-tenor URL', async () => {
|
|
37
|
-
expect(await resolveTenorToImageUrl('')).toBeNull();
|
|
38
|
-
expect(await resolveTenorToImageUrl('https://example.com')).toBeNull();
|
|
39
|
-
expect(await resolveTenorToImageUrl('https://giphy.com/view/123')).toBeNull();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('resolves GIF URL from tenor view page JSON-LD', async () => {
|
|
43
|
-
const result = await resolveTenorToImageUrl(
|
|
44
|
-
'https://tenor.com/view/stressed-gif-7048057395502071840',
|
|
45
|
-
);
|
|
46
|
-
expect(result).not.toBeNull();
|
|
47
|
-
expect(result!.url).toContain('.gif');
|
|
48
|
-
expect(result!.url).toContain('media.tenor.com');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('falls back to oEmbed when page fetch fails', async () => {
|
|
52
|
-
vi.stubGlobal(
|
|
53
|
-
'fetch',
|
|
54
|
-
vi.fn((url: string) => {
|
|
55
|
-
if (url.includes('tenor.com/view')) {
|
|
56
|
-
return Promise.resolve({ ok: false });
|
|
57
|
-
}
|
|
58
|
-
if (url.includes('oembed')) {
|
|
59
|
-
return Promise.resolve({
|
|
60
|
-
ok: true,
|
|
61
|
-
json: () =>
|
|
62
|
-
Promise.resolve({
|
|
63
|
-
thumbnail_url: 'https://media.tenor.com/fallback/image.png',
|
|
64
|
-
}),
|
|
65
|
-
} as Response);
|
|
66
|
-
}
|
|
67
|
-
return Promise.reject(new Error('Unexpected'));
|
|
68
|
-
}),
|
|
69
|
-
);
|
|
70
|
-
const result = await resolveTenorToImageUrl('https://tenor.com/view/test-123');
|
|
71
|
-
expect(result).not.toBeNull();
|
|
72
|
-
expect(result!.url).toContain('media.tenor.com');
|
|
73
|
-
expect(result!.url).toContain('.gif');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { EmbedMediaFlags } from '@erinjs/types';
|
|
2
|
-
|
|
3
|
-
/** Result for embed media: url and optional flags. */
|
|
4
|
-
export interface TenorMediaResult {
|
|
5
|
-
url: string;
|
|
6
|
-
flags?: number;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Resolve a Tenor view URL to a direct GIF URL for use in embeds.
|
|
11
|
-
* Embeds require GIF format (not MP4). Fetches the Tenor page for JSON-LD
|
|
12
|
-
* or oEmbed, then derives the GIF URL from the media.tenor.com path.
|
|
13
|
-
*
|
|
14
|
-
* @param tenorViewUrl - Tenor view URL (e.g. https://tenor.com/view/stressed-gif-7048057395502071840)
|
|
15
|
-
* @returns { url, flags? } for setImage/setThumbnail, or null if resolution fails
|
|
16
|
-
* @example
|
|
17
|
-
* const media = await resolveTenorToImageUrl('https://tenor.com/view/stressed-gif-7048057395502071840');
|
|
18
|
-
* if (media) embed.setImage(media);
|
|
19
|
-
*/
|
|
20
|
-
export async function resolveTenorToImageUrl(
|
|
21
|
-
tenorViewUrl: string,
|
|
22
|
-
): Promise<TenorMediaResult | null> {
|
|
23
|
-
if (!tenorViewUrl || !tenorViewUrl.includes('tenor.com')) return null;
|
|
24
|
-
|
|
25
|
-
// Try page HTML + JSON-LD first
|
|
26
|
-
try {
|
|
27
|
-
const pageRes = await fetch(tenorViewUrl, {
|
|
28
|
-
signal: AbortSignal.timeout(5000),
|
|
29
|
-
headers: { 'User-Agent': 'Mozilla/5.0 (compatible; FluxerSDK/1.0)' },
|
|
30
|
-
});
|
|
31
|
-
if (!pageRes.ok) throw new Error('Page fetch failed');
|
|
32
|
-
const html = await pageRes.text();
|
|
33
|
-
const jsonLd = extractTenorJsonLd(html);
|
|
34
|
-
const gifUrl = extractGifUrlFromJsonLd(jsonLd);
|
|
35
|
-
if (gifUrl) {
|
|
36
|
-
return { url: gifUrl, flags: EmbedMediaFlags.IS_ANIMATED };
|
|
37
|
-
}
|
|
38
|
-
} catch {
|
|
39
|
-
// Fall through to oEmbed
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Fallback: oEmbed thumbnail, derive GIF URL (media.tenor.com/ID/name.png -> name.gif)
|
|
43
|
-
try {
|
|
44
|
-
const oembedUrl = `https://tenor.com/oembed?url=${encodeURIComponent(tenorViewUrl)}`;
|
|
45
|
-
const res = await fetch(oembedUrl, { signal: AbortSignal.timeout(5000) });
|
|
46
|
-
if (!res.ok) return null;
|
|
47
|
-
const data = (await res.json()) as { thumbnail_url?: string };
|
|
48
|
-
const gifUrl = deriveGifFromThumbnail(data.thumbnail_url);
|
|
49
|
-
return gifUrl ? { url: gifUrl, flags: EmbedMediaFlags.IS_ANIMATED } : null;
|
|
50
|
-
} catch {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** Extract GIF URL from JSON-LD. Prefers .gif URLs; derives from thumbnail path if needed. */
|
|
56
|
-
function extractGifUrlFromJsonLd(jsonLd: Record<string, unknown> | null): string | null {
|
|
57
|
-
if (!jsonLd) return null;
|
|
58
|
-
const image = jsonLd.image as Record<string, string> | undefined;
|
|
59
|
-
const video = jsonLd.video as Record<string, string> | undefined;
|
|
60
|
-
const thumbnailUrl = image?.thumbnailUrl ?? image?.url;
|
|
61
|
-
const contentUrl = image?.contentUrl ?? video?.contentUrl;
|
|
62
|
-
if (contentUrl && /\.gif($|\?)/i.test(contentUrl)) return contentUrl;
|
|
63
|
-
if (thumbnailUrl) return deriveGifFromThumbnail(thumbnailUrl);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Derive GIF URL from media.tenor.com thumbnail (.png -> .gif). */
|
|
68
|
-
function deriveGifFromThumbnail(thumbUrl: string | undefined): string | null {
|
|
69
|
-
if (!thumbUrl || !thumbUrl.includes('media.tenor.com')) return null;
|
|
70
|
-
const gifUrl = thumbUrl.replace(/\.(png|jpg|jpeg|webp)(\?|$)/i, '.gif$2');
|
|
71
|
-
return gifUrl !== thumbUrl ? gifUrl : null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function extractTenorJsonLd(html: string): Record<string, unknown> | null {
|
|
75
|
-
const re =
|
|
76
|
-
/<script[^>]*class="dynamic"[^>]*type="application\/ld\+json"[^>]*>([\s\S]*?)<\/script>/i;
|
|
77
|
-
const alt =
|
|
78
|
-
/<script[^>]*type="application\/ld\+json"[^>]*class="dynamic"[^>]*>([\s\S]*?)<\/script>/i;
|
|
79
|
-
const match = html.match(re) ?? html.match(alt);
|
|
80
|
-
if (!match?.[1]) return null;
|
|
81
|
-
try {
|
|
82
|
-
return JSON.parse(match[1].trim()) as Record<string, unknown>;
|
|
83
|
-
} catch {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
}
|