-
Notifications
You must be signed in to change notification settings - Fork 16.4k
Expand file tree
/
Copy pathclient.ts
More file actions
106 lines (85 loc) · 3.2 KB
/
Copy pathclient.ts
File metadata and controls
106 lines (85 loc) · 3.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import type { Session, Environment, ControlResponse, SessionEvent } from "../types";
const BASE = "";
function generateUuid(): string {
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
return crypto.randomUUID();
}
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) =>
(Number(c) ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (Number(c) / 4)))).toString(16),
);
}
export function getUuid(): string {
let uuid = localStorage.getItem("rcs_uuid");
if (!uuid) {
uuid = generateUuid();
localStorage.setItem("rcs_uuid", uuid);
}
return uuid;
}
export function setUuid(uuid: string): void {
localStorage.setItem("rcs_uuid", uuid);
}
/** Active API token for Authorization header (set by useTokens) */
let _activeToken: string | null = null;
export function setActiveApiToken(token: string | null): void {
_activeToken = token;
}
export function getActiveApiToken(): string | null {
return _activeToken;
}
async function api<T>(method: string, path: string, body?: unknown): Promise<T> {
const headers: Record<string, string> = { "Content-Type": "application/json" };
if (_activeToken) {
headers["Authorization"] = `Bearer ${_activeToken}`;
}
// When using Bearer token auth, backend derives UUID from the token — no need to send query param.
// Otherwise fall back to UUID auth via query param.
let url: string;
if (_activeToken) {
const sep = path.includes("?") ? "&" : "?";
url = `${BASE}${path}${sep}uuid=${encodeURIComponent(_activeToken)}`;
} else {
const uuid = getUuid();
const sep = path.includes("?") ? "&" : "?";
url = `${BASE}${path}${sep}uuid=${encodeURIComponent(uuid)}`;
}
const opts: RequestInit = { method, headers };
if (body !== undefined) opts.body = JSON.stringify(body);
const res = await fetch(url, opts);
const data = await res.json();
if (!res.ok) {
const err = data.error || { type: "unknown", message: res.statusText };
throw new Error(err.message || err.type);
}
return data as T;
}
export function apiBind(sessionId: string) {
return api<void>("POST", "/web/bind", { sessionId });
}
export function apiFetchSessions() {
return api<Session[]>("GET", "/web/sessions");
}
export function apiFetchAllSessions() {
return api<Session[]>("GET", "/web/sessions/all");
}
export function apiFetchSession(id: string) {
return api<Session>("GET", `/web/sessions/${id}`);
}
export function apiFetchSessionHistory(id: string) {
return api<{ events: SessionEvent[] }>("GET", `/web/sessions/${id}/history`);
}
export function apiFetchEnvironments() {
return api<Environment[]>("GET", "/web/environments");
}
export function apiSendEvent(sessionId: string, body: Record<string, unknown>) {
return api<void>("POST", `/web/sessions/${sessionId}/events`, body);
}
export function apiSendControl(sessionId: string, body: ControlResponse) {
return api<void>("POST", `/web/sessions/${sessionId}/control`, body);
}
export function apiInterrupt(sessionId: string) {
return api<void>("POST", `/web/sessions/${sessionId}/interrupt`);
}
export function apiCreateSession(body: { title?: string; environment_id?: string }) {
return api<Session>("POST", "/web/sessions", body);
}