You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs-src/spectrum-ts/custom-events-and-lifecycle.mdx.vel
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -42,7 +42,7 @@ Use the flat form on `app` when you want a merged feed across platforms; use the
42
42
await app.stop();
43
43
```
44
44
45
-
This closes the merged message stream, drains and disposes every custom event stream, and tears down every platform client via its `lifecycle.destroyClient` hook. It's idempotent — calling `stop()` twice is safe.
45
+
This closes the merged message stream, drains and disposes every custom event stream, and tears down every platform client via its `lifecycle.destroyClient` hook (if one is defined). It's idempotent — calling `stop()` twice is safe.
| `space.resolve` | Yes | Resolves or creates a conversation. Receives an array of users plus optional params. |
94
94
| `space.schema` | No | Optional Zod schema for the resolved space. |
95
95
| `space.params` | No | Zod schema for additional space creation parameters — surfaces as the second arg to `platform(app).space()`. |
96
-
| `lifecycle.createClient` | Yes | Creates the platform client. Receives `config`, `projectId`, `projectSecret` (both may be `undefined`). |
97
-
| `lifecycle.destroyClient` | Yes | Tears down the client on shutdown. |
96
+
| `lifecycle.createClient` | Yes | Creates the platform client. Receives `config`, `projectId`, `projectSecret` (both may be `undefined`), and `store`. |
97
+
| `lifecycle.destroyClient` | No | Tears down the client on shutdown. Omit if no cleanup is needed. |
Every event generator receives `{ client, config }` and returns an `AsyncIterable`. The signature is <TypeTooltip name="EventProducer" type={`{{ ep.signature }}`} />.
110
+
Every event generator receives `{ client, config, store }` and returns an `AsyncIterable`. The signature is <TypeTooltip name="EventProducer" type={`{{ ep.signature }}`} />.
Copy file name to clipboardExpand all lines: docs-src/spectrum-ts/providers/imessage.mdx.vel
+18-6Lines changed: 18 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@ description: "Receive and send iMessage across local, cloud, and dedicated modes
7
7
import { imessage } from "spectrum-ts/providers/imessage";
8
8
```
9
9
10
-
The iMessage provider supports three connection modes — local, cloud, and dedicated — and exposes iMessage-specific features (tapbacks, DM vs group spaces) through [platform narrowing](/spectrum-ts/platform-narrowing).
10
+
The iMessage provider supports three connection modes — local, cloud, and dedicated — and exposes iMessage-specific features (tapbacks, DM vs group spaces, per-phone routing) through [platform narrowing](/spectrum-ts/platform-narrowing).
11
11
12
12
## Connection modes
13
13
@@ -41,18 +41,18 @@ The iMessage provider supports three connection modes — local, cloud, and dedi
41
41
</Note>
42
42
</Tab>
43
43
<Tab title="Dedicated">
44
-
Connect directly to one or more iMessage gRPC endpoints with your own tokens — use this when you're running your own iMessage relay and want to skip cloud auth:
44
+
Connect directly to one or more iMessage gRPC endpoints with your own tokens — use this when you're running your own iMessage relay and want to skip cloud auth. Each entry must include the `phone` number the instance serves, so Spectrum can route messages through the right number:
Multiple clients route messages based on the phone number associated with each space.
56
56
</Tab>
57
57
</Tabs>
58
58
@@ -66,6 +66,7 @@ Cloud mode routes your messages through phone numbers ("lines") provisioned by S
66
66
| **Business** | **Dedicated.** All of your end users text the same number, which belongs to your project. | A normal iMessage, always from the same number. |
67
67
68
68
End-user delivery is identical in both modes; the distinction is which number sends.
69
+
Cloud mode routes your messages through dedicated phone numbers ("lines") provisioned by Spectrum. Each project gets one or more dedicated lines, and all your end users text the same number(s).
69
70
70
71
### Auto-scale
71
72
@@ -77,12 +78,13 @@ When traffic to a dedicated line approaches its per-line capacity, Spectrum can
77
78
78
79
## Space types
79
80
80
-
iMessage spaces carry a `type` field — `"dm"` or `"group"` — accessible through narrowing:
81
+
iMessage spaces carry a `type` field — `"dm"` or `"group"` — and a `phone` field indicating which phone number the conversation is routed through. Both are accessible through narrowing:
81
82
82
83
```ts
83
84
for await (const [space, message] of app.messages) {
84
85
if (message.platform !== "iMessage") continue;
85
86
const im = imessage(space);
87
+
console.log(im.phone); // the phone number handling this conversation
86
88
if (im.type === "group") {
87
89
// group chat logic
88
90
}
@@ -109,6 +111,16 @@ await group.send("Welcome to the group.");
109
111
110
112
Space creation requires cloud or dedicated mode. In local mode `space()` throws — the local Messages database doesn't expose chat creation.
111
113
114
+
### Per-phone routing
115
+
116
+
If your account has multiple phone numbers, you can pin a conversation to a specific line by passing `phone` as a space parameter:
When omitted, Spectrum picks a phone at random from the available lines. All subsequent actions on that space — sending, typing, replies, edits, reactions, and lookups — route through the chosen number.
123
+
112
124
## Tapback constants
113
125
114
126
iMessage uses a fixed set of tapback reactions. The `imessage` object exposes them as constants:
0 commit comments