bsuir-iis-api 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -16
- package/LICENSE +21 -21
- package/README.md +114 -98
- package/dist/index.d.ts +35 -3
- package/dist/index.js +124 -17
- package/dist/index.js.map +1 -1
- package/package.json +66 -66
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project are documented in this file.
|
|
4
|
-
|
|
5
|
-
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
-
and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [0.
|
|
9
|
-
|
|
10
|
-
### Added
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.2.0] - 2026-03-15
|
|
9
|
+
|
|
10
|
+
### Added (0.2.0)
|
|
11
|
+
|
|
12
|
+
- Schedule filtering helpers: `getGroupFiltered()` and `getEmployeeFiltered()`.
|
|
13
|
+
- Additional schedule DX helpers: exams-only and subgroup shortcuts.
|
|
14
|
+
- Expanded normalized schedule payload with `lessonsByDay`, `scheduleLessons`, and `examLessons`.
|
|
15
|
+
- Retry enhancements with exponential backoff, jitter, and `Retry-After` support.
|
|
16
|
+
|
|
17
|
+
## [0.1.1] - 2026-03-15
|
|
18
|
+
|
|
19
|
+
### Changed (0.1.1)
|
|
20
|
+
|
|
21
|
+
- Hardened timeout test logic to avoid CI race conditions with aborted signals.
|
|
22
|
+
- Updated release workflow to support manual dispatch and OIDC trusted publishing.
|
|
23
|
+
- Normalized `repository.url` in `package.json` for npm metadata compliance.
|
|
24
|
+
|
|
25
|
+
## [0.1.0] - 2026-03-15
|
|
26
|
+
|
|
27
|
+
### Added (0.1.0)
|
|
28
|
+
|
|
29
|
+
- Initial ESM-only TypeScript SDK implementation.
|
|
30
|
+
- Typed modules for schedules, catalogs, announcements, current week and last update.
|
|
31
|
+
- Retry/timeout-enabled HTTP client with typed errors.
|
|
32
|
+
- Unit and smoke tests with Vitest.
|
|
33
|
+
- CI, release and npm publishing scaffolding.
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 kotru21
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kotru21
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,98 +1,114 @@
|
|
|
1
|
-
# bsuir-iis-api
|
|
2
|
-
|
|
3
|
-
Type-safe ESM SDK for [BSUIR IIS API](https://iis.bsuir.by/api/v1) with support for Node.js and browser runtimes.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install bsuir-iis-api
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Quick start
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { createBsuirClient } from "bsuir-iis-api";
|
|
15
|
-
|
|
16
|
-
const client = createBsuirClient();
|
|
17
|
-
|
|
18
|
-
const schedule = await client.schedule.getGroup("053503");
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
defaultRaw: false
|
|
33
|
-
});
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
- `fetch` can be passed for custom runtime/testing.
|
|
37
|
-
- `AbortSignal` is supported by all read methods.
|
|
38
|
-
|
|
39
|
-
## API
|
|
40
|
-
|
|
41
|
-
### Schedule
|
|
42
|
-
|
|
43
|
-
- `client.schedule.getGroup(groupNumber, options?)`
|
|
44
|
-
- `client.schedule.getEmployee(urlId, options?)`
|
|
45
|
-
- `client.schedule.
|
|
46
|
-
- `client.schedule.
|
|
47
|
-
- `client.schedule.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- `client.
|
|
52
|
-
- `client.
|
|
53
|
-
- `client.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
- `client.
|
|
61
|
-
- `client.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- `client.
|
|
67
|
-
- `client.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- `
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
1
|
+
# bsuir-iis-api
|
|
2
|
+
|
|
3
|
+
Type-safe ESM SDK for [BSUIR IIS API](https://iis.bsuir.by/api/v1) with support for Node.js and browser runtimes.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install bsuir-iis-api
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createBsuirClient } from "bsuir-iis-api";
|
|
15
|
+
|
|
16
|
+
const client = createBsuirClient();
|
|
17
|
+
|
|
18
|
+
const schedule = await client.schedule.getGroup("053503");
|
|
19
|
+
console.log(schedule.lessons.length);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Client options
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const client = createBsuirClient({
|
|
26
|
+
baseUrl: "https://iis.bsuir.by/api/v1",
|
|
27
|
+
timeoutMs: 10000,
|
|
28
|
+
retries: 2,
|
|
29
|
+
retryDelayMs: 300,
|
|
30
|
+
retryMaxDelayMs: 3000,
|
|
31
|
+
retryJitter: true,
|
|
32
|
+
defaultRaw: false
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- `fetch` can be passed for custom runtime/testing.
|
|
37
|
+
- `AbortSignal` is supported by all read methods.
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
|
|
41
|
+
### Schedule
|
|
42
|
+
|
|
43
|
+
- `client.schedule.getGroup(groupNumber, options?)`
|
|
44
|
+
- `client.schedule.getEmployee(urlId, options?)`
|
|
45
|
+
- `client.schedule.getGroupFiltered(groupNumber, filter, options?)`
|
|
46
|
+
- `client.schedule.getEmployeeFiltered(urlId, filter, options?)`
|
|
47
|
+
- `client.schedule.getGroupExams(groupNumber, options?)`
|
|
48
|
+
- `client.schedule.getEmployeeExams(urlId, options?)`
|
|
49
|
+
- `client.schedule.getGroupBySubgroup(groupNumber, subgroup, options?)`
|
|
50
|
+
- `client.schedule.getEmployeeBySubgroup(urlId, subgroup, options?)`
|
|
51
|
+
- `client.schedule.getCurrentWeek(options?)`
|
|
52
|
+
- `client.schedule.getLastUpdateByGroup({ groupNumber } | { id }, options?)`
|
|
53
|
+
- `client.schedule.getLastUpdateByEmployee({ urlId } | { id }, options?)`
|
|
54
|
+
|
|
55
|
+
### Catalogs
|
|
56
|
+
|
|
57
|
+
- `client.groups.listAll(options?)`
|
|
58
|
+
- `client.employees.listAll(options?)`
|
|
59
|
+
- `client.faculties.listAll(options?)`
|
|
60
|
+
- `client.departments.listAll(options?)`
|
|
61
|
+
- `client.specialities.listAll(options?)`
|
|
62
|
+
- `client.auditories.listAll(options?)`
|
|
63
|
+
|
|
64
|
+
### Announcements
|
|
65
|
+
|
|
66
|
+
- `client.announcements.byEmployee(urlId, options?)`
|
|
67
|
+
- `client.announcements.byDepartment(id, options?)`
|
|
68
|
+
|
|
69
|
+
### Meta
|
|
70
|
+
|
|
71
|
+
- `client.currentWeek.get(options?)`
|
|
72
|
+
- `client.lastUpdate.byGroup({ groupNumber } | { id }, options?)`
|
|
73
|
+
- `client.lastUpdate.byEmployee({ urlId } | { id }, options?)`
|
|
74
|
+
|
|
75
|
+
## Errors
|
|
76
|
+
|
|
77
|
+
SDK throws typed errors:
|
|
78
|
+
|
|
79
|
+
- `BsuirApiError` for HTTP errors (contains `status`, `endpoint`, `body`)
|
|
80
|
+
- `BsuirNetworkError` for transport errors
|
|
81
|
+
- `BsuirTimeoutError` for timeouts
|
|
82
|
+
- `BsuirValidationError` for invalid input parameters
|
|
83
|
+
|
|
84
|
+
## Raw vs normalized schedule response
|
|
85
|
+
|
|
86
|
+
By default, schedule methods return normalized response with `lessons`, `lessonsByDay`,
|
|
87
|
+
`scheduleLessons`, and `examLessons`.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const raw = await client.schedule.getGroup("053503", { raw: true });
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Use `defaultRaw: true` in `createBsuirClient` to change global behavior.
|
|
94
|
+
|
|
95
|
+
Filtering example:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
const exams = await client.schedule.getGroupFiltered("053503", {
|
|
99
|
+
source: "exams",
|
|
100
|
+
lessonTypeAbbrev: ["Консультация", "Экзамен"]
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Development
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npm install
|
|
108
|
+
npm run check
|
|
109
|
+
npm run build
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -7,10 +7,18 @@ interface RequestOptions {
|
|
|
7
7
|
interface BsuirClientOptions {
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
fetch?: typeof globalThis.fetch;
|
|
10
|
+
/** Request timeout per attempt, in milliseconds. */
|
|
10
11
|
timeoutMs?: number;
|
|
12
|
+
/** Number of retry attempts for retriable GET failures. */
|
|
11
13
|
retries?: number;
|
|
14
|
+
/** Base retry delay before backoff, in milliseconds. */
|
|
12
15
|
retryDelayMs?: number;
|
|
16
|
+
/** Upper bound for retry delay, in milliseconds. */
|
|
17
|
+
retryMaxDelayMs?: number;
|
|
18
|
+
/** Enable jitter for retry backoff to avoid synchronized retries. */
|
|
19
|
+
retryJitter?: boolean;
|
|
13
20
|
userAgent?: string;
|
|
21
|
+
/** Force raw API payload for schedule endpoints by default. */
|
|
14
22
|
defaultRaw?: boolean;
|
|
15
23
|
}
|
|
16
24
|
|
|
@@ -20,8 +28,18 @@ interface ReadOptions extends RequestOptions {
|
|
|
20
28
|
|
|
21
29
|
declare function createBsuirClient(options?: BsuirClientOptions): {
|
|
22
30
|
schedule: {
|
|
23
|
-
getGroup(groupNumber: string, options?: ReadOptions
|
|
24
|
-
|
|
31
|
+
getGroup: <TRaw extends boolean | undefined = undefined>(groupNumber: string, options?: ReadOptions & {
|
|
32
|
+
raw?: TRaw;
|
|
33
|
+
}) => Promise<TRaw extends true ? ScheduleResponse : NormalizedScheduleResponse>;
|
|
34
|
+
getEmployee: <TRaw extends boolean | undefined = undefined>(urlId: string, options?: ReadOptions & {
|
|
35
|
+
raw?: TRaw;
|
|
36
|
+
}) => Promise<TRaw extends true ? ScheduleResponse : NormalizedScheduleResponse>;
|
|
37
|
+
getGroupFiltered: (groupNumber: string, filter: ScheduleFilterOptions, options?: ReadOptions) => Promise<FlattenedScheduleItem[]>;
|
|
38
|
+
getEmployeeFiltered: (urlId: string, filter: ScheduleFilterOptions, options?: ReadOptions) => Promise<FlattenedScheduleItem[]>;
|
|
39
|
+
getGroupExams(groupNumber: string, options?: ReadOptions): Promise<FlattenedScheduleItem[]>;
|
|
40
|
+
getEmployeeExams(urlId: string, options?: ReadOptions): Promise<FlattenedScheduleItem[]>;
|
|
41
|
+
getGroupBySubgroup(groupNumber: string, subgroup: number, options?: ReadOptions): Promise<FlattenedScheduleItem[]>;
|
|
42
|
+
getEmployeeBySubgroup(urlId: string, subgroup: number, options?: ReadOptions): Promise<FlattenedScheduleItem[]>;
|
|
25
43
|
getCurrentWeek(options?: ReadOptions): Promise<number>;
|
|
26
44
|
getLastUpdateByGroup(params: {
|
|
27
45
|
groupNumber: string;
|
|
@@ -241,10 +259,24 @@ interface FlattenedScheduleItem extends ScheduleItem {
|
|
|
241
259
|
day: Weekday | null;
|
|
242
260
|
source: "schedules" | "exams";
|
|
243
261
|
}
|
|
262
|
+
type FlattenedLessonsByDay = Partial<Record<Weekday, FlattenedScheduleItem[]>>;
|
|
263
|
+
interface ScheduleFilterOptions {
|
|
264
|
+
source?: "schedules" | "exams";
|
|
265
|
+
weekday?: Weekday;
|
|
266
|
+
weekNumber?: number;
|
|
267
|
+
subgroup?: number;
|
|
268
|
+
lessonTypeAbbrev?: string | string[];
|
|
269
|
+
subjectQuery?: string;
|
|
270
|
+
employeeUrlId?: string;
|
|
271
|
+
auditory?: string;
|
|
272
|
+
}
|
|
244
273
|
interface NormalizedScheduleResponse extends Omit<ScheduleResponse, "schedules" | "exams"> {
|
|
245
274
|
schedules: WeekScheduleMap;
|
|
246
275
|
exams: ScheduleItem[];
|
|
247
276
|
lessons: FlattenedScheduleItem[];
|
|
277
|
+
lessonsByDay: FlattenedLessonsByDay;
|
|
278
|
+
scheduleLessons: FlattenedScheduleItem[];
|
|
279
|
+
examLessons: FlattenedScheduleItem[];
|
|
248
280
|
}
|
|
249
281
|
|
|
250
|
-
export { type Announcement, type ApiDateResponse, type Auditory, type AuditoryDepartment, type AuditoryType, BsuirApiError, type BsuirClient, type BsuirClientOptions, BsuirNetworkError, BsuirTimeoutError, BsuirValidationError, type BuildingNumber, type Department, type EducationForm, type Employee, type EmployeeCatalogItem, type Faculty, type FlattenedScheduleItem, type LessonStudentGroup, type Maybe, type NormalizedScheduleResponse, type ScheduleItem, type ScheduleResponse, type Speciality, type StudentGroupCatalogItem, type StudentGroupShort, type WeekScheduleMap, type Weekday, createBsuirClient };
|
|
282
|
+
export { type Announcement, type ApiDateResponse, type Auditory, type AuditoryDepartment, type AuditoryType, BsuirApiError, type BsuirClient, type BsuirClientOptions, BsuirNetworkError, BsuirTimeoutError, BsuirValidationError, type BuildingNumber, type Department, type EducationForm, type Employee, type EmployeeCatalogItem, type Faculty, type FlattenedLessonsByDay, type FlattenedScheduleItem, type LessonStudentGroup, type Maybe, type NormalizedScheduleResponse, type ScheduleFilterOptions, type ScheduleItem, type ScheduleResponse, type Speciality, type StudentGroupCatalogItem, type StudentGroupShort, type WeekScheduleMap, type Weekday, createBsuirClient };
|
package/dist/index.js
CHANGED
|
@@ -81,6 +81,33 @@ function mergeSignals(signal, timeoutMs) {
|
|
|
81
81
|
function sleep(ms) {
|
|
82
82
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
83
83
|
}
|
|
84
|
+
function parseRetryAfterMs(retryAfter) {
|
|
85
|
+
if (!retryAfter) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const asSeconds = Number(retryAfter);
|
|
89
|
+
if (!Number.isNaN(asSeconds)) {
|
|
90
|
+
return Math.max(0, Math.floor(asSeconds * 1e3));
|
|
91
|
+
}
|
|
92
|
+
const dateValue = Date.parse(retryAfter);
|
|
93
|
+
if (!Number.isNaN(dateValue)) {
|
|
94
|
+
return Math.max(0, dateValue - Date.now());
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
function getRetryDelayMs(config, attempt, retryAfterHeader) {
|
|
99
|
+
const retryAfterDelay = parseRetryAfterMs(retryAfterHeader ?? null);
|
|
100
|
+
if (retryAfterDelay !== null) {
|
|
101
|
+
return Math.min(retryAfterDelay, config.retryMaxDelayMs);
|
|
102
|
+
}
|
|
103
|
+
const exponent = Math.max(0, attempt);
|
|
104
|
+
const baseDelay = Math.min(config.retryDelayMs * 2 ** exponent, config.retryMaxDelayMs);
|
|
105
|
+
if (!config.retryJitter) {
|
|
106
|
+
return baseDelay;
|
|
107
|
+
}
|
|
108
|
+
const jitterFactor = 0.75 + Math.random() * 0.5;
|
|
109
|
+
return Math.floor(baseDelay * jitterFactor);
|
|
110
|
+
}
|
|
84
111
|
async function parseBody(response) {
|
|
85
112
|
const contentType = response.headers.get("content-type") ?? "";
|
|
86
113
|
if (!contentType.includes("application/json")) {
|
|
@@ -94,7 +121,6 @@ async function parseBody(response) {
|
|
|
94
121
|
}
|
|
95
122
|
async function requestJson(config, path, options = {}) {
|
|
96
123
|
const endpoint = buildUrl(config.baseUrl, path, options.query);
|
|
97
|
-
const requestSignal = mergeSignals(options.signal, config.timeoutMs);
|
|
98
124
|
const headers = new Headers({
|
|
99
125
|
Accept: "application/json"
|
|
100
126
|
});
|
|
@@ -102,6 +128,7 @@ async function requestJson(config, path, options = {}) {
|
|
|
102
128
|
headers.set("User-Agent", config.userAgent);
|
|
103
129
|
}
|
|
104
130
|
for (let attempt = 0; attempt <= config.retries; attempt += 1) {
|
|
131
|
+
const requestSignal = mergeSignals(options.signal, config.timeoutMs);
|
|
105
132
|
try {
|
|
106
133
|
const response = await config.fetchImpl(endpoint, {
|
|
107
134
|
method: "GET",
|
|
@@ -111,7 +138,8 @@ async function requestJson(config, path, options = {}) {
|
|
|
111
138
|
if (!response.ok) {
|
|
112
139
|
const errorBody = await parseBody(response);
|
|
113
140
|
if (attempt < config.retries && RETRIABLE_STATUS_CODES.has(response.status)) {
|
|
114
|
-
|
|
141
|
+
const delayMs = getRetryDelayMs(config, attempt, response.headers.get("retry-after"));
|
|
142
|
+
await sleep(delayMs);
|
|
115
143
|
continue;
|
|
116
144
|
}
|
|
117
145
|
throw new BsuirApiError(
|
|
@@ -137,7 +165,8 @@ async function requestJson(config, path, options = {}) {
|
|
|
137
165
|
);
|
|
138
166
|
}
|
|
139
167
|
if (attempt < config.retries) {
|
|
140
|
-
|
|
168
|
+
const delayMs = getRetryDelayMs(config, attempt);
|
|
169
|
+
await sleep(delayMs);
|
|
141
170
|
continue;
|
|
142
171
|
}
|
|
143
172
|
throw new BsuirNetworkError(`Network error while requesting ${path}`, endpoint, error);
|
|
@@ -277,8 +306,11 @@ var WEEKDAYS = [
|
|
|
277
306
|
];
|
|
278
307
|
function normalizeSchedule(response) {
|
|
279
308
|
const lessons = [];
|
|
309
|
+
const lessonsByDay = {};
|
|
280
310
|
for (const day of WEEKDAYS) {
|
|
281
311
|
const dayItems = response.schedules[day] ?? [];
|
|
312
|
+
const flattenedDayItems = dayItems.map((item) => ({ ...item, day, source: "schedules" }));
|
|
313
|
+
lessonsByDay[day] = flattenedDayItems;
|
|
282
314
|
for (const item of dayItems) {
|
|
283
315
|
lessons.push({ ...item, day, source: "schedules" });
|
|
284
316
|
}
|
|
@@ -291,27 +323,100 @@ function normalizeSchedule(response) {
|
|
|
291
323
|
source: "exams"
|
|
292
324
|
});
|
|
293
325
|
}
|
|
326
|
+
const scheduleLessons = lessons.filter((lesson) => lesson.source === "schedules");
|
|
327
|
+
const examLessons = lessons.filter((lesson) => lesson.source === "exams");
|
|
294
328
|
return {
|
|
295
329
|
...response,
|
|
296
|
-
lessons
|
|
330
|
+
lessons,
|
|
331
|
+
lessonsByDay,
|
|
332
|
+
scheduleLessons,
|
|
333
|
+
examLessons
|
|
297
334
|
};
|
|
298
335
|
}
|
|
336
|
+
function matchesFilter(item, filter) {
|
|
337
|
+
if (filter.source && item.source !== filter.source) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
if (filter.weekday && item.day !== filter.weekday) {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
if (typeof filter.weekNumber === "number" && !item.weekNumber.includes(filter.weekNumber)) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
if (typeof filter.subgroup === "number" && item.numSubgroup !== filter.subgroup) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
if (filter.lessonTypeAbbrev) {
|
|
350
|
+
const types = Array.isArray(filter.lessonTypeAbbrev) ? filter.lessonTypeAbbrev : [filter.lessonTypeAbbrev];
|
|
351
|
+
if (!types.includes(item.lessonTypeAbbrev)) {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (filter.subjectQuery) {
|
|
356
|
+
const query = filter.subjectQuery.toLowerCase();
|
|
357
|
+
const haystack = `${item.subject} ${item.subjectFullName} ${item.note ?? ""}`.toLowerCase();
|
|
358
|
+
if (!haystack.includes(query)) {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (filter.employeeUrlId) {
|
|
363
|
+
const employeeMatch = item.employees?.some((employee) => employee.urlId === filter.employeeUrlId);
|
|
364
|
+
if (!employeeMatch) {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (filter.auditory && !item.auditories.includes(filter.auditory)) {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
function filterLessons(response, filter) {
|
|
374
|
+
return response.lessons.filter((item) => matchesFilter(item, filter));
|
|
375
|
+
}
|
|
299
376
|
function createScheduleModule(config) {
|
|
377
|
+
async function getGroup(groupNumber, options = {}) {
|
|
378
|
+
assertNonEmptyString(groupNumber, "groupNumber");
|
|
379
|
+
const response = await requestJson(config, "/schedule", {
|
|
380
|
+
query: { studentGroup: groupNumber },
|
|
381
|
+
signal: options.signal
|
|
382
|
+
});
|
|
383
|
+
const result = options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);
|
|
384
|
+
return result;
|
|
385
|
+
}
|
|
386
|
+
async function getEmployee(urlId, options = {}) {
|
|
387
|
+
assertNonEmptyString(urlId, "urlId");
|
|
388
|
+
const response = await requestJson(config, `/employees/schedule/${urlId}`, {
|
|
389
|
+
signal: options.signal
|
|
390
|
+
});
|
|
391
|
+
const result = options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);
|
|
392
|
+
return result;
|
|
393
|
+
}
|
|
394
|
+
async function getGroupFiltered(groupNumber, filter, options = {}) {
|
|
395
|
+
const normalized = await getGroup(groupNumber, { ...options, raw: false });
|
|
396
|
+
return filterLessons(normalized, filter);
|
|
397
|
+
}
|
|
398
|
+
async function getEmployeeFiltered(urlId, filter, options = {}) {
|
|
399
|
+
const normalized = await getEmployee(urlId, { ...options, raw: false });
|
|
400
|
+
return filterLessons(normalized, filter);
|
|
401
|
+
}
|
|
300
402
|
return {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
});
|
|
307
|
-
return options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);
|
|
403
|
+
getGroup,
|
|
404
|
+
getEmployee,
|
|
405
|
+
getGroupFiltered,
|
|
406
|
+
getEmployeeFiltered,
|
|
407
|
+
async getGroupExams(groupNumber, options = {}) {
|
|
408
|
+
return getGroupFiltered(groupNumber, { source: "exams" }, options);
|
|
308
409
|
},
|
|
309
|
-
async
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return
|
|
410
|
+
async getEmployeeExams(urlId, options = {}) {
|
|
411
|
+
return getEmployeeFiltered(urlId, { source: "exams" }, options);
|
|
412
|
+
},
|
|
413
|
+
async getGroupBySubgroup(groupNumber, subgroup, options = {}) {
|
|
414
|
+
assertPositiveInt(subgroup, "subgroup");
|
|
415
|
+
return getGroupFiltered(groupNumber, { source: "schedules", subgroup }, options);
|
|
416
|
+
},
|
|
417
|
+
async getEmployeeBySubgroup(urlId, subgroup, options = {}) {
|
|
418
|
+
assertPositiveInt(subgroup, "subgroup");
|
|
419
|
+
return getEmployeeFiltered(urlId, { source: "schedules", subgroup }, options);
|
|
315
420
|
},
|
|
316
421
|
async getCurrentWeek(options = {}) {
|
|
317
422
|
return requestJson(config, "/schedule/current-week", { signal: options.signal });
|
|
@@ -376,6 +481,8 @@ function createInternalConfig(options = {}) {
|
|
|
376
481
|
timeoutMs: options.timeoutMs ?? 1e4,
|
|
377
482
|
retries: options.retries ?? 1,
|
|
378
483
|
retryDelayMs: options.retryDelayMs ?? 300,
|
|
484
|
+
retryMaxDelayMs: options.retryMaxDelayMs ?? 3e3,
|
|
485
|
+
retryJitter: options.retryJitter ?? true,
|
|
379
486
|
userAgent: options.userAgent,
|
|
380
487
|
defaultRaw: options.defaultRaw ?? false
|
|
381
488
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/errors.ts","../src/utils/guards.ts","../src/client/http.ts","../src/modules/announcements.ts","../src/modules/auditories.ts","../src/modules/currentWeek.ts","../src/modules/departments.ts","../src/modules/employees.ts","../src/modules/faculties.ts","../src/modules/groups.ts","../src/modules/lastUpdate.ts","../src/modules/schedule.ts","../src/modules/specialities.ts","../src/client/createClient.ts"],"sourcesContent":["export class BsuirApiError extends Error {\r\n readonly status: number;\r\n readonly endpoint: string;\r\n readonly body: unknown;\r\n\r\n constructor(message: string, status: number, endpoint: string, body: unknown) {\r\n super(message);\r\n this.name = \"BsuirApiError\";\r\n this.status = status;\r\n this.endpoint = endpoint;\r\n this.body = body;\r\n }\r\n}\r\n\r\nexport class BsuirNetworkError extends Error {\r\n readonly endpoint: string;\r\n readonly causeError: unknown;\r\n\r\n constructor(message: string, endpoint: string, causeError: unknown) {\r\n super(message);\r\n this.name = \"BsuirNetworkError\";\r\n this.endpoint = endpoint;\r\n this.causeError = causeError;\r\n }\r\n}\r\n\r\nexport class BsuirTimeoutError extends Error {\r\n readonly endpoint: string;\r\n readonly timeoutMs: number;\r\n\r\n constructor(message: string, endpoint: string, timeoutMs: number) {\r\n super(message);\r\n this.name = \"BsuirTimeoutError\";\r\n this.endpoint = endpoint;\r\n this.timeoutMs = timeoutMs;\r\n }\r\n}\r\n\r\nexport class BsuirValidationError extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = \"BsuirValidationError\";\r\n }\r\n}\r\n","import { BsuirValidationError } from \"../client/errors\";\r\n\r\nexport function assertNonEmptyString(value: string, fieldName: string): void {\r\n if (!value || value.trim().length === 0) {\r\n throw new BsuirValidationError(`'${fieldName}' must be a non-empty string`);\r\n }\r\n}\r\n\r\nexport function assertPositiveInt(value: number, fieldName: string): void {\r\n if (!Number.isInteger(value) || value <= 0) {\r\n throw new BsuirValidationError(`'${fieldName}' must be a positive integer`);\r\n }\r\n}\r\n\r\nexport function isAbortError(error: unknown): boolean {\r\n return error instanceof DOMException && error.name === \"AbortError\";\r\n}\r\n","import { BsuirApiError, BsuirNetworkError, BsuirTimeoutError } from \"./errors\";\r\nimport type { InternalClientConfig, QueryParams, RequestOptions } from \"./types\";\r\nimport { isAbortError } from \"../utils/guards\";\r\n\r\nconst RETRIABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504]);\r\n\r\nfunction buildUrl(baseUrl: string, path: string, query?: QueryParams): string {\r\n const normalizedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\r\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\r\n const url = new URL(`${normalizedBase}${normalizedPath}`);\r\n\r\n if (query) {\r\n for (const [key, value] of Object.entries(query)) {\r\n if (value === undefined || value === null) {\r\n continue;\r\n }\r\n url.searchParams.set(key, String(value));\r\n }\r\n }\r\n\r\n return url.toString();\r\n}\r\n\r\nfunction mergeSignals(signal: AbortSignal | undefined, timeoutMs: number): AbortSignal {\r\n if (typeof AbortSignal.any === \"function\") {\r\n return AbortSignal.any([AbortSignal.timeout(timeoutMs), signal].filter(Boolean) as AbortSignal[]);\r\n }\r\n\r\n if (signal) {\r\n return signal;\r\n }\r\n\r\n return AbortSignal.timeout(timeoutMs);\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nasync function parseBody(response: Response): Promise<unknown> {\r\n const contentType = response.headers.get(\"content-type\") ?? \"\";\r\n if (!contentType.includes(\"application/json\")) {\r\n return response.text();\r\n }\r\n\r\n try {\r\n return await response.json();\r\n } catch {\r\n throw new BsuirApiError(\"Invalid JSON response payload\", response.status, response.url, null);\r\n }\r\n}\r\n\r\nexport async function requestJson<T>(\r\n config: InternalClientConfig,\r\n path: string,\r\n options: RequestOptions = {}\r\n): Promise<T> {\r\n const endpoint = buildUrl(config.baseUrl, path, options.query);\r\n const requestSignal = mergeSignals(options.signal, config.timeoutMs);\r\n const headers = new Headers({\r\n Accept: \"application/json\"\r\n });\r\n\r\n if (config.userAgent) {\r\n headers.set(\"User-Agent\", config.userAgent);\r\n }\r\n\r\n for (let attempt = 0; attempt <= config.retries; attempt += 1) {\r\n try {\r\n const response = await config.fetchImpl(endpoint, {\r\n method: \"GET\",\r\n headers,\r\n signal: requestSignal\r\n });\r\n\r\n if (!response.ok) {\r\n const errorBody = await parseBody(response);\r\n if (attempt < config.retries && RETRIABLE_STATUS_CODES.has(response.status)) {\r\n await sleep(config.retryDelayMs * (attempt + 1));\r\n continue;\r\n }\r\n throw new BsuirApiError(\r\n `BSUIR API returned HTTP ${response.status} for ${path}`,\r\n response.status,\r\n endpoint,\r\n errorBody\r\n );\r\n }\r\n\r\n return (await parseBody(response)) as T;\r\n } catch (error) {\r\n if (error instanceof BsuirApiError) {\r\n throw error;\r\n }\r\n\r\n if (isAbortError(error)) {\r\n if (options.signal?.aborted) {\r\n throw error;\r\n }\r\n throw new BsuirTimeoutError(\r\n `Request timed out after ${config.timeoutMs}ms: ${path}`,\r\n endpoint,\r\n config.timeoutMs\r\n );\r\n }\r\n\r\n if (attempt < config.retries) {\r\n await sleep(config.retryDelayMs * (attempt + 1));\r\n continue;\r\n }\r\n\r\n throw new BsuirNetworkError(`Network error while requesting ${path}`, endpoint, error);\r\n }\r\n }\r\n\r\n throw new BsuirNetworkError(`Network error while requesting ${path}`, endpoint, null);\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport { assertNonEmptyString, assertPositiveInt } from \"../utils/guards\";\r\nimport type { Announcement } from \"../types/announcement\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createAnnouncementsModule(config: InternalClientConfig) {\r\n return {\r\n async byEmployee(urlId: string, options: ReadOptions = {}): Promise<Announcement[]> {\r\n assertNonEmptyString(urlId, \"urlId\");\r\n return requestJson<Announcement[]>(config, \"/announcements/employees\", {\r\n query: { \"url-id\": urlId },\r\n signal: options.signal\r\n });\r\n },\r\n\r\n async byDepartment(id: number, options: ReadOptions = {}): Promise<Announcement[]> {\r\n assertPositiveInt(id, \"id\");\r\n return requestJson<Announcement[]>(config, \"/announcements/departments\", {\r\n query: { id },\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport type { Auditory } from \"../types/catalog\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createAuditoriesModule(config: InternalClientConfig) {\r\n return {\r\n async listAll(options: ReadOptions = {}): Promise<Auditory[]> {\r\n return requestJson<Auditory[]>(config, \"/auditories\", {\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createCurrentWeekModule(config: InternalClientConfig) {\r\n return {\r\n async get(options: ReadOptions = {}): Promise<number> {\r\n return requestJson<number>(config, \"/schedule/current-week\", {\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport type { Department } from \"../types/catalog\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createDepartmentsModule(config: InternalClientConfig) {\r\n return {\r\n async listAll(options: ReadOptions = {}): Promise<Department[]> {\r\n return requestJson<Department[]>(config, \"/departments\", {\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport type { EmployeeCatalogItem } from \"../types/employee\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createEmployeesModule(config: InternalClientConfig) {\r\n return {\r\n async listAll(options: ReadOptions = {}): Promise<EmployeeCatalogItem[]> {\r\n return requestJson<EmployeeCatalogItem[]>(config, \"/employees/all\", {\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport type { Faculty } from \"../types/catalog\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createFacultiesModule(config: InternalClientConfig) {\r\n return {\r\n async listAll(options: ReadOptions = {}): Promise<Faculty[]> {\r\n return requestJson<Faculty[]>(config, \"/faculties\", {\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport type { StudentGroupCatalogItem } from \"../types/catalog\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createGroupsModule(config: InternalClientConfig) {\r\n return {\r\n async listAll(options: ReadOptions = {}): Promise<StudentGroupCatalogItem[]> {\r\n return requestJson<StudentGroupCatalogItem[]>(config, \"/student-groups\", {\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport { assertNonEmptyString, assertPositiveInt } from \"../utils/guards\";\r\nimport type { ApiDateResponse } from \"../types/common\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createLastUpdateModule(config: InternalClientConfig) {\r\n return {\r\n async byGroup(\r\n params: { groupNumber: string } | { id: number },\r\n options: ReadOptions = {}\r\n ): Promise<ApiDateResponse> {\r\n let query: Record<string, string | number>;\r\n if (\"groupNumber\" in params) {\r\n assertNonEmptyString(params.groupNumber, \"groupNumber\");\r\n query = { groupNumber: params.groupNumber };\r\n } else {\r\n assertPositiveInt(params.id, \"id\");\r\n query = { id: params.id };\r\n }\r\n\r\n return requestJson<ApiDateResponse>(config, \"/last-update-date/student-group\", {\r\n query,\r\n signal: options.signal\r\n });\r\n },\r\n\r\n async byEmployee(\r\n params: { urlId: string } | { id: number },\r\n options: ReadOptions = {}\r\n ): Promise<ApiDateResponse> {\r\n let query: Record<string, string | number>;\r\n if (\"urlId\" in params) {\r\n assertNonEmptyString(params.urlId, \"urlId\");\r\n query = { \"url-id\": params.urlId };\r\n } else {\r\n assertPositiveInt(params.id, \"id\");\r\n query = { id: params.id };\r\n }\r\n\r\n return requestJson<ApiDateResponse>(config, \"/last-update-date/employee\", {\r\n query,\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport { assertNonEmptyString, assertPositiveInt } from \"../utils/guards\";\r\nimport type {\r\n FlattenedScheduleItem,\r\n NormalizedScheduleResponse,\r\n ScheduleResponse\r\n} from \"../types/schedule\";\r\nimport type { ApiDateResponse } from \"../types/common\";\r\nimport type { Weekday } from \"../types/common\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nconst WEEKDAYS: Weekday[] = [\r\n \"Понедельник\",\r\n \"Вторник\",\r\n \"Среда\",\r\n \"Четверг\",\r\n \"Пятница\",\r\n \"Суббота\"\r\n];\r\n\r\nfunction normalizeSchedule(response: ScheduleResponse): NormalizedScheduleResponse {\r\n const lessons: FlattenedScheduleItem[] = [];\r\n for (const day of WEEKDAYS) {\r\n const dayItems = response.schedules[day] ?? [];\r\n for (const item of dayItems) {\r\n lessons.push({ ...item, day, source: \"schedules\" });\r\n }\r\n }\r\n\r\n for (const exam of response.exams) {\r\n lessons.push({\r\n ...exam,\r\n day: null,\r\n // Exams are not grouped by weekday in API response.\r\n source: \"exams\"\r\n });\r\n }\r\n\r\n return {\r\n ...response,\r\n lessons\r\n };\r\n}\r\n\r\nexport function createScheduleModule(config: InternalClientConfig) {\r\n return {\r\n async getGroup(\r\n groupNumber: string,\r\n options: ReadOptions = {}\r\n ): Promise<ScheduleResponse | NormalizedScheduleResponse> {\r\n assertNonEmptyString(groupNumber, \"groupNumber\");\r\n const response = await requestJson<ScheduleResponse>(config, \"/schedule\", {\r\n query: { studentGroup: groupNumber },\r\n signal: options.signal\r\n });\r\n return options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);\r\n },\r\n\r\n async getEmployee(\r\n urlId: string,\r\n options: ReadOptions = {}\r\n ): Promise<ScheduleResponse | NormalizedScheduleResponse> {\r\n assertNonEmptyString(urlId, \"urlId\");\r\n const response = await requestJson<ScheduleResponse>(config, `/employees/schedule/${urlId}`, {\r\n signal: options.signal\r\n });\r\n return options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);\r\n },\r\n\r\n async getCurrentWeek(options: ReadOptions = {}): Promise<number> {\r\n return requestJson<number>(config, \"/schedule/current-week\", { signal: options.signal });\r\n },\r\n\r\n async getLastUpdateByGroup(\r\n params: { groupNumber: string } | { id: number },\r\n options: ReadOptions = {}\r\n ): Promise<ApiDateResponse> {\r\n let query: Record<string, string | number>;\r\n if (\"groupNumber\" in params) {\r\n assertNonEmptyString(params.groupNumber, \"groupNumber\");\r\n query = { groupNumber: params.groupNumber };\r\n } else {\r\n assertPositiveInt(params.id, \"id\");\r\n query = { id: params.id };\r\n }\r\n return requestJson<ApiDateResponse>(config, \"/last-update-date/student-group\", {\r\n query,\r\n signal: options.signal\r\n });\r\n },\r\n\r\n async getLastUpdateByEmployee(\r\n params: { urlId: string } | { id: number },\r\n options: ReadOptions = {}\r\n ): Promise<ApiDateResponse> {\r\n let query: Record<string, string | number>;\r\n if (\"urlId\" in params) {\r\n assertNonEmptyString(params.urlId, \"urlId\");\r\n query = { \"url-id\": params.urlId };\r\n } else {\r\n assertPositiveInt(params.id, \"id\");\r\n query = { id: params.id };\r\n }\r\n return requestJson<ApiDateResponse>(config, \"/last-update-date/employee\", {\r\n query,\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { InternalClientConfig } from \"../client/types\";\r\nimport { requestJson } from \"../client/http\";\r\nimport type { Speciality } from \"../types/catalog\";\r\nimport type { ReadOptions } from \"./types\";\r\n\r\nexport function createSpecialitiesModule(config: InternalClientConfig) {\r\n return {\r\n async listAll(options: ReadOptions = {}): Promise<Speciality[]> {\r\n return requestJson<Speciality[]>(config, \"/specialities\", {\r\n signal: options.signal\r\n });\r\n }\r\n };\r\n}\r\n","import type { BsuirClientOptions, InternalClientConfig } from \"./types\";\r\nimport { createAnnouncementsModule } from \"../modules/announcements\";\r\nimport { createAuditoriesModule } from \"../modules/auditories\";\r\nimport { createCurrentWeekModule } from \"../modules/currentWeek\";\r\nimport { createDepartmentsModule } from \"../modules/departments\";\r\nimport { createEmployeesModule } from \"../modules/employees\";\r\nimport { createFacultiesModule } from \"../modules/faculties\";\r\nimport { createGroupsModule } from \"../modules/groups\";\r\nimport { createLastUpdateModule } from \"../modules/lastUpdate\";\r\nimport { createScheduleModule } from \"../modules/schedule\";\r\nimport { createSpecialitiesModule } from \"../modules/specialities\";\r\n\r\nconst DEFAULT_BASE_URL = \"https://iis.bsuir.by/api/v1\";\r\n\r\nfunction resolveFetch(customFetch?: typeof globalThis.fetch): typeof globalThis.fetch {\r\n if (customFetch) {\r\n return customFetch;\r\n }\r\n\r\n if (typeof globalThis.fetch !== \"function\") {\r\n throw new Error(\"Global fetch is unavailable. Provide 'fetch' in createBsuirClient options.\");\r\n }\r\n\r\n return globalThis.fetch;\r\n}\r\n\r\nfunction createInternalConfig(options: BsuirClientOptions = {}): InternalClientConfig {\r\n return {\r\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\r\n fetchImpl: resolveFetch(options.fetch),\r\n timeoutMs: options.timeoutMs ?? 10_000,\r\n retries: options.retries ?? 1,\r\n retryDelayMs: options.retryDelayMs ?? 300,\r\n userAgent: options.userAgent,\r\n defaultRaw: options.defaultRaw ?? false\r\n };\r\n}\r\n\r\nexport function createBsuirClient(options: BsuirClientOptions = {}) {\r\n const config = createInternalConfig(options);\r\n\r\n return {\r\n schedule: createScheduleModule(config),\r\n groups: createGroupsModule(config),\r\n employees: createEmployeesModule(config),\r\n faculties: createFacultiesModule(config),\r\n departments: createDepartmentsModule(config),\r\n specialities: createSpecialitiesModule(config),\r\n announcements: createAnnouncementsModule(config),\r\n auditories: createAuditoriesModule(config),\r\n lastUpdate: createLastUpdateModule(config),\r\n currentWeek: createCurrentWeekModule(config)\r\n };\r\n}\r\n\r\nexport type BsuirClient = ReturnType<typeof createBsuirClient>;\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client/errors.ts","../src/utils/guards.ts","../src/client/http.ts","../src/modules/announcements.ts","../src/modules/auditories.ts","../src/modules/currentWeek.ts","../src/modules/departments.ts","../src/modules/employees.ts","../src/modules/faculties.ts","../src/modules/groups.ts","../src/modules/lastUpdate.ts","../src/modules/schedule.ts","../src/modules/specialities.ts","../src/client/createClient.ts"],"sourcesContent":["export class BsuirApiError extends Error {\n readonly status: number;\n readonly endpoint: string;\n readonly body: unknown;\n\n constructor(message: string, status: number, endpoint: string, body: unknown) {\n super(message);\n this.name = \"BsuirApiError\";\n this.status = status;\n this.endpoint = endpoint;\n this.body = body;\n }\n}\n\nexport class BsuirNetworkError extends Error {\n readonly endpoint: string;\n readonly causeError: unknown;\n\n constructor(message: string, endpoint: string, causeError: unknown) {\n super(message);\n this.name = \"BsuirNetworkError\";\n this.endpoint = endpoint;\n this.causeError = causeError;\n }\n}\n\nexport class BsuirTimeoutError extends Error {\n readonly endpoint: string;\n readonly timeoutMs: number;\n\n constructor(message: string, endpoint: string, timeoutMs: number) {\n super(message);\n this.name = \"BsuirTimeoutError\";\n this.endpoint = endpoint;\n this.timeoutMs = timeoutMs;\n }\n}\n\nexport class BsuirValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BsuirValidationError\";\n }\n}\n","import { BsuirValidationError } from \"../client/errors\";\n\nexport function assertNonEmptyString(value: string, fieldName: string): void {\n if (!value || value.trim().length === 0) {\n throw new BsuirValidationError(`'${fieldName}' must be a non-empty string`);\n }\n}\n\nexport function assertPositiveInt(value: number, fieldName: string): void {\n if (!Number.isInteger(value) || value <= 0) {\n throw new BsuirValidationError(`'${fieldName}' must be a positive integer`);\n }\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === \"AbortError\";\n}\n","import { BsuirApiError, BsuirNetworkError, BsuirTimeoutError } from \"./errors\";\nimport type { InternalClientConfig, QueryParams, RequestOptions } from \"./types\";\nimport { isAbortError } from \"../utils/guards\";\n\nconst RETRIABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504]);\n\nfunction buildUrl(baseUrl: string, path: string, query?: QueryParams): string {\n const normalizedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n const url = new URL(`${normalizedBase}${normalizedPath}`);\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n url.searchParams.set(key, String(value));\n }\n }\n\n return url.toString();\n}\n\nfunction mergeSignals(signal: AbortSignal | undefined, timeoutMs: number): AbortSignal {\n if (typeof AbortSignal.any === \"function\") {\n return AbortSignal.any([AbortSignal.timeout(timeoutMs), signal].filter(Boolean) as AbortSignal[]);\n }\n\n if (signal) {\n return signal;\n }\n\n return AbortSignal.timeout(timeoutMs);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseRetryAfterMs(retryAfter: string | null): number | null {\n if (!retryAfter) {\n return null;\n }\n\n const asSeconds = Number(retryAfter);\n if (!Number.isNaN(asSeconds)) {\n return Math.max(0, Math.floor(asSeconds * 1000));\n }\n\n const dateValue = Date.parse(retryAfter);\n if (!Number.isNaN(dateValue)) {\n return Math.max(0, dateValue - Date.now());\n }\n\n return null;\n}\n\nfunction getRetryDelayMs(\n config: InternalClientConfig,\n attempt: number,\n retryAfterHeader?: string | null\n): number {\n const retryAfterDelay = parseRetryAfterMs(retryAfterHeader ?? null);\n if (retryAfterDelay !== null) {\n return Math.min(retryAfterDelay, config.retryMaxDelayMs);\n }\n\n const exponent = Math.max(0, attempt);\n const baseDelay = Math.min(config.retryDelayMs * 2 ** exponent, config.retryMaxDelayMs);\n if (!config.retryJitter) {\n return baseDelay;\n }\n\n const jitterFactor = 0.75 + Math.random() * 0.5;\n return Math.floor(baseDelay * jitterFactor);\n}\n\nasync function parseBody(response: Response): Promise<unknown> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (!contentType.includes(\"application/json\")) {\n return response.text();\n }\n\n try {\n return await response.json();\n } catch {\n throw new BsuirApiError(\"Invalid JSON response payload\", response.status, response.url, null);\n }\n}\n\nexport async function requestJson<T>(\n config: InternalClientConfig,\n path: string,\n options: RequestOptions = {}\n): Promise<T> {\n const endpoint = buildUrl(config.baseUrl, path, options.query);\n const headers = new Headers({\n Accept: \"application/json\"\n });\n\n if (config.userAgent) {\n headers.set(\"User-Agent\", config.userAgent);\n }\n\n for (let attempt = 0; attempt <= config.retries; attempt += 1) {\n const requestSignal = mergeSignals(options.signal, config.timeoutMs);\n try {\n const response = await config.fetchImpl(endpoint, {\n method: \"GET\",\n headers,\n signal: requestSignal\n });\n\n if (!response.ok) {\n const errorBody = await parseBody(response);\n if (attempt < config.retries && RETRIABLE_STATUS_CODES.has(response.status)) {\n const delayMs = getRetryDelayMs(config, attempt, response.headers.get(\"retry-after\"));\n await sleep(delayMs);\n continue;\n }\n throw new BsuirApiError(\n `BSUIR API returned HTTP ${response.status} for ${path}`,\n response.status,\n endpoint,\n errorBody\n );\n }\n\n return (await parseBody(response)) as T;\n } catch (error) {\n if (error instanceof BsuirApiError) {\n throw error;\n }\n\n if (isAbortError(error)) {\n if (options.signal?.aborted) {\n throw error;\n }\n throw new BsuirTimeoutError(\n `Request timed out after ${config.timeoutMs}ms: ${path}`,\n endpoint,\n config.timeoutMs\n );\n }\n\n if (attempt < config.retries) {\n const delayMs = getRetryDelayMs(config, attempt);\n await sleep(delayMs);\n continue;\n }\n\n throw new BsuirNetworkError(`Network error while requesting ${path}`, endpoint, error);\n }\n }\n\n throw new BsuirNetworkError(`Network error while requesting ${path}`, endpoint, null);\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertNonEmptyString, assertPositiveInt } from \"../utils/guards\";\nimport type { Announcement } from \"../types/announcement\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createAnnouncementsModule(config: InternalClientConfig) {\n return {\n async byEmployee(urlId: string, options: ReadOptions = {}): Promise<Announcement[]> {\n assertNonEmptyString(urlId, \"urlId\");\n return requestJson<Announcement[]>(config, \"/announcements/employees\", {\n query: { \"url-id\": urlId },\n signal: options.signal\n });\n },\n\n async byDepartment(id: number, options: ReadOptions = {}): Promise<Announcement[]> {\n assertPositiveInt(id, \"id\");\n return requestJson<Announcement[]>(config, \"/announcements/departments\", {\n query: { id },\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { Auditory } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createAuditoriesModule(config: InternalClientConfig) {\n return {\n async listAll(options: ReadOptions = {}): Promise<Auditory[]> {\n return requestJson<Auditory[]>(config, \"/auditories\", {\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createCurrentWeekModule(config: InternalClientConfig) {\n return {\n async get(options: ReadOptions = {}): Promise<number> {\n return requestJson<number>(config, \"/schedule/current-week\", {\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { Department } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createDepartmentsModule(config: InternalClientConfig) {\n return {\n async listAll(options: ReadOptions = {}): Promise<Department[]> {\n return requestJson<Department[]>(config, \"/departments\", {\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { EmployeeCatalogItem } from \"../types/employee\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createEmployeesModule(config: InternalClientConfig) {\n return {\n async listAll(options: ReadOptions = {}): Promise<EmployeeCatalogItem[]> {\n return requestJson<EmployeeCatalogItem[]>(config, \"/employees/all\", {\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { Faculty } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createFacultiesModule(config: InternalClientConfig) {\n return {\n async listAll(options: ReadOptions = {}): Promise<Faculty[]> {\n return requestJson<Faculty[]>(config, \"/faculties\", {\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { StudentGroupCatalogItem } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createGroupsModule(config: InternalClientConfig) {\n return {\n async listAll(options: ReadOptions = {}): Promise<StudentGroupCatalogItem[]> {\n return requestJson<StudentGroupCatalogItem[]>(config, \"/student-groups\", {\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertNonEmptyString, assertPositiveInt } from \"../utils/guards\";\nimport type { ApiDateResponse } from \"../types/common\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createLastUpdateModule(config: InternalClientConfig) {\n return {\n async byGroup(\n params: { groupNumber: string } | { id: number },\n options: ReadOptions = {}\n ): Promise<ApiDateResponse> {\n let query: Record<string, string | number>;\n if (\"groupNumber\" in params) {\n assertNonEmptyString(params.groupNumber, \"groupNumber\");\n query = { groupNumber: params.groupNumber };\n } else {\n assertPositiveInt(params.id, \"id\");\n query = { id: params.id };\n }\n\n return requestJson<ApiDateResponse>(config, \"/last-update-date/student-group\", {\n query,\n signal: options.signal\n });\n },\n\n async byEmployee(\n params: { urlId: string } | { id: number },\n options: ReadOptions = {}\n ): Promise<ApiDateResponse> {\n let query: Record<string, string | number>;\n if (\"urlId\" in params) {\n assertNonEmptyString(params.urlId, \"urlId\");\n query = { \"url-id\": params.urlId };\n } else {\n assertPositiveInt(params.id, \"id\");\n query = { id: params.id };\n }\n\n return requestJson<ApiDateResponse>(config, \"/last-update-date/employee\", {\n query,\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertNonEmptyString, assertPositiveInt } from \"../utils/guards\";\nimport type {\n FlattenedLessonsByDay,\n FlattenedScheduleItem,\n NormalizedScheduleResponse,\n ScheduleFilterOptions,\n ScheduleResponse\n} from \"../types/schedule\";\nimport type { ApiDateResponse } from \"../types/common\";\nimport type { Weekday } from \"../types/common\";\nimport type { ReadOptions } from \"./types\";\n\nconst WEEKDAYS: Weekday[] = [\n \"Понедельник\",\n \"Вторник\",\n \"Среда\",\n \"Четверг\",\n \"Пятница\",\n \"Суббота\"\n];\n\nfunction normalizeSchedule(response: ScheduleResponse): NormalizedScheduleResponse {\n const lessons: FlattenedScheduleItem[] = [];\n const lessonsByDay: FlattenedLessonsByDay = {};\n for (const day of WEEKDAYS) {\n const dayItems = response.schedules[day] ?? [];\n const flattenedDayItems = dayItems.map((item) => ({ ...item, day, source: \"schedules\" as const }));\n lessonsByDay[day] = flattenedDayItems;\n for (const item of dayItems) {\n lessons.push({ ...item, day, source: \"schedules\" });\n }\n }\n\n for (const exam of response.exams) {\n lessons.push({\n ...exam,\n day: null,\n // Exams are not grouped by weekday in API response.\n source: \"exams\"\n });\n }\n\n const scheduleLessons = lessons.filter((lesson) => lesson.source === \"schedules\");\n const examLessons = lessons.filter((lesson) => lesson.source === \"exams\");\n\n return {\n ...response,\n lessons,\n lessonsByDay,\n scheduleLessons,\n examLessons\n };\n}\n\nfunction matchesFilter(item: FlattenedScheduleItem, filter: ScheduleFilterOptions): boolean {\n if (filter.source && item.source !== filter.source) {\n return false;\n }\n\n if (filter.weekday && item.day !== filter.weekday) {\n return false;\n }\n\n if (typeof filter.weekNumber === \"number\" && !item.weekNumber.includes(filter.weekNumber)) {\n return false;\n }\n\n if (typeof filter.subgroup === \"number\" && item.numSubgroup !== filter.subgroup) {\n return false;\n }\n\n if (filter.lessonTypeAbbrev) {\n const types = Array.isArray(filter.lessonTypeAbbrev)\n ? filter.lessonTypeAbbrev\n : [filter.lessonTypeAbbrev];\n if (!types.includes(item.lessonTypeAbbrev)) {\n return false;\n }\n }\n\n if (filter.subjectQuery) {\n const query = filter.subjectQuery.toLowerCase();\n const haystack = `${item.subject} ${item.subjectFullName} ${item.note ?? \"\"}`.toLowerCase();\n if (!haystack.includes(query)) {\n return false;\n }\n }\n\n if (filter.employeeUrlId) {\n const employeeMatch = item.employees?.some((employee) => employee.urlId === filter.employeeUrlId);\n if (!employeeMatch) {\n return false;\n }\n }\n\n if (filter.auditory && !item.auditories.includes(filter.auditory)) {\n return false;\n }\n\n return true;\n}\n\nfunction filterLessons(\n response: NormalizedScheduleResponse,\n filter: ScheduleFilterOptions\n): FlattenedScheduleItem[] {\n return response.lessons.filter((item) => matchesFilter(item, filter));\n}\n\nexport function createScheduleModule(config: InternalClientConfig) {\n async function getGroup<TRaw extends boolean | undefined = undefined>(\n groupNumber: string,\n options: ReadOptions & { raw?: TRaw } = {}\n ): Promise<TRaw extends true ? ScheduleResponse : NormalizedScheduleResponse> {\n assertNonEmptyString(groupNumber, \"groupNumber\");\n const response = await requestJson<ScheduleResponse>(config, \"/schedule\", {\n query: { studentGroup: groupNumber },\n signal: options.signal\n });\n const result = options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);\n return result as TRaw extends true ? ScheduleResponse : NormalizedScheduleResponse;\n }\n\n async function getEmployee<TRaw extends boolean | undefined = undefined>(\n urlId: string,\n options: ReadOptions & { raw?: TRaw } = {}\n ): Promise<TRaw extends true ? ScheduleResponse : NormalizedScheduleResponse> {\n assertNonEmptyString(urlId, \"urlId\");\n const response = await requestJson<ScheduleResponse>(config, `/employees/schedule/${urlId}`, {\n signal: options.signal\n });\n const result = options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);\n return result as TRaw extends true ? ScheduleResponse : NormalizedScheduleResponse;\n }\n\n async function getGroupFiltered(\n groupNumber: string,\n filter: ScheduleFilterOptions,\n options: ReadOptions = {}\n ): Promise<FlattenedScheduleItem[]> {\n const normalized = await getGroup(groupNumber, { ...options, raw: false });\n return filterLessons(normalized, filter);\n }\n\n async function getEmployeeFiltered(\n urlId: string,\n filter: ScheduleFilterOptions,\n options: ReadOptions = {}\n ): Promise<FlattenedScheduleItem[]> {\n const normalized = await getEmployee(urlId, { ...options, raw: false });\n return filterLessons(normalized, filter);\n }\n\n return {\n getGroup,\n getEmployee,\n getGroupFiltered,\n getEmployeeFiltered,\n\n async getGroupExams(groupNumber: string, options: ReadOptions = {}): Promise<FlattenedScheduleItem[]> {\n return getGroupFiltered(groupNumber, { source: \"exams\" }, options);\n },\n\n async getEmployeeExams(urlId: string, options: ReadOptions = {}): Promise<FlattenedScheduleItem[]> {\n return getEmployeeFiltered(urlId, { source: \"exams\" }, options);\n },\n\n async getGroupBySubgroup(\n groupNumber: string,\n subgroup: number,\n options: ReadOptions = {}\n ): Promise<FlattenedScheduleItem[]> {\n assertPositiveInt(subgroup, \"subgroup\");\n return getGroupFiltered(groupNumber, { source: \"schedules\", subgroup }, options);\n },\n\n async getEmployeeBySubgroup(\n urlId: string,\n subgroup: number,\n options: ReadOptions = {}\n ): Promise<FlattenedScheduleItem[]> {\n assertPositiveInt(subgroup, \"subgroup\");\n return getEmployeeFiltered(urlId, { source: \"schedules\", subgroup }, options);\n },\n\n async getCurrentWeek(options: ReadOptions = {}): Promise<number> {\n return requestJson<number>(config, \"/schedule/current-week\", { signal: options.signal });\n },\n\n async getLastUpdateByGroup(\n params: { groupNumber: string } | { id: number },\n options: ReadOptions = {}\n ): Promise<ApiDateResponse> {\n let query: Record<string, string | number>;\n if (\"groupNumber\" in params) {\n assertNonEmptyString(params.groupNumber, \"groupNumber\");\n query = { groupNumber: params.groupNumber };\n } else {\n assertPositiveInt(params.id, \"id\");\n query = { id: params.id };\n }\n return requestJson<ApiDateResponse>(config, \"/last-update-date/student-group\", {\n query,\n signal: options.signal\n });\n },\n\n async getLastUpdateByEmployee(\n params: { urlId: string } | { id: number },\n options: ReadOptions = {}\n ): Promise<ApiDateResponse> {\n let query: Record<string, string | number>;\n if (\"urlId\" in params) {\n assertNonEmptyString(params.urlId, \"urlId\");\n query = { \"url-id\": params.urlId };\n } else {\n assertPositiveInt(params.id, \"id\");\n query = { id: params.id };\n }\n return requestJson<ApiDateResponse>(config, \"/last-update-date/employee\", {\n query,\n signal: options.signal\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { Speciality } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createSpecialitiesModule(config: InternalClientConfig) {\n return {\n async listAll(options: ReadOptions = {}): Promise<Speciality[]> {\n return requestJson<Speciality[]>(config, \"/specialities\", {\n signal: options.signal\n });\n }\n };\n}\n","import type { BsuirClientOptions, InternalClientConfig } from \"./types\";\nimport { createAnnouncementsModule } from \"../modules/announcements\";\nimport { createAuditoriesModule } from \"../modules/auditories\";\nimport { createCurrentWeekModule } from \"../modules/currentWeek\";\nimport { createDepartmentsModule } from \"../modules/departments\";\nimport { createEmployeesModule } from \"../modules/employees\";\nimport { createFacultiesModule } from \"../modules/faculties\";\nimport { createGroupsModule } from \"../modules/groups\";\nimport { createLastUpdateModule } from \"../modules/lastUpdate\";\nimport { createScheduleModule } from \"../modules/schedule\";\nimport { createSpecialitiesModule } from \"../modules/specialities\";\n\nconst DEFAULT_BASE_URL = \"https://iis.bsuir.by/api/v1\";\n\nfunction resolveFetch(customFetch?: typeof globalThis.fetch): typeof globalThis.fetch {\n if (customFetch) {\n return customFetch;\n }\n\n if (typeof globalThis.fetch !== \"function\") {\n throw new Error(\"Global fetch is unavailable. Provide 'fetch' in createBsuirClient options.\");\n }\n\n return globalThis.fetch;\n}\n\nfunction createInternalConfig(options: BsuirClientOptions = {}): InternalClientConfig {\n return {\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n fetchImpl: resolveFetch(options.fetch),\n timeoutMs: options.timeoutMs ?? 10_000,\n retries: options.retries ?? 1,\n retryDelayMs: options.retryDelayMs ?? 300,\n retryMaxDelayMs: options.retryMaxDelayMs ?? 3_000,\n retryJitter: options.retryJitter ?? true,\n userAgent: options.userAgent,\n defaultRaw: options.defaultRaw ?? false\n };\n}\n\nexport function createBsuirClient(options: BsuirClientOptions = {}) {\n const config = createInternalConfig(options);\n\n return {\n schedule: createScheduleModule(config),\n groups: createGroupsModule(config),\n employees: createEmployeesModule(config),\n faculties: createFacultiesModule(config),\n departments: createDepartmentsModule(config),\n specialities: createSpecialitiesModule(config),\n announcements: createAnnouncementsModule(config),\n auditories: createAuditoriesModule(config),\n lastUpdate: createLastUpdateModule(config),\n currentWeek: createCurrentWeekModule(config)\n };\n}\n\nexport type BsuirClient = ReturnType<typeof createBsuirClient>;\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "bsuir-iis-api",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Type-safe ESM SDK for BSUIR IIS API",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"author": "kotru21",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/kotru21/bsuir-iis-api.git"
|
|
11
|
-
},
|
|
12
|
-
"homepage": "https://github.com/kotru21/bsuir-iis-api#readme",
|
|
13
|
-
"bugs": {
|
|
14
|
-
"url": "https://github.com/kotru21/bsuir-iis-api/issues"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"bsuir",
|
|
18
|
-
"iis",
|
|
19
|
-
"schedule",
|
|
20
|
-
"api",
|
|
21
|
-
"sdk",
|
|
22
|
-
"typescript"
|
|
23
|
-
],
|
|
24
|
-
"engines": {
|
|
25
|
-
"node": ">=18"
|
|
26
|
-
},
|
|
27
|
-
"exports": {
|
|
28
|
-
".": {
|
|
29
|
-
"types": "./dist/index.d.ts",
|
|
30
|
-
"import": "./dist/index.js"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
"main": "./dist/index.js",
|
|
34
|
-
"types": "./dist/index.d.ts",
|
|
35
|
-
"files": [
|
|
36
|
-
"dist",
|
|
37
|
-
"README.md",
|
|
38
|
-
"CHANGELOG.md",
|
|
39
|
-
"LICENSE"
|
|
40
|
-
],
|
|
41
|
-
"scripts": {
|
|
42
|
-
"build": "tsup",
|
|
43
|
-
"dev": "tsup --watch",
|
|
44
|
-
"typecheck": "tsc --noEmit",
|
|
45
|
-
"lint": "eslint .",
|
|
46
|
-
"test": "vitest run",
|
|
47
|
-
"test:coverage": "vitest run --coverage",
|
|
48
|
-
"check": "npm run lint && npm run typecheck && npm run test",
|
|
49
|
-
"release:dry": "npm pack --dry-run"
|
|
50
|
-
},
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"@changesets/cli": "^2.29.7",
|
|
53
|
-
"@eslint/js": "^9.38.0",
|
|
54
|
-
"@types/node": "^24.7.2",
|
|
55
|
-
"@typescript-eslint/eslint-plugin": "^8.46.1",
|
|
56
|
-
"@typescript-eslint/parser": "^8.46.1",
|
|
57
|
-
"@vitest/coverage-v8": "^3.2.4",
|
|
58
|
-
"eslint": "^9.38.0",
|
|
59
|
-
"eslint-config-prettier": "^10.1.8",
|
|
60
|
-
"globals": "^16.4.0",
|
|
61
|
-
"prettier": "^3.6.2",
|
|
62
|
-
"tsup": "^8.5.0",
|
|
63
|
-
"typescript": "^5.9.3",
|
|
64
|
-
"vitest": "^3.2.4"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "bsuir-iis-api",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Type-safe ESM SDK for BSUIR IIS API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "kotru21",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/kotru21/bsuir-iis-api.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/kotru21/bsuir-iis-api#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/kotru21/bsuir-iis-api/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"bsuir",
|
|
18
|
+
"iis",
|
|
19
|
+
"schedule",
|
|
20
|
+
"api",
|
|
21
|
+
"sdk",
|
|
22
|
+
"typescript"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"main": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"README.md",
|
|
38
|
+
"CHANGELOG.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"dev": "tsup --watch",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"lint": "eslint .",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:coverage": "vitest run --coverage",
|
|
48
|
+
"check": "npm run lint && npm run typecheck && npm run test",
|
|
49
|
+
"release:dry": "npm pack --dry-run"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@changesets/cli": "^2.29.7",
|
|
53
|
+
"@eslint/js": "^9.38.0",
|
|
54
|
+
"@types/node": "^24.7.2",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^8.46.1",
|
|
56
|
+
"@typescript-eslint/parser": "^8.46.1",
|
|
57
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
58
|
+
"eslint": "^9.38.0",
|
|
59
|
+
"eslint-config-prettier": "^10.1.8",
|
|
60
|
+
"globals": "^16.4.0",
|
|
61
|
+
"prettier": "^3.6.2",
|
|
62
|
+
"tsup": "^8.5.0",
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"vitest": "^3.2.4"
|
|
65
|
+
}
|
|
66
|
+
}
|