Cross Platform
As a cross-platform chat protocol, Satori provides the ability to access any platform’s native interfaces. This means you can write generic code in most cases, and use native interfaces when needed to implement platform-specific functionality.
These native capabilities are collectively referred to as internal interfaces, covering APIs, events, message elements, routes, and more.
Platform vs Adapter
Most Satori APIs require the Satori-Platform and Satori-User-ID request headers, in order to distinguish the login account that initiates the request. Different platforms have different login.platform, while different accounts on the same platform have different login.user.id. With this mechanism, safe isolation is achieved.
For most chat platforms, the platform field is a fixed value set directly by SDKs. However, for platforms that can be self-hosted (e.g. Rocket Chat and Zulip), SDKs usually need the deployer to configure platform to differentiate between different servers. If mixed directly, this may cause issues such as data collisions.
Therefore, for any Login, there are actually two different concepts:
login.platform: chat platform. Usually, users within the same platform can message each other, while users across different platforms cannot. In Satori,platformalso acts as a namespace, so SDKs must ensure the uniqueness ofuser.id,guild.id, etc. within the sameplatform.login.adapter: adapter. This is more of an implementation concept: it determines how the platform is communicated with. Under the same adapter, there are usually the same extended APIs, events, and message elements. This field is typically set directly by SDKs, and developers can use it to determine whether the implementation supports certain features.
TIP
If you still find it hard to distinguish platform and adapter, remember:
- IDs are compatible within the same
platform; - APIs are compatible within the same
adapter.
These two conditions are sufficient but not necessary. In other words, even if two Logins have compatible IDs or APIs, they may still use different platform or adapter. This depends entirely on SDK implementation and community conventions.
TIP
Note that these two concepts are actually many-to-many. Some special scenarios:
- Single adapter, multiple platforms: a platform allows self-hosting. Two independent self-hosted servers have different data; all
user.id,guild.id, etc. belong to different namespaces, soplatformshould be different. But they use the same communication method, soadaptershould be the same. - Single platform, multiple adapters: a platform has both official and unofficial SDKs, and the two SDKs use different communication methods, so
adaptershould be different. But they both target the same platform; alluser.id,guild.id, etc. belong to the same namespace, soplatformshould be the same.
API Extensions
SDKs can proxy platform-native APIs via the route /{version}/internal/{method}.
For example, Discord provides a RESTful API, so you can make a request like:
DELETE /v1/internal/channels/111222333
Satori-Platform: discord
Satori-User-ID: 1234567890Except for the prefixed route and the additional Satori-Platform and Satori-User-ID headers, the request and response formats are identical to the platform’s native API.
Event Extensions
Platform-native Events
SDKs can proxy platform-native events through the _type and _data fields of the internal event. Its structure is:
| Field | Type | Description |
|---|---|---|
sn | number | Event sequence number |
type | string | Event type (fixed as internal) |
login | Login | Login info |
_type | string | Native event type |
_data | object | Native event payload |
Extension Fields on Standard Events
Platform-native fields for standard events can also be accessed via _type and _data. Its structure is:
| Field | Type | Description |
|---|---|---|
type | string | Event type (should not be internal) |
_type | string | Platform-generic name |
_data | object | Native event payload |
| other fields | Other standard event fields |
TIP
Some platform-native events can map directly to standard events. When such events are triggered, SDKs may emit both a standard event and a platform-native event. Both events include _type and _data, but their values may differ.
Message Element Extensions
Platform-native Message Elements
Platforms may provide native message elements, but they must be prefixed with the adapter name. For example:
<kook:card size="lg">
<kook:countdown end-time="1608819168000"/>
</kook:card>Extension Attributes on Standard Elements
Platform-native attributes for standard elements can also be declared by prefixing them with the adapter name. For example:
<!-- src is a standard attribute of the audio element. -->
<!-- cover is not standardized, so it needs a prefix. -->
<audio src="url1" kook:cover="url2"/>TIP
Whether attributes on platform-native message elements need a prefix is up to SDK implementation. If a message element is likely to be standardized in the future, adding a prefix can reduce migration cost. If standardization is not needed, omitting the prefix is more convenient to write.