---
name: bijection-photon
description: "Evaluate and integrate the Photon component with Bijection."
---

# Photon

Bijection component for Photon iMessage — durable inbound pipeline, batching, cancellation, and a deduped, paced outbox.

- Package: @bijectionhq/photon
- Category: Messaging
- Status: Preview
- License: MIT
- Bijection source (repository access required): https://github.com/bijectionhq/photon/tree/054653aa8a91a527f788645eb4144413329605a5
- Upstream: https://github.com/photon-hq/spectrum-convex/tree/1f02145fded5085320f5e8f486fa7c1a24a0e605
- Documentation: https://docs.bijection.com/components/using
- Directory: https://bijection.com/components/photon

## Get the source

Bijection repository access is required. Request access at https://bijection.com/contact.

```sh
git clone https://github.com/bijectionhq/photon.git
cd photon
git checkout 054653aa8a91a527f788645eb4144413329605a5
```

## Before using this component

Read the package README at the recorded revision for setup, dependencies, and API examples. Upstream documentation describes the original package and may differ from the Bijection adaptation. This is a source candidate for evaluation. Catalog inclusion does not establish npm availability or runtime qualification. Check compatibility with your SDK and deployment before adoption. External providers run their own compute.

## Integration workflow

1. Read the source README and package manifest at the recorded revision.
2. Confirm the required SDK, dependency availability, and runtime compatibility.
3. Follow the component's documented setup and configuration. Never invent an npm install command from a catalog package name.
4. Keep credentials in the project's existing secret store.
5. Follow the project's execution rules for verification and report what was actually checked.

## Original upstream skill

The following guidance describes @spectrum-ts/convex. Its installation commands and APIs refer to the upstream package. Evaluate compatibility with the Bijection source separately.


> Agents: read this skill fully before writing code that uses iMessage (Photon). Follow the installation and configuration steps exactly.

# iMessage (Photon)

## Instructions

Use iMessage (Photon) to convex component that durably handles imessage, rcs, and sms via photon with verified webhook ingestion, burst debouncing, and a grpc outbox pipeline. This Convex component integrates directly with your backend.

### Installation

```bash
npm install @spectrum-ts/convex
```

Current npm version: `@spectrum-ts/convex@0.1.1`

### Capabilities

- Receive iMessage, RCS, and SMS webhooks durably: messages are written to Convex before the 200 response, so no delivery is lost if your handler crashes.
- Avoid rebuilding the Photon production pipeline: burst debouncing, in-flight cancellation, carry-forward context, and paced sends are included out of the box.
- Choose between immediate and collapse turn policies to control whether each message triggers its own handler or bursts are coalesced into a single LLM call.
- Deduplicate at-least-once webhook deliveries automatically using provider message IDs, and deduplicate outbound sends using deterministic client GUIDs.

## Examples

### how to receive iMessage webhooks in a Convex backend

The @spectrum-ts/convex component registers an HTTP route via spectrum.registerRoutes(http) that verifies the Photon HMAC signature and writes the delivery to a Convex table before returning 200. Because the write is durable before the response, Convex's scheduler can process the message even if the isolate is torn down immediately after. No long-lived process is needed on the Convex side.

### how to build an iMessage AI agent with Convex that handles rapid follow-up messages

Set mode: 'collapse' when constructing the Spectrum instance. In this mode, a new inbound message cancels any in-flight reply that has not yet been sent and carries all prior messages forward as context, so the agent answers the final intent rather than each intermediate message. The isCancelled check inside your internalAction lets you abort after slow operations like LLM calls.

### send iMessage from a Convex action using Photon gRPC

Call spectrum.send(ctx, { spaceId, chainId, content }) inside a Convex Node action. The component queues the send to an outbox and dispatches it through a gRPC transport via createCloudSender from @spectrum-ts/convex/sender. You must install the gRPC peer dependencies and add them to node.externalPackages in convex.json, and include a _workaround.ts re-export so Convex bundles the optional peers.

### deduplicate webhook deliveries in Convex messaging component

The @spectrum-ts/convex component deduplicates inbound deliveries on the provider message ID, so redeliveries of the same message do not create duplicate rows or trigger duplicate handler calls. Outbound sends are also deduplicated at the outbox using a clientGuid derived from (chainId, seq), preventing the same logical send from being queued twice.

## When NOT to use

- When a simpler built-in solution exists for your specific use case
- If you are not using Convex as your backend
- When the functionality provided by iMessage (Photon) is not needed

## Troubleshooting

**Why can't I use Photon's app.messages loop or app.webhook() directly in Convex?**

Photon's app.messages loop requires a long-lived process, which Convex isolates do not support. The app.webhook() handler runs after the HTTP response is returned, but a Convex isolate is frozen at that point, so any work done there is unreliable. The @spectrum-ts/convex component solves this by writing the verified delivery to a Convex table before the 200 response is sent, making it durable, and then scheduling all subsequent work through Convex's scheduler.

**What environment variables does the iMessage (Photon) Convex component require?**

The @spectrum-ts/convex component requires three environment variables set in the Convex dashboard: SPECTRUM_WEBHOOK_SECRET for verifying the HMAC signature on incoming webhooks, SPECTRUM_PROJECT_ID for identifying your Spectrum Cloud project, and SPECTRUM_PROJECT_SECRET for authenticating with Spectrum Cloud.

**What is the difference between immediate and collapse mode in @spectrum-ts/convex?**

In immediate mode (the default), every inbound message triggers a separate onBatch handler call with a single message and no carried context, which is appropriate for cheap replies like echo bots or commands. In collapse mode, a burst of messages within a settling window is coalesced into one handler call, and a new message while a reply is in flight cancels that reply and carries all messages forward as prior context, which is appropriate for expensive LLM-based replies.

**Why do gRPC sends fail with a peer dependency error even when the packages are in package.json?**

Convex only installs externalPackages entries if the bundled code statically imports them. The gRPC peers (nice-grpc, nice-grpc-common, @grpc/grpc-js) are optional peers of @photon-ai/advanced-imessage and are loaded dynamically, so the bundler never references them and they are not installed. The fix is to add a convex/_workaround.ts file that re-exports all three packages, giving the bundler the static reference it needs to include them.

**What message content types can be sent through the @spectrum-ts/convex outbox?**

The @spectrum-ts/convex outbox currently supports text and markdown content. The outbox serializes content to JSON for durability and replays it later, and there is no public Photon SDK API to send a pre-resolved Content object back. Attachments, polls, and other rich content types are not supported and will throw a clear error rather than sending incorrect content.

## Resources

- [npm package](https://www.npmjs.com/package/%40spectrum-ts%2Fconvex)
- [GitHub repository](https://github.com/photon-hq/spectrum-convex)
- [Live demo](https://salesdemo.photon.codes/)
- [Convex Components Directory](https://www.convex.dev/components/spectrum-ts/convex)
- [Convex documentation](https://docs.convex.dev)