@neontechspace/fluxerly 1000.0.0-nightly.12
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/CHANGELOG.md +833 -0
- package/LICENSE +201 -0
- package/README.md +129 -0
- package/agents/AGENTS.md +195 -0
- package/dist/api/default/application.d.ts +34 -0
- package/dist/api/default/application.d.ts.map +1 -0
- package/dist/api/default/application.js +2 -0
- package/dist/api/default/application.js.map +1 -0
- package/dist/api/default/attachments.d.ts +89 -0
- package/dist/api/default/attachments.d.ts.map +1 -0
- package/dist/api/default/attachments.js +2 -0
- package/dist/api/default/attachments.js.map +1 -0
- package/dist/api/default/audit-logs.d.ts +48 -0
- package/dist/api/default/audit-logs.d.ts.map +1 -0
- package/dist/api/default/audit-logs.js +2 -0
- package/dist/api/default/audit-logs.js.map +1 -0
- package/dist/api/default/bot.d.ts +200 -0
- package/dist/api/default/bot.d.ts.map +1 -0
- package/dist/api/default/bot.js +309 -0
- package/dist/api/default/bot.js.map +1 -0
- package/dist/api/default/cache.d.ts +105 -0
- package/dist/api/default/cache.d.ts.map +1 -0
- package/dist/api/default/cache.js +2 -0
- package/dist/api/default/cache.js.map +1 -0
- package/dist/api/default/channels.d.ts +249 -0
- package/dist/api/default/channels.d.ts.map +1 -0
- package/dist/api/default/channels.js +2 -0
- package/dist/api/default/channels.js.map +1 -0
- package/dist/api/default/client.d.ts +528 -0
- package/dist/api/default/client.d.ts.map +1 -0
- package/dist/api/default/client.js +301 -0
- package/dist/api/default/client.js.map +1 -0
- package/dist/api/default/collectors.d.ts +76 -0
- package/dist/api/default/collectors.d.ts.map +1 -0
- package/dist/api/default/collectors.js +2 -0
- package/dist/api/default/collectors.js.map +1 -0
- package/dist/api/default/commands.d.ts +91 -0
- package/dist/api/default/commands.d.ts.map +1 -0
- package/dist/api/default/commands.js +92 -0
- package/dist/api/default/commands.js.map +1 -0
- package/dist/api/default/direct-messages.d.ts +111 -0
- package/dist/api/default/direct-messages.d.ts.map +1 -0
- package/dist/api/default/direct-messages.js +2 -0
- package/dist/api/default/direct-messages.js.map +1 -0
- package/dist/api/default/discovery.d.ts +76 -0
- package/dist/api/default/discovery.d.ts.map +1 -0
- package/dist/api/default/discovery.js +2 -0
- package/dist/api/default/discovery.js.map +1 -0
- package/dist/api/default/emojis.d.ts +88 -0
- package/dist/api/default/emojis.d.ts.map +1 -0
- package/dist/api/default/emojis.js +2 -0
- package/dist/api/default/emojis.js.map +1 -0
- package/dist/api/default/events.d.ts +127 -0
- package/dist/api/default/events.d.ts.map +1 -0
- package/dist/api/default/events.js +2 -0
- package/dist/api/default/events.js.map +1 -0
- package/dist/api/default/gateway.d.ts +62 -0
- package/dist/api/default/gateway.d.ts.map +1 -0
- package/dist/api/default/gateway.js +2 -0
- package/dist/api/default/gateway.js.map +1 -0
- package/dist/api/default/guards.d.ts +87 -0
- package/dist/api/default/guards.d.ts.map +1 -0
- package/dist/api/default/guards.js +78 -0
- package/dist/api/default/guards.js.map +1 -0
- package/dist/api/default/guilds.d.ts +230 -0
- package/dist/api/default/guilds.d.ts.map +1 -0
- package/dist/api/default/guilds.js +2 -0
- package/dist/api/default/guilds.js.map +1 -0
- package/dist/api/default/helpers.d.ts +79 -0
- package/dist/api/default/helpers.d.ts.map +1 -0
- package/dist/api/default/helpers.js +79 -0
- package/dist/api/default/helpers.js.map +1 -0
- package/dist/api/default/instance.d.ts +47 -0
- package/dist/api/default/instance.d.ts.map +1 -0
- package/dist/api/default/instance.js +2 -0
- package/dist/api/default/instance.js.map +1 -0
- package/dist/api/default/invites.d.ts +57 -0
- package/dist/api/default/invites.d.ts.map +1 -0
- package/dist/api/default/invites.js +2 -0
- package/dist/api/default/invites.js.map +1 -0
- package/dist/api/default/logging.d.ts +37 -0
- package/dist/api/default/logging.d.ts.map +1 -0
- package/dist/api/default/logging.js +2 -0
- package/dist/api/default/logging.js.map +1 -0
- package/dist/api/default/members.d.ts +442 -0
- package/dist/api/default/members.d.ts.map +1 -0
- package/dist/api/default/members.js +2 -0
- package/dist/api/default/members.js.map +1 -0
- package/dist/api/default/messages.d.ts +898 -0
- package/dist/api/default/messages.d.ts.map +1 -0
- package/dist/api/default/messages.js +2 -0
- package/dist/api/default/messages.js.map +1 -0
- package/dist/api/default/oauth.d.ts +168 -0
- package/dist/api/default/oauth.d.ts.map +1 -0
- package/dist/api/default/oauth.js +84 -0
- package/dist/api/default/oauth.js.map +1 -0
- package/dist/api/default/permissions.d.ts +44 -0
- package/dist/api/default/permissions.d.ts.map +1 -0
- package/dist/api/default/permissions.js +2 -0
- package/dist/api/default/permissions.js.map +1 -0
- package/dist/api/default/presence.d.ts +88 -0
- package/dist/api/default/presence.d.ts.map +1 -0
- package/dist/api/default/presence.js +2 -0
- package/dist/api/default/presence.js.map +1 -0
- package/dist/api/default/rest.d.ts +28 -0
- package/dist/api/default/rest.d.ts.map +1 -0
- package/dist/api/default/rest.js +2 -0
- package/dist/api/default/rest.js.map +1 -0
- package/dist/api/default/results.d.ts +31 -0
- package/dist/api/default/results.d.ts.map +1 -0
- package/dist/api/default/results.js +14 -0
- package/dist/api/default/results.js.map +1 -0
- package/dist/api/default/roles.d.ts +119 -0
- package/dist/api/default/roles.d.ts.map +1 -0
- package/dist/api/default/roles.js +2 -0
- package/dist/api/default/roles.js.map +1 -0
- package/dist/api/default/stickers.d.ts +92 -0
- package/dist/api/default/stickers.d.ts.map +1 -0
- package/dist/api/default/stickers.js +2 -0
- package/dist/api/default/stickers.js.map +1 -0
- package/dist/api/default/supervisor.d.ts +51 -0
- package/dist/api/default/supervisor.d.ts.map +1 -0
- package/dist/api/default/supervisor.js +53 -0
- package/dist/api/default/supervisor.js.map +1 -0
- package/dist/api/default/threads.d.ts +158 -0
- package/dist/api/default/threads.d.ts.map +1 -0
- package/dist/api/default/threads.js +2 -0
- package/dist/api/default/threads.js.map +1 -0
- package/dist/api/default/users.d.ts +73 -0
- package/dist/api/default/users.d.ts.map +1 -0
- package/dist/api/default/users.js +2 -0
- package/dist/api/default/users.js.map +1 -0
- package/dist/api/default/webhook-client.d.ts +149 -0
- package/dist/api/default/webhook-client.d.ts.map +1 -0
- package/dist/api/default/webhook-client.js +69 -0
- package/dist/api/default/webhook-client.js.map +1 -0
- package/dist/api/default/webhooks.d.ts +62 -0
- package/dist/api/default/webhooks.d.ts.map +1 -0
- package/dist/api/default/webhooks.js +2 -0
- package/dist/api/default/webhooks.js.map +1 -0
- package/dist/api/effect/application.d.ts +29 -0
- package/dist/api/effect/application.d.ts.map +1 -0
- package/dist/api/effect/application.js +2 -0
- package/dist/api/effect/application.js.map +1 -0
- package/dist/api/effect/attachments.d.ts +84 -0
- package/dist/api/effect/attachments.d.ts.map +1 -0
- package/dist/api/effect/attachments.js +2 -0
- package/dist/api/effect/attachments.js.map +1 -0
- package/dist/api/effect/audit-logs.d.ts +42 -0
- package/dist/api/effect/audit-logs.d.ts.map +1 -0
- package/dist/api/effect/audit-logs.js +2 -0
- package/dist/api/effect/audit-logs.js.map +1 -0
- package/dist/api/effect/bot.d.ts +233 -0
- package/dist/api/effect/bot.d.ts.map +1 -0
- package/dist/api/effect/bot.js +230 -0
- package/dist/api/effect/bot.js.map +1 -0
- package/dist/api/effect/cache.d.ts +103 -0
- package/dist/api/effect/cache.d.ts.map +1 -0
- package/dist/api/effect/cache.js +2 -0
- package/dist/api/effect/cache.js.map +1 -0
- package/dist/api/effect/channels.d.ts +231 -0
- package/dist/api/effect/channels.d.ts.map +1 -0
- package/dist/api/effect/channels.js +2 -0
- package/dist/api/effect/channels.js.map +1 -0
- package/dist/api/effect/client.d.ts +622 -0
- package/dist/api/effect/client.d.ts.map +1 -0
- package/dist/api/effect/client.js +191 -0
- package/dist/api/effect/client.js.map +1 -0
- package/dist/api/effect/collectors.d.ts +90 -0
- package/dist/api/effect/collectors.d.ts.map +1 -0
- package/dist/api/effect/collectors.js +2 -0
- package/dist/api/effect/collectors.js.map +1 -0
- package/dist/api/effect/commands.d.ts +86 -0
- package/dist/api/effect/commands.d.ts.map +1 -0
- package/dist/api/effect/commands.js +87 -0
- package/dist/api/effect/commands.js.map +1 -0
- package/dist/api/effect/direct-messages.d.ts +102 -0
- package/dist/api/effect/direct-messages.d.ts.map +1 -0
- package/dist/api/effect/direct-messages.js +2 -0
- package/dist/api/effect/direct-messages.js.map +1 -0
- package/dist/api/effect/discovery.d.ts +68 -0
- package/dist/api/effect/discovery.d.ts.map +1 -0
- package/dist/api/effect/discovery.js +2 -0
- package/dist/api/effect/discovery.js.map +1 -0
- package/dist/api/effect/emojis.d.ts +77 -0
- package/dist/api/effect/emojis.d.ts.map +1 -0
- package/dist/api/effect/emojis.js +2 -0
- package/dist/api/effect/emojis.js.map +1 -0
- package/dist/api/effect/events.d.ts +78 -0
- package/dist/api/effect/events.d.ts.map +1 -0
- package/dist/api/effect/events.js +12 -0
- package/dist/api/effect/events.js.map +1 -0
- package/dist/api/effect/failures.d.ts +14 -0
- package/dist/api/effect/failures.d.ts.map +1 -0
- package/dist/api/effect/failures.js +2 -0
- package/dist/api/effect/failures.js.map +1 -0
- package/dist/api/effect/gateway.d.ts +63 -0
- package/dist/api/effect/gateway.d.ts.map +1 -0
- package/dist/api/effect/gateway.js +2 -0
- package/dist/api/effect/gateway.js.map +1 -0
- package/dist/api/effect/guards.d.ts +91 -0
- package/dist/api/effect/guards.d.ts.map +1 -0
- package/dist/api/effect/guards.js +94 -0
- package/dist/api/effect/guards.js.map +1 -0
- package/dist/api/effect/guilds.d.ts +221 -0
- package/dist/api/effect/guilds.d.ts.map +1 -0
- package/dist/api/effect/guilds.js +2 -0
- package/dist/api/effect/guilds.js.map +1 -0
- package/dist/api/effect/helpers.d.ts +300 -0
- package/dist/api/effect/helpers.d.ts.map +1 -0
- package/dist/api/effect/helpers.js +156 -0
- package/dist/api/effect/helpers.js.map +1 -0
- package/dist/api/effect/hierarchy.d.ts +26 -0
- package/dist/api/effect/hierarchy.d.ts.map +1 -0
- package/dist/api/effect/hierarchy.js +26 -0
- package/dist/api/effect/hierarchy.js.map +1 -0
- package/dist/api/effect/instance.d.ts +46 -0
- package/dist/api/effect/instance.d.ts.map +1 -0
- package/dist/api/effect/instance.js +8 -0
- package/dist/api/effect/instance.js.map +1 -0
- package/dist/api/effect/invites.d.ts +49 -0
- package/dist/api/effect/invites.d.ts.map +1 -0
- package/dist/api/effect/invites.js +2 -0
- package/dist/api/effect/invites.js.map +1 -0
- package/dist/api/effect/logging.d.ts +37 -0
- package/dist/api/effect/logging.d.ts.map +1 -0
- package/dist/api/effect/logging.js +2 -0
- package/dist/api/effect/logging.js.map +1 -0
- package/dist/api/effect/members.d.ts +433 -0
- package/dist/api/effect/members.d.ts.map +1 -0
- package/dist/api/effect/members.js +2 -0
- package/dist/api/effect/members.js.map +1 -0
- package/dist/api/effect/messages.d.ts +877 -0
- package/dist/api/effect/messages.d.ts.map +1 -0
- package/dist/api/effect/messages.js +2 -0
- package/dist/api/effect/messages.js.map +1 -0
- package/dist/api/effect/oauth.d.ts +148 -0
- package/dist/api/effect/oauth.d.ts.map +1 -0
- package/dist/api/effect/oauth.js +51 -0
- package/dist/api/effect/oauth.js.map +1 -0
- package/dist/api/effect/permissions.d.ts +41 -0
- package/dist/api/effect/permissions.d.ts.map +1 -0
- package/dist/api/effect/permissions.js +2 -0
- package/dist/api/effect/permissions.js.map +1 -0
- package/dist/api/effect/presence.d.ts +83 -0
- package/dist/api/effect/presence.d.ts.map +1 -0
- package/dist/api/effect/presence.js +2 -0
- package/dist/api/effect/presence.js.map +1 -0
- package/dist/api/effect/rest.d.ts +27 -0
- package/dist/api/effect/rest.d.ts.map +1 -0
- package/dist/api/effect/rest.js +2 -0
- package/dist/api/effect/rest.js.map +1 -0
- package/dist/api/effect/roles.d.ts +104 -0
- package/dist/api/effect/roles.d.ts.map +1 -0
- package/dist/api/effect/roles.js +2 -0
- package/dist/api/effect/roles.js.map +1 -0
- package/dist/api/effect/service.d.ts +76 -0
- package/dist/api/effect/service.d.ts.map +1 -0
- package/dist/api/effect/service.js +79 -0
- package/dist/api/effect/service.js.map +1 -0
- package/dist/api/effect/stickers.d.ts +81 -0
- package/dist/api/effect/stickers.d.ts.map +1 -0
- package/dist/api/effect/stickers.js +2 -0
- package/dist/api/effect/stickers.js.map +1 -0
- package/dist/api/effect/supervisor.d.ts +56 -0
- package/dist/api/effect/supervisor.d.ts.map +1 -0
- package/dist/api/effect/supervisor.js +58 -0
- package/dist/api/effect/supervisor.js.map +1 -0
- package/dist/api/effect/threads.d.ts +154 -0
- package/dist/api/effect/threads.d.ts.map +1 -0
- package/dist/api/effect/threads.js +2 -0
- package/dist/api/effect/threads.js.map +1 -0
- package/dist/api/effect/users.d.ts +62 -0
- package/dist/api/effect/users.d.ts.map +1 -0
- package/dist/api/effect/users.js +2 -0
- package/dist/api/effect/users.js.map +1 -0
- package/dist/api/effect/webhook-client.d.ts +140 -0
- package/dist/api/effect/webhook-client.d.ts.map +1 -0
- package/dist/api/effect/webhook-client.js +50 -0
- package/dist/api/effect/webhook-client.js.map +1 -0
- package/dist/api/effect/webhooks.d.ts +54 -0
- package/dist/api/effect/webhooks.d.ts.map +1 -0
- package/dist/api/effect/webhooks.js +2 -0
- package/dist/api/effect/webhooks.js.map +1 -0
- package/dist/api-errors.d.ts +609 -0
- package/dist/api-errors.d.ts.map +1 -0
- package/dist/api-errors.js +589 -0
- package/dist/api-errors.js.map +1 -0
- package/dist/application.d.ts +85 -0
- package/dist/application.d.ts.map +1 -0
- package/dist/application.js +44 -0
- package/dist/application.js.map +1 -0
- package/dist/assets.d.ts +197 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +419 -0
- package/dist/assets.js.map +1 -0
- package/dist/attachments.d.ts +400 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +88 -0
- package/dist/attachments.js.map +1 -0
- package/dist/audit-logs.d.ts +292 -0
- package/dist/audit-logs.d.ts.map +1 -0
- package/dist/audit-logs.js +46 -0
- package/dist/audit-logs.js.map +1 -0
- package/dist/bot-runner.d.ts +69 -0
- package/dist/bot-runner.d.ts.map +1 -0
- package/dist/bot-runner.js +41 -0
- package/dist/bot-runner.js.map +1 -0
- package/dist/builders.d.ts +153 -0
- package/dist/builders.d.ts.map +1 -0
- package/dist/builders.js +326 -0
- package/dist/builders.js.map +1 -0
- package/dist/cache.d.ts +187 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +2 -0
- package/dist/cache.js.map +1 -0
- package/dist/channels.d.ts +903 -0
- package/dist/channels.d.ts.map +1 -0
- package/dist/channels.js +125 -0
- package/dist/channels.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +65 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +645 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -0
- package/dist/collectors.d.ts +205 -0
- package/dist/collectors.d.ts.map +1 -0
- package/dist/collectors.js +71 -0
- package/dist/collectors.js.map +1 -0
- package/dist/colors.d.ts +55 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +40 -0
- package/dist/colors.js.map +1 -0
- package/dist/command-arguments.d.ts +353 -0
- package/dist/command-arguments.d.ts.map +1 -0
- package/dist/command-arguments.js +2 -0
- package/dist/command-arguments.js.map +1 -0
- package/dist/command-help.d.ts +54 -0
- package/dist/command-help.d.ts.map +1 -0
- package/dist/command-help.js +2 -0
- package/dist/command-help.js.map +1 -0
- package/dist/commands.d.ts +328 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +62 -0
- package/dist/commands.js.map +1 -0
- package/dist/counts.d.ts +124 -0
- package/dist/counts.d.ts.map +1 -0
- package/dist/counts.js +52 -0
- package/dist/counts.js.map +1 -0
- package/dist/default-commands.d.ts +400 -0
- package/dist/default-commands.d.ts.map +1 -0
- package/dist/default-commands.js +488 -0
- package/dist/default-commands.js.map +1 -0
- package/dist/default-supervisor.d.ts +111 -0
- package/dist/default-supervisor.d.ts.map +1 -0
- package/dist/default-supervisor.js +277 -0
- package/dist/default-supervisor.js.map +1 -0
- package/dist/discovery.d.ts +223 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +18 -0
- package/dist/discovery.js.map +1 -0
- package/dist/effect-testing.d.ts +388 -0
- package/dist/effect-testing.d.ts.map +1 -0
- package/dist/effect-testing.js +261 -0
- package/dist/effect-testing.js.map +1 -0
- package/dist/effect.d.ts +220 -0
- package/dist/effect.d.ts.map +1 -0
- package/dist/effect.js +101 -0
- package/dist/effect.js.map +1 -0
- package/dist/embeds.d.ts +243 -0
- package/dist/embeds.d.ts.map +1 -0
- package/dist/embeds.js +2 -0
- package/dist/embeds.js.map +1 -0
- package/dist/error-tools.d.ts +101 -0
- package/dist/error-tools.d.ts.map +1 -0
- package/dist/error-tools.js +125 -0
- package/dist/error-tools.js.map +1 -0
- package/dist/errors.d.ts +386 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +440 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +798 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +2 -0
- package/dist/events.js.map +1 -0
- package/dist/expressions.d.ts +188 -0
- package/dist/expressions.d.ts.map +1 -0
- package/dist/expressions.js +2 -0
- package/dist/expressions.js.map +1 -0
- package/dist/failures.d.ts +53 -0
- package/dist/failures.d.ts.map +1 -0
- package/dist/failures.js +2 -0
- package/dist/failures.js.map +1 -0
- package/dist/gateway.d.ts +48 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +60 -0
- package/dist/gateway.js.map +1 -0
- package/dist/guilds.d.ts +923 -0
- package/dist/guilds.d.ts.map +1 -0
- package/dist/guilds.js +204 -0
- package/dist/guilds.js.map +1 -0
- package/dist/helpers.d.ts +423 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +434 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +228 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/input-validation.d.ts +51 -0
- package/dist/input-validation.d.ts.map +1 -0
- package/dist/input-validation.js +34 -0
- package/dist/input-validation.js.map +1 -0
- package/dist/instance.d.ts +101 -0
- package/dist/instance.d.ts.map +1 -0
- package/dist/instance.js +2 -0
- package/dist/instance.js.map +1 -0
- package/dist/internal/agents-section.d.ts +22 -0
- package/dist/internal/agents-section.d.ts.map +1 -0
- package/dist/internal/agents-section.js +101 -0
- package/dist/internal/agents-section.js.map +1 -0
- package/dist/internal/application.d.ts +16 -0
- package/dist/internal/application.d.ts.map +1 -0
- package/dist/internal/application.js +33 -0
- package/dist/internal/application.js.map +1 -0
- package/dist/internal/attachment-refresh.d.ts +18 -0
- package/dist/internal/attachment-refresh.d.ts.map +1 -0
- package/dist/internal/attachment-refresh.js +39 -0
- package/dist/internal/attachment-refresh.js.map +1 -0
- package/dist/internal/attachments.d.ts +45 -0
- package/dist/internal/attachments.d.ts.map +1 -0
- package/dist/internal/attachments.js +230 -0
- package/dist/internal/attachments.js.map +1 -0
- package/dist/internal/audit-logs.d.ts +13 -0
- package/dist/internal/audit-logs.d.ts.map +1 -0
- package/dist/internal/audit-logs.js +295 -0
- package/dist/internal/audit-logs.js.map +1 -0
- package/dist/internal/audit.d.ts +12 -0
- package/dist/internal/audit.d.ts.map +1 -0
- package/dist/internal/audit.js +22 -0
- package/dist/internal/audit.js.map +1 -0
- package/dist/internal/binding/default-adapters.d.ts +22 -0
- package/dist/internal/binding/default-adapters.d.ts.map +1 -0
- package/dist/internal/binding/default-adapters.js +304 -0
- package/dist/internal/binding/default-adapters.js.map +1 -0
- package/dist/internal/binding/default.d.ts +45 -0
- package/dist/internal/binding/default.d.ts.map +1 -0
- package/dist/internal/binding/default.js +86 -0
- package/dist/internal/binding/default.js.map +1 -0
- package/dist/internal/binding/execute.d.ts +51 -0
- package/dist/internal/binding/execute.d.ts.map +1 -0
- package/dist/internal/binding/execute.js +123 -0
- package/dist/internal/binding/execute.js.map +1 -0
- package/dist/internal/binding/native-adapters.d.ts +23 -0
- package/dist/internal/binding/native-adapters.d.ts.map +1 -0
- package/dist/internal/binding/native-adapters.js +90 -0
- package/dist/internal/binding/native-adapters.js.map +1 -0
- package/dist/internal/binding/native.d.ts +41 -0
- package/dist/internal/binding/native.d.ts.map +1 -0
- package/dist/internal/binding/native.js +34 -0
- package/dist/internal/binding/native.js.map +1 -0
- package/dist/internal/binding/operations.d.ts +361 -0
- package/dist/internal/binding/operations.d.ts.map +1 -0
- package/dist/internal/binding/operations.js +272 -0
- package/dist/internal/binding/operations.js.map +1 -0
- package/dist/internal/bot-runner.d.ts +65 -0
- package/dist/internal/bot-runner.d.ts.map +1 -0
- package/dist/internal/bot-runner.js +363 -0
- package/dist/internal/bot-runner.js.map +1 -0
- package/dist/internal/cache-changes.d.ts +43 -0
- package/dist/internal/cache-changes.d.ts.map +1 -0
- package/dist/internal/cache-changes.js +320 -0
- package/dist/internal/cache-changes.js.map +1 -0
- package/dist/internal/cache.d.ts +57 -0
- package/dist/internal/cache.d.ts.map +1 -0
- package/dist/internal/cache.js +318 -0
- package/dist/internal/cache.js.map +1 -0
- package/dist/internal/calls.d.ts +16 -0
- package/dist/internal/calls.d.ts.map +1 -0
- package/dist/internal/calls.js +108 -0
- package/dist/internal/calls.js.map +1 -0
- package/dist/internal/channel-cache.d.ts +69 -0
- package/dist/internal/channel-cache.d.ts.map +1 -0
- package/dist/internal/channel-cache.js +413 -0
- package/dist/internal/channel-cache.js.map +1 -0
- package/dist/internal/channel-decode.d.ts +44 -0
- package/dist/internal/channel-decode.d.ts.map +1 -0
- package/dist/internal/channel-decode.js +377 -0
- package/dist/internal/channel-decode.js.map +1 -0
- package/dist/internal/channels.d.ts +60 -0
- package/dist/internal/channels.d.ts.map +1 -0
- package/dist/internal/channels.js +605 -0
- package/dist/internal/channels.js.map +1 -0
- package/dist/internal/client/backoff.d.ts +42 -0
- package/dist/internal/client/backoff.d.ts.map +1 -0
- package/dist/internal/client/backoff.js +36 -0
- package/dist/internal/client/backoff.js.map +1 -0
- package/dist/internal/client/configuration-fields.d.ts +14 -0
- package/dist/internal/client/configuration-fields.d.ts.map +1 -0
- package/dist/internal/client/configuration-fields.js +11 -0
- package/dist/internal/client/configuration-fields.js.map +1 -0
- package/dist/internal/client/drain.d.ts +33 -0
- package/dist/internal/client/drain.d.ts.map +1 -0
- package/dist/internal/client/drain.js +109 -0
- package/dist/internal/client/drain.js.map +1 -0
- package/dist/internal/client/intake.d.ts +27 -0
- package/dist/internal/client/intake.d.ts.map +1 -0
- package/dist/internal/client/intake.js +198 -0
- package/dist/internal/client/intake.js.map +1 -0
- package/dist/internal/client/lifetime.d.ts +35 -0
- package/dist/internal/client/lifetime.d.ts.map +1 -0
- package/dist/internal/client/lifetime.js +109 -0
- package/dist/internal/client/lifetime.js.map +1 -0
- package/dist/internal/client/shard-loop.d.ts +93 -0
- package/dist/internal/client/shard-loop.d.ts.map +1 -0
- package/dist/internal/client/shard-loop.js +452 -0
- package/dist/internal/client/shard-loop.js.map +1 -0
- package/dist/internal/client-registry.d.ts +26 -0
- package/dist/internal/client-registry.d.ts.map +1 -0
- package/dist/internal/client-registry.js +11 -0
- package/dist/internal/client-registry.js.map +1 -0
- package/dist/internal/client.d.ts +189 -0
- package/dist/internal/client.d.ts.map +1 -0
- package/dist/internal/client.js +1935 -0
- package/dist/internal/client.js.map +1 -0
- package/dist/internal/clock.d.ts +9 -0
- package/dist/internal/clock.d.ts.map +1 -0
- package/dist/internal/clock.js +5 -0
- package/dist/internal/clock.js.map +1 -0
- package/dist/internal/code-catalogue.d.ts +712 -0
- package/dist/internal/code-catalogue.d.ts.map +1 -0
- package/dist/internal/code-catalogue.js +655 -0
- package/dist/internal/code-catalogue.js.map +1 -0
- package/dist/internal/collector.d.ts +34 -0
- package/dist/internal/collector.d.ts.map +1 -0
- package/dist/internal/collector.js +400 -0
- package/dist/internal/collector.js.map +1 -0
- package/dist/internal/command-arguments.d.ts +29 -0
- package/dist/internal/command-arguments.d.ts.map +1 -0
- package/dist/internal/command-arguments.js +484 -0
- package/dist/internal/command-arguments.js.map +1 -0
- package/dist/internal/command-guards.d.ts +57 -0
- package/dist/internal/command-guards.d.ts.map +1 -0
- package/dist/internal/command-guards.js +81 -0
- package/dist/internal/command-guards.js.map +1 -0
- package/dist/internal/command-help.d.ts +15 -0
- package/dist/internal/command-help.d.ts.map +1 -0
- package/dist/internal/command-help.js +121 -0
- package/dist/internal/command-help.js.map +1 -0
- package/dist/internal/commands.d.ts +212 -0
- package/dist/internal/commands.d.ts.map +1 -0
- package/dist/internal/commands.js +1004 -0
- package/dist/internal/commands.js.map +1 -0
- package/dist/internal/configuration.d.ts +86 -0
- package/dist/internal/configuration.d.ts.map +1 -0
- package/dist/internal/configuration.js +401 -0
- package/dist/internal/configuration.js.map +1 -0
- package/dist/internal/counts.d.ts +33 -0
- package/dist/internal/counts.d.ts.map +1 -0
- package/dist/internal/counts.js +348 -0
- package/dist/internal/counts.js.map +1 -0
- package/dist/internal/decode/primitives.d.ts +30 -0
- package/dist/internal/decode/primitives.d.ts.map +1 -0
- package/dist/internal/decode/primitives.js +56 -0
- package/dist/internal/decode/primitives.js.map +1 -0
- package/dist/internal/decode/timestamp.d.ts +13 -0
- package/dist/internal/decode/timestamp.d.ts.map +1 -0
- package/dist/internal/decode/timestamp.js +27 -0
- package/dist/internal/decode/timestamp.js.map +1 -0
- package/dist/internal/decode/trace.d.ts +11 -0
- package/dist/internal/decode/trace.d.ts.map +1 -0
- package/dist/internal/decode/trace.js +69 -0
- package/dist/internal/decode/trace.js.map +1 -0
- package/dist/internal/defects.d.ts +48 -0
- package/dist/internal/defects.d.ts.map +1 -0
- package/dist/internal/defects.js +100 -0
- package/dist/internal/defects.js.map +1 -0
- package/dist/internal/effect-failures.d.ts +12 -0
- package/dist/internal/effect-failures.d.ts.map +1 -0
- package/dist/internal/effect-failures.js +45 -0
- package/dist/internal/effect-failures.js.map +1 -0
- package/dist/internal/embeds.d.ts +12 -0
- package/dist/internal/embeds.d.ts.map +1 -0
- package/dist/internal/embeds.js +308 -0
- package/dist/internal/embeds.js.map +1 -0
- package/dist/internal/events.d.ts +156 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +1071 -0
- package/dist/internal/events.js.map +1 -0
- package/dist/internal/expiry-queue.d.ts +42 -0
- package/dist/internal/expiry-queue.d.ts.map +1 -0
- package/dist/internal/expiry-queue.js +138 -0
- package/dist/internal/expiry-queue.js.map +1 -0
- package/dist/internal/expressions.d.ts +35 -0
- package/dist/internal/expressions.d.ts.map +1 -0
- package/dist/internal/expressions.js +311 -0
- package/dist/internal/expressions.js.map +1 -0
- package/dist/internal/failures.d.ts +107 -0
- package/dist/internal/failures.d.ts.map +1 -0
- package/dist/internal/failures.js +416 -0
- package/dist/internal/failures.js.map +1 -0
- package/dist/internal/field-text.d.ts +10 -0
- package/dist/internal/field-text.d.ts.map +1 -0
- package/dist/internal/field-text.js +37 -0
- package/dist/internal/field-text.js.map +1 -0
- package/dist/internal/gateway/commands.d.ts +92 -0
- package/dist/internal/gateway/commands.d.ts.map +1 -0
- package/dist/internal/gateway/commands.js +223 -0
- package/dist/internal/gateway/commands.js.map +1 -0
- package/dist/internal/gateway/dispatch-table.d.ts +42 -0
- package/dist/internal/gateway/dispatch-table.d.ts.map +1 -0
- package/dist/internal/gateway/dispatch-table.js +288 -0
- package/dist/internal/gateway/dispatch-table.js.map +1 -0
- package/dist/internal/gateway/event-dispatches.d.ts +97 -0
- package/dist/internal/gateway/event-dispatches.d.ts.map +1 -0
- package/dist/internal/gateway/event-dispatches.js +172 -0
- package/dist/internal/gateway/event-dispatches.js.map +1 -0
- package/dist/internal/gateway/frames.d.ts +45 -0
- package/dist/internal/gateway/frames.d.ts.map +1 -0
- package/dist/internal/gateway/frames.js +121 -0
- package/dist/internal/gateway/frames.js.map +1 -0
- package/dist/internal/gateway/options.d.ts +24 -0
- package/dist/internal/gateway/options.d.ts.map +1 -0
- package/dist/internal/gateway/options.js +103 -0
- package/dist/internal/gateway/options.js.map +1 -0
- package/dist/internal/gateway/session.d.ts +104 -0
- package/dist/internal/gateway/session.d.ts.map +1 -0
- package/dist/internal/gateway/session.js +420 -0
- package/dist/internal/gateway/session.js.map +1 -0
- package/dist/internal/gateway-requests.d.ts +10 -0
- package/dist/internal/gateway-requests.d.ts.map +1 -0
- package/dist/internal/gateway-requests.js +26 -0
- package/dist/internal/gateway-requests.js.map +1 -0
- package/dist/internal/gateway.d.ts +19 -0
- package/dist/internal/gateway.d.ts.map +1 -0
- package/dist/internal/gateway.js +11 -0
- package/dist/internal/gateway.js.map +1 -0
- package/dist/internal/guild-cache.d.ts +69 -0
- package/dist/internal/guild-cache.d.ts.map +1 -0
- package/dist/internal/guild-cache.js +402 -0
- package/dist/internal/guild-cache.js.map +1 -0
- package/dist/internal/guild-discovery.d.ts +15 -0
- package/dist/internal/guild-discovery.d.ts.map +1 -0
- package/dist/internal/guild-discovery.js +258 -0
- package/dist/internal/guild-discovery.js.map +1 -0
- package/dist/internal/guild-lifecycle.d.ts +18 -0
- package/dist/internal/guild-lifecycle.d.ts.map +1 -0
- package/dist/internal/guild-lifecycle.js +119 -0
- package/dist/internal/guild-lifecycle.js.map +1 -0
- package/dist/internal/guild-settings.d.ts +11 -0
- package/dist/internal/guild-settings.d.ts.map +1 -0
- package/dist/internal/guild-settings.js +150 -0
- package/dist/internal/guild-settings.js.map +1 -0
- package/dist/internal/guilds.d.ts +94 -0
- package/dist/internal/guilds.d.ts.map +1 -0
- package/dist/internal/guilds.js +785 -0
- package/dist/internal/guilds.js.map +1 -0
- package/dist/internal/init-command.d.ts +54 -0
- package/dist/internal/init-command.d.ts.map +1 -0
- package/dist/internal/init-command.js +248 -0
- package/dist/internal/init-command.js.map +1 -0
- package/dist/internal/instance.d.ts +69 -0
- package/dist/internal/instance.d.ts.map +1 -0
- package/dist/internal/instance.js +455 -0
- package/dist/internal/instance.js.map +1 -0
- package/dist/internal/invalid-callback-return.d.ts +3 -0
- package/dist/internal/invalid-callback-return.d.ts.map +1 -0
- package/dist/internal/invalid-callback-return.js +26 -0
- package/dist/internal/invalid-callback-return.js.map +1 -0
- package/dist/internal/invites.d.ts +19 -0
- package/dist/internal/invites.d.ts.map +1 -0
- package/dist/internal/invites.js +182 -0
- package/dist/internal/invites.js.map +1 -0
- package/dist/internal/logging.d.ts +129 -0
- package/dist/internal/logging.d.ts.map +1 -0
- package/dist/internal/logging.js +868 -0
- package/dist/internal/logging.js.map +1 -0
- package/dist/internal/logical-scheduler.d.ts +27 -0
- package/dist/internal/logical-scheduler.d.ts.map +1 -0
- package/dist/internal/logical-scheduler.js +102 -0
- package/dist/internal/logical-scheduler.js.map +1 -0
- package/dist/internal/masking.d.ts +13 -0
- package/dist/internal/masking.d.ts.map +1 -0
- package/dist/internal/masking.js +235 -0
- package/dist/internal/masking.js.map +1 -0
- package/dist/internal/member-chunks.d.ts +96 -0
- package/dist/internal/member-chunks.d.ts.map +1 -0
- package/dist/internal/member-chunks.js +557 -0
- package/dist/internal/member-chunks.js.map +1 -0
- package/dist/internal/member-search-workflow.d.ts +19 -0
- package/dist/internal/member-search-workflow.d.ts.map +1 -0
- package/dist/internal/member-search-workflow.js +143 -0
- package/dist/internal/member-search-workflow.js.map +1 -0
- package/dist/internal/member-search.d.ts +20 -0
- package/dist/internal/member-search.d.ts.map +1 -0
- package/dist/internal/member-search.js +201 -0
- package/dist/internal/member-search.js.map +1 -0
- package/dist/internal/message-cleanup.d.ts +9 -0
- package/dist/internal/message-cleanup.d.ts.map +1 -0
- package/dist/internal/message-cleanup.js +368 -0
- package/dist/internal/message-cleanup.js.map +1 -0
- package/dist/internal/message-fields.d.ts +9 -0
- package/dist/internal/message-fields.d.ts.map +1 -0
- package/dist/internal/message-fields.js +55 -0
- package/dist/internal/message-fields.js.map +1 -0
- package/dist/internal/message-search-workflow.d.ts +14 -0
- package/dist/internal/message-search-workflow.d.ts.map +1 -0
- package/dist/internal/message-search-workflow.js +101 -0
- package/dist/internal/message-search-workflow.js.map +1 -0
- package/dist/internal/message-search.d.ts +19 -0
- package/dist/internal/message-search.d.ts.map +1 -0
- package/dist/internal/message-search.js +317 -0
- package/dist/internal/message-search.js.map +1 -0
- package/dist/internal/message.d.ts +34 -0
- package/dist/internal/message.d.ts.map +1 -0
- package/dist/internal/message.js +723 -0
- package/dist/internal/message.js.map +1 -0
- package/dist/internal/metrics.d.ts +16 -0
- package/dist/internal/metrics.d.ts.map +1 -0
- package/dist/internal/metrics.js +49 -0
- package/dist/internal/metrics.js.map +1 -0
- package/dist/internal/moderation.d.ts +20 -0
- package/dist/internal/moderation.d.ts.map +1 -0
- package/dist/internal/moderation.js +219 -0
- package/dist/internal/moderation.js.map +1 -0
- package/dist/internal/multipart.d.ts +10 -0
- package/dist/internal/multipart.d.ts.map +1 -0
- package/dist/internal/multipart.js +156 -0
- package/dist/internal/multipart.js.map +1 -0
- package/dist/internal/node-version.d.ts +10 -0
- package/dist/internal/node-version.d.ts.map +1 -0
- package/dist/internal/node-version.js +21 -0
- package/dist/internal/node-version.js.map +1 -0
- package/dist/internal/oauth.d.ts +29 -0
- package/dist/internal/oauth.d.ts.map +1 -0
- package/dist/internal/oauth.js +721 -0
- package/dist/internal/oauth.js.map +1 -0
- package/dist/internal/observer.d.ts +21 -0
- package/dist/internal/observer.d.ts.map +1 -0
- package/dist/internal/observer.js +48 -0
- package/dist/internal/observer.js.map +1 -0
- package/dist/internal/operation-signal.d.ts +9 -0
- package/dist/internal/operation-signal.d.ts.map +1 -0
- package/dist/internal/operation-signal.js +19 -0
- package/dist/internal/operation-signal.js.map +1 -0
- package/dist/internal/pagination.d.ts +67 -0
- package/dist/internal/pagination.d.ts.map +1 -0
- package/dist/internal/pagination.js +306 -0
- package/dist/internal/pagination.js.map +1 -0
- package/dist/internal/permission-requirements.d.ts +34 -0
- package/dist/internal/permission-requirements.d.ts.map +1 -0
- package/dist/internal/permission-requirements.js +204 -0
- package/dist/internal/permission-requirements.js.map +1 -0
- package/dist/internal/permissions.d.ts +28 -0
- package/dist/internal/permissions.d.ts.map +1 -0
- package/dist/internal/permissions.js +314 -0
- package/dist/internal/permissions.js.map +1 -0
- package/dist/internal/pins.d.ts +24 -0
- package/dist/internal/pins.d.ts.map +1 -0
- package/dist/internal/pins.js +83 -0
- package/dist/internal/pins.js.map +1 -0
- package/dist/internal/presence.d.ts +101 -0
- package/dist/internal/presence.d.ts.map +1 -0
- package/dist/internal/presence.js +581 -0
- package/dist/internal/presence.js.map +1 -0
- package/dist/internal/protocol/gateway.d.ts +116 -0
- package/dist/internal/protocol/gateway.d.ts.map +1 -0
- package/dist/internal/protocol/gateway.js +258 -0
- package/dist/internal/protocol/gateway.js.map +1 -0
- package/dist/internal/rate-limit-templates.d.ts +2 -0
- package/dist/internal/rate-limit-templates.d.ts.map +1 -0
- package/dist/internal/rate-limit-templates.js +132 -0
- package/dist/internal/rate-limit-templates.js.map +1 -0
- package/dist/internal/rate-limits.d.ts +32 -0
- package/dist/internal/rate-limits.d.ts.map +1 -0
- package/dist/internal/rate-limits.js +306 -0
- package/dist/internal/rate-limits.js.map +1 -0
- package/dist/internal/reaction-collector.d.ts +39 -0
- package/dist/internal/reaction-collector.d.ts.map +1 -0
- package/dist/internal/reaction-collector.js +441 -0
- package/dist/internal/reaction-collector.js.map +1 -0
- package/dist/internal/reaction-pages.d.ts +18 -0
- package/dist/internal/reaction-pages.d.ts.map +1 -0
- package/dist/internal/reaction-pages.js +213 -0
- package/dist/internal/reaction-pages.js.map +1 -0
- package/dist/internal/reactions.d.ts +30 -0
- package/dist/internal/reactions.d.ts.map +1 -0
- package/dist/internal/reactions.js +160 -0
- package/dist/internal/reactions.js.map +1 -0
- package/dist/internal/rejection-scope.d.ts +25 -0
- package/dist/internal/rejection-scope.d.ts.map +1 -0
- package/dist/internal/rejection-scope.js +103 -0
- package/dist/internal/rejection-scope.js.map +1 -0
- package/dist/internal/response-json.d.ts +12 -0
- package/dist/internal/response-json.d.ts.map +1 -0
- package/dist/internal/response-json.js +74 -0
- package/dist/internal/response-json.js.map +1 -0
- package/dist/internal/rest/admission.d.ts +77 -0
- package/dist/internal/rest/admission.d.ts.map +1 -0
- package/dist/internal/rest/admission.js +178 -0
- package/dist/internal/rest/admission.js.map +1 -0
- package/dist/internal/rest/attempt.d.ts +124 -0
- package/dist/internal/rest/attempt.d.ts.map +1 -0
- package/dist/internal/rest/attempt.js +410 -0
- package/dist/internal/rest/attempt.js.map +1 -0
- package/dist/internal/rest/classify.d.ts +93 -0
- package/dist/internal/rest/classify.d.ts.map +1 -0
- package/dist/internal/rest/classify.js +304 -0
- package/dist/internal/rest/classify.js.map +1 -0
- package/dist/internal/rest/download.d.ts +66 -0
- package/dist/internal/rest/download.d.ts.map +1 -0
- package/dist/internal/rest/download.js +552 -0
- package/dist/internal/rest/download.js.map +1 -0
- package/dist/internal/rest/options.d.ts +42 -0
- package/dist/internal/rest/options.d.ts.map +1 -0
- package/dist/internal/rest/options.js +99 -0
- package/dist/internal/rest/options.js.map +1 -0
- package/dist/internal/rest/owner.d.ts +154 -0
- package/dist/internal/rest/owner.d.ts.map +1 -0
- package/dist/internal/rest/owner.js +1292 -0
- package/dist/internal/rest/owner.js.map +1 -0
- package/dist/internal/rest/request.d.ts +31 -0
- package/dist/internal/rest/request.d.ts.map +1 -0
- package/dist/internal/rest/request.js +227 -0
- package/dist/internal/rest/request.js.map +1 -0
- package/dist/internal/rest.d.ts +10 -0
- package/dist/internal/rest.d.ts.map +1 -0
- package/dist/internal/rest.js +9 -0
- package/dist/internal/rest.js.map +1 -0
- package/dist/internal/retention-age.d.ts +11 -0
- package/dist/internal/retention-age.d.ts.map +1 -0
- package/dist/internal/retention-age.js +29 -0
- package/dist/internal/retention-age.js.map +1 -0
- package/dist/internal/role-hierarchy-workflow.d.ts +15 -0
- package/dist/internal/role-hierarchy-workflow.d.ts.map +1 -0
- package/dist/internal/role-hierarchy-workflow.js +122 -0
- package/dist/internal/role-hierarchy-workflow.js.map +1 -0
- package/dist/internal/role-hierarchy.d.ts +11 -0
- package/dist/internal/role-hierarchy.d.ts.map +1 -0
- package/dist/internal/role-hierarchy.js +87 -0
- package/dist/internal/role-hierarchy.js.map +1 -0
- package/dist/internal/scheduled-tasks.d.ts +46 -0
- package/dist/internal/scheduled-tasks.d.ts.map +1 -0
- package/dist/internal/scheduled-tasks.js +190 -0
- package/dist/internal/scheduled-tasks.js.map +1 -0
- package/dist/internal/sharding.d.ts +62 -0
- package/dist/internal/sharding.d.ts.map +1 -0
- package/dist/internal/sharding.js +205 -0
- package/dist/internal/sharding.js.map +1 -0
- package/dist/internal/starter-project.d.ts +27 -0
- package/dist/internal/starter-project.d.ts.map +1 -0
- package/dist/internal/starter-project.js +224 -0
- package/dist/internal/starter-project.js.map +1 -0
- package/dist/internal/suggest.d.ts +12 -0
- package/dist/internal/suggest.d.ts.map +1 -0
- package/dist/internal/suggest.js +51 -0
- package/dist/internal/suggest.js.map +1 -0
- package/dist/internal/supervisor.d.ts +95 -0
- package/dist/internal/supervisor.d.ts.map +1 -0
- package/dist/internal/supervisor.js +1829 -0
- package/dist/internal/supervisor.js.map +1 -0
- package/dist/internal/testing/discovery.d.ts +24 -0
- package/dist/internal/testing/discovery.d.ts.map +1 -0
- package/dist/internal/testing/discovery.js +22 -0
- package/dist/internal/testing/discovery.js.map +1 -0
- package/dist/internal/testing/errors.d.ts +43 -0
- package/dist/internal/testing/errors.d.ts.map +1 -0
- package/dist/internal/testing/errors.js +63 -0
- package/dist/internal/testing/errors.js.map +1 -0
- package/dist/internal/testing/fixtures.d.ts +477 -0
- package/dist/internal/testing/fixtures.d.ts.map +1 -0
- package/dist/internal/testing/fixtures.js +233 -0
- package/dist/internal/testing/fixtures.js.map +1 -0
- package/dist/internal/testing/gateway.d.ts +51 -0
- package/dist/internal/testing/gateway.d.ts.map +1 -0
- package/dist/internal/testing/gateway.js +265 -0
- package/dist/internal/testing/gateway.js.map +1 -0
- package/dist/internal/testing/harness.d.ts +60 -0
- package/dist/internal/testing/harness.d.ts.map +1 -0
- package/dist/internal/testing/harness.js +280 -0
- package/dist/internal/testing/harness.js.map +1 -0
- package/dist/internal/testing/http.d.ts +31 -0
- package/dist/internal/testing/http.d.ts.map +1 -0
- package/dist/internal/testing/http.js +347 -0
- package/dist/internal/testing/http.js.map +1 -0
- package/dist/internal/testing/types.d.ts +222 -0
- package/dist/internal/testing/types.d.ts.map +1 -0
- package/dist/internal/testing/types.js +2 -0
- package/dist/internal/testing/types.js.map +1 -0
- package/dist/internal/testing/wait.d.ts +16 -0
- package/dist/internal/testing/wait.d.ts.map +1 -0
- package/dist/internal/testing/wait.js +55 -0
- package/dist/internal/testing/wait.js.map +1 -0
- package/dist/internal/thread-events.d.ts +40 -0
- package/dist/internal/thread-events.d.ts.map +1 -0
- package/dist/internal/thread-events.js +121 -0
- package/dist/internal/thread-events.js.map +1 -0
- package/dist/internal/threads.d.ts +47 -0
- package/dist/internal/threads.d.ts.map +1 -0
- package/dist/internal/threads.js +587 -0
- package/dist/internal/threads.js.map +1 -0
- package/dist/internal/transfer-source.d.ts +29 -0
- package/dist/internal/transfer-source.d.ts.map +1 -0
- package/dist/internal/transfer-source.js +347 -0
- package/dist/internal/transfer-source.js.map +1 -0
- package/dist/internal/transport/http.d.ts +12 -0
- package/dist/internal/transport/http.d.ts.map +1 -0
- package/dist/internal/transport/http.js +44 -0
- package/dist/internal/transport/http.js.map +1 -0
- package/dist/internal/transport/index.d.ts +21 -0
- package/dist/internal/transport/index.d.ts.map +1 -0
- package/dist/internal/transport/index.js +15 -0
- package/dist/internal/transport/index.js.map +1 -0
- package/dist/internal/transport/socket.d.ts +51 -0
- package/dist/internal/transport/socket.d.ts.map +1 -0
- package/dist/internal/transport/socket.js +27 -0
- package/dist/internal/transport/socket.js.map +1 -0
- package/dist/internal/transport/user-agent.d.ts +7 -0
- package/dist/internal/transport/user-agent.d.ts.map +1 -0
- package/dist/internal/transport/user-agent.js +42 -0
- package/dist/internal/transport/user-agent.js.map +1 -0
- package/dist/internal/uploads.d.ts +23 -0
- package/dist/internal/uploads.d.ts.map +1 -0
- package/dist/internal/uploads.js +89 -0
- package/dist/internal/uploads.js.map +1 -0
- package/dist/internal/user-cache.d.ts +50 -0
- package/dist/internal/user-cache.d.ts.map +1 -0
- package/dist/internal/user-cache.js +273 -0
- package/dist/internal/user-cache.js.map +1 -0
- package/dist/internal/users.d.ts +41 -0
- package/dist/internal/users.d.ts.map +1 -0
- package/dist/internal/users.js +333 -0
- package/dist/internal/users.js.map +1 -0
- package/dist/internal/vanity-url.d.ts +11 -0
- package/dist/internal/vanity-url.d.ts.map +1 -0
- package/dist/internal/vanity-url.js +58 -0
- package/dist/internal/vanity-url.js.map +1 -0
- package/dist/internal/webhooks.d.ts +58 -0
- package/dist/internal/webhooks.d.ts.map +1 -0
- package/dist/internal/webhooks.js +490 -0
- package/dist/internal/webhooks.js.map +1 -0
- package/dist/invites.d.ts +86 -0
- package/dist/invites.d.ts.map +1 -0
- package/dist/invites.js +2 -0
- package/dist/invites.js.map +1 -0
- package/dist/logging.d.ts +228 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +2 -0
- package/dist/logging.js.map +1 -0
- package/dist/member-chunks.d.ts +145 -0
- package/dist/member-chunks.d.ts.map +1 -0
- package/dist/member-chunks.js +68 -0
- package/dist/member-chunks.js.map +1 -0
- package/dist/member-search.d.ts +140 -0
- package/dist/member-search.d.ts.map +1 -0
- package/dist/member-search.js +14 -0
- package/dist/member-search.js.map +1 -0
- package/dist/message-cleanup.d.ts +227 -0
- package/dist/message-cleanup.d.ts.map +1 -0
- package/dist/message-cleanup.js +101 -0
- package/dist/message-cleanup.js.map +1 -0
- package/dist/message-errors.d.ts +172 -0
- package/dist/message-errors.d.ts.map +1 -0
- package/dist/message-errors.js +173 -0
- package/dist/message-errors.js.map +1 -0
- package/dist/message-search.d.ts +201 -0
- package/dist/message-search.d.ts.map +1 -0
- package/dist/message-search.js +2 -0
- package/dist/message-search.js.map +1 -0
- package/dist/messages.d.ts +694 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +37 -0
- package/dist/messages.js.map +1 -0
- package/dist/native-commands.d.ts +451 -0
- package/dist/native-commands.d.ts.map +1 -0
- package/dist/native-commands.js +432 -0
- package/dist/native-commands.js.map +1 -0
- package/dist/native-supervisor.d.ts +125 -0
- package/dist/native-supervisor.d.ts.map +1 -0
- package/dist/native-supervisor.js +126 -0
- package/dist/native-supervisor.js.map +1 -0
- package/dist/oauth.d.ts +298 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +128 -0
- package/dist/oauth.js.map +1 -0
- package/dist/observer.d.ts +111 -0
- package/dist/observer.d.ts.map +1 -0
- package/dist/observer.js +2 -0
- package/dist/observer.js.map +1 -0
- package/dist/pagination.d.ts +117 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +61 -0
- package/dist/pagination.js.map +1 -0
- package/dist/permissions.d.ts +73 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +2 -0
- package/dist/permissions.js.map +1 -0
- package/dist/pins.d.ts +62 -0
- package/dist/pins.d.ts.map +1 -0
- package/dist/pins.js +2 -0
- package/dist/pins.js.map +1 -0
- package/dist/presence.d.ts +84 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +46 -0
- package/dist/presence.js.map +1 -0
- package/dist/reaction-pages.d.ts +99 -0
- package/dist/reaction-pages.d.ts.map +1 -0
- package/dist/reaction-pages.js +2 -0
- package/dist/reaction-pages.js.map +1 -0
- package/dist/reactions.d.ts +118 -0
- package/dist/reactions.d.ts.map +1 -0
- package/dist/reactions.js +2 -0
- package/dist/reactions.js.map +1 -0
- package/dist/rest.d.ts +260 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +46 -0
- package/dist/rest.js.map +1 -0
- package/dist/role-hierarchy.d.ts +81 -0
- package/dist/role-hierarchy.d.ts.map +1 -0
- package/dist/role-hierarchy.js +53 -0
- package/dist/role-hierarchy.js.map +1 -0
- package/dist/sharding.d.ts +219 -0
- package/dist/sharding.d.ts.map +1 -0
- package/dist/sharding.js +86 -0
- package/dist/sharding.js.map +1 -0
- package/dist/supervisor.d.ts +392 -0
- package/dist/supervisor.d.ts.map +1 -0
- package/dist/supervisor.js +101 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/testing.d.ts +258 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +202 -0
- package/dist/testing.js.map +1 -0
- package/dist/text.d.ts +38 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +46 -0
- package/dist/text.js.map +1 -0
- package/dist/threads.d.ts +258 -0
- package/dist/threads.d.ts.map +1 -0
- package/dist/threads.js +2 -0
- package/dist/threads.js.map +1 -0
- package/dist/users.d.ts +204 -0
- package/dist/users.d.ts.map +1 -0
- package/dist/users.js +44 -0
- package/dist/users.js.map +1 -0
- package/dist/webhooks.d.ts +423 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +68 -0
- package/dist/webhooks.js.map +1 -0
- package/esm-only.cjs +3 -0
- package/examples/starter/bot-effect.ts +17 -0
- package/examples/starter/bot.js +13 -0
- package/examples/starter/bot.ts +13 -0
- package/package.json +82 -0
- package/src/api/default/application.ts +40 -0
- package/src/api/default/attachments.ts +106 -0
- package/src/api/default/audit-logs.ts +58 -0
- package/src/api/default/bot.ts +586 -0
- package/src/api/default/cache.ts +106 -0
- package/src/api/default/channels.ts +317 -0
- package/src/api/default/client.ts +829 -0
- package/src/api/default/collectors.ts +81 -0
- package/src/api/default/commands.ts +92 -0
- package/src/api/default/direct-messages.ts +143 -0
- package/src/api/default/discovery.ts +103 -0
- package/src/api/default/emojis.ts +125 -0
- package/src/api/default/events.ts +144 -0
- package/src/api/default/gateway.ts +67 -0
- package/src/api/default/guards.ts +173 -0
- package/src/api/default/guilds.ts +271 -0
- package/src/api/default/helpers.ts +97 -0
- package/src/api/default/instance.ts +49 -0
- package/src/api/default/invites.ts +73 -0
- package/src/api/default/logging.ts +37 -0
- package/src/api/default/members.ts +550 -0
- package/src/api/default/messages.ts +1053 -0
- package/src/api/default/oauth.ts +293 -0
- package/src/api/default/permissions.ts +47 -0
- package/src/api/default/presence.ts +88 -0
- package/src/api/default/rest.ts +30 -0
- package/src/api/default/results.ts +44 -0
- package/src/api/default/roles.ts +154 -0
- package/src/api/default/stickers.ts +129 -0
- package/src/api/default/supervisor.ts +53 -0
- package/src/api/default/threads.ts +233 -0
- package/src/api/default/users.ts +82 -0
- package/src/api/default/webhook-client.ts +266 -0
- package/src/api/default/webhooks.ts +89 -0
- package/src/api/effect/application.ts +29 -0
- package/src/api/effect/attachments.ts +100 -0
- package/src/api/effect/audit-logs.ts +50 -0
- package/src/api/effect/bot.ts +546 -0
- package/src/api/effect/cache.ts +110 -0
- package/src/api/effect/channels.ts +293 -0
- package/src/api/effect/client.ts +792 -0
- package/src/api/effect/collectors.ts +103 -0
- package/src/api/effect/commands.ts +87 -0
- package/src/api/effect/direct-messages.ts +119 -0
- package/src/api/effect/discovery.ts +87 -0
- package/src/api/effect/emojis.ts +108 -0
- package/src/api/effect/events.ts +92 -0
- package/src/api/effect/failures.ts +14 -0
- package/src/api/effect/gateway.ts +63 -0
- package/src/api/effect/guards.ts +194 -0
- package/src/api/effect/guilds.ts +247 -0
- package/src/api/effect/helpers.ts +359 -0
- package/src/api/effect/hierarchy.ts +26 -0
- package/src/api/effect/instance.ts +50 -0
- package/src/api/effect/invites.ts +59 -0
- package/src/api/effect/logging.ts +37 -0
- package/src/api/effect/members.ts +521 -0
- package/src/api/effect/messages.ts +1003 -0
- package/src/api/effect/oauth.ts +208 -0
- package/src/api/effect/permissions.ts +44 -0
- package/src/api/effect/presence.ts +83 -0
- package/src/api/effect/rest.ts +27 -0
- package/src/api/effect/roles.ts +136 -0
- package/src/api/effect/service.ts +104 -0
- package/src/api/effect/stickers.ts +112 -0
- package/src/api/effect/supervisor.ts +58 -0
- package/src/api/effect/threads.ts +221 -0
- package/src/api/effect/users.ts +66 -0
- package/src/api/effect/webhook-client.ts +206 -0
- package/src/api/effect/webhooks.ts +75 -0
- package/src/api-errors.ts +985 -0
- package/src/application.ts +103 -0
- package/src/assets.ts +731 -0
- package/src/attachments.ts +469 -0
- package/src/audit-logs.ts +355 -0
- package/src/bot-runner.ts +91 -0
- package/src/builders.ts +390 -0
- package/src/cache.ts +190 -0
- package/src/channels.ts +1051 -0
- package/src/cli.ts +60 -0
- package/src/client.ts +663 -0
- package/src/collectors.ts +248 -0
- package/src/colors.ts +91 -0
- package/src/command-arguments.ts +432 -0
- package/src/command-help.ts +55 -0
- package/src/commands.ts +403 -0
- package/src/counts.ts +160 -0
- package/src/default-commands.ts +1147 -0
- package/src/default-supervisor.ts +484 -0
- package/src/discovery.ts +241 -0
- package/src/effect-testing.ts +603 -0
- package/src/effect.ts +751 -0
- package/src/embeds.ts +253 -0
- package/src/error-tools.ts +191 -0
- package/src/errors.ts +849 -0
- package/src/events.ts +830 -0
- package/src/expressions.ts +198 -0
- package/src/failures.ts +55 -0
- package/src/gateway.ts +86 -0
- package/src/guilds.ts +1108 -0
- package/src/helpers.ts +836 -0
- package/src/index.ts +796 -0
- package/src/input-validation.ts +94 -0
- package/src/instance.ts +111 -0
- package/src/internal/agents-section.ts +114 -0
- package/src/internal/application.ts +51 -0
- package/src/internal/attachment-refresh.ts +57 -0
- package/src/internal/attachments.ts +313 -0
- package/src/internal/audit-logs.ts +336 -0
- package/src/internal/audit.ts +33 -0
- package/src/internal/binding/default-adapters.ts +482 -0
- package/src/internal/binding/default.ts +155 -0
- package/src/internal/binding/execute.ts +221 -0
- package/src/internal/binding/native-adapters.ts +199 -0
- package/src/internal/binding/native.ts +72 -0
- package/src/internal/binding/operations.ts +1171 -0
- package/src/internal/bot-runner.ts +480 -0
- package/src/internal/cache-changes.ts +363 -0
- package/src/internal/cache.ts +323 -0
- package/src/internal/calls.ts +119 -0
- package/src/internal/channel-cache.ts +435 -0
- package/src/internal/channel-decode.ts +399 -0
- package/src/internal/channels.ts +874 -0
- package/src/internal/client/backoff.ts +69 -0
- package/src/internal/client/configuration-fields.ts +18 -0
- package/src/internal/client/drain.ts +150 -0
- package/src/internal/client/intake.ts +228 -0
- package/src/internal/client/lifetime.ts +165 -0
- package/src/internal/client/shard-loop.ts +586 -0
- package/src/internal/client-registry.ts +35 -0
- package/src/internal/client.ts +2448 -0
- package/src/internal/clock.ts +11 -0
- package/src/internal/code-catalogue.ts +739 -0
- package/src/internal/collector.ts +452 -0
- package/src/internal/command-arguments.ts +585 -0
- package/src/internal/command-guards.ts +96 -0
- package/src/internal/command-help.ts +156 -0
- package/src/internal/commands.ts +1319 -0
- package/src/internal/configuration.ts +529 -0
- package/src/internal/counts.ts +471 -0
- package/src/internal/decode/primitives.ts +67 -0
- package/src/internal/decode/timestamp.ts +29 -0
- package/src/internal/decode/trace.ts +65 -0
- package/src/internal/defects.ts +115 -0
- package/src/internal/effect-failures.ts +65 -0
- package/src/internal/embeds.ts +355 -0
- package/src/internal/events.ts +1345 -0
- package/src/internal/expiry-queue.ts +148 -0
- package/src/internal/expressions.ts +415 -0
- package/src/internal/failures.ts +492 -0
- package/src/internal/field-text.ts +40 -0
- package/src/internal/gateway/commands.ts +328 -0
- package/src/internal/gateway/dispatch-table.ts +383 -0
- package/src/internal/gateway/event-dispatches.ts +201 -0
- package/src/internal/gateway/frames.ts +176 -0
- package/src/internal/gateway/options.ts +144 -0
- package/src/internal/gateway/session.ts +625 -0
- package/src/internal/gateway-requests.ts +26 -0
- package/src/internal/gateway.ts +22 -0
- package/src/internal/guild-cache.ts +424 -0
- package/src/internal/guild-discovery.ts +332 -0
- package/src/internal/guild-lifecycle.ts +128 -0
- package/src/internal/guild-settings.ts +209 -0
- package/src/internal/guilds.ts +949 -0
- package/src/internal/init-command.ts +305 -0
- package/src/internal/instance.ts +645 -0
- package/src/internal/invalid-callback-return.ts +28 -0
- package/src/internal/invites.ts +234 -0
- package/src/internal/logging.ts +1007 -0
- package/src/internal/logical-scheduler.ts +139 -0
- package/src/internal/masking.ts +224 -0
- package/src/internal/member-chunks.ts +649 -0
- package/src/internal/member-search-workflow.ts +237 -0
- package/src/internal/member-search.ts +272 -0
- package/src/internal/message-cleanup.ts +515 -0
- package/src/internal/message-fields.ts +71 -0
- package/src/internal/message-search-workflow.ts +166 -0
- package/src/internal/message-search.ts +476 -0
- package/src/internal/message.ts +879 -0
- package/src/internal/metrics.ts +55 -0
- package/src/internal/moderation.ts +288 -0
- package/src/internal/multipart.ts +171 -0
- package/src/internal/node-version.ts +22 -0
- package/src/internal/oauth.ts +1146 -0
- package/src/internal/observer.ts +62 -0
- package/src/internal/operation-signal.ts +26 -0
- package/src/internal/pagination.ts +494 -0
- package/src/internal/permission-requirements.ts +359 -0
- package/src/internal/permissions.ts +417 -0
- package/src/internal/pins.ts +115 -0
- package/src/internal/presence.ts +745 -0
- package/src/internal/protocol/gateway.ts +299 -0
- package/src/internal/rate-limit-templates.ts +138 -0
- package/src/internal/rate-limits.ts +346 -0
- package/src/internal/reaction-collector.ts +499 -0
- package/src/internal/reaction-pages.ts +260 -0
- package/src/internal/reactions.ts +174 -0
- package/src/internal/rejection-scope.ts +119 -0
- package/src/internal/response-json.ts +76 -0
- package/src/internal/rest/admission.ts +210 -0
- package/src/internal/rest/attempt.ts +617 -0
- package/src/internal/rest/classify.ts +391 -0
- package/src/internal/rest/download.ts +658 -0
- package/src/internal/rest/options.ts +145 -0
- package/src/internal/rest/owner.ts +1828 -0
- package/src/internal/rest/request.ts +289 -0
- package/src/internal/rest.ts +9 -0
- package/src/internal/retention-age.ts +33 -0
- package/src/internal/role-hierarchy-workflow.ts +150 -0
- package/src/internal/role-hierarchy.ts +93 -0
- package/src/internal/scheduled-tasks.ts +217 -0
- package/src/internal/sharding.ts +270 -0
- package/src/internal/starter-project.ts +251 -0
- package/src/internal/suggest.ts +50 -0
- package/src/internal/supervisor.ts +2253 -0
- package/src/internal/testing/discovery.ts +23 -0
- package/src/internal/testing/errors.ts +67 -0
- package/src/internal/testing/fixtures.ts +714 -0
- package/src/internal/testing/gateway.ts +305 -0
- package/src/internal/testing/harness.ts +328 -0
- package/src/internal/testing/http.ts +395 -0
- package/src/internal/testing/types.ts +240 -0
- package/src/internal/testing/wait.ts +63 -0
- package/src/internal/thread-events.ts +128 -0
- package/src/internal/threads.ts +718 -0
- package/src/internal/transfer-source.ts +359 -0
- package/src/internal/transport/http.ts +46 -0
- package/src/internal/transport/index.ts +23 -0
- package/src/internal/transport/socket.ts +71 -0
- package/src/internal/transport/user-agent.ts +46 -0
- package/src/internal/uploads.ts +111 -0
- package/src/internal/user-cache.ts +294 -0
- package/src/internal/users.ts +402 -0
- package/src/internal/vanity-url.ts +80 -0
- package/src/internal/webhooks.ts +690 -0
- package/src/invites.ts +87 -0
- package/src/logging.ts +247 -0
- package/src/member-chunks.ts +195 -0
- package/src/member-search.ts +152 -0
- package/src/message-cleanup.ts +308 -0
- package/src/message-errors.ts +245 -0
- package/src/message-search.ts +213 -0
- package/src/messages.ts +768 -0
- package/src/native-commands.ts +1249 -0
- package/src/native-supervisor.ts +345 -0
- package/src/oauth.ts +413 -0
- package/src/observer.ts +118 -0
- package/src/pagination.ts +172 -0
- package/src/permissions.ts +74 -0
- package/src/pins.ts +65 -0
- package/src/presence.ts +124 -0
- package/src/reaction-pages.ts +106 -0
- package/src/reactions.ts +126 -0
- package/src/rest.ts +282 -0
- package/src/role-hierarchy.ts +127 -0
- package/src/sharding.ts +272 -0
- package/src/supervisor.ts +460 -0
- package/src/testing.ts +424 -0
- package/src/text.ts +76 -0
- package/src/threads.ts +274 -0
- package/src/users.ts +237 -0
- package/src/webhooks.ts +512 -0
|
@@ -0,0 +1,1829 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local supervisor: Forked child clients with fixed or computed assignments, Identify coordination, restarts, child
|
|
3
|
+
* diagnostics and output forwarding.
|
|
4
|
+
* Invariant: Assignments are fixed once known: At creation, or at start after one community count for totalShards "auto".
|
|
5
|
+
* An automatic plan changes only when a child reports a 4011 (sharding required) closure: Every child stops, the
|
|
6
|
+
* communities are counted again and a larger plan starts, at most three times an hour.
|
|
7
|
+
* Only an application-supplied identify coordinator reaches beyond the children it forked. The children share Fluxer's
|
|
8
|
+
* account-wide limits through the parent: It relays a global rate-limit pause one child learns to the others, and keeps
|
|
9
|
+
* the one member request window, counting a granted request from its grant and again once it reached the socket. An
|
|
10
|
+
* unanswered child uses its own window. Per-route REST buckets stay per process, and session retention belongs to each
|
|
11
|
+
* child's own SessionStore. It terminates only an
|
|
12
|
+
* unresponsive child after the graceful deadline and awaits that child's exit, passes its resolved format to children
|
|
13
|
+
* through FLUXERLY_LOG_FORMAT and FLUXERLY_LOG_COLOR, and keeps forwarded JSON output valid JSON Lines. Implements [SDK contracts: Connection and recovery](/docs/SDK-CONTRACTS.md#connection-and-recovery)
|
|
14
|
+
*/
|
|
15
|
+
import { fork } from "node:child_process";
|
|
16
|
+
import { isAbsolute } from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
import * as Cause from "effect/Cause";
|
|
19
|
+
import * as Deferred from "effect/Deferred";
|
|
20
|
+
import * as Effect from "effect/Effect";
|
|
21
|
+
import * as Exit from "effect/Exit";
|
|
22
|
+
import * as Fiber from "effect/Fiber";
|
|
23
|
+
import { ConfigurationError, ConnectionError } from "#sdk/errors";
|
|
24
|
+
import { loggingConfiguration } from "#sdk/internal/logging";
|
|
25
|
+
import { maskText } from "#sdk/internal/masking";
|
|
26
|
+
import { makeClient } from "#sdk/internal/client";
|
|
27
|
+
import { memberRequestLimit, memberRequestWindowMs } from "#sdk/internal/member-chunks";
|
|
28
|
+
import { validateConfiguration } from "#sdk/internal/configuration";
|
|
29
|
+
import { admitReshard, automaticShardPlan, guildsPerShard, largerShardPlan, maximumShardCount, } from "#sdk/internal/sharding";
|
|
30
|
+
import { CloseCode } from "#sdk/internal/protocol/gateway";
|
|
31
|
+
import { SupervisorChildError, SupervisorError, } from "#sdk/supervisor";
|
|
32
|
+
import { record, safeInteger, snapshotArray } from "#sdk/internal/decode/primitives";
|
|
33
|
+
import { callerFields, readCaller, suspendMarked } from "#sdk/internal/defects";
|
|
34
|
+
import { unsupportedKeyHint } from "#sdk/internal/suggest";
|
|
35
|
+
const maximumTimerMs = 2_147_483_647;
|
|
36
|
+
const maximumAttempts = 100;
|
|
37
|
+
const maximumChildEnvironmentEntries = 64;
|
|
38
|
+
const maximumArgumentEntries = 64;
|
|
39
|
+
const maximumArgumentLength = 4_096;
|
|
40
|
+
const maximumChildIdLength = 128;
|
|
41
|
+
const defaultStartupTimeoutMs = 30_000;
|
|
42
|
+
const defaultShutdownTimeoutMs = 5_000;
|
|
43
|
+
const grantAcknowledgementMs = 5_000;
|
|
44
|
+
/** Longest wait for the parent's answer to a member request slot, after which the child uses its own window */
|
|
45
|
+
const memberAnswerMs = 1_000;
|
|
46
|
+
const defaultDiagnosticsIntervalMs = 5_000;
|
|
47
|
+
/** Part of shutdownTimeoutMs a stopping child keeps for closing its connections after draining running work */
|
|
48
|
+
const childCloseReserveMs = 1_000;
|
|
49
|
+
/** Longest wait after a child exits for its forwarded output streams to close */
|
|
50
|
+
const outputDrainGraceMs = 1_000;
|
|
51
|
+
/** The documented restart defaults, used when the restart option is omitted */
|
|
52
|
+
const defaultRestart = Object.freeze({
|
|
53
|
+
maxAttempts: 3,
|
|
54
|
+
minDelayMs: 1_000,
|
|
55
|
+
maxDelayMs: 30_000,
|
|
56
|
+
healthyResetMs: 60_000,
|
|
57
|
+
});
|
|
58
|
+
const connectionStates = ["Disconnected", "Connecting", "Connected", "Recovering", "Closing", "Closed"];
|
|
59
|
+
function connectionState(value) {
|
|
60
|
+
return typeof value === "string" && connectionStates.includes(value);
|
|
61
|
+
}
|
|
62
|
+
/** Top-level fields of a ClientDiagnostics snapshot, which a diagnostics message must carry exactly */
|
|
63
|
+
const diagnosticsKeys = [
|
|
64
|
+
"state",
|
|
65
|
+
"gatewayLatencyMs",
|
|
66
|
+
"shards",
|
|
67
|
+
"rest",
|
|
68
|
+
"uploads",
|
|
69
|
+
"gatewayRequests",
|
|
70
|
+
"events",
|
|
71
|
+
"caches",
|
|
72
|
+
"counters",
|
|
73
|
+
];
|
|
74
|
+
/** Freeze a snapshot received over IPC, which Node has already copied, so status readers cannot change it */
|
|
75
|
+
function deepFreeze(value) {
|
|
76
|
+
if (typeof value === "object" && value !== null) {
|
|
77
|
+
for (const entry of Object.values(value))
|
|
78
|
+
deepFreeze(entry);
|
|
79
|
+
Object.freeze(value);
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Split every shard of a plan into contiguous blocks, one per child, named process-0, process-1 and so on.
|
|
85
|
+
* Processes get sizes that differ by at most one, and shardsPerProcess leaves the remainder to the last child
|
|
86
|
+
*/
|
|
87
|
+
function splitShards(totalShards, split) {
|
|
88
|
+
const count = "processes" in split ? Math.min(split.processes, totalShards) : Math.ceil(totalShards / split.shardsPerProcess);
|
|
89
|
+
const children = [];
|
|
90
|
+
let next = 0;
|
|
91
|
+
for (let index = 0; index < count; index += 1) {
|
|
92
|
+
const size = "processes" in split
|
|
93
|
+
? Math.floor(totalShards / count) + (index < totalShards % count ? 1 : 0)
|
|
94
|
+
: Math.min(split.shardsPerProcess, totalShards - next);
|
|
95
|
+
const shardIds = Array.from({ length: size }, (_, offset) => next + offset);
|
|
96
|
+
next += size;
|
|
97
|
+
children.push(Object.freeze({
|
|
98
|
+
id: `process-${index}`,
|
|
99
|
+
assignment: Object.freeze({ totalShards, shardIds: Object.freeze(shardIds) }),
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
return Object.freeze(children);
|
|
103
|
+
}
|
|
104
|
+
function hasOnlyKeys(value, keys) {
|
|
105
|
+
return Object.keys(value).every((key) => keys.includes(key));
|
|
106
|
+
}
|
|
107
|
+
function hasExactKeys(value, keys) {
|
|
108
|
+
return hasOnlyKeys(value, keys) && keys.every((key) => key in value);
|
|
109
|
+
}
|
|
110
|
+
function positiveTimer(value) {
|
|
111
|
+
return safeInteger(value) && value > 0 && value <= maximumTimerMs;
|
|
112
|
+
}
|
|
113
|
+
function childEntry(value) {
|
|
114
|
+
if (typeof value === "string")
|
|
115
|
+
return isAbsolute(value) ? value : undefined;
|
|
116
|
+
// Read the URL fields outside the parse guard, so a throwing getter stays an application fault
|
|
117
|
+
if (!record(value) || value.protocol !== "file:")
|
|
118
|
+
return undefined;
|
|
119
|
+
const href = value.href;
|
|
120
|
+
if (typeof href !== "string")
|
|
121
|
+
return undefined;
|
|
122
|
+
try {
|
|
123
|
+
const path = fileURLToPath(href);
|
|
124
|
+
return isAbsolute(path) ? path : undefined;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// allow-silent: An unusable entry becomes the typed ConfigurationError returned by the caller
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function filteredExecArguments(values) {
|
|
132
|
+
const result = [];
|
|
133
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
134
|
+
const argument = values[index];
|
|
135
|
+
// Child processes resolve the shipped output, so neither Node spelling may retain the source-test condition
|
|
136
|
+
if ((argument === "--conditions" || argument === "-C") && values[index + 1] === "fluxerly-source") {
|
|
137
|
+
index += 1;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (argument === "--conditions=fluxerly-source")
|
|
141
|
+
continue;
|
|
142
|
+
result.push(argument);
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
/** Copy a caller string array once, then validate the copy. A sparse entry copies as undefined and fails */
|
|
147
|
+
function stringArray(value, field) {
|
|
148
|
+
const copied = snapshotArray(value, maximumArgumentEntries);
|
|
149
|
+
if (copied === undefined)
|
|
150
|
+
return new ConfigurationError(field, `The supervisor option ${JSON.stringify(field)} must be an array of at most ${maximumArgumentEntries} strings`);
|
|
151
|
+
if (copied.some((entry) => typeof entry !== "string" || entry.length > maximumArgumentLength))
|
|
152
|
+
return new ConfigurationError(field, `The supervisor option ${JSON.stringify(field)} must contain only strings of at most ${maximumArgumentLength.toLocaleString("en-US")} characters, with no empty slots`);
|
|
153
|
+
return copied;
|
|
154
|
+
}
|
|
155
|
+
/** Copy caller shard IDs once, then validate the copy, so the validated IDs are the ones assigned */
|
|
156
|
+
function assignment(value, totalShards) {
|
|
157
|
+
const copied = snapshotArray(value, totalShards);
|
|
158
|
+
if (copied === undefined || copied.length === 0)
|
|
159
|
+
return undefined;
|
|
160
|
+
const seen = new Set();
|
|
161
|
+
for (const shardId of copied) {
|
|
162
|
+
if (!safeInteger(shardId) || shardId < 0 || shardId >= totalShards || seen.has(shardId))
|
|
163
|
+
return undefined;
|
|
164
|
+
seen.add(shardId);
|
|
165
|
+
}
|
|
166
|
+
return copied;
|
|
167
|
+
}
|
|
168
|
+
function childEnvironment(value) {
|
|
169
|
+
if (value === undefined)
|
|
170
|
+
return Object.freeze([]);
|
|
171
|
+
if (!record(value) || Object.getOwnPropertySymbols(value).length > 0)
|
|
172
|
+
return new ConfigurationError("childEnvironment", 'The supervisor option "childEnvironment" must be an object of environment variable names and string values');
|
|
173
|
+
const entries = Object.entries(value);
|
|
174
|
+
if (entries.length > maximumChildEnvironmentEntries)
|
|
175
|
+
return new ConfigurationError("childEnvironment", `The supervisor option "childEnvironment" can have at most ${maximumChildEnvironmentEntries} entries`);
|
|
176
|
+
const copied = [];
|
|
177
|
+
for (const [key, current] of entries) {
|
|
178
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) ||
|
|
179
|
+
typeof current !== "string" ||
|
|
180
|
+
current.length > maximumArgumentLength)
|
|
181
|
+
return new ConfigurationError("childEnvironment", `The supervisor option "childEnvironment" must use names of letters, digits and underscores that do not start with a digit, and string values of at most ${maximumArgumentLength.toLocaleString("en-US")} characters`);
|
|
182
|
+
copied.push(Object.freeze([key, current]));
|
|
183
|
+
}
|
|
184
|
+
return Object.freeze(copied);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Validate and snapshot supervisor configuration without creating a child process. Each caller field is read once, and
|
|
188
|
+
* only the reads of the options are marked as application input, so a fault in the surrounding validation or logger
|
|
189
|
+
* creation stays an SDK fault
|
|
190
|
+
*/
|
|
191
|
+
function validateSupervisorConfiguration(options, native = false) {
|
|
192
|
+
return suspendMarked(() => supervisorSettings(options, native));
|
|
193
|
+
}
|
|
194
|
+
const supervisorOptionKeys = [
|
|
195
|
+
"entry",
|
|
196
|
+
"totalShards",
|
|
197
|
+
"assignments",
|
|
198
|
+
"processes",
|
|
199
|
+
"shardsPerProcess",
|
|
200
|
+
"token",
|
|
201
|
+
"instance",
|
|
202
|
+
"transport",
|
|
203
|
+
"restart",
|
|
204
|
+
"identify",
|
|
205
|
+
"diagnosticsIntervalMs",
|
|
206
|
+
"startupTimeoutMs",
|
|
207
|
+
"shutdownTimeoutMs",
|
|
208
|
+
"childEnvironment",
|
|
209
|
+
"args",
|
|
210
|
+
"execArgv",
|
|
211
|
+
"childOutput",
|
|
212
|
+
"logging",
|
|
213
|
+
];
|
|
214
|
+
/** Reject malformed supervisor option objects and suggest supported names before their values are read */
|
|
215
|
+
export function supervisorOptionError(options, supported, field, label) {
|
|
216
|
+
if (!record(options))
|
|
217
|
+
return new ConfigurationError(field, `${label} must be an object`);
|
|
218
|
+
const unsupported = Object.keys(options).find((key) => !supported.includes(key));
|
|
219
|
+
return unsupported === undefined
|
|
220
|
+
? undefined
|
|
221
|
+
: new ConfigurationError(field, `Unsupported option ${JSON.stringify(unsupported)} in the ${label.charAt(0).toLowerCase()}${label.slice(1)}`, {
|
|
222
|
+
hint: unsupportedKeyHint(unsupported, supported),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
function supervisorSettings(options, native) {
|
|
226
|
+
{
|
|
227
|
+
if (!record(options))
|
|
228
|
+
return Effect.fail(new ConfigurationError("supervisor", "Supervisor settings must be an object"));
|
|
229
|
+
const unsupported = readCaller(() => Object.keys(options)).find((key) => !supervisorOptionKeys.includes(key));
|
|
230
|
+
if (unsupported !== undefined)
|
|
231
|
+
return Effect.fail(new ConfigurationError("supervisor", `Unsupported supervisor option ${JSON.stringify(unsupported)}`, {
|
|
232
|
+
hint: unsupportedKeyHint(unsupported, supervisorOptionKeys),
|
|
233
|
+
}));
|
|
234
|
+
const field = callerFields(options);
|
|
235
|
+
const entry = readCaller(() => childEntry(field("entry")));
|
|
236
|
+
if (!entry)
|
|
237
|
+
return Effect.fail(new ConfigurationError("entry", 'The supervisor option "entry" must be an absolute path or a file URL'));
|
|
238
|
+
const totalShards = field("totalShards");
|
|
239
|
+
if (totalShards !== "auto" && (!safeInteger(totalShards) || totalShards < 1 || totalShards > maximumShardCount))
|
|
240
|
+
return Effect.fail(new ConfigurationError("totalShards", 'The supervisor option "totalShards" must be an integer from 1 through 16,384, or "auto"'));
|
|
241
|
+
const split = processSplit(field("assignments"), field("processes"), field("shardsPerProcess"), totalShards);
|
|
242
|
+
if (split instanceof ConfigurationError)
|
|
243
|
+
return Effect.fail(split);
|
|
244
|
+
const counting = ["token", "instance", "transport"].map((key) => [key, field(key)]);
|
|
245
|
+
const automatic = totalShards === "auto"
|
|
246
|
+
? countingOptions(counting, field("logging"), split, native)
|
|
247
|
+
: undefined;
|
|
248
|
+
if (automatic instanceof ConfigurationError)
|
|
249
|
+
return Effect.fail(automatic);
|
|
250
|
+
if (totalShards !== "auto") {
|
|
251
|
+
const supplied = counting.find(([, value]) => value !== undefined);
|
|
252
|
+
if (supplied)
|
|
253
|
+
return Effect.fail(new ConfigurationError(supplied[0], `The supervisor option ${JSON.stringify(supplied[0])} is used only to count the bot's communities when totalShards is "auto"`, { hint: 'Remove it, or set totalShards to "auto" to size the plan at start' }));
|
|
254
|
+
}
|
|
255
|
+
const children = totalShards === "auto"
|
|
256
|
+
? Object.freeze([])
|
|
257
|
+
: split === undefined
|
|
258
|
+
? readCaller(() => fixedAssignments(field("assignments"), totalShards))
|
|
259
|
+
: splitShards(totalShards, split);
|
|
260
|
+
if (children instanceof ConfigurationError)
|
|
261
|
+
return Effect.fail(children);
|
|
262
|
+
const restart = field("restart");
|
|
263
|
+
let restartConfiguration = defaultRestart;
|
|
264
|
+
if (restart === false)
|
|
265
|
+
restartConfiguration = undefined;
|
|
266
|
+
else if (restart !== undefined) {
|
|
267
|
+
const configured = readCaller(() => restartSettings(restart));
|
|
268
|
+
if (configured instanceof ConfigurationError)
|
|
269
|
+
return Effect.fail(configured);
|
|
270
|
+
restartConfiguration = configured;
|
|
271
|
+
}
|
|
272
|
+
const identify = readCaller(() => identifySettings(field("identify")));
|
|
273
|
+
if (identify instanceof ConfigurationError)
|
|
274
|
+
return Effect.fail(identify);
|
|
275
|
+
const diagnosticsInput = field("diagnosticsIntervalMs");
|
|
276
|
+
const diagnosticsIntervalMs = diagnosticsInput === undefined ? defaultDiagnosticsIntervalMs : diagnosticsInput;
|
|
277
|
+
if (!positiveTimer(diagnosticsIntervalMs) || diagnosticsIntervalMs < 1_000)
|
|
278
|
+
return Effect.fail(new ConfigurationError("diagnosticsIntervalMs", 'The supervisor option "diagnosticsIntervalMs" must be an integer from 1,000 through 2,147,483,647 milliseconds'));
|
|
279
|
+
const startupInput = field("startupTimeoutMs");
|
|
280
|
+
const startupTimeoutMs = startupInput === undefined ? defaultStartupTimeoutMs : startupInput;
|
|
281
|
+
if (!positiveTimer(startupTimeoutMs))
|
|
282
|
+
return Effect.fail(new ConfigurationError("startupTimeoutMs", 'The supervisor option "startupTimeoutMs" must be an integer from 1 through 2,147,483,647 milliseconds'));
|
|
283
|
+
const shutdownInput = field("shutdownTimeoutMs");
|
|
284
|
+
const shutdownTimeoutMs = shutdownInput === undefined ? defaultShutdownTimeoutMs : shutdownInput;
|
|
285
|
+
if (!positiveTimer(shutdownTimeoutMs))
|
|
286
|
+
return Effect.fail(new ConfigurationError("shutdownTimeoutMs", 'The supervisor option "shutdownTimeoutMs" must be an integer from 1 through 2,147,483,647 milliseconds'));
|
|
287
|
+
const childEnvironmentOverrides = readCaller(() => childEnvironment(field("childEnvironment")));
|
|
288
|
+
if (childEnvironmentOverrides instanceof ConfigurationError)
|
|
289
|
+
return Effect.fail(childEnvironmentOverrides);
|
|
290
|
+
const environment = new Map();
|
|
291
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
292
|
+
if (typeof value === "string")
|
|
293
|
+
environment.set(key, value);
|
|
294
|
+
}
|
|
295
|
+
for (const [key, value] of childEnvironmentOverrides)
|
|
296
|
+
environment.set(key, value);
|
|
297
|
+
const argsInput = field("args");
|
|
298
|
+
const args = argsInput === undefined ? Object.freeze([]) : readCaller(() => stringArray(argsInput, "args"));
|
|
299
|
+
if (args instanceof ConfigurationError)
|
|
300
|
+
return Effect.fail(args);
|
|
301
|
+
const execArgvOption = field("execArgv");
|
|
302
|
+
const execArgv = readCaller(() => stringArray(execArgvOption === undefined ? process.execArgv : execArgvOption, "execArgv"));
|
|
303
|
+
if (execArgv instanceof ConfigurationError)
|
|
304
|
+
return Effect.fail(execArgv);
|
|
305
|
+
const childOutputInput = field("childOutput");
|
|
306
|
+
const childOutput = childOutputInput === undefined ? "prefix" : childOutputInput;
|
|
307
|
+
if (childOutput !== "prefix" && childOutput !== "inherit" && childOutput !== "ignore")
|
|
308
|
+
return Effect.fail(new ConfigurationError("childOutput", 'The supervisor option "childOutput" must be "prefix", "inherit" or "ignore"'));
|
|
309
|
+
const logger = loggingConfiguration(field("logging"), native);
|
|
310
|
+
if (logger instanceof ConfigurationError)
|
|
311
|
+
return Effect.fail(logger);
|
|
312
|
+
return Effect.succeed(Object.freeze({
|
|
313
|
+
entry,
|
|
314
|
+
children,
|
|
315
|
+
automatic,
|
|
316
|
+
restart: restartConfiguration,
|
|
317
|
+
minimumSpacingMs: identify.minimumSpacingMs,
|
|
318
|
+
coordinator: identify.coordinator,
|
|
319
|
+
diagnosticsIntervalMs,
|
|
320
|
+
startupTimeoutMs,
|
|
321
|
+
shutdownTimeoutMs,
|
|
322
|
+
environment: Object.freeze([...environment].map((entry) => Object.freeze(entry))),
|
|
323
|
+
args,
|
|
324
|
+
execArgv: Object.freeze(filteredExecArguments(execArgv)),
|
|
325
|
+
childOutput,
|
|
326
|
+
logger,
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Choose how children are formed: undefined for explicit assignments, otherwise the processes or shardsPerProcess
|
|
332
|
+
* split. Exactly one of the three must be present, and an automatic total needs a split
|
|
333
|
+
*/
|
|
334
|
+
function processSplit(assignments, processes, shardsPerProcess, totalShards) {
|
|
335
|
+
const chosen = [assignments, processes, shardsPerProcess].filter((value) => value !== undefined).length;
|
|
336
|
+
if (chosen !== 1)
|
|
337
|
+
return new ConfigurationError(chosen === 0 ? "assignments" : "supervisor", chosen === 0
|
|
338
|
+
? 'The supervisor needs one of the options "assignments", "processes" or "shardsPerProcess"'
|
|
339
|
+
: 'The supervisor options "assignments", "processes" and "shardsPerProcess" cannot be combined', {
|
|
340
|
+
hint: "Use processes to split every shard evenly across that many children, or assignments to choose each child's shards",
|
|
341
|
+
});
|
|
342
|
+
if (assignments !== undefined) {
|
|
343
|
+
if (totalShards === "auto")
|
|
344
|
+
return new ConfigurationError("assignments", 'The supervisor option "assignments" needs a numeric totalShards, because fixed shard IDs depend on the total', { hint: 'Use processes or shardsPerProcess with totalShards "auto"' });
|
|
345
|
+
return undefined;
|
|
346
|
+
}
|
|
347
|
+
const name = processes !== undefined ? "processes" : "shardsPerProcess";
|
|
348
|
+
const value = processes ?? shardsPerProcess;
|
|
349
|
+
if (!safeInteger(value) || value < 1 || value > maximumShardCount)
|
|
350
|
+
return new ConfigurationError(name, `The supervisor option "${name}" must be an integer from 1 through 16,384`);
|
|
351
|
+
if (name === "processes" && totalShards !== "auto" && value > totalShards)
|
|
352
|
+
return new ConfigurationError("processes", 'The supervisor option "processes" can be at most totalShards, because each child needs at least one shard');
|
|
353
|
+
return name === "processes" ? { processes: value } : { shardsPerProcess: value };
|
|
354
|
+
}
|
|
355
|
+
/** Validate the settings of the transient client that counts communities for totalShards "auto" */
|
|
356
|
+
function countingOptions(counting, logging, split, native) {
|
|
357
|
+
const clientOptions = {};
|
|
358
|
+
for (const [key, value] of counting)
|
|
359
|
+
if (value !== undefined)
|
|
360
|
+
clientOptions[key] = value;
|
|
361
|
+
if (logging !== undefined)
|
|
362
|
+
clientOptions.logging = logging;
|
|
363
|
+
if (clientOptions.token === undefined)
|
|
364
|
+
return new ConfigurationError("token", 'The supervisor option "token" is required when totalShards is "auto"', {
|
|
365
|
+
hint: "Pass the bot token, such as process.env.FLUXER_BOT_TOKEN, so the supervisor can count the bot's communities",
|
|
366
|
+
});
|
|
367
|
+
const validated = Effect.runSyncExit(validateConfiguration(clientOptions, native));
|
|
368
|
+
if (Exit.isFailure(validated)) {
|
|
369
|
+
const failure = validated.cause.reasons.find((reason) => reason._tag === "Fail");
|
|
370
|
+
if (failure?._tag === "Fail")
|
|
371
|
+
return failure.error;
|
|
372
|
+
throw Cause.squash(validated.cause);
|
|
373
|
+
}
|
|
374
|
+
return Object.freeze({ split, clientOptions: Object.freeze(clientOptions) });
|
|
375
|
+
}
|
|
376
|
+
/** Copy and validate explicit assignments for a numeric total */
|
|
377
|
+
function fixedAssignments(value, totalShards) {
|
|
378
|
+
const assignments = snapshotArray(value, totalShards);
|
|
379
|
+
if (assignments === undefined || assignments.length === 0)
|
|
380
|
+
return new ConfigurationError("assignments", `The supervisor option "assignments" must be a non-empty array with at most ${totalShards} entries, one per child`);
|
|
381
|
+
const seenIds = new Set();
|
|
382
|
+
const seenShards = new Set();
|
|
383
|
+
const children = [];
|
|
384
|
+
for (const current of assignments) {
|
|
385
|
+
if (!record(current))
|
|
386
|
+
return new ConfigurationError("assignments", "Each supervisor assignment must be an object with id and shardIds");
|
|
387
|
+
const invalidKeys = supervisorOptionError(current, ["id", "shardIds"], "assignments", "Supervisor assignment options");
|
|
388
|
+
if (invalidKeys)
|
|
389
|
+
return invalidKeys;
|
|
390
|
+
if (!hasExactKeys(current, ["id", "shardIds"]))
|
|
391
|
+
return new ConfigurationError("assignments", "Each supervisor assignment must contain exactly id and shardIds");
|
|
392
|
+
const id = current.id;
|
|
393
|
+
if (typeof id === "string" && seenIds.has(id))
|
|
394
|
+
return new ConfigurationError("childId", `Supervisor assignment ID ${JSON.stringify(id)} is used more than once`);
|
|
395
|
+
if (typeof id !== "string" || id.trim().length === 0 || id.length > maximumChildIdLength)
|
|
396
|
+
return new ConfigurationError("childId", `Supervisor assignment IDs must be non-blank strings of at most ${maximumChildIdLength} characters`);
|
|
397
|
+
const shardIds = assignment(current.shardIds, totalShards);
|
|
398
|
+
if (!shardIds)
|
|
399
|
+
return new ConfigurationError("shardIds", `The shardIds of supervisor assignment ${JSON.stringify(id)} must be a non-empty array of unique integers from 0 through ${totalShards - 1}`);
|
|
400
|
+
for (const shardId of shardIds) {
|
|
401
|
+
if (seenShards.has(shardId))
|
|
402
|
+
return new ConfigurationError("shardIds", `Shard ${shardId} is assigned to more than one supervisor child`);
|
|
403
|
+
seenShards.add(shardId);
|
|
404
|
+
}
|
|
405
|
+
seenIds.add(id);
|
|
406
|
+
children.push(Object.freeze({ id, assignment: Object.freeze({ totalShards, shardIds: Object.freeze([...shardIds]) }) }));
|
|
407
|
+
}
|
|
408
|
+
return Object.freeze(children);
|
|
409
|
+
}
|
|
410
|
+
/** Validate a supplied restart object, filling each omitted setting with its default */
|
|
411
|
+
function restartSettings(restart) {
|
|
412
|
+
if (!record(restart))
|
|
413
|
+
return new ConfigurationError("restart", 'The supervisor option "restart" must be an object or false');
|
|
414
|
+
const restartKeys = ["maxAttempts", "minDelayMs", "maxDelayMs", "healthyResetMs"];
|
|
415
|
+
const unsupportedRestart = Object.keys(restart).find((key) => !restartKeys.includes(key));
|
|
416
|
+
if (unsupportedRestart !== undefined)
|
|
417
|
+
return new ConfigurationError("restart", `Unsupported restart setting ${JSON.stringify(unsupportedRestart)}`, {
|
|
418
|
+
hint: unsupportedKeyHint(unsupportedRestart, restartKeys, "settings"),
|
|
419
|
+
});
|
|
420
|
+
const restartField = callerFields(restart);
|
|
421
|
+
const orDefault = (key) => {
|
|
422
|
+
const value = restartField(key);
|
|
423
|
+
return value === undefined ? defaultRestart[key] : value;
|
|
424
|
+
};
|
|
425
|
+
const maxAttempts = orDefault("maxAttempts");
|
|
426
|
+
const minDelayMs = orDefault("minDelayMs");
|
|
427
|
+
const maxDelayMs = orDefault("maxDelayMs");
|
|
428
|
+
const healthyResetMs = orDefault("healthyResetMs");
|
|
429
|
+
if (!safeInteger(maxAttempts) || maxAttempts < 0 || maxAttempts > maximumAttempts)
|
|
430
|
+
return new ConfigurationError("maxAttempts", `The supervisor option "restart.maxAttempts" must be an integer from 0 through ${maximumAttempts}`);
|
|
431
|
+
if (!positiveTimer(minDelayMs) || !positiveTimer(maxDelayMs) || minDelayMs > maxDelayMs)
|
|
432
|
+
return new ConfigurationError("restart", 'The supervisor options "restart.minDelayMs" and "restart.maxDelayMs" must be integers from 1 through 2,147,483,647 milliseconds, with minDelayMs no larger than maxDelayMs');
|
|
433
|
+
if (!positiveTimer(healthyResetMs))
|
|
434
|
+
return new ConfigurationError("healthyResetMs", 'The supervisor option "restart.healthyResetMs" must be an integer from 1 through 2,147,483,647 milliseconds');
|
|
435
|
+
return Object.freeze({ maxAttempts, minDelayMs, maxDelayMs, healthyResetMs });
|
|
436
|
+
}
|
|
437
|
+
/** Validate Identify pacing: Parent spacing, or an application coordinator that replaces it */
|
|
438
|
+
function identifySettings(identify) {
|
|
439
|
+
if (identify !== undefined && !record(identify))
|
|
440
|
+
return new ConfigurationError("identify", "Supervisor Identify options must be an object");
|
|
441
|
+
if (identify !== undefined) {
|
|
442
|
+
const invalidKeys = supervisorOptionError(identify, ["minimumSpacingMs", "coordinator"], "identify", "Supervisor Identify options");
|
|
443
|
+
if (invalidKeys)
|
|
444
|
+
return invalidKeys;
|
|
445
|
+
}
|
|
446
|
+
const spacing = identify?.minimumSpacingMs;
|
|
447
|
+
const coordinator = identify?.coordinator;
|
|
448
|
+
if (coordinator !== undefined) {
|
|
449
|
+
if (spacing !== undefined)
|
|
450
|
+
return new ConfigurationError("identify", 'The supervisor options "identify.minimumSpacingMs" and "identify.coordinator" cannot be combined, because the coordinator owns Identify pacing', { hint: "Space the permits inside the coordinator instead" });
|
|
451
|
+
const permit = record(coordinator) ? coordinator.permit : undefined;
|
|
452
|
+
if (typeof permit !== "function")
|
|
453
|
+
return new ConfigurationError("identify", 'The supervisor option "identify.coordinator" must be an object with a permit function');
|
|
454
|
+
return { minimumSpacingMs: 0, coordinator: permit.bind(coordinator) };
|
|
455
|
+
}
|
|
456
|
+
const minimumSpacingMs = spacing === undefined ? 1_000 : spacing;
|
|
457
|
+
if (!positiveTimer(minimumSpacingMs) || minimumSpacingMs < 1_000)
|
|
458
|
+
return new ConfigurationError("minimumSpacingMs", 'The supervisor option "identify.minimumSpacingMs" must be an integer from 1,000 through 2,147,483,647 milliseconds');
|
|
459
|
+
return { minimumSpacingMs, coordinator: undefined };
|
|
460
|
+
}
|
|
461
|
+
/** Label for one child's forwarded output lines, naming its shard when it owns exactly one */
|
|
462
|
+
function outputLabel(configuration) {
|
|
463
|
+
const shards = configuration.assignment.shardIds;
|
|
464
|
+
return shards.length === 1 ? `[shard ${shards[0]}]` : `[child ${configuration.id}]`;
|
|
465
|
+
}
|
|
466
|
+
/** Longest forwarded line in characters. Longer lines are cut with a marker so one child cannot grow parent memory */
|
|
467
|
+
export const maximumForwardedLineLength = 262_144;
|
|
468
|
+
const truncationMarker = " … [line truncated by the supervisor]";
|
|
469
|
+
/** One child line in the parent's JSON Lines output. An SDK record gains a fields.child entry, another JSON object
|
|
470
|
+
* passes through unchanged, and any other text becomes a supervisor.childOutput record, so the output stays valid
|
|
471
|
+
*/
|
|
472
|
+
function jsonOutputLine(line, configuration, stream) {
|
|
473
|
+
try {
|
|
474
|
+
const value = JSON.parse(line);
|
|
475
|
+
if (record(value)) {
|
|
476
|
+
if (typeof value.level !== "string" || typeof value.code !== "string" || typeof value.category !== "string")
|
|
477
|
+
return line;
|
|
478
|
+
const fields = record(value.fields) ? value.fields : {};
|
|
479
|
+
return JSON.stringify({ ...value, fields: { ...fields, child: configuration.id } });
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
// allow-silent: A line that is not JSON is wrapped as a supervisor.childOutput record below
|
|
484
|
+
}
|
|
485
|
+
return JSON.stringify({
|
|
486
|
+
time: new Date().toISOString(),
|
|
487
|
+
level: stream === "stderr" ? "warn" : "info",
|
|
488
|
+
category: "supervisor",
|
|
489
|
+
code: "supervisor.childOutput",
|
|
490
|
+
message: maskText(line),
|
|
491
|
+
fields: { child: configuration.id, shards: configuration.assignment.shardIds.join(","), stream },
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Forward each line from a child stream in the parent's format for that stream: Labelled text for pretty output,
|
|
496
|
+
* or JSON Lines for json output. Lines longer than maximumForwardedLineLength are truncated with a marker, the child
|
|
497
|
+
* stream pauses while the parent stream applies backpressure, and a partial final line is forwarded at the end.
|
|
498
|
+
* The done callback runs once the child stream has ended or closed
|
|
499
|
+
*/
|
|
500
|
+
function forwardLines(stream, target, name, configuration, logger, done) {
|
|
501
|
+
if (!stream)
|
|
502
|
+
return done();
|
|
503
|
+
const label = outputLabel(configuration);
|
|
504
|
+
const json = logger.consoleFormat(name).format === "json";
|
|
505
|
+
let pending = "";
|
|
506
|
+
let skipping = false;
|
|
507
|
+
let finished = false;
|
|
508
|
+
const emit = (line) => {
|
|
509
|
+
const text = json ? jsonOutputLine(line, configuration, name) : `${label} ${line}`;
|
|
510
|
+
if (!target.write(`${text}\n`) && !stream.isPaused()) {
|
|
511
|
+
stream.pause();
|
|
512
|
+
target.once("drain", () => stream.resume());
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
stream.setEncoding("utf8");
|
|
516
|
+
stream.on("data", (chunk) => {
|
|
517
|
+
let start = 0;
|
|
518
|
+
while (start < chunk.length) {
|
|
519
|
+
const end = chunk.indexOf("\n", start);
|
|
520
|
+
const piece = chunk.slice(start, end === -1 ? chunk.length : end);
|
|
521
|
+
start = end === -1 ? chunk.length : end + 1;
|
|
522
|
+
if (!skipping) {
|
|
523
|
+
pending += piece;
|
|
524
|
+
if (pending.length > maximumForwardedLineLength) {
|
|
525
|
+
emit(`${pending.slice(0, maximumForwardedLineLength)}${truncationMarker}`);
|
|
526
|
+
pending = "";
|
|
527
|
+
skipping = true;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (end !== -1) {
|
|
531
|
+
if (!skipping)
|
|
532
|
+
emit(pending.endsWith("\r") ? pending.slice(0, -1) : pending);
|
|
533
|
+
pending = "";
|
|
534
|
+
skipping = false;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
const finish = () => {
|
|
539
|
+
if (finished)
|
|
540
|
+
return;
|
|
541
|
+
finished = true;
|
|
542
|
+
if (pending !== "" && !skipping)
|
|
543
|
+
emit(pending);
|
|
544
|
+
pending = "";
|
|
545
|
+
done();
|
|
546
|
+
};
|
|
547
|
+
stream.once("end", finish);
|
|
548
|
+
stream.once("close", finish);
|
|
549
|
+
// A read error ends forwarding of this stream while the child can keep running, so the error is recorded. The child's
|
|
550
|
+
// exit is still observed and logged separately
|
|
551
|
+
stream.once("error", (error) => {
|
|
552
|
+
logger.log({
|
|
553
|
+
level: "warn",
|
|
554
|
+
category: "supervisor",
|
|
555
|
+
code: "supervisor.outputFailed",
|
|
556
|
+
message: `Reading the ${name === "stdout" ? "standard output" : "standard error"} of child ${configuration.id} failed, so the supervisor stops forwarding it`,
|
|
557
|
+
error,
|
|
558
|
+
fields: { child: configuration.id, shards: configuration.assignment.shardIds.join(","), stream: name },
|
|
559
|
+
});
|
|
560
|
+
finish();
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
/** Owns only processes forked from one local supervisor instance */
|
|
564
|
+
function childSlot(configuration) {
|
|
565
|
+
return {
|
|
566
|
+
configuration,
|
|
567
|
+
generation: 0,
|
|
568
|
+
restarts: 0,
|
|
569
|
+
child: undefined,
|
|
570
|
+
hello: false,
|
|
571
|
+
ready: false,
|
|
572
|
+
readyAt: undefined,
|
|
573
|
+
connectionState: null,
|
|
574
|
+
diagnostics: null,
|
|
575
|
+
state: "idle",
|
|
576
|
+
restartTimer: undefined,
|
|
577
|
+
startupTimer: undefined,
|
|
578
|
+
stopTimer: undefined,
|
|
579
|
+
disconnectTimer: undefined,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
export class SupervisorOwner {
|
|
583
|
+
/** One slot per assignment. Empty for an automatic plan until its count completes */
|
|
584
|
+
#slots;
|
|
585
|
+
/** The running community count for totalShards "auto" */
|
|
586
|
+
#counting;
|
|
587
|
+
/** Whether the count finished, which can happen before runFork returns its fiber */
|
|
588
|
+
#countSettled = false;
|
|
589
|
+
/** Times of moves to a larger automatic plan, for the hourly limit */
|
|
590
|
+
#reshards = [];
|
|
591
|
+
/** The plan being replaced while its children stop and the communities are counted again */
|
|
592
|
+
#resharding;
|
|
593
|
+
#native;
|
|
594
|
+
#startup = Deferred.makeUnsafe();
|
|
595
|
+
#terminal = Deferred.makeUnsafe();
|
|
596
|
+
#stopped = Deferred.makeUnsafe();
|
|
597
|
+
#readiness = Deferred.makeUnsafe();
|
|
598
|
+
#readyObserved = false;
|
|
599
|
+
#configuration;
|
|
600
|
+
#state = "idle";
|
|
601
|
+
#stopping = false;
|
|
602
|
+
#failed = false;
|
|
603
|
+
#failure;
|
|
604
|
+
#pending = [];
|
|
605
|
+
#outstanding;
|
|
606
|
+
#lastIdentifyAt = -Infinity;
|
|
607
|
+
#grantTimer;
|
|
608
|
+
/** Host time at which the latest global rate-limit pause a child reported ends. Fluxer pauses the whole account */
|
|
609
|
+
#globalPauseUntil = 0;
|
|
610
|
+
/**
|
|
611
|
+
* Member requests of every child counted against Fluxer's account limit, oldest first. Only the latest
|
|
612
|
+
* memberRequestLimit decide admission, so no more are kept
|
|
613
|
+
*/
|
|
614
|
+
#memberRequests = [];
|
|
615
|
+
constructor(configuration, native = false) {
|
|
616
|
+
this.#configuration = configuration;
|
|
617
|
+
this.#native = native;
|
|
618
|
+
this.#slots = configuration.children.map(childSlot);
|
|
619
|
+
}
|
|
620
|
+
start() {
|
|
621
|
+
const owner = this;
|
|
622
|
+
return Effect.uninterruptibleMask((restore) => Effect.suspend(() => {
|
|
623
|
+
if (owner.#state === "closed" || owner.#state === "failed" || owner.#state === "stopping")
|
|
624
|
+
return Effect.fail(new SupervisorError(null, "closed"));
|
|
625
|
+
owner.#beginStart();
|
|
626
|
+
return restore(Deferred.await(owner.#startup)).pipe(Effect.onInterrupt(() => owner.shutdown()));
|
|
627
|
+
}));
|
|
628
|
+
}
|
|
629
|
+
waitForClose() {
|
|
630
|
+
return Deferred.await(this.#terminal);
|
|
631
|
+
}
|
|
632
|
+
waitForReady() {
|
|
633
|
+
return Effect.suspend(() => {
|
|
634
|
+
if (this.#state === "idle" || this.#state === "closed" || this.#state === "stopping")
|
|
635
|
+
return Effect.fail(new SupervisorError(null, "closed"));
|
|
636
|
+
if (this.#state === "failed")
|
|
637
|
+
return Effect.fail(this.#failure ?? new SupervisorError(null, "closed"));
|
|
638
|
+
if (this.#allConnected())
|
|
639
|
+
return Effect.void;
|
|
640
|
+
return Deferred.await(this.#readiness);
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
status() {
|
|
644
|
+
return Object.freeze({
|
|
645
|
+
state: this.#state,
|
|
646
|
+
children: Object.freeze(this.#slots.map((slot) => Object.freeze({
|
|
647
|
+
id: slot.configuration.id,
|
|
648
|
+
assignment: slot.configuration.assignment,
|
|
649
|
+
generation: slot.generation,
|
|
650
|
+
pid: typeof slot.child?.pid === "number" ? slot.child.pid : null,
|
|
651
|
+
restarts: slot.restarts,
|
|
652
|
+
state: slot.state,
|
|
653
|
+
connectionState: slot.connectionState,
|
|
654
|
+
diagnostics: slot.diagnostics,
|
|
655
|
+
}))),
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
shutdown() {
|
|
659
|
+
return Effect.uninterruptible(Effect.sync(() => this.#beginShutdown()).pipe(Effect.andThen(Deferred.await(this.#stopped))));
|
|
660
|
+
}
|
|
661
|
+
/** Whether every child reported Connected. An automatic plan that is still counting has no children yet */
|
|
662
|
+
#allConnected() {
|
|
663
|
+
return this.#slots.length > 0 && this.#slots.every((slot) => slot.connectionState === "Connected");
|
|
664
|
+
}
|
|
665
|
+
#beginStart() {
|
|
666
|
+
if (this.#state !== "idle")
|
|
667
|
+
return;
|
|
668
|
+
this.#state = "starting";
|
|
669
|
+
const automatic = this.#configuration.automatic;
|
|
670
|
+
if (automatic)
|
|
671
|
+
return this.#startCount(automatic);
|
|
672
|
+
this.#spawnAll();
|
|
673
|
+
}
|
|
674
|
+
/** Count the communities in the background, for the first plan or, while resharding, a larger one */
|
|
675
|
+
#startCount(automatic) {
|
|
676
|
+
this.#countSettled = false;
|
|
677
|
+
const counting = this.#countPlan(automatic);
|
|
678
|
+
const context = this.#configuration.logger.context;
|
|
679
|
+
const fiber = (context ? Effect.runForkWith(context) : Effect.runFork)(counting);
|
|
680
|
+
if (!this.#countSettled)
|
|
681
|
+
this.#counting = fiber;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Answer a child's 4011 (sharding required) closure under an automatic plan: Stop every child, then count the
|
|
685
|
+
* communities again and start a larger plan once all have exited. Beyond the hourly limit the supervisor fails, as a
|
|
686
|
+
* client with sharding "auto" ends. A second report during the move joins it
|
|
687
|
+
*/
|
|
688
|
+
#reshard(slot) {
|
|
689
|
+
if (this.#resharding !== undefined)
|
|
690
|
+
return;
|
|
691
|
+
const previousTotalShards = slot.configuration.assignment.totalShards;
|
|
692
|
+
const refused = admitReshard(this.#reshards, performance.now(), previousTotalShards);
|
|
693
|
+
if (refused !== undefined) {
|
|
694
|
+
this.#log("error", "supervisor.resharded", `Fluxer closed a shard of child ${slot.configuration.id} with close code 4011 (sharding required), but the supervisor cannot move to a larger plan because ${refused}, so the supervisor shuts down`, slot, { fields: { totalShards: previousTotalShards } });
|
|
695
|
+
this.#fail(new SupervisorError(slot.configuration.id, "closed"));
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
this.#resharding = { previousTotalShards, childId: slot.configuration.id };
|
|
699
|
+
if (this.#grantTimer)
|
|
700
|
+
clearTimeout(this.#grantTimer);
|
|
701
|
+
this.#grantTimer = undefined;
|
|
702
|
+
this.#pending = [];
|
|
703
|
+
// A granted Identify can still reach Fluxer before its child stops. It stays outstanding until the child reports
|
|
704
|
+
// it sent or exits, so the larger plan's first Identify keeps the spacing after it
|
|
705
|
+
if (this.#outstanding?.timer === undefined)
|
|
706
|
+
this.#clearOutstanding();
|
|
707
|
+
for (const current of this.#slots) {
|
|
708
|
+
if (current.restartTimer)
|
|
709
|
+
clearTimeout(current.restartTimer);
|
|
710
|
+
current.restartTimer = undefined;
|
|
711
|
+
if (current.startupTimer)
|
|
712
|
+
clearTimeout(current.startupTimer);
|
|
713
|
+
current.startupTimer = undefined;
|
|
714
|
+
if (current.child)
|
|
715
|
+
this.#requestStop(current);
|
|
716
|
+
else
|
|
717
|
+
current.state = "closed";
|
|
718
|
+
}
|
|
719
|
+
this.#continueReshard();
|
|
720
|
+
}
|
|
721
|
+
/** Count again once every child of the old plan has exited */
|
|
722
|
+
#continueReshard() {
|
|
723
|
+
if (this.#resharding === undefined || this.#counting || this.#slots.some((slot) => slot.child !== undefined))
|
|
724
|
+
return;
|
|
725
|
+
this.#startCount(this.#configuration.automatic);
|
|
726
|
+
}
|
|
727
|
+
#spawnAll() {
|
|
728
|
+
for (const slot of this.#slots) {
|
|
729
|
+
this.#spawn(slot);
|
|
730
|
+
if (this.#failed)
|
|
731
|
+
break;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Count the bot's communities with a transient client, then split the resulting plan into children and start them.
|
|
736
|
+
* Shutdown interrupts the count, and cleanup completes only after the transient client has closed
|
|
737
|
+
*/
|
|
738
|
+
#countPlan(automatic) {
|
|
739
|
+
const owner = this;
|
|
740
|
+
const configuration = this.#configuration;
|
|
741
|
+
const count = Effect.scoped(Effect.gen(function* () {
|
|
742
|
+
const scope = yield* Effect.scope;
|
|
743
|
+
const client = yield* makeClient(automatic.clientOptions, scope, owner.#native);
|
|
744
|
+
yield* Effect.addFinalizer(() => client.shutdown());
|
|
745
|
+
return yield* client.countGuilds(configuration.startupTimeoutMs);
|
|
746
|
+
}));
|
|
747
|
+
// onExit also runs when shutdown interrupts the count, so shutdown can finish after the client has closed
|
|
748
|
+
return count.pipe(Effect.onExit((exit) => Effect.sync(() => owner.#planned(exit, automatic.split))),
|
|
749
|
+
// allow-silent: #planned turns a failed count into the SupervisorError that start and waitForClose return
|
|
750
|
+
Effect.ignore);
|
|
751
|
+
}
|
|
752
|
+
#planned(exit, split) {
|
|
753
|
+
this.#counting = undefined;
|
|
754
|
+
this.#countSettled = true;
|
|
755
|
+
if (this.#stopping || this.#failed)
|
|
756
|
+
return this.#checkStopped();
|
|
757
|
+
if (Exit.isFailure(exit)) {
|
|
758
|
+
const failure = exit.cause.reasons.find((reason) => reason._tag === "Fail");
|
|
759
|
+
const cause = failure?._tag === "Fail" ? failure.error : Cause.squash(exit.cause);
|
|
760
|
+
return this.#fail(new SupervisorError(null, "shardCount", { cause }));
|
|
761
|
+
}
|
|
762
|
+
const guilds = exit.value;
|
|
763
|
+
const resharding = this.#resharding;
|
|
764
|
+
this.#resharding = undefined;
|
|
765
|
+
if (resharding !== undefined) {
|
|
766
|
+
const { totalShards } = largerShardPlan(guilds, resharding.previousTotalShards);
|
|
767
|
+
this.#slots = splitShards(totalShards, split).map(childSlot);
|
|
768
|
+
this.#log("warn", "supervisor.resharded", `Fluxer closed a shard of child ${resharding.childId} with close code 4011 (sharding required), so the supervisor moved from ${resharding.previousTotalShards} to ${totalShards} shards for ${guilds} communit${guilds === 1 ? "y" : "ies"}, split across ${this.#slots.length} child process${this.#slots.length === 1 ? "" : "es"}. Every shard starts a new session, so events sent during the move are missed`, undefined, {
|
|
769
|
+
fields: {
|
|
770
|
+
guilds,
|
|
771
|
+
previousTotalShards: resharding.previousTotalShards,
|
|
772
|
+
totalShards,
|
|
773
|
+
children: this.#slots.length,
|
|
774
|
+
},
|
|
775
|
+
});
|
|
776
|
+
return this.#spawnAll();
|
|
777
|
+
}
|
|
778
|
+
const { totalShards } = automaticShardPlan(guilds);
|
|
779
|
+
this.#slots = splitShards(totalShards, split).map(childSlot);
|
|
780
|
+
this.#log("info", "supervisor.automaticSharding", `The supervisor chose ${totalShards} shard${totalShards === 1 ? "" : "s"} for ${guilds} communit${guilds === 1 ? "y" : "ies"}, aiming for at most ${guildsPerShard} per shard on average, split across ${this.#slots.length} child process${this.#slots.length === 1 ? "" : "es"}`, undefined, { fields: { guilds, totalShards, guildsPerShard, children: this.#slots.length } });
|
|
781
|
+
this.#spawnAll();
|
|
782
|
+
}
|
|
783
|
+
#spawn(slot) {
|
|
784
|
+
if (this.#stopping || this.#failed)
|
|
785
|
+
return;
|
|
786
|
+
this.#clearDisconnectTimer(slot);
|
|
787
|
+
slot.generation += 1;
|
|
788
|
+
slot.hello = false;
|
|
789
|
+
slot.ready = false;
|
|
790
|
+
slot.readyAt = undefined;
|
|
791
|
+
slot.connectionState = null;
|
|
792
|
+
slot.diagnostics = null;
|
|
793
|
+
slot.state = "starting";
|
|
794
|
+
let child;
|
|
795
|
+
const generation = slot.generation;
|
|
796
|
+
const output = this.#configuration.childOutput;
|
|
797
|
+
const stdio = output === "prefix" ? "pipe" : output;
|
|
798
|
+
// Prefixed children write into pipes, so they receive the parent's console format and color rather than
|
|
799
|
+
// choosing JSON for a non-terminal output. Explicit environment values still win
|
|
800
|
+
const inherited = output === "prefix"
|
|
801
|
+
? (() => {
|
|
802
|
+
const { format, color } = this.#configuration.logger.consoleFormat("stdout");
|
|
803
|
+
return { FLUXERLY_LOG_FORMAT: format, FLUXERLY_LOG_COLOR: color ? "1" : "0" };
|
|
804
|
+
})()
|
|
805
|
+
: {};
|
|
806
|
+
try {
|
|
807
|
+
child = fork(this.#configuration.entry, [...this.#configuration.args], {
|
|
808
|
+
env: { ...inherited, ...Object.fromEntries(this.#configuration.environment) },
|
|
809
|
+
execArgv: [...this.#configuration.execArgv],
|
|
810
|
+
stdio: ["ignore", stdio, stdio, "ipc"],
|
|
811
|
+
windowsHide: true,
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
catch (error) {
|
|
815
|
+
slot.state = "failed";
|
|
816
|
+
this.#log("error", "supervisor.spawnFailed", `Could not start child ${slot.configuration.id}`, slot, {
|
|
817
|
+
error,
|
|
818
|
+
});
|
|
819
|
+
this.#fail(new SupervisorError(slot.configuration.id, "spawn", { cause: error }));
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
// Exit is handled after forwarded output has drained, so a crash stack trace printed just before exit is kept.
|
|
823
|
+
// A grandchild holding a pipe open cannot delay exit handling beyond a bounded grace period
|
|
824
|
+
let openStreams = output === "prefix" ? 2 : 0;
|
|
825
|
+
let exited;
|
|
826
|
+
let grace;
|
|
827
|
+
const settle = (force = false) => {
|
|
828
|
+
if (!exited || (openStreams > 0 && !force))
|
|
829
|
+
return;
|
|
830
|
+
const [code, signal] = exited;
|
|
831
|
+
exited = undefined;
|
|
832
|
+
if (grace)
|
|
833
|
+
clearTimeout(grace);
|
|
834
|
+
this.#exit(slot, child, generation, code, signal);
|
|
835
|
+
};
|
|
836
|
+
if (output === "prefix") {
|
|
837
|
+
const drained = () => {
|
|
838
|
+
openStreams -= 1;
|
|
839
|
+
settle();
|
|
840
|
+
};
|
|
841
|
+
const logger = this.#configuration.logger;
|
|
842
|
+
forwardLines(child.stdout, process.stdout, "stdout", slot.configuration, logger, drained);
|
|
843
|
+
forwardLines(child.stderr, process.stderr, "stderr", slot.configuration, logger, drained);
|
|
844
|
+
}
|
|
845
|
+
this.#log("info", "supervisor.spawn", `Started child ${slot.configuration.id}${typeof child.pid === "number" ? ` (pid ${child.pid})` : ""} for ${slot.configuration.assignment.shardIds.length === 1 ? "shard" : "shards"} ${slot.configuration.assignment.shardIds.join(", ")}`, slot, { fields: { generation: slot.generation } });
|
|
846
|
+
slot.child = child;
|
|
847
|
+
const startupTimeoutMs = this.#configuration.startupTimeoutMs;
|
|
848
|
+
slot.startupTimer = setTimeout(() => {
|
|
849
|
+
if (slot.child !== child || slot.generation !== generation || slot.ready)
|
|
850
|
+
return;
|
|
851
|
+
this.#log("error", "supervisor.startupTimeout", `Child ${slot.configuration.id} did not become ready within ${startupTimeoutMs} ms (startupTimeoutMs), so the supervisor shuts down`, slot, { fields: { startupTimeoutMs } });
|
|
852
|
+
this.#fail(new SupervisorError(slot.configuration.id, "startupTimeout"));
|
|
853
|
+
}, startupTimeoutMs);
|
|
854
|
+
child.on("message", (message) => this.#message(slot, child, generation, message));
|
|
855
|
+
child.once("disconnect", () => this.#disconnect(slot, child, generation));
|
|
856
|
+
child.once("error", (error) => this.#childError(slot, child, generation, error));
|
|
857
|
+
child.once("exit", (code, signal) => {
|
|
858
|
+
exited = [code, signal];
|
|
859
|
+
if (openStreams > 0)
|
|
860
|
+
grace = setTimeout(() => settle(true), outputDrainGraceMs);
|
|
861
|
+
settle();
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
#log(level, code, message, slot, extra = {}) {
|
|
865
|
+
this.#configuration?.logger.log({
|
|
866
|
+
level,
|
|
867
|
+
category: "supervisor",
|
|
868
|
+
code,
|
|
869
|
+
message,
|
|
870
|
+
...(extra.error === undefined ? {} : { error: extra.error }),
|
|
871
|
+
...(extra.origin === undefined ? {} : { origin: extra.origin }),
|
|
872
|
+
fields: {
|
|
873
|
+
...(slot === undefined
|
|
874
|
+
? {}
|
|
875
|
+
: { child: slot.configuration.id, shards: slot.configuration.assignment.shardIds.join(",") }),
|
|
876
|
+
...extra.fields,
|
|
877
|
+
},
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
#childError(slot, child, generation, error) {
|
|
881
|
+
if (slot.child !== child || slot.generation !== generation)
|
|
882
|
+
return;
|
|
883
|
+
slot.state = "failed";
|
|
884
|
+
this.#log("error", "supervisor.spawnFailed", `Child ${slot.configuration.id} failed to start, or the supervisor could not send it a message`, slot, {
|
|
885
|
+
error,
|
|
886
|
+
});
|
|
887
|
+
this.#fail(new SupervisorError(slot.configuration.id, "spawn", { cause: error }));
|
|
888
|
+
if (typeof child.pid !== "number") {
|
|
889
|
+
if (slot.stopTimer)
|
|
890
|
+
clearTimeout(slot.stopTimer);
|
|
891
|
+
slot.stopTimer = undefined;
|
|
892
|
+
this.#clearDisconnectTimer(slot);
|
|
893
|
+
slot.child = undefined;
|
|
894
|
+
this.#checkStopped();
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
this.#requestStop(slot);
|
|
898
|
+
}
|
|
899
|
+
#disconnect(slot, child, generation) {
|
|
900
|
+
if (slot.child !== child || slot.generation !== generation)
|
|
901
|
+
return;
|
|
902
|
+
slot.connectionState = null;
|
|
903
|
+
this.#refreshReadiness();
|
|
904
|
+
if (this.#stopping || this.#failed || slot.disconnectTimer)
|
|
905
|
+
return;
|
|
906
|
+
if (slot.startupTimer)
|
|
907
|
+
clearTimeout(slot.startupTimer);
|
|
908
|
+
slot.startupTimer = undefined;
|
|
909
|
+
this.#pending = this.#pending.filter((request) => request.slot !== slot || request.generation !== generation);
|
|
910
|
+
if (this.#outstanding?.slot === slot && this.#outstanding.generation === generation) {
|
|
911
|
+
if (this.#outstanding.timer)
|
|
912
|
+
clearTimeout(this.#outstanding.timer);
|
|
913
|
+
this.#outstanding.permit?.abort();
|
|
914
|
+
}
|
|
915
|
+
// A normal process exit closes IPC just before its exit event. Reuse the configured graceful deadline
|
|
916
|
+
// before classifying a still-running current child as a terminal supervisor failure
|
|
917
|
+
const shutdownTimeoutMs = this.#configuration.shutdownTimeoutMs;
|
|
918
|
+
slot.disconnectTimer = setTimeout(() => {
|
|
919
|
+
slot.disconnectTimer = undefined;
|
|
920
|
+
if (this.#stopping ||
|
|
921
|
+
this.#failed ||
|
|
922
|
+
slot.child !== child ||
|
|
923
|
+
slot.generation !== generation ||
|
|
924
|
+
child.exitCode !== null ||
|
|
925
|
+
child.signalCode !== null)
|
|
926
|
+
return;
|
|
927
|
+
// The observation window is the disconnected child's only graceful exit window. Do not give it a
|
|
928
|
+
// second shutdown timeout after terminal coordination loss, while sibling children still receive
|
|
929
|
+
// their normal graceful stop request
|
|
930
|
+
this.#log("error", "supervisor.terminated", `Child ${slot.configuration.id} lost its message channel to the supervisor and was still running ${shutdownTimeoutMs} ms later (shutdownTimeoutMs), so the supervisor shuts down and force-terminates it`, slot, { fields: { shutdownTimeoutMs } });
|
|
931
|
+
this.#fail(new SupervisorError(slot.configuration.id, "closed"));
|
|
932
|
+
this.#requestStop(slot, true);
|
|
933
|
+
}, shutdownTimeoutMs);
|
|
934
|
+
}
|
|
935
|
+
#message(slot, child, generation, message) {
|
|
936
|
+
if (slot.child !== child || slot.generation !== generation || slot.disconnectTimer)
|
|
937
|
+
return;
|
|
938
|
+
// Children that drain during a shutdown still share the account limits, so they never wait for an answer
|
|
939
|
+
if (this.#accountLimitMessage(slot, generation, message))
|
|
940
|
+
return;
|
|
941
|
+
if (this.#stopping || this.#failed)
|
|
942
|
+
return;
|
|
943
|
+
if (!record(message) || typeof message.type !== "string")
|
|
944
|
+
return this.#fail(new SupervisorError(slot.configuration.id, "protocol"));
|
|
945
|
+
if ("generation" in message && message.generation !== generation)
|
|
946
|
+
return;
|
|
947
|
+
if (message.type === "hello") {
|
|
948
|
+
if (!hasExactKeys(message, ["type"]) || slot.hello)
|
|
949
|
+
return this.#fail(new SupervisorError(slot.configuration.id, "protocol"));
|
|
950
|
+
slot.hello = true;
|
|
951
|
+
const { diagnosticsIntervalMs, shutdownTimeoutMs } = this.#configuration;
|
|
952
|
+
this.#send(slot, {
|
|
953
|
+
type: "assignment",
|
|
954
|
+
generation,
|
|
955
|
+
assignment: slot.configuration.assignment,
|
|
956
|
+
diagnosticsIntervalMs,
|
|
957
|
+
// A stopping child lets running work finish, keeping a reserve of shutdownTimeoutMs to close
|
|
958
|
+
drainMs: Math.max(0, shutdownTimeoutMs - childCloseReserveMs),
|
|
959
|
+
});
|
|
960
|
+
// A new or restarted child starts with the account's running global pause
|
|
961
|
+
const waitMs = Math.ceil(this.#globalPauseUntil - performance.now());
|
|
962
|
+
if (waitMs > 0)
|
|
963
|
+
this.#send(slot, { type: "globalPause", generation, waitMs });
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
if (message.type === "diagnostics" &&
|
|
967
|
+
hasExactKeys(message, ["type", "generation", "diagnostics"]) &&
|
|
968
|
+
slot.ready &&
|
|
969
|
+
record(message.diagnostics) &&
|
|
970
|
+
hasExactKeys(message.diagnostics, diagnosticsKeys)) {
|
|
971
|
+
slot.diagnostics = Object.freeze({
|
|
972
|
+
receivedAt: Date.now(),
|
|
973
|
+
client: deepFreeze(message.diagnostics),
|
|
974
|
+
});
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
if (message.type === "state" &&
|
|
978
|
+
hasExactKeys(message, ["type", "generation", "state"]) &&
|
|
979
|
+
slot.hello &&
|
|
980
|
+
!slot.ready &&
|
|
981
|
+
connectionState(message.state))
|
|
982
|
+
return;
|
|
983
|
+
if (message.type === "ready" && hasExactKeys(message, ["type", "generation"]) && slot.hello && !slot.ready) {
|
|
984
|
+
slot.ready = true;
|
|
985
|
+
slot.readyAt = performance.now();
|
|
986
|
+
slot.state = "running";
|
|
987
|
+
if (slot.startupTimer)
|
|
988
|
+
clearTimeout(slot.startupTimer);
|
|
989
|
+
slot.startupTimer = undefined;
|
|
990
|
+
if (this.#slots.every((current) => current.ready)) {
|
|
991
|
+
this.#state = "running";
|
|
992
|
+
Deferred.doneUnsafe(this.#startup, Effect.void);
|
|
993
|
+
}
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
if (message.type === "state" &&
|
|
997
|
+
hasExactKeys(message, ["type", "generation", "state"]) &&
|
|
998
|
+
slot.hello &&
|
|
999
|
+
slot.ready &&
|
|
1000
|
+
connectionState(message.state)) {
|
|
1001
|
+
slot.connectionState = message.state;
|
|
1002
|
+
this.#refreshReadiness();
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
if (message.type === "identify" &&
|
|
1006
|
+
hasExactKeys(message, ["type", "generation", "requestId", "shardId"]) &&
|
|
1007
|
+
safeInteger(message.requestId) &&
|
|
1008
|
+
message.requestId >= 0 &&
|
|
1009
|
+
safeInteger(message.shardId) &&
|
|
1010
|
+
slot.hello &&
|
|
1011
|
+
slot.ready &&
|
|
1012
|
+
slot.configuration.assignment.shardIds.includes(message.shardId)) {
|
|
1013
|
+
// Every child stops during a reshard, so its request stays unanswered until stopping withdraws it
|
|
1014
|
+
if (this.#resharding !== undefined)
|
|
1015
|
+
return;
|
|
1016
|
+
if (this.#pending.some((request) => request.slot === slot &&
|
|
1017
|
+
request.generation === generation &&
|
|
1018
|
+
request.requestId === message.requestId) ||
|
|
1019
|
+
(this.#outstanding?.slot === slot &&
|
|
1020
|
+
this.#outstanding.generation === generation &&
|
|
1021
|
+
this.#outstanding.requestId === message.requestId))
|
|
1022
|
+
return this.#fail(new SupervisorError(slot.configuration.id, "protocol"));
|
|
1023
|
+
this.#pending.push({ slot, generation, requestId: message.requestId, shardId: message.shardId });
|
|
1024
|
+
this.#scheduleGrant();
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
if (message.type === "cancel" &&
|
|
1028
|
+
hasExactKeys(message, ["type", "generation", "requestId"]) &&
|
|
1029
|
+
safeInteger(message.requestId) &&
|
|
1030
|
+
message.requestId >= 0) {
|
|
1031
|
+
if (this.#outstanding?.slot === slot &&
|
|
1032
|
+
this.#outstanding.generation === generation &&
|
|
1033
|
+
this.#outstanding.requestId === message.requestId) {
|
|
1034
|
+
if (this.#outstanding.stalled)
|
|
1035
|
+
return;
|
|
1036
|
+
this.#clearOutstanding();
|
|
1037
|
+
this.#send(slot, { type: "cancelled", generation, requestId: message.requestId });
|
|
1038
|
+
this.#scheduleGrant();
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
this.#pending = this.#pending.filter((request) => !(request.slot === slot &&
|
|
1042
|
+
request.generation === generation &&
|
|
1043
|
+
request.requestId === message.requestId));
|
|
1044
|
+
this.#send(slot, { type: "cancelled", generation, requestId: message.requestId });
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
if (message.type === "sent" &&
|
|
1048
|
+
hasExactKeys(message, ["type", "generation", "requestId"]) &&
|
|
1049
|
+
safeInteger(message.requestId) &&
|
|
1050
|
+
this.#outstanding?.slot === slot &&
|
|
1051
|
+
this.#outstanding.generation === generation &&
|
|
1052
|
+
this.#outstanding.requestId === message.requestId &&
|
|
1053
|
+
// A send before the grant, while the coordinator is still deciding, is a protocol failure
|
|
1054
|
+
this.#outstanding.timer !== undefined) {
|
|
1055
|
+
if (this.#outstanding.stalled)
|
|
1056
|
+
return;
|
|
1057
|
+
this.#clearOutstanding();
|
|
1058
|
+
this.#lastIdentifyAt = performance.now();
|
|
1059
|
+
this.#scheduleGrant();
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
if ((message.type === "closed" || message.type === "failed") &&
|
|
1063
|
+
hasExactKeys(message, message.type === "closed" ? ["type", "generation"] : ["type", "generation", "reason"]) &&
|
|
1064
|
+
slot.hello) {
|
|
1065
|
+
if (message.type === "failed" &&
|
|
1066
|
+
message.reason !== "client" &&
|
|
1067
|
+
message.reason !== "configure" &&
|
|
1068
|
+
message.reason !== "sharding")
|
|
1069
|
+
return this.#fail(new SupervisorError(slot.configuration.id, "protocol"));
|
|
1070
|
+
// An explicit total is the application's plan, so its 4011 closure is an ordinary child failure
|
|
1071
|
+
if (message.type === "failed" && message.reason === "sharding" && this.#configuration.automatic)
|
|
1072
|
+
return this.#reshard(slot);
|
|
1073
|
+
this.#requestStop(slot);
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
this.#fail(new SupervisorError(slot.configuration.id, "protocol"));
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Handle a child message about Fluxer's account-wide limits, in every supervisor state. Returns false for any other
|
|
1080
|
+
* message, including a malformed one, which the caller then treats like other messages
|
|
1081
|
+
*/
|
|
1082
|
+
#accountLimitMessage(slot, generation, message) {
|
|
1083
|
+
if (!record(message) || message.generation !== generation || !slot.hello)
|
|
1084
|
+
return false;
|
|
1085
|
+
const { type, requestId } = message;
|
|
1086
|
+
const request = safeInteger(requestId) && requestId >= 0 ? requestId : undefined;
|
|
1087
|
+
const exact = (keys) => hasExactKeys(message, ["type", "generation", ...keys]);
|
|
1088
|
+
if (type === "globalPause" && exact(["waitMs"]) && positiveTimer(message.waitMs)) {
|
|
1089
|
+
this.#relayGlobalPause(slot, message.waitMs);
|
|
1090
|
+
return true;
|
|
1091
|
+
}
|
|
1092
|
+
if (type === "memberRequest" && exact(["requestId"]) && request !== undefined) {
|
|
1093
|
+
const now = performance.now();
|
|
1094
|
+
this.#memberRequests = this.#memberRequests.filter(({ at }) => at > now - memberRequestWindowMs);
|
|
1095
|
+
if (this.#memberRequests.length >= memberRequestLimit) {
|
|
1096
|
+
const oldest = this.#memberRequests[this.#memberRequests.length - memberRequestLimit];
|
|
1097
|
+
this.#send(slot, {
|
|
1098
|
+
type: "memberDenied",
|
|
1099
|
+
generation,
|
|
1100
|
+
requestId: request,
|
|
1101
|
+
retryAfterMs: Math.max(1, Math.ceil(oldest.at + memberRequestWindowMs - now)),
|
|
1102
|
+
});
|
|
1103
|
+
return true;
|
|
1104
|
+
}
|
|
1105
|
+
this.#countMemberRequest({ at: now, holder: { slot, generation, requestId: request } });
|
|
1106
|
+
this.#send(slot, { type: "memberGrant", generation, requestId: request });
|
|
1107
|
+
return true;
|
|
1108
|
+
}
|
|
1109
|
+
// A sent report without requestId is a member request that had no grant, such as one from gateway.send
|
|
1110
|
+
if (type === "memberSent" && (exact([]) || (exact(["requestId"]) && request !== undefined))) {
|
|
1111
|
+
if (request !== undefined)
|
|
1112
|
+
this.#releaseMemberRequest(slot, generation, request);
|
|
1113
|
+
this.#countMemberRequest({ at: performance.now() });
|
|
1114
|
+
return true;
|
|
1115
|
+
}
|
|
1116
|
+
if (type === "memberWithdrawn" && exact(["requestId"]) && request !== undefined) {
|
|
1117
|
+
this.#releaseMemberRequest(slot, generation, request);
|
|
1118
|
+
return true;
|
|
1119
|
+
}
|
|
1120
|
+
return false;
|
|
1121
|
+
}
|
|
1122
|
+
/** Record a global pause one child learned and pass it to every other child, unless a running pause ends later */
|
|
1123
|
+
#relayGlobalPause(source, waitMs) {
|
|
1124
|
+
const until = performance.now() + waitMs;
|
|
1125
|
+
if (until <= this.#globalPauseUntil)
|
|
1126
|
+
return;
|
|
1127
|
+
this.#globalPauseUntil = until;
|
|
1128
|
+
for (const slot of this.#slots)
|
|
1129
|
+
if (slot !== source && slot.hello && slot.child?.connected && !slot.disconnectTimer)
|
|
1130
|
+
this.#send(slot, { type: "globalPause", generation: slot.generation, waitMs });
|
|
1131
|
+
}
|
|
1132
|
+
/** Count a member request as the latest, keeping only the latest memberRequestLimit */
|
|
1133
|
+
#countMemberRequest(request) {
|
|
1134
|
+
this.#memberRequests.push(request);
|
|
1135
|
+
if (this.#memberRequests.length > memberRequestLimit)
|
|
1136
|
+
this.#memberRequests.shift();
|
|
1137
|
+
}
|
|
1138
|
+
/** Stop counting a child's granted request from its grant. It has been withdrawn, or is counted again as sent */
|
|
1139
|
+
#releaseMemberRequest(slot, generation, requestId) {
|
|
1140
|
+
const index = this.#memberRequests.findIndex(({ holder }) => holder?.slot === slot && holder.generation === generation && holder.requestId === requestId);
|
|
1141
|
+
if (index !== -1)
|
|
1142
|
+
this.#memberRequests.splice(index, 1);
|
|
1143
|
+
}
|
|
1144
|
+
#scheduleGrant() {
|
|
1145
|
+
if (this.#grantTimer || this.#outstanding || this.#stopping || this.#failed || this.#pending.length === 0)
|
|
1146
|
+
return;
|
|
1147
|
+
const delay = Math.max(0, this.#lastIdentifyAt + this.#configuration.minimumSpacingMs - performance.now());
|
|
1148
|
+
if (delay === 0)
|
|
1149
|
+
return this.#grant();
|
|
1150
|
+
this.#grantTimer = setTimeout(() => {
|
|
1151
|
+
this.#grantTimer = undefined;
|
|
1152
|
+
this.#scheduleGrant();
|
|
1153
|
+
}, Math.ceil(delay));
|
|
1154
|
+
}
|
|
1155
|
+
#refreshReadiness() {
|
|
1156
|
+
const ready = this.#allConnected();
|
|
1157
|
+
if (ready && !this.#readyObserved) {
|
|
1158
|
+
this.#readyObserved = true;
|
|
1159
|
+
Deferred.doneUnsafe(this.#readiness, Effect.void);
|
|
1160
|
+
}
|
|
1161
|
+
else if (!ready && this.#readyObserved) {
|
|
1162
|
+
this.#readyObserved = false;
|
|
1163
|
+
this.#readiness = Deferred.makeUnsafe();
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
#grant() {
|
|
1167
|
+
if (this.#stopping || this.#failed || this.#outstanding)
|
|
1168
|
+
return;
|
|
1169
|
+
while (this.#pending.length) {
|
|
1170
|
+
const request = this.#pending.shift();
|
|
1171
|
+
if (request.slot.child === undefined || request.slot.generation !== request.generation)
|
|
1172
|
+
continue;
|
|
1173
|
+
const outstanding = { ...request, timer: undefined, permit: undefined, stalled: false };
|
|
1174
|
+
this.#outstanding = outstanding;
|
|
1175
|
+
const coordinator = this.#configuration.coordinator;
|
|
1176
|
+
if (coordinator)
|
|
1177
|
+
this.#askCoordinator(outstanding, coordinator);
|
|
1178
|
+
else
|
|
1179
|
+
this.#sendGrant(outstanding);
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Wait for the application coordinator before granting. The request stays outstanding meanwhile, so no other child
|
|
1185
|
+
* is granted, and a cancel, exit or shutdown aborts the permit signal
|
|
1186
|
+
*/
|
|
1187
|
+
#askCoordinator(outstanding, coordinator) {
|
|
1188
|
+
const controller = new AbortController();
|
|
1189
|
+
outstanding.permit = controller;
|
|
1190
|
+
const slot = outstanding.slot;
|
|
1191
|
+
const totalShards = slot.configuration.assignment.totalShards;
|
|
1192
|
+
let permit;
|
|
1193
|
+
try {
|
|
1194
|
+
permit = Promise.resolve(coordinator(outstanding.shardId, totalShards, controller.signal));
|
|
1195
|
+
}
|
|
1196
|
+
catch (error) {
|
|
1197
|
+
permit = Promise.reject(error);
|
|
1198
|
+
}
|
|
1199
|
+
permit.then(() => {
|
|
1200
|
+
if (controller.signal.aborted || this.#outstanding !== outstanding)
|
|
1201
|
+
return;
|
|
1202
|
+
outstanding.permit = undefined;
|
|
1203
|
+
this.#sendGrant(outstanding);
|
|
1204
|
+
}, (error) => {
|
|
1205
|
+
// A rejection after this supervisor aborted the permit answers its own cancellation
|
|
1206
|
+
if (controller.signal.aborted || this.#outstanding !== outstanding)
|
|
1207
|
+
return;
|
|
1208
|
+
outstanding.permit = undefined;
|
|
1209
|
+
this.#log("error", "supervisor.identifyPermitFailed", `The identify coordinator (identify.coordinator) failed to grant shard ${outstanding.shardId} permission to start a new session, so child ${slot.configuration.id} retries the connection as after a network failure`, slot, { error, origin: "application", fields: { shardId: outstanding.shardId } });
|
|
1210
|
+
this.#clearOutstanding();
|
|
1211
|
+
this.#send(slot, {
|
|
1212
|
+
type: "denied",
|
|
1213
|
+
generation: outstanding.generation,
|
|
1214
|
+
requestId: outstanding.requestId,
|
|
1215
|
+
});
|
|
1216
|
+
this.#scheduleGrant();
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
#sendGrant(outstanding) {
|
|
1220
|
+
outstanding.timer = setTimeout(() => {
|
|
1221
|
+
if (this.#outstanding === outstanding) {
|
|
1222
|
+
outstanding.stalled = true;
|
|
1223
|
+
this.#log("warn", "supervisor.identifyUnacknowledged", `Child ${outstanding.slot.configuration.id} did not confirm sending Identify for shard ${outstanding.shardId} within ${grantAcknowledgementMs} ms of its permission, so the supervisor stops it`, outstanding.slot, { fields: { shardId: outstanding.shardId } });
|
|
1224
|
+
this.#requestStop(outstanding.slot);
|
|
1225
|
+
}
|
|
1226
|
+
}, grantAcknowledgementMs);
|
|
1227
|
+
if (!this.#send(outstanding.slot, {
|
|
1228
|
+
type: "grant",
|
|
1229
|
+
generation: outstanding.generation,
|
|
1230
|
+
requestId: outstanding.requestId,
|
|
1231
|
+
}))
|
|
1232
|
+
this.#requestStop(outstanding.slot);
|
|
1233
|
+
}
|
|
1234
|
+
#clearOutstanding() {
|
|
1235
|
+
if (!this.#outstanding)
|
|
1236
|
+
return;
|
|
1237
|
+
if (this.#outstanding.timer)
|
|
1238
|
+
clearTimeout(this.#outstanding.timer);
|
|
1239
|
+
this.#outstanding.permit?.abort();
|
|
1240
|
+
this.#outstanding = undefined;
|
|
1241
|
+
}
|
|
1242
|
+
#send(slot, message) {
|
|
1243
|
+
const child = slot.child;
|
|
1244
|
+
if (!child || !child.connected) {
|
|
1245
|
+
// Parent-initiated shutdown remains successful when a child has already lost IPC. The owned process
|
|
1246
|
+
// still follows the normal stop deadline and verified-exit path
|
|
1247
|
+
if (!this.#stopping && !this.#failed && !slot.disconnectTimer)
|
|
1248
|
+
this.#fail(new SupervisorError(slot.configuration.id, "spawn"));
|
|
1249
|
+
return false;
|
|
1250
|
+
}
|
|
1251
|
+
try {
|
|
1252
|
+
child.send(message, undefined, undefined, (error) => {
|
|
1253
|
+
// A child exiting on its own can fail a stop request with EPIPE before IPC reports the disconnect.
|
|
1254
|
+
// The stop deadline and verified exit still complete a shutdown or the stop of one child, so a failed
|
|
1255
|
+
// send cannot fail either
|
|
1256
|
+
if (error &&
|
|
1257
|
+
slot.child === child &&
|
|
1258
|
+
!this.#stopping &&
|
|
1259
|
+
slot.state !== "stopping" &&
|
|
1260
|
+
!slot.disconnectTimer)
|
|
1261
|
+
this.#childError(slot, child, slot.generation, error);
|
|
1262
|
+
});
|
|
1263
|
+
return true;
|
|
1264
|
+
}
|
|
1265
|
+
catch (error) {
|
|
1266
|
+
if ((this.#stopping && !child.connected) || slot.disconnectTimer)
|
|
1267
|
+
return false;
|
|
1268
|
+
this.#childError(slot, child, slot.generation, error);
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
#exit(slot, child, generation, code = null, signal = null) {
|
|
1273
|
+
if (slot.child !== child || slot.generation !== generation)
|
|
1274
|
+
return;
|
|
1275
|
+
const expected = this.#stopping || slot.state === "stopping";
|
|
1276
|
+
this.#log(expected ? "info" : "warn", "supervisor.exit", `Child ${slot.configuration.id} exited${signal === null ? ` with code ${code ?? "unknown"}` : ` after signal ${signal}`}${expected ? "" : " unexpectedly"}`, slot, { fields: { exitCode: code, signal } });
|
|
1277
|
+
slot.child = undefined;
|
|
1278
|
+
slot.connectionState = null;
|
|
1279
|
+
slot.diagnostics = null;
|
|
1280
|
+
this.#refreshReadiness();
|
|
1281
|
+
if (slot.startupTimer)
|
|
1282
|
+
clearTimeout(slot.startupTimer);
|
|
1283
|
+
slot.startupTimer = undefined;
|
|
1284
|
+
if (slot.stopTimer)
|
|
1285
|
+
clearTimeout(slot.stopTimer);
|
|
1286
|
+
slot.stopTimer = undefined;
|
|
1287
|
+
this.#clearDisconnectTimer(slot);
|
|
1288
|
+
this.#pending = this.#pending.filter((request) => request.slot !== slot || request.generation !== generation);
|
|
1289
|
+
if (this.#outstanding?.slot === slot && this.#outstanding.generation === generation) {
|
|
1290
|
+
this.#clearOutstanding();
|
|
1291
|
+
// The child might have sent after the parent lost IPC, so start a fresh full interval only after verified exit
|
|
1292
|
+
this.#lastIdentifyAt = performance.now();
|
|
1293
|
+
}
|
|
1294
|
+
// A granted member request the child never reported may have reached Fluxer just before the exit, so it counts
|
|
1295
|
+
// from the exit
|
|
1296
|
+
const exited = ({ holder }) => holder?.slot === slot && holder.generation === generation;
|
|
1297
|
+
const held = this.#memberRequests.filter(exited).length;
|
|
1298
|
+
this.#memberRequests = this.#memberRequests.filter((request) => !exited(request));
|
|
1299
|
+
for (let index = 0; index < held; index++)
|
|
1300
|
+
this.#countMemberRequest({ at: performance.now() });
|
|
1301
|
+
if (this.#stopping || this.#failed) {
|
|
1302
|
+
slot.state = this.#failed ? "failed" : "closed";
|
|
1303
|
+
this.#checkStopped();
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
if (this.#resharding !== undefined) {
|
|
1307
|
+
slot.state = "closed";
|
|
1308
|
+
return this.#continueReshard();
|
|
1309
|
+
}
|
|
1310
|
+
const restart = this.#configuration.restart;
|
|
1311
|
+
if (!restart) {
|
|
1312
|
+
slot.state = "failed";
|
|
1313
|
+
this.#log("error", "supervisor.crash", `Child ${slot.configuration.id} stopped unexpectedly, and the supervisor option restart is false, so the supervisor shuts down`, slot, {
|
|
1314
|
+
fields: { exitCode: code, signal },
|
|
1315
|
+
});
|
|
1316
|
+
this.#fail(new SupervisorError(slot.configuration.id, "closed"));
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
// Only consecutive crashes count: A child that ran long enough after readiness failed on its own, not in a loop
|
|
1320
|
+
const budgetReset = slot.restarts > 0 &&
|
|
1321
|
+
slot.readyAt !== undefined &&
|
|
1322
|
+
performance.now() - slot.readyAt >= restart.healthyResetMs;
|
|
1323
|
+
if (budgetReset)
|
|
1324
|
+
slot.restarts = 0;
|
|
1325
|
+
if (slot.restarts >= restart.maxAttempts) {
|
|
1326
|
+
slot.state = "failed";
|
|
1327
|
+
this.#log("error", "supervisor.crash", `Child ${slot.configuration.id} stopped again after using all ${restart.maxAttempts} restarts (restart.maxAttempts), so the supervisor shuts down`, slot, { fields: { exitCode: code, signal, restarts: slot.restarts } });
|
|
1328
|
+
this.#fail(new SupervisorError(slot.configuration.id, "restartLimit"));
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
slot.restarts += 1;
|
|
1332
|
+
slot.state = "restarting";
|
|
1333
|
+
const delay = Math.min(restart.maxDelayMs, restart.minDelayMs * 2 ** (slot.restarts - 1));
|
|
1334
|
+
this.#log("warn", "supervisor.restart", `Restarting child ${slot.configuration.id} in ${delay} ms (restart ${slot.restarts} of ${restart.maxAttempts}${budgetReset ? ", count reset after a healthy run" : ""})`, slot, { fields: { restarts: slot.restarts, delayMs: delay, budgetReset } });
|
|
1335
|
+
slot.restartTimer = setTimeout(() => {
|
|
1336
|
+
slot.restartTimer = undefined;
|
|
1337
|
+
this.#spawn(slot);
|
|
1338
|
+
}, delay);
|
|
1339
|
+
this.#scheduleGrant();
|
|
1340
|
+
}
|
|
1341
|
+
#requestStop(slot, force = false) {
|
|
1342
|
+
const child = slot.child;
|
|
1343
|
+
if (!child)
|
|
1344
|
+
return;
|
|
1345
|
+
if (force) {
|
|
1346
|
+
if (slot.stopTimer)
|
|
1347
|
+
clearTimeout(slot.stopTimer);
|
|
1348
|
+
slot.stopTimer = undefined;
|
|
1349
|
+
slot.state = "stopping";
|
|
1350
|
+
try {
|
|
1351
|
+
// The disconnected child has already consumed its configured observation window
|
|
1352
|
+
child.kill("SIGKILL");
|
|
1353
|
+
}
|
|
1354
|
+
catch (error) {
|
|
1355
|
+
this.#childError(slot, child, slot.generation, error);
|
|
1356
|
+
}
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
if (slot.stopTimer)
|
|
1360
|
+
return;
|
|
1361
|
+
slot.state = "stopping";
|
|
1362
|
+
const generation = slot.generation;
|
|
1363
|
+
const shutdownTimeoutMs = this.#configuration.shutdownTimeoutMs;
|
|
1364
|
+
slot.stopTimer = setTimeout(() => {
|
|
1365
|
+
if (slot.child !== child || slot.generation !== generation)
|
|
1366
|
+
return;
|
|
1367
|
+
this.#log("warn", "supervisor.terminated", `Child ${slot.configuration.id} did not exit within ${shutdownTimeoutMs} ms (shutdownTimeoutMs) of the stop request, so the supervisor force-terminates it`, slot, { fields: { shutdownTimeoutMs } });
|
|
1368
|
+
try {
|
|
1369
|
+
// Only this exact ChildProcess is force-terminated. Completion still waits for its exit event
|
|
1370
|
+
child.kill("SIGKILL");
|
|
1371
|
+
}
|
|
1372
|
+
catch (error) {
|
|
1373
|
+
this.#childError(slot, child, generation, error);
|
|
1374
|
+
}
|
|
1375
|
+
}, shutdownTimeoutMs);
|
|
1376
|
+
this.#send(slot, { type: "shutdown", generation });
|
|
1377
|
+
}
|
|
1378
|
+
#fail(error) {
|
|
1379
|
+
if (this.#failed)
|
|
1380
|
+
return;
|
|
1381
|
+
this.#failed = true;
|
|
1382
|
+
this.#state = "failed";
|
|
1383
|
+
this.#failure = error;
|
|
1384
|
+
this.#beginShutdown();
|
|
1385
|
+
}
|
|
1386
|
+
#beginShutdown() {
|
|
1387
|
+
if (this.#stopping)
|
|
1388
|
+
return;
|
|
1389
|
+
this.#stopping = true;
|
|
1390
|
+
if (!this.#failed)
|
|
1391
|
+
this.#state = "stopping";
|
|
1392
|
+
if (this.#grantTimer)
|
|
1393
|
+
clearTimeout(this.#grantTimer);
|
|
1394
|
+
this.#grantTimer = undefined;
|
|
1395
|
+
this.#pending = [];
|
|
1396
|
+
if (this.#outstanding?.timer)
|
|
1397
|
+
clearTimeout(this.#outstanding.timer);
|
|
1398
|
+
this.#outstanding?.permit?.abort();
|
|
1399
|
+
// The count's own cleanup closes its transient client, and #planned then completes the shutdown
|
|
1400
|
+
if (this.#counting)
|
|
1401
|
+
Effect.runFork(Fiber.interrupt(this.#counting));
|
|
1402
|
+
for (const slot of this.#slots) {
|
|
1403
|
+
if (slot.restartTimer)
|
|
1404
|
+
clearTimeout(slot.restartTimer);
|
|
1405
|
+
slot.restartTimer = undefined;
|
|
1406
|
+
if (slot.startupTimer)
|
|
1407
|
+
clearTimeout(slot.startupTimer);
|
|
1408
|
+
slot.startupTimer = undefined;
|
|
1409
|
+
this.#clearDisconnectTimer(slot);
|
|
1410
|
+
if (slot.child)
|
|
1411
|
+
this.#requestStop(slot);
|
|
1412
|
+
else {
|
|
1413
|
+
slot.state = this.#failed ? "failed" : "closed";
|
|
1414
|
+
slot.connectionState = null;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
this.#checkStopped();
|
|
1418
|
+
}
|
|
1419
|
+
#clearDisconnectTimer(slot) {
|
|
1420
|
+
if (slot.disconnectTimer)
|
|
1421
|
+
clearTimeout(slot.disconnectTimer);
|
|
1422
|
+
slot.disconnectTimer = undefined;
|
|
1423
|
+
}
|
|
1424
|
+
#checkStopped() {
|
|
1425
|
+
if (this.#counting || this.#slots.some((slot) => slot.child !== undefined))
|
|
1426
|
+
return;
|
|
1427
|
+
this.#clearOutstanding();
|
|
1428
|
+
if (this.#failed) {
|
|
1429
|
+
Deferred.doneUnsafe(this.#startup, Effect.fail(this.#failure));
|
|
1430
|
+
Deferred.doneUnsafe(this.#terminal, Effect.fail(this.#failure));
|
|
1431
|
+
Deferred.doneUnsafe(this.#readiness, Effect.fail(this.#failure));
|
|
1432
|
+
}
|
|
1433
|
+
else {
|
|
1434
|
+
this.#state = "closed";
|
|
1435
|
+
Deferred.doneUnsafe(this.#startup, Effect.fail(new SupervisorError(null, "closed")));
|
|
1436
|
+
Deferred.doneUnsafe(this.#terminal, Effect.void);
|
|
1437
|
+
Deferred.doneUnsafe(this.#readiness, Effect.fail(new SupervisorError(null, "closed")));
|
|
1438
|
+
}
|
|
1439
|
+
this.#configuration = undefined;
|
|
1440
|
+
Deferred.doneUnsafe(this.#stopped, Effect.void);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
/** The failure of a session start that the supervisor can no longer grant, because it stopped this child or lost contact */
|
|
1444
|
+
function supervisorStopped() {
|
|
1445
|
+
return new ConnectionError("gateway", "closed", null, {
|
|
1446
|
+
details: { detail: "the supervisor stopped this child or lost contact with it" },
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
const unreachable = Object.freeze({ kind: "unreachable" });
|
|
1450
|
+
/** Child-side IPC bridge. It owns no process signals and reports no child output */
|
|
1451
|
+
export class ChildBridge {
|
|
1452
|
+
#assignment = Deferred.makeUnsafe();
|
|
1453
|
+
#stop = Deferred.makeUnsafe();
|
|
1454
|
+
#pending = new Map();
|
|
1455
|
+
#cancelled = new Set();
|
|
1456
|
+
/** Member request slots waiting for the parent's answer, by request ID */
|
|
1457
|
+
#memberAnswers = new Map();
|
|
1458
|
+
/** Host time at which the latest global pause the parent relayed ends */
|
|
1459
|
+
#globalPauseUntil = 0;
|
|
1460
|
+
#onGlobalPause;
|
|
1461
|
+
#generation;
|
|
1462
|
+
#diagnosticsIntervalMs = defaultDiagnosticsIntervalMs;
|
|
1463
|
+
#drainMs = 0;
|
|
1464
|
+
#diagnosticsTimer;
|
|
1465
|
+
#nextRequestId = 0;
|
|
1466
|
+
#stopping = false;
|
|
1467
|
+
#ended = false;
|
|
1468
|
+
#cleaned = false;
|
|
1469
|
+
#abort = new AbortController();
|
|
1470
|
+
signal = this.#abort.signal;
|
|
1471
|
+
identifyGate = {
|
|
1472
|
+
permit: (shardId, send) => this.#permit(shardId, send),
|
|
1473
|
+
};
|
|
1474
|
+
accountLimits = {
|
|
1475
|
+
shareGlobalPause: (waitMs) => {
|
|
1476
|
+
if (!this.#ended && this.#generation !== undefined && positiveTimer(waitMs))
|
|
1477
|
+
this.#send({ type: "globalPause", generation: this.#generation, waitMs });
|
|
1478
|
+
},
|
|
1479
|
+
onGlobalPause: (listener) => {
|
|
1480
|
+
this.#onGlobalPause = listener;
|
|
1481
|
+
const waitMs = Math.ceil(this.#globalPauseUntil - performance.now());
|
|
1482
|
+
if (waitMs > 0)
|
|
1483
|
+
listener(waitMs);
|
|
1484
|
+
},
|
|
1485
|
+
members: {
|
|
1486
|
+
request: () => this.#memberRequest(),
|
|
1487
|
+
sent: () => {
|
|
1488
|
+
if (!this.#ended && this.#generation !== undefined)
|
|
1489
|
+
this.#send({ type: "memberSent", generation: this.#generation });
|
|
1490
|
+
},
|
|
1491
|
+
},
|
|
1492
|
+
};
|
|
1493
|
+
onMessage = (message) => this.#message(message);
|
|
1494
|
+
onDisconnect = () => this.#disconnect();
|
|
1495
|
+
constructor() {
|
|
1496
|
+
process.on("message", this.onMessage);
|
|
1497
|
+
process.once("disconnect", this.onDisconnect);
|
|
1498
|
+
if (!this.#send({ type: "hello" }))
|
|
1499
|
+
this.#disconnect();
|
|
1500
|
+
}
|
|
1501
|
+
static open() {
|
|
1502
|
+
return Effect.suspend(() => {
|
|
1503
|
+
if (typeof process.send !== "function" || !process.connected)
|
|
1504
|
+
return Effect.fail(new SupervisorChildError("disconnected"));
|
|
1505
|
+
return Effect.succeed(new ChildBridge());
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
waitForAssignment() {
|
|
1509
|
+
return Deferred.await(this.#assignment);
|
|
1510
|
+
}
|
|
1511
|
+
waitForStop() {
|
|
1512
|
+
return Deferred.await(this.#stop);
|
|
1513
|
+
}
|
|
1514
|
+
ready() {
|
|
1515
|
+
if (!this.#ended && this.#generation !== undefined)
|
|
1516
|
+
this.#send({ type: "ready", generation: this.#generation });
|
|
1517
|
+
}
|
|
1518
|
+
state(state) {
|
|
1519
|
+
if (!this.#ended && this.#generation !== undefined)
|
|
1520
|
+
this.#send({ type: "state", generation: this.#generation, state });
|
|
1521
|
+
}
|
|
1522
|
+
/** How long a stop requested by the parent lets running work finish, within the parent's shutdownTimeoutMs */
|
|
1523
|
+
get drainMs() {
|
|
1524
|
+
return this.#drainMs;
|
|
1525
|
+
}
|
|
1526
|
+
failed(reason) {
|
|
1527
|
+
if (!this.#ended && this.#generation !== undefined)
|
|
1528
|
+
this.#send({ type: "failed", generation: this.#generation, reason });
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Send the client's diagnostics now and then at the parent's interval until this bridge closes. The timer does not
|
|
1532
|
+
* keep the process alive
|
|
1533
|
+
*/
|
|
1534
|
+
reportDiagnostics(read) {
|
|
1535
|
+
if (this.#diagnosticsTimer || this.#ended)
|
|
1536
|
+
return;
|
|
1537
|
+
const report = () => {
|
|
1538
|
+
if (!this.#ended && this.#generation !== undefined)
|
|
1539
|
+
this.#send({ type: "diagnostics", generation: this.#generation, diagnostics: read() });
|
|
1540
|
+
};
|
|
1541
|
+
report();
|
|
1542
|
+
this.#diagnosticsTimer = setInterval(report, this.#diagnosticsIntervalMs);
|
|
1543
|
+
this.#diagnosticsTimer.unref();
|
|
1544
|
+
}
|
|
1545
|
+
close() {
|
|
1546
|
+
if (!this.#ended) {
|
|
1547
|
+
this.#ended = true;
|
|
1548
|
+
this.#abort.abort();
|
|
1549
|
+
if (this.#generation !== undefined)
|
|
1550
|
+
this.#send({ type: "closed", generation: this.#generation });
|
|
1551
|
+
}
|
|
1552
|
+
Deferred.doneUnsafe(this.#stop, Effect.void);
|
|
1553
|
+
this.#cleanup(true);
|
|
1554
|
+
}
|
|
1555
|
+
#permit(shardId, send) {
|
|
1556
|
+
const bridge = this;
|
|
1557
|
+
return Effect.callback((resume) => {
|
|
1558
|
+
const generation = bridge.#generation;
|
|
1559
|
+
const requestId = bridge.#nextRequestId++;
|
|
1560
|
+
if (bridge.#ended || bridge.#stopping || generation === undefined) {
|
|
1561
|
+
resume(Effect.fail(supervisorStopped()));
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
bridge.#pending.set(requestId, { send, resume });
|
|
1565
|
+
if (!bridge.#send({ type: "identify", generation, requestId, shardId })) {
|
|
1566
|
+
bridge.#pending.delete(requestId);
|
|
1567
|
+
resume(Effect.fail(supervisorStopped()));
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
return Effect.sync(() => {
|
|
1571
|
+
if (bridge.#pending.delete(requestId)) {
|
|
1572
|
+
bridge.#cancelled.add(requestId);
|
|
1573
|
+
bridge.#send({ type: "cancel", generation, requestId });
|
|
1574
|
+
}
|
|
1575
|
+
});
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Ask the parent for a member request slot. The answer is unreachable at once without a channel, when the channel
|
|
1580
|
+
* closes, or after memberAnswerMs without an answer, so a child never waits on a parent that cannot answer.
|
|
1581
|
+
* Interruption or a missed answer withdraws the request, so a late grant frees its slot again
|
|
1582
|
+
*/
|
|
1583
|
+
#memberRequest() {
|
|
1584
|
+
const bridge = this;
|
|
1585
|
+
return Effect.callback((resume) => {
|
|
1586
|
+
const generation = bridge.#generation;
|
|
1587
|
+
if (bridge.#ended || generation === undefined) {
|
|
1588
|
+
resume(Effect.succeed(unreachable));
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
const requestId = bridge.#nextRequestId++;
|
|
1592
|
+
const withdraw = () => bridge.#send({ type: "memberWithdrawn", generation, requestId });
|
|
1593
|
+
const timer = setTimeout(() => {
|
|
1594
|
+
if (!bridge.#memberAnswers.delete(requestId))
|
|
1595
|
+
return;
|
|
1596
|
+
withdraw();
|
|
1597
|
+
resume(Effect.succeed(unreachable));
|
|
1598
|
+
}, memberAnswerMs);
|
|
1599
|
+
bridge.#memberAnswers.set(requestId, (slot) => {
|
|
1600
|
+
clearTimeout(timer);
|
|
1601
|
+
resume(Effect.succeed(slot));
|
|
1602
|
+
});
|
|
1603
|
+
if (!bridge.#send({ type: "memberRequest", generation, requestId })) {
|
|
1604
|
+
bridge.#memberAnswers.delete(requestId);
|
|
1605
|
+
clearTimeout(timer);
|
|
1606
|
+
resume(Effect.succeed(unreachable));
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
return Effect.sync(() => {
|
|
1610
|
+
if (!bridge.#memberAnswers.delete(requestId))
|
|
1611
|
+
return;
|
|
1612
|
+
clearTimeout(timer);
|
|
1613
|
+
withdraw();
|
|
1614
|
+
});
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
/** A granted slot that reports exactly once whether its request reached the socket */
|
|
1618
|
+
#grantedMember(generation, requestId) {
|
|
1619
|
+
let reported = false;
|
|
1620
|
+
const report = (type) => {
|
|
1621
|
+
if (reported)
|
|
1622
|
+
return;
|
|
1623
|
+
reported = true;
|
|
1624
|
+
if (!this.#ended)
|
|
1625
|
+
this.#send({ type, generation, requestId });
|
|
1626
|
+
};
|
|
1627
|
+
return { kind: "granted", sent: () => report("memberSent"), withdraw: () => report("memberWithdrawn") };
|
|
1628
|
+
}
|
|
1629
|
+
#message(message) {
|
|
1630
|
+
if (this.#ended)
|
|
1631
|
+
return;
|
|
1632
|
+
if (!record(message) || typeof message.type !== "string")
|
|
1633
|
+
return this.#protocol();
|
|
1634
|
+
if ((message.type === "memberGrant" || message.type === "memberDenied") &&
|
|
1635
|
+
hasExactKeys(message, message.type === "memberGrant"
|
|
1636
|
+
? ["type", "generation", "requestId"]
|
|
1637
|
+
: ["type", "generation", "requestId", "retryAfterMs"]) &&
|
|
1638
|
+
safeInteger(message.generation) &&
|
|
1639
|
+
message.generation === this.#generation &&
|
|
1640
|
+
safeInteger(message.requestId) &&
|
|
1641
|
+
(message.type === "memberGrant" || positiveTimer(message.retryAfterMs))) {
|
|
1642
|
+
const answer = this.#memberAnswers.get(message.requestId);
|
|
1643
|
+
// An answer after this child stopped waiting is ignored. The child withdrew that request then
|
|
1644
|
+
if (!answer)
|
|
1645
|
+
return;
|
|
1646
|
+
this.#memberAnswers.delete(message.requestId);
|
|
1647
|
+
answer(message.type === "memberGrant"
|
|
1648
|
+
? this.#grantedMember(message.generation, message.requestId)
|
|
1649
|
+
: { kind: "refused", retryAfterMs: message.retryAfterMs });
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
if (message.type === "globalPause" &&
|
|
1653
|
+
hasExactKeys(message, ["type", "generation", "waitMs"]) &&
|
|
1654
|
+
message.generation === this.#generation &&
|
|
1655
|
+
positiveTimer(message.waitMs)) {
|
|
1656
|
+
const until = performance.now() + message.waitMs;
|
|
1657
|
+
if (until > this.#globalPauseUntil) {
|
|
1658
|
+
this.#globalPauseUntil = until;
|
|
1659
|
+
this.#onGlobalPause?.(message.waitMs);
|
|
1660
|
+
}
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
if (message.type === "assignment" &&
|
|
1664
|
+
hasExactKeys(message, ["type", "generation", "assignment", "diagnosticsIntervalMs", "drainMs"]) &&
|
|
1665
|
+
safeInteger(message.generation) &&
|
|
1666
|
+
message.generation > 0 &&
|
|
1667
|
+
positiveTimer(message.diagnosticsIntervalMs) &&
|
|
1668
|
+
safeInteger(message.drainMs) &&
|
|
1669
|
+
message.drainMs >= 0 &&
|
|
1670
|
+
message.drainMs <= maximumTimerMs &&
|
|
1671
|
+
record(message.assignment) &&
|
|
1672
|
+
hasExactKeys(message.assignment, ["totalShards", "shardIds"]) &&
|
|
1673
|
+
safeInteger(message.assignment.totalShards) &&
|
|
1674
|
+
message.assignment.totalShards > 0) {
|
|
1675
|
+
if (this.#generation !== undefined)
|
|
1676
|
+
return this.#protocol();
|
|
1677
|
+
const shardIds = assignment(message.assignment.shardIds, message.assignment.totalShards);
|
|
1678
|
+
if (!shardIds)
|
|
1679
|
+
return this.#protocol();
|
|
1680
|
+
this.#generation = message.generation;
|
|
1681
|
+
this.#diagnosticsIntervalMs = message.diagnosticsIntervalMs;
|
|
1682
|
+
this.#drainMs = message.drainMs;
|
|
1683
|
+
Deferred.doneUnsafe(this.#assignment, Effect.succeed(Object.freeze({
|
|
1684
|
+
totalShards: message.assignment.totalShards,
|
|
1685
|
+
shardIds: Object.freeze([...shardIds]),
|
|
1686
|
+
})));
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
if (message.type === "grant" &&
|
|
1690
|
+
hasExactKeys(message, ["type", "generation", "requestId"]) &&
|
|
1691
|
+
message.generation === this.#generation &&
|
|
1692
|
+
safeInteger(message.requestId)) {
|
|
1693
|
+
const pending = this.#pending.get(message.requestId);
|
|
1694
|
+
if (!pending) {
|
|
1695
|
+
if (this.#cancelled.delete(message.requestId))
|
|
1696
|
+
return;
|
|
1697
|
+
return this.#protocol();
|
|
1698
|
+
}
|
|
1699
|
+
this.#pending.delete(message.requestId);
|
|
1700
|
+
const generation = this.#generation;
|
|
1701
|
+
pending.resume(Effect.uninterruptible(Effect.try({
|
|
1702
|
+
try: () => {
|
|
1703
|
+
if (this.#stopping || this.#ended)
|
|
1704
|
+
throw new Error("closed");
|
|
1705
|
+
pending.send();
|
|
1706
|
+
if (generation === undefined ||
|
|
1707
|
+
!this.#send({ type: "sent", generation, requestId: message.requestId }))
|
|
1708
|
+
throw new Error("closed");
|
|
1709
|
+
},
|
|
1710
|
+
catch: () => supervisorStopped(),
|
|
1711
|
+
})));
|
|
1712
|
+
return;
|
|
1713
|
+
}
|
|
1714
|
+
if (message.type === "cancelled" &&
|
|
1715
|
+
hasExactKeys(message, ["type", "generation", "requestId"]) &&
|
|
1716
|
+
message.generation === this.#generation &&
|
|
1717
|
+
safeInteger(message.requestId)) {
|
|
1718
|
+
this.#cancelled.delete(message.requestId);
|
|
1719
|
+
return;
|
|
1720
|
+
}
|
|
1721
|
+
if (message.type === "denied" &&
|
|
1722
|
+
hasExactKeys(message, ["type", "generation", "requestId"]) &&
|
|
1723
|
+
message.generation === this.#generation &&
|
|
1724
|
+
safeInteger(message.requestId)) {
|
|
1725
|
+
const pending = this.#pending.get(message.requestId);
|
|
1726
|
+
if (!pending) {
|
|
1727
|
+
if (this.#cancelled.delete(message.requestId))
|
|
1728
|
+
return;
|
|
1729
|
+
return this.#protocol();
|
|
1730
|
+
}
|
|
1731
|
+
this.#pending.delete(message.requestId);
|
|
1732
|
+
// The parent logged the coordinator's failure. The client retries this like a network failure
|
|
1733
|
+
pending.resume(Effect.fail(new ConnectionError("gateway", "network", null, {
|
|
1734
|
+
details: {
|
|
1735
|
+
detail: "the supervisor's identify coordinator did not grant permission to start a new session",
|
|
1736
|
+
},
|
|
1737
|
+
hint: "Check the supervisor's records with code supervisor.identifyPermitFailed and the permit function of its identify.coordinator",
|
|
1738
|
+
})));
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
if (message.type === "shutdown" &&
|
|
1742
|
+
hasExactKeys(message, ["type", "generation"]) &&
|
|
1743
|
+
message.generation === this.#generation) {
|
|
1744
|
+
this.#stopping = true;
|
|
1745
|
+
this.#abort.abort();
|
|
1746
|
+
Deferred.doneUnsafe(this.#stop, Effect.void);
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
this.#protocol();
|
|
1750
|
+
}
|
|
1751
|
+
#disconnect() {
|
|
1752
|
+
if (this.#ended)
|
|
1753
|
+
return this.#cleanup(false);
|
|
1754
|
+
this.#ended = true;
|
|
1755
|
+
this.#stopping = true;
|
|
1756
|
+
this.#abort.abort();
|
|
1757
|
+
Deferred.doneUnsafe(this.#assignment, Effect.fail(new SupervisorChildError("disconnected")));
|
|
1758
|
+
Deferred.doneUnsafe(this.#stop, Effect.fail(new SupervisorChildError("disconnected")));
|
|
1759
|
+
this.#cleanup(false);
|
|
1760
|
+
}
|
|
1761
|
+
#protocol() {
|
|
1762
|
+
if (this.#ended)
|
|
1763
|
+
return this.#cleanup(false);
|
|
1764
|
+
this.#ended = true;
|
|
1765
|
+
this.#stopping = true;
|
|
1766
|
+
Deferred.doneUnsafe(this.#assignment, Effect.fail(new SupervisorChildError("protocol")));
|
|
1767
|
+
Deferred.doneUnsafe(this.#stop, Effect.fail(new SupervisorChildError("protocol")));
|
|
1768
|
+
this.#cleanup(false);
|
|
1769
|
+
}
|
|
1770
|
+
#cleanup(notifyCancellation) {
|
|
1771
|
+
if (this.#cleaned)
|
|
1772
|
+
return;
|
|
1773
|
+
this.#cleaned = true;
|
|
1774
|
+
if (this.#diagnosticsTimer)
|
|
1775
|
+
clearInterval(this.#diagnosticsTimer);
|
|
1776
|
+
this.#diagnosticsTimer = undefined;
|
|
1777
|
+
process.off("message", this.onMessage);
|
|
1778
|
+
process.off("disconnect", this.onDisconnect);
|
|
1779
|
+
for (const [requestId, pending] of this.#pending) {
|
|
1780
|
+
if (notifyCancellation && this.#generation !== undefined)
|
|
1781
|
+
this.#send({ type: "cancel", generation: this.#generation, requestId });
|
|
1782
|
+
pending.resume(Effect.fail(supervisorStopped()));
|
|
1783
|
+
}
|
|
1784
|
+
this.#pending.clear();
|
|
1785
|
+
this.#cancelled.clear();
|
|
1786
|
+
const answers = [...this.#memberAnswers.values()];
|
|
1787
|
+
this.#memberAnswers.clear();
|
|
1788
|
+
for (const answer of answers)
|
|
1789
|
+
answer(unreachable);
|
|
1790
|
+
this.#onGlobalPause = undefined;
|
|
1791
|
+
}
|
|
1792
|
+
#send(message) {
|
|
1793
|
+
try {
|
|
1794
|
+
if (!process.connected || typeof process.send !== "function")
|
|
1795
|
+
return false;
|
|
1796
|
+
process.send(message, undefined, undefined, (error) => {
|
|
1797
|
+
if (error)
|
|
1798
|
+
this.#disconnect();
|
|
1799
|
+
});
|
|
1800
|
+
return true;
|
|
1801
|
+
}
|
|
1802
|
+
catch {
|
|
1803
|
+
// allow-silent: A false return makes the child treat the parent as disconnected and stop
|
|
1804
|
+
return false;
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* The failure reason a child reports for its stopped client: Sharding when Fluxer closed a shard with 4011 (sharding
|
|
1810
|
+
* required), so a supervisor with totalShards "auto" can move to a larger plan, otherwise client
|
|
1811
|
+
*/
|
|
1812
|
+
export function childFailureReason(error) {
|
|
1813
|
+
// Tags rather than classes, so a failure from another copy of the SDK module graph is still recognized
|
|
1814
|
+
const failure = record(error) && error._tag === "ShardConnectionError" ? error.failure : error;
|
|
1815
|
+
return record(failure) &&
|
|
1816
|
+
failure._tag === "ConnectionError" &&
|
|
1817
|
+
failure.phase === "gateway" &&
|
|
1818
|
+
failure.status === CloseCode.shardingRequired
|
|
1819
|
+
? "sharding"
|
|
1820
|
+
: "client";
|
|
1821
|
+
}
|
|
1822
|
+
export function createSupervisor(options, native = false) {
|
|
1823
|
+
return validateSupervisorConfiguration(options, native).pipe(Effect.tap((configuration) => Effect.withFiber((fiber) => {
|
|
1824
|
+
if (native)
|
|
1825
|
+
configuration.logger.context = fiber.context;
|
|
1826
|
+
return Effect.void;
|
|
1827
|
+
})), Effect.map((configuration) => new SupervisorOwner(configuration, native)));
|
|
1828
|
+
}
|
|
1829
|
+
//# sourceMappingURL=supervisor.js.map
|