@excali-boards/boards-api-client 1.1.36 โ†’ 1.1.37

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/README.md CHANGED
@@ -1,59 +1,88 @@
1
1
  # ๐Ÿงฐ boards-api-client
2
2
 
3
- A comprehensive TypeScript client library for the [Boards Room API](https://github.com/Excali-Boards), featuring both REST API and WebSocket support. Build real-time collaborative applications with ease.
3
+ A TypeScript client library for interacting with the [Boards Room API](https://github.com/Excali-Boards), the backend behind the collaborative whiteboarding platform. This SDK simplifies API integration for developers building apps on top of Boards infrastructure.
4
4
 
5
5
  ---
6
6
 
7
- ## Features
7
+ ## ๐Ÿš€ Features
8
8
 
9
- - Fully typed REST client (boards, users, permissions, files, sessions, categories, flashcards, codesnippets, metrics, invites)
10
- - WebSocket client with auto-reconnect, heartbeat, and message queueing
11
- - React hooks: generic `useWebSocket` and `useExecutor` for code execution streams
12
- - Zero-config defaults; override `baseUrl` when needed
9
+ * Fully typed API wrapper for the Boards backend
10
+ * CRUD support for:
13
11
 
14
- ## Installation
12
+ * ๐Ÿข Groups and ๐Ÿ“‚ Categories
13
+ * ๐Ÿ“ Boards and ๐Ÿ–ผ๏ธ Rooms
14
+ * ๐Ÿ‘ค Users and ๐Ÿ” Permissions
15
+ * Real-time room metadata access and user management
16
+ * OAuth-based authentication support
17
+ * Utility endpoints for resolving board references and cleanup
18
+ * Built-in Axios request handler with date transformation
19
+
20
+ ---
21
+
22
+ ## ๐Ÿ“ฆ Installation
15
23
 
16
24
  ```bash
17
- pnpm add @excali-boards/boards-api-client
25
+ npm install boards-api-client
18
26
  # or
19
- npm install @excali-boards/boards-api-client
27
+ pnpm add boards-api-client
20
28
  ```
21
29
 
22
- ## Quick start
30
+ ---
23
31
 
24
- ### REST
32
+ ## โœจ Usage
33
+
34
+ ### Initialize the client
25
35
 
26
36
  ```ts
27
- import { BoardsManager } from "@excali-boards/boards-api-client";
37
+ import { BoardsManager } from 'boards-api-client';
28
38
 
29
- const api = new BoardsManager("https://api.example.com");
30
- const boards = await api.boards.list();
39
+ const client = new BoardsManager('https://your-api-url.com');
31
40
  ```
32
41
 
33
- ### WebSocket (generic)
42
+ ### Access a module
34
43
 
35
44
  ```ts
36
- import { createConnection } from "@excali-boards/boards-api-client";
45
+ const authToken = 'Bearer YOUR_TOKEN_HERE';
37
46
 
38
- const ws = createConnection("/executor", { baseUrl: "localhost:3000" });
39
- await ws.connect();
40
- ws.send(1, { code: "print(42)", language: "python" });
41
- ws.on(3, (data) => console.log("output:", data.output));
47
+ const groups = await client.groups.getGroups({ auth: authToken });
48
+ console.log(groups);
42
49
  ```
43
50
 
44
- ### React hook (executor)
51
+ ### Common endpoints
52
+
53
+ * `client.auth.authenticate(...)` โ€” Login a user
54
+ * `client.groups.getAllSorted(...)` โ€” Fetch full hierarchy
55
+ * `client.boards.getBoard(...)` โ€” Fetch single board info
56
+ * `client.admin.updateUserPermissions(...)` โ€” Update admin permissions
57
+ * `client.stats.globalStats(...)` โ€” Fetch global app statistics
58
+ * `client.utils.resolveBoard(...)` โ€” Resolve board ID by name
59
+
60
+ ---
45
61
 
46
- ```tsx
47
- import { useExecutor } from "@excali-boards/boards-api-client";
62
+ ## ๐Ÿงช Example
48
63
 
49
- const { isConnected, startSession, sendInput, outputs } = useExecutor();
64
+ ```ts
65
+ const data = await client.boards.getBoard({
66
+ auth: token,
67
+ groupId: 'grp123',
68
+ categoryId: 'cat456',
69
+ boardId: 'brd789'
70
+ });
71
+
72
+ console.log(data.board.name);
50
73
  ```
51
74
 
52
- ## Integrations
75
+ ---
76
+
77
+ ## ๐Ÿ› ๏ธ Development
53
78
 
54
- - React/Next: `useWebSocket`, `useExecutor`
55
- - Node/SSR: `createConnection` without React
56
- - TypeScript-first: message payloads and REST responses are typed
79
+ Clone the repo and install dependencies:
80
+
81
+ ```bash
82
+ git clone https://github.com/Excali-Boards/boards-api-client.git
83
+ cd boards-api-client
84
+ pnpm install
85
+ ```
57
86
 
58
87
  ---
59
88
 
@@ -65,7 +65,6 @@ export type GetBoardOutput = {
65
65
  type: BoardType;
66
66
  dataUrl: string;
67
67
  hasFlashcards: boolean;
68
- hasCodeSnippets: boolean;
69
68
  totalSizeBytes: number;
70
69
  accessLevel: AccessLevel;
71
70
  scheduledForDeletion: Date | null;
@@ -68,7 +68,6 @@ export type GetAllSortedOutput = (SingleOutput & {
68
68
  categories: (SingleOutput & {
69
69
  boards: (SingleOutput & {
70
70
  hasFlashcards: boolean;
71
- hasCodeSnippets: boolean;
72
71
  totalSizeBytes: number;
73
72
  scheduledForDeletion: Date | null;
74
73
  })[];
@@ -1,5 +1,4 @@
1
1
  import { PaginatedWebResponse, RequestMethod, WebResponse } from '../types';
2
- import { APICodeSnippets } from '../classes/codesnippets';
3
2
  import { AxiosResponse } from 'axios';
4
3
  import { APIPermissions } from '../classes/permissions';
5
4
  import { APIFlashcards } from '../classes/flashcards';
@@ -16,7 +15,6 @@ import { APIFiles } from '../classes/files';
16
15
  import { APIAdmin } from '../classes/admin';
17
16
  export declare class BoardsManager {
18
17
  url: string;
19
- readonly codeSnippets: APICodeSnippets;
20
18
  readonly permissions: APIPermissions;
21
19
  readonly categories: APICategories;
22
20
  readonly flashcards: APIFlashcards;
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.BoardsManager = void 0;
7
- const codesnippets_1 = require("../classes/codesnippets");
8
7
  const axios_1 = __importDefault(require("axios"));
9
8
  const permissions_1 = require("../classes/permissions");
10
9
  const flashcards_1 = require("../classes/flashcards");
@@ -22,7 +21,6 @@ const admin_1 = require("../classes/admin");
22
21
  const utils_2 = require("./utils");
23
22
  class BoardsManager {
24
23
  url;
25
- codeSnippets = new codesnippets_1.APICodeSnippets(this);
26
24
  permissions = new permissions_1.APIPermissions(this);
27
25
  categories = new categories_1.APICategories(this);
28
26
  flashcards = new flashcards_1.APIFlashcards(this);
package/dist/index.d.ts CHANGED
@@ -2,10 +2,6 @@ export * from './core/manager';
2
2
  export * from './types';
3
3
  export * from './external/types';
4
4
  export * from './external/vars';
5
- export * from './websocket/manager';
6
- export * from './websocket/client';
7
- export * from './websocket/types';
8
- export * from './classes/codesnippets';
9
5
  export * from './classes/permissions';
10
6
  export * from './classes/categories';
11
7
  export * from './classes/flashcards';
package/dist/index.js CHANGED
@@ -18,10 +18,6 @@ __exportStar(require("./core/manager"), exports);
18
18
  __exportStar(require("./types"), exports);
19
19
  __exportStar(require("./external/types"), exports);
20
20
  __exportStar(require("./external/vars"), exports);
21
- __exportStar(require("./websocket/manager"), exports);
22
- __exportStar(require("./websocket/client"), exports);
23
- __exportStar(require("./websocket/types"), exports);
24
- __exportStar(require("./classes/codesnippets"), exports);
25
21
  __exportStar(require("./classes/permissions"), exports);
26
22
  __exportStar(require("./classes/categories"), exports);
27
23
  __exportStar(require("./classes/flashcards"), exports);
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/types.ts","../src/classes/admin.ts","../src/classes/boards.ts","../src/classes/calendar.ts","../src/classes/categories.ts","../src/classes/codesnippets.ts","../src/classes/files.ts","../src/classes/flashcards.ts","../src/classes/groups.ts","../src/classes/invites.ts","../src/classes/metrics.ts","../src/classes/permissions.ts","../src/classes/sessions.ts","../src/classes/users.ts","../src/classes/utils.ts","../src/core/manager.ts","../src/core/utils.ts","../src/external/types.ts","../src/external/vars.ts","../src/websocket/client.ts","../src/websocket/manager.ts","../src/websocket/types.ts","../src/websocket/hooks/useExecutor.ts","../src/websocket/hooks/useWebSocket.ts"],"version":"5.9.2"}
1
+ {"root":["../src/index.ts","../src/types.ts","../src/classes/admin.ts","../src/classes/boards.ts","../src/classes/calendar.ts","../src/classes/categories.ts","../src/classes/files.ts","../src/classes/flashcards.ts","../src/classes/groups.ts","../src/classes/invites.ts","../src/classes/metrics.ts","../src/classes/permissions.ts","../src/classes/sessions.ts","../src/classes/users.ts","../src/classes/utils.ts","../src/core/manager.ts","../src/core/utils.ts","../src/external/types.ts","../src/external/vars.ts"],"version":"5.9.2"}
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.36",
2
+ "version": "1.1.37",
3
3
  "name": "@excali-boards/boards-api-client",
4
4
  "description": "A simple API client for the Boards API.",
5
5
  "repository": "https://github.com/Excali-Boards/boards-api-client",
@@ -32,7 +32,6 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "20.14.13",
35
- "@types/react": "^19.2.8",
36
35
  "@typescript-eslint/eslint-plugin": "6.18.0",
37
36
  "@typescript-eslint/parser": "6.18.0",
38
37
  "eslint": "8.56.0",
@@ -45,11 +44,7 @@
45
44
  "@prisma/client": "6.16.2",
46
45
  "axios": "1.12.2",
47
46
  "prisma": "6.16.2",
48
- "react": "^18.2.0",
49
47
  "ts-prisma": "1.3.3",
50
48
  "zod": "4.1.9"
51
- },
52
- "peerDependencies": {
53
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
54
49
  }
55
50
  }
@@ -43,8 +43,7 @@ model Board {
43
43
  categoryId String
44
44
  category Category @relation(fields: [categoryId], references: [categoryId], onDelete: Cascade)
45
45
 
46
- flashcardDeck FlashcardDeck?
47
- codeSnippetCollection CodeSnippetCollection?
46
+ flashcardDeck FlashcardDeck?
48
47
 
49
48
  files File[]
50
49
  boardPermission BoardPermission[]
@@ -1,93 +0,0 @@
1
- import { AccessLevel } from '../external/types';
2
- import { BoardsManager } from '../core/manager';
3
- export declare class APICodeSnippets {
4
- private web;
5
- constructor(web: BoardsManager);
6
- getCollection({ auth, groupId, categoryId, boardId }: CodeSnippetsFunctionsInput['getCollection']): Promise<import("..").WebResponse<CodeSnippetCollectionResponse>>;
7
- initializeCollection({ auth, groupId, categoryId, boardId }: CodeSnippetsFunctionsInput['initializeCollection']): Promise<import("..").WebResponse<string>>;
8
- destroyCollection({ auth, groupId, categoryId, boardId }: CodeSnippetsFunctionsInput['destroyCollection']): Promise<import("..").WebResponse<string>>;
9
- createSnippets({ auth, groupId, categoryId, boardId, body }: CodeSnippetsFunctionsInput['createSnippets']): Promise<import("..").WebResponse<string>>;
10
- updateSnippets({ auth, groupId, categoryId, boardId, body }: CodeSnippetsFunctionsInput['updateSnippets']): Promise<import("..").WebResponse<string>>;
11
- deleteSnippets({ auth, groupId, categoryId, boardId, body }: CodeSnippetsFunctionsInput['deleteSnippets']): Promise<import("..").WebResponse<string>>;
12
- reorderSnippets({ auth, groupId, categoryId, boardId, body }: CodeSnippetsFunctionsInput['reorderSnippets']): Promise<import("..").WebResponse<string>>;
13
- }
14
- export type CodeSnippetsFunctionsInput = {
15
- getCollection: {
16
- auth: string;
17
- groupId: string;
18
- categoryId: string;
19
- boardId: string;
20
- };
21
- initializeCollection: {
22
- auth: string;
23
- groupId: string;
24
- categoryId: string;
25
- boardId: string;
26
- };
27
- destroyCollection: {
28
- auth: string;
29
- groupId: string;
30
- categoryId: string;
31
- boardId: string;
32
- };
33
- createSnippets: {
34
- auth: string;
35
- groupId: string;
36
- categoryId: string;
37
- boardId: string;
38
- body: CodeSnippetInput[];
39
- };
40
- updateSnippets: {
41
- auth: string;
42
- groupId: string;
43
- categoryId: string;
44
- boardId: string;
45
- body: CodeSnippetUpdateInput[];
46
- };
47
- deleteSnippets: {
48
- auth: string;
49
- groupId: string;
50
- categoryId: string;
51
- boardId: string;
52
- body: string[];
53
- };
54
- reorderSnippets: {
55
- auth: string;
56
- groupId: string;
57
- categoryId: string;
58
- boardId: string;
59
- body: string[];
60
- };
61
- };
62
- export type CodeSnippetInput = {
63
- title: string;
64
- description?: string;
65
- code: string;
66
- language?: string;
67
- };
68
- export type CodeSnippetUpdateInput = CodeSnippetInput & {
69
- id: string;
70
- };
71
- export type CodeSnippetCollectionResponse = {
72
- board: {
73
- id: string;
74
- name: string;
75
- accessLevel: AccessLevel;
76
- };
77
- collection: {
78
- id: string;
79
- createdAt: Date;
80
- updatedAt: Date;
81
- };
82
- snippets: CodeSnippet[];
83
- };
84
- export type CodeSnippet = {
85
- id: string;
86
- title: string;
87
- description: string;
88
- code: string;
89
- language: string;
90
- index: number;
91
- createdAt: Date;
92
- updatedAt: Date;
93
- };
@@ -1,54 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.APICodeSnippets = void 0;
4
- // Data.
5
- class APICodeSnippets {
6
- web;
7
- constructor(web) {
8
- this.web = web;
9
- }
10
- // Methods.
11
- async getCollection({ auth, groupId, categoryId, boardId }) {
12
- return await this.web.request({
13
- method: 'GET', auth,
14
- endpoint: this.web.qp(`/groups/${groupId}/categories/${categoryId}/boards/${boardId}/codesnippets`),
15
- });
16
- }
17
- async initializeCollection({ auth, groupId, categoryId, boardId }) {
18
- return await this.web.request({
19
- method: 'POST', auth,
20
- endpoint: this.web.qp(`/groups/${groupId}/categories/${categoryId}/boards/${boardId}/codesnippets/initialize`),
21
- });
22
- }
23
- async destroyCollection({ auth, groupId, categoryId, boardId }) {
24
- return await this.web.request({
25
- method: 'POST', auth,
26
- endpoint: this.web.qp(`/groups/${groupId}/categories/${categoryId}/boards/${boardId}/codesnippets/destroy`),
27
- });
28
- }
29
- async createSnippets({ auth, groupId, categoryId, boardId, body }) {
30
- return await this.web.request({
31
- method: 'POST', auth, body,
32
- endpoint: this.web.qp(`/groups/${groupId}/categories/${categoryId}/boards/${boardId}/codesnippets`),
33
- });
34
- }
35
- async updateSnippets({ auth, groupId, categoryId, boardId, body }) {
36
- return await this.web.request({
37
- method: 'PATCH', auth, body,
38
- endpoint: this.web.qp(`/groups/${groupId}/categories/${categoryId}/boards/${boardId}/codesnippets`),
39
- });
40
- }
41
- async deleteSnippets({ auth, groupId, categoryId, boardId, body }) {
42
- return await this.web.request({
43
- method: 'DELETE', auth, body,
44
- endpoint: this.web.qp(`/groups/${groupId}/categories/${categoryId}/boards/${boardId}/codesnippets`),
45
- });
46
- }
47
- async reorderSnippets({ auth, groupId, categoryId, boardId, body }) {
48
- return await this.web.request({
49
- method: 'POST', auth, body,
50
- endpoint: this.web.qp(`/groups/${groupId}/categories/${categoryId}/boards/${boardId}/codesnippets/reorder`),
51
- });
52
- }
53
- }
54
- exports.APICodeSnippets = APICodeSnippets;
@@ -1,33 +0,0 @@
1
- import { WebSocketMessage, WSConnectionState, ExtractOpCode, ExtractDataForOp } from './types.js';
2
- export type HandlerFunction = (data: unknown) => void;
3
- export declare class WSClient<TMessage extends WebSocketMessage = WebSocketMessage> {
4
- private state;
5
- private ws;
6
- private reconnectAttempts;
7
- private reconnectTimer;
8
- private heartbeatTimer;
9
- private handlers;
10
- private messageQueue;
11
- private url;
12
- private onConnect?;
13
- private onDisconnect?;
14
- private onError?;
15
- constructor(url: string, options?: {
16
- onConnect?: () => void;
17
- onDisconnect?: (code?: number, reason?: string) => void;
18
- onError?: (error: string) => void;
19
- });
20
- connect(): Promise<void>;
21
- disconnect(): void;
22
- send<TOp extends ExtractOpCode<TMessage>>(op: TOp, data: ExtractDataForOp<TMessage, TOp>): boolean;
23
- private sendInternal;
24
- on<TOp extends ExtractOpCode<TMessage>>(op: TOp, handler: (data: ExtractDataForOp<TMessage, TOp>) => void): void;
25
- off(op: number): void;
26
- getState(): WSConnectionState;
27
- private handleMessage;
28
- private startHeartbeat;
29
- private stopHeartbeat;
30
- private shouldReconnect;
31
- private scheduleReconnect;
32
- private flushMessageQueue;
33
- }
@@ -1,171 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WSClient = void 0;
4
- const types_js_1 = require("./types.js");
5
- class WSClient {
6
- state = types_js_1.WSConnectionState.Disconnected;
7
- ws = null;
8
- reconnectAttempts = 0;
9
- reconnectTimer = null;
10
- heartbeatTimer = null;
11
- handlers = new Map();
12
- messageQueue = [];
13
- url;
14
- onConnect;
15
- onDisconnect;
16
- onError;
17
- constructor(url, options = {}) {
18
- this.url = url;
19
- this.onConnect = options.onConnect;
20
- this.onDisconnect = options.onDisconnect;
21
- this.onError = options.onError;
22
- }
23
- async connect() {
24
- if (this.state === types_js_1.WSConnectionState.Connecting || this.state === types_js_1.WSConnectionState.Connected) {
25
- return;
26
- }
27
- this.state = types_js_1.WSConnectionState.Connecting;
28
- return new Promise((resolve, reject) => {
29
- try {
30
- this.ws = new WebSocket(this.url);
31
- this.ws.onopen = () => {
32
- this.state = types_js_1.WSConnectionState.Connected;
33
- this.reconnectAttempts = 0;
34
- this.startHeartbeat();
35
- this.flushMessageQueue();
36
- this.onConnect?.();
37
- resolve();
38
- };
39
- this.ws.onmessage = (event) => {
40
- try {
41
- const message = JSON.parse(event.data);
42
- this.handleMessage(message);
43
- }
44
- catch (error) {
45
- console.error('Failed to parse WebSocket message:', error);
46
- }
47
- };
48
- this.ws.onclose = (event) => {
49
- this.state = types_js_1.WSConnectionState.Disconnected;
50
- this.stopHeartbeat();
51
- this.onDisconnect?.(event.code, event.reason);
52
- if (this.shouldReconnect(event.code)) {
53
- this.scheduleReconnect();
54
- }
55
- };
56
- this.ws.onerror = () => {
57
- this.state = types_js_1.WSConnectionState.Error;
58
- this.onError?.('WebSocket connection error');
59
- reject(new Error('WebSocket connection failed'));
60
- };
61
- }
62
- catch (error) {
63
- this.state = types_js_1.WSConnectionState.Error;
64
- reject(error);
65
- }
66
- });
67
- }
68
- disconnect() {
69
- this.state = types_js_1.WSConnectionState.Disconnected;
70
- if (this.reconnectTimer) {
71
- clearTimeout(this.reconnectTimer);
72
- this.reconnectTimer = null;
73
- }
74
- this.stopHeartbeat();
75
- if (this.ws) {
76
- this.ws.close(1000, 'Client disconnect');
77
- this.ws = null;
78
- }
79
- this.messageQueue = [];
80
- this.handlers.clear();
81
- }
82
- send(op, data) {
83
- return this.sendInternal(op, data);
84
- }
85
- sendInternal(op, data) {
86
- const message = { op, data };
87
- if (this.state !== types_js_1.WSConnectionState.Connected || !this.ws) {
88
- if (this.state === types_js_1.WSConnectionState.Connecting) {
89
- this.messageQueue.push(message);
90
- return true;
91
- }
92
- return false;
93
- }
94
- try {
95
- this.ws.send(JSON.stringify(message));
96
- return true;
97
- }
98
- catch (error) {
99
- console.error('Failed to send WebSocket message:', error);
100
- return false;
101
- }
102
- }
103
- on(op, handler) {
104
- this.handlers.set(op, handler);
105
- }
106
- off(op) {
107
- this.handlers.delete(op);
108
- }
109
- getState() {
110
- return this.state;
111
- }
112
- handleMessage(message) {
113
- if (message.op === types_js_1.SpecialOPCodes.Ping) {
114
- this.sendInternal(types_js_1.SpecialOPCodes.Pong);
115
- return;
116
- }
117
- if (message.op === types_js_1.SpecialOPCodes.Pong) {
118
- return;
119
- }
120
- const handler = this.handlers.get(message.op);
121
- if (handler) {
122
- try {
123
- handler(message.data);
124
- }
125
- catch (error) {
126
- console.error('Error in message handler:', error);
127
- }
128
- }
129
- }
130
- startHeartbeat() {
131
- this.heartbeatTimer = setInterval(() => {
132
- if (this.state === types_js_1.WSConnectionState.Connected) {
133
- this.sendInternal(types_js_1.SpecialOPCodes.Ping);
134
- }
135
- }, 30000);
136
- }
137
- stopHeartbeat() {
138
- if (this.heartbeatTimer) {
139
- clearInterval(this.heartbeatTimer);
140
- this.heartbeatTimer = null;
141
- }
142
- }
143
- shouldReconnect(code) {
144
- if (code === 1000 || this.reconnectAttempts >= 5)
145
- return false;
146
- return true;
147
- }
148
- scheduleReconnect() {
149
- if (this.reconnectTimer)
150
- return;
151
- this.state = types_js_1.WSConnectionState.Reconnecting;
152
- this.reconnectAttempts++;
153
- const delay = 1000 * Math.pow(2, Math.min(this.reconnectAttempts - 1, 4));
154
- this.reconnectTimer = setTimeout(async () => {
155
- this.reconnectTimer = null;
156
- try {
157
- await this.connect();
158
- }
159
- catch (error) {
160
- console.error('Reconnection failed:', error);
161
- }
162
- }, delay);
163
- }
164
- flushMessageQueue() {
165
- while (this.messageQueue.length > 0 && this.state === types_js_1.WSConnectionState.Connected) {
166
- const message = this.messageQueue.shift();
167
- this.sendInternal(message.op, message.data);
168
- }
169
- }
170
- }
171
- exports.WSClient = WSClient;
@@ -1,58 +0,0 @@
1
- export type UseExecutorOptions = {
2
- autoConnect?: boolean;
3
- baseUrl?: string;
4
- onOutput?: (output: string, type: 'stdout' | 'stderr') => void;
5
- onSessionComplete?: (exitCode: number) => void;
6
- onError?: (error: string) => void;
7
- };
8
- export declare function useExecutor(options?: UseExecutorOptions): {
9
- connectionState: import("../types").WSConnectionState;
10
- error: string | null;
11
- isConnected: boolean;
12
- connect: () => Promise<import("../client").WSClient<ExecutorWSMessageUnion>>;
13
- disconnect: () => void;
14
- startSession: (code: string, language: string) => Promise<boolean>;
15
- sendInput: (input: string) => boolean;
16
- stopSession: () => boolean;
17
- sessionId: string | null;
18
- outputs: {
19
- output: string;
20
- type: "stdout" | "stderr";
21
- timestamp: number;
22
- }[];
23
- isSessionActive: boolean;
24
- };
25
- export declare enum ExecutorWSOpCodes {
26
- StartCodeSession = 1,
27
- CodeSessionCreated = 2,
28
- CodeOutput = 3,
29
- CodeSessionError = 5,
30
- CodeSessionCompleted = 6,
31
- SendCodeInput = 7,
32
- StopCodeSession = 8
33
- }
34
- export type ExecutorWSMessage<T extends ExecutorWSOpCodes> = {
35
- op: T;
36
- data: T extends ExecutorWSOpCodes.StartCodeSession ? {
37
- code: string;
38
- language: string;
39
- } : T extends ExecutorWSOpCodes.CodeSessionCreated ? {
40
- sessionId: string;
41
- } : T extends ExecutorWSOpCodes.CodeOutput ? {
42
- sessionId: string;
43
- output: string;
44
- type: 'stdout' | 'stderr';
45
- } : T extends ExecutorWSOpCodes.CodeSessionError ? {
46
- sessionId: string | null;
47
- error: string;
48
- } : T extends ExecutorWSOpCodes.CodeSessionCompleted ? {
49
- sessionId: string;
50
- exitCode: number;
51
- } : T extends ExecutorWSOpCodes.SendCodeInput ? {
52
- sessionId: string;
53
- input: string;
54
- } : T extends ExecutorWSOpCodes.StopCodeSession ? {
55
- sessionId: string;
56
- } : never;
57
- };
58
- export type ExecutorWSMessageUnion = ExecutorWSMessage<ExecutorWSOpCodes.StartCodeSession> | ExecutorWSMessage<ExecutorWSOpCodes.CodeSessionCreated> | ExecutorWSMessage<ExecutorWSOpCodes.CodeOutput> | ExecutorWSMessage<ExecutorWSOpCodes.CodeSessionError> | ExecutorWSMessage<ExecutorWSOpCodes.CodeSessionCompleted> | ExecutorWSMessage<ExecutorWSOpCodes.SendCodeInput> | ExecutorWSMessage<ExecutorWSOpCodes.StopCodeSession>;
@@ -1,78 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ExecutorWSOpCodes = void 0;
4
- exports.useExecutor = useExecutor;
5
- const react_1 = require("react");
6
- const useWebSocket_1 = require("./useWebSocket");
7
- function useExecutor(options = {}) {
8
- const [sessionId, setSessionId] = (0, react_1.useState)(null);
9
- const [outputs, setOutputs] = (0, react_1.useState)([]);
10
- const { connectionState, error, isConnected, connect, disconnect, send, on, } = (0, useWebSocket_1.useWebSocket)('/executor', {
11
- autoConnect: options.autoConnect,
12
- baseUrl: options.baseUrl,
13
- onError: options.onError,
14
- });
15
- (0, react_1.useEffect)(() => {
16
- if (!isConnected)
17
- return;
18
- on(ExecutorWSOpCodes.CodeSessionCreated, (data) => {
19
- setSessionId(data.sessionId);
20
- });
21
- on(ExecutorWSOpCodes.CodeOutput, (data) => {
22
- const outputEntry = {
23
- output: data.output,
24
- type: data.type,
25
- timestamp: Date.now(),
26
- };
27
- setOutputs((prev) => [...prev, outputEntry]);
28
- options.onOutput?.(data.output, data.type);
29
- });
30
- on(ExecutorWSOpCodes.CodeSessionCompleted, (data) => {
31
- setSessionId(null);
32
- options.onSessionComplete?.(data.exitCode);
33
- });
34
- on(ExecutorWSOpCodes.CodeSessionError, (data) => {
35
- options.onError?.(data.error);
36
- });
37
- }, [isConnected, on, options]);
38
- const startSession = (0, react_1.useCallback)(async (code, language) => {
39
- if (!isConnected)
40
- await connect();
41
- setOutputs([]);
42
- return send(ExecutorWSOpCodes.StartCodeSession, { code, language });
43
- }, [isConnected, connect, send]);
44
- const sendInput = (0, react_1.useCallback)((input) => {
45
- if (!sessionId)
46
- return false;
47
- return send(ExecutorWSOpCodes.SendCodeInput, { sessionId, input });
48
- }, [sessionId, send]);
49
- const stopSession = (0, react_1.useCallback)(() => {
50
- if (!sessionId)
51
- return false;
52
- return send(ExecutorWSOpCodes.StopCodeSession, { sessionId });
53
- }, [sessionId, send]);
54
- return {
55
- connectionState,
56
- error,
57
- isConnected,
58
- connect,
59
- disconnect,
60
- startSession,
61
- sendInput,
62
- stopSession,
63
- sessionId,
64
- outputs,
65
- isSessionActive: sessionId !== null,
66
- };
67
- }
68
- // Executor WebSocket message types and opcodes
69
- var ExecutorWSOpCodes;
70
- (function (ExecutorWSOpCodes) {
71
- ExecutorWSOpCodes[ExecutorWSOpCodes["StartCodeSession"] = 1] = "StartCodeSession";
72
- ExecutorWSOpCodes[ExecutorWSOpCodes["CodeSessionCreated"] = 2] = "CodeSessionCreated";
73
- ExecutorWSOpCodes[ExecutorWSOpCodes["CodeOutput"] = 3] = "CodeOutput";
74
- ExecutorWSOpCodes[ExecutorWSOpCodes["CodeSessionError"] = 5] = "CodeSessionError";
75
- ExecutorWSOpCodes[ExecutorWSOpCodes["CodeSessionCompleted"] = 6] = "CodeSessionCompleted";
76
- ExecutorWSOpCodes[ExecutorWSOpCodes["SendCodeInput"] = 7] = "SendCodeInput";
77
- ExecutorWSOpCodes[ExecutorWSOpCodes["StopCodeSession"] = 8] = "StopCodeSession";
78
- })(ExecutorWSOpCodes || (exports.ExecutorWSOpCodes = ExecutorWSOpCodes = {}));
@@ -1,15 +0,0 @@
1
- import { WSConnectionState, WSOptions, WebSocketMessage, ExtractOpCode, ExtractDataForOp } from '../types.js';
2
- import type { WSClient } from '../client.js';
3
- export declare function useWebSocket<TMessage extends WebSocketMessage = WebSocketMessage>(path: string, options?: WSOptions & {
4
- autoConnect?: boolean;
5
- }): {
6
- error: string | null;
7
- connectionState: WSConnectionState;
8
- client: WSClient<TMessage> | null;
9
- isConnected: boolean;
10
- isConnecting: boolean;
11
- connect: () => Promise<WSClient<TMessage>>;
12
- disconnect: () => void;
13
- send: <TOp extends ExtractOpCode<TMessage>>(op: TOp, data: ExtractDataForOp<TMessage, TOp>) => boolean;
14
- on: <TOp extends ExtractOpCode<TMessage>>(op: TOp, handler: (data: ExtractDataForOp<TMessage, TOp>) => void) => void;
15
- };
@@ -1,72 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useWebSocket = useWebSocket;
4
- const types_js_1 = require("../types.js");
5
- const react_1 = require("react");
6
- const manager_js_1 = require("../manager.js");
7
- function useWebSocket(path, options = {}) {
8
- const { autoConnect = true, ...wsOptions } = options;
9
- const [connectionState, setConnectionState] = (0, react_1.useState)(types_js_1.WSConnectionState.Disconnected);
10
- const [error, setError] = (0, react_1.useState)(null);
11
- const clientRef = (0, react_1.useRef)(null);
12
- const connect = (0, react_1.useCallback)(async () => {
13
- if (clientRef.current?.getState() === types_js_1.WSConnectionState.Connected)
14
- return clientRef.current;
15
- try {
16
- setConnectionState(types_js_1.WSConnectionState.Connecting);
17
- const client = (0, manager_js_1.createConnection)(path, {
18
- ...wsOptions,
19
- onConnect: () => {
20
- setConnectionState(types_js_1.WSConnectionState.Connected);
21
- setError(null);
22
- wsOptions.onConnect?.();
23
- },
24
- onDisconnect: (code, reason) => {
25
- setConnectionState(types_js_1.WSConnectionState.Disconnected);
26
- clientRef.current = null;
27
- wsOptions.onDisconnect?.(code, reason);
28
- },
29
- onError: (err) => {
30
- setConnectionState(types_js_1.WSConnectionState.Error);
31
- setError(err);
32
- wsOptions.onError?.(err);
33
- },
34
- });
35
- clientRef.current = client;
36
- await client.connect();
37
- return client;
38
- }
39
- catch (err) {
40
- setConnectionState(types_js_1.WSConnectionState.Error);
41
- setError(err instanceof Error ? err.message : 'Connection failed');
42
- throw err;
43
- }
44
- }, [path, wsOptions]);
45
- const disconnect = (0, react_1.useCallback)(() => {
46
- clientRef.current?.disconnect();
47
- clientRef.current = null;
48
- setConnectionState(types_js_1.WSConnectionState.Disconnected);
49
- }, []);
50
- const send = (0, react_1.useCallback)((op, data) => {
51
- return clientRef.current?.send(op, data) ?? false;
52
- }, []);
53
- const on = (0, react_1.useCallback)((op, handler) => {
54
- clientRef.current?.on(op, handler);
55
- }, []);
56
- (0, react_1.useEffect)(() => {
57
- if (autoConnect)
58
- connect().catch(console.error);
59
- return disconnect;
60
- }, [autoConnect, connect, disconnect]);
61
- return {
62
- error,
63
- connectionState,
64
- client: clientRef.current,
65
- isConnected: connectionState === types_js_1.WSConnectionState.Connected,
66
- isConnecting: connectionState === types_js_1.WSConnectionState.Connecting,
67
- connect,
68
- disconnect,
69
- send,
70
- on,
71
- };
72
- }
@@ -1,5 +0,0 @@
1
- import { WSOptions, WebSocketMessage } from './types.js';
2
- import { WSClient } from './client.js';
3
- export declare function createConnection<TMessage extends WebSocketMessage = WebSocketMessage>(path: string, options?: WSOptions): WSClient<TMessage>;
4
- export * from './hooks/useExecutor.js';
5
- export * from './hooks/useWebSocket.js';
@@ -1,44 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.createConnection = createConnection;
18
- const types_js_1 = require("./types.js");
19
- const client_js_1 = require("./client.js");
20
- const connections = new Map();
21
- function createWebSocketUrl(path, baseUrl) {
22
- const base = baseUrl || (typeof window !== 'undefined' ? window.location.host : 'localhost:3000');
23
- const protocol = base.startsWith('https') || base.includes('443') ? 'wss' : 'ws';
24
- return `${protocol}://${base.replace(/^https?:\/\//g, '')}${path}`;
25
- }
26
- function createConnection(path, options = {}) {
27
- const url = createWebSocketUrl(path, options.baseUrl);
28
- const existing = connections.get(path);
29
- if (existing && existing.getState() === types_js_1.WSConnectionState.Connected)
30
- return existing;
31
- const client = new client_js_1.WSClient(url, {
32
- onError: options.onError,
33
- onConnect: options.onConnect,
34
- onDisconnect: (code, reason) => {
35
- connections.delete(path);
36
- options.onDisconnect?.(code, reason);
37
- },
38
- });
39
- connections.set(path, client);
40
- return client;
41
- }
42
- // Exports.
43
- __exportStar(require("./hooks/useExecutor.js"), exports);
44
- __exportStar(require("./hooks/useWebSocket.js"), exports);
@@ -1,28 +0,0 @@
1
- export type WebSocketMessage<T = unknown> = {
2
- op: number;
3
- data: T;
4
- };
5
- export declare enum SpecialOPCodes {
6
- Ping = -1,
7
- Pong = -2
8
- }
9
- export declare enum WSConnectionState {
10
- Disconnected = 0,
11
- Connecting = 1,
12
- Connected = 2,
13
- Reconnecting = 3,
14
- Error = 4
15
- }
16
- export type WSOptions = {
17
- baseUrl?: string;
18
- onConnect?: () => void;
19
- onDisconnect?: (code?: number, reason?: string) => void;
20
- onError?: (error: string) => void;
21
- };
22
- export type ExtractOpCode<T> = T extends {
23
- op: infer U;
24
- } ? U : never;
25
- export type ExtractDataForOp<TMessage, TOp> = TMessage extends {
26
- op: TOp;
27
- data: infer U;
28
- } ? U : never;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WSConnectionState = exports.SpecialOPCodes = void 0;
4
- var SpecialOPCodes;
5
- (function (SpecialOPCodes) {
6
- SpecialOPCodes[SpecialOPCodes["Ping"] = -1] = "Ping";
7
- SpecialOPCodes[SpecialOPCodes["Pong"] = -2] = "Pong";
8
- })(SpecialOPCodes || (exports.SpecialOPCodes = SpecialOPCodes = {}));
9
- var WSConnectionState;
10
- (function (WSConnectionState) {
11
- WSConnectionState[WSConnectionState["Disconnected"] = 0] = "Disconnected";
12
- WSConnectionState[WSConnectionState["Connecting"] = 1] = "Connecting";
13
- WSConnectionState[WSConnectionState["Connected"] = 2] = "Connected";
14
- WSConnectionState[WSConnectionState["Reconnecting"] = 3] = "Reconnecting";
15
- WSConnectionState[WSConnectionState["Error"] = 4] = "Error";
16
- })(WSConnectionState || (exports.WSConnectionState = WSConnectionState = {}));
@@ -1,33 +0,0 @@
1
- model CodeSnippetCollection {
2
- dbId String @id @default(uuid())
3
- collectionId String @unique
4
-
5
- createdAt DateTime @default(now())
6
- updatedAt DateTime @updatedAt
7
-
8
- boardId String @unique
9
- board Board @relation(fields: [boardId], references: [boardId], onDelete: Cascade)
10
-
11
- snippets CodeSnippet[]
12
-
13
- @@index([boardId])
14
- }
15
-
16
- model CodeSnippet {
17
- dbId String @id @default(uuid())
18
- snippetId String @unique
19
-
20
- title String
21
- description String @default("")
22
- code String @db.Text
23
- language String @default("cpp")
24
- index Int
25
-
26
- createdAt DateTime @default(now())
27
- updatedAt DateTime @updatedAt
28
-
29
- collectionId String
30
- collection CodeSnippetCollection @relation(fields: [collectionId], references: [collectionId], onDelete: Cascade)
31
-
32
- @@index([collectionId])
33
- }