Skip to content

feat(discord) - Discord Provider - #129

Open
Andy (invisicat) wants to merge 33 commits into
mainfrom
andy/discord-provider
Open

feat(discord) - Discord Provider#129
Andy (invisicat) wants to merge 33 commits into
mainfrom
andy/discord-provider

Conversation

@invisicat

@invisicat Andy (invisicat) commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Adds a full Discord bot provider to spectrum-ts. Inbound events arrive over Fusor; outbound sends call the Discord REST API (v10) directly via the generated @photon-ai/discord-ts client.

import { Spectrum } from "@photon-ai/spectrum-ts";
import { discord } from "@photon-ai/spectrum-ts/providers/discord";

const app = Spectrum({
  providers: [
    discord.config({
      botToken: process.env.DISCORD_BOT_TOKEN!,
      applicationId: process.env.DISCORD_APPLICATION_ID!,
    }),
  ],
});

Design

  • Fusor mode. lifecycle.createClient returns a fusor(...) client (platform + verify). verify just parses the relayed Gateway frame and there are no webhooks to self-register.
  • REST client built inline, never cached. discordClient(config) makes no network call, so send and the inbound poll-vote path construct one on demand from config.

Inbound (verifymessages)

Maps Gateway dispatches to ProviderMessageRecords:

Dispatch Mapped to
MESSAGE_CREATE (text/attachments) text / attachment / voice; text + multiple attachments → group
MESSAGE_CREATE (poll) poll
MESSAGE_UPDATE edit
MESSAGE_DELETE unsend
MESSAGE_REACTION_ADD / _REMOVE reaction / unsend
MESSAGE_POLL_VOTE_ADD / _REMOVE poll_option (selected true/false)
INTERACTION_CREATE (MESSAGE_COMPONENT) custom (raw.discord.type === "interaction")
  • Self-echo drop — events whose actor id equals applicationId are dropped so the bot never re-ingests its own activity; authorless MESSAGE_UPDATE (Discord's own link-embed edits) are ignored.
  • Synthetic, stable event ids for edits/deletes/reactions/votes so a removal resolves back to what it retracts.
  • Poll-vote resolution — vote dispatches carry no poll shape, so the handler reconstructs options from the source message and caches them in the platform store (first vote fetches once; siblings skip the round trip).
  • Lazy media — attachment bytes download from Discord's pre-signed CDN URLs only when a consumer reads the content.
  • Component interactions are acked first (silent DEFERRED_UPDATE_MESSAGE within the 3s window), then surfaced as custom carrying custom_id / values / component_type / message_id / interaction_id / token.

Outbound (send)

text/markdown, richlink, attachment/voice/contact (vCard), poll (native), reply, reaction, edit, typing, read (no-op), group, and custom (raw body passthrough). Every message resolves allowed_mentions via resolveAllowedMentions (configurable through config.allowedMentions, replied_user off by default).

Instance actions: startThread/createThread (threaded through the fusor definePlatform overload) and pin/unpin.

Discord-scoped content

Helpers exported from @photon-ai/spectrum-ts/providers/discord that stay out of the universal Content union:

  • embed(...) — up to 10 RichEmbeds + optional leading text in one message; validated against Discord's embed limits up front. Supports attachment:// file references.
  • components(...) — up to 5 action rows of buttons / select menus + optional text; button clicks and select submits return as inbound custom interactions.

Docs & tests

  • docs/discord.md — full provider documentation.
  • New tests: inbound message mapping, outbound message/embed/components/pin/thread, and allowed-mentions resolution.

Notes

  • New dep: published @photon-ai/discord-ts ^10.0.0.
  • One core touch: platform/define.ts gains a fusor definePlatform overload to thread instance actions — scoped to enable provider thread/pin actions.
  • Provider registered in providers/index.ts and the tsup entry list.

Changes: 25 commits, +4064 across 29 files.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

New Features

  • Discord provider support — End-to-end Gateway inbound mapping and REST outbound sending, including poll reconstruction/votes, reaction handling, and component interaction routing.
  • Authoring upgrades — New core helpers/types for attachments, edits, replies, and unsend, plus shared store utility.
  • Interactive components & embeds — Validated button/select builders and rich embed authoring with Discord limits and attachment:// resolution.
  • Discord actions & sending — Thread creation plus pin/unpin, improved allowed-mentions resolution, and safer message id handling.

Documentation

  • Added Discord package docs and updated the main Platforms list.

Tests

  • Added Bun test coverage for Discord inbound/outbound behaviors (including allowed mentions and embeds/components).

Compatibility / Chores

  • Updated Spectrum provider re-exports and added the Discord provider build entry.

Move the client-agnostic helpers (toFormData multipart serializer and
downloadAttachment CDN fetch) out of client.ts so the file is just the
photon-client API surface. Update inbound/media.ts to import
downloadAttachment from the new ./util module.
Handle MESSAGE_DELETE and MESSAGE_REACTION_REMOVE dispatches, mapping
each to an unsend that retracts the original message or reaction. Reuse
the reaction add handler's synthesized event id so a removal resolves to
the same reaction it retracts.

Resolve flattened group-item ids (`<snowflake>:<index>`) back to the
underlying Discord snowflake in parseMessageId, so a reply/edit/reaction
targeting any group part hits the real message.

Add inbound and outbound tests covering the discord adapter.
Map `poll` content to a Discord PollCreateRequest (question + ordered
answers), letting Discord's defaults apply (24h duration, single-select).
Outbound `poll_option` stays unsupported since bots cannot cast votes.
A poll arriving on MESSAGE_CREATE surfaces as `poll` content. Poll votes
(MESSAGE_POLL_VOTE_ADD/REMOVE) map to `poll_option` (selected true/false);
a removal preserves which option was unvoted rather than collapsing to an
unsend. Votes carry only an answer_id, so the poll is reconstructed from a
store cache, falling back to a one-off message fetch (getChannelMessage) on
a miss and caching the result.
…orm overload

The fusor definePlatform overload never threaded the instance `_Actions`
generic into PlatformDef (only the regular overload did), so fusor-based
providers could not declare data-returning instance actions. The runtime
(buildInstanceActions) already supported them — this was a types-only gap.
Add the `_Actions` generic to the fusor overload's def param and return type.
Wrap @photon-ai/discord-ts createThreadFromMessage and createThread as
startThreadFromMessage (POST /channels/{id}/messages/{id}/threads) and
startChannelThread (POST /channels/{id}/threads), mirroring the existing
client helpers. Both return the created thread, whose id is a snowflake
addressable as a space.
…ctions

Sending and receiving in an existing thread already worked (a thread id is
a channel snowflake, so it is a valid space.id). This adds the missing
ability to start one: instance actions startThread (from an existing
message) and createThread (a standalone text thread) open a thread and
return its id, which the caller passes to space.get(id) to post into it.
Discord's client here is fusor (inbound-only), so the REST client is built
from config, matching send.
@invisicat Andy (invisicat) self-assigned this Jun 16, 2026
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8e921bd7-39e3-46e4-8f4a-927ebdae9f97

📥 Commits

Reviewing files that changed from the base of the PR and between 08abd26 and 1d58e0d.

📒 Files selected for processing (4)
  • packages/discord/src/client.ts
  • packages/discord/src/inbound/messages.ts
  • packages/discord/src/outbound/send.ts
  • packages/discord/src/verify.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/discord/src/verify.ts
  • packages/discord/src/client.ts
  • packages/discord/src/inbound/messages.ts
  • packages/discord/src/outbound/send.ts

📝 Walkthrough

Walkthrough

Introduces a new @spectrum-ts/discord package implementing a complete Discord provider for Spectrum. It includes Fusor-mode inbound Gateway dispatch parsing, outbound REST sending, Discord-scoped embed and components content types, instance actions for threads and pins, Zod config validation, and a typed client wrapper. The provider is wired into packages/spectrum-ts as a compat shim.

Changes

Discord Provider Implementation

Layer / File(s) Summary
Types, config schemas, Fusor generic fix, and package wiring
packages/discord/src/types.ts, packages/discord/src/config.ts, packages/core/src/platform/define.ts, packages/core/src/authoring.ts, packages/discord/package.json, packages/discord/tsconfig.json, packages/discord/tsdown.config.ts, packages/discord/turbo.json, packages/spectrum-ts/package.json, packages/spectrum-ts/src/providers/discord/index.ts, packages/spectrum-ts/src/providers/index.ts, packages/spectrum-ts/tsdown.config.ts, packages/spectrum-ts/test/providers-shims.test.ts
Defines all inbound Gateway dispatch interfaces, outbound REST DTOs, and event constants; validates botToken, applicationId, and allowedMentions with mutual-exclusivity enforcement via Zod; adds _Actions generic parameter to both definePlatform overloads; expands authoring.ts re-exports (asEdit, asReply, asUnsend, createStore, attachmentSchema, BaseContent); registers the new package and wires it into the spectrum-ts shim, providers barrel, and build config.
Discord client wrapper and HTTP utilities
packages/discord/src/client.ts, packages/discord/src/util.ts
Wraps @photon-ai/discord-ts into token-bound typed helpers for message create (JSON and multipart), edit, fetch, reaction, typing, thread start/create, pin/unpin, interaction ack, and DM channel creation; adds toFormData for multipart construction and downloadAttachment for lazy CDN fetches with timeout.
Inbound: verify, media, poll reconstruction, and message dispatch handler
packages/discord/src/verify.ts, packages/discord/src/inbound/media.ts, packages/discord/src/inbound/poll.ts, packages/discord/src/inbound/messages.ts, packages/discord/test/inbound/messages.test.ts
Implements the Fusor verify hook that decodes raw Gateway dispatch frames; maps Discord attachments to lazy Spectrum Content; reconstructs Discord polls into Spectrum poll shapes with answer-id indexing; routes all supported dispatch types (MESSAGE_CREATE/UPDATE/DELETE, reaction add/remove, poll vote add/remove, INTERACTION_CREATE) into ProviderMessageRecords with self-echo filtering, synthetic id strategies, poll store caching, and immediate interaction ack.
Discord-scoped content: embed and components builders
packages/discord/src/content/embed.ts, packages/discord/src/content/components.ts, packages/discord/test/outbound/embed.test.ts, packages/discord/test/outbound/components.test.ts
Implements embed(...) with Zod schema validation (per-embed character limits, total cap, color range, attachment:// ref checking, async file resolution) and a ContentBuilder factory; implements components(...) with action-row Zod refinements, per-component validators, ergonomic constructors (button, linkButton, select, row), and a ContentBuilder factory with eager validation.
Outbound: message spec builders, send dispatcher, and allowed_mentions
packages/discord/src/outbound/message.ts, packages/discord/src/outbound/send.ts, packages/discord/test/outbound/message.test.ts, packages/discord/test/outbound/allowed-mentions.test.ts, packages/discord/test/outbound/app.test.ts
Adds parseMessageId (snowflake/group-item unwrapping), converters for poll/embed/components/custom to DiscordSendSpec, and buildSend routing all Spectrum content variants to Discord REST payloads including recursive reply with message_reference; implements resolveAllowedMentions precedence logic and the send dispatcher routing by content.type with UnsupportedError for unhandled types.
Outbound instance actions: space, thread, and pin
packages/discord/src/space.ts, packages/discord/src/outbound/thread.ts, packages/discord/src/outbound/pin.ts, packages/discord/test/outbound/thread.test.ts, packages/discord/test/outbound/pin.test.ts
Defines DiscordSpace and createSpace (single-recipient DM only, rejects multi-recipient) plus resolveUser; implements startThread and createThread with public/private type selection; implements pin and unpin delegating to client helpers via parseMessageId.
Provider entrypoint: wiring and public re-exports
packages/discord/src/index.ts
Wires configSchema, Fusor client creation, verify, handleMessages, resolveUser, createSpace, send, and instance actions (startThread, createThread, pin, unpin) into the discord platform via definePlatform; re-exports DiscordConfig, ActionRow, ButtonStyle, Components, Embed, and content helper functions.
Discord provider documentation
docs/discord.md, packages/discord/README.md, README.md
Comprehensive provider docs covering Fusor-mode inbound dispatch parsing, outbound REST send behavior per content type, Discord-scoped embed/components content, allowed_mentions precedence, instance actions, space creation rules, config fields, module file map, and test suite layout; package README with install/usage example; Platforms table entry.

Sequence Diagram(s)

sequenceDiagram
  participant Bot as Bot HTTP Server
  participant verify as verify.ts
  participant handleMessages as handleMessages
  participant store as Platform Store
  participant client as client.ts
  participant Discord as Discord REST API

  Bot->>verify: rawBody (Gateway relay)
  verify-->>Bot: DiscordPayload {t, d}
  Bot->>handleMessages: {payload, config, store}

  alt MESSAGE_CREATE with poll
    handleMessages->>store: get(pollCacheKey)
    store-->>handleMessages: undefined (cache miss)
    handleMessages->>handleMessages: reconstructPoll(d.poll)
    handleMessages->>store: set(pollCacheKey, reconstructed)
  end

  alt INTERACTION_CREATE (component click)
    handleMessages->>client: acknowledgeComponentInteraction(id, token)
    client->>Discord: POST /interactions/{id}/{token}/callback
    Discord-->>client: 200
    client-->>handleMessages: void
  end

  alt MESSAGE_POLL_VOTE_ADD cache miss
    handleMessages->>store: get(pollCacheKey)
    store-->>handleMessages: undefined
    handleMessages->>client: getChannelMessage(channelId, messageId)
    client->>Discord: GET /channels/{id}/messages/{id}
    Discord-->>client: MessageResponse
    client-->>handleMessages: message
    handleMessages->>handleMessages: reconstructPoll(message.poll)
    handleMessages->>store: set(pollCacheKey, reconstructed)
  end

  handleMessages-->>Bot: ProviderMessageRecord | undefined
Loading
sequenceDiagram
  participant App as Application
  participant send as send.ts
  participant buildSend as buildSend (message.ts)
  participant client as client.ts
  participant Discord as Discord REST API

  App->>send: {space, content, config}

  alt content.type = reaction
    send->>client: addReaction(channelId, targetId, emoji)
    client->>Discord: PUT /channels/{id}/messages/{id}/reactions/{emoji}/@me
    Discord-->>client: 204
    send-->>App: synthetic ProviderMessageRecord
  end

  alt content.type = edit
    send->>client: editChannelMessage(channelId, messageId, body)
    client->>Discord: PATCH /channels/{id}/messages/{id}
    Discord-->>client: MessageResponse
    send-->>App: undefined
  end

  alt content.type = text/embed/components/etc.
    send->>buildSend: content
    buildSend-->>send: DiscordSendSpec
    send->>send: resolveAllowedMentions(config, existing)
    send->>client: createChannelMessage(client, channelId, spec)
    client->>Discord: POST /channels/{id}/messages
    Discord-->>client: MessageResponse
    client-->>send: MessageResponse
    send-->>App: ProviderMessageRecord
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • photon-hq/spectrum-ts#140: The main PR's Discord outbound buildSend/message payload mapping includes handling for Spectrum content.type === "app", which directly corresponds to the retrieved PR introducing the universal app content builder and app layout model in @spectrum-ts/core.

Suggested reviewers

  • underthestars-zhy

Poem

🐇 Hop hop, a new platform appears,
Discord channels ring out, no more fears!
Polls and buttons, reactions galore,
Embeds and threads — who could want more?
The rabbit wired it all up with glee,
From Gateway dispatch to REST, wild and free! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(discord) - Discord Provider' accurately describes the main change: adding a new Discord provider to spectrum-ts. It is concise, specific, and clearly identifies the primary addition.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch andy/discord-provider

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Add embed(...) as Discord-scoped content (__platform: "Discord", not part
of the universal Content union): one message carrying up to 10 RichEmbeds
plus optional leading text and attachment:// files. Validated up front
against Discord's embed limits. buildSend narrows it via isEmbed so it
also works as the inner content of a reply or an item of a group.
…eplied_user off

Add an optional allowedMentions to the Discord config (Discord's
allowed_mentions: parse/users/roles/replied_user, validated up front incl.
the parse-vs-id-list mutual exclusivity) and apply it to every outbound
message in send. Precedence: content-level allowed_mentions (custom) wins,
then config.allowedMentions, else a safe default that parses all mention
types but never pings the replied-to author (replied_user: false) — so a
reply no longer pings its target unless opted back in.
Add pin/unpin instance actions mirroring startThread/createThread. Each takes a Message, resolves its channel and message snowflakes (unwrapping flattened group-item ids), and toggles the pinned state through new pinMessage/unpinMessage REST client helpers (createPin/deletePin).
Map an INTERACTION_CREATE of type MESSAGE_COMPONENT (a button click or
select-menu submit) to a Spectrum message. Acknowledge it within Discord's
3-second window first — DEFERRED_UPDATE_MESSAGE acks silently, so a reply the
handler sends is an ordinary channel message — then surface the click as
`custom` content a handler narrows on (`raw.discord.type === "interaction"`),
carrying custom_id, select values, the source message id, and the
interaction id/token for a future explicit-response API. Slash commands,
autocomplete and modal submits remain out of scope.
…ispatch matches

The embed() and components() content builders hardcoded __platform: "Discord",
but the dispatch guard in platform/build.ts compares the tag against the
provider's definePlatform name ("discord") with a strict, case-sensitive !==.
The capitalized tag silently failed that check, dropping every embed/components
send as "unsupported". Use the DISCORD_PLATFORM constant on both the schema and
the as* factories so the two can never drift, and pin the equality in tests.
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Caution

Review failed

An error occurred during the review process. Please try again later.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch andy/discord-provider

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

The discord provider source existed but was missing from tsup.config.ts's
entry list, so the manifest generator threw because no compiled output was
produced. Add the entry so the build succeeds and discord is emitted to
dist and included in the manifest.
@invisicat
Andy (invisicat) marked this pull request as ready for review June 17, 2026 00:57
Copilot AI review requested due to automatic review settings June 17, 2026 00:57
@coderabbitai coderabbitai Bot added the release Just as it is label Jun 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a first-class Discord bot provider to spectrum-ts, integrating Fusor-relayed Gateway dispatches for inbound events and direct Discord REST API (v10) calls for outbound operations, plus Discord-only rich features (embeds/components) and new instance actions (threads/pins).

Changes:

  • Introduces the Discord provider implementation (config, verify, inbound mapping, outbound send/mapping, REST client helpers, space creation).
  • Adds Discord-scoped content helpers (embed(...), components(...)) with upfront limit validation and outbound mapping support.
  • Extends the fusor definePlatform overload to type instance actions, and adds docs/tests + build/entry/dependency wiring.

Reviewed changes

Copilot reviewed 28 out of 29 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/spectrum-ts/tsup.config.ts Adds a build entry for the Discord provider.
packages/spectrum-ts/test/providers/discord/outbound/thread.test.ts Tests outbound thread instance actions via stubbed client helpers.
packages/spectrum-ts/test/providers/discord/outbound/pin.test.ts Tests pin/unpin instance actions and message-id unwrapping.
packages/spectrum-ts/test/providers/discord/outbound/message.test.ts Tests message-id parsing and poll spec mapping in buildSend.
packages/spectrum-ts/test/providers/discord/outbound/embed.test.ts Tests Discord-scoped embed builder/validation and mapping to send spec.
packages/spectrum-ts/test/providers/discord/outbound/components.test.ts Tests Discord-scoped components constructors/validation and mapping to send spec.
packages/spectrum-ts/test/providers/discord/outbound/allowed-mentions.test.ts Tests allowed-mentions resolution precedence and schema constraints.
packages/spectrum-ts/test/providers/discord/inbound/messages.test.ts Tests inbound dispatch → record mapping incl. polls/votes and interactions.
packages/spectrum-ts/src/providers/index.ts Exposes discord from the providers barrel.
packages/spectrum-ts/src/providers/discord/verify.ts Implements Fusor verify parsing for relayed Gateway dispatch frames.
packages/spectrum-ts/src/providers/discord/util.ts Adds multipart form serialization and CDN attachment download helper.
packages/spectrum-ts/src/providers/discord/types.ts Introduces inbound Gateway subset types and outbound DTO for sends.
packages/spectrum-ts/src/providers/discord/space.ts Adds Discord space creation (DM channel open) and user resolution.
packages/spectrum-ts/src/providers/discord/outbound/thread.ts Implements thread-start REST calls and option mapping.
packages/spectrum-ts/src/providers/discord/outbound/send.ts Adds outbound dispatcher incl. reactions, edits, groups, mentions defaults.
packages/spectrum-ts/src/providers/discord/outbound/pin.ts Implements pin/unpin instance actions.
packages/spectrum-ts/src/providers/discord/outbound/message.ts Adds content→Discord send spec mapping (poll, reply, files, custom, etc.).
packages/spectrum-ts/src/providers/discord/index.ts Wires the provider via definePlatform (fusor mode) + instance actions + exports.
packages/spectrum-ts/src/providers/discord/inbound/poll.ts Adds poll reconstruction and answer-id resolution helpers.
packages/spectrum-ts/src/providers/discord/inbound/messages.ts Maps dispatches to Spectrum records (messages/edits/deletes/reactions/votes/interactions).
packages/spectrum-ts/src/providers/discord/inbound/media.ts Maps Discord attachments to lazily-downloaded Spectrum attachment content.
packages/spectrum-ts/src/providers/discord/content/embed.ts Adds Discord-only embed content builder + limit validation + attachment refs.
packages/spectrum-ts/src/providers/discord/content/components.ts Adds Discord-only components builder + constructors + limit/layout validation.
packages/spectrum-ts/src/providers/discord/config.ts Adds provider config schema and allowed-mentions validation.
packages/spectrum-ts/src/providers/discord/client.ts Adds REST client construction and helper calls (messages, reactions, threads, pins, interactions, DM).
packages/spectrum-ts/src/platform/define.ts Extends fusor-mode definePlatform overload typing to include instance actions.
packages/spectrum-ts/package.json Adds @photon-ai/discord-ts dependency.
docs/discord.md Adds comprehensive Discord provider documentation.
bun.lock Updates lockfile with the new dependency and workspace metadata.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/discord/src/inbound/messages.ts
Comment thread docs/discord.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
docs/discord.md (1)

266-266: 💤 Low value

Consider rephrasing "exactly" for conciseness.

Line 266 uses the word "exactly," which LanguageTool flags as overused. The sentence: "Each returned value is exactly the @photon-ai/discord-ts request type..." can be streamlined without loss of clarity.

💡 Suggested rephrase
- Each returned value is exactly the `@photon-ai/discord-ts` request type, so an
+ Each returned value matches the `@photon-ai/discord-ts` request type, so an

or

- Each returned value is exactly the `@photon-ai/discord-ts` request type, so an
+ Each returned value is the `@photon-ai/discord-ts` request type, so an
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/discord.md` at line 266, The word "exactly" in the sentence beginning
with "Each returned value is exactly the `@photon-ai/discord-ts` request type..."
is flagged as overused by LanguageTool. Rephrase this sentence to remove or
replace "exactly" while maintaining the original meaning and clarity. Consider
alternatives that convey the same information more concisely, such as removing
"exactly" entirely or using a more specific verb or structure.
packages/spectrum-ts/src/providers/discord/client.ts (2)

54-66: ⚡ Quick win

Consider adding runtime validation for the multipart upload response.

The response from the raw client.post is cast to MessageResponse without schema validation (line 66). While throwOnError: true prevents error responses from being incorrectly typed, an unexpected success response shape could propagate invalid data downstream. Consider using a Zod schema or the discord-ts response validator if available.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/spectrum-ts/src/providers/discord/client.ts` around lines 54 - 66,
The return statement where res.data is cast to MessageResponse lacks runtime
validation of the response shape. Instead of directly casting res.data to
MessageResponse, validate the response object against a Zod schema or use the
discord-ts response validator before returning it. This ensures that unexpected
response shapes from the raw client.post call are caught at runtime rather than
propagating invalid data downstream. Apply the validation before the type
assertion to maintain type safety while catching structural issues.

234-238: ⚡ Quick win

Consider validating the DM channel response shape.

Line 238 casts the response to { id: string } without runtime validation. If Discord returns an unexpected shape, this could cause issues downstream. Consider adding a runtime check or using a Zod schema.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/spectrum-ts/src/providers/discord/client.ts` around lines 234 - 238,
The channel response from the createDm function is being cast to { id: string }
without any runtime validation, which could cause issues if Discord returns an
unexpected response shape. Add runtime validation to verify that the channel
response contains the expected id property before casting and returning it.
Consider using a Zod schema to validate the response structure or implement
manual validation checks to ensure the response has the required id field before
accessing it in the return statement.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/discord.md`:
- Line 105: In the discord.md documentation file, there is a typo where "AP"
should be "API". Locate the phrase "explicit-response AP" and change "AP" to
"API" to correctly reference the API functionality in the context of future
explicit-response features.

In `@packages/spectrum-ts/src/providers/discord/inbound/messages.ts`:
- Around line 51-55: The senderRef function incorrectly sets the isMe field to
Boolean(user.bot), which marks all bots as "me" rather than just the
application's own bot. This is inconsistent with other message handlers like
reactions, votes, and reaction-removes which hardcode isMe to false. Since
self-filtering is already handled via config.applicationId checks before
messages reach senderRef, all remaining inbound senders are from OTHER users or
bots. Change the isMe field in the senderRef function to be a hardcoded false
value instead of Boolean(user.bot) to match the semantics used elsewhere and
prevent downstream bugs from false positives.

In `@packages/spectrum-ts/src/providers/discord/types.ts`:
- Around line 52-55: The JSDoc comment for the DiscordPollMedia interface is
inaccurate. Update the comment to reflect the actual interface definition, which
only contains a text field. Remove the reference to "optional emoji" and clarify
that the interface contains "text only" with a note that "emoji support
intentionally omitted" to match the actual implementation and align with the
design decision documented in message.ts.

---

Nitpick comments:
In `@docs/discord.md`:
- Line 266: The word "exactly" in the sentence beginning with "Each returned
value is exactly the `@photon-ai/discord-ts` request type..." is flagged as
overused by LanguageTool. Rephrase this sentence to remove or replace "exactly"
while maintaining the original meaning and clarity. Consider alternatives that
convey the same information more concisely, such as removing "exactly" entirely
or using a more specific verb or structure.

In `@packages/spectrum-ts/src/providers/discord/client.ts`:
- Around line 54-66: The return statement where res.data is cast to
MessageResponse lacks runtime validation of the response shape. Instead of
directly casting res.data to MessageResponse, validate the response object
against a Zod schema or use the discord-ts response validator before returning
it. This ensures that unexpected response shapes from the raw client.post call
are caught at runtime rather than propagating invalid data downstream. Apply the
validation before the type assertion to maintain type safety while catching
structural issues.
- Around line 234-238: The channel response from the createDm function is being
cast to { id: string } without any runtime validation, which could cause issues
if Discord returns an unexpected response shape. Add runtime validation to
verify that the channel response contains the expected id property before
casting and returning it. Consider using a Zod schema to validate the response
structure or implement manual validation checks to ensure the response has the
required id field before accessing it in the return statement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2f1f8853-b326-40f5-961d-12a5fa25baff

📥 Commits

Reviewing files that changed from the base of the PR and between e47cf3d and 14def20.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • docs/discord.md
  • packages/spectrum-ts/package.json
  • packages/spectrum-ts/src/platform/define.ts
  • packages/spectrum-ts/src/providers/discord/client.ts
  • packages/spectrum-ts/src/providers/discord/config.ts
  • packages/spectrum-ts/src/providers/discord/content/components.ts
  • packages/spectrum-ts/src/providers/discord/content/embed.ts
  • packages/spectrum-ts/src/providers/discord/inbound/media.ts
  • packages/spectrum-ts/src/providers/discord/inbound/messages.ts
  • packages/spectrum-ts/src/providers/discord/inbound/poll.ts
  • packages/spectrum-ts/src/providers/discord/index.ts
  • packages/spectrum-ts/src/providers/discord/outbound/message.ts
  • packages/spectrum-ts/src/providers/discord/outbound/pin.ts
  • packages/spectrum-ts/src/providers/discord/outbound/send.ts
  • packages/spectrum-ts/src/providers/discord/outbound/thread.ts
  • packages/spectrum-ts/src/providers/discord/space.ts
  • packages/spectrum-ts/src/providers/discord/types.ts
  • packages/spectrum-ts/src/providers/discord/util.ts
  • packages/spectrum-ts/src/providers/discord/verify.ts
  • packages/spectrum-ts/src/providers/index.ts
  • packages/spectrum-ts/test/providers/discord/inbound/messages.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/allowed-mentions.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/components.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/embed.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/message.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/pin.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/thread.test.ts
  • packages/spectrum-ts/tsup.config.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity in TypeScript
Prefer unknown over any when the type is genuinely unknown in TypeScript
Use const assertions (as const) for immutable values and literal types in TypeScript
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/spectrum-ts/src/providers/discord/inbound/media.ts
  • packages/spectrum-ts/src/providers/discord/util.ts
  • packages/spectrum-ts/src/providers/index.ts
  • packages/spectrum-ts/test/providers/discord/outbound/message.test.ts
  • packages/spectrum-ts/src/providers/discord/inbound/poll.ts
  • packages/spectrum-ts/tsup.config.ts
  • packages/spectrum-ts/src/providers/discord/verify.ts
  • packages/spectrum-ts/src/providers/discord/space.ts
  • packages/spectrum-ts/test/providers/discord/outbound/allowed-mentions.test.ts
  • packages/spectrum-ts/src/providers/discord/outbound/pin.ts
  • packages/spectrum-ts/test/providers/discord/outbound/pin.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/thread.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/embed.test.ts
  • packages/spectrum-ts/src/providers/discord/config.ts
  • packages/spectrum-ts/src/providers/discord/outbound/send.ts
  • packages/spectrum-ts/src/providers/discord/outbound/thread.ts
  • packages/spectrum-ts/src/providers/discord/index.ts
  • packages/spectrum-ts/src/platform/define.ts
  • packages/spectrum-ts/test/providers/discord/outbound/components.test.ts
  • packages/spectrum-ts/src/providers/discord/client.ts
  • packages/spectrum-ts/src/providers/discord/outbound/message.ts
  • packages/spectrum-ts/test/providers/discord/inbound/messages.test.ts
  • packages/spectrum-ts/src/providers/discord/content/embed.ts
  • packages/spectrum-ts/src/providers/discord/content/components.ts
  • packages/spectrum-ts/src/providers/discord/types.ts
  • packages/spectrum-ts/src/providers/discord/inbound/messages.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions in JavaScript/TypeScript
Prefer for...of loops over .forEach() and indexed for loops in JavaScript/TypeScript
Use optional chaining (?.) and nullish coalescing (??) for safer property access in JavaScript/TypeScript
Prefer template literals over string concatenation in JavaScript/TypeScript
Use destructuring for object and array assignments in JavaScript/TypeScript
Use const by default, let only when reassignment is needed, never var in JavaScript/TypeScript
Always await promises in async functions - don't forget to use the return value in JavaScript/TypeScript
Use async/await syntax instead of promise chains for better readability in JavaScript/TypeScript
Handle errors appropriately in async code with try-catch blocks in JavaScript/TypeScript
Don't use async functions as Promise executors in JavaScript/TypeScript
Remove console.log, debugger, and alert statements from production code in JavaScript/TypeScript
Throw Error objects with descriptive messages, not strings or other values in JavaScript/TypeScript
Use try-catch blocks meaningfully - don't catch errors just to rethrow them in JavaScript/TypeScript
Prefer early returns over nested conditionals for error cases in JavaScript/TypeScript
Keep functions focused and under reasonable cognitive complexity limits
Extract complex conditions into well-named boolean variables in JavaScript/TypeScript
Use early returns to reduce nesting in JavaScript/TypeScript
Prefer simple conditionals over nested ternary operators in JavaScript/TypeScript
Group related code together and separate concerns in JavaScript/TypeScript
Don't use eval() or assign directly to document.cookie in JavaScript/TypeScript
Validate and sanitize user input in JavaScript/TypeScript
Avoid spread syntax in accumulators within loops in JavaScript/Ty...

Files:

  • packages/spectrum-ts/src/providers/discord/inbound/media.ts
  • packages/spectrum-ts/src/providers/discord/util.ts
  • packages/spectrum-ts/src/providers/index.ts
  • packages/spectrum-ts/test/providers/discord/outbound/message.test.ts
  • packages/spectrum-ts/src/providers/discord/inbound/poll.ts
  • packages/spectrum-ts/tsup.config.ts
  • packages/spectrum-ts/src/providers/discord/verify.ts
  • packages/spectrum-ts/src/providers/discord/space.ts
  • packages/spectrum-ts/test/providers/discord/outbound/allowed-mentions.test.ts
  • packages/spectrum-ts/src/providers/discord/outbound/pin.ts
  • packages/spectrum-ts/test/providers/discord/outbound/pin.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/thread.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/embed.test.ts
  • packages/spectrum-ts/src/providers/discord/config.ts
  • packages/spectrum-ts/src/providers/discord/outbound/send.ts
  • packages/spectrum-ts/src/providers/discord/outbound/thread.ts
  • packages/spectrum-ts/src/providers/discord/index.ts
  • packages/spectrum-ts/src/platform/define.ts
  • packages/spectrum-ts/test/providers/discord/outbound/components.test.ts
  • packages/spectrum-ts/src/providers/discord/client.ts
  • packages/spectrum-ts/src/providers/discord/outbound/message.ts
  • packages/spectrum-ts/test/providers/discord/inbound/messages.test.ts
  • packages/spectrum-ts/src/providers/discord/content/embed.ts
  • packages/spectrum-ts/src/providers/discord/content/components.ts
  • packages/spectrum-ts/src/providers/discord/types.ts
  • packages/spectrum-ts/src/providers/discord/inbound/messages.ts
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions inside it() or test() blocks in test files
Avoid done callbacks in async tests - use async/await instead in test files
Don't use .only or .skip in committed code in test files
Keep test suites reasonably flat - avoid excessive describe nesting in test files

Files:

  • packages/spectrum-ts/test/providers/discord/outbound/message.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/allowed-mentions.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/pin.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/thread.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/embed.test.ts
  • packages/spectrum-ts/test/providers/discord/outbound/components.test.ts
  • packages/spectrum-ts/test/providers/discord/inbound/messages.test.ts
🪛 LanguageTool
docs/discord.md

[grammar] ~105-~105: Use a hyphen to join words.
Context: ...teraction_id/token`. The id/token ride along so a future explicit-response AP...

(QB_NEW_EN_HYPHEN)


[style] ~266-~266: Consider an alternative for the overused word “exactly”.
Context: .../premium| Each returned value is exactly the@photon-ai/discord-ts` request typ...

(EXACTLY_PRECISELY)

🪛 OpenGrep (1.22.0)
packages/spectrum-ts/src/providers/discord/outbound/message.ts

[ERROR] 30-30: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🔇 Additional comments (29)
packages/spectrum-ts/src/providers/discord/verify.ts (1)

1-46: LGTM!

packages/spectrum-ts/src/providers/discord/inbound/media.ts (1)

1-23: LGTM!

packages/spectrum-ts/src/providers/discord/inbound/poll.ts (1)

1-66: LGTM!

packages/spectrum-ts/src/providers/discord/inbound/messages.ts (2)

60-91: LGTM!


93-423: LGTM!

packages/spectrum-ts/test/providers/discord/inbound/messages.test.ts (1)

1-336: LGTM!

packages/spectrum-ts/package.json (1)

105-105: LGTM!

packages/spectrum-ts/src/platform/define.ts (1)

435-435: LGTM!

Also applies to: 458-460, 495-497

packages/spectrum-ts/src/providers/discord/types.ts (1)

14-23: LGTM!

Also applies to: 31-33, 35-240

packages/spectrum-ts/src/providers/discord/config.ts (1)

1-133: LGTM!

packages/spectrum-ts/tsup.config.ts (1)

11-11: LGTM!

packages/spectrum-ts/src/providers/index.ts (1)

2-2: LGTM!

packages/spectrum-ts/src/providers/discord/client.ts (2)

60-63: Excellent security handling for multipart uploads.

The explicit security opt-in ensures the bot token is sent with ad-hoc POST requests. The comment clearly explains why this is necessary—well done.


33-34: LGTM!

Also applies to: 76-86, 93-101, 107-117, 123-128, 136-146, 155-164, 171-180, 188-197, 214-224

packages/spectrum-ts/src/providers/discord/util.ts (1)

1-42: LGTM!

packages/spectrum-ts/src/providers/discord/space.ts (1)

1-47: LGTM!

packages/spectrum-ts/src/providers/discord/outbound/thread.ts (1)

1-91: LGTM!

packages/spectrum-ts/src/providers/discord/outbound/pin.ts (1)

1-42: LGTM!

packages/spectrum-ts/test/providers/discord/outbound/thread.test.ts (1)

1-122: LGTM!

packages/spectrum-ts/test/providers/discord/outbound/pin.test.ts (1)

1-66: LGTM!

packages/spectrum-ts/src/providers/discord/index.ts (1)

1-96: LGTM!

packages/spectrum-ts/src/providers/discord/content/embed.ts (1)

1-253: LGTM!

packages/spectrum-ts/src/providers/discord/content/components.ts (1)

1-377: LGTM!

packages/spectrum-ts/test/providers/discord/outbound/embed.test.ts (1)

1-208: LGTM!

packages/spectrum-ts/test/providers/discord/outbound/components.test.ts (1)

1-255: LGTM!

packages/spectrum-ts/src/providers/discord/outbound/message.ts (1)

1-184: LGTM!

packages/spectrum-ts/src/providers/discord/outbound/send.ts (1)

1-181: LGTM!

packages/spectrum-ts/test/providers/discord/outbound/message.test.ts (1)

1-56: LGTM!

packages/spectrum-ts/test/providers/discord/outbound/allowed-mentions.test.ts (1)

1-87: LGTM!

Comment thread docs/discord.md
Comment thread packages/discord/src/inbound/messages.ts
Comment thread packages/discord/src/types.ts
sometimes bots will send messages as well.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 17, 2026 01:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 17, 2026 01:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Reconcile the discord provider with the v5 monolith split (#124): move it
into its own @spectrum-ts/discord package (mirroring telegram), rewrite its
imports onto @spectrum-ts/core + /authoring, and leave a compat shim at
spectrum-ts/providers/discord.

- Add asEdit, asUnsend, asReply, attachmentSchema, BaseContent, createStore
  to @spectrum-ts/core/authoring (the inbound factories discord needs)
- New packages/discord package: package.json, tsconfig, tsdown, turbo, README
- Wire discord into the providers barrel, spectrum-ts deps, tsdown entries,
  providers-shims parity test, and the README platform table
@pkg-pr-new

pkg-pr-new Bot commented Jun 18, 2026

Copy link
Copy Markdown

Open in StackBlitz

@spectrum-ts/core

npm i https://pkg.pr.new/photon-hq/spectrum-ts/@spectrum-ts/core@129

@spectrum-ts/discord

npm i https://pkg.pr.new/photon-hq/spectrum-ts/@spectrum-ts/discord@129

@spectrum-ts/imessage

npm i https://pkg.pr.new/photon-hq/spectrum-ts/@spectrum-ts/imessage@129

@spectrum-ts/slack

npm i https://pkg.pr.new/photon-hq/spectrum-ts/@spectrum-ts/slack@129

spectrum-ts

npm i https://pkg.pr.new/photon-hq/spectrum-ts@129

@spectrum-ts/telegram

npm i https://pkg.pr.new/photon-hq/spectrum-ts/@spectrum-ts/telegram@129

@spectrum-ts/terminal

npm i https://pkg.pr.new/photon-hq/spectrum-ts/@spectrum-ts/terminal@129

@spectrum-ts/whatsapp-business

npm i https://pkg.pr.new/photon-hq/spectrum-ts/@spectrum-ts/whatsapp-business@129

commit: 1d58e0d

Copilot AI review requested due to automatic review settings June 18, 2026 20:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/discord/package.json (1)

56-56: Avoid latest for @types/bun to keep installs reproducible.

Using latest causes the dependency to float, potentially pulling different type definitions across installs and CI runs. Pin to a specific version range instead.

Proposed change
-    "`@types/bun`": "latest",
+    "`@types/bun`": "^1.2.0",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/discord/package.json` at line 56, The "`@types/bun`" dependency in
packages/discord/package.json is pinned to "latest" which causes
non-reproducible installs as different versions may be resolved in different
environments and CI runs. Replace the "latest" version string with a specific
version or version range (such as a pinned version like "1.0.0" or a ranged
version like "^1.0.0") to ensure consistent and reproducible dependency
resolution across all installs and CI environments.
packages/spectrum-ts/test/providers-shims.test.ts (1)

36-42: ⚡ Quick win

Assert exact export-key parity, not just pkg→shim forwarding.

This currently allows extra shim-only exports to slip through while still passing. Add a key-set equality assertion before identity checks.

Suggested patch
   for (const [key, shim, pkg] of cases) {
     it(`${key}: forwards every export of the provider package`, () => {
-      for (const name of Object.keys(pkg)) {
+      const pkgKeys = Object.keys(pkg).sort();
+      const shimKeys = Object.keys(shim).sort();
+      expect(shimKeys).toEqual(pkgKeys);
+
+      for (const name of pkgKeys) {
         expect(shim[name as keyof typeof shim]).toBe(
           pkg[name as keyof typeof pkg]
         );
       }
-      expect(Object.keys(pkg).length).toBeGreaterThan(0);
+      expect(pkgKeys.length).toBeGreaterThan(0);
     });
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/spectrum-ts/test/providers-shims.test.ts` around lines 36 - 42, The
test currently only verifies that all keys from pkg exist in the shim object,
but does not verify that the shim object does not contain extra keys beyond what
pkg exports. Add an assertion to check that the set of keys in the shim object
exactly matches the set of keys in the pkg object, ensuring complete export-key
parity. This assertion should compare Object.keys(shim) with Object.keys(pkg) to
guarantee they have identical exports and no extra shim-only exports slip
through.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/discord/package.json`:
- Line 56: The "`@types/bun`" dependency in packages/discord/package.json is
pinned to "latest" which causes non-reproducible installs as different versions
may be resolved in different environments and CI runs. Replace the "latest"
version string with a specific version or version range (such as a pinned
version like "1.0.0" or a ranged version like "^1.0.0") to ensure consistent and
reproducible dependency resolution across all installs and CI environments.

In `@packages/spectrum-ts/test/providers-shims.test.ts`:
- Around line 36-42: The test currently only verifies that all keys from pkg
exist in the shim object, but does not verify that the shim object does not
contain extra keys beyond what pkg exports. Add an assertion to check that the
set of keys in the shim object exactly matches the set of keys in the pkg
object, ensuring complete export-key parity. This assertion should compare
Object.keys(shim) with Object.keys(pkg) to guarantee they have identical exports
and no extra shim-only exports slip through.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d034f338-9e4e-4d02-8bf0-1f0ce9385975

📥 Commits

Reviewing files that changed from the base of the PR and between 3d4ce97 and a7b1d67.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (36)
  • README.md
  • packages/core/src/authoring.ts
  • packages/core/src/platform/define.ts
  • packages/discord/README.md
  • packages/discord/package.json
  • packages/discord/src/client.ts
  • packages/discord/src/config.ts
  • packages/discord/src/content/components.ts
  • packages/discord/src/content/embed.ts
  • packages/discord/src/inbound/media.ts
  • packages/discord/src/inbound/messages.ts
  • packages/discord/src/inbound/poll.ts
  • packages/discord/src/index.ts
  • packages/discord/src/outbound/message.ts
  • packages/discord/src/outbound/pin.ts
  • packages/discord/src/outbound/send.ts
  • packages/discord/src/outbound/thread.ts
  • packages/discord/src/space.ts
  • packages/discord/src/types.ts
  • packages/discord/src/util.ts
  • packages/discord/src/verify.ts
  • packages/discord/test/inbound/messages.test.ts
  • packages/discord/test/outbound/allowed-mentions.test.ts
  • packages/discord/test/outbound/components.test.ts
  • packages/discord/test/outbound/embed.test.ts
  • packages/discord/test/outbound/message.test.ts
  • packages/discord/test/outbound/pin.test.ts
  • packages/discord/test/outbound/thread.test.ts
  • packages/discord/tsconfig.json
  • packages/discord/tsdown.config.ts
  • packages/discord/turbo.json
  • packages/spectrum-ts/package.json
  • packages/spectrum-ts/src/providers/discord/index.ts
  • packages/spectrum-ts/src/providers/index.ts
  • packages/spectrum-ts/test/providers-shims.test.ts
  • packages/spectrum-ts/tsdown.config.ts
💤 Files with no reviewable changes (5)
  • packages/discord/src/space.ts
  • packages/discord/src/util.ts
  • packages/discord/src/types.ts
  • packages/discord/src/client.ts
  • packages/core/src/platform/define.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/discord/turbo.json
  • packages/discord/README.md
  • README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/spectrum-ts/src/providers/index.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity in TypeScript
Prefer unknown over any when the type is genuinely unknown in TypeScript
Use const assertions (as const) for immutable values and literal types in TypeScript
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/spectrum-ts/tsdown.config.ts
  • packages/discord/test/outbound/message.test.ts
  • packages/discord/tsdown.config.ts
  • packages/core/src/authoring.ts
  • packages/discord/src/verify.ts
  • packages/discord/src/inbound/poll.ts
  • packages/spectrum-ts/test/providers-shims.test.ts
  • packages/discord/test/outbound/thread.test.ts
  • packages/discord/src/inbound/media.ts
  • packages/discord/src/outbound/thread.ts
  • packages/discord/test/inbound/messages.test.ts
  • packages/discord/src/index.ts
  • packages/discord/test/outbound/components.test.ts
  • packages/discord/src/outbound/pin.ts
  • packages/discord/test/outbound/allowed-mentions.test.ts
  • packages/discord/src/content/embed.ts
  • packages/discord/test/outbound/embed.test.ts
  • packages/discord/src/config.ts
  • packages/discord/test/outbound/pin.test.ts
  • packages/discord/src/outbound/message.ts
  • packages/discord/src/outbound/send.ts
  • packages/discord/src/inbound/messages.ts
  • packages/discord/src/content/components.ts
  • packages/spectrum-ts/src/providers/discord/index.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions in JavaScript/TypeScript
Prefer for...of loops over .forEach() and indexed for loops in JavaScript/TypeScript
Use optional chaining (?.) and nullish coalescing (??) for safer property access in JavaScript/TypeScript
Prefer template literals over string concatenation in JavaScript/TypeScript
Use destructuring for object and array assignments in JavaScript/TypeScript
Use const by default, let only when reassignment is needed, never var in JavaScript/TypeScript
Always await promises in async functions - don't forget to use the return value in JavaScript/TypeScript
Use async/await syntax instead of promise chains for better readability in JavaScript/TypeScript
Handle errors appropriately in async code with try-catch blocks in JavaScript/TypeScript
Don't use async functions as Promise executors in JavaScript/TypeScript
Remove console.log, debugger, and alert statements from production code in JavaScript/TypeScript
Throw Error objects with descriptive messages, not strings or other values in JavaScript/TypeScript
Use try-catch blocks meaningfully - don't catch errors just to rethrow them in JavaScript/TypeScript
Prefer early returns over nested conditionals for error cases in JavaScript/TypeScript
Keep functions focused and under reasonable cognitive complexity limits
Extract complex conditions into well-named boolean variables in JavaScript/TypeScript
Use early returns to reduce nesting in JavaScript/TypeScript
Prefer simple conditionals over nested ternary operators in JavaScript/TypeScript
Group related code together and separate concerns in JavaScript/TypeScript
Don't use eval() or assign directly to document.cookie in JavaScript/TypeScript
Validate and sanitize user input in JavaScript/TypeScript
Avoid spread syntax in accumulators within loops in JavaScript/Ty...

Files:

  • packages/spectrum-ts/tsdown.config.ts
  • packages/discord/test/outbound/message.test.ts
  • packages/discord/tsdown.config.ts
  • packages/core/src/authoring.ts
  • packages/discord/src/verify.ts
  • packages/discord/src/inbound/poll.ts
  • packages/spectrum-ts/test/providers-shims.test.ts
  • packages/discord/test/outbound/thread.test.ts
  • packages/discord/src/inbound/media.ts
  • packages/discord/src/outbound/thread.ts
  • packages/discord/test/inbound/messages.test.ts
  • packages/discord/src/index.ts
  • packages/discord/test/outbound/components.test.ts
  • packages/discord/src/outbound/pin.ts
  • packages/discord/test/outbound/allowed-mentions.test.ts
  • packages/discord/src/content/embed.ts
  • packages/discord/test/outbound/embed.test.ts
  • packages/discord/src/config.ts
  • packages/discord/test/outbound/pin.test.ts
  • packages/discord/src/outbound/message.ts
  • packages/discord/src/outbound/send.ts
  • packages/discord/src/inbound/messages.ts
  • packages/discord/src/content/components.ts
  • packages/spectrum-ts/src/providers/discord/index.ts
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions inside it() or test() blocks in test files
Avoid done callbacks in async tests - use async/await instead in test files
Don't use .only or .skip in committed code in test files
Keep test suites reasonably flat - avoid excessive describe nesting in test files

Files:

  • packages/discord/test/outbound/message.test.ts
  • packages/spectrum-ts/test/providers-shims.test.ts
  • packages/discord/test/outbound/thread.test.ts
  • packages/discord/test/inbound/messages.test.ts
  • packages/discord/test/outbound/components.test.ts
  • packages/discord/test/outbound/allowed-mentions.test.ts
  • packages/discord/test/outbound/embed.test.ts
  • packages/discord/test/outbound/pin.test.ts
🔇 Additional comments (27)
packages/discord/src/verify.ts (1)

1-1: LGTM!

packages/discord/src/inbound/media.ts (1)

1-2: LGTM!

packages/discord/src/inbound/poll.ts (1)

1-2: LGTM!

packages/discord/src/inbound/messages.ts (1)

1-17: LGTM!

packages/discord/test/inbound/messages.test.ts (1)

16-29: LGTM!

packages/discord/src/config.ts (1)

108-108: LGTM!

Also applies to: 118-120

packages/discord/tsconfig.json (1)

1-10: LGTM!

packages/discord/tsdown.config.ts (1)

1-10: LGTM!

packages/discord/src/outbound/thread.ts (1)

2-2: LGTM!

packages/discord/src/outbound/pin.ts (1)

1-1: LGTM!

packages/discord/test/outbound/pin.test.ts (1)

16-24: LGTM!

packages/discord/src/index.ts (1)

1-99: LGTM!

packages/discord/package.json (1)

19-33: No issue: publishConfig.exports correctly overrides for npm publish.

The workspace exports.types intentionally points to ./src/index.ts for development DX (buildless in-repo resolution). The build/publish toolchain (clean-publish) applies publishConfig.exports during publishing, which correctly maps types to ./dist/index.d.ts. This is validated in CI via publint and @arethetypeswrong/cli against the cleaned artifact before npm publish, confirming downstream TypeScript resolution will not break.

packages/core/src/authoring.ts (1)

1-54: LGTM!

packages/discord/test/outbound/embed.test.ts (1)

2-6: LGTM!

packages/discord/test/outbound/components.test.ts (1)

2-4: LGTM!

Also applies to: 14-15

packages/discord/src/outbound/send.ts (1)

2-8: LGTM!

packages/discord/test/outbound/message.test.ts (1)

2-3: LGTM!

packages/discord/test/outbound/allowed-mentions.test.ts (1)

6-7: LGTM!

packages/discord/test/outbound/thread.test.ts (1)

32-40: LGTM!

packages/spectrum-ts/package.json (1)

3-4: LGTM!

Also applies to: 60-60, 94-111

packages/spectrum-ts/src/providers/discord/index.ts (1)

1-10: LGTM!

packages/spectrum-ts/tsdown.config.ts (1)

1-29: LGTM!

packages/spectrum-ts/test/providers-shims.test.ts (1)

1-35: LGTM!

Also applies to: 43-54

packages/discord/src/content/embed.ts (1)

2-3: LGTM!

packages/discord/src/content/components.ts (1)

12-12: LGTM!

packages/discord/src/outbound/message.ts (1)

1-6: LGTM!

# Conflicts:
#	bun.lock
#	packages/core/src/authoring.ts
…g URL

main (#140) added the universal `app` content type to the base Content
union. Discord has no mini-app surface (iMessage renders the card; others
fall back to the URL), so map `app` to its resolved URL in buildSend —
Discord auto-embeds it, exactly like `richlink`. Handling it in buildSend
(not just send) lets `app` also be the inner content of a `reply` or an
item of a `group`.
…nd client

Discord was the one provider untouched by #139's structured-logging pass.
Wire in the same createLogger/errorAttrs pattern:

- verify: warn on rejected inbound events (bad JSON / missing `t`)
- inbound: warn on interaction-ack failure, debug on poll cache-miss
  fetch, warn when a poll vote is dropped (fetched message has no poll)
- outbound: warn on send failure (excludes by-design UnsupportedError)
- client: warn on DM-channel open failure (typically a 403)

Error paths log then re-throw — no behavior change. Attrs are PII-safe
(ids and byte counts only).
Copilot AI review requested due to automatic review settings June 19, 2026 19:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release Just as it is

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants