bsuir-iis-api 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,21 @@ This changelog is maintained manually and updated in release commits.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.2.7] - 2026-03-16
12
+
13
+ ### Added (0.2.7)
14
+
15
+ - Added `npm run lint:fix` for convenient local autofix flow.
16
+
17
+ ### Changed (0.2.7)
18
+
19
+ - Reworked ESLint flat config to use typed `typescript-eslint` presets:
20
+ `recommendedTypeChecked`, `strictTypeChecked`, and `stylisticTypeChecked`.
21
+ - Switched ESLint typed linting to `parserOptions.projectService` with `tsconfigRootDir`.
22
+ - Introduced explicit lint zones for `src` and `test`/`vitest` with targeted test overrides.
23
+ - Added `linterOptions.reportUnusedDisableDirectives` and normalized flat-config ignore patterns.
24
+ - Updated development docs with lint workflow and strict lint profile notes.
25
+
11
26
  ## [0.2.6] - 2026-03-16
12
27
 
13
28
  ### Added
package/README.md CHANGED
@@ -129,10 +129,15 @@ const subgroupLessons = await client.schedule.getEmployeeBySubgroup("s-nesterenk
129
129
 
130
130
  ```bash
131
131
  npm install
132
+ npm run lint
133
+ npm run lint:fix
132
134
  npm run check
133
135
  npm run build
134
136
  ```
135
137
 
138
+ Linting uses ESLint flat config with strict type-aware TypeScript rules for `src`,
139
+ plus test-specific overrides for `test` and `vitest.config.ts`.
140
+
136
141
  Live contract tests against real BSUIR API are opt-in:
137
142
 
138
143
  ```bash
package/dist/index.js CHANGED
@@ -166,7 +166,7 @@ async function requestJson(config, path, options = {}) {
166
166
  continue;
167
167
  }
168
168
  throw new BsuirApiError(
169
- `BSUIR API returned HTTP ${response.status} for ${path}`,
169
+ `BSUIR API returned HTTP ${String(response.status)} for ${path}`,
170
170
  response.status,
171
171
  endpoint,
172
172
  errorBody
@@ -182,7 +182,7 @@ async function requestJson(config, path, options = {}) {
182
182
  throw error;
183
183
  }
184
184
  throw new BsuirTimeoutError(
185
- `Request timed out after ${config.timeoutMs}ms: ${path}`,
185
+ `Request timed out after ${String(config.timeoutMs)}ms: ${path}`,
186
186
  endpoint,
187
187
  config.timeoutMs
188
188
  );
@@ -369,7 +369,7 @@ function normalizeSchedule(response) {
369
369
  const lessons = [];
370
370
  const lessonsByDay = {};
371
371
  const safeSchedules = response.schedules ?? {};
372
- const safeExams = response.exams ?? [];
372
+ const safeExams = response.exams;
373
373
  for (const day of WEEKDAYS) {
374
374
  const dayItems = safeSchedules[day] ?? [];
375
375
  const flattenedDayItems = dayItems.map((item) => ({ ...item, day, source: "schedules" }));
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/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\nconst GROUP_NUMBER_PATTERN = /^\\d+$/;\nconst EMPLOYEE_URL_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/i;\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 assertGroupNumber(value: string, fieldName = \"groupNumber\"): void {\n assertNonEmptyString(value, fieldName);\n if (!GROUP_NUMBER_PATTERN.test(value)) {\n throw new BsuirValidationError(`'${fieldName}' must contain only digits`);\n }\n}\n\nexport function assertEmployeeUrlId(value: string, fieldName = \"urlId\"): void {\n assertNonEmptyString(value, fieldName);\n if (!EMPLOYEE_URL_ID_PATTERN.test(value)) {\n throw new BsuirValidationError(\n `'${fieldName}' must be a valid slug (letters, digits, hyphen)`\n );\n }\n}\n\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n return true;\n }\n\n if (typeof error === \"object\" && error !== null) {\n const maybeError = error as { name?: unknown; code?: unknown };\n return maybeError.name === \"AbortError\" || maybeError.code === \"ABORT_ERR\";\n }\n\n return false;\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 { assertEmployeeUrlId, 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 assertEmployeeUrlId(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 { BsuirValidationError } from \"../client/errors\";\nimport { 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\n/**\n * Normalizes semester week payload from API to a positive integer.\n * API can return plain text (`\"1\\n\"`) or number.\n */\nexport function parseSemesterWeek(payload: unknown): number {\n if (typeof payload === \"number\") {\n assertPositiveInt(payload, \"semesterWeek\");\n return payload;\n }\n\n if (typeof payload === \"string\") {\n const normalized = payload.trim();\n if (normalized.length > 0) {\n const parsed = Number(normalized);\n if (Number.isInteger(parsed)) {\n assertPositiveInt(parsed, \"semesterWeek\");\n return parsed;\n }\n }\n }\n\n if (typeof payload === \"object\" && payload !== null) {\n const record = payload as Record<string, unknown>;\n if (\"weekNumber\" in record) {\n return parseSemesterWeek(record.weekNumber);\n }\n if (\"currentWeek\" in record) {\n return parseSemesterWeek(record.currentWeek);\n }\n }\n\n throw new BsuirValidationError(\"'semesterWeek' response payload must be a positive integer\");\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { ReadOptions } from \"./types\";\nimport { parseSemesterWeek, toCycleWeek } from \"../utils/week\";\n\nexport function createCurrentWeekModule(config: InternalClientConfig) {\n /**\n * Returns current semester week number.\n */\n async function get(options: ReadOptions = {}): Promise<number> {\n const payload = await requestJson<unknown>(config, \"/schedule/current-week\", {\n signal: options.signal\n });\n return parseSemesterWeek(payload);\n }\n\n /**\n * Returns current cycle week number (1..4).\n */\n async function getCycle(options: ReadOptions & { weeksPerCycle?: number } = {}): Promise<number> {\n const semesterWeek = await get(options);\n return toCycleWeek(semesterWeek, options.weeksPerCycle);\n }\n\n return { get, getCycle };\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 { assertEmployeeUrlId, assertGroupNumber, 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 assertGroupNumber(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 assertEmployeeUrlId(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 { assertEmployeeUrlId, assertGroupNumber, 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 { parseSemesterWeek, 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\") {\n if (!Array.isArray(item.weekNumber) || !item.weekNumber.includes(filter.weekNumber)) {\n return false;\n }\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 (!item.lessonTypeAbbrev || !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 assertGroupNumber(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 assertEmployeeUrlId(urlId, \"urlId\");\n const response = await requestJson<ScheduleResponse>(\n config,\n `/employees/schedule/${encodeURIComponent(urlId)}`,\n {\n signal: options.signal\n }\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 async function getCurrentWeek(options: ReadOptions = {}): Promise<number> {\n const payload = await requestJson<unknown>(config, \"/schedule/current-week\", {\n signal: options.signal\n });\n return parseSemesterWeek(payload);\n }\n\n async function getCurrentCycleWeek(\n options: ReadOptions & { weeksPerCycle?: number } = {}\n ): Promise<number> {\n const semesterWeek = await getCurrentWeek(options);\n return toCycleWeek(semesterWeek, options.weeksPerCycle);\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 getCurrentWeek,\n getCurrentCycleWeek,\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 assertGroupNumber(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 assertEmployeeUrlId(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\nconst GROUP_NUMBER_PATTERN = /^\\d+$/;\nconst EMPLOYEE_URL_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/i;\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 assertGroupNumber(value: string, fieldName = \"groupNumber\"): void {\n assertNonEmptyString(value, fieldName);\n if (!GROUP_NUMBER_PATTERN.test(value)) {\n throw new BsuirValidationError(`'${fieldName}' must contain only digits`);\n }\n}\n\nexport function assertEmployeeUrlId(value: string, fieldName = \"urlId\"): void {\n assertNonEmptyString(value, fieldName);\n if (!EMPLOYEE_URL_ID_PATTERN.test(value)) {\n throw new BsuirValidationError(\n `'${fieldName}' must be a valid slug (letters, digits, hyphen)`\n );\n }\n}\n\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n return true;\n }\n\n if (typeof error === \"object\" && error !== null) {\n const maybeError = error as { name?: unknown; code?: unknown };\n return maybeError.name === \"AbortError\" || maybeError.code === \"ABORT_ERR\";\n }\n\n return false;\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 ${String(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 ${String(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 { assertEmployeeUrlId, 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 assertEmployeeUrlId(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 { BsuirValidationError } from \"../client/errors\";\nimport { 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\n/**\n * Normalizes semester week payload from API to a positive integer.\n * API can return plain text (`\"1\\n\"`) or number.\n */\nexport function parseSemesterWeek(payload: unknown): number {\n if (typeof payload === \"number\") {\n assertPositiveInt(payload, \"semesterWeek\");\n return payload;\n }\n\n if (typeof payload === \"string\") {\n const normalized = payload.trim();\n if (normalized.length > 0) {\n const parsed = Number(normalized);\n if (Number.isInteger(parsed)) {\n assertPositiveInt(parsed, \"semesterWeek\");\n return parsed;\n }\n }\n }\n\n if (typeof payload === \"object\" && payload !== null) {\n const record = payload as Record<string, unknown>;\n if (\"weekNumber\" in record) {\n return parseSemesterWeek(record.weekNumber);\n }\n if (\"currentWeek\" in record) {\n return parseSemesterWeek(record.currentWeek);\n }\n }\n\n throw new BsuirValidationError(\"'semesterWeek' response payload must be a positive integer\");\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport type { ReadOptions } from \"./types\";\nimport { parseSemesterWeek, toCycleWeek } from \"../utils/week\";\n\nexport function createCurrentWeekModule(config: InternalClientConfig) {\n /**\n * Returns current semester week number.\n */\n async function get(options: ReadOptions = {}): Promise<number> {\n const payload = await requestJson<unknown>(config, \"/schedule/current-week\", {\n signal: options.signal\n });\n return parseSemesterWeek(payload);\n }\n\n /**\n * Returns current cycle week number (1..4).\n */\n async function getCycle(options: ReadOptions & { weeksPerCycle?: number } = {}): Promise<number> {\n const semesterWeek = await get(options);\n return toCycleWeek(semesterWeek, options.weeksPerCycle);\n }\n\n return { get, getCycle };\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 { assertEmployeeUrlId, assertGroupNumber, 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 assertGroupNumber(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 assertEmployeeUrlId(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 { assertEmployeeUrlId, assertGroupNumber, 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 { parseSemesterWeek, 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\") {\n if (!Array.isArray(item.weekNumber) || !item.weekNumber.includes(filter.weekNumber)) {\n return false;\n }\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 (!item.lessonTypeAbbrev || !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 assertGroupNumber(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 assertEmployeeUrlId(urlId, \"urlId\");\n const response = await requestJson<ScheduleResponse>(\n config,\n `/employees/schedule/${encodeURIComponent(urlId)}`,\n {\n signal: options.signal\n }\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 async function getCurrentWeek(options: ReadOptions = {}): Promise<number> {\n const payload = await requestJson<unknown>(config, \"/schedule/current-week\", {\n signal: options.signal\n });\n return parseSemesterWeek(payload);\n }\n\n async function getCurrentCycleWeek(\n options: ReadOptions & { weeksPerCycle?: number } = {}\n ): Promise<number> {\n const semesterWeek = await getCurrentWeek(options);\n return toCycleWeek(semesterWeek, options.weeksPerCycle);\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 getCurrentWeek,\n getCurrentCycleWeek,\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 assertGroupNumber(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 assertEmployeeUrlId(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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bsuir-iis-api",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Type-safe ESM SDK for BSUIR IIS API",
5
5
  "type": "module",
6
6
  "author": "kotru21",
@@ -43,6 +43,7 @@
43
43
  "dev": "tsup --watch",
44
44
  "typecheck": "tsc --noEmit",
45
45
  "lint": "eslint .",
46
+ "lint:fix": "eslint . --fix",
46
47
  "test": "vitest run",
47
48
  "test:live": "vitest run test/integration/live-api.contract.test.ts",
48
49
  "test:coverage": "vitest run --coverage",
@@ -64,6 +65,7 @@
64
65
  "prettier": "^3.6.2",
65
66
  "tsup": "^8.5.0",
66
67
  "typescript": "^5.9.3",
68
+ "typescript-eslint": "^8.57.0",
67
69
  "vitest": "^4.1.0"
68
70
  }
69
71
  }