Reference
The SDK
@tabs-and-spaces/sdk has no dependencies and two entry points:
@tabs-and-spaces/sdk, for your page:connect().@tabs-and-spaces/sdk/server, for your server:verifyToken(),fetchKeys()and, for actions,dataClient().
connect()
function connect(options?: ConnectOptions): Promise<Connection>;Connects your page to the workspace showing it. It says hello, then resolves when the workspace answers with who's looking.
| Option | Default | What it does |
|---|---|---|
timeoutMs | 10000 | How long to wait for the workspace before rejecting |
window | window | The window your page runs in (for tests) |
It rejects with an Error when:
- the page isn't open in a workspace ("This page isn't open in a Tabs & Spaces workspace.");
- the workspace doesn't answer in time ("The workspace didn't answer.").
Connection
| Member | What it is |
|---|---|
context | Who's looking, and where: a TabContext |
theme | "light" or "dark", now |
token() | Promise<string>: the current token, or a fresh one when less than a minute is left. Calls made together share one request. It rejects if the workspace refuses, for example if your app was removed. |
values(scope) | Free-form values in a scope (workspace, space, tab or user): get(key), set(key, value), delete(key), list(). See Keeping data. |
collection(name) | A collection your manifest declares: list(options), get(id), create(data), update(id, data), delete(id). See Keeping data. |
data(request) | Any data request, as values() and collection() send it |
emit(name, data) | Promise<void>: reports an event your manifest declares, for the person looking, in this space. See Events. |
onTheme(listener) | Calls listener(theme) when the reader switches theme. Returns a function that stops it. |
close() | Stops listening. Pending token() calls reject. |
TabContext
interface TabContext {
user: { id: string; name: string };
workspace: { id: string; slug: string; name: string };
space: {
id: string;
kind: "general" | "personal" | "normal" | "dm";
name: string; // as the reader sees it, in their language
};
tab: { id: string; appTabId: string };
app: { id: string };
locale: string; // "en", "fr", …
}WorkspaceError
Data calls reject with a WorkspaceError when the workspace refuses. Its code says why:
| Code | When |
|---|---|
INVALID | The data doesn't fit the collection, or the request is malformed |
NOT_FOUND | No such collection or record, here |
FORBIDDEN | Only people in the space can change its data |
TOO_LARGE | A value over 16 KB, a record over 32 KB, or a request over 64 KB |
APP_DATA_FULL | Your app keeps 100 MB here already |
APP_NOT_INSTALLED | Your app was removed from the workspace |
verifyToken()
function verifyToken(
token: string,
options: { keys: PublicKey[]; audience: string; issuer?: string; now?: number },
): Promise<VerifiedToken>;Checks a token and returns who's looking:
| Option | What it is |
|---|---|
keys | The deployment's public keys, from fetchKeys() |
audience | Your app's origin, like https://crm.example.com |
issuer | The deployment's address. Pass it; see Decide which workspaces you serve. |
now | The time, in milliseconds (for tests) |
It resolves with { context: TabContext, issuer: string, expiresAt: Date, action: string | null }; action names the action an action's token is for. It throws a TokenError when the token:
- isn't a token;
- uses another algorithm;
- names a key it doesn't know;
- has a signature that doesn't match;
- is meant for another app;
- comes from another deployment;
- has expired.
fetchKeys()
function fetchKeys(deploymentUrl: string, fetcher?: typeof fetch): Promise<PublicKey[]>;Fetches a deployment's public keys from <deploymentUrl>/api/apps/keys. It throws a TokenError if they can't be fetched. Cache the result. See Keys.
dataClient()
function dataClient(
request: { dataKey: string; dataUrl: string },
fetcher?: typeof fetch,
): {
values(scope): Values;
collection(name): Collection;
data(request): Promise<unknown>;
emit(name: string, data?: Record<string, unknown>): Promise<void>;
};Your app's data from your server, with the key an action's request carries (pass the whole ActionRequest). The same values() and collection() as in your page, for the action's place and person, for five minutes. Refusals throw a DataError with a code. See Your data, from your server. emit() reports an event with the same key.
ActionRequest<Input> is the type of an action request's body: action, input, context, agent, dataKey and dataUrl.
Messages
The SDK also exports the frame protocol's types and readers (AppMessage, HostMessage, DataRequest, DataRecord, readAppMessage(), readHostMessage() and PROTOCOL_VERSION), for anyone speaking it directly. See The frame protocol.