Skip to content

feat: SwiftDisc v2.0.0#11

Merged
M1tsumi merged 14 commits intomainfrom
release/v2.0.0
Mar 6, 2026
Merged

feat: SwiftDisc v2.0.0#11
M1tsumi merged 14 commits intomainfrom
release/v2.0.0

Conversation

@M1tsumi
Copy link
Owner

@M1tsumi M1tsumi commented Mar 2, 2026

  • Upgrade to swift-tools-version:6.2, .swiftLanguageMode(.v6)
  • Complete Swift 6 strict-concurrency migration (actors, @sendable, Sendable)
  • throws(DiscordError) typed throws throughout the REST layer
  • Fix HTTPClient double-wrap catch bug (DiscordError re-wrapped as .network)
  • Fix soundboard gateway event names: SOUND_BOARD_SOUND_* -> SOUNDBOARD_SOUND_*
  • Expand Guild model from 4-field stub to full ~50-field Discord API model
  • Add 32 new gateway event callbacks on DiscordClient
  • Full EventDispatcher rewire + GUILD_CREATE cache seeding
  • DiscordError: Sendable + .unavailable case
  • RateLimiter.waitTurn: throws(DiscordError)

DX improvements:

  • message.reply() - reply with auto message_reference, mention control
  • client.sendDM() - open DM + send in one call
  • SlashCommandRouter.Context: typed resolvers ctx.user/channel/role/attachment/member
  • EmbedBuilder.timestamp(Date) - pass Date() directly
  • CooldownManager promoted to public actor with remaining() + clearCooldown() + purgeExpired()
  • Filtered event stream helpers: messageEvents(), reactionAddEvents(), interactionEvents(), memberAddEvents/Remove, presenceUpdateEvents()
  • Cache background TTL eviction task (auto-starts when TTL configured, 60s interval)

SwiftDisc Bot and others added 14 commits March 2, 2026 16:31
- Upgrade to swift-tools-version:6.2, .swiftLanguageMode(.v6)
- Complete Swift 6 strict-concurrency migration (actors, @sendable, Sendable)
- throws(DiscordError) typed throws throughout the REST layer
- Fix HTTPClient double-wrap catch bug (DiscordError re-wrapped as .network)
- Fix soundboard gateway event names: SOUND_BOARD_SOUND_* -> SOUNDBOARD_SOUND_*
- Expand Guild model from 4-field stub to full ~50-field Discord API model
- Add 32 new gateway event callbacks on DiscordClient
- Full EventDispatcher rewire + GUILD_CREATE cache seeding
- DiscordError: Sendable + .unavailable case
- RateLimiter.waitTurn: throws(DiscordError)

DX improvements:
- message.reply() - reply with auto message_reference, mention control
- client.sendDM() - open DM + send in one call
- SlashCommandRouter.Context: typed resolvers ctx.user/channel/role/attachment/member
- EmbedBuilder.timestamp(Date) - pass Date() directly
- CooldownManager promoted to public actor with remaining() + clearCooldown() + purgeExpired()
- Filtered event stream helpers: messageEvents(), reactionAddEvents(), interactionEvents(), memberAddEvents/Remove, presenceUpdateEvents()
- Cache background TTL eviction task (auto-starts when TTL configured, 60s interval)
…iRef, syncCommands, archiveThread, cache roles/emojis, permission helpers

- MessagePayload fluent builder: .content/.embed/.component/.reply/.ephemeral/.silent/.file
  + DiscordClient extensions: send(to:_:), edit(channelId:messageId:_:), respond(to:with:)
- WebhookClient struct: no bot token required, parses webhook URL, execute/editMessage/deleteMessage
- CommandRouter.Middleware typealias + use(_:) registration + chain execution
- SlashCommandRouter.Middleware typealias + use(_:) + chain execution
- CommandRouter.Context: hasPermission(_:), isAdmin, memberHasRole(_:)
- SlashCommandRouter.Context: hasPermission(_:), isAdmin, memberHasRole(_:)
- Cache: upsert(role:guildId:), getRoles/getRole/removeRole, upsert(emojis:guildId:), getEmojis/getEmoji
- GuildMember.permissions: String? — Discord includes this in interaction + some gateway payloads
- DiscordClient.EmojiRef enum: .unicode(String) / .custom(name:id:) with .encoded
- Typed reaction overloads: addReaction/removeOwnReaction/removeUserReaction/getReactions/removeAllReactionsForEmoji(emoji: EmojiRef)
- DiscordClient.archiveThread(channelId:locked:) — PATCH /channels/{id} archived+locked
- DiscordClient.syncCommands(_:guildId:) — fetch, diff name sets, bulkOverwrite only on change
- CHANGELOG.md: document all new features under [2.0.0]
…2 strict concurrency

Windows Swift 6.2 strictly requires all associated values of a Sendable-conforming
enum to themselves be Sendable. DiscordEvent: Sendable had many associated value
types missing this conformance.

- Snowflake<T>: add extension Snowflake: @unchecked Sendable {} — stores only
  String (Sendable), phantom T is never held at runtime, so unconditional is correct
- Globally add Sendable to all 138 structs/enums with ': Codable, Hashable {'
  across GatewayModels.swift and all Models/*.swift (Message, Guild, Channel,
  Interaction, User, Role, Emoji, GuildMember, AuditLog, AutoModeration,
  Monetization, ScheduledEvent, Thread, MessageComponents, Sticker, Embed,
  Attachment, Webhook, Invite, PartialGuild, etc. and all their nested types)
- PermissionBitset: OptionSet, Codable, Hashable -> add Sendable
- Package.swift: restore swift-tools-version:6.2 (CI now uses Swift 6.2 toolchain)
macOS CI failures:
- GatewayIntents: add Sendable to OptionSet conformance
- FileAttachment: add Sendable
- CooldownManager: fix empty dict literal [] -> [:] for [String:Date]
- DiscordClient: relax http to internal so MessagePayload extension can use it
- ShardingGatewayManager: nonisolated(unsafe) on logDateFormatter (ISO8601DateFormatter
  is not Sendable); add Sendable to ShardHandle struct
- EventDispatcher: fix invalid 'for x in arr, let y = ...' syntax (not valid Swift)
  -> use 'for x in arr { if let y = ... { } }' on guild members and members chunk loops
- ApplicationRoleConnection: add Sendable to RoleConnectionMetadataType enum
- MessageComponents: add Sendable to TextInput.Style nested enum
- ScheduledEvent: add Sendable to GuildScheduledEvent.EntityType and .Status nested enums

Repo hygiene:
- Add errors/ to .gitignore so local CI log dumps are never committed
- Untrack previously committed errors/macos.txt and errors/windows.txt
macOS failures:
- DiscordConfiguration: add Sendable (fixes 'sending configuration' data race)
- ShardedEvent: add Sendable (fixes 'sending ev' data race in ShardingGatewayManager)
- DiscordClient: mark eventStream/eventContinuation nonisolated(unsafe) to allow
  setting in nonisolated actor init (Swift 6.2 change)
- DiscordClient: move voiceClient setOnFrame setup from init to loginAndConnect/
  loginAndConnectSharded where self is fully isolated (fixes 'sending closure' error)
- DiscordClient: add Sendable to all local Body/Payload/DataObj/Ack structs
  (fixes 'sending non-Sendable Body risks data races' across ~76 REST methods)
- DiscordClient: add Sendable to public embedded types (AutocompleteChoice,
  ApplicationCommand, ApplicationCommandOption, ApplicationCommandCreate,
  PrunePayload, PruneResponse, RoleCreate, RoleUpdate, etc.)
- Cache: mark evictionTask nonisolated(unsafe) to allow init access

Windows failures:
- WebhookClient: import FoundationNetworking on non-Apple platforms
  (URLSession/URLRequest are in FoundationNetworking on Linux/Windows)
- Files: add Sendable to PartialAttachment
- AdvancedMessagePayloads: add Sendable to V2MessagePayload and PollPayload
- RoleMemberCount: add Sendable
- GatewayModels: add Sendable to GatewayHello, GatewayOpcode, PresenceUpdatePayload,
  GatewayPayload, IdentifyPayload, IdentifyConnectionProperties, ResumePayload
…ion from source files)

The previous commit (3e8de14) accidentally embedded a PowerShell regex script
block into DiscordClient.swift and GatewayModels.swift instead of executing it,
causing syntax errors ('expressions not allowed at top level', 'extraneous }').

This commit:
- Restores both files to the pre-corruption state (ff800bc)
- Properly applies all intended Sendable conformances:

GatewayModels.swift:
  - GatewayHello: add Sendable
  - GatewayOpcode: add Sendable
  - GatewayPayload: add conditional extension 'Sendable where D: Sendable'
  - IdentifyPayload: add Sendable
  - IdentifyConnectionProperties: add Sendable
  - ResumePayload: add Sendable
  - PresenceUpdatePayload: add Sendable
  - PresenceUpdatePayload.Data: add Sendable

DiscordClient.swift:
  - eventStream/eventContinuation: mark nonisolated(unsafe) (Swift 6.2 actor init)
  - voiceClient.setOnFrame: move from init to loginAndConnect/loginAndConnectSharded
    (fixes 'sending closure captures self' error in nonisolated actor init)
  - ~76 local Body/Payload/DataObj/Ack/Entry/Empty structs: add Sendable
    (fixes 'sending non-Sendable Body risks data races' errors)
  - PrunePayload, PruneResponse, RoleCreate, RoleUpdate: add Sendable
  - AutocompleteChoice, ApplicationCommand, ApplicationCommandOption,
    ApplicationCommandCreate: add Sendable
…ypes

ApplicationCommandOption was marked Sendable but its two nested types were not:
- ApplicationCommandOptionType (enum): add Sendable
- Choice (struct): add Sendable

This resolves:
  error: stored property 'type' has non-Sendable type 'ApplicationCommandOptionType'
  error: stored property 'choices' contains non-Sendable type 'Choice'

Both macOS and Windows CI failures.
…dClient

- loginAndConnect / loginAndConnectSharded: remove explicit [self] capture list
  from Task { } blocks inside setOnFrame callbacks. The explicit [self] annotates
  self as a 'sending' capture which Swift 6.2 rejects when the closure is passed
  as a 'sending' parameter; dropping the capture list uses implicit capture and
  avoids the diagnostic.

- rawPOST / rawPATCH / rawPUT: tighten generic constraint from 'B: Encodable'
  to 'B: Encodable & Sendable', since the body value is passed to an async
  method across an actor boundary and must be Sendable.

Fixes both macOS and Windows CI:
  error: passing closure as a 'sending' parameter risks causing data races (x2)
  error: sending 'body' risks causing data races (x3)
… platforms

- VoiceFrame: add explicit Sendable conformance so the struct can be safely
  sent across task/actor boundaries without triggering Swift 6.2's strict
  sending checks
- DiscordClient: add explicit [frame] capture list to both Task closures in
  loginAndConnect and loginAndConnectSharded; Swift 6.2 requires that values
  passed to a 'sending' closure (Task.init) are not shared with the current
  task context -- an explicit copy capture satisfies this requirement

Fixes:
  DiscordClient.swift:559:17 - passing closure as 'sending' parameter risks
  data races (loginAndConnect setOnFrame Task body)
  DiscordClient.swift:577:17 - same issue in loginAndConnectSharded
- Mark DiscordClient.token as nonisolated to allow access from
  nonisolated autoclosures (fixes XCTAssertEqual in SwiftDiscTests)
- Remove unused captured var 'called' in ViewManagerTests to fix
  SendableClosureCaptures error in @sendable ViewHandler closure
README.md
- Remove duplicate Command Framework example section
- Update Roadmap to reflect features shipped in v2.0.0 (MessagePayload,
  Middleware, WebhookClient, syncCommands); remaining items are genuinely upcoming
- Remove reference to CONTRIBUTING.md (file does not exist)

InstallGuide.txt
- Update minimum Swift requirement from 5.9 to 6.2
- Update recommended Xcode from 15+ to 16.4+
- Update package version references from 0.10.2 to 2.0.0
- Remove 'Windows WebSocket adapter is planned' note (shipped in v2.0.0)
- Remove 'per-route buckets (planned)' note (fully implemented)

SwiftDiscDocs.txt
- Rewrite Role Connections section: replace informal/marketing prose
  with concise factual description
- Rewrite Typed Permissions section: replace informal/marketing prose
  with precise technical description
- Replace stale Roadmap Highlights with an accurate Implemented
  Capabilities Summary reflecting v2.0.0 state

EmbedBuilder.swift
- Add full /// docstrings to all public methods (init, title, description,
  url, color, footer, author, addField, thumbnail, image, timestamp x2, build)
- Add top-level type docstring with usage example
- Expand cramped one-liner methods for readability

Utilities.swift
- Upgrade BotUtils from // inline comments to /// documentation comments
- Add parameter and return documentation to all four public methods
@M1tsumi M1tsumi merged commit f61bf28 into main Mar 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant