bsuir-iis-api 0.9.0 → 0.9.1
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 +10 -8
- package/dist/_tsup-dts-rollup.d.ts +172 -20
- package/dist/index.js +13 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.9.
|
|
3
|
+
## [0.9.1] - 2026-05-10
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### Fixed
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- `http.ts`: cache eviction now performs true LRU — entries are sorted by `accessedAt` timestamp before eviction instead of relying on Map insertion order (which produced FIFO behaviour, not LRU).
|
|
8
|
+
- `http.ts`: `setCache` now removes the key before re-inserting on a cache refresh, ensuring Map insertion order stays consistent with actual last-write time.
|
|
9
|
+
- `http.ts`: `canUseCaching` and `canUseDedup` now check `config.signal?.aborted` in addition to per-request `options.signal`; previously a globally aborted client signal did not suppress cache reads, which could return stale data after cancellation.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
### Documentation
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
- `types.ts`: all `BsuirClientOptions` fields now have full JSDoc — description, `@defaultValue`, `@example`, and side-effect notes where applicable.
|
|
14
|
+
- `types.ts`: `validateResponses` JSDoc explicitly recommends `process.env.NODE_ENV !== "production"` as a sensible default pattern and clarifies the performance trade-off.
|
|
15
|
+
- `types.ts`: `signal` JSDoc clarifies that an aborted global signal suppresses both cache reads and in-flight deduplication.
|
|
14
16
|
|
|
15
|
-
## [0.
|
|
17
|
+
## [0.9.0] - 2026-05-10
|
|
16
18
|
|
|
17
19
|
### Added
|
|
18
20
|
|
|
@@ -88,43 +88,181 @@ export { BsuirClient as BsuirClient_alias_1 }
|
|
|
88
88
|
* Options accepted by `createBsuirClient`.
|
|
89
89
|
*/
|
|
90
90
|
declare interface BsuirClientOptions {
|
|
91
|
+
/**
|
|
92
|
+
* Base URL of the BSUIR IIS API.
|
|
93
|
+
*
|
|
94
|
+
* @defaultValue "https://iis.bsuir.by/api/v1"
|
|
95
|
+
*/
|
|
91
96
|
baseUrl?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Custom `fetch` implementation. Useful for environments where the global
|
|
99
|
+
* `fetch` is unavailable (older Node.js versions) or when you want to wrap
|
|
100
|
+
* requests with a proxy, MSW handler, or test mock.
|
|
101
|
+
*
|
|
102
|
+
* @defaultValue globalThis.fetch
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* import nodeFetch from "node-fetch";
|
|
106
|
+
* const client = createBsuirClient({ fetch: nodeFetch as typeof fetch });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
92
109
|
fetch?: typeof globalThis.fetch;
|
|
93
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Global `AbortSignal` that cancels **all** requests made by this client
|
|
112
|
+
* instance. Per-call signals are combined with this one.
|
|
113
|
+
*
|
|
114
|
+
* Note: caching and in-flight deduplication are disabled for requests that
|
|
115
|
+
* carry a signal (per-call or global) to prevent stale data from being
|
|
116
|
+
* returned after cancellation.
|
|
117
|
+
*/
|
|
94
118
|
signal?: AbortSignal;
|
|
95
|
-
/**
|
|
119
|
+
/**
|
|
120
|
+
* Request timeout per attempt, in milliseconds.
|
|
121
|
+
*
|
|
122
|
+
* If a single fetch attempt does not complete within this window it is
|
|
123
|
+
* aborted and a `BsuirTimeoutError` is thrown (or the request is retried
|
|
124
|
+
* if retries remain).
|
|
125
|
+
*
|
|
126
|
+
* @defaultValue 10_000 (10 seconds)
|
|
127
|
+
*/
|
|
96
128
|
timeoutMs?: number;
|
|
97
|
-
/**
|
|
129
|
+
/**
|
|
130
|
+
* Number of additional retry attempts for retriable GET failures (HTTP 429,
|
|
131
|
+
* 500, 502, 503, 504 and network errors). Set to `0` to disable retries.
|
|
132
|
+
*
|
|
133
|
+
* @defaultValue 1
|
|
134
|
+
*/
|
|
98
135
|
retries?: number;
|
|
99
|
-
/**
|
|
136
|
+
/**
|
|
137
|
+
* Base delay before the first retry, in milliseconds. Subsequent retries use
|
|
138
|
+
* exponential backoff: `retryDelayMs * 2^attempt`, capped by `retryMaxDelayMs`.
|
|
139
|
+
*
|
|
140
|
+
* @defaultValue 300
|
|
141
|
+
*/
|
|
100
142
|
retryDelayMs?: number;
|
|
101
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* Upper bound for the retry delay after backoff, in milliseconds.
|
|
145
|
+
*
|
|
146
|
+
* @defaultValue 3_000 (3 seconds)
|
|
147
|
+
*/
|
|
102
148
|
retryMaxDelayMs?: number;
|
|
103
|
-
/**
|
|
149
|
+
/**
|
|
150
|
+
* When `true`, a random jitter factor (±25 %) is applied to each retry delay
|
|
151
|
+
* to avoid synchronized retries from multiple clients hitting the API at the
|
|
152
|
+
* same time.
|
|
153
|
+
*
|
|
154
|
+
* @defaultValue true
|
|
155
|
+
*/
|
|
104
156
|
retryJitter?: boolean;
|
|
105
|
-
/**
|
|
157
|
+
/**
|
|
158
|
+
* Value sent as the `User-Agent` request header. Mainly useful in Node.js
|
|
159
|
+
* environments where servers can log the client identity.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* const client = createBsuirClient({ userAgent: "my-app/1.0.0" });
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
106
166
|
userAgent?: string;
|
|
107
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* In-memory response cache configuration for successful GET requests.
|
|
169
|
+
*
|
|
170
|
+
* When configured, responses are stored in a `Map` keyed by the full request
|
|
171
|
+
* URL. Cache hits skip the network entirely and fire `onResponse` with
|
|
172
|
+
* `fromCache: true`. The cache uses a true LRU eviction policy — the
|
|
173
|
+
* least-recently-*read* entry is evicted first when `maxEntries` is exceeded.
|
|
174
|
+
*
|
|
175
|
+
* Caching is automatically skipped for requests that carry an `AbortSignal`
|
|
176
|
+
* (per-call or global) to prevent serving stale data after cancellation.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* // Cache for 5 minutes, keep at most 500 entries
|
|
181
|
+
* const client = createBsuirClient({
|
|
182
|
+
* cache: { ttlMs: 5 * 60 * 1000, maxEntries: 500 },
|
|
183
|
+
* });
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
108
186
|
cache?: CacheOptions;
|
|
109
|
-
/**
|
|
187
|
+
/**
|
|
188
|
+
* Enables in-flight GET request deduplication by full URL.
|
|
189
|
+
*
|
|
190
|
+
* When two identical GET requests are made concurrently, only the first one
|
|
191
|
+
* hits the network; the second one awaits the same `Promise`. This prevents
|
|
192
|
+
* duplicate API calls in scenarios like parallel component rendering.
|
|
193
|
+
*
|
|
194
|
+
* Disabled automatically when the request carries an `AbortSignal`.
|
|
195
|
+
*
|
|
196
|
+
* @defaultValue true
|
|
197
|
+
*/
|
|
110
198
|
dedupeInFlight?: boolean;
|
|
111
|
-
/**
|
|
199
|
+
/**
|
|
200
|
+
* Enables runtime shape validation of API responses.
|
|
201
|
+
*
|
|
202
|
+
* When `true`, each response is checked against the expected TypeScript type
|
|
203
|
+
* at runtime. An `BsuirApiError` is thrown if the payload does not match,
|
|
204
|
+
* which makes integration issues with the upstream API visible immediately
|
|
205
|
+
* instead of causing silent type-cast bugs later.
|
|
206
|
+
*
|
|
207
|
+
* **Recommended to enable during development and in test environments.**
|
|
208
|
+
* Can be left `false` in production for a small performance gain.
|
|
209
|
+
*
|
|
210
|
+
* @defaultValue false
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* // Enable only in non-production environments
|
|
215
|
+
* const client = createBsuirClient({
|
|
216
|
+
* validateResponses: process.env.NODE_ENV !== "production",
|
|
217
|
+
* });
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
112
220
|
validateResponses?: boolean;
|
|
113
|
-
/**
|
|
221
|
+
/**
|
|
222
|
+
* Lifecycle hooks called at various stages of the request pipeline.
|
|
223
|
+
*
|
|
224
|
+
* Useful for logging, metrics collection, or custom error reporting.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* const client = createBsuirClient({
|
|
229
|
+
* hooks: {
|
|
230
|
+
* onRequest: ({ method, path }) => console.log(`→ ${method} ${path}`),
|
|
231
|
+
* onResponse: ({ path, durationMs, fromCache }) =>
|
|
232
|
+
* console.log(`← ${path} ${durationMs}ms${fromCache ? " (cache)" : ""}`),
|
|
233
|
+
* onRetry: ({ path, attempt, reason }) =>
|
|
234
|
+
* console.warn(`↺ ${path} retry #${attempt} (${reason})`),
|
|
235
|
+
* onError: ({ path, error }) => console.error(`✗ ${path}`, error),
|
|
236
|
+
* },
|
|
237
|
+
* });
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
114
240
|
hooks?: ClientHooks;
|
|
115
241
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
242
|
+
* Controls the default return type of `schedule.getGroup` and
|
|
243
|
+
* `schedule.getEmployee` when the per-call `raw` option is omitted.
|
|
244
|
+
*
|
|
245
|
+
* - `false` (default) — returns `NormalizedScheduleResponse` with flattened
|
|
246
|
+
* `lessons`, `lessonsByDay`, `scheduleLessons`, and `examLessons` arrays.
|
|
247
|
+
* - `true` — returns the raw `ScheduleResponse` exactly as received from the
|
|
248
|
+
* BSUIR IIS API.
|
|
249
|
+
*
|
|
250
|
+
* A per-call `raw` option always takes precedence over this default.
|
|
118
251
|
*
|
|
119
|
-
*
|
|
252
|
+
* @defaultValue false
|
|
120
253
|
*
|
|
121
254
|
* @example
|
|
122
255
|
* ```ts
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* const
|
|
126
|
-
*
|
|
127
|
-
*
|
|
256
|
+
* // Normalized (default):
|
|
257
|
+
* const client = createBsuirClient();
|
|
258
|
+
* const norm = await client.schedule.getGroup("053503"); // NormalizedScheduleResponse
|
|
259
|
+
*
|
|
260
|
+
* // Raw by default:
|
|
261
|
+
* const rawClient = createBsuirClient({ defaultRaw: true });
|
|
262
|
+
* const raw = await rawClient.schedule.getGroup("053503"); // ScheduleResponse
|
|
263
|
+
*
|
|
264
|
+
* // Per-call override (always wins):
|
|
265
|
+
* const override = await client.schedule.getGroup("053503", { raw: true }); // ScheduleResponse
|
|
128
266
|
* ```
|
|
129
267
|
*/
|
|
130
268
|
defaultRaw?: boolean;
|
|
@@ -213,10 +351,24 @@ export { BuildingNumber as BuildingNumber_alias_2 }
|
|
|
213
351
|
declare interface CacheOptions {
|
|
214
352
|
/**
|
|
215
353
|
* Cache TTL for successful GET responses, in milliseconds.
|
|
354
|
+
*
|
|
355
|
+
* After this duration has elapsed the cached entry is considered stale and
|
|
356
|
+
* the next request will hit the network again.
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* ```ts
|
|
360
|
+
* // Cache responses for 5 minutes
|
|
361
|
+
* const client = createBsuirClient({ cache: { ttlMs: 5 * 60 * 1000 } });
|
|
362
|
+
* ```
|
|
216
363
|
*/
|
|
217
364
|
ttlMs: number;
|
|
218
365
|
/**
|
|
219
|
-
* Maximum number of
|
|
366
|
+
* Maximum number of entries kept in the in-memory cache.
|
|
367
|
+
*
|
|
368
|
+
* When the limit is exceeded the least-recently-used (LRU) entries are evicted
|
|
369
|
+
* first. Expired entries are always removed before LRU eviction runs.
|
|
370
|
+
*
|
|
371
|
+
* @defaultValue 200
|
|
220
372
|
*/
|
|
221
373
|
maxEntries?: number;
|
|
222
374
|
}
|
package/dist/index.js
CHANGED
|
@@ -213,6 +213,7 @@ function setCache(config, key, value) {
|
|
|
213
213
|
return;
|
|
214
214
|
}
|
|
215
215
|
const now = Date.now();
|
|
216
|
+
config.responseCache.delete(key);
|
|
216
217
|
config.responseCache.set(key, {
|
|
217
218
|
value,
|
|
218
219
|
expiresAt: now + config.cacheTtlMs,
|
|
@@ -227,12 +228,16 @@ function setCache(config, key, value) {
|
|
|
227
228
|
config.responseCache.delete(k);
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
if (config.responseCache.size > config.cacheMaxEntries) {
|
|
232
|
+
const byLeastRecentlyUsed = [...config.responseCache.entries()].sort(
|
|
233
|
+
(a, b) => a[1].accessedAt - b[1].accessedAt
|
|
234
|
+
);
|
|
235
|
+
for (const [k] of byLeastRecentlyUsed) {
|
|
236
|
+
if (config.responseCache.size <= config.cacheMaxEntries) {
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
config.responseCache.delete(k);
|
|
234
240
|
}
|
|
235
|
-
config.responseCache.delete(firstKey);
|
|
236
241
|
}
|
|
237
242
|
}
|
|
238
243
|
function combineAbortSignals(first, second) {
|
|
@@ -327,8 +332,9 @@ async function requestJson(config, path, options = {}) {
|
|
|
327
332
|
headers.set("Content-Type", "application/json");
|
|
328
333
|
}
|
|
329
334
|
const cacheKey = endpoint;
|
|
330
|
-
const
|
|
331
|
-
const
|
|
335
|
+
const hasActiveSignal = options.signal != null || config.signal?.aborted === true;
|
|
336
|
+
const canUseCaching = config.cacheTtlMs !== void 0 && method === "GET" && !hasActiveSignal;
|
|
337
|
+
const canUseDedup = config.dedupeInFlight && method === "GET" && !hasActiveSignal;
|
|
332
338
|
if (canUseCaching) {
|
|
333
339
|
const cached = tryReadCache(config, cacheKey);
|
|
334
340
|
if (cached !== void 0) {
|
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.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 on every read so LRU eviction keeps frequently-used entries alive.\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\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\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 // 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);\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"]}
|