@neta-art/cohub 1.0.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.
@@ -0,0 +1,373 @@
1
+ import { ensureRealtimeConnected } from "../realtime.js";
2
+ const DEFAULT_DEDUP_WINDOW_MS = 2000;
3
+ const toSessionEventName = (type) => {
4
+ switch (type) {
5
+ case "session.turn.progress":
6
+ return "turn.progress";
7
+ case "session.turn.final":
8
+ return "turn.final";
9
+ case "session.turn.error":
10
+ return "turn.error";
11
+ case "session.message.persisted":
12
+ return "message.persisted";
13
+ default:
14
+ return null;
15
+ }
16
+ };
17
+ export class SpacesApi {
18
+ transport;
19
+ constructor(transport) {
20
+ this.transport = transport;
21
+ }
22
+ list(customFetch) {
23
+ return this.transport.request("/api/spaces", {
24
+ method: "GET",
25
+ fetch: customFetch,
26
+ });
27
+ }
28
+ get(spaceId, customFetch) {
29
+ return this.transport.request(`/api/spaces/${spaceId}`, {
30
+ fetch: customFetch,
31
+ });
32
+ }
33
+ create(input, headers) {
34
+ return this.transport.request("/api/spaces", {
35
+ method: "POST",
36
+ headers: {
37
+ ...headers,
38
+ "Content-Type": "application/json",
39
+ },
40
+ body: JSON.stringify(input ?? {}),
41
+ });
42
+ }
43
+ }
44
+ export class SpaceFilesApi {
45
+ transport;
46
+ spaceId;
47
+ constructor(transport, spaceId) {
48
+ this.transport = transport;
49
+ this.spaceId = spaceId;
50
+ }
51
+ list(path = "", customFetch) {
52
+ const params = new URLSearchParams();
53
+ if (path)
54
+ params.set("path", path);
55
+ const query = params.toString();
56
+ return this.transport.request(`/api/spaces/${this.spaceId}/fs/tree${query ? `?${query}` : ""}`, { fetch: customFetch });
57
+ }
58
+ read(path, customFetch) {
59
+ const params = new URLSearchParams({ path });
60
+ return this.transport.request(`/api/spaces/${this.spaceId}/fs/file?${params.toString()}`, { fetch: customFetch });
61
+ }
62
+ getDownloadUrl(path) {
63
+ const params = new URLSearchParams({ path });
64
+ return `/api/spaces/${this.spaceId}/fs/download?${params.toString()}`;
65
+ }
66
+ write(input) {
67
+ return this.transport.request(`/api/spaces/${this.spaceId}/fs/file`, {
68
+ method: "PUT",
69
+ headers: { "Content-Type": "application/json" },
70
+ body: JSON.stringify(input),
71
+ });
72
+ }
73
+ createDir(path) {
74
+ return this.transport.request(`/api/spaces/${this.spaceId}/fs/dir`, {
75
+ method: "POST",
76
+ headers: { "Content-Type": "application/json" },
77
+ body: JSON.stringify({ path }),
78
+ });
79
+ }
80
+ delete(path, recursive = false) {
81
+ const params = new URLSearchParams({ path });
82
+ if (recursive)
83
+ params.set("recursive", "true");
84
+ return this.transport.request(`/api/spaces/${this.spaceId}/fs/node?${params.toString()}`, { method: "DELETE" });
85
+ }
86
+ move(input) {
87
+ return this.transport.request(`/api/spaces/${this.spaceId}/fs/move`, {
88
+ method: "POST",
89
+ headers: { "Content-Type": "application/json" },
90
+ body: JSON.stringify(input),
91
+ });
92
+ }
93
+ }
94
+ class SessionMessagesClient {
95
+ transport;
96
+ sessionId;
97
+ lastSentSignature = "";
98
+ lastSentSessionId = "";
99
+ lastSentAt = 0;
100
+ constructor(transport, sessionId) {
101
+ this.transport = transport;
102
+ this.sessionId = sessionId;
103
+ }
104
+ list(customFetch) {
105
+ return this.transport.request(`/api/sessions/${this.sessionId}/messages`, {
106
+ fetch: customFetch,
107
+ });
108
+ }
109
+ listPaginated(options, customFetch) {
110
+ const params = new URLSearchParams();
111
+ if (options?.cursor !== undefined)
112
+ params.set("cursor", String(options.cursor));
113
+ if (options?.limit !== undefined)
114
+ params.set("limit", String(options.limit));
115
+ if (options?.direction)
116
+ params.set("direction", options.direction);
117
+ const query = params.toString();
118
+ return this.transport.request(`/api/sessions/${this.sessionId}/messages${query ? `?${query}` : ""}`, {
119
+ fetch: customFetch,
120
+ });
121
+ }
122
+ async send(input) {
123
+ const signature = JSON.stringify({ sessionId: this.sessionId, input });
124
+ const now = Date.now();
125
+ if (this.sessionId === this.lastSentSessionId &&
126
+ signature === this.lastSentSignature &&
127
+ now - this.lastSentAt < DEFAULT_DEDUP_WINDOW_MS) {
128
+ throw new Error("Duplicate message ignored");
129
+ }
130
+ this.lastSentSessionId = this.sessionId;
131
+ this.lastSentSignature = signature;
132
+ this.lastSentAt = now;
133
+ return this.transport.request(`/api/sessions/${this.sessionId}/messages`, {
134
+ method: "POST",
135
+ headers: {
136
+ "Content-Type": "application/json",
137
+ },
138
+ body: JSON.stringify({
139
+ content: input.content,
140
+ model: input.model,
141
+ provider: input.provider,
142
+ clientMessageId: input.clientMessageId,
143
+ }),
144
+ });
145
+ }
146
+ }
147
+ class SessionRealtimeClient {
148
+ websocketClient;
149
+ spaceId;
150
+ sessionId;
151
+ constructor(websocketClient, spaceId, sessionId) {
152
+ this.websocketClient = websocketClient;
153
+ this.spaceId = spaceId;
154
+ this.sessionId = sessionId;
155
+ }
156
+ subscribe(handlers) {
157
+ if (!this.websocketClient) {
158
+ throw new Error("realtime transport is not configured for this client");
159
+ }
160
+ ensureRealtimeConnected(this.websocketClient);
161
+ const unsubscribe = this.websocketClient.on("event", (event) => {
162
+ if (event.spaceId !== this.spaceId || event.sessionId !== this.sessionId)
163
+ return;
164
+ handlers.event?.(event);
165
+ const eventName = toSessionEventName(event.type);
166
+ if (eventName === "turn.progress")
167
+ handlers.progress?.(event);
168
+ if (eventName === "turn.final")
169
+ handlers.final?.(event);
170
+ if (eventName === "turn.error")
171
+ handlers.error?.(event);
172
+ if (eventName === "message.persisted")
173
+ handlers.persisted?.(event);
174
+ });
175
+ return () => unsubscribe();
176
+ }
177
+ on(type, handler) {
178
+ return this.subscribe({
179
+ event: (event) => {
180
+ if (toSessionEventName(event.type) === type)
181
+ handler(event);
182
+ },
183
+ });
184
+ }
185
+ }
186
+ export class SessionClient {
187
+ spaceId;
188
+ id;
189
+ transport;
190
+ messages;
191
+ realtime;
192
+ constructor(spaceId, id, transport, websocketClient) {
193
+ this.spaceId = spaceId;
194
+ this.id = id;
195
+ this.transport = transport;
196
+ this.messages = new SessionMessagesClient(transport, id);
197
+ this.realtime = new SessionRealtimeClient(websocketClient, spaceId, id);
198
+ }
199
+ get(customFetch) {
200
+ return this.transport.request(`/api/sessions/${this.id}`, {
201
+ fetch: customFetch,
202
+ });
203
+ }
204
+ subscribe(handlers) {
205
+ return this.realtime.subscribe(handlers);
206
+ }
207
+ on(type, handler) {
208
+ return this.realtime.on(type, handler);
209
+ }
210
+ }
211
+ export class SpaceSessionsApi {
212
+ transport;
213
+ spaceId;
214
+ websocketClient;
215
+ constructor(transport, spaceId, websocketClient) {
216
+ this.transport = transport;
217
+ this.spaceId = spaceId;
218
+ this.websocketClient = websocketClient;
219
+ }
220
+ create(input) {
221
+ return this.transport.request(`/api/spaces/${this.spaceId}/sessions`, {
222
+ method: "POST",
223
+ headers: {
224
+ "Content-Type": "application/json",
225
+ },
226
+ body: JSON.stringify(input ?? {}),
227
+ });
228
+ }
229
+ list(customFetch) {
230
+ return this.transport.request(`/api/spaces/${this.spaceId}/sessions`, {
231
+ fetch: customFetch,
232
+ });
233
+ }
234
+ byId(sessionId) {
235
+ return new SessionClient(this.spaceId, sessionId, this.transport, this.websocketClient);
236
+ }
237
+ }
238
+ export class SpaceEventsApi {
239
+ websocketClient;
240
+ spaceId;
241
+ constructor(websocketClient, spaceId) {
242
+ this.websocketClient = websocketClient;
243
+ this.spaceId = spaceId;
244
+ }
245
+ subscribe(handler) {
246
+ if (!this.websocketClient) {
247
+ throw new Error("realtime transport is not configured for this client");
248
+ }
249
+ ensureRealtimeConnected(this.websocketClient);
250
+ return this.websocketClient.on("event", (event) => {
251
+ if (event.spaceId !== this.spaceId)
252
+ return;
253
+ handler(event);
254
+ });
255
+ }
256
+ on(type, handler) {
257
+ return this.subscribe((event) => {
258
+ if (type === "event") {
259
+ handler(event);
260
+ return;
261
+ }
262
+ if (toSessionEventName(event.type) === type)
263
+ handler(event);
264
+ });
265
+ }
266
+ }
267
+ export class SpaceMembersApi {
268
+ transport;
269
+ spaceId;
270
+ constructor(transport, spaceId) {
271
+ this.transport = transport;
272
+ this.spaceId = spaceId;
273
+ }
274
+ list() {
275
+ return this.transport.request(`/api/spaces/${this.spaceId}/members`);
276
+ }
277
+ update(userId, role) {
278
+ return this.transport.request(`/api/spaces/${this.spaceId}/members`, {
279
+ method: "PUT",
280
+ headers: { "Content-Type": "application/json" },
281
+ body: JSON.stringify({ userId, role }),
282
+ });
283
+ }
284
+ remove(userId) {
285
+ return this.transport.request(`/api/spaces/${this.spaceId}/members`, {
286
+ method: "DELETE",
287
+ headers: { "Content-Type": "application/json" },
288
+ body: JSON.stringify({ userId }),
289
+ });
290
+ }
291
+ }
292
+ export class SpaceAccessApi {
293
+ transport;
294
+ spaceId;
295
+ constructor(transport, spaceId) {
296
+ this.transport = transport;
297
+ this.spaceId = spaceId;
298
+ }
299
+ get() {
300
+ return this.transport.request(`/api/spaces/${this.spaceId}/access`);
301
+ }
302
+ set(body) {
303
+ return this.transport.request(`/api/spaces/${this.spaceId}/access`, {
304
+ method: "PUT",
305
+ headers: { "Content-Type": "application/json" },
306
+ body: JSON.stringify(body),
307
+ });
308
+ }
309
+ }
310
+ export class SpaceCheckpointsApi {
311
+ transport;
312
+ spaceId;
313
+ constructor(transport, spaceId) {
314
+ this.transport = transport;
315
+ this.spaceId = spaceId;
316
+ }
317
+ create(description) {
318
+ return this.transport.request(`/api/spaces/${this.spaceId}/checkpoints`, {
319
+ method: "POST",
320
+ headers: { "Content-Type": "application/json" },
321
+ body: JSON.stringify({ description: description ?? null }),
322
+ });
323
+ }
324
+ list() {
325
+ return this.transport.request(`/api/spaces/${this.spaceId}/checkpoints`);
326
+ }
327
+ get(checkpointId, customFetch) {
328
+ return this.transport.request(`/api/spaces/${this.spaceId}/checkpoints/${checkpointId}`, { fetch: customFetch });
329
+ }
330
+ }
331
+ export class SpaceClient {
332
+ id;
333
+ transport;
334
+ websocketClient;
335
+ files;
336
+ sessions;
337
+ members;
338
+ access;
339
+ checkpoints;
340
+ constructor(id, transport, websocketClient) {
341
+ this.id = id;
342
+ this.transport = transport;
343
+ this.websocketClient = websocketClient;
344
+ this.files = new SpaceFilesApi(transport, id);
345
+ this.sessions = new SpaceSessionsApi(transport, id, websocketClient);
346
+ this.members = new SpaceMembersApi(transport, id);
347
+ this.access = new SpaceAccessApi(transport, id);
348
+ this.checkpoints = new SpaceCheckpointsApi(transport, id);
349
+ }
350
+ get(customFetch) {
351
+ return this.transport.request(`/api/spaces/${this.id}`, {
352
+ fetch: customFetch,
353
+ });
354
+ }
355
+ rename(name) {
356
+ return this.transport.request(`/api/spaces/${this.id}`, {
357
+ method: "PATCH",
358
+ headers: {
359
+ "Content-Type": "application/json",
360
+ },
361
+ body: JSON.stringify({ name }),
362
+ });
363
+ }
364
+ session(sessionId) {
365
+ return new SessionClient(this.id, sessionId, this.transport, this.websocketClient);
366
+ }
367
+ subscribe(handler) {
368
+ return new SpaceEventsApi(this.websocketClient, this.id).subscribe(handler);
369
+ }
370
+ on(type, handler) {
371
+ return new SpaceEventsApi(this.websocketClient, this.id).on(type, handler);
372
+ }
373
+ }
@@ -0,0 +1,20 @@
1
+ import type { HttpTransport } from "../transport.js";
2
+ import type { CreateScheduledTaskInput, TaskRunRecord } from "../types.js";
3
+ export declare class TasksApi {
4
+ private readonly transport;
5
+ constructor(transport: HttpTransport);
6
+ get(taskRunId: string): Promise<{
7
+ run: TaskRunRecord;
8
+ }>;
9
+ list(filters?: {
10
+ cronJobId?: string;
11
+ spaceId?: string;
12
+ }): Promise<{
13
+ runs: TaskRunRecord[];
14
+ }>;
15
+ createScheduled(data: CreateScheduledTaskInput): Promise<{
16
+ ok: true;
17
+ taskRunId: string;
18
+ scheduledAt: string;
19
+ }>;
20
+ }
@@ -0,0 +1,25 @@
1
+ export class TasksApi {
2
+ transport;
3
+ constructor(transport) {
4
+ this.transport = transport;
5
+ }
6
+ get(taskRunId) {
7
+ return this.transport.request(`/api/tasks/${taskRunId}`);
8
+ }
9
+ list(filters) {
10
+ const params = new URLSearchParams();
11
+ if (filters?.cronJobId)
12
+ params.set("cronJobId", filters.cronJobId);
13
+ if (filters?.spaceId)
14
+ params.set("spaceId", filters.spaceId);
15
+ const query = params.toString();
16
+ return this.transport.request(`/api/tasks${query ? `?${query}` : ""}`);
17
+ }
18
+ createScheduled(data) {
19
+ return this.transport.request("/api/tasks", {
20
+ method: "POST",
21
+ headers: { "Content-Type": "application/json" },
22
+ body: JSON.stringify(data),
23
+ });
24
+ }
25
+ }
@@ -0,0 +1,20 @@
1
+ import { type HttpTransport, type Fetch } from "../transport.js";
2
+ import type { UserSshKey } from "../types.js";
3
+ export declare class UserApi {
4
+ private readonly transport;
5
+ private readonly transportBaseUrl;
6
+ private readonly setStoredAuthToken?;
7
+ private readonly clearStoredAuthToken?;
8
+ constructor(transport: HttpTransport, transportBaseUrl: string, setStoredAuthToken?: ((token: string) => void) | undefined, clearStoredAuthToken?: (() => void) | undefined);
9
+ getMe(customFetch?: Fetch): Promise<unknown>;
10
+ setAuthToken(token: string): Promise<any>;
11
+ clearAuthToken(): Promise<null>;
12
+ getSshKeys(customFetch?: Fetch): Promise<UserSshKey[]>;
13
+ createSshKey(data: {
14
+ key: string;
15
+ title: string;
16
+ }): Promise<UserSshKey>;
17
+ deleteSshKey(id: string): Promise<{
18
+ ok: true;
19
+ }>;
20
+ }
@@ -0,0 +1,58 @@
1
+ import { HttpError } from "../transport.js";
2
+ export class UserApi {
3
+ transport;
4
+ transportBaseUrl;
5
+ setStoredAuthToken;
6
+ clearStoredAuthToken;
7
+ constructor(transport, transportBaseUrl, setStoredAuthToken, clearStoredAuthToken) {
8
+ this.transport = transport;
9
+ this.transportBaseUrl = transportBaseUrl;
10
+ this.setStoredAuthToken = setStoredAuthToken;
11
+ this.clearStoredAuthToken = clearStoredAuthToken;
12
+ }
13
+ getMe(customFetch) {
14
+ return this.transport.request("/api/me", { fetch: customFetch });
15
+ }
16
+ async setAuthToken(token) {
17
+ const trimmedToken = token.trim();
18
+ const response = await fetch(this.transportBaseUrl ? `${this.transportBaseUrl}/api/me` : "/api/me", {
19
+ headers: {
20
+ Authorization: `Bearer ${trimmedToken}`,
21
+ },
22
+ });
23
+ if (!response.ok) {
24
+ const contentType = response.headers.get("content-type") ?? "";
25
+ const body = contentType.includes("application/json")
26
+ ? await response.json().catch(() => null)
27
+ : await response.text().catch(() => response.statusText);
28
+ const message = typeof body === "string" ? body : JSON.stringify(body ?? null);
29
+ throw new HttpError(message || response.statusText, response.status, body);
30
+ }
31
+ this.setStoredAuthToken?.(trimmedToken);
32
+ return response.json();
33
+ }
34
+ async clearAuthToken() {
35
+ this.clearStoredAuthToken?.();
36
+ return null;
37
+ }
38
+ getSshKeys(customFetch) {
39
+ return this.transport.request("/api/user/ssh-keys", {
40
+ method: "GET",
41
+ fetch: customFetch,
42
+ });
43
+ }
44
+ createSshKey(data) {
45
+ return this.transport.request("/api/user/ssh-keys", {
46
+ method: "POST",
47
+ headers: {
48
+ "Content-Type": "application/json",
49
+ },
50
+ body: JSON.stringify(data),
51
+ });
52
+ }
53
+ deleteSshKey(id) {
54
+ return this.transport.request(`/api/user/ssh-keys/${id}`, {
55
+ method: "DELETE",
56
+ });
57
+ }
58
+ }
@@ -0,0 +1,22 @@
1
+ import { ChannelsApi } from "./apis/channels.js";
2
+ import { CronJobsApi } from "./apis/cron-jobs.js";
3
+ import { ModelsApi } from "./apis/models.js";
4
+ import { SessionAccessApi } from "./apis/session-access.js";
5
+ import { SpaceClient, SpacesApi } from "./apis/spaces.js";
6
+ import { TasksApi } from "./apis/tasks.js";
7
+ import { UserApi } from "./apis/user.js";
8
+ import { type CohubClientOptions } from "./transport.js";
9
+ export declare class CohubClient {
10
+ readonly spaces: SpacesApi;
11
+ readonly channels: ChannelsApi;
12
+ readonly user: UserApi;
13
+ readonly models: ModelsApi;
14
+ readonly sessionAccess: SessionAccessApi;
15
+ readonly tasks: TasksApi;
16
+ readonly cronJobs: CronJobsApi;
17
+ private readonly transport;
18
+ private readonly websocketClient;
19
+ constructor(options?: CohubClientOptions);
20
+ space(spaceId: string): SpaceClient;
21
+ }
22
+ export declare const createCohubClient: (options?: CohubClientOptions) => CohubClient;
package/dist/client.js ADDED
@@ -0,0 +1,38 @@
1
+ import { ChannelsApi } from "./apis/channels.js";
2
+ import { CronJobsApi } from "./apis/cron-jobs.js";
3
+ import { ModelsApi } from "./apis/models.js";
4
+ import { SessionAccessApi } from "./apis/session-access.js";
5
+ import { SpaceClient, SpacesApi } from "./apis/spaces.js";
6
+ import { TasksApi } from "./apis/tasks.js";
7
+ import { UserApi } from "./apis/user.js";
8
+ import { HttpTransport } from "./transport.js";
9
+ import { createWebsocketClient } from "./websocket.js";
10
+ export class CohubClient {
11
+ spaces;
12
+ channels;
13
+ user;
14
+ models;
15
+ sessionAccess;
16
+ tasks;
17
+ cronJobs;
18
+ transport;
19
+ websocketClient;
20
+ constructor(options = {}) {
21
+ this.transport = new HttpTransport(options);
22
+ this.websocketClient = createWebsocketClient({
23
+ ...options.websocket,
24
+ getAccessToken: options.getAccessToken,
25
+ });
26
+ this.spaces = new SpacesApi(this.transport);
27
+ this.channels = new ChannelsApi(this.transport);
28
+ this.user = new UserApi(this.transport, options.baseUrl ?? "", options.setStoredAuthToken, options.clearStoredAuthToken);
29
+ this.models = new ModelsApi(options.fetch ?? fetch, options.baseUrl ?? "");
30
+ this.sessionAccess = new SessionAccessApi(this.transport);
31
+ this.tasks = new TasksApi(this.transport);
32
+ this.cronJobs = new CronJobsApi(this.transport);
33
+ }
34
+ space(spaceId) {
35
+ return new SpaceClient(spaceId, this.transport, this.websocketClient);
36
+ }
37
+ }
38
+ export const createCohubClient = (options) => new CohubClient(options);
package/dist/http.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import { ChannelsApi } from "./apis/channels.js";
2
+ import { CronJobsApi } from "./apis/cron-jobs.js";
3
+ import { ModelsApi } from "./apis/models.js";
4
+ import { SessionAccessApi } from "./apis/session-access.js";
5
+ import { SpaceClient, SpacesApi } from "./apis/spaces.js";
6
+ import { TasksApi } from "./apis/tasks.js";
7
+ import { UserApi } from "./apis/user.js";
8
+ import { HttpTransport, HttpError, type CohubClientOptions, type Fetch } from "./transport.js";
9
+ export declare class CohubHttpClient {
10
+ readonly spaces: SpacesApi;
11
+ readonly channels: ChannelsApi;
12
+ readonly user: UserApi;
13
+ readonly models: ModelsApi;
14
+ readonly sessionAccess: SessionAccessApi;
15
+ readonly tasks: TasksApi;
16
+ readonly cronJobs: CronJobsApi;
17
+ private readonly transport;
18
+ constructor(options?: CohubClientOptions);
19
+ space(spaceId: string): SpaceClient;
20
+ }
21
+ export declare const createHttpClient: (options?: CohubClientOptions) => CohubHttpClient;
22
+ export { HttpTransport, HttpError };
23
+ export type { CohubClientOptions, Fetch };
24
+ export * from "./types.js";
package/dist/http.js ADDED
@@ -0,0 +1,34 @@
1
+ import { ChannelsApi } from "./apis/channels.js";
2
+ import { CronJobsApi } from "./apis/cron-jobs.js";
3
+ import { ModelsApi } from "./apis/models.js";
4
+ import { SessionAccessApi } from "./apis/session-access.js";
5
+ import { SpaceClient, SpacesApi } from "./apis/spaces.js";
6
+ import { TasksApi } from "./apis/tasks.js";
7
+ import { UserApi } from "./apis/user.js";
8
+ import { HttpTransport, HttpError } from "./transport.js";
9
+ export class CohubHttpClient {
10
+ spaces;
11
+ channels;
12
+ user;
13
+ models;
14
+ sessionAccess;
15
+ tasks;
16
+ cronJobs;
17
+ transport;
18
+ constructor(options = {}) {
19
+ this.transport = new HttpTransport(options);
20
+ this.spaces = new SpacesApi(this.transport);
21
+ this.channels = new ChannelsApi(this.transport);
22
+ this.user = new UserApi(this.transport, options.baseUrl ?? "", options.setStoredAuthToken, options.clearStoredAuthToken);
23
+ this.models = new ModelsApi(options.fetch ?? fetch, options.baseUrl ?? "");
24
+ this.sessionAccess = new SessionAccessApi(this.transport);
25
+ this.tasks = new TasksApi(this.transport);
26
+ this.cronJobs = new CronJobsApi(this.transport);
27
+ }
28
+ space(spaceId) {
29
+ return new SpaceClient(spaceId, this.transport, null);
30
+ }
31
+ }
32
+ export const createHttpClient = (options) => new CohubHttpClient(options);
33
+ export { HttpTransport, HttpError };
34
+ export * from "./types.js";
@@ -0,0 +1,7 @@
1
+ export { CohubHttpClient, createHttpClient } from "./http.js";
2
+ export { CohubClient, createCohubClient } from "./client.js";
3
+ export { WebsocketClient, createWebsocketClient } from "./websocket.js";
4
+ export { HttpError } from "./transport.js";
5
+ export type { CohubClientOptions, Fetch } from "./transport.js";
6
+ export * from "./types.js";
7
+ export type { SessionEventName, SessionSubscriptionHandlers, SpaceEventName } from "./apis/spaces.js";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { CohubHttpClient, createHttpClient } from "./http.js";
2
+ export { CohubClient, createCohubClient } from "./client.js";
3
+ export { WebsocketClient, createWebsocketClient } from "./websocket.js";
4
+ export { HttpError } from "./transport.js";
5
+ export * from "./types.js";
@@ -0,0 +1,2 @@
1
+ import type { WebsocketClient } from "./websocket.js";
2
+ export declare function ensureRealtimeConnected(websocketClient: WebsocketClient): void;
@@ -0,0 +1,5 @@
1
+ export function ensureRealtimeConnected(websocketClient) {
2
+ void websocketClient.connect().catch((error) => {
3
+ console.error("[CohubClient] Failed to connect realtime websocket:", error);
4
+ });
5
+ }
@@ -0,0 +1,27 @@
1
+ import type { WebsocketClientOptions } from "./websocket.js";
2
+ export type Fetch = typeof globalThis.fetch;
3
+ export type CohubClientOptions = {
4
+ baseUrl?: string;
5
+ getAccessToken?: () => Promise<string | null> | string | null;
6
+ onUnauthorized?: () => Promise<void> | void;
7
+ setStoredAuthToken?: (token: string) => void;
8
+ clearStoredAuthToken?: () => void;
9
+ fetch?: Fetch;
10
+ websocket?: WebsocketClientOptions;
11
+ };
12
+ export declare class HttpError extends Error {
13
+ readonly status: number;
14
+ readonly body: unknown;
15
+ constructor(message: string, status: number, body: unknown);
16
+ }
17
+ export declare class HttpTransport {
18
+ private readonly baseUrl;
19
+ private readonly fetcher;
20
+ private readonly getAccessToken?;
21
+ private readonly onUnauthorized?;
22
+ constructor(options?: CohubClientOptions);
23
+ private withAuthorization;
24
+ request<T>(path: string, init?: RequestInit & {
25
+ fetch?: Fetch;
26
+ }): Promise<T>;
27
+ }