bsuir-iis-api 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -8
- package/README.md +9 -2
- package/dist/_tsup-dts-rollup.d.ts +285 -106
- package/dist/index.js +239 -210
- package/dist/index.js.map +1 -1
- package/package.json +16 -16
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/errors.ts","../src/client/mergeSignals.ts","../src/utils/guards.ts","../src/client/http.ts","../src/client/responseValidators.ts","../src/modules/announcements.ts","../src/modules/auditories.ts","../src/modules/departments.ts","../src/modules/employees.ts","../src/modules/faculties.ts","../src/modules/groups.ts","../src/utils/week.ts","../src/modules/schedule.ts","../src/modules/specialities.ts","../src/client/createClient.ts"],"sourcesContent":["/**\n * Restores proper prototype chain for Error subclasses in transpiled outputs.\n * TypeScript's ES<2015 transpilation breaks `class Foo extends Error`:\n * the compiled function lacks Error.prototype in its chain. This restores it.\n * See: https://github.com/microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins\n */\nfunction fixErrorPrototype(instance: Error, prototype: object): void {\n Object.setPrototypeOf(instance, prototype);\n}\n\nexport 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 fixErrorPrototype(this, BsuirApiError.prototype);\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\n constructor(message: string, endpoint: string, cause: unknown) {\n super(message, { cause });\n fixErrorPrototype(this, BsuirNetworkError.prototype);\n this.name = \"BsuirNetworkError\";\n this.endpoint = endpoint;\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, cause?: unknown) {\n super(message, { cause });\n fixErrorPrototype(this, BsuirTimeoutError.prototype);\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 fixErrorPrototype(this, BsuirValidationError.prototype);\n this.name = \"BsuirValidationError\";\n }\n}\n\nexport class BsuirResponseValidationError extends Error {\n readonly endpoint: string;\n\n constructor(message: string, endpoint: string) {\n super(message);\n fixErrorPrototype(this, BsuirResponseValidationError.prototype);\n this.name = \"BsuirResponseValidationError\";\n this.endpoint = endpoint;\n }\n}\n\nexport class BsuirConfigurationError extends Error {\n constructor(message: string) {\n super(message);\n fixErrorPrototype(this, BsuirConfigurationError.prototype);\n this.name = \"BsuirConfigurationError\";\n }\n}\n","type AbortSignalConstructor = typeof AbortSignal & {\n any?(signals: AbortSignal[]): AbortSignal;\n};\n\nconst AbortSignalCtor = AbortSignal as AbortSignalConstructor;\n\n/**\n * Combines multiple abort signals and/or a timeout into a single signal.\n * When `AbortSignal.any` exists at runtime, delegates to the platform implementation.\n * Otherwise uses a manual merge so all signals are respected.\n *\n * @param signalsOrFirst - Array of signals to merge, or a single signal (legacy signature)\n * @param timeoutMs - Optional timeout in milliseconds to include as an additional signal\n *\n * @remarks\n * Calling with no signals and no timeout (e.g. `mergeSignals([])`) returns a signal\n * that is never aborted — the caller is responsible for not doing this intentionally.\n */\nexport function mergeSignals(\n signalsOrFirst: AbortSignal[] | (AbortSignal | undefined),\n timeoutMs?: number\n): AbortSignal {\n // Handle both signatures for backwards compatibility\n let signals: (AbortSignal | undefined)[];\n let timeout: number | undefined;\n\n if (Array.isArray(signalsOrFirst)) {\n signals = signalsOrFirst;\n timeout = timeoutMs;\n } else {\n // Legacy signature: mergeSignals(signal, timeoutMs)\n signals = [signalsOrFirst];\n timeout = timeoutMs;\n }\n\n const parts = signals.filter((s): s is AbortSignal => s !== undefined);\n\n if (parts.length === 0) {\n if (timeout !== undefined) {\n // Only a timeout, no external signal\n if (typeof AbortSignalCtor.any === \"function\") {\n return AbortSignalCtor.any([AbortSignal.timeout(timeout)]);\n }\n return mergeSignalsManual([], timeout);\n }\n // No signals and no timeout — returns a signal that is never aborted.\n // This is a degenerate case; callers should avoid it.\n return new AbortController().signal;\n }\n\n if (parts.length === 1 && timeout === undefined) {\n // Single signal, no timeout — return it directly\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return parts[0]!;\n }\n\n // Use platform AbortSignal.any when available (covers both timeout and multi-signal cases)\n if (typeof AbortSignalCtor.any === \"function\") {\n const all = timeout !== undefined ? [...parts, AbortSignal.timeout(timeout)] : parts;\n return AbortSignalCtor.any(all);\n }\n\n // Fallback: manual merge with possible timeout\n return mergeSignalsManual(parts, timeout);\n}\n\n/** Used when `AbortSignal.any` is unavailable; exposed for unit tests. */\nexport function mergeSignalsManual(signals: AbortSignal[], timeoutMs?: number): AbortSignal {\n if (signals.length === 0 && timeoutMs === undefined) {\n return new AbortController().signal;\n }\n if (signals.length === 1 && timeoutMs === undefined) {\n // Single signal, no timeout\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return signals[0]!;\n }\n\n const combined = new AbortController();\n const listeners: { signal: AbortSignal; handler: () => void }[] = [];\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const onAnyAbort = (): void => {\n if (!combined.signal.aborted) {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n combined.abort();\n }\n };\n\n // Setup timeout if provided\n if (timeoutMs !== undefined) {\n timeoutId = setTimeout(() => {\n if (!combined.signal.aborted) {\n combined.abort();\n }\n }, timeoutMs);\n }\n\n // Setup listeners for external signals\n for (const signal of signals) {\n if (signal.aborted) {\n onAnyAbort();\n break;\n } else {\n signal.addEventListener(\"abort\", onAnyAbort, { once: true });\n listeners.push({ signal, handler: onAnyAbort });\n }\n }\n\n // Cleanup listeners and timeout when combined signal aborts to prevent memory leaks\n combined.signal.addEventListener(\n \"abort\",\n () => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n for (const listener of listeners) {\n listener.signal.removeEventListener(\"abort\", listener.handler);\n }\n },\n { once: true }\n );\n\n return combined.signal;\n}\n","import { BsuirValidationError } from \"../client/errors\";\n\n// BSUIR IIS API accepts only numeric group IDs (e.g., \"053503\").\n// Pattern is intentionally strict and covers only current IIS format.\nconst GROUP_NUMBER_PATTERN = /^\\d+$/;\nconst EMPLOYEE_URL_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/i;\n\nexport function assertNonEmptyString(value: unknown, fieldName: string): asserts value is string {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new BsuirValidationError(`'${fieldName}' must be a non-empty string`);\n }\n}\n\nexport function assertPositiveInt(value: unknown, fieldName: string): asserts value is number {\n if (typeof value !== \"number\" || !Number.isInteger(value) || value <= 0) {\n throw new BsuirValidationError(`'${fieldName}' must be a positive integer`);\n }\n}\n\nexport function assertGroupNumber(value: unknown, fieldName = \"groupNumber\"): asserts value is string {\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: unknown, fieldName = \"urlId\"): asserts value is string {\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 // Browser: DOMException with name \"AbortError\"\n if (error instanceof DOMException && error.name === \"AbortError\") {\n return true;\n }\n\n // Node.js: Error-like object with code \"ABORT_ERR\"\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 { mergeSignals } from \"./mergeSignals\";\nimport type {\n ErrorHookContext,\n InternalClientConfig,\n QueryParams,\n RequestHookContext,\n RequestMethod,\n RequestOptions,\n ResponseHookContext,\n RetryHookContext,\n} 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 sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction tryReadCache(config: Readonly<InternalClientConfig>, key: string): unknown {\n const entry = config.responseCache.get(key);\n if (!entry) {\n return undefined;\n }\n if (entry.expiresAt <= Date.now()) {\n config.responseCache.delete(key);\n return undefined;\n }\n // Update accessedAt for LRU eviction\n entry.accessedAt = Date.now();\n return entry.value;\n}\n\nfunction setCache(config: Readonly<InternalClientConfig>, key: string, value: unknown): void {\n if (config.cacheTtlMs === undefined) {\n return;\n }\n const now = Date.now();\n config.responseCache.set(key, {\n value,\n expiresAt: now + config.cacheTtlMs,\n accessedAt: now,\n });\n\n // Only trigger cleanup when cache is approaching capacity (>90%) to avoid O(n) scan on every set\n const cleanupThreshold = config.cacheMaxEntries * 0.9;\n if (config.responseCache.size <= cleanupThreshold) {\n return;\n }\n\n // Remove expired entries first\n for (const [k, v] of config.responseCache) {\n if (v.expiresAt <= now) {\n config.responseCache.delete(k);\n }\n }\n\n // Apply pseudo-LRU eviction if still over capacity.\n // Map preserves insertion order; the first key is the oldest-inserted entry,\n // which serves as a fast O(1) approximation of LRU without a separate bookkeeping structure.\n while (config.responseCache.size > config.cacheMaxEntries) {\n const firstKey = config.responseCache.keys().next().value;\n if (firstKey === undefined) {\n break;\n }\n config.responseCache.delete(firstKey);\n }\n}\n\nfunction combineAbortSignals(\n first: AbortSignal | undefined,\n second: AbortSignal | undefined,\n): AbortSignal | undefined {\n if (!first) {\n return second;\n }\n if (!second) {\n return first;\n }\n // Delegate to mergeSignals for consistent signal combination logic\n return mergeSignals([first, second]);\n}\n\nfunction parseRetryAfterMs(retryAfter: string | null): number | null {\n if (!retryAfter || retryAfter.trim().length === 0) {\n return null;\n }\n\n // Try parsing as seconds (RFC 7231: numeric-value)\n const asSeconds = Number(retryAfter);\n if (Number.isFinite(asSeconds) && asSeconds >= 0) {\n // Validate it's actually numeric format, not a date string starting with a digit\n if (/^\\d+(\\.\\d+)?$/.test(retryAfter.trim())) {\n return Math.floor(asSeconds * 1000);\n }\n }\n\n // Try parsing as HTTP date format (RFC 7231: http-date)\n const dateValue = Date.parse(retryAfter);\n if (Number.isFinite(dateValue)) {\n const delayMs = dateValue - Date.now();\n // Only accept if date is in the future\n if (delayMs > 0) {\n return Math.min(delayMs, 86_400_000); // Cap at 24 hours to prevent unreasonably long waits\n }\n }\n\n return null;\n}\n\nfunction getRetryDelayMs(\n config: Readonly<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 const declaredJson = contentType.includes(\"application/json\");\n const text = await response.text();\n if (text.length === 0) {\n if (declaredJson) {\n throw new BsuirApiError(\"Invalid JSON response payload\", response.status, response.url, null);\n }\n return \"\";\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n if (declaredJson) {\n throw new BsuirApiError(\"Invalid JSON response payload\", response.status, response.url, null);\n }\n return text;\n }\n}\n\nfunction baseHookContext(\n method: RequestMethod,\n path: string,\n endpoint: string,\n attempt: number,\n maxAttempts: number,\n query: QueryParams | undefined,\n): RequestHookContext {\n return {\n method,\n path,\n endpoint,\n attempt,\n maxAttempts,\n query,\n };\n}\n\nexport async function requestJson<T>(\n config: Readonly<InternalClientConfig>,\n path: string,\n options: RequestOptions = {},\n): Promise<T> {\n const endpoint = buildUrl(config.baseUrl, path, options.query);\n const method = options.method ?? \"GET\";\n const requestCanRetry = method === \"GET\";\n const maxRetries = requestCanRetry ? config.retries : 0;\n const maxAttempts = maxRetries + 1;\n const headers = new Headers({\n Accept: \"application/json\",\n });\n\n if (config.userAgent) {\n headers.set(\"User-Agent\", config.userAgent);\n }\n if (options.headers) {\n for (const [key, value] of new Headers(options.headers)) {\n headers.set(key, value);\n }\n }\n\n const body = options.body === undefined ? undefined : JSON.stringify(options.body);\n if (body !== undefined && !headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n const cacheKey = endpoint;\n const canUseCaching = config.cacheTtlMs !== undefined && method === \"GET\" && !options.signal;\n const canUseDedup = config.dedupeInFlight && method === \"GET\" && !options.signal;\n\n if (canUseCaching) {\n const cached = tryReadCache(config, cacheKey);\n if (cached !== undefined) {\n const cacheHitCtx: ResponseHookContext = {\n ...baseHookContext(method, path, endpoint, 1, maxAttempts, options.query),\n status: 200,\n durationMs: 0,\n fromCache: true,\n };\n config.hooks.onResponse?.(cacheHitCtx);\n return cached as T;\n }\n }\n\n const performRequest = async (): Promise<T> => {\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n const attemptNumber = attempt + 1;\n const startedAt = Date.now();\n const hookCtx = baseHookContext(method, path, endpoint, attemptNumber, maxAttempts, options.query);\n\n config.hooks.onRequest?.(hookCtx);\n\n const externalSignal = combineAbortSignals(options.signal, config.signal);\n const requestSignal = mergeSignals(externalSignal, config.timeoutMs);\n\n try {\n const requestInit: RequestInit = {\n method,\n headers,\n signal: requestSignal,\n };\n if (body !== undefined) {\n requestInit.body = body;\n }\n\n const response = await config.fetchImpl(endpoint, requestInit);\n\n if (!response.ok) {\n const errorBody = await parseBody(response);\n if (attempt < maxRetries && RETRIABLE_STATUS_CODES.has(response.status)) {\n const delayMs = getRetryDelayMs(config, attempt, response.headers.get(\"retry-after\"));\n const retryCtx: RetryHookContext = {\n ...hookCtx,\n delayMs,\n reason: \"http_status\",\n status: response.status,\n };\n config.hooks.onRetry?.(retryCtx);\n await sleep(delayMs);\n continue;\n }\n const apiError = new BsuirApiError(\n `BSUIR API returned HTTP ${String(response.status)} for ${method} ${path}`,\n response.status,\n endpoint,\n errorBody,\n );\n const errorCtx: ErrorHookContext = {\n ...hookCtx,\n durationMs: Date.now() - startedAt,\n error: apiError,\n };\n config.hooks.onError?.(errorCtx);\n throw apiError;\n }\n\n const parsed = (await parseBody(response)) as T;\n const responseCtx: ResponseHookContext = {\n ...hookCtx,\n status: response.status,\n durationMs: Date.now() - startedAt,\n fromCache: false,\n };\n config.hooks.onResponse?.(responseCtx);\n return parsed;\n } catch (error: unknown) {\n if (error instanceof BsuirApiError) {\n throw error;\n }\n\n if (isAbortError(error)) {\n if (options.signal?.aborted || config.signal?.aborted) {\n const abortCtx: ErrorHookContext = {\n ...hookCtx,\n durationMs: Date.now() - startedAt,\n error,\n };\n config.hooks.onError?.(abortCtx);\n throw error;\n }\n const timeoutError = new BsuirTimeoutError(\n `Request timed out after ${String(config.timeoutMs)}ms: ${path}`,\n endpoint,\n config.timeoutMs,\n error,\n );\n const timeoutCtx: ErrorHookContext = {\n ...hookCtx,\n durationMs: Date.now() - startedAt,\n error: timeoutError,\n };\n config.hooks.onError?.(timeoutCtx);\n throw timeoutError;\n }\n\n if (attempt < maxRetries) {\n const delayMs = getRetryDelayMs(config, attempt);\n const retryCtx: RetryHookContext = {\n ...hookCtx,\n delayMs,\n reason: \"network_error\",\n status: undefined,\n };\n config.hooks.onRetry?.(retryCtx);\n await sleep(delayMs);\n continue;\n }\n\n const networkError = new BsuirNetworkError(\n `Network error while requesting ${path}`,\n endpoint,\n error,\n );\n const networkErrorCtx: ErrorHookContext = {\n ...hookCtx,\n durationMs: Date.now() - startedAt,\n error: networkError,\n };\n config.hooks.onError?.(networkErrorCtx);\n throw networkError;\n }\n }\n\n throw new BsuirNetworkError(`Unexpected retry loop termination for ${path}`, endpoint, null);\n };\n\n if (canUseDedup) {\n const inFlight = config.inFlightRequests.get(cacheKey);\n if (inFlight) {\n return (await inFlight) as T;\n }\n\n const inFlightPromise: Promise<T> = performRequest()\n .then((payload) => {\n if (canUseCaching) {\n setCache(config, cacheKey, payload);\n }\n return payload;\n })\n .finally(() => {\n config.inFlightRequests.delete(cacheKey);\n });\n config.inFlightRequests.set(cacheKey, inFlightPromise);\n return await inFlightPromise;\n }\n\n const payload = await performRequest();\n if (canUseCaching) {\n setCache(config, cacheKey, payload);\n }\n return payload;\n}\n","import { BsuirResponseValidationError } from \"./errors\";\nimport type { ApiDateResponse } from \"../types/common\";\nimport type { ScheduleResponse } from \"../types/schedule\";\n\nfunction asRecord(payload: unknown): Record<string, unknown> | null {\n if (typeof payload !== \"object\" || payload === null || Array.isArray(payload)) {\n return null;\n }\n return payload as Record<string, unknown>;\n}\n\nfunction ensureRecord(payload: unknown, endpoint: string, expected: string): Record<string, unknown> {\n const record = asRecord(payload);\n if (!record) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: expected ${expected}`,\n endpoint\n );\n }\n return record;\n}\n\nfunction isNullableObject(value: unknown): boolean {\n return value === null || value === undefined || (typeof value === \"object\" && !Array.isArray(value));\n}\n\nexport function assertArrayResponse(payload: unknown, endpoint: string): asserts payload is unknown[] {\n if (!Array.isArray(payload)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: expected array, got ${typeof payload}`,\n endpoint\n );\n }\n}\n\nexport function assertApiDateResponse(\n payload: unknown,\n endpoint: string\n): asserts payload is ApiDateResponse {\n const record = ensureRecord(payload, endpoint, \"object with lastUpdateDate\");\n if (typeof record.lastUpdateDate !== \"string\" || record.lastUpdateDate.trim().length === 0) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'lastUpdateDate' must be a non-empty string, got ${typeof record.lastUpdateDate}`,\n endpoint\n );\n }\n}\n\nexport function assertScheduleResponse(\n payload: unknown,\n endpoint: string\n): asserts payload is ScheduleResponse {\n const record = ensureRecord(payload, endpoint, \"object\");\n const schedules = record.schedules;\n const exams = record.exams;\n const employeeDto = record.employeeDto;\n const studentGroupDto = record.studentGroupDto;\n\n // undefined treated as absent field — API may omit schedules/exams for exam-only or schedule-only entries\n if (schedules !== null && schedules !== undefined) {\n if (typeof schedules !== \"object\" || Array.isArray(schedules)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'schedules' must be object or null, got ${\n Array.isArray(schedules) ? \"array\" : typeof schedules\n }`,\n endpoint\n );\n }\n }\n\n if (exams !== null && exams !== undefined) {\n if (!Array.isArray(exams)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'exams' must be array or null, got ${typeof exams}`,\n endpoint\n );\n }\n }\n\n if (!isNullableObject(employeeDto)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'employeeDto' must be object or null, got ${typeof employeeDto}`,\n endpoint\n );\n }\n\n if (!isNullableObject(studentGroupDto)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'studentGroupDto' must be object or null, got ${typeof studentGroupDto}`,\n endpoint\n );\n }\n}\n","import { BsuirApiError } from \"../client/errors\";\nimport { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { InternalClientConfig } from \"../client/types\";\nimport type { Announcement } from \"../types/announcement\";\nimport { assertEmployeeUrlId, assertPositiveInt } from \"../utils/guards\";\nimport type { ReadOptions } from \"./types\";\n\nconst ANNOUNCEMENT_EMPTY_LIST_STATUSES = new Set<number>([404, 400]);\n\n/**\n * Fetches an announcement list, converting empty responses (404/400) to empty arrays.\n * The BSUIR IIS API returns 404 or 400 when an entity has no announcements or endpoint doesn't exist.\n * This function normalizes those to an empty list instead of throwing an error.\n *\n * @returns The announcement list, or empty array if API returned 404/400\n * @throws {BsuirApiError} For non-empty responses with error status codes\n * @throws {BsuirNetworkError} On transport failures\n * @throws {BsuirTimeoutError} When request times out\n */\nasync function requestAnnouncementList(\n config: Readonly<InternalClientConfig>,\n path: string,\n options: ReadOptions & { query: Record<string, string | number> }\n): Promise<Announcement[]> {\n try {\n const payload = await requestJson<unknown>(config, path, options);\n if (config.validateResponses) {\n assertArrayResponse(payload, path);\n }\n return payload as Announcement[];\n } catch (error) {\n if (error instanceof BsuirApiError && ANNOUNCEMENT_EMPTY_LIST_STATUSES.has(error.status)) {\n return [];\n }\n throw error;\n }\n}\n\nexport function createAnnouncementsModule(config: Readonly<InternalClientConfig>) {\n return {\n /**\n * Lists announcements for an employee. IIS may return HTTP `404` or `400` (no list / endpoint quirks); the SDK maps those to `[]`.\n */\n async byEmployee(urlId: string, options: ReadOptions = {}): Promise<Announcement[]> {\n assertEmployeeUrlId(urlId, \"urlId\");\n return requestAnnouncementList(config, \"/announcements/employees\", {\n ...options,\n query: { \"url-id\": urlId }\n });\n },\n\n /**\n * Lists announcements for a department. IIS may return HTTP `404` or `400` (no list / endpoint quirks); the SDK maps those to `[]`.\n */\n async byDepartment(id: number, options: ReadOptions = {}): Promise<Announcement[]> {\n assertPositiveInt(id, \"id\");\n return requestAnnouncementList(config, \"/announcements/departments\", {\n ...options,\n query: { id }\n });\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { Auditory } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createAuditoriesModule(config: Readonly<InternalClientConfig>) {\n return {\n /**\n * Returns the full list of auditories from `/auditories`.\n * If the caller aborts `options.signal`, the platform propagates `AbortError` (not wrapped by the SDK).\n *\n * @throws {BsuirApiError} When the API returns a non-success HTTP status\n * @throws {BsuirNetworkError} On transport failures after retries\n * @throws {BsuirTimeoutError} When the request exceeds `timeoutMs`\n */\n async listAll(options: ReadOptions = {}): Promise<Auditory[]> {\n const payload = await requestJson<unknown>(config, \"/auditories\", {\n signal: options.signal\n });\n if (config.validateResponses) {\n assertArrayResponse(payload, \"/auditories\");\n }\n return payload as Auditory[];\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { Department } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createDepartmentsModule(config: Readonly<InternalClientConfig>) {\n return {\n /**\n * Returns the full list of departments from `/departments`.\n * If the caller aborts `options.signal`, the platform propagates `AbortError` (not wrapped by the SDK).\n *\n * @throws {BsuirApiError} When the API returns a non-success HTTP status\n * @throws {BsuirNetworkError} On transport failures after retries\n * @throws {BsuirTimeoutError} When the request exceeds `timeoutMs`\n */\n async listAll(options: ReadOptions = {}): Promise<Department[]> {\n const payload = await requestJson<unknown>(config, \"/departments\", {\n signal: options.signal\n });\n if (config.validateResponses) {\n assertArrayResponse(payload, \"/departments\");\n }\n return payload as Department[];\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { EmployeeCatalogItem } from \"../types/employee\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createEmployeesModule(config: Readonly<InternalClientConfig>) {\n return {\n /**\n * Returns the full list of employees from `/employees/all`.\n * If the caller aborts `options.signal`, the platform propagates `AbortError` (not wrapped by the SDK).\n *\n * @throws {BsuirApiError} When the API returns a non-success HTTP status\n * @throws {BsuirNetworkError} On transport failures after retries\n * @throws {BsuirTimeoutError} When the request exceeds `timeoutMs`\n */\n async listAll(options: ReadOptions = {}): Promise<EmployeeCatalogItem[]> {\n const payload = await requestJson<unknown>(config, \"/employees/all\", {\n signal: options.signal\n });\n if (config.validateResponses) {\n assertArrayResponse(payload, \"/employees/all\");\n }\n return payload as EmployeeCatalogItem[];\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { Faculty } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createFacultiesModule(config: Readonly<InternalClientConfig>) {\n return {\n /**\n * Returns the full list of faculties from `/faculties`.\n * If the caller aborts `options.signal`, the platform propagates `AbortError` (not wrapped by the SDK).\n *\n * @throws {BsuirApiError} When the API returns a non-success HTTP status\n * @throws {BsuirNetworkError} On transport failures after retries\n * @throws {BsuirTimeoutError} When the request exceeds `timeoutMs`\n */\n async listAll(options: ReadOptions = {}): Promise<Faculty[]> {\n const payload = await requestJson<unknown>(config, \"/faculties\", {\n signal: options.signal\n });\n if (config.validateResponses) {\n assertArrayResponse(payload, \"/faculties\");\n }\n return payload as Faculty[];\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { StudentGroupCatalogItem } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createGroupsModule(config: Readonly<InternalClientConfig>) {\n return {\n /**\n * Returns the full list of student groups from `/student-groups`.\n * If the caller aborts `options.signal`, the platform propagates `AbortError` (not wrapped by the SDK).\n *\n * @throws {BsuirApiError} When the API returns a non-success HTTP status\n * @throws {BsuirNetworkError} On transport failures after retries\n * @throws {BsuirTimeoutError} When the request exceeds `timeoutMs`\n */\n async listAll(options: ReadOptions = {}): Promise<StudentGroupCatalogItem[]> {\n const payload = await requestJson<unknown>(config, \"/student-groups\", {\n signal: options.signal\n });\n if (config.validateResponses) {\n assertArrayResponse(payload, \"/student-groups\");\n }\n return payload as StudentGroupCatalogItem[];\n }\n };\n}\n","import { BsuirValidationError } from \"../client/errors\";\nimport { assertPositiveInt } from \"./guards\";\n\n// API response should never nest deeper than 2 levels; 10 is a generous safety cap to prevent stack overflow\nconst MAX_PARSE_DEPTH = 10;\n\n/**\n * Normalizes current week payload from API to a positive integer.\n * API can return plain text (`\"1\\n\"`) or number.\n */\nexport function parseCurrentWeek(payload: unknown): number {\n return parseCurrentWeekInternal(payload, 0);\n}\n\nfunction parseCurrentWeekInternal(payload: unknown, depth: number): number {\n if (depth > MAX_PARSE_DEPTH) {\n throw new BsuirValidationError(\"'currentWeek' response payload has excessive nesting depth\");\n }\n\n if (typeof payload === \"number\") {\n assertPositiveInt(payload, \"currentWeek\");\n return payload;\n }\n\n if (typeof payload === \"string\") {\n const normalized = payload.trim();\n if (normalized.length === 0) {\n throw new BsuirValidationError(\n \"'currentWeek' response payload is an empty string\"\n );\n }\n const parsed = Number(normalized);\n // assertPositiveInt validates both isInteger and > 0 — no need to pre-check isInteger\n assertPositiveInt(parsed, \"currentWeek\");\n return parsed;\n }\n\n if (typeof payload === \"object\" && payload !== null) {\n const record = payload as Record<string, unknown>;\n if (\"weekNumber\" in record) {\n return parseCurrentWeekInternal(record.weekNumber, depth + 1);\n }\n if (\"currentWeek\" in record) {\n return parseCurrentWeekInternal(record.currentWeek, depth + 1);\n }\n }\n\n throw new BsuirValidationError(\"'currentWeek' response payload must be a positive integer\");\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertApiDateResponse, assertScheduleResponse } from \"../client/responseValidators\";\nimport { assertEmployeeUrlId, assertGroupNumber, assertPositiveInt } from \"../utils/guards\";\nimport type {\n FlattenedLessonsByDay,\n FlattenedScheduleItem,\n NormalizedScheduleResponse,\n ScheduleFilterOptions,\n ScheduleItem,\n ScheduleResponse\n} from \"../types/schedule\";\nimport type { ApiDateResponse } from \"../types/common\";\nimport type { Weekday } from \"../types/common\";\nimport type { ReadOptions } from \"./types\";\nimport { parseCurrentWeek } from \"../utils/week\";\n\nconst WEEKDAYS: Weekday[] = [\n \"Понедельник\",\n \"Вторник\",\n \"Среда\",\n \"Четверг\",\n \"Пятница\",\n \"Суббота\"\n];\n\nfunction lessonAuditories(item: ScheduleItem): string[] {\n const { auditories } = item;\n return Array.isArray(auditories) ? auditories : [];\n}\n\ntype ScheduleResponseByRawOption<TRaw extends boolean | undefined, TRawDefault extends boolean> =\n TRaw extends true\n ? ScheduleResponse\n : TRaw extends false\n ? NormalizedScheduleResponse\n : TRawDefault extends true\n ? ScheduleResponse\n : NormalizedScheduleResponse;\n\n/**\n * Transforms raw API schedule response into a normalized structure with flattened lessons.\n *\n * Raw API response contains lessons grouped by weekday (`schedules` object with day keys)\n * and exams in a separate array. This function flattens them into a single `lessons` array\n * for easier filtering and iteration, while preserving day-grouped view in `lessonsByDay`.\n *\n * @param response - Raw schedule response from API\n * @returns Normalized schedule with additional computed fields: `lessons` (flattened array),\n * `lessonsByDay` (grouped by weekday), `scheduleLessons`, and `examLessons`\n *\n * @example\n * ```ts\n * const rawSchedule = await client.schedule.getGroup(\"053503\", { raw: true });\n * const normalized = normalizeSchedule(rawSchedule);\n * console.log(normalized.lessons.length); // All lessons + exams flattened\n * console.log(normalized.lessonsByDay[\"Понедельник\"]); // Monday-only lessons\n * console.log(normalized.scheduleLessons.length); // Only regular schedule\n * console.log(normalized.examLessons.length); // Only exams\n * ```\n */\nexport function normalizeSchedule(response: ScheduleResponse): NormalizedScheduleResponse {\n const lessons: FlattenedScheduleItem[] = [];\n const scheduleLessons: FlattenedScheduleItem[] = [];\n const examLessons: FlattenedScheduleItem[] = [];\n // Initialize with all WEEKDAYS keys mapped to empty arrays to satisfy Readonly<> type\n const lessonsByDay = Object.fromEntries(\n WEEKDAYS.map((day) => [day, [] as FlattenedScheduleItem[]])\n ) as FlattenedLessonsByDay;\n const safeSchedules = response.schedules ?? {};\n const safeExams = response.exams ?? [];\n\n // Build lessons and lessonsByDay in single pass, collecting schedule lessons\n for (const day of WEEKDAYS) {\n const dayItems = safeSchedules[day] ?? [];\n const flattenedDayItems = dayItems.map((item) => {\n const auditories = lessonAuditories(item);\n return {\n ...item,\n auditories,\n day,\n source: \"schedules\" as const\n };\n });\n lessonsByDay[day] = flattenedDayItems;\n lessons.push(...flattenedDayItems);\n scheduleLessons.push(...flattenedDayItems);\n }\n\n // Collect exam lessons\n for (const exam of safeExams) {\n const auditories = lessonAuditories(exam);\n const flattenedExam: FlattenedScheduleItem = {\n ...exam,\n auditories,\n day: null,\n // Exams are not grouped by weekday in API response.\n source: \"exams\"\n };\n lessons.push(flattenedExam);\n examLessons.push(flattenedExam);\n }\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 && !lessonAuditories(item).includes(filter.auditory)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Filters normalized schedule lessons by specified criteria.\n *\n * @param response - Normalized schedule response containing lessons\n * @param filter - Filter options with optional fields: source, weekday, weekNumber, subgroup,\n * lessonTypeAbbrev, subjectQuery, employeeUrlId, auditory\n * @returns Array of lessons matching all provided filter criteria\n *\n * @example\n * ```ts\n * const schedule = await client.schedule.getGroup(\"053503\");\n * const mondayLessons = filterLessons(schedule, { weekday: \"Понедельник\" });\n * const practiceLessons = filterLessons(schedule, { lessonTypeAbbrev: \"пр\" });\n * const lectureLessons = filterLessons(schedule, { lessonTypeAbbrev: [\"лк\", \"лекция\"] });\n * ```\n */\nexport function filterLessons(\n response: NormalizedScheduleResponse,\n filter: ScheduleFilterOptions\n): FlattenedScheduleItem[] {\n // Validate weekNumber early — week 0 does not exist in BSUIR schedule\n if (typeof filter.weekNumber === \"number\") {\n assertPositiveInt(filter.weekNumber, \"filter.weekNumber\");\n }\n return response.lessons.filter((item) => matchesFilter(item, filter));\n}\n\nexport function createScheduleModule<TRawDefault extends boolean>(\n config: Readonly<InternalClientConfig<TRawDefault>>\n) {\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<ScheduleResponseByRawOption<TRaw, TRawDefault>> {\n assertGroupNumber(groupNumber, \"groupNumber\");\n const payload = await requestJson<unknown>(config, \"/schedule\", {\n query: { studentGroup: groupNumber },\n signal: options.signal\n });\n if (config.validateResponses) {\n assertScheduleResponse(payload, \"/schedule\");\n }\n const response = payload as ScheduleResponse;\n const result = options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);\n return result as ScheduleResponseByRawOption<TRaw, TRawDefault>;\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<ScheduleResponseByRawOption<TRaw, TRawDefault>> {\n assertEmployeeUrlId(urlId, \"urlId\");\n const endpoint = `/employees/schedule/${encodeURIComponent(urlId)}`;\n const payload = await requestJson<unknown>(config, endpoint, { signal: options.signal });\n if (config.validateResponses) {\n assertScheduleResponse(payload, endpoint);\n }\n const response = payload as ScheduleResponse;\n const result = options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);\n return result as ScheduleResponseByRawOption<TRaw, TRawDefault>;\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 parseCurrentWeek(payload);\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\n /**\n * Calls IIS `/last-update-date/student-group`. That route is legacy and unsupported on the server;\n * it may return an error for newer group numbers (e.g. six-digit `524404`).\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 const payload = await requestJson<unknown>(config, \"/last-update-date/student-group\", {\n query,\n signal: options.signal\n });\n if (config.validateResponses) {\n assertApiDateResponse(payload, \"/last-update-date/student-group\");\n }\n return payload as ApiDateResponse;\n },\n\n /**\n * Calls IIS `/last-update-date/employee`. That route is legacy and unsupported on the server; prefer\n * not relying on it for critical cache logic.\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 const payload = await requestJson<unknown>(config, \"/last-update-date/employee\", {\n query,\n signal: options.signal\n });\n if (config.validateResponses) {\n assertApiDateResponse(payload, \"/last-update-date/employee\");\n }\n return payload as ApiDateResponse;\n }\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { Speciality } from \"../types/catalog\";\nimport type { ReadOptions } from \"./types\";\n\nexport function createSpecialitiesModule(config: Readonly<InternalClientConfig>) {\n return {\n /**\n * Returns the full list of specialities from `/specialities`.\n * If the caller aborts `options.signal`, the platform propagates `AbortError` (not wrapped by the SDK).\n *\n * @throws {BsuirApiError} When the API returns a non-success HTTP status\n * @throws {BsuirNetworkError} On transport failures after retries\n * @throws {BsuirTimeoutError} When the request exceeds `timeoutMs`\n */\n async listAll(options: ReadOptions = {}): Promise<Speciality[]> {\n const payload = await requestJson<unknown>(config, \"/specialities\", {\n signal: options.signal\n });\n if (config.validateResponses) {\n assertArrayResponse(payload, \"/specialities\");\n }\n return payload as Speciality[];\n }\n };\n}\n","import { BsuirConfigurationError } from \"./errors\";\nimport type { BsuirClientOptions, InternalClientConfig } from \"./types\";\nimport {\n createAnnouncementsModule,\n createAuditoriesModule,\n createDepartmentsModule,\n createEmployeesModule,\n createFacultiesModule,\n createGroupsModule,\n createScheduleModule,\n createSpecialitiesModule\n} from \"../modules\";\n\nconst DEFAULT_BASE_URL = \"https://iis.bsuir.by/api/v1\";\n\n// Prevents setTimeout() integer overflow (max safe value ~24.8 days).\n// 5 minutes is a generous upper bound for any HTTP request in this context.\nconst MAX_TIMEOUT_MS = 300_000;\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 BsuirConfigurationError(\n \"Global fetch is unavailable. Provide 'fetch' in createBsuirClient options.\"\n );\n }\n\n return globalThis.fetch;\n}\n\nfunction assertIntegerOption(\n value: number | undefined,\n name: string,\n minInclusive: number\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n if (!Number.isFinite(value) || !Number.isInteger(value) || value < minInclusive) {\n throw new BsuirConfigurationError(\n `'${name}' must be an integer greater than or equal to ${String(minInclusive)}`\n );\n }\n return value;\n}\n\nfunction createInternalConfig<TRawDefault extends boolean>(\n options: BsuirClientOptions & { defaultRaw: TRawDefault }\n): InternalClientConfig<TRawDefault> {\n const timeoutMs = assertIntegerOption(options.timeoutMs, \"timeoutMs\", 1) ?? 10_000;\n if (timeoutMs > MAX_TIMEOUT_MS) {\n throw new BsuirConfigurationError(\n `'timeoutMs' must not exceed ${String(MAX_TIMEOUT_MS)}ms (5 minutes)`\n );\n }\n\n const retries = assertIntegerOption(options.retries, \"retries\", 0) ?? 1;\n const retryDelayMs = assertIntegerOption(options.retryDelayMs, \"retryDelayMs\", 0) ?? 300;\n const retryMaxDelayMs =\n assertIntegerOption(options.retryMaxDelayMs, \"retryMaxDelayMs\", 0) ?? 3_000;\n const cacheTtlMs = assertIntegerOption(options.cache?.ttlMs, \"cache.ttlMs\", 1);\n const cacheMaxEntries =\n assertIntegerOption(options.cache?.maxEntries, \"cache.maxEntries\", 1) ?? 200;\n\n if (retryDelayMs > retryMaxDelayMs) {\n throw new BsuirConfigurationError(\n \"'retryDelayMs' must be less than or equal to 'retryMaxDelayMs'\"\n );\n }\n\n return {\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n fetchImpl: resolveFetch(options.fetch),\n signal: options.signal,\n timeoutMs,\n retries,\n retryDelayMs,\n retryMaxDelayMs,\n retryJitter: options.retryJitter ?? true,\n userAgent: options.userAgent,\n cacheTtlMs,\n cacheMaxEntries,\n dedupeInFlight: options.dedupeInFlight ?? true,\n validateResponses: options.validateResponses ?? false,\n hooks: options.hooks ?? {},\n responseCache: new Map(),\n inFlightRequests: new Map(),\n defaultRaw: options.defaultRaw\n };\n}\n\n/**\n * Fully-typed public shape of the BSUIR API client.\n * All module types are inlined so API Extractor never needs to reach into private helpers.\n *\n * `TRawDefault` controls the default return type of\n * `schedule.getGroup` / `schedule.getEmployee` when the per-call `raw` option is omitted:\n * - `false` (default) → returns `NormalizedScheduleResponse`\n * - `true` → returns `ScheduleResponse` (raw API payload)\n *\n * Per-call `raw` always takes precedence over this default.\n *\n * @example\n * ```ts\n * // Default (normalized):\n * const client = createBsuirClient();\n * const norm = await client.schedule.getGroup(\"053503\"); // NormalizedScheduleResponse\n *\n * // Raw by default:\n * const rawClient = createBsuirClient({ defaultRaw: true });\n * const raw = await rawClient.schedule.getGroup(\"053503\"); // ScheduleResponse\n *\n * // Per-call override (always wins):\n * const override = await client.schedule.getGroup(\"053503\", { raw: true }); // ScheduleResponse\n * ```\n */\nexport interface BsuirClientShape<TRawDefault extends boolean> {\n schedule: ReturnType<typeof createScheduleModule<TRawDefault>>;\n groups: ReturnType<typeof createGroupsModule>;\n employees: ReturnType<typeof createEmployeesModule>;\n faculties: ReturnType<typeof createFacultiesModule>;\n departments: ReturnType<typeof createDepartmentsModule>;\n specialities: ReturnType<typeof createSpecialitiesModule>;\n announcements: ReturnType<typeof createAnnouncementsModule>;\n auditories: ReturnType<typeof createAuditoriesModule>;\n};\n\n/**\n * Creates a configured BSUIR IIS API client.\n *\n * Pass `{ defaultRaw: true }` to switch the default return shape of\n * `schedule.getGroup` and `schedule.getEmployee` from `NormalizedScheduleResponse`\n * to the raw `ScheduleResponse`. Per-call `raw` option always takes precedence.\n *\n * @example\n * ```ts\n * // Normalized (default):\n * const client = createBsuirClient();\n *\n * // Raw by default:\n * const rawClient = createBsuirClient({ defaultRaw: true });\n *\n * // Custom fetch + timeout:\n * const client = createBsuirClient({ fetch: myFetch, timeoutMs: 5_000 });\n * ```\n */\nexport function createBsuirClient(\n options: BsuirClientOptions & { defaultRaw: true }\n): BsuirClientShape<true>;\nexport function createBsuirClient(\n options?: BsuirClientOptions & { defaultRaw?: false | undefined }\n): BsuirClientShape<false>;\nexport function createBsuirClient(\n options: BsuirClientOptions = {}\n): BsuirClientShape<boolean> {\n const defaultRaw = options.defaultRaw ?? false;\n const config = createInternalConfig({ ...options, defaultRaw });\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 };\n}\n\n/**\n * Public client contract returned by `createBsuirClient`.\n * Use `BsuirClientShape<true>` or `BsuirClientShape<false>` for typed overloads.\n */\nexport type BsuirClient = ReturnType<typeof createBsuirClient>;\n"],"mappings":"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","names":["payload"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/errors.ts","../src/client/mergeSignals.ts","../src/utils/guards.ts","../src/client/http/cache.ts","../src/client/http/response.ts","../src/client/http/retry.ts","../src/client/http/url.ts","../src/client/http/requestJson.ts","../src/client/responseValidators.ts","../src/modules/announcements.ts","../src/modules/createListModule.ts","../src/modules/auditories.ts","../src/modules/departments.ts","../src/modules/employees.ts","../src/modules/faculties.ts","../src/modules/groups.ts","../src/utils/week.ts","../src/modules/scheduleFilter.ts","../src/modules/scheduleNormalize.ts","../src/modules/scheduleApi.ts","../src/modules/specialities.ts","../src/client/createClient.ts"],"sourcesContent":["/**\n * Restores proper prototype chain for Error subclasses in transpiled outputs.\n * TypeScript's ES<2015 transpilation breaks `class Foo extends Error`:\n * the compiled function lacks Error.prototype in its chain. This restores it.\n * See: https://github.com/microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins\n */\nfunction fixErrorPrototype(instance: Error, prototype: object): void {\n Object.setPrototypeOf(instance, prototype);\n}\n\nexport 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 fixErrorPrototype(this, BsuirApiError.prototype);\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\n constructor(message: string, endpoint: string, cause: unknown) {\n super(message, { cause });\n fixErrorPrototype(this, BsuirNetworkError.prototype);\n this.name = \"BsuirNetworkError\";\n this.endpoint = endpoint;\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, cause?: unknown) {\n super(message, { cause });\n fixErrorPrototype(this, BsuirTimeoutError.prototype);\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 fixErrorPrototype(this, BsuirValidationError.prototype);\n this.name = \"BsuirValidationError\";\n }\n}\n\nexport class BsuirResponseValidationError extends Error {\n readonly endpoint: string;\n\n constructor(message: string, endpoint: string) {\n super(message);\n fixErrorPrototype(this, BsuirResponseValidationError.prototype);\n this.name = \"BsuirResponseValidationError\";\n this.endpoint = endpoint;\n }\n}\n\nexport class BsuirConfigurationError extends Error {\n constructor(message: string) {\n super(message);\n fixErrorPrototype(this, BsuirConfigurationError.prototype);\n this.name = \"BsuirConfigurationError\";\n }\n}\n","type AbortSignalConstructor = typeof AbortSignal & {\n any?(signals: AbortSignal[]): AbortSignal;\n};\n\nconst AbortSignalCtor = AbortSignal as AbortSignalConstructor;\n\n/**\n * Combines multiple abort signals and/or a timeout into a single signal.\n * When `AbortSignal.any` exists at runtime, delegates to the platform implementation.\n * Otherwise uses a manual merge so all signals are respected.\n *\n * @param signalsOrFirst - Array of signals to merge, or a single signal (legacy signature)\n * @param timeoutMs - Optional timeout in milliseconds to include as an additional signal\n *\n * @remarks\n * Calling with no signals and no timeout (e.g. `mergeSignals([])`) returns a signal\n * that is never aborted — the caller is responsible for not doing this intentionally.\n */\nexport function mergeSignals(\n signalsOrFirst: AbortSignal[] | (AbortSignal | undefined),\n timeoutMs?: number\n): AbortSignal {\n // Handle both signatures for backwards compatibility\n let signals: (AbortSignal | undefined)[];\n let timeout: number | undefined;\n\n if (Array.isArray(signalsOrFirst)) {\n signals = signalsOrFirst;\n timeout = timeoutMs;\n } else {\n // Legacy signature: mergeSignals(signal, timeoutMs)\n signals = [signalsOrFirst];\n timeout = timeoutMs;\n }\n\n const parts = signals.filter((s): s is AbortSignal => s !== undefined);\n\n if (parts.length === 0) {\n if (timeout !== undefined) {\n // Only a timeout, no external signal\n if (typeof AbortSignalCtor.any === \"function\") {\n return AbortSignalCtor.any([AbortSignal.timeout(timeout)]);\n }\n return mergeSignalsManual([], timeout);\n }\n // No signals and no timeout — returns a signal that is never aborted.\n // This is a degenerate case; callers should avoid it.\n return new AbortController().signal;\n }\n\n if (parts.length === 1 && timeout === undefined) {\n // Single signal, no timeout — return it directly\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return parts[0]!;\n }\n\n // Use platform AbortSignal.any when available (covers both timeout and multi-signal cases)\n if (typeof AbortSignalCtor.any === \"function\") {\n const all = timeout !== undefined ? [...parts, AbortSignal.timeout(timeout)] : parts;\n return AbortSignalCtor.any(all);\n }\n\n // Fallback: manual merge with possible timeout\n return mergeSignalsManual(parts, timeout);\n}\n\n/** Used when `AbortSignal.any` is unavailable; exposed for unit tests. */\nexport function mergeSignalsManual(signals: AbortSignal[], timeoutMs?: number): AbortSignal {\n if (signals.length === 0 && timeoutMs === undefined) {\n return new AbortController().signal;\n }\n if (signals.length === 1 && timeoutMs === undefined) {\n // Single signal, no timeout\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return signals[0]!;\n }\n\n const combined = new AbortController();\n const listeners: { signal: AbortSignal; handler: () => void }[] = [];\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const onAnyAbort = (): void => {\n if (!combined.signal.aborted) {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n combined.abort();\n }\n };\n\n // Setup timeout if provided\n if (timeoutMs !== undefined) {\n timeoutId = setTimeout(() => {\n if (!combined.signal.aborted) {\n combined.abort();\n }\n }, timeoutMs);\n }\n\n // Setup listeners for external signals\n for (const signal of signals) {\n if (signal.aborted) {\n onAnyAbort();\n break;\n } else {\n signal.addEventListener(\"abort\", onAnyAbort, { once: true });\n listeners.push({ signal, handler: onAnyAbort });\n }\n }\n\n // Cleanup listeners and timeout when combined signal aborts to prevent memory leaks\n combined.signal.addEventListener(\n \"abort\",\n () => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n for (const listener of listeners) {\n listener.signal.removeEventListener(\"abort\", listener.handler);\n }\n },\n { once: true }\n );\n\n return combined.signal;\n}\n","import { BsuirValidationError } from \"../client/errors\";\n\n// BSUIR IIS API accepts only numeric group IDs (e.g., \"053503\").\n// Pattern is intentionally strict and covers only current IIS format.\nconst GROUP_NUMBER_PATTERN = /^\\d+$/;\nconst EMPLOYEE_URL_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/i;\n\nexport function assertNonEmptyString(value: unknown, fieldName: string): asserts value is string {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new BsuirValidationError(`'${fieldName}' must be a non-empty string`);\n }\n}\n\nexport function assertPositiveInt(value: unknown, fieldName: string): asserts value is number {\n if (typeof value !== \"number\" || !Number.isInteger(value) || value <= 0) {\n throw new BsuirValidationError(`'${fieldName}' must be a positive integer`);\n }\n}\n\nexport function assertGroupNumber(value: unknown, fieldName = \"groupNumber\"): asserts value is string {\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: unknown, fieldName = \"urlId\"): asserts value is string {\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 // Browser: DOMException with name \"AbortError\"\n if (error instanceof DOMException && error.name === \"AbortError\") {\n return true;\n }\n\n // Node.js: Error-like object with code \"ABORT_ERR\"\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 type { InternalClientConfig } from \"../types\";\n\n/**\n * Reads a cached response value by key, applying TTL validation and LRU touch update.\n */\nexport function tryReadCache(config: Readonly<InternalClientConfig>, key: string): unknown {\n const entry = config.responseCache.get(key);\n if (!entry) {\n return undefined;\n }\n if (entry.expiresAt <= Date.now()) {\n config.responseCache.delete(key);\n return undefined;\n }\n // Update accessedAt on every read so LRU eviction keeps frequently-used entries alive.\n entry.accessedAt = Date.now();\n return entry.value;\n}\n\n/**\n * Writes response value to cache and performs eviction when size approaches capacity.\n */\nexport function setCache(config: Readonly<InternalClientConfig>, key: string, value: unknown): void {\n if (config.cacheTtlMs === undefined) {\n return;\n }\n const now = Date.now();\n\n // Re-insert to refresh insertion order in the Map (used as tie-breaker after accessedAt sort).\n config.responseCache.delete(key);\n config.responseCache.set(key, {\n value,\n expiresAt: now + config.cacheTtlMs,\n accessedAt: now,\n });\n\n // Only trigger cleanup when cache is approaching capacity (>90%) to avoid O(n) scan on every set.\n const cleanupThreshold = config.cacheMaxEntries * 0.9;\n if (config.responseCache.size <= cleanupThreshold) {\n return;\n }\n\n // Remove expired entries first — cheapest cleanup, no sorting needed.\n for (const [k, v] of config.responseCache) {\n if (v.expiresAt <= now) {\n config.responseCache.delete(k);\n }\n }\n\n // True LRU eviction: sort all remaining entries by accessedAt ascending and\n // drop the least-recently-used ones until we are within capacity.\n // O(n log n) but only runs when the cache is nearly full, so it is infrequent.\n if (config.responseCache.size > config.cacheMaxEntries) {\n const byLeastRecentlyUsed = [...config.responseCache.entries()].sort(\n (a, b) => a[1].accessedAt - b[1].accessedAt,\n );\n for (const [k] of byLeastRecentlyUsed) {\n if (config.responseCache.size <= config.cacheMaxEntries) {\n break;\n }\n config.responseCache.delete(k);\n }\n }\n}\n","import { BsuirApiError } from \"../errors\";\n\nasync function readBodyTextWithLimit(response: Response, maxResponseBytes: number): Promise<string> {\n const contentLengthHeader = response.headers.get(\"content-length\");\n if (contentLengthHeader) {\n const parsedLength = Number(contentLengthHeader);\n if (Number.isFinite(parsedLength) && parsedLength > maxResponseBytes) {\n throw new BsuirApiError(\n `Response body exceeds maxResponseBytes limit (${String(maxResponseBytes)} bytes)`,\n response.status,\n response.url,\n null\n );\n }\n }\n\n if (!response.body || typeof response.body.getReader !== \"function\") {\n const fallbackText = await response.text();\n if (new TextEncoder().encode(fallbackText).byteLength > maxResponseBytes) {\n throw new BsuirApiError(\n `Response body exceeds maxResponseBytes limit (${String(maxResponseBytes)} bytes)`,\n response.status,\n response.url,\n null\n );\n }\n return fallbackText;\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let bytesRead = 0;\n let text = \"\";\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n bytesRead += value.byteLength;\n if (bytesRead > maxResponseBytes) {\n await reader.cancel();\n throw new BsuirApiError(\n `Response body exceeds maxResponseBytes limit (${String(maxResponseBytes)} bytes)`,\n response.status,\n response.url,\n null\n );\n }\n text += decoder.decode(value, { stream: true });\n }\n text += decoder.decode();\n return text;\n}\n\n/**\n * Parses response body as JSON when possible, otherwise returns text.\n * Throws `BsuirApiError` for declared JSON payloads that are empty/invalid.\n */\nexport async function parseBody(response: Response, maxResponseBytes: number): Promise<unknown> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const declaredJson = contentType.includes(\"application/json\");\n const text = await readBodyTextWithLimit(response, maxResponseBytes);\n if (text.length === 0) {\n if (declaredJson) {\n throw new BsuirApiError(\"Invalid JSON response payload\", response.status, response.url, null);\n }\n return \"\";\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n if (declaredJson) {\n throw new BsuirApiError(\"Invalid JSON response payload\", response.status, response.url, null);\n }\n return text;\n }\n}\n","import type { InternalClientConfig } from \"../types\";\n\n/** HTTP status codes retriable by the request pipeline. */\nexport const RETRIABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504]);\n\n/** Delays execution for a specified number of milliseconds. */\nexport function 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 || retryAfter.trim().length === 0) {\n return null;\n }\n\n // Try parsing as seconds (RFC 7231: numeric-value).\n const asSeconds = Number(retryAfter);\n if (Number.isFinite(asSeconds) && asSeconds >= 0) {\n // Validate it's actually numeric format, not a date string starting with a digit.\n if (/^\\d+(\\.\\d+)?$/.test(retryAfter.trim())) {\n return Math.floor(asSeconds * 1000);\n }\n }\n\n // Try parsing as HTTP date format (RFC 7231: http-date).\n const dateValue = Date.parse(retryAfter);\n if (Number.isFinite(dateValue)) {\n const delayMs = dateValue - Date.now();\n // Only accept if date is in the future.\n if (delayMs > 0) {\n return Math.min(delayMs, 86_400_000); // Cap at 24 hours to prevent unreasonably long waits.\n }\n }\n\n return null;\n}\n\n/**\n * Calculates retry delay using `Retry-After` when present, otherwise exponential backoff.\n */\nexport function getRetryDelayMs(\n config: Readonly<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","import type { QueryParams } from \"../types\";\n\n/**\n * Builds absolute endpoint URL from base URL, path and query params.\n */\nexport function 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","import { BsuirApiError, BsuirNetworkError, BsuirTimeoutError } from \"../errors\";\nimport { mergeSignals } from \"../mergeSignals\";\nimport type {\n ErrorHookContext,\n InternalClientConfig,\n QueryParams,\n RequestHookContext,\n RequestMethod,\n RequestOptions,\n ResponseHookContext,\n RetryHookContext,\n} from \"../types\";\nimport { isAbortError } from \"../../utils/guards\";\nimport { setCache, tryReadCache } from \"./cache\";\nimport { parseBody } from \"./response\";\nimport { getRetryDelayMs, RETRIABLE_STATUS_CODES, sleep } from \"./retry\";\nimport { buildUrl } from \"./url\";\n\nfunction combineAbortSignals(\n first: AbortSignal | undefined,\n second: AbortSignal | undefined,\n): AbortSignal | undefined {\n if (!first) {\n return second;\n }\n if (!second) {\n return first;\n }\n // Delegate to mergeSignals for consistent signal combination logic.\n return mergeSignals([first, second]);\n}\n\nfunction baseHookContext(\n method: RequestMethod,\n path: string,\n endpoint: string,\n attempt: number,\n maxAttempts: number,\n query: QueryParams | undefined,\n): RequestHookContext {\n return {\n method,\n path,\n endpoint,\n attempt,\n maxAttempts,\n query,\n };\n}\n\n/**\n * Executes JSON HTTP request with timeout, retry/backoff, deduplication and cache support.\n */\nexport async function requestJson<T>(\n config: Readonly<InternalClientConfig>,\n path: string,\n options: RequestOptions = {},\n): Promise<T> {\n const endpoint = buildUrl(config.baseUrl, path, options.query);\n const method = options.method ?? \"GET\";\n const requestCanRetry = method === \"GET\";\n const maxRetries = requestCanRetry ? config.retries : 0;\n const maxAttempts = maxRetries + 1;\n const headers = new Headers({\n Accept: \"application/json\",\n });\n\n if (config.userAgent) {\n headers.set(\"User-Agent\", config.userAgent);\n }\n if (options.headers) {\n for (const [key, value] of new Headers(options.headers)) {\n headers.set(key, value);\n }\n }\n\n const body = options.body === undefined ? undefined : JSON.stringify(options.body);\n if (body !== undefined && !headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n const cacheKey = endpoint;\n // Caching and dedup are disabled when a per-call signal is provided (caller manages lifecycle)\n // OR when a global client signal is already aborted — stale data must not be served after abort.\n const hasActiveSignal = options.signal != null || config.signal?.aborted === true;\n const canUseCaching = config.cacheTtlMs !== undefined && method === \"GET\" && !hasActiveSignal;\n const canUseDedup = config.dedupeInFlight && method === \"GET\" && !hasActiveSignal;\n\n if (canUseCaching) {\n const cached = tryReadCache(config, cacheKey);\n if (cached !== undefined) {\n const cacheHitCtx: ResponseHookContext = {\n ...baseHookContext(method, path, endpoint, 1, maxAttempts, options.query),\n status: 200,\n durationMs: 0,\n fromCache: true,\n };\n config.hooks.onResponse?.(cacheHitCtx);\n return cached as T;\n }\n }\n\n const performRequest = async (): Promise<T> => {\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n const attemptNumber = attempt + 1;\n const startedAt = Date.now();\n const hookCtx = baseHookContext(method, path, endpoint, attemptNumber, maxAttempts, options.query);\n\n config.hooks.onRequest?.(hookCtx);\n\n const externalSignal = combineAbortSignals(options.signal, config.signal);\n const requestSignal = mergeSignals(externalSignal, config.timeoutMs);\n\n try {\n const requestInit: RequestInit = {\n method,\n headers,\n signal: requestSignal,\n };\n if (body !== undefined) {\n requestInit.body = body;\n }\n\n const response = await config.fetchImpl(endpoint, requestInit);\n\n if (!response.ok) {\n const errorBody = await parseBody(response, config.maxResponseBytes);\n if (attempt < maxRetries && RETRIABLE_STATUS_CODES.has(response.status)) {\n const delayMs = getRetryDelayMs(config, attempt, response.headers.get(\"retry-after\"));\n const retryCtx: RetryHookContext = {\n ...hookCtx,\n delayMs,\n reason: \"http_status\",\n status: response.status,\n };\n config.hooks.onRetry?.(retryCtx);\n await sleep(delayMs);\n continue;\n }\n const apiError = new BsuirApiError(\n `BSUIR API returned HTTP ${String(response.status)} for ${method} ${path}`,\n response.status,\n endpoint,\n errorBody,\n );\n const errorCtx: ErrorHookContext = {\n ...hookCtx,\n durationMs: Date.now() - startedAt,\n error: apiError,\n };\n config.hooks.onError?.(errorCtx);\n throw apiError;\n }\n\n const parsed = (await parseBody(response, config.maxResponseBytes)) as T;\n const responseCtx: ResponseHookContext = {\n ...hookCtx,\n status: response.status,\n durationMs: Date.now() - startedAt,\n fromCache: false,\n };\n config.hooks.onResponse?.(responseCtx);\n return parsed;\n } catch (error: unknown) {\n if (error instanceof BsuirApiError) {\n throw error;\n }\n\n if (isAbortError(error)) {\n if (options.signal?.aborted || config.signal?.aborted) {\n const abortCtx: ErrorHookContext = {\n ...hookCtx,\n durationMs: Date.now() - startedAt,\n error,\n };\n config.hooks.onError?.(abortCtx);\n throw error;\n }\n const timeoutError = new BsuirTimeoutError(\n `Request timed out after ${String(config.timeoutMs)}ms: ${path}`,\n endpoint,\n config.timeoutMs,\n error,\n );\n const timeoutCtx: ErrorHookContext = {\n ...hookCtx,\n durationMs: Date.now() - startedAt,\n error: timeoutError,\n };\n config.hooks.onError?.(timeoutCtx);\n throw timeoutError;\n }\n\n if (attempt < maxRetries) {\n const delayMs = getRetryDelayMs(config, attempt);\n const retryCtx: RetryHookContext = {\n ...hookCtx,\n delayMs,\n reason: \"network_error\",\n status: undefined,\n };\n config.hooks.onRetry?.(retryCtx);\n await sleep(delayMs);\n continue;\n }\n\n const networkError = new BsuirNetworkError(\n `Network error while requesting ${path}`,\n endpoint,\n error,\n );\n const networkErrorCtx: ErrorHookContext = {\n ...hookCtx,\n durationMs: Date.now() - startedAt,\n error: networkError,\n };\n config.hooks.onError?.(networkErrorCtx);\n throw networkError;\n }\n }\n\n throw new BsuirNetworkError(`Unexpected retry loop termination for ${path}`, endpoint, null);\n };\n\n if (canUseDedup) {\n const inFlight = config.inFlightRequests.get(cacheKey);\n if (inFlight) {\n return (await inFlight) as T;\n }\n\n const inFlightPromise: Promise<T> = performRequest()\n .then((payload) => {\n if (canUseCaching) {\n setCache(config, cacheKey, payload);\n }\n return payload;\n })\n .finally(() => {\n config.inFlightRequests.delete(cacheKey);\n });\n config.inFlightRequests.set(cacheKey, inFlightPromise);\n return await inFlightPromise;\n }\n\n const payload = await performRequest();\n if (canUseCaching) {\n setCache(config, cacheKey, payload);\n }\n return payload;\n}\n","import { BsuirResponseValidationError } from \"./errors\";\nimport type { ApiDateResponse } from \"../types/common\";\nimport type { ScheduleResponse } from \"../types/schedule\";\n\nfunction asRecord(payload: unknown): Record<string, unknown> | null {\n if (typeof payload !== \"object\" || payload === null || Array.isArray(payload)) {\n return null;\n }\n return payload as Record<string, unknown>;\n}\n\nfunction ensureRecord(payload: unknown, endpoint: string, expected: string): Record<string, unknown> {\n const record = asRecord(payload);\n if (!record) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: expected ${expected}`,\n endpoint\n );\n }\n return record;\n}\n\nfunction isNullableObject(value: unknown): boolean {\n return value === null || value === undefined || (typeof value === \"object\" && !Array.isArray(value));\n}\n\nexport function assertArrayResponse(payload: unknown, endpoint: string): asserts payload is unknown[] {\n if (!Array.isArray(payload)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: expected array, got ${typeof payload}`,\n endpoint\n );\n }\n}\n\nexport function assertApiDateResponse(\n payload: unknown,\n endpoint: string\n): asserts payload is ApiDateResponse {\n const record = ensureRecord(payload, endpoint, \"object with lastUpdateDate\");\n if (typeof record.lastUpdateDate !== \"string\" || record.lastUpdateDate.trim().length === 0) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'lastUpdateDate' must be a non-empty string, got ${typeof record.lastUpdateDate}`,\n endpoint\n );\n }\n}\n\nexport function assertScheduleResponse(\n payload: unknown,\n endpoint: string\n): asserts payload is ScheduleResponse {\n const record = ensureRecord(payload, endpoint, \"object\");\n const schedules = record.schedules;\n const exams = record.exams;\n const employeeDto = record.employeeDto;\n const studentGroupDto = record.studentGroupDto;\n\n // undefined treated as absent field — API may omit schedules/exams for exam-only or schedule-only entries\n if (schedules !== null && schedules !== undefined) {\n if (typeof schedules !== \"object\" || Array.isArray(schedules)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'schedules' must be object or null, got ${\n Array.isArray(schedules) ? \"array\" : typeof schedules\n }`,\n endpoint\n );\n }\n }\n\n if (exams !== null && exams !== undefined) {\n if (!Array.isArray(exams)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'exams' must be array or null, got ${typeof exams}`,\n endpoint\n );\n }\n }\n\n if (!isNullableObject(employeeDto)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'employeeDto' must be object or null, got ${typeof employeeDto}`,\n endpoint\n );\n }\n\n if (!isNullableObject(studentGroupDto)) {\n throw new BsuirResponseValidationError(\n `Invalid response payload for ${endpoint}: 'studentGroupDto' must be object or null, got ${typeof studentGroupDto}`,\n endpoint\n );\n }\n}\n","import { BsuirApiError } from \"../client/errors\";\nimport { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { InternalClientConfig } from \"../client/types\";\nimport type { Announcement } from \"../types/announcement\";\nimport { assertEmployeeUrlId, assertPositiveInt } from \"../utils/guards\";\nimport type { ReadOptions } from \"./types\";\n\nconst ANNOUNCEMENT_EMPTY_LIST_STATUSES = new Set<number>([404, 400]);\n\n/**\n * Fetches an announcement list, converting empty responses (404/400) to empty arrays.\n * The BSUIR IIS API returns 404 or 400 when an entity has no announcements or endpoint doesn't exist.\n * This function normalizes those to an empty list instead of throwing an error.\n *\n * @returns The announcement list, or empty array if API returned 404/400\n * @throws {BsuirApiError} For non-empty responses with error status codes\n * @throws {BsuirNetworkError} On transport failures\n * @throws {BsuirTimeoutError} When request times out\n */\nasync function requestAnnouncementList(\n config: Readonly<InternalClientConfig>,\n path: string,\n options: ReadOptions & { query: Record<string, string | number> }\n): Promise<Announcement[]> {\n try {\n const payload = await requestJson<unknown>(config, path, options);\n if (config.validateResponses) {\n assertArrayResponse(payload, path);\n }\n return payload as Announcement[];\n } catch (error) {\n if (error instanceof BsuirApiError && ANNOUNCEMENT_EMPTY_LIST_STATUSES.has(error.status)) {\n return [];\n }\n throw error;\n }\n}\n\nexport function createAnnouncementsModule(config: Readonly<InternalClientConfig>) {\n return {\n /**\n * Lists announcements for an employee. IIS may return HTTP `404` or `400` (no list / endpoint quirks); the SDK maps those to `[]`.\n */\n async byEmployee(urlId: string, options: ReadOptions = {}): Promise<Announcement[]> {\n assertEmployeeUrlId(urlId, \"urlId\");\n return requestAnnouncementList(config, \"/announcements/employees\", {\n ...options,\n query: { \"url-id\": urlId }\n });\n },\n\n /**\n * Lists announcements for a department. IIS may return HTTP `404` or `400` (no list / endpoint quirks); the SDK maps those to `[]`.\n */\n async byDepartment(id: number, options: ReadOptions = {}): Promise<Announcement[]> {\n assertPositiveInt(id, \"id\");\n return requestAnnouncementList(config, \"/announcements/departments\", {\n ...options,\n query: { id }\n });\n }\n };\n}\n","import { requestJson } from \"../client/http\";\nimport { assertArrayResponse } from \"../client/responseValidators\";\nimport type { InternalClientConfig } from \"../client/types\";\nimport type { ReadOptions } from \"./types\";\n\n/**\n * Creates a simple catalog-like module exposing `listAll()` for a fixed endpoint.\n */\nexport function createListModule<T>(\n config: Readonly<InternalClientConfig>,\n endpoint: string,\n) {\n return {\n /**\n * Returns all items from the configured endpoint.\n */\n async listAll(options: ReadOptions = {}): Promise<T[]> {\n const payload = await requestJson<unknown>(config, endpoint, {\n signal: options.signal,\n });\n if (config.validateResponses) {\n assertArrayResponse(payload, endpoint);\n }\n return payload as T[];\n },\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport type { Auditory } from \"../types/catalog\";\nimport { createListModule } from \"./createListModule\";\n\n/**\n * Creates API module for `/auditories`.\n */\nexport function createAuditoriesModule(config: Readonly<InternalClientConfig>) {\n return createListModule<Auditory>(config, \"/auditories\");\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport type { Department } from \"../types/catalog\";\nimport { createListModule } from \"./createListModule\";\n\n/**\n * Creates API module for `/departments`.\n */\nexport function createDepartmentsModule(config: Readonly<InternalClientConfig>) {\n return createListModule<Department>(config, \"/departments\");\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport type { EmployeeCatalogItem } from \"../types/employee\";\nimport { createListModule } from \"./createListModule\";\n\n/**\n * Creates API module for `/employees/all`.\n */\nexport function createEmployeesModule(config: Readonly<InternalClientConfig>) {\n return createListModule<EmployeeCatalogItem>(config, \"/employees/all\");\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport type { Faculty } from \"../types/catalog\";\nimport { createListModule } from \"./createListModule\";\n\n/**\n * Creates API module for `/faculties`.\n */\nexport function createFacultiesModule(config: Readonly<InternalClientConfig>) {\n return createListModule<Faculty>(config, \"/faculties\");\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport type { StudentGroupCatalogItem } from \"../types/catalog\";\nimport { createListModule } from \"./createListModule\";\n\n/**\n * Creates API module for `/student-groups`.\n */\nexport function createGroupsModule(config: Readonly<InternalClientConfig>) {\n return createListModule<StudentGroupCatalogItem>(config, \"/student-groups\");\n}\n","import { BsuirValidationError } from \"../client/errors\";\nimport { assertPositiveInt } from \"./guards\";\n\n// API response should never nest deeper than 2 levels; 10 is a generous safety cap to prevent stack overflow\nconst MAX_PARSE_DEPTH = 10;\n\n/**\n * Normalizes current week payload from API to a positive integer.\n * API can return plain text (`\"1\\n\"`) or number.\n */\nexport function parseCurrentWeek(payload: unknown): number {\n return parseCurrentWeekInternal(payload, 0);\n}\n\nfunction parseCurrentWeekInternal(payload: unknown, depth: number): number {\n if (depth > MAX_PARSE_DEPTH) {\n throw new BsuirValidationError(\"'currentWeek' response payload has excessive nesting depth\");\n }\n\n if (typeof payload === \"number\") {\n assertPositiveInt(payload, \"currentWeek\");\n return payload;\n }\n\n if (typeof payload === \"string\") {\n const normalized = payload.trim();\n if (normalized.length === 0) {\n throw new BsuirValidationError(\n \"'currentWeek' response payload is an empty string\"\n );\n }\n const parsed = Number(normalized);\n // assertPositiveInt validates both isInteger and > 0 — no need to pre-check isInteger\n assertPositiveInt(parsed, \"currentWeek\");\n return parsed;\n }\n\n if (typeof payload === \"object\" && payload !== null) {\n const record = payload as Record<string, unknown>;\n if (\"weekNumber\" in record) {\n return parseCurrentWeekInternal(record.weekNumber, depth + 1);\n }\n if (\"currentWeek\" in record) {\n return parseCurrentWeekInternal(record.currentWeek, depth + 1);\n }\n }\n\n throw new BsuirValidationError(\"'currentWeek' response payload must be a positive integer\");\n}\n","import { assertPositiveInt } from \"../utils/guards\";\nimport type {\n FlattenedScheduleItem,\n NormalizedScheduleResponse,\n ScheduleFilterOptions,\n ScheduleItem,\n} from \"../types/schedule\";\n\nfunction lessonAuditories(item: ScheduleItem): string[] {\n const { auditories } = item;\n return Array.isArray(auditories) ? auditories : [];\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 && !lessonAuditories(item).includes(filter.auditory)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Filters normalized schedule lessons by criteria.\n */\nexport function filterLessons(\n response: NormalizedScheduleResponse,\n filter: ScheduleFilterOptions,\n): FlattenedScheduleItem[] {\n if (typeof filter.weekNumber === \"number\") {\n assertPositiveInt(filter.weekNumber, \"filter.weekNumber\");\n }\n return response.lessons.filter((item) => matchesFilter(item, filter));\n}\n","import type { Weekday } from \"../types/common\";\nimport type {\n FlattenedLessonsByDay,\n FlattenedScheduleItem,\n NormalizedScheduleResponse,\n ScheduleItem,\n ScheduleResponse,\n} from \"../types/schedule\";\n\nconst WEEKDAYS: Weekday[] = [\n \"Понедельник\",\n \"Вторник\",\n \"Среда\",\n \"Четверг\",\n \"Пятница\",\n \"Суббота\",\n];\n\nfunction lessonAuditories(item: ScheduleItem): string[] {\n const { auditories } = item;\n return Array.isArray(auditories) ? auditories : [];\n}\n\n/**\n * Transforms raw schedule response into normalized structure with flattened lessons.\n */\nexport function normalizeSchedule(response: ScheduleResponse): NormalizedScheduleResponse {\n const lessons: FlattenedScheduleItem[] = [];\n const scheduleLessons: FlattenedScheduleItem[] = [];\n const examLessons: FlattenedScheduleItem[] = [];\n const lessonsByDay = Object.fromEntries(\n WEEKDAYS.map((day) => [day, [] as FlattenedScheduleItem[]]),\n ) as FlattenedLessonsByDay;\n const safeSchedules = response.schedules ?? {};\n const safeExams = response.exams ?? [];\n\n for (const day of WEEKDAYS) {\n const dayItems = safeSchedules[day] ?? [];\n const flattenedDayItems = dayItems.map((item) => {\n const auditories = lessonAuditories(item);\n return {\n ...item,\n auditories,\n day,\n source: \"schedules\" as const,\n };\n });\n lessonsByDay[day] = flattenedDayItems;\n lessons.push(...flattenedDayItems);\n scheduleLessons.push(...flattenedDayItems);\n }\n\n for (const exam of safeExams) {\n const auditories = lessonAuditories(exam);\n const flattenedExam: FlattenedScheduleItem = {\n ...exam,\n auditories,\n day: null,\n source: \"exams\",\n };\n lessons.push(flattenedExam);\n examLessons.push(flattenedExam);\n }\n\n return {\n ...response,\n schedules: safeSchedules,\n exams: safeExams,\n lessons,\n lessonsByDay,\n scheduleLessons,\n examLessons,\n };\n}\n","import { requestJson } from \"../client/http\";\nimport { assertApiDateResponse, assertScheduleResponse } from \"../client/responseValidators\";\nimport type { InternalClientConfig } from \"../client/types\";\nimport type { ApiDateResponse } from \"../types/common\";\nimport type {\n FlattenedScheduleItem,\n ScheduleFilterOptions,\n ScheduleResponse,\n NormalizedScheduleResponse,\n} from \"../types/schedule\";\nimport { assertEmployeeUrlId, assertGroupNumber, assertPositiveInt } from \"../utils/guards\";\nimport { parseCurrentWeek } from \"../utils/week\";\nimport { filterLessons } from \"./scheduleFilter\";\nimport { normalizeSchedule } from \"./scheduleNormalize\";\nimport type { ReadOptions } from \"./types\";\n\ntype ScheduleResponseByRawOption<TRaw extends boolean | undefined, TRawDefault extends boolean> =\n TRaw extends true\n ? ScheduleResponse\n : TRaw extends false\n ? NormalizedScheduleResponse\n : TRawDefault extends true\n ? ScheduleResponse\n : NormalizedScheduleResponse;\n\n/**\n * Creates schedule API module with raw/normalized response support.\n */\nexport function createScheduleModule<TRawDefault extends boolean>(\n config: Readonly<InternalClientConfig<TRawDefault>>,\n) {\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<ScheduleResponseByRawOption<TRaw, TRawDefault>> {\n assertGroupNumber(groupNumber, \"groupNumber\");\n const payload = await requestJson<unknown>(config, \"/schedule\", {\n query: { studentGroup: groupNumber },\n signal: options.signal,\n });\n if (config.validateResponses) {\n assertScheduleResponse(payload, \"/schedule\");\n }\n const response = payload as ScheduleResponse;\n const result = options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);\n return result as ScheduleResponseByRawOption<TRaw, TRawDefault>;\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<ScheduleResponseByRawOption<TRaw, TRawDefault>> {\n assertEmployeeUrlId(urlId, \"urlId\");\n const endpoint = `/employees/schedule/${encodeURIComponent(urlId)}`;\n const payload = await requestJson<unknown>(config, endpoint, { signal: options.signal });\n if (config.validateResponses) {\n assertScheduleResponse(payload, endpoint);\n }\n const response = payload as ScheduleResponse;\n const result = options.raw ?? config.defaultRaw ? response : normalizeSchedule(response);\n return result as ScheduleResponseByRawOption<TRaw, TRawDefault>;\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 /**\n * Returns current academic week number.\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 parseCurrentWeek(payload);\n }\n\n return {\n getGroup,\n getEmployee,\n getGroupFiltered,\n getEmployeeFiltered,\n\n /**\n * Returns exams for a group.\n */\n async getGroupExams(groupNumber: string, options: ReadOptions = {}): Promise<FlattenedScheduleItem[]> {\n return getGroupFiltered(groupNumber, { source: \"exams\" }, options);\n },\n\n /**\n * Returns exams for an employee.\n */\n async getEmployeeExams(urlId: string, options: ReadOptions = {}): Promise<FlattenedScheduleItem[]> {\n return getEmployeeFiltered(urlId, { source: \"exams\" }, options);\n },\n\n /**\n * Returns regular schedule lessons of a specific subgroup for a group.\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 /**\n * Returns regular schedule lessons of a specific subgroup for an employee.\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\n /**\n * Calls IIS `/last-update-date/student-group`.\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 const payload = await requestJson<unknown>(config, \"/last-update-date/student-group\", {\n query,\n signal: options.signal,\n });\n if (config.validateResponses) {\n assertApiDateResponse(payload, \"/last-update-date/student-group\");\n }\n return payload as ApiDateResponse;\n },\n\n /**\n * Calls IIS `/last-update-date/employee`.\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 const payload = await requestJson<unknown>(config, \"/last-update-date/employee\", {\n query,\n signal: options.signal,\n });\n if (config.validateResponses) {\n assertApiDateResponse(payload, \"/last-update-date/employee\");\n }\n return payload as ApiDateResponse;\n },\n };\n}\n","import type { InternalClientConfig } from \"../client/types\";\nimport type { Speciality } from \"../types/catalog\";\nimport { createListModule } from \"./createListModule\";\n\n/**\n * Creates API module for `/specialities`.\n */\nexport function createSpecialitiesModule(config: Readonly<InternalClientConfig>) {\n return createListModule<Speciality>(config, \"/specialities\");\n}\n","import { BsuirConfigurationError } from \"./errors\";\nimport type { BsuirClientOptions, InternalClientConfig } from \"./types\";\nimport {\n createAnnouncementsModule,\n createAuditoriesModule,\n createDepartmentsModule,\n createEmployeesModule,\n createFacultiesModule,\n createGroupsModule,\n createScheduleModule,\n createSpecialitiesModule\n} from \"../modules\";\n\nconst DEFAULT_BASE_URL = \"https://iis.bsuir.by/api/v1\";\nconst DEFAULT_ALLOWED_BASE_URL_HOSTS = [\"iis.bsuir.by\"];\nconst DEFAULT_MAX_RESPONSE_BYTES = 5_000_000;\n\n// Prevents setTimeout() integer overflow (max safe value ~24.8 days).\n// 5 minutes is a generous upper bound for any HTTP request in this context.\nconst MAX_TIMEOUT_MS = 300_000;\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 BsuirConfigurationError(\n \"Global fetch is unavailable. Provide 'fetch' in createBsuirClient options.\"\n );\n }\n\n return globalThis.fetch;\n}\n\nfunction assertIntegerOption(\n value: number | undefined,\n name: string,\n minInclusive: number\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n if (!Number.isFinite(value) || !Number.isInteger(value) || value < minInclusive) {\n throw new BsuirConfigurationError(\n `'${name}' must be an integer greater than or equal to ${String(minInclusive)}`\n );\n }\n return value;\n}\n\nfunction normalizeBaseUrl(\n rawBaseUrl: string,\n allowInsecureHttp: boolean,\n allowedHosts: readonly string[]\n): string {\n let parsed: URL;\n try {\n parsed = new URL(rawBaseUrl);\n } catch {\n throw new BsuirConfigurationError(\"'baseUrl' must be a valid absolute URL\");\n }\n\n if (parsed.username || parsed.password) {\n throw new BsuirConfigurationError(\"'baseUrl' must not include credentials\");\n }\n\n if (parsed.search || parsed.hash) {\n throw new BsuirConfigurationError(\"'baseUrl' must not include query string or hash\");\n }\n\n if (parsed.protocol !== \"https:\" && !(allowInsecureHttp && parsed.protocol === \"http:\")) {\n throw new BsuirConfigurationError(\n \"'baseUrl' must use HTTPS. Set 'allowInsecureHttp: true' only for trusted local/test endpoints.\"\n );\n }\n\n const normalizedAllowedHosts = new Set(\n allowedHosts.map((host) => host.trim().toLowerCase()).filter((host) => host.length > 0)\n );\n if (normalizedAllowedHosts.size === 0) {\n throw new BsuirConfigurationError(\"'allowedBaseUrlHosts' must contain at least one hostname\");\n }\n\n const host = parsed.hostname.toLowerCase();\n if (!normalizedAllowedHosts.has(host)) {\n throw new BsuirConfigurationError(\n `'baseUrl' host '${host}' is not allowed. Allowed hosts: ${[...normalizedAllowedHosts].join(\", \")}`\n );\n }\n\n const normalizedPath = parsed.pathname.replace(/\\/+$/, \"\");\n return `${parsed.origin}${normalizedPath}`;\n}\n\nfunction createInternalConfig<TRawDefault extends boolean>(\n options: BsuirClientOptions & { defaultRaw: TRawDefault }\n): InternalClientConfig<TRawDefault> {\n const timeoutMs = assertIntegerOption(options.timeoutMs, \"timeoutMs\", 1) ?? 10_000;\n if (timeoutMs > MAX_TIMEOUT_MS) {\n throw new BsuirConfigurationError(\n `'timeoutMs' must not exceed ${String(MAX_TIMEOUT_MS)}ms (5 minutes)`\n );\n }\n\n const retries = assertIntegerOption(options.retries, \"retries\", 0) ?? 1;\n const retryDelayMs = assertIntegerOption(options.retryDelayMs, \"retryDelayMs\", 0) ?? 300;\n const retryMaxDelayMs =\n assertIntegerOption(options.retryMaxDelayMs, \"retryMaxDelayMs\", 0) ?? 3_000;\n const cacheTtlMs = assertIntegerOption(options.cache?.ttlMs, \"cache.ttlMs\", 1);\n const cacheMaxEntries =\n assertIntegerOption(options.cache?.maxEntries, \"cache.maxEntries\", 1) ?? 200;\n const maxResponseBytes =\n assertIntegerOption(options.maxResponseBytes, \"maxResponseBytes\", 1) ??\n DEFAULT_MAX_RESPONSE_BYTES;\n const allowInsecureHttp = options.allowInsecureHttp ?? false;\n const allowedBaseUrlHosts = options.allowedBaseUrlHosts ?? DEFAULT_ALLOWED_BASE_URL_HOSTS;\n\n if (retryDelayMs > retryMaxDelayMs) {\n throw new BsuirConfigurationError(\n \"'retryDelayMs' must be less than or equal to 'retryMaxDelayMs'\"\n );\n }\n\n return {\n baseUrl: normalizeBaseUrl(options.baseUrl ?? DEFAULT_BASE_URL, allowInsecureHttp, allowedBaseUrlHosts),\n fetchImpl: resolveFetch(options.fetch),\n signal: options.signal,\n timeoutMs,\n retries,\n retryDelayMs,\n retryMaxDelayMs,\n retryJitter: options.retryJitter ?? true,\n userAgent: options.userAgent,\n cacheTtlMs,\n cacheMaxEntries,\n dedupeInFlight: options.dedupeInFlight ?? true,\n maxResponseBytes,\n validateResponses: options.validateResponses ?? true,\n hooks: options.hooks ?? {},\n responseCache: new Map(),\n inFlightRequests: new Map(),\n defaultRaw: options.defaultRaw\n };\n}\n\n/**\n * Fully-typed public shape of the BSUIR API client.\n * All module types are inlined so API Extractor never needs to reach into private helpers.\n *\n * `TRawDefault` controls the default return type of\n * `schedule.getGroup` / `schedule.getEmployee` when the per-call `raw` option is omitted:\n * - `false` (default) → returns `NormalizedScheduleResponse`\n * - `true` → returns `ScheduleResponse` (raw API payload)\n *\n * Per-call `raw` always takes precedence over this default.\n *\n * @example\n * ```ts\n * // Default (normalized):\n * const client = createBsuirClient();\n * const norm = await client.schedule.getGroup(\"053503\"); // NormalizedScheduleResponse\n *\n * // Raw by default:\n * const rawClient = createBsuirClient({ defaultRaw: true });\n * const raw = await rawClient.schedule.getGroup(\"053503\"); // ScheduleResponse\n *\n * // Per-call override (always wins):\n * const override = await client.schedule.getGroup(\"053503\", { raw: true }); // ScheduleResponse\n * ```\n */\nexport interface BsuirClientShape<TRawDefault extends boolean> {\n schedule: ReturnType<typeof createScheduleModule<TRawDefault>>;\n groups: ReturnType<typeof createGroupsModule>;\n employees: ReturnType<typeof createEmployeesModule>;\n faculties: ReturnType<typeof createFacultiesModule>;\n departments: ReturnType<typeof createDepartmentsModule>;\n specialities: ReturnType<typeof createSpecialitiesModule>;\n announcements: ReturnType<typeof createAnnouncementsModule>;\n auditories: ReturnType<typeof createAuditoriesModule>;\n};\n\n/**\n * Creates a configured BSUIR IIS API client.\n *\n * Pass `{ defaultRaw: true }` to switch the default return shape of\n * `schedule.getGroup` and `schedule.getEmployee` from `NormalizedScheduleResponse`\n * to the raw `ScheduleResponse`. Per-call `raw` option always takes precedence.\n *\n * @example\n * ```ts\n * // Normalized (default):\n * const client = createBsuirClient();\n *\n * // Raw by default:\n * const rawClient = createBsuirClient({ defaultRaw: true });\n *\n * // Custom fetch + timeout:\n * const client = createBsuirClient({ fetch: myFetch, timeoutMs: 5_000 });\n * ```\n */\nexport function createBsuirClient(\n options: BsuirClientOptions & { defaultRaw: true }\n): BsuirClientShape<true>;\nexport function createBsuirClient(\n options?: BsuirClientOptions & { defaultRaw?: false | undefined }\n): BsuirClientShape<false>;\nexport function createBsuirClient(\n options: BsuirClientOptions = {}\n): BsuirClientShape<boolean> {\n const defaultRaw = options.defaultRaw ?? false;\n const config = createInternalConfig({ ...options, defaultRaw });\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 };\n}\n\n/**\n * Public client contract returned by `createBsuirClient`.\n * Use `BsuirClientShape<true>` or `BsuirClientShape<false>` for typed overloads.\n */\nexport type BsuirClient = ReturnType<typeof createBsuirClient>;\n"],"mappings":"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","names":["payload","lessonAuditories","host"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bsuir-iis-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Type-safe ESM SDK for BSUIR IIS API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "kotru21",
|
|
@@ -55,20 +55,20 @@
|
|
|
55
55
|
"release:dry": "npm pack --dry-run"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@microsoft/api-extractor": "
|
|
59
|
-
"@changesets/cli": "
|
|
60
|
-
"@eslint/js": "
|
|
61
|
-
"@types/node": "
|
|
62
|
-
"@typescript-eslint/eslint-plugin": "
|
|
63
|
-
"@typescript-eslint/parser": "
|
|
64
|
-
"@vitest/coverage-v8": "
|
|
65
|
-
"eslint": "
|
|
66
|
-
"eslint-config-prettier": "
|
|
67
|
-
"globals": "
|
|
68
|
-
"prettier": "
|
|
69
|
-
"tsup": "
|
|
70
|
-
"typescript": "
|
|
71
|
-
"typescript-eslint": "
|
|
72
|
-
"vitest": "
|
|
58
|
+
"@microsoft/api-extractor": "7.58.7",
|
|
59
|
+
"@changesets/cli": "2.31.0",
|
|
60
|
+
"@eslint/js": "10.0.1",
|
|
61
|
+
"@types/node": "25.6.2",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "8.59.2",
|
|
63
|
+
"@typescript-eslint/parser": "8.59.2",
|
|
64
|
+
"@vitest/coverage-v8": "4.1.5",
|
|
65
|
+
"eslint": "10.3.0",
|
|
66
|
+
"eslint-config-prettier": "10.1.8",
|
|
67
|
+
"globals": "17.6.0",
|
|
68
|
+
"prettier": "3.8.3",
|
|
69
|
+
"tsup": "8.5.1",
|
|
70
|
+
"typescript": "6.0.3",
|
|
71
|
+
"typescript-eslint": "8.59.2",
|
|
72
|
+
"vitest": "4.1.5"
|
|
73
73
|
}
|
|
74
74
|
}
|