@tabs-and-spaces/sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +14 -1
- package/dist/client.js +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/protocol.d.ts +24 -0
- package/dist/protocol.js +16 -0
- package/dist/server.d.ts +12 -1
- package/dist/server.js +20 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DataRecord, type DataRequest, type DataScope, type TabContext, type Theme } from "./protocol.js";
|
|
1
|
+
import { type DataRecord, type DataRequest, type DataScope, type EventKey, type TabContext, type Theme } from "./protocol.js";
|
|
2
2
|
/** A refusal from the workspace, with its reason's code (like `INVALID` or `FORBIDDEN`). */
|
|
3
3
|
export declare class WorkspaceError extends Error {
|
|
4
4
|
readonly code: string | null;
|
|
@@ -54,6 +54,19 @@ export interface Connection {
|
|
|
54
54
|
* (triggers in this space may start a task). Resolves once it's taken.
|
|
55
55
|
*/
|
|
56
56
|
emit(name: string, data?: Record<string, unknown>): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Asks for a key your server can report events with, in this tab, whenever they
|
|
59
|
+
* happen (a webhook from another service, say). The person sees what's asked and
|
|
60
|
+
* allows it (only those who manage the space's tabs can); a new key replaces this
|
|
61
|
+
* tab's last one. Fails with `DECLINED` if they don't, `FORBIDDEN` if they can't.
|
|
62
|
+
*/
|
|
63
|
+
requestEventKey(): Promise<EventKey>;
|
|
64
|
+
/**
|
|
65
|
+
* Opens a new trigger in this space, starting on one of your manifest's events in this
|
|
66
|
+
* tab (or the first, without `event`): the person sets the task and saves it. Fails
|
|
67
|
+
* with `NO_TASKS_TAB` when the space has no Tasks tab to keep triggers in.
|
|
68
|
+
*/
|
|
69
|
+
openTrigger(event?: string): Promise<void>;
|
|
57
70
|
/** Called when the reader switches between light and dark. Returns an unsubscribe. */
|
|
58
71
|
onTheme(listener: (theme: Theme) => void): () => void;
|
|
59
72
|
/** Stops listening. */
|
package/dist/client.js
CHANGED
|
@@ -124,6 +124,10 @@ export function connect({ timeoutMs = 10_000, window: win = window } = {}) {
|
|
|
124
124
|
async emit(name, fields = {}) {
|
|
125
125
|
await ask((id) => ({ tands: 1, type: "event", id, name, data: fields }));
|
|
126
126
|
},
|
|
127
|
+
requestEventKey: () => ask((id) => ({ tands: 1, type: "eventKey", id })),
|
|
128
|
+
async openTrigger(event) {
|
|
129
|
+
await ask((id) => ({ tands: 1, type: "openTrigger", id, event: event ?? null }));
|
|
130
|
+
},
|
|
127
131
|
values(scope) {
|
|
128
132
|
return {
|
|
129
133
|
get: async (key) => (await data({ op: "values.get", scope, key })).value,
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* server: `verifyToken()` from "@tabs-and-spaces/sdk/server".
|
|
4
4
|
*/
|
|
5
5
|
export { connect, WorkspaceError, type Collection, type Connection, type ConnectOptions, type Values, } from "./client.js";
|
|
6
|
-
export { PROTOCOL_VERSION, readAppMessage, readHostMessage, type AppMessage, type DataRecord, type DataRequest, type DataScope, type HostMessage, type TabContext, type Theme, } from "./protocol.js";
|
|
6
|
+
export { PROTOCOL_VERSION, readAppMessage, readHostMessage, type AppMessage, type DataRecord, type DataRequest, type DataScope, type EventKey, type HostMessage, type TabContext, type Theme, } from "./protocol.js";
|
package/dist/protocol.d.ts
CHANGED
|
@@ -120,7 +120,31 @@ export type AppMessage = {
|
|
|
120
120
|
id: string;
|
|
121
121
|
name: string;
|
|
122
122
|
data: Record<string, unknown>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* A key for the app's server to report events in this tab on its own (answered like
|
|
126
|
+
* data, with an `EventKey`), once the person allows it.
|
|
127
|
+
*/
|
|
128
|
+
| {
|
|
129
|
+
tands: 1;
|
|
130
|
+
type: "eventKey";
|
|
131
|
+
id: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Opens a new trigger in this space, starting on one of the app's events in this tab
|
|
135
|
+
* (decision 174). Answered like data once it's open.
|
|
136
|
+
*/
|
|
137
|
+
| {
|
|
138
|
+
tands: 1;
|
|
139
|
+
type: "openTrigger";
|
|
140
|
+
id: string;
|
|
141
|
+
event: string | null;
|
|
123
142
|
};
|
|
143
|
+
/** What the app's server reports events with, at `eventsUrl` (decision 170). */
|
|
144
|
+
export interface EventKey {
|
|
145
|
+
key: string;
|
|
146
|
+
eventsUrl: string;
|
|
147
|
+
}
|
|
124
148
|
/** From the workspace to the page. */
|
|
125
149
|
export type HostMessage = {
|
|
126
150
|
tands: 1;
|
package/dist/protocol.js
CHANGED
|
@@ -23,6 +23,22 @@ export function readAppMessage(data) {
|
|
|
23
23
|
// Checked in full by the workspace's server.
|
|
24
24
|
return { tands: 1, type: "data", id: data.id, request: data.request };
|
|
25
25
|
}
|
|
26
|
+
if (data.type === "eventKey" && typeof data.id === "string" && data.id.length <= 64) {
|
|
27
|
+
return { tands: 1, type: "eventKey", id: data.id };
|
|
28
|
+
}
|
|
29
|
+
if (data.type === "openTrigger" &&
|
|
30
|
+
typeof data.id === "string" &&
|
|
31
|
+
data.id.length <= 64 &&
|
|
32
|
+
(data.event === undefined ||
|
|
33
|
+
data.event === null ||
|
|
34
|
+
(typeof data.event === "string" && data.event.length <= 40))) {
|
|
35
|
+
return {
|
|
36
|
+
tands: 1,
|
|
37
|
+
type: "openTrigger",
|
|
38
|
+
id: data.id,
|
|
39
|
+
event: typeof data.event === "string" ? data.event : null,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
26
42
|
if (data.type === "event" &&
|
|
27
43
|
typeof data.id === "string" &&
|
|
28
44
|
data.id.length <= 64 &&
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DataRecord, DataRequest, DataScope, TabContext } from "./protocol.js";
|
|
1
|
+
import type { DataRecord, DataRequest, DataScope, EventKey, TabContext } from "./protocol.js";
|
|
2
2
|
/**
|
|
3
3
|
* Checking a Custom tab's token on your server (Node 22+, Deno, Bun, Workers:
|
|
4
4
|
* anywhere with Web Crypto's Ed25519). The workspace signs it (EdDSA); its
|
|
@@ -89,8 +89,19 @@ export declare function dataClient({ dataKey, dataUrl }: Pick<ActionRequest, "da
|
|
|
89
89
|
delete: (id: string) => Promise<void>;
|
|
90
90
|
};
|
|
91
91
|
};
|
|
92
|
+
/**
|
|
93
|
+
* Reports an event from your server at any time (decision 170), with the event key
|
|
94
|
+
* your tab got from `requestEventKey()`: in that tab's space, for the person who
|
|
95
|
+
* allowed it. Keep the key secret, like a password.
|
|
96
|
+
*
|
|
97
|
+
* ```ts
|
|
98
|
+
* await reportEvent(stored, "pull_request_opened", { title: "Fix login", number: 42 });
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare function reportEvent({ key, eventsUrl }: EventKey, name: string, fields?: Record<string, unknown>, fetcher?: typeof fetch): Promise<void>;
|
|
92
102
|
/** A refusal from the workspace's data endpoint, with its code. */
|
|
93
103
|
export declare class DataError extends Error {
|
|
94
104
|
readonly code: string | null;
|
|
95
105
|
constructor(message: string, code: string | null);
|
|
96
106
|
}
|
|
107
|
+
export type { EventKey } from "./protocol.js";
|
package/dist/server.js
CHANGED
|
@@ -122,6 +122,26 @@ export function dataClient({ dataKey, dataUrl }, fetcher = fetch) {
|
|
|
122
122
|
},
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Reports an event from your server at any time (decision 170), with the event key
|
|
127
|
+
* your tab got from `requestEventKey()`: in that tab's space, for the person who
|
|
128
|
+
* allowed it. Keep the key secret, like a password.
|
|
129
|
+
*
|
|
130
|
+
* ```ts
|
|
131
|
+
* await reportEvent(stored, "pull_request_opened", { title: "Fix login", number: 42 });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export async function reportEvent({ key, eventsUrl }, name, fields = {}, fetcher = fetch) {
|
|
135
|
+
const response = await fetcher(eventsUrl, {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${key}` },
|
|
138
|
+
body: JSON.stringify({ name, data: fields }),
|
|
139
|
+
});
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
const body = (await response.json().catch(() => null));
|
|
142
|
+
throw new DataError(body?.error?.message ?? `It answered ${response.status}.`, body?.error?.code ?? null);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
125
145
|
/** A refusal from the workspace's data endpoint, with its code. */
|
|
126
146
|
export class DataError extends Error {
|
|
127
147
|
code;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tabs-and-spaces/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Building apps for Tabs & Spaces: a Custom tab's page talks to the workspace, its server checks who's looking. No dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tabs & Spaces",
|