bsuir-iis-api 0.2.1 → 0.2.2
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 +13 -0
- package/README.md +16 -1
- package/dist/index.d.ts +14 -2
- package/dist/index.js +30 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,19 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
This changelog is maintained manually and updated in release commits.
|
|
8
8
|
|
|
9
|
+
## [0.2.2] - 2026-03-15
|
|
10
|
+
|
|
11
|
+
### Added (0.2.2)
|
|
12
|
+
|
|
13
|
+
- Added cycle week support with `toCycleWeek()` helper and
|
|
14
|
+
`schedule.getCurrentCycleWeek()` / `currentWeek.getCycle()` methods.
|
|
15
|
+
- Added explicit docs clarifying semester week vs cycle week behavior and aliases.
|
|
16
|
+
|
|
17
|
+
### Changed (0.2.2)
|
|
18
|
+
|
|
19
|
+
- Schedule API raw types now allow `schedules: null` from upstream payload.
|
|
20
|
+
- Normalized schedule responses now guarantee `schedules` is always an object.
|
|
21
|
+
|
|
9
22
|
## [0.2.1] - 2026-03-15
|
|
10
23
|
|
|
11
24
|
### Changed (0.2.1)
|
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ const client = createBsuirClient({
|
|
|
49
49
|
- `client.schedule.getGroupBySubgroup(groupNumber, subgroup, options?)`
|
|
50
50
|
- `client.schedule.getEmployeeBySubgroup(urlId, subgroup, options?)`
|
|
51
51
|
- `client.schedule.getCurrentWeek(options?)`
|
|
52
|
+
- `client.schedule.getCurrentCycleWeek(options?)`
|
|
52
53
|
- `client.schedule.getLastUpdateByGroup({ groupNumber } | { id }, options?)`
|
|
53
54
|
- `client.schedule.getLastUpdateByEmployee({ urlId } | { id }, options?)`
|
|
54
55
|
|
|
@@ -68,7 +69,8 @@ const client = createBsuirClient({
|
|
|
68
69
|
|
|
69
70
|
### Meta
|
|
70
71
|
|
|
71
|
-
- `client.currentWeek.get(options?)`
|
|
72
|
+
- `client.currentWeek.get(options?)` (alias to `client.schedule.getCurrentWeek`)
|
|
73
|
+
- `client.currentWeek.getCycle(options?)` (alias to `client.schedule.getCurrentCycleWeek`)
|
|
72
74
|
- `client.lastUpdate.byGroup({ groupNumber } | { id }, options?)`
|
|
73
75
|
- `client.lastUpdate.byEmployee({ urlId } | { id }, options?)`
|
|
74
76
|
|
|
@@ -92,6 +94,19 @@ const raw = await client.schedule.getGroup("053503", { raw: true });
|
|
|
92
94
|
|
|
93
95
|
Use `defaultRaw: true` in `createBsuirClient` to change global behavior.
|
|
94
96
|
When `raw` is omitted, `getGroup()` and `getEmployee()` return normalized payload.
|
|
97
|
+
In raw mode API may return `schedules: null`; normalized mode always converts it to `{}`.
|
|
98
|
+
|
|
99
|
+
## Semester week vs cycle week
|
|
100
|
+
|
|
101
|
+
`getCurrentWeek()` returns the current semester week number from API.
|
|
102
|
+
For cycle week (1..4) use `getCurrentCycleWeek()` or helper `toCycleWeek()`.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { toCycleWeek } from "bsuir-iis-api";
|
|
106
|
+
|
|
107
|
+
const semesterWeek = await client.schedule.getCurrentWeek();
|
|
108
|
+
const cycleWeek = toCycleWeek(semesterWeek); // default: 2 semester weeks per cycle week
|
|
109
|
+
```
|
|
95
110
|
|
|
96
111
|
Filtering example:
|
|
97
112
|
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,9 @@ declare function createBsuirClient(options?: BsuirClientOptions): {
|
|
|
53
53
|
getGroupBySubgroup(groupNumber: string, subgroup: number, options?: ReadOptions): Promise<FlattenedScheduleItem[]>;
|
|
54
54
|
getEmployeeBySubgroup(urlId: string, subgroup: number, options?: ReadOptions): Promise<FlattenedScheduleItem[]>;
|
|
55
55
|
getCurrentWeek(options?: ReadOptions): Promise<number>;
|
|
56
|
+
getCurrentCycleWeek(options?: ReadOptions & {
|
|
57
|
+
weeksPerCycle?: number;
|
|
58
|
+
}): Promise<number>;
|
|
56
59
|
getLastUpdateByGroup(params: {
|
|
57
60
|
groupNumber: string;
|
|
58
61
|
} | {
|
|
@@ -100,6 +103,9 @@ declare function createBsuirClient(options?: BsuirClientOptions): {
|
|
|
100
103
|
};
|
|
101
104
|
currentWeek: {
|
|
102
105
|
get(options?: ReadOptions): Promise<number>;
|
|
106
|
+
getCycle(options?: ReadOptions & {
|
|
107
|
+
weeksPerCycle?: number;
|
|
108
|
+
}): Promise<number>;
|
|
103
109
|
};
|
|
104
110
|
};
|
|
105
111
|
/**
|
|
@@ -107,6 +113,12 @@ declare function createBsuirClient(options?: BsuirClientOptions): {
|
|
|
107
113
|
*/
|
|
108
114
|
type BsuirClient = ReturnType<typeof createBsuirClient>;
|
|
109
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Converts semester week number to BSUIR cycle week (1..4).
|
|
118
|
+
* For default configuration weeks 1-2 => 1, 3-4 => 2, 5-6 => 3, 7-8 => 4.
|
|
119
|
+
*/
|
|
120
|
+
declare function toCycleWeek(semesterWeek: number, weeksPerCycle?: number): number;
|
|
121
|
+
|
|
110
122
|
/**
|
|
111
123
|
* Read options used by all module methods.
|
|
112
124
|
*/
|
|
@@ -273,7 +285,7 @@ type WeekScheduleMap = Partial<Record<Weekday, ScheduleItem[]>>;
|
|
|
273
285
|
interface ScheduleResponse {
|
|
274
286
|
employeeDto: Maybe<Employee>;
|
|
275
287
|
studentGroupDto: Maybe<StudentGroupCatalogItem>;
|
|
276
|
-
schedules: WeekScheduleMap;
|
|
288
|
+
schedules: WeekScheduleMap | null;
|
|
277
289
|
exams: ScheduleItem[];
|
|
278
290
|
startDate: Maybe<string>;
|
|
279
291
|
endDate: Maybe<string>;
|
|
@@ -304,4 +316,4 @@ interface NormalizedScheduleResponse extends Omit<ScheduleResponse, "schedules"
|
|
|
304
316
|
examLessons: FlattenedScheduleItem[];
|
|
305
317
|
}
|
|
306
318
|
|
|
307
|
-
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 ReadOptions, type RequestOptions, type ScheduleFilterOptions, type ScheduleItem, type ScheduleResponse, type Speciality, type StudentGroupCatalogItem, type StudentGroupShort, type WeekScheduleMap, type Weekday, createBsuirClient };
|
|
319
|
+
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 ReadOptions, type RequestOptions, type ScheduleFilterOptions, type ScheduleItem, type ScheduleResponse, type Speciality, type StudentGroupCatalogItem, type StudentGroupShort, type WeekScheduleMap, type Weekday, createBsuirClient, toCycleWeek };
|
package/dist/index.js
CHANGED
|
@@ -206,13 +206,31 @@ function createAuditoriesModule(config) {
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
// src/utils/week.ts
|
|
210
|
+
var CYCLE_LENGTH = 4;
|
|
211
|
+
function toCycleWeek(semesterWeek, weeksPerCycle = 2) {
|
|
212
|
+
assertPositiveInt(semesterWeek, "semesterWeek");
|
|
213
|
+
assertPositiveInt(weeksPerCycle, "weeksPerCycle");
|
|
214
|
+
return Math.floor((semesterWeek - 1) / weeksPerCycle) % CYCLE_LENGTH + 1;
|
|
215
|
+
}
|
|
216
|
+
|
|
209
217
|
// src/modules/currentWeek.ts
|
|
210
218
|
function createCurrentWeekModule(config) {
|
|
211
219
|
return {
|
|
220
|
+
/**
|
|
221
|
+
* Returns current semester week number.
|
|
222
|
+
*/
|
|
212
223
|
async get(options = {}) {
|
|
213
224
|
return requestJson(config, "/schedule/current-week", {
|
|
214
225
|
signal: options.signal
|
|
215
226
|
});
|
|
227
|
+
},
|
|
228
|
+
/**
|
|
229
|
+
* Returns current cycle week number (1..4).
|
|
230
|
+
*/
|
|
231
|
+
async getCycle(options = {}) {
|
|
232
|
+
const semesterWeek = await this.get(options);
|
|
233
|
+
return toCycleWeek(semesterWeek, options.weeksPerCycle);
|
|
216
234
|
}
|
|
217
235
|
};
|
|
218
236
|
}
|
|
@@ -307,15 +325,17 @@ var WEEKDAYS = [
|
|
|
307
325
|
function normalizeSchedule(response) {
|
|
308
326
|
const lessons = [];
|
|
309
327
|
const lessonsByDay = {};
|
|
328
|
+
const safeSchedules = response.schedules ?? {};
|
|
329
|
+
const safeExams = response.exams ?? [];
|
|
310
330
|
for (const day of WEEKDAYS) {
|
|
311
|
-
const dayItems =
|
|
331
|
+
const dayItems = safeSchedules[day] ?? [];
|
|
312
332
|
const flattenedDayItems = dayItems.map((item) => ({ ...item, day, source: "schedules" }));
|
|
313
333
|
lessonsByDay[day] = flattenedDayItems;
|
|
314
334
|
for (const item of dayItems) {
|
|
315
335
|
lessons.push({ ...item, day, source: "schedules" });
|
|
316
336
|
}
|
|
317
337
|
}
|
|
318
|
-
for (const exam of
|
|
338
|
+
for (const exam of safeExams) {
|
|
319
339
|
lessons.push({
|
|
320
340
|
...exam,
|
|
321
341
|
day: null,
|
|
@@ -327,6 +347,8 @@ function normalizeSchedule(response) {
|
|
|
327
347
|
const examLessons = lessons.filter((lesson) => lesson.source === "exams");
|
|
328
348
|
return {
|
|
329
349
|
...response,
|
|
350
|
+
schedules: safeSchedules,
|
|
351
|
+
exams: safeExams,
|
|
330
352
|
lessons,
|
|
331
353
|
lessonsByDay,
|
|
332
354
|
scheduleLessons,
|
|
@@ -421,6 +443,10 @@ function createScheduleModule(config) {
|
|
|
421
443
|
async getCurrentWeek(options = {}) {
|
|
422
444
|
return requestJson(config, "/schedule/current-week", { signal: options.signal });
|
|
423
445
|
},
|
|
446
|
+
async getCurrentCycleWeek(options = {}) {
|
|
447
|
+
const semesterWeek = await this.getCurrentWeek(options);
|
|
448
|
+
return toCycleWeek(semesterWeek, options.weeksPerCycle);
|
|
449
|
+
},
|
|
424
450
|
async getLastUpdateByGroup(params, options = {}) {
|
|
425
451
|
let query;
|
|
426
452
|
if ("groupNumber" in params) {
|
|
@@ -507,6 +533,7 @@ export {
|
|
|
507
533
|
BsuirNetworkError,
|
|
508
534
|
BsuirTimeoutError,
|
|
509
535
|
BsuirValidationError,
|
|
510
|
-
createBsuirClient
|
|
536
|
+
createBsuirClient,
|
|
537
|
+
toCycleWeek
|
|
511
538
|
};
|
|
512
539
|
//# sourceMappingURL=index.js.map
|
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 {\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 /**\n * Returns schedule for a student group.\n * By default returns normalized payload, unless `raw: true` is passed.\n */\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 /**\n * Returns schedule for an employee.\n * By default returns normalized payload, unless `raw: true` is passed.\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 /**\n * Returns filtered schedule items for a group from normalized schedule payload.\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 /**\n * Returns filtered schedule items for an employee from normalized schedule payload.\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\n/**\n * Creates a configured BSUIR IIS API client.\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\n/**\n * Public client contract returned by {@link createBsuirClient}.\n */\nexport type BsuirClient = ReturnType<typeof createBsuirClient>;\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/utils/week.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 { assertPositiveInt } from \"./guards\";\n\nconst CYCLE_LENGTH = 4;\n\n/**\n * Converts semester week number to BSUIR cycle week (1..4).\n * For default configuration weeks 1-2 => 1, 3-4 => 2, 5-6 => 3, 7-8 => 4.\n */\nexport function toCycleWeek(semesterWeek: number, weeksPerCycle = 2): number {\n assertPositiveInt(semesterWeek, \"semesterWeek\");\n assertPositiveInt(weeksPerCycle, \"weeksPerCycle\");\n\n return (Math.floor((semesterWeek - 1) / weeksPerCycle) % CYCLE_LENGTH) + 1;\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { ReadOptions } from \"./types\";\nimport { toCycleWeek } from \"../utils/week\";\n\nexport function createCurrentWeekModule(config: InternalClientConfig) {\n return {\n /**\n * Returns current semester week number.\n */\n async get(options: ReadOptions = {}): Promise<number> {\n return requestJson<number>(config, \"/schedule/current-week\", {\n signal: options.signal\n });\n },\n\n /**\n * Returns current cycle week number (1..4).\n */\n async getCycle(options: ReadOptions & { weeksPerCycle?: number } = {}): Promise<number> {\n const semesterWeek = await this.get(options);\n return toCycleWeek(semesterWeek, options.weeksPerCycle);\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\";\nimport { toCycleWeek } from \"../utils/week\";\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 const safeSchedules = response.schedules ?? {};\n const safeExams = response.exams ?? [];\n for (const day of WEEKDAYS) {\n const dayItems = safeSchedules[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 safeExams) {\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 schedules: safeSchedules,\n exams: safeExams,\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 /**\n * Returns schedule for a student group.\n * By default returns normalized payload, unless `raw: true` is passed.\n */\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 /**\n * Returns schedule for an employee.\n * By default returns normalized payload, unless `raw: true` is passed.\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 /**\n * Returns filtered schedule items for a group from normalized schedule payload.\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 /**\n * Returns filtered schedule items for an employee from normalized schedule payload.\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 getCurrentCycleWeek(\n options: ReadOptions & { weeksPerCycle?: number } = {}\n ): Promise<number> {\n const semesterWeek = await this.getCurrentWeek(options);\n return toCycleWeek(semesterWeek, options.weeksPerCycle);\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\n/**\n * Creates a configured BSUIR IIS API client.\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\n/**\n * Public client contract returned by {@link createBsuirClient}.\n */\nexport type BsuirClient = ReturnType<typeof createBsuirClient>;\n"],"mappings":"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","names":[]}
|