@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,32 +0,0 @@
|
|
|
1
|
-
declare module 'mp4box' {
|
|
2
|
-
export interface MP4File {
|
|
3
|
-
onReady?: (info: {
|
|
4
|
-
tracks?: Array<{
|
|
5
|
-
id: number;
|
|
6
|
-
type: string;
|
|
7
|
-
codec: string;
|
|
8
|
-
video?: { width: number; height: number };
|
|
9
|
-
timescale?: number;
|
|
10
|
-
}>;
|
|
11
|
-
}) => void;
|
|
12
|
-
onError?: (e: Error) => void;
|
|
13
|
-
onSamples?: (
|
|
14
|
-
trackId: number,
|
|
15
|
-
user: unknown,
|
|
16
|
-
samples: Array<{
|
|
17
|
-
data: ArrayBuffer;
|
|
18
|
-
is_sync?: boolean;
|
|
19
|
-
is_rap?: boolean;
|
|
20
|
-
timescale: number;
|
|
21
|
-
dts: number;
|
|
22
|
-
duration: number;
|
|
23
|
-
}>,
|
|
24
|
-
) => void;
|
|
25
|
-
appendBuffer(data: ArrayBuffer): number;
|
|
26
|
-
flush(): void;
|
|
27
|
-
setExtractionOptions(trackId: number, user: unknown, options: { nbSamples?: number }): void;
|
|
28
|
-
start(): void;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function createFile(): MP4File;
|
|
32
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { parseOpusPacketBoundaries } from './opusUtils.js';
|
|
3
|
-
|
|
4
|
-
describe('parseOpusPacketBoundaries', () => {
|
|
5
|
-
it('returns null for buffer shorter than 2 bytes', () => {
|
|
6
|
-
expect(parseOpusPacketBoundaries(new Uint8Array([]))).toBeNull();
|
|
7
|
-
expect(parseOpusPacketBoundaries(new Uint8Array([0]))).toBeNull();
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it('returns single frame for c=0 (one frame)', () => {
|
|
11
|
-
const buf = new Uint8Array([0x78, 0x01, 0x02, 0x03]); // c=0
|
|
12
|
-
const result = parseOpusPacketBoundaries(buf);
|
|
13
|
-
expect(result).not.toBeNull();
|
|
14
|
-
expect(result!.frames).toHaveLength(1);
|
|
15
|
-
expect(result!.consumed).toBe(4);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('returns null for c=1 when not enough data', () => {
|
|
19
|
-
const buf = new Uint8Array([0x79, 0x05]); // c=1, L1=5, need 2+5+1=8 min
|
|
20
|
-
expect(parseOpusPacketBoundaries(buf)).toBeNull();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('handles c=2 (two frames CBR)', () => {
|
|
24
|
-
const buf = new Uint8Array([0x7a, 0x00, 0x01, 0x02, 0x03, 0x04]); // c=2, 4 bytes data -> 2 per frame
|
|
25
|
-
const result = parseOpusPacketBoundaries(buf);
|
|
26
|
-
expect(result).not.toBeNull();
|
|
27
|
-
expect(result!.frames).toHaveLength(2);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared Opus parsing utilities for voice connections.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Parse Opus packet (RFC 6716) and return single-frame packets for decodeFrame().
|
|
7
|
-
* TOC byte: config (0-4), s (5), c (6-7). c=0: 1 frame; c=1: 2 frames + 1 length byte; c=2: 2 frames CBR + padding; c=3: N frames + (N-1) length bytes.
|
|
8
|
-
* Returns { frames: Uint8Array[], consumed } or null if not enough data.
|
|
9
|
-
*/
|
|
10
|
-
export function parseOpusPacketBoundaries(
|
|
11
|
-
buffer: Uint8Array,
|
|
12
|
-
): { frames: Uint8Array[]; consumed: number } | null {
|
|
13
|
-
if (buffer.length < 2) return null;
|
|
14
|
-
const toc = buffer[0];
|
|
15
|
-
const c = toc & 3; // frame count code
|
|
16
|
-
const tocSingle = (toc & 0xfc) | 0; // same config/s, one frame
|
|
17
|
-
|
|
18
|
-
if (c === 0) {
|
|
19
|
-
return { frames: [buffer.slice()], consumed: buffer.length };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (c === 1) {
|
|
23
|
-
if (buffer.length < 2) return null;
|
|
24
|
-
const L1 = buffer[1] + 1;
|
|
25
|
-
if (buffer.length < 2 + L1) return null;
|
|
26
|
-
const L2 = buffer.length - 2 - L1;
|
|
27
|
-
const frame0 = new Uint8Array(1 + L1);
|
|
28
|
-
frame0[0] = tocSingle;
|
|
29
|
-
frame0.set(buffer.subarray(2, 2 + L1), 1);
|
|
30
|
-
const frame1 = new Uint8Array(1 + L2);
|
|
31
|
-
frame1[0] = tocSingle;
|
|
32
|
-
frame1.set(buffer.subarray(2 + L1), 1);
|
|
33
|
-
return { frames: [frame0, frame1], consumed: buffer.length };
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (c === 2) {
|
|
37
|
-
if (buffer.length < 3) return null;
|
|
38
|
-
const frameLen = Math.floor((buffer.length - 2) / 2);
|
|
39
|
-
if (frameLen < 1) return null;
|
|
40
|
-
const frame0 = new Uint8Array(1 + frameLen);
|
|
41
|
-
frame0[0] = tocSingle;
|
|
42
|
-
frame0.set(buffer.subarray(2, 2 + frameLen), 1);
|
|
43
|
-
const frame1 = new Uint8Array(1 + frameLen);
|
|
44
|
-
frame1[0] = tocSingle;
|
|
45
|
-
frame1.set(buffer.subarray(2 + frameLen, 2 + 2 * frameLen), 1);
|
|
46
|
-
return { frames: [frame0, frame1], consumed: 2 + 2 * frameLen };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (c === 3) {
|
|
50
|
-
if (buffer.length < 2) return null;
|
|
51
|
-
const N = buffer[1];
|
|
52
|
-
if (N < 1 || N > 255) return null;
|
|
53
|
-
const numLengthBytes = N - 1;
|
|
54
|
-
if (buffer.length < 2 + numLengthBytes) return null;
|
|
55
|
-
const lengths: number[] = [];
|
|
56
|
-
for (let i = 0; i < numLengthBytes; i++) {
|
|
57
|
-
lengths.push(buffer[2 + i] + 1);
|
|
58
|
-
}
|
|
59
|
-
const headerLen = 2 + numLengthBytes;
|
|
60
|
-
let offset = headerLen;
|
|
61
|
-
const sumKnown = lengths.reduce((a, b) => a + b, 0);
|
|
62
|
-
const lastLen = buffer.length - headerLen - sumKnown;
|
|
63
|
-
if (lastLen < 0) return null;
|
|
64
|
-
lengths.push(lastLen);
|
|
65
|
-
const frames: Uint8Array[] = [];
|
|
66
|
-
for (let i = 0; i < lengths.length; i++) {
|
|
67
|
-
const L = lengths[i];
|
|
68
|
-
if (offset + L > buffer.length) return null;
|
|
69
|
-
const frame = new Uint8Array(1 + L);
|
|
70
|
-
frame[0] = tocSingle;
|
|
71
|
-
frame.set(buffer.subarray(offset, offset + L), 1);
|
|
72
|
-
frames.push(frame);
|
|
73
|
-
offset += L;
|
|
74
|
-
}
|
|
75
|
-
return { frames, consumed: offset };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function concatUint8Arrays(a: Uint8Array, b: Uint8Array): Uint8Array {
|
|
82
|
-
const out = new Uint8Array(a.length + b.length);
|
|
83
|
-
out.set(a);
|
|
84
|
-
out.set(b, a.length);
|
|
85
|
-
return out;
|
|
86
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { thumbnail } from './streamPreviewPlaceholder.js';
|
|
3
|
-
|
|
4
|
-
describe('streamPreviewPlaceholder', () => {
|
|
5
|
-
it('exports valid base64 string', () => {
|
|
6
|
-
expect(typeof thumbnail).toBe('string');
|
|
7
|
-
expect(thumbnail.length).toBeGreaterThan(0);
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it('decodes to valid PNG header', () => {
|
|
11
|
-
const decoded = Buffer.from(thumbnail, 'base64');
|
|
12
|
-
expect(decoded[0]).toBe(0x89);
|
|
13
|
-
expect(decoded[1]).toBe(0x50);
|
|
14
|
-
expect(decoded[2]).toBe(0x4e);
|
|
15
|
-
});
|
|
16
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal 1x1 grey PNG as base64 for stream preview placeholder.
|
|
3
|
-
* Used when uploading preview before actual frames are available.
|
|
4
|
-
*/
|
|
5
|
-
const MINIMAL_PNG_BASE64 =
|
|
6
|
-
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==';
|
|
7
|
-
|
|
8
|
-
export const thumbnail = MINIMAL_PNG_BASE64;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
declare module 'ws';
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@erinjs/ws",
|
|
3
|
-
"publishConfig": {
|
|
4
|
-
"access": "public"
|
|
5
|
-
},
|
|
6
|
-
"version": "1.2.4",
|
|
7
|
-
"description": "WebSocket manager for the Fluxer Gateway",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/blstmo-abandoned-us-for-the-milk/core.git",
|
|
11
|
-
"directory": "packages/ws"
|
|
12
|
-
},
|
|
13
|
-
"bugs": "https://github.com/blstmo-abandoned-us-for-the-milk/core/issues",
|
|
14
|
-
"homepage": "https://github.com/blstmo-abandoned-us-for-the-milk/core#readme",
|
|
15
|
-
"keywords": [
|
|
16
|
-
"fluxer",
|
|
17
|
-
"websocket",
|
|
18
|
-
"gateway",
|
|
19
|
-
"sdk"
|
|
20
|
-
],
|
|
21
|
-
"license": "Apache-2.0",
|
|
22
|
-
"main": "./dist/index.js",
|
|
23
|
-
"module": "./dist/index.mjs",
|
|
24
|
-
"types": "./dist/index.d.ts",
|
|
25
|
-
"exports": {
|
|
26
|
-
".": {
|
|
27
|
-
"types": "./dist/index.d.ts",
|
|
28
|
-
"import": "./dist/index.mjs",
|
|
29
|
-
"require": "./dist/index.js"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
"files": [
|
|
33
|
-
"dist"
|
|
34
|
-
],
|
|
35
|
-
"scripts": {
|
|
36
|
-
"build": "tsup",
|
|
37
|
-
"clean": "rm -rf dist",
|
|
38
|
-
"lint": "eslint src --max-warnings 0 --config ../../eslint.config.js",
|
|
39
|
-
"lint:fix": "eslint src --fix --config ../../eslint.config.js",
|
|
40
|
-
"test": "vitest run --passWithNoTests",
|
|
41
|
-
"test:coverage": "vitest run --coverage --passWithNoTests"
|
|
42
|
-
},
|
|
43
|
-
"dependencies": {
|
|
44
|
-
"@erinjs/types": "workspace:*",
|
|
45
|
-
"ws": "^8.18.0"
|
|
46
|
-
},
|
|
47
|
-
"devDependencies": {
|
|
48
|
-
"@types/node": "^20.0.0",
|
|
49
|
-
"tsup": "^8.3.0",
|
|
50
|
-
"typescript": "^5.6.0"
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import { APIGatewayBotResponse, GatewayPresenceUpdateData } from '@erinjs/types';
|
|
3
|
-
import { WebSocketShard } from './WebSocketShard.js';
|
|
4
|
-
import { getDefaultWebSocket } from './utils/getWebSocket.js';
|
|
5
|
-
|
|
6
|
-
import { WebSocketConstructor as WSConstructor } from './WebSocketShard';
|
|
7
|
-
|
|
8
|
-
export type WebSocketConstructor = WSConstructor;
|
|
9
|
-
|
|
10
|
-
const RETRY_INITIAL_MS = 1000;
|
|
11
|
-
const RETRY_MAX_MS = 45000;
|
|
12
|
-
|
|
13
|
-
function sleep(ms: number): Promise<void> {
|
|
14
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface WebSocketManagerOptions {
|
|
18
|
-
token: string;
|
|
19
|
-
intents: number;
|
|
20
|
-
rest: { get: (route: string) => Promise<unknown> };
|
|
21
|
-
version?: string;
|
|
22
|
-
presence?: GatewayPresenceUpdateData;
|
|
23
|
-
shardIds?: number[];
|
|
24
|
-
shardCount?: number;
|
|
25
|
-
WebSocket?: WebSocketConstructor;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export class WebSocketManager extends EventEmitter {
|
|
29
|
-
private readonly options: WebSocketManagerOptions;
|
|
30
|
-
private shards = new Map<number, WebSocketShard>();
|
|
31
|
-
private gatewayUrl: string | null = null;
|
|
32
|
-
private shardCount = 1;
|
|
33
|
-
private _aborted = false;
|
|
34
|
-
|
|
35
|
-
constructor(options: WebSocketManagerOptions) {
|
|
36
|
-
super();
|
|
37
|
-
this.options = options;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async connect(): Promise<void> {
|
|
41
|
-
this._aborted = false;
|
|
42
|
-
|
|
43
|
-
let WS = this.options.WebSocket;
|
|
44
|
-
let delayMs = RETRY_INITIAL_MS;
|
|
45
|
-
|
|
46
|
-
if (!WS) {
|
|
47
|
-
while (!this._aborted) {
|
|
48
|
-
try {
|
|
49
|
-
WS = await getDefaultWebSocket();
|
|
50
|
-
break;
|
|
51
|
-
} catch (err) {
|
|
52
|
-
const e = err instanceof Error ? err : new Error(String(err));
|
|
53
|
-
this.emit('error', { shardId: -1, error: e });
|
|
54
|
-
await sleep(delayMs);
|
|
55
|
-
delayMs = Math.min(RETRY_MAX_MS, Math.floor(delayMs * 1.5));
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (this._aborted) throw new Error('Connection aborted');
|
|
59
|
-
if (!WS) throw new Error('Failed to load WebSocket');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
let gateway: APIGatewayBotResponse | null = null;
|
|
63
|
-
while (!this._aborted) {
|
|
64
|
-
try {
|
|
65
|
-
gateway = (await this.options.rest.get('/gateway/bot')) as APIGatewayBotResponse;
|
|
66
|
-
break;
|
|
67
|
-
} catch (err) {
|
|
68
|
-
const e = err instanceof Error ? err : new Error(String(err));
|
|
69
|
-
this.emit('error', { shardId: -1, error: e });
|
|
70
|
-
await sleep(delayMs);
|
|
71
|
-
delayMs = Math.min(RETRY_MAX_MS, Math.floor(delayMs * 1.5));
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (this._aborted) throw new Error('Connection aborted');
|
|
76
|
-
if (!gateway) throw new Error('Failed to fetch gateway');
|
|
77
|
-
|
|
78
|
-
this.gatewayUrl = gateway.url;
|
|
79
|
-
this.shardCount = this.options.shardCount ?? gateway.shards;
|
|
80
|
-
|
|
81
|
-
const ids = this.options.shardIds ?? [...Array(this.shardCount).keys()];
|
|
82
|
-
|
|
83
|
-
const version = this.options.version ?? '1';
|
|
84
|
-
|
|
85
|
-
for (const id of ids) {
|
|
86
|
-
const shard = new WebSocketShard({
|
|
87
|
-
url: this.gatewayUrl ?? gateway.url,
|
|
88
|
-
token: this.options.token,
|
|
89
|
-
intents: this.options.intents,
|
|
90
|
-
presence: this.options.presence,
|
|
91
|
-
shardId: id,
|
|
92
|
-
numShards: this.shardCount,
|
|
93
|
-
version,
|
|
94
|
-
WebSocket: WS,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
shard.on('ready', (data) => this.emit('ready', { shardId: id, data }));
|
|
98
|
-
shard.on('resumed', () => this.emit('resumed', id));
|
|
99
|
-
shard.on('dispatch', (payload) => this.emit('dispatch', { shardId: id, payload }));
|
|
100
|
-
shard.on('close', (code) => this.emit('close', { shardId: id, code }));
|
|
101
|
-
shard.on('error', (err) => this.emit('error', { shardId: id, error: err }));
|
|
102
|
-
shard.on('debug', (msg) => this.emit('debug', msg));
|
|
103
|
-
|
|
104
|
-
this.shards.set(id, shard);
|
|
105
|
-
try {
|
|
106
|
-
shard.connect();
|
|
107
|
-
} catch (err) {
|
|
108
|
-
this.emit('error', {
|
|
109
|
-
shardId: id,
|
|
110
|
-
error: err instanceof Error ? err : new Error(String(err)),
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
send(shardId: number, payload: Parameters<WebSocketShard['send']>[0]): void {
|
|
117
|
-
this.shards.get(shardId)?.send(payload);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
destroy(): void {
|
|
121
|
-
this._aborted = true;
|
|
122
|
-
for (const shard of this.shards.values()) shard.destroy();
|
|
123
|
-
this.shards.clear();
|
|
124
|
-
this.gatewayUrl = null;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
getShardCount(): number {
|
|
128
|
-
return this.shardCount;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import {
|
|
3
|
-
GatewaySendPayload,
|
|
4
|
-
GatewayHelloData,
|
|
5
|
-
GatewayReceivePayload,
|
|
6
|
-
GatewayIdentifyData,
|
|
7
|
-
GatewayResumeData,
|
|
8
|
-
GatewayPresenceUpdateData,
|
|
9
|
-
} from '@erinjs/types';
|
|
10
|
-
import { GatewayOpcodes } from '@erinjs/types';
|
|
11
|
-
import { getDefaultWebSocketSync } from './utils/getWebSocket.js';
|
|
12
|
-
|
|
13
|
-
export type WebSocketLike = {
|
|
14
|
-
send(data: string | ArrayBufferLike): void;
|
|
15
|
-
close(code?: number): void;
|
|
16
|
-
readyState: number;
|
|
17
|
-
addEventListener?(type: string, listener: (e: unknown) => void): void;
|
|
18
|
-
on?(event: string, cb: (data?: unknown) => void): void;
|
|
19
|
-
};
|
|
20
|
-
export type WebSocketConstructor = new (url: string) => WebSocketLike;
|
|
21
|
-
|
|
22
|
-
export interface WebSocketShardOptions {
|
|
23
|
-
url: string;
|
|
24
|
-
token: string;
|
|
25
|
-
intents: number;
|
|
26
|
-
presence?: GatewayPresenceUpdateData;
|
|
27
|
-
shardId: number;
|
|
28
|
-
numShards: number;
|
|
29
|
-
/** Gateway API version (e.g. "1" for Fluxer). Defaults to "1" when not set. */
|
|
30
|
-
version?: string;
|
|
31
|
-
WebSocket?: WebSocketConstructor;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface WebSocketShardEvents {
|
|
35
|
-
ready: [payload: unknown];
|
|
36
|
-
resumed: [];
|
|
37
|
-
dispatch: [payload: GatewayReceivePayload];
|
|
38
|
-
close: [code: number];
|
|
39
|
-
error: [error: Error];
|
|
40
|
-
debug: [message: string];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const RECONNECT_INITIAL_MS = 1000;
|
|
44
|
-
const RECONNECT_MAX_MS = 45000;
|
|
45
|
-
|
|
46
|
-
export class WebSocketShard extends EventEmitter {
|
|
47
|
-
private ws: WebSocketLike | null = null;
|
|
48
|
-
private readonly options: WebSocketShardOptions;
|
|
49
|
-
private heartbeatInterval: ReturnType<typeof setInterval> | null = null;
|
|
50
|
-
private heartbeatAt = 0;
|
|
51
|
-
/** True until we send a heartbeat; then false until we get HeartbeatAck. Avoids closing before first heartbeat. */
|
|
52
|
-
private lastHeartbeatAck = true;
|
|
53
|
-
private sessionId: string | null = null;
|
|
54
|
-
private seq: number | null = null;
|
|
55
|
-
private destroying = false;
|
|
56
|
-
private readonly url: string;
|
|
57
|
-
private readonly WS: WebSocketConstructor;
|
|
58
|
-
/** Current reconnect delay in ms; resets on successful connect. */
|
|
59
|
-
private reconnectDelayMs = RECONNECT_INITIAL_MS;
|
|
60
|
-
private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
61
|
-
|
|
62
|
-
private scheduleReconnect(): void {
|
|
63
|
-
if (this.destroying) return;
|
|
64
|
-
if (this.reconnectTimeout !== null) return;
|
|
65
|
-
const delay = Math.min(RECONNECT_MAX_MS, this.reconnectDelayMs * (0.75 + Math.random() * 0.5));
|
|
66
|
-
this.reconnectDelayMs = Math.min(RECONNECT_MAX_MS, this.reconnectDelayMs * 1.5);
|
|
67
|
-
this.debug(`Reconnecting in ${Math.round(delay)}ms…`);
|
|
68
|
-
this.reconnectTimeout = setTimeout(() => {
|
|
69
|
-
this.reconnectTimeout = null;
|
|
70
|
-
this.connect();
|
|
71
|
-
}, delay);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
constructor(options: WebSocketShardOptions) {
|
|
75
|
-
super();
|
|
76
|
-
this.options = options;
|
|
77
|
-
this.WS = options.WebSocket ?? (getDefaultWebSocketSync() as unknown as WebSocketConstructor);
|
|
78
|
-
const version = options.version ?? '1';
|
|
79
|
-
const params = new URLSearchParams({ v: version, encoding: 'json' });
|
|
80
|
-
this.url = `${options.url}?${params}`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
get id(): number {
|
|
84
|
-
return this.options.shardId;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
get status(): number {
|
|
88
|
-
if (!this.ws) return 0; // Idle
|
|
89
|
-
switch (this.ws.readyState) {
|
|
90
|
-
case 0:
|
|
91
|
-
return 1; // Connecting
|
|
92
|
-
case 1:
|
|
93
|
-
return 2; // Ready
|
|
94
|
-
case 2:
|
|
95
|
-
return 3; // Closing
|
|
96
|
-
case 3:
|
|
97
|
-
return 0;
|
|
98
|
-
default:
|
|
99
|
-
return 0;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
connect(): void {
|
|
104
|
-
if (this.ws?.readyState === 1) return;
|
|
105
|
-
this.destroying = false;
|
|
106
|
-
this.debug('Connecting');
|
|
107
|
-
const ws = new this.WS(this.url);
|
|
108
|
-
this.ws = ws;
|
|
109
|
-
|
|
110
|
-
const handleMessage = (data: string | Buffer) => {
|
|
111
|
-
try {
|
|
112
|
-
const str = typeof data === 'string' ? data : (data as Buffer).toString();
|
|
113
|
-
this.handlePayload(JSON.parse(str) as GatewayReceivePayload);
|
|
114
|
-
} catch (err) {
|
|
115
|
-
this.emit('error', err instanceof Error ? err : new Error(String(err)));
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const handleClose = (code: number) => {
|
|
120
|
-
this.ws = null;
|
|
121
|
-
this.stopHeartbeat();
|
|
122
|
-
this.emit('close', code);
|
|
123
|
-
this.debug(`Closed: ${code}`);
|
|
124
|
-
if (!this.destroying && shouldReconnectOnClose(code)) {
|
|
125
|
-
this.scheduleReconnect();
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const handleError = (err?: unknown) => {
|
|
130
|
-
const error = err instanceof Error ? err : new Error('WebSocket error');
|
|
131
|
-
this.emit('error', error);
|
|
132
|
-
if (!this.destroying && this.ws) {
|
|
133
|
-
this.ws = null;
|
|
134
|
-
this.stopHeartbeat();
|
|
135
|
-
this.debug('Connection error; will retry…');
|
|
136
|
-
this.scheduleReconnect();
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const handleOpen = () => {
|
|
141
|
-
this.debug('Socket open');
|
|
142
|
-
this.reconnectDelayMs = RECONNECT_INITIAL_MS;
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
if (typeof ws.addEventListener === 'function') {
|
|
146
|
-
ws.addEventListener('open', handleOpen);
|
|
147
|
-
ws.addEventListener('message', (e: unknown) =>
|
|
148
|
-
handleMessage((e as MessageEvent).data as string),
|
|
149
|
-
);
|
|
150
|
-
ws.addEventListener('close', (e: unknown) => handleClose((e as CloseEvent).code));
|
|
151
|
-
ws.addEventListener('error', () => handleError(new Error('WebSocket error')));
|
|
152
|
-
} else if (typeof ws.on === 'function') {
|
|
153
|
-
ws.on('open', handleOpen);
|
|
154
|
-
ws.on('message', (d: unknown) => handleMessage(d as Buffer | string));
|
|
155
|
-
ws.on('close', (code?: unknown) => handleClose((code as number) ?? 1006));
|
|
156
|
-
ws.on('error', (err?: unknown) => handleError(err));
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private debug(message: string): void {
|
|
161
|
-
this.emit('debug', `[Shard ${this.id}] ${message}`);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
private handlePayload(payload: GatewayReceivePayload): void {
|
|
165
|
-
switch (payload.op) {
|
|
166
|
-
case GatewayOpcodes.Hello:
|
|
167
|
-
this.handleHello(payload.d as GatewayHelloData);
|
|
168
|
-
break;
|
|
169
|
-
case GatewayOpcodes.HeartbeatAck:
|
|
170
|
-
this.lastHeartbeatAck = true;
|
|
171
|
-
break;
|
|
172
|
-
case GatewayOpcodes.Dispatch:
|
|
173
|
-
if (payload.t === 'READY') {
|
|
174
|
-
const d = payload.d as { session_id: string };
|
|
175
|
-
this.sessionId = d.session_id;
|
|
176
|
-
this.reconnectDelayMs = RECONNECT_INITIAL_MS;
|
|
177
|
-
this.emit('ready', payload.d);
|
|
178
|
-
} else if (payload.t === 'RESUMED') {
|
|
179
|
-
this.reconnectDelayMs = RECONNECT_INITIAL_MS;
|
|
180
|
-
this.emit('resumed');
|
|
181
|
-
}
|
|
182
|
-
if (payload.s !== undefined) this.seq = payload.s;
|
|
183
|
-
this.emit('dispatch', payload);
|
|
184
|
-
break;
|
|
185
|
-
case GatewayOpcodes.InvalidSession:
|
|
186
|
-
this.debug(`Invalid session (d=${payload.d}), reconnecting`);
|
|
187
|
-
this.sessionId = null;
|
|
188
|
-
this.seq = null;
|
|
189
|
-
this.ws?.close(1000);
|
|
190
|
-
// Let handleClose() own reconnect scheduling for this close.
|
|
191
|
-
break;
|
|
192
|
-
case GatewayOpcodes.Reconnect:
|
|
193
|
-
this.debug('Reconnect requested');
|
|
194
|
-
this.ws?.close(1000);
|
|
195
|
-
setTimeout(() => this.connect(), 100);
|
|
196
|
-
break;
|
|
197
|
-
default:
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
private handleHello(data: GatewayHelloData): void {
|
|
203
|
-
const jitter = Math.random() * data.heartbeat_interval;
|
|
204
|
-
this.heartbeatAt = Date.now() + jitter;
|
|
205
|
-
this.startHeartbeat(data.heartbeat_interval);
|
|
206
|
-
|
|
207
|
-
if (this.sessionId && this.seq !== null) {
|
|
208
|
-
this.send({
|
|
209
|
-
op: GatewayOpcodes.Resume,
|
|
210
|
-
d: {
|
|
211
|
-
token: this.options.token,
|
|
212
|
-
session_id: this.sessionId,
|
|
213
|
-
seq: this.seq,
|
|
214
|
-
} as GatewayResumeData,
|
|
215
|
-
});
|
|
216
|
-
} else {
|
|
217
|
-
const identify: GatewayIdentifyData = {
|
|
218
|
-
token: this.options.token,
|
|
219
|
-
intents: this.options.intents,
|
|
220
|
-
properties: {
|
|
221
|
-
os: process.platform ?? 'unknown',
|
|
222
|
-
browser: 'erin.js',
|
|
223
|
-
device: 'erin.js',
|
|
224
|
-
},
|
|
225
|
-
};
|
|
226
|
-
if (this.options.presence) identify.presence = this.options.presence;
|
|
227
|
-
this.send({ op: GatewayOpcodes.Identify, d: identify });
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
private startHeartbeat(interval: number): void {
|
|
232
|
-
this.stopHeartbeat();
|
|
233
|
-
this.lastHeartbeatAck = true; // no heartbeat sent yet → don't treat as missed ack
|
|
234
|
-
this.heartbeatInterval = setInterval(() => {
|
|
235
|
-
if (!this.lastHeartbeatAck && this.seq !== null) {
|
|
236
|
-
this.debug('Heartbeat ack missed; reconnecting');
|
|
237
|
-
this.ws?.close(1000);
|
|
238
|
-
if (!this.destroying) this.scheduleReconnect();
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
this.lastHeartbeatAck = false;
|
|
242
|
-
this.send({ op: GatewayOpcodes.Heartbeat, d: this.seq ?? null });
|
|
243
|
-
}, interval);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
private stopHeartbeat(): void {
|
|
247
|
-
if (this.heartbeatInterval) {
|
|
248
|
-
clearInterval(this.heartbeatInterval);
|
|
249
|
-
this.heartbeatInterval = null;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
send(payload: GatewaySendPayload): void {
|
|
254
|
-
if (this.ws?.readyState !== 1) return;
|
|
255
|
-
this.ws.send(JSON.stringify(payload));
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
destroy(): void {
|
|
259
|
-
this.destroying = true;
|
|
260
|
-
if (this.reconnectTimeout) {
|
|
261
|
-
clearTimeout(this.reconnectTimeout);
|
|
262
|
-
this.reconnectTimeout = null;
|
|
263
|
-
}
|
|
264
|
-
this.stopHeartbeat();
|
|
265
|
-
this.ws?.close(1000);
|
|
266
|
-
this.ws = null;
|
|
267
|
-
this.sessionId = null;
|
|
268
|
-
this.seq = null;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/** Close codes after which we should reconnect (normal closure, server ask, or transient/network issues). */
|
|
273
|
-
function shouldReconnectOnClose(code: number): boolean {
|
|
274
|
-
switch (code) {
|
|
275
|
-
case 1000: // Normal Closure (server may close with this to ask for reconnect)
|
|
276
|
-
case 1001: // Going Away
|
|
277
|
-
case 1011: // Internal Error (server hit unexpected condition; often transient)
|
|
278
|
-
case 1005: // No Status Received
|
|
279
|
-
case 1006: // Abnormal Closure (network drop, server crash)
|
|
280
|
-
case 1012: // Service Restart
|
|
281
|
-
case 1013: // Try Again Later
|
|
282
|
-
case 1014: // Bad Gateway
|
|
283
|
-
case 1015: // TLS Handshake Failed
|
|
284
|
-
return true;
|
|
285
|
-
case 4000: // Unknown error
|
|
286
|
-
case 4007: // Invalid seq
|
|
287
|
-
case 4009: // Session timeout
|
|
288
|
-
case 4010: // Invalid shard
|
|
289
|
-
case 4011: // Sharding required
|
|
290
|
-
case 4012: // Invalid API version (after fix, reconnect is safe)
|
|
291
|
-
case 4013: // Ack backpressure (server event buffer full; transient, safe to retry)
|
|
292
|
-
return true;
|
|
293
|
-
default:
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
}
|