@studious-lms/server 1.0.6 → 1.0.7
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/API_SPECIFICATION.md +1117 -0
- package/dist/exportType.js +1 -2
- package/dist/index.js +25 -30
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +31 -29
- package/dist/lib/googleCloudStorage.js +9 -14
- package/dist/lib/prisma.js +4 -7
- package/dist/lib/thumbnailGenerator.js +12 -20
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +17 -22
- package/dist/middleware/logging.js +5 -9
- package/dist/routers/_app.d.ts +3483 -1801
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +28 -27
- package/dist/routers/agenda.d.ts +13 -8
- package/dist/routers/agenda.d.ts.map +1 -1
- package/dist/routers/agenda.js +14 -17
- package/dist/routers/announcement.d.ts +4 -3
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +28 -31
- package/dist/routers/assignment.d.ts +282 -196
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +256 -202
- package/dist/routers/attendance.d.ts +5 -4
- package/dist/routers/attendance.d.ts.map +1 -1
- package/dist/routers/attendance.js +31 -34
- package/dist/routers/auth.d.ts +1 -0
- package/dist/routers/auth.d.ts.map +1 -1
- package/dist/routers/auth.js +80 -75
- package/dist/routers/class.d.ts +284 -14
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +435 -164
- package/dist/routers/event.d.ts +47 -38
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/event.js +76 -79
- package/dist/routers/file.d.ts +71 -1
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/file.js +267 -32
- package/dist/routers/folder.d.ts +296 -0
- package/dist/routers/folder.d.ts.map +1 -0
- package/dist/routers/folder.js +693 -0
- package/dist/routers/notifications.d.ts +103 -0
- package/dist/routers/notifications.d.ts.map +1 -0
- package/dist/routers/notifications.js +91 -0
- package/dist/routers/school.d.ts +208 -0
- package/dist/routers/school.d.ts.map +1 -0
- package/dist/routers/school.js +481 -0
- package/dist/routers/section.d.ts +1 -0
- package/dist/routers/section.d.ts.map +1 -1
- package/dist/routers/section.js +30 -33
- package/dist/routers/user.d.ts +2 -1
- package/dist/routers/user.d.ts.map +1 -1
- package/dist/routers/user.js +21 -24
- package/dist/seedDatabase.d.ts +22 -0
- package/dist/seedDatabase.d.ts.map +1 -0
- package/dist/seedDatabase.js +57 -0
- package/dist/socket/handlers.js +26 -30
- package/dist/trpc.d.ts +5 -0
- package/dist/trpc.d.ts.map +1 -1
- package/dist/trpc.js +35 -26
- package/dist/types/trpc.js +1 -2
- package/dist/utils/email.js +2 -8
- package/dist/utils/generateInviteCode.js +1 -5
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +13 -9
- package/dist/utils/prismaErrorHandler.d.ts +9 -0
- package/dist/utils/prismaErrorHandler.d.ts.map +1 -0
- package/dist/utils/prismaErrorHandler.js +234 -0
- package/dist/utils/prismaWrapper.d.ts +14 -0
- package/dist/utils/prismaWrapper.d.ts.map +1 -0
- package/dist/utils/prismaWrapper.js +64 -0
- package/package.json +11 -4
- package/prisma/migrations/20250807062924_init/migration.sql +436 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +67 -0
- package/src/index.ts +2 -2
- package/src/lib/fileUpload.ts +16 -7
- package/src/middleware/auth.ts +0 -2
- package/src/routers/_app.ts +5 -1
- package/src/routers/assignment.ts +82 -22
- package/src/routers/auth.ts +80 -54
- package/src/routers/class.ts +330 -36
- package/src/routers/file.ts +283 -20
- package/src/routers/folder.ts +755 -0
- package/src/routers/notifications.ts +93 -0
- package/src/seedDatabase.ts +66 -0
- package/src/socket/handlers.ts +4 -4
- package/src/trpc.ts +13 -0
- package/src/utils/logger.ts +14 -4
- package/src/utils/prismaErrorHandler.ts +275 -0
- package/src/utils/prismaWrapper.ts +91 -0
- package/tests/auth.test.ts +25 -0
- package/tests/class.test.ts +281 -0
- package/tests/setup.ts +98 -0
- package/tests/startup.test.ts +5 -0
- package/tsconfig.json +2 -1
- package/vitest.config.ts +11 -0
- package/dist/logger.d.ts +0 -26
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -135
- package/src/logger.ts +0 -163
|
@@ -0,0 +1,1117 @@
|
|
|
1
|
+
# Easy LMS API Specification
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Easy LMS is a comprehensive Learning Management System built with tRPC, Prisma, and PostgreSQL. This document provides a complete API specification for frontend developers.
|
|
6
|
+
|
|
7
|
+
### Base URL
|
|
8
|
+
- **Development**: `http://localhost:3001/trpc`
|
|
9
|
+
- **Production**: `https://your-domain.com/trpc`
|
|
10
|
+
|
|
11
|
+
### Authentication
|
|
12
|
+
- **Method**: Bearer Token Authentication
|
|
13
|
+
- **Header**: `Authorization: Bearer <token>`
|
|
14
|
+
- **Session Management**: Token-based sessions with expiration
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 🔐 Authentication Endpoints
|
|
19
|
+
|
|
20
|
+
### `auth.register`
|
|
21
|
+
**Type**: Mutation
|
|
22
|
+
**Access**: Public
|
|
23
|
+
**Description**: Register a new user account
|
|
24
|
+
|
|
25
|
+
**Input**:
|
|
26
|
+
```typescript
|
|
27
|
+
{
|
|
28
|
+
username: string; // min 3 characters
|
|
29
|
+
email: string; // valid email format
|
|
30
|
+
password: string; // min 6 characters
|
|
31
|
+
confirmPassword: string;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Output**:
|
|
36
|
+
```typescript
|
|
37
|
+
{
|
|
38
|
+
user: {
|
|
39
|
+
id: string;
|
|
40
|
+
username: string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `auth.login`
|
|
46
|
+
**Type**: Mutation
|
|
47
|
+
**Access**: Public
|
|
48
|
+
**Description**: Login with username and password
|
|
49
|
+
|
|
50
|
+
**Input**:
|
|
51
|
+
```typescript
|
|
52
|
+
{
|
|
53
|
+
username: string;
|
|
54
|
+
password: string;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Output**:
|
|
59
|
+
```typescript
|
|
60
|
+
{
|
|
61
|
+
token: string;
|
|
62
|
+
user: {
|
|
63
|
+
id: string;
|
|
64
|
+
username: string;
|
|
65
|
+
};
|
|
66
|
+
verified?: boolean;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `auth.logout`
|
|
71
|
+
**Type**: Mutation
|
|
72
|
+
**Access**: Public
|
|
73
|
+
**Description**: Logout and invalidate session
|
|
74
|
+
|
|
75
|
+
**Output**:
|
|
76
|
+
```typescript
|
|
77
|
+
{
|
|
78
|
+
success: boolean;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `auth.check`
|
|
83
|
+
**Type**: Query
|
|
84
|
+
**Access**: Protected
|
|
85
|
+
**Description**: Verify current authentication status
|
|
86
|
+
|
|
87
|
+
**Output**:
|
|
88
|
+
```typescript
|
|
89
|
+
{
|
|
90
|
+
user: {
|
|
91
|
+
id: string;
|
|
92
|
+
username: string;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `auth.verify`
|
|
98
|
+
**Type**: Mutation
|
|
99
|
+
**Access**: Public
|
|
100
|
+
**Description**: Verify email with token
|
|
101
|
+
|
|
102
|
+
**Input**:
|
|
103
|
+
```typescript
|
|
104
|
+
{
|
|
105
|
+
token: string;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `auth.resendVerificationEmail`
|
|
110
|
+
**Type**: Mutation
|
|
111
|
+
**Access**: Public
|
|
112
|
+
**Description**: Resend verification email
|
|
113
|
+
|
|
114
|
+
**Input**:
|
|
115
|
+
```typescript
|
|
116
|
+
{
|
|
117
|
+
email: string;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 👤 User Management
|
|
124
|
+
|
|
125
|
+
### `user.getProfile`
|
|
126
|
+
**Type**: Query
|
|
127
|
+
**Access**: Protected
|
|
128
|
+
**Description**: Get current user profile
|
|
129
|
+
|
|
130
|
+
**Output**:
|
|
131
|
+
```typescript
|
|
132
|
+
{
|
|
133
|
+
id: string;
|
|
134
|
+
username: string;
|
|
135
|
+
profile: Record<string, any>;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `user.updateProfile`
|
|
140
|
+
**Type**: Mutation
|
|
141
|
+
**Access**: Protected
|
|
142
|
+
**Description**: Update user profile
|
|
143
|
+
|
|
144
|
+
**Input**:
|
|
145
|
+
```typescript
|
|
146
|
+
{
|
|
147
|
+
profile: Record<string, any>;
|
|
148
|
+
profilePicture?: {
|
|
149
|
+
name: string;
|
|
150
|
+
type: string;
|
|
151
|
+
size: number;
|
|
152
|
+
data: string; // base64
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 🏫 Class Management
|
|
160
|
+
|
|
161
|
+
### `class.getAll`
|
|
162
|
+
**Type**: Query
|
|
163
|
+
**Access**: Protected
|
|
164
|
+
**Description**: Get all classes for current user
|
|
165
|
+
|
|
166
|
+
**Output**:
|
|
167
|
+
```typescript
|
|
168
|
+
{
|
|
169
|
+
teacherInClass: Array<{
|
|
170
|
+
id: string;
|
|
171
|
+
name: string;
|
|
172
|
+
section: string;
|
|
173
|
+
subject: string;
|
|
174
|
+
color?: string;
|
|
175
|
+
dueToday: Assignment[];
|
|
176
|
+
assignments: Assignment[];
|
|
177
|
+
}>;
|
|
178
|
+
studentInClass: Array<{
|
|
179
|
+
id: string;
|
|
180
|
+
name: string;
|
|
181
|
+
section: string;
|
|
182
|
+
subject: string;
|
|
183
|
+
color?: string;
|
|
184
|
+
dueToday: Assignment[];
|
|
185
|
+
assignments: Assignment[];
|
|
186
|
+
}>;
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### `class.get`
|
|
191
|
+
**Type**: Query
|
|
192
|
+
**Access**: Protected
|
|
193
|
+
**Description**: Get specific class details
|
|
194
|
+
|
|
195
|
+
**Input**:
|
|
196
|
+
```typescript
|
|
197
|
+
{
|
|
198
|
+
classId: string;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Output**:
|
|
203
|
+
```typescript
|
|
204
|
+
{
|
|
205
|
+
class: {
|
|
206
|
+
id: string;
|
|
207
|
+
name: string;
|
|
208
|
+
subject: string;
|
|
209
|
+
section: string;
|
|
210
|
+
color?: string;
|
|
211
|
+
teachers: Array<{
|
|
212
|
+
id: string;
|
|
213
|
+
username: string;
|
|
214
|
+
}>;
|
|
215
|
+
students: Array<{
|
|
216
|
+
id: string;
|
|
217
|
+
username: string;
|
|
218
|
+
}>;
|
|
219
|
+
announcements: Array<{
|
|
220
|
+
id: string;
|
|
221
|
+
remarks: string;
|
|
222
|
+
createdAt: Date;
|
|
223
|
+
teacher: {
|
|
224
|
+
id: string;
|
|
225
|
+
username: string;
|
|
226
|
+
};
|
|
227
|
+
}>;
|
|
228
|
+
assignments: Assignment[];
|
|
229
|
+
sections: Section[];
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### `class.create`
|
|
235
|
+
**Type**: Mutation
|
|
236
|
+
**Access**: Protected
|
|
237
|
+
**Description**: Create a new class
|
|
238
|
+
|
|
239
|
+
**Input**:
|
|
240
|
+
```typescript
|
|
241
|
+
{
|
|
242
|
+
name: string;
|
|
243
|
+
section: string;
|
|
244
|
+
subject: string;
|
|
245
|
+
color?: string;
|
|
246
|
+
students?: string[];
|
|
247
|
+
teachers?: string[];
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### `class.update`
|
|
252
|
+
**Type**: Mutation
|
|
253
|
+
**Access**: Teacher Only
|
|
254
|
+
**Description**: Update class details
|
|
255
|
+
|
|
256
|
+
**Input**:
|
|
257
|
+
```typescript
|
|
258
|
+
{
|
|
259
|
+
classId: string;
|
|
260
|
+
name?: string;
|
|
261
|
+
section?: string;
|
|
262
|
+
subject?: string;
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### `class.delete`
|
|
267
|
+
**Type**: Mutation
|
|
268
|
+
**Access**: Teacher Only
|
|
269
|
+
**Description**: Delete a class
|
|
270
|
+
|
|
271
|
+
**Input**:
|
|
272
|
+
```typescript
|
|
273
|
+
{
|
|
274
|
+
classId: string;
|
|
275
|
+
id: string;
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### `class.join`
|
|
280
|
+
**Type**: Mutation
|
|
281
|
+
**Access**: Protected
|
|
282
|
+
**Description**: Join class with invite code
|
|
283
|
+
|
|
284
|
+
**Input**:
|
|
285
|
+
```typescript
|
|
286
|
+
{
|
|
287
|
+
classCode: string;
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### `class.getInviteCode`
|
|
292
|
+
**Type**: Query
|
|
293
|
+
**Access**: Teacher Only
|
|
294
|
+
**Description**: Get class invite code
|
|
295
|
+
|
|
296
|
+
**Input**:
|
|
297
|
+
```typescript
|
|
298
|
+
{
|
|
299
|
+
classId: string;
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Output**:
|
|
304
|
+
```typescript
|
|
305
|
+
{
|
|
306
|
+
code: string;
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### `class.addStudent`
|
|
311
|
+
**Type**: Mutation
|
|
312
|
+
**Access**: Teacher Only
|
|
313
|
+
**Description**: Add student to class
|
|
314
|
+
|
|
315
|
+
**Input**:
|
|
316
|
+
```typescript
|
|
317
|
+
{
|
|
318
|
+
classId: string;
|
|
319
|
+
studentId: string;
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### `class.changeRole`
|
|
324
|
+
**Type**: Mutation
|
|
325
|
+
**Access**: Teacher Only
|
|
326
|
+
**Description**: Change user role in class
|
|
327
|
+
|
|
328
|
+
**Input**:
|
|
329
|
+
```typescript
|
|
330
|
+
{
|
|
331
|
+
classId: string;
|
|
332
|
+
userId: string;
|
|
333
|
+
type: 'teacher' | 'student';
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### `class.removeMember`
|
|
338
|
+
**Type**: Mutation
|
|
339
|
+
**Access**: Teacher Only
|
|
340
|
+
**Description**: Remove member from class
|
|
341
|
+
|
|
342
|
+
**Input**:
|
|
343
|
+
```typescript
|
|
344
|
+
{
|
|
345
|
+
classId: string;
|
|
346
|
+
userId: string;
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## 📝 Assignment Management
|
|
353
|
+
|
|
354
|
+
### `assignment.create`
|
|
355
|
+
**Type**: Mutation
|
|
356
|
+
**Access**: Protected
|
|
357
|
+
**Description**: Create a new assignment
|
|
358
|
+
|
|
359
|
+
**Input**:
|
|
360
|
+
```typescript
|
|
361
|
+
{
|
|
362
|
+
classId: string;
|
|
363
|
+
title: string;
|
|
364
|
+
instructions: string;
|
|
365
|
+
dueDate: string;
|
|
366
|
+
files?: File[];
|
|
367
|
+
existingFileIds?: string[];
|
|
368
|
+
maxGrade?: number;
|
|
369
|
+
graded?: boolean;
|
|
370
|
+
weight?: number;
|
|
371
|
+
sectionId?: string;
|
|
372
|
+
type?: 'HOMEWORK' | 'QUIZ' | 'TEST' | 'PROJECT' | 'ESSAY' | 'DISCUSSION' | 'PRESENTATION' | 'LAB' | 'OTHER';
|
|
373
|
+
markSchemeId?: string;
|
|
374
|
+
gradingBoundaryId?: string;
|
|
375
|
+
inProgress?: boolean;
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### `assignment.update`
|
|
380
|
+
**Type**: Mutation
|
|
381
|
+
**Access**: Protected
|
|
382
|
+
**Description**: Update assignment
|
|
383
|
+
|
|
384
|
+
**Input**:
|
|
385
|
+
```typescript
|
|
386
|
+
{
|
|
387
|
+
classId: string;
|
|
388
|
+
id: string;
|
|
389
|
+
title?: string;
|
|
390
|
+
instructions?: string;
|
|
391
|
+
dueDate?: string;
|
|
392
|
+
files?: File[];
|
|
393
|
+
existingFileIds?: string[];
|
|
394
|
+
removedAttachments?: string[];
|
|
395
|
+
maxGrade?: number;
|
|
396
|
+
graded?: boolean;
|
|
397
|
+
weight?: number;
|
|
398
|
+
sectionId?: string | null;
|
|
399
|
+
type?: AssignmentType;
|
|
400
|
+
inProgress?: boolean;
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### `assignment.delete`
|
|
405
|
+
**Type**: Mutation
|
|
406
|
+
**Access**: Protected
|
|
407
|
+
**Description**: Delete assignment
|
|
408
|
+
|
|
409
|
+
**Input**:
|
|
410
|
+
```typescript
|
|
411
|
+
{
|
|
412
|
+
id: string;
|
|
413
|
+
classId: string;
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### `assignment.get`
|
|
418
|
+
**Type**: Query
|
|
419
|
+
**Access**: Protected
|
|
420
|
+
**Description**: Get assignment details
|
|
421
|
+
|
|
422
|
+
**Input**:
|
|
423
|
+
```typescript
|
|
424
|
+
{
|
|
425
|
+
id: string;
|
|
426
|
+
classId: string;
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### `assignment.getSubmission`
|
|
431
|
+
**Type**: Query
|
|
432
|
+
**Access**: Class Member
|
|
433
|
+
**Description**: Get student's submission for assignment
|
|
434
|
+
|
|
435
|
+
**Input**:
|
|
436
|
+
```typescript
|
|
437
|
+
{
|
|
438
|
+
assignmentId: string;
|
|
439
|
+
classId: string;
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### `assignment.getSubmissions`
|
|
444
|
+
**Type**: Query
|
|
445
|
+
**Access**: Teacher Only
|
|
446
|
+
**Description**: Get all submissions for assignment
|
|
447
|
+
|
|
448
|
+
**Input**:
|
|
449
|
+
```typescript
|
|
450
|
+
{
|
|
451
|
+
assignmentId: string;
|
|
452
|
+
classId: string;
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### `assignment.updateSubmission`
|
|
457
|
+
**Type**: Mutation
|
|
458
|
+
**Access**: Class Member
|
|
459
|
+
**Description**: Update student submission
|
|
460
|
+
|
|
461
|
+
**Input**:
|
|
462
|
+
```typescript
|
|
463
|
+
{
|
|
464
|
+
assignmentId: string;
|
|
465
|
+
classId: string;
|
|
466
|
+
submissionId: string;
|
|
467
|
+
submit?: boolean;
|
|
468
|
+
newAttachments?: File[];
|
|
469
|
+
existingFileIds?: string[];
|
|
470
|
+
removedAttachments?: string[];
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### `assignment.updateSubmissionAsTeacher`
|
|
475
|
+
**Type**: Mutation
|
|
476
|
+
**Access**: Teacher Only
|
|
477
|
+
**Description**: Update submission as teacher (grading)
|
|
478
|
+
|
|
479
|
+
**Input**:
|
|
480
|
+
```typescript
|
|
481
|
+
{
|
|
482
|
+
assignmentId: string;
|
|
483
|
+
classId: string;
|
|
484
|
+
submissionId: string;
|
|
485
|
+
return?: boolean;
|
|
486
|
+
gradeReceived?: number | null;
|
|
487
|
+
newAttachments?: File[];
|
|
488
|
+
existingFileIds?: string[];
|
|
489
|
+
removedAttachments?: string[];
|
|
490
|
+
rubricGrades?: Array<{
|
|
491
|
+
criteriaId: string;
|
|
492
|
+
selectedLevelId: string;
|
|
493
|
+
points: number;
|
|
494
|
+
comments: string;
|
|
495
|
+
}>;
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## 📢 Announcements
|
|
502
|
+
|
|
503
|
+
### `announcement.getAll`
|
|
504
|
+
**Type**: Query
|
|
505
|
+
**Access**: Class Member
|
|
506
|
+
**Description**: Get all class announcements
|
|
507
|
+
|
|
508
|
+
**Input**:
|
|
509
|
+
```typescript
|
|
510
|
+
{
|
|
511
|
+
classId: string;
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
**Output**:
|
|
516
|
+
```typescript
|
|
517
|
+
{
|
|
518
|
+
announcements: Array<{
|
|
519
|
+
id: string;
|
|
520
|
+
remarks: string;
|
|
521
|
+
createdAt: Date;
|
|
522
|
+
teacher: {
|
|
523
|
+
id: string;
|
|
524
|
+
username: string;
|
|
525
|
+
};
|
|
526
|
+
}>;
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### `announcement.create`
|
|
531
|
+
**Type**: Mutation
|
|
532
|
+
**Access**: Teacher Only
|
|
533
|
+
**Description**: Create new announcement
|
|
534
|
+
|
|
535
|
+
**Input**:
|
|
536
|
+
```typescript
|
|
537
|
+
{
|
|
538
|
+
classId: string;
|
|
539
|
+
remarks: string;
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### `announcement.update`
|
|
544
|
+
**Type**: Mutation
|
|
545
|
+
**Access**: Protected
|
|
546
|
+
**Description**: Update announcement
|
|
547
|
+
|
|
548
|
+
**Input**:
|
|
549
|
+
```typescript
|
|
550
|
+
{
|
|
551
|
+
id: string;
|
|
552
|
+
data: {
|
|
553
|
+
content: string;
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### `announcement.delete`
|
|
559
|
+
**Type**: Mutation
|
|
560
|
+
**Access**: Protected
|
|
561
|
+
**Description**: Delete announcement
|
|
562
|
+
|
|
563
|
+
**Input**:
|
|
564
|
+
```typescript
|
|
565
|
+
{
|
|
566
|
+
id: string;
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## 📁 File Management
|
|
573
|
+
|
|
574
|
+
### `file.getSignedUrl`
|
|
575
|
+
**Type**: Mutation
|
|
576
|
+
**Access**: Protected
|
|
577
|
+
**Description**: Get signed URL for file download
|
|
578
|
+
|
|
579
|
+
**Input**:
|
|
580
|
+
```typescript
|
|
581
|
+
{
|
|
582
|
+
fileId: string;
|
|
583
|
+
}
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
**Output**:
|
|
587
|
+
```typescript
|
|
588
|
+
{
|
|
589
|
+
url: string;
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### `file.move`
|
|
594
|
+
**Type**: Mutation
|
|
595
|
+
**Access**: Teacher Only
|
|
596
|
+
**Description**: Move file to different folder
|
|
597
|
+
|
|
598
|
+
**Input**:
|
|
599
|
+
```typescript
|
|
600
|
+
{
|
|
601
|
+
fileId: string;
|
|
602
|
+
targetFolderId: string;
|
|
603
|
+
classId: string;
|
|
604
|
+
}
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
### `file.rename`
|
|
608
|
+
**Type**: Mutation
|
|
609
|
+
**Access**: Teacher Only
|
|
610
|
+
**Description**: Rename file
|
|
611
|
+
|
|
612
|
+
**Input**:
|
|
613
|
+
```typescript
|
|
614
|
+
{
|
|
615
|
+
fileId: string;
|
|
616
|
+
newName: string;
|
|
617
|
+
classId: string;
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### `file.delete`
|
|
622
|
+
**Type**: Mutation
|
|
623
|
+
**Access**: Teacher Only
|
|
624
|
+
**Description**: Delete file
|
|
625
|
+
|
|
626
|
+
**Input**:
|
|
627
|
+
```typescript
|
|
628
|
+
{
|
|
629
|
+
fileId: string;
|
|
630
|
+
classId: string;
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## 🔔 Notifications
|
|
637
|
+
|
|
638
|
+
### `notification.list`
|
|
639
|
+
**Type**: Query
|
|
640
|
+
**Access**: Protected
|
|
641
|
+
**Description**: Get all notifications for user
|
|
642
|
+
|
|
643
|
+
**Output**:
|
|
644
|
+
```typescript
|
|
645
|
+
Array<{
|
|
646
|
+
id: string;
|
|
647
|
+
title: string;
|
|
648
|
+
content: string;
|
|
649
|
+
createdAt: Date;
|
|
650
|
+
read: boolean;
|
|
651
|
+
sender?: {
|
|
652
|
+
username: string;
|
|
653
|
+
};
|
|
654
|
+
receiver: {
|
|
655
|
+
username: string;
|
|
656
|
+
};
|
|
657
|
+
}>
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
### `notification.get`
|
|
661
|
+
**Type**: Query
|
|
662
|
+
**Access**: Protected
|
|
663
|
+
**Description**: Get specific notification
|
|
664
|
+
|
|
665
|
+
**Input**:
|
|
666
|
+
```typescript
|
|
667
|
+
{
|
|
668
|
+
id: string;
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### `notification.sendTo`
|
|
673
|
+
**Type**: Mutation
|
|
674
|
+
**Access**: Protected
|
|
675
|
+
**Description**: Send notification to user
|
|
676
|
+
|
|
677
|
+
**Input**:
|
|
678
|
+
```typescript
|
|
679
|
+
{
|
|
680
|
+
receiverId: string;
|
|
681
|
+
title: string;
|
|
682
|
+
content: string;
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### `notification.sendToMultiple`
|
|
687
|
+
**Type**: Mutation
|
|
688
|
+
**Access**: Protected
|
|
689
|
+
**Description**: Send notification to multiple users
|
|
690
|
+
|
|
691
|
+
**Input**:
|
|
692
|
+
```typescript
|
|
693
|
+
{
|
|
694
|
+
receiverIds: string[];
|
|
695
|
+
title: string;
|
|
696
|
+
content: string;
|
|
697
|
+
}
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### `notification.markAsRead`
|
|
701
|
+
**Type**: Mutation
|
|
702
|
+
**Access**: Protected
|
|
703
|
+
**Description**: Mark notification as read
|
|
704
|
+
|
|
705
|
+
**Input**:
|
|
706
|
+
```typescript
|
|
707
|
+
{
|
|
708
|
+
id: string;
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
## 🏫 School Management
|
|
715
|
+
|
|
716
|
+
*Note: Router exists but implementation details need to be examined*
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
## 📊 Grading & Assessment
|
|
721
|
+
|
|
722
|
+
### `class.getGrades`
|
|
723
|
+
**Type**: Query
|
|
724
|
+
**Access**: Class Member
|
|
725
|
+
**Description**: Get grades for a user
|
|
726
|
+
|
|
727
|
+
**Input**:
|
|
728
|
+
```typescript
|
|
729
|
+
{
|
|
730
|
+
classId: string;
|
|
731
|
+
userId: string;
|
|
732
|
+
}
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
### `class.updateGrade`
|
|
736
|
+
**Type**: Mutation
|
|
737
|
+
**Access**: Teacher Only
|
|
738
|
+
**Description**: Update student grade
|
|
739
|
+
|
|
740
|
+
**Input**:
|
|
741
|
+
```typescript
|
|
742
|
+
{
|
|
743
|
+
classId: string;
|
|
744
|
+
assignmentId: string;
|
|
745
|
+
submissionId: string;
|
|
746
|
+
gradeReceived: number | null;
|
|
747
|
+
}
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
### Mark Schemes
|
|
751
|
+
|
|
752
|
+
### `class.listMarkSchemes`
|
|
753
|
+
**Type**: Query
|
|
754
|
+
**Access**: Teacher Only
|
|
755
|
+
|
|
756
|
+
### `class.createMarkScheme`
|
|
757
|
+
**Type**: Mutation
|
|
758
|
+
**Access**: Teacher Only
|
|
759
|
+
|
|
760
|
+
### `class.updateMarkScheme`
|
|
761
|
+
**Type**: Mutation
|
|
762
|
+
**Access**: Teacher Only
|
|
763
|
+
|
|
764
|
+
### `class.deleteMarkScheme`
|
|
765
|
+
**Type**: Mutation
|
|
766
|
+
**Access**: Teacher Only
|
|
767
|
+
|
|
768
|
+
### Grading Boundaries
|
|
769
|
+
|
|
770
|
+
### `class.listGradingBoundaries`
|
|
771
|
+
**Type**: Query
|
|
772
|
+
**Access**: Teacher Only
|
|
773
|
+
|
|
774
|
+
### `class.createGradingBoundary`
|
|
775
|
+
**Type**: Mutation
|
|
776
|
+
**Access**: Teacher Only
|
|
777
|
+
|
|
778
|
+
### `class.updateGradingBoundary`
|
|
779
|
+
**Type**: Mutation
|
|
780
|
+
**Access**: Teacher Only
|
|
781
|
+
|
|
782
|
+
### `class.deleteGradingBoundary`
|
|
783
|
+
**Type**: Mutation
|
|
784
|
+
**Access**: Teacher Only
|
|
785
|
+
|
|
786
|
+
---
|
|
787
|
+
|
|
788
|
+
## 📅 Calendar & Events
|
|
789
|
+
|
|
790
|
+
### `class.getEvents`
|
|
791
|
+
**Type**: Query
|
|
792
|
+
**Access**: Teacher Only
|
|
793
|
+
**Description**: Get class events
|
|
794
|
+
|
|
795
|
+
**Input**:
|
|
796
|
+
```typescript
|
|
797
|
+
{
|
|
798
|
+
classId: string;
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
### `assignment.attachToEvent`
|
|
803
|
+
**Type**: Mutation
|
|
804
|
+
**Access**: Teacher Only
|
|
805
|
+
**Description**: Attach assignment to event
|
|
806
|
+
|
|
807
|
+
**Input**:
|
|
808
|
+
```typescript
|
|
809
|
+
{
|
|
810
|
+
assignmentId: string;
|
|
811
|
+
eventId: string;
|
|
812
|
+
}
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
### `assignment.detachEvent`
|
|
816
|
+
**Type**: Mutation
|
|
817
|
+
**Access**: Teacher Only
|
|
818
|
+
**Description**: Detach assignment from event
|
|
819
|
+
|
|
820
|
+
**Input**:
|
|
821
|
+
```typescript
|
|
822
|
+
{
|
|
823
|
+
assignmentId: string;
|
|
824
|
+
}
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
### `assignment.getAvailableEvents`
|
|
828
|
+
**Type**: Query
|
|
829
|
+
**Access**: Teacher Only
|
|
830
|
+
**Description**: Get available events for assignment
|
|
831
|
+
|
|
832
|
+
**Input**:
|
|
833
|
+
```typescript
|
|
834
|
+
{
|
|
835
|
+
assignmentId: string;
|
|
836
|
+
}
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## 🔧 Lab Management (Draft System)
|
|
842
|
+
|
|
843
|
+
### `class.listLabDrafts`
|
|
844
|
+
**Type**: Query
|
|
845
|
+
**Access**: Teacher Only
|
|
846
|
+
**Description**: Get lab drafts
|
|
847
|
+
|
|
848
|
+
**Input**:
|
|
849
|
+
```typescript
|
|
850
|
+
{
|
|
851
|
+
classId: string;
|
|
852
|
+
}
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
### `class.createLabDraft`
|
|
856
|
+
**Type**: Mutation
|
|
857
|
+
**Access**: Teacher Only
|
|
858
|
+
**Description**: Create lab draft
|
|
859
|
+
|
|
860
|
+
### `class.updateLabDraft`
|
|
861
|
+
**Type**: Mutation
|
|
862
|
+
**Access**: Teacher Only
|
|
863
|
+
**Description**: Update lab draft
|
|
864
|
+
|
|
865
|
+
### `class.deleteLabDraft`
|
|
866
|
+
**Type**: Mutation
|
|
867
|
+
**Access**: Teacher Only
|
|
868
|
+
**Description**: Delete lab draft
|
|
869
|
+
|
|
870
|
+
### `class.publishLabDraft`
|
|
871
|
+
**Type**: Mutation
|
|
872
|
+
**Access**: Teacher Only
|
|
873
|
+
**Description**: Publish lab draft as assignment
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
## 📄 Syllabus Management
|
|
878
|
+
|
|
879
|
+
### `class.getSyllabus`
|
|
880
|
+
**Type**: Query
|
|
881
|
+
**Access**: Class Member
|
|
882
|
+
**Description**: Get class syllabus
|
|
883
|
+
|
|
884
|
+
**Input**:
|
|
885
|
+
```typescript
|
|
886
|
+
{
|
|
887
|
+
classId: string;
|
|
888
|
+
}
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
**Output**:
|
|
892
|
+
```typescript
|
|
893
|
+
{
|
|
894
|
+
syllabus: string;
|
|
895
|
+
gradingBoundaries: GradingBoundary[];
|
|
896
|
+
markSchemes: MarkScheme[];
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
### `class.updateSyllabus`
|
|
901
|
+
**Type**: Mutation
|
|
902
|
+
**Access**: Teacher Only
|
|
903
|
+
**Description**: Update class syllabus
|
|
904
|
+
|
|
905
|
+
**Input**:
|
|
906
|
+
```typescript
|
|
907
|
+
{
|
|
908
|
+
classId: string;
|
|
909
|
+
contents: string;
|
|
910
|
+
}
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
---
|
|
914
|
+
|
|
915
|
+
## 🗂️ File Organization
|
|
916
|
+
|
|
917
|
+
### `class.getFiles`
|
|
918
|
+
**Type**: Query
|
|
919
|
+
**Access**: Class Member
|
|
920
|
+
**Description**: Get organized files for class
|
|
921
|
+
|
|
922
|
+
**Input**:
|
|
923
|
+
```typescript
|
|
924
|
+
{
|
|
925
|
+
classId: string;
|
|
926
|
+
}
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
**Output**:
|
|
930
|
+
```typescript
|
|
931
|
+
Array<{
|
|
932
|
+
id: string;
|
|
933
|
+
title: string;
|
|
934
|
+
teacher: {
|
|
935
|
+
id: string;
|
|
936
|
+
username: string;
|
|
937
|
+
};
|
|
938
|
+
teacherAttachments: File[];
|
|
939
|
+
students: Array<{
|
|
940
|
+
id: string;
|
|
941
|
+
username: string;
|
|
942
|
+
attachments: File[];
|
|
943
|
+
annotations: File[];
|
|
944
|
+
}>;
|
|
945
|
+
}>
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
---
|
|
949
|
+
|
|
950
|
+
## 🌐 Real-time Features
|
|
951
|
+
|
|
952
|
+
### Socket.IO Events
|
|
953
|
+
- **Connection**: `/socket.io/`
|
|
954
|
+
- **Events**: Class updates, new assignments, submissions, etc.
|
|
955
|
+
|
|
956
|
+
---
|
|
957
|
+
|
|
958
|
+
## 📊 Data Models
|
|
959
|
+
|
|
960
|
+
### File Object
|
|
961
|
+
```typescript
|
|
962
|
+
{
|
|
963
|
+
id: string;
|
|
964
|
+
name: string;
|
|
965
|
+
type: string;
|
|
966
|
+
size: number;
|
|
967
|
+
data: string; // base64 encoded
|
|
968
|
+
}
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
### Assignment Object
|
|
972
|
+
```typescript
|
|
973
|
+
{
|
|
974
|
+
id: string;
|
|
975
|
+
title: string;
|
|
976
|
+
instructions: string;
|
|
977
|
+
dueDate: Date;
|
|
978
|
+
maxGrade?: number;
|
|
979
|
+
graded: boolean;
|
|
980
|
+
weight: number;
|
|
981
|
+
type: AssignmentType;
|
|
982
|
+
inProgress: boolean;
|
|
983
|
+
template: boolean;
|
|
984
|
+
attachments: File[];
|
|
985
|
+
submissions: Submission[];
|
|
986
|
+
section?: Section;
|
|
987
|
+
teacher: User;
|
|
988
|
+
class: Class;
|
|
989
|
+
markScheme?: MarkScheme;
|
|
990
|
+
gradingBoundary?: GradingBoundary;
|
|
991
|
+
eventAttached?: Event;
|
|
992
|
+
}
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
### User Roles
|
|
996
|
+
- `STUDENT`: Can view classes, submit assignments
|
|
997
|
+
- `TEACHER`: Can create/manage classes, grade assignments
|
|
998
|
+
- `ADMIN`: System administration
|
|
999
|
+
- `NONE`: No specific role
|
|
1000
|
+
|
|
1001
|
+
### Assignment Types
|
|
1002
|
+
- `HOMEWORK`
|
|
1003
|
+
- `QUIZ`
|
|
1004
|
+
- `TEST`
|
|
1005
|
+
- `PROJECT`
|
|
1006
|
+
- `ESSAY`
|
|
1007
|
+
- `DISCUSSION`
|
|
1008
|
+
- `PRESENTATION`
|
|
1009
|
+
- `LAB`
|
|
1010
|
+
- `OTHER`
|
|
1011
|
+
|
|
1012
|
+
---
|
|
1013
|
+
|
|
1014
|
+
## 🔒 Access Control
|
|
1015
|
+
|
|
1016
|
+
### Public Endpoints
|
|
1017
|
+
- All `auth.*` endpoints
|
|
1018
|
+
|
|
1019
|
+
### Protected Endpoints
|
|
1020
|
+
- Require valid authentication token
|
|
1021
|
+
- User must be logged in
|
|
1022
|
+
|
|
1023
|
+
### Class Member Endpoints
|
|
1024
|
+
- Require `classId` parameter
|
|
1025
|
+
- User must be student or teacher in the class
|
|
1026
|
+
|
|
1027
|
+
### Teacher Only Endpoints
|
|
1028
|
+
- User must be teacher in the specified class
|
|
1029
|
+
- Full management capabilities
|
|
1030
|
+
|
|
1031
|
+
---
|
|
1032
|
+
|
|
1033
|
+
## ⚠️ Error Handling
|
|
1034
|
+
|
|
1035
|
+
### Common Error Codes
|
|
1036
|
+
- `UNAUTHORIZED`: Invalid or missing authentication
|
|
1037
|
+
- `FORBIDDEN`: Insufficient permissions
|
|
1038
|
+
- `NOT_FOUND`: Resource doesn't exist
|
|
1039
|
+
- `BAD_REQUEST`: Invalid input data
|
|
1040
|
+
- `CONFLICT`: Resource already exists
|
|
1041
|
+
- `INTERNAL_SERVER_ERROR`: Server error
|
|
1042
|
+
|
|
1043
|
+
### Error Response Format
|
|
1044
|
+
```typescript
|
|
1045
|
+
{
|
|
1046
|
+
error: {
|
|
1047
|
+
code: string;
|
|
1048
|
+
message: string;
|
|
1049
|
+
data?: {
|
|
1050
|
+
zodError?: any;
|
|
1051
|
+
prismaError?: any;
|
|
1052
|
+
};
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
---
|
|
1058
|
+
|
|
1059
|
+
## 🚀 Usage Examples
|
|
1060
|
+
|
|
1061
|
+
### TypeScript Client Setup
|
|
1062
|
+
```typescript
|
|
1063
|
+
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
|
1064
|
+
import type { AppRouter } from '@studious-lms/server';
|
|
1065
|
+
|
|
1066
|
+
const trpc = createTRPCProxyClient<AppRouter>({
|
|
1067
|
+
links: [
|
|
1068
|
+
httpBatchLink({
|
|
1069
|
+
url: 'http://localhost:3001/trpc',
|
|
1070
|
+
headers() {
|
|
1071
|
+
return {
|
|
1072
|
+
authorization: `Bearer ${getAuthToken()}`,
|
|
1073
|
+
};
|
|
1074
|
+
},
|
|
1075
|
+
}),
|
|
1076
|
+
],
|
|
1077
|
+
});
|
|
1078
|
+
```
|
|
1079
|
+
|
|
1080
|
+
### Example API Calls
|
|
1081
|
+
```typescript
|
|
1082
|
+
// Login
|
|
1083
|
+
const loginResult = await trpc.auth.login.mutate({
|
|
1084
|
+
username: 'john_doe',
|
|
1085
|
+
password: 'password123'
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
// Get classes
|
|
1089
|
+
const classes = await trpc.class.getAll.query();
|
|
1090
|
+
|
|
1091
|
+
// Create assignment
|
|
1092
|
+
const assignment = await trpc.assignment.create.mutate({
|
|
1093
|
+
classId: 'class-id',
|
|
1094
|
+
title: 'Math Homework',
|
|
1095
|
+
instructions: 'Complete problems 1-10',
|
|
1096
|
+
dueDate: '2024-01-15T23:59:59Z',
|
|
1097
|
+
maxGrade: 100,
|
|
1098
|
+
graded: true
|
|
1099
|
+
});
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
---
|
|
1103
|
+
|
|
1104
|
+
## 📝 Notes for Frontend Developers
|
|
1105
|
+
|
|
1106
|
+
1. **File Uploads**: Files are sent as base64 encoded strings in the `data` field
|
|
1107
|
+
2. **Date Handling**: All dates are ISO 8601 strings
|
|
1108
|
+
3. **Authentication**: Store JWT token and include in all requests
|
|
1109
|
+
4. **Real-time Updates**: Use Socket.IO for live updates
|
|
1110
|
+
5. **Error Handling**: Always handle tRPC errors appropriately
|
|
1111
|
+
6. **Type Safety**: Use the exported TypeScript types for full type safety
|
|
1112
|
+
|
|
1113
|
+
---
|
|
1114
|
+
|
|
1115
|
+
*Generated on: $(date)*
|
|
1116
|
+
*Version: 1.0.6*
|
|
1117
|
+
*Last Updated: January 2024*
|