bsuir-iis-api 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.0] - 2026-05-24
4
+
5
+ ### Added
6
+
7
+ - `schedule.getGroupBySubgroup()` and `schedule.getEmployeeBySubgroup()` accept `rawEnvelope: true` for envelope-preserving raw subgroup output.
8
+ - `announcements.byEmployee()` / `byDepartment()` accept `treat404AsEmpty` (default `true`) to opt out of mapping IIS `404`/`400` empty-announcement responses to `[]`.
9
+ - Optional `onInvalidTime` hook for `sortLessonsByTime()`, `getCurrentLesson()`, `getNextLesson()`, and `buildScheduleDays()`.
10
+
11
+ ### Changed
12
+
13
+ - `schedule.getGroup()` / `getEmployee()` now always return normalized payloads; use `getGroupRaw()`, `getEmployeeRaw()`, `getGroupEnvelope()`, or `getEmployeeEnvelope()` for raw API envelopes.
14
+ - Response cache stores deep-frozen JSON values, returns the cached frozen reference on hits, and rejects non-JSON cache writes with `BsuirConfigurationError`.
15
+ - `requestJson` keeps response caching enabled for non-aborted `AbortSignal`s; in-flight deduplication remains disabled for per-call signals to avoid cross-caller cancellation semantics.
16
+ - Query keys are sorted deterministically for stable cache keys, query key validation is relaxed for safe non-structural characters, and private-header detection now uses an explicit denylist.
17
+ - Request bodies pass through native `BodyInit` shapes (`FormData`, `URLSearchParams`, `Blob`, `ArrayBuffer`, `ReadableStream`) instead of being JSON-stringified.
18
+ - `Retry-After` numeric values now use the same internal cap as date-based values.
19
+ - `allowInsecureHttp: true` rejects non-loopback hosts in `allowedBaseUrlHosts`.
20
+ - `normalizeSchedule` clones lessons once, always performs a minimal envelope check, and delegates full validation to `assertScheduleResponse`.
21
+ - `mergeSignalsManual` cleanup is idempotent and records listeners before registration to avoid leaks.
22
+
23
+ ### Documentation
24
+
25
+ - README now documents explicit raw schedule helpers, `validateResponses` as opt-in, `BsuirResponsePayloadTooLargeError` for oversized payloads, and the Changesets release flow.
26
+
27
+ ### Potentially Breaking
28
+
29
+ - Removed `defaultRaw` and per-call `raw` selection from `schedule.getGroup()` / `getEmployee()`; callers should use explicit raw helpers instead.
30
+ - Cached responses are frozen shared references; callers that need mutation should clone returned values first.
31
+ - Native `BodyInit` request bodies are no longer JSON-stringified.
32
+ - `allowInsecureHttp: true` is limited to loopback hosts.
33
+
34
+ ## [0.10.1] - 2026-05-13
35
+
36
+ ### Documentation
37
+
38
+ - README: clarified `defaultRaw` behavior for `schedule.getGroup()` / `schedule.getEmployee()` when per-call `raw` is omitted.
39
+ - README: clarified retry semantics (GET retries cover retriable HTTP statuses and network/transport errors).
40
+ - README: documented `maxResponseBytes` failure behavior (`BsuirApiError` on oversized payloads).
41
+ - README: made usage snippets standalone by adding required imports/client initialization.
42
+ - README: added explicit public export reference for runtime helpers, error classes, and exported domain/types surface.
43
+
44
+ ### Changed
45
+
46
+ - Changelog restored explicit `0.8.0` section and separated `0.9.0` release-management metadata.
47
+ - Changelog now marks `0.10.0` behavior shifts with potentially breaking downstream impact notes.
48
+
3
49
  ## [0.10.0] - 2026-05-13
4
50
 
5
51
  ### Added
@@ -18,6 +64,12 @@
18
64
  - GitHub Actions in CI/release workflows are pinned to commit SHAs.
19
65
  - Dev dependencies in `package.json` are now pinned to exact versions.
20
66
 
67
+ ### Potentially Breaking
68
+
69
+ - `baseUrl` validation is now strict; previously accepted non-normalized/less-safe values can now throw `BsuirConfigurationError`.
70
+ - `validateResponses` defaults to `true`; integrations that relied on unchecked payloads may now see `BsuirResponseValidationError`.
71
+ - Response body size is now actively enforced via `maxResponseBytes`; oversized responses now fail fast with `BsuirApiError`.
72
+
21
73
  ### Fixed
22
74
 
23
75
  - Response parser now enforces `maxResponseBytes` for both `Content-Length` pre-checks and streamed body reads.
@@ -40,6 +92,12 @@
40
92
 
41
93
  ## [0.9.0] - 2026-05-10
42
94
 
95
+ ### Changed
96
+
97
+ - Release-management update from Changesets (`version: 0.9.0` + release metadata). Runtime API/content remained aligned with the `0.8.0` code snapshot.
98
+
99
+ ## [0.8.0] - 2026-05-10
100
+
43
101
  ### Added
44
102
 
45
103
  - Public exports for schedule utilities: `normalizeSchedule` and `filterLessons`.
package/README.md CHANGED
@@ -16,7 +16,7 @@ npm install bsuir-iis-api
16
16
 
17
17
  ## Quick start
18
18
 
19
- Default schedule calls return a **normalized** payload (`defaultRaw: false`). That shape includes `lessons`, `lessonsByDay`, `scheduleLessons`, and `examLessons` (see types). With `{ raw: true }` you get the API’s raw `ScheduleResponse` instead—no `lessons` field; use `schedules` / `exams` and match examples to the option you use.
19
+ Default schedule calls return a **normalized** payload. That shape includes `lessons`, `lessonsByDay`, `scheduleLessons`, and `examLessons` (see types). Use explicit raw helpers such as `client.schedule.getGroupRaw()` / `getEmployeeRaw()` to obtain the API’s raw `ScheduleResponse` (which has `schedules` / `exams` and may omit `lessons`).
20
20
 
21
21
  ```ts
22
22
  import { createBsuirClient } from "bsuir-iis-api";
@@ -31,6 +31,8 @@ console.log(schedule.lessons.length);
31
31
  ## Client options
32
32
 
33
33
  ```ts
34
+ import { createBsuirClient } from "bsuir-iis-api";
35
+
34
36
  const client = createBsuirClient({
35
37
  baseUrl: "https://iis.bsuir.by/api/v1",
36
38
  allowedBaseUrlHosts: ["iis.bsuir.by"],
@@ -48,8 +50,7 @@ const client = createBsuirClient({
48
50
  onRetry: ({ endpoint, delayMs, reason }) => {
49
51
  console.log("retry", endpoint, delayMs, reason);
50
52
  }
51
- },
52
- defaultRaw: false
53
+ }
53
54
  });
54
55
  ```
55
56
 
@@ -58,10 +59,10 @@ const client = createBsuirClient({
58
59
  - `allowedBaseUrlHosts` controls which hosts are allowed for `baseUrl` (defaults to `["iis.bsuir.by"]`).
59
60
  - `allowInsecureHttp` enables `http://` only for trusted local/test endpoints.
60
61
  - `signal` in `createBsuirClient({ signal })` acts as a global cancellation signal for all requests made by that client.
61
- - `cache` stores successful GET responses in-memory for the configured TTL.
62
- - `dedupeInFlight` reuses the same in-flight GET request for concurrent callers (when no per-request signal is passed).
62
+ - `cache` stores successful GET responses in-memory for the configured TTL. A live `AbortSignal` can still use cache; an already-aborted signal skips cache.
63
+ - `dedupeInFlight` reuses the same in-flight GET request for concurrent callers. It is disabled for per-request signals, non-default cache modes, private credential headers, and already-aborted signals.
63
64
  - `maxResponseBytes` limits body size per response to protect against memory spikes.
64
- - `validateResponses` enables runtime payload-shape checks for key endpoints (enabled by default).
65
+ - `validateResponses` enables opt-in runtime payload-shape checks for key endpoints.
65
66
  - `hooks` provides lifecycle callbacks (`onRequest`, `onRetry`, `onResponse`, `onError`) for observability.
66
67
  - `AbortSignal` is supported by all read methods.
67
68
 
@@ -99,11 +100,20 @@ const client = createBsuirClient({
99
100
 
100
101
  When IIS responds with HTTP `404` or `400` (no list, missing resource, or endpoint quirks), these methods resolve to an empty array `[]` instead of throwing `BsuirApiError`. Client-side validation still runs first (`urlId`, department `id`). If IIS later returns a meaningful `400` for bad parameters, it will also map to `[]`; other HTTP errors are unchanged.
101
102
 
103
+ ### Public exports (runtime utilities and types)
104
+
105
+ - Core runtime API: `createBsuirClient`, `BsuirClient`
106
+ - Client/runtime option types: `BsuirClientOptions`, `CacheOptions`, `ClientHooks`, `RequestOptions`, `ReadOptions`, `RequestHookContext`, `RetryHookContext`, `ResponseHookContext`, `ErrorHookContext`
107
+ - Schedule utilities: `normalizeSchedule`, `filterLessons`, `getLessonsForDate`, `getTodayLessons`, `getTomorrowLessons`, `getLessonsForWeek`, `sortLessonsByTime`, `groupLessonsByDay`, `getCurrentLesson`, `getNextLesson`, `buildScheduleDays`, `ScheduleFilterOptions`
108
+ - Error classes: `BsuirApiError`, `BsuirNetworkError`, `BsuirTimeoutError`, `BsuirValidationError`, `BsuirResponseValidationError`, `BsuirResponsePayloadTooLargeError`, `BsuirConfigurationError`
109
+ - Domain types: `Announcement`, `ApiDateResponse`, `Auditory`, `AuditoryDepartment`, `AuditoryType`, `BuildingNumber`, `Department`, `EducationForm`, `Employee`, `EmployeeCatalogItem`, `Faculty`, `FlattenedLessonsByDay`, `FlattenedScheduleItem`, `LessonStudentGroup`, `Maybe`, `NormalizedScheduleResponse`, `ScheduleItem`, `ScheduleResponse`, `Speciality`, `StudentGroupCatalogItem`, `StudentGroupShort`, `Weekday`, `WeekScheduleMap`
110
+
102
111
  ## Errors
103
112
 
104
113
  SDK throws typed errors:
105
114
 
106
115
  - `BsuirApiError` for HTTP errors (contains `status`, `endpoint`, `body`). **Exception:** `client.announcements.byEmployee` / `byDepartment` resolve to `[]` on IIS HTTP `404` or `400` instead of throwing (see Announcements above).
116
+ - `BsuirResponsePayloadTooLargeError` when response body size exceeds configured `maxResponseBytes`.
107
117
  - `BsuirNetworkError` for transport errors (contains `endpoint` and standard `cause`)
108
118
  - `BsuirResponseValidationError` for invalid payload shapes when `validateResponses: true`
109
119
  - `BsuirTimeoutError` for timeouts (contains `endpoint`, `timeoutMs`)
@@ -115,9 +125,9 @@ Validation rules:
115
125
  - `groupNumber` must contain digits only
116
126
  - `urlId` must be a slug with letters/digits/hyphens (for example `s-nesterenkov`)
117
127
  - `id` and `subgroup` parameters must be positive integers
118
- Retry and abort behavior:
128
+ Retry and abort behavior:
119
129
 
120
- - Retries are applied to `429`, `500`, `502`, `503`, `504`
130
+ - Retries are applied to GET requests for transport/network errors and HTTP `429`, `500`, `502`, `503`, `504`
121
131
  - `Retry-After` is respected for retriable responses
122
132
  - Caller-provided aborted `AbortSignal` is re-thrown as native `AbortError`
123
133
  - Internal timeout is mapped to `BsuirTimeoutError`
@@ -131,17 +141,20 @@ For **2xx** responses the client reads the body as text, then applies `JSON.pars
131
141
  - Valid JSON is returned even when `Content-Type` does **not** include `application/json` (mislabeled responses still parse).
132
142
  - If `Content-Type` indicates **`application/json`** but the body is empty or not valid JSON, the client throws `BsuirApiError` (`Invalid JSON response payload`), same as for a truncated `{` payload.
133
143
  - If the body is **empty** and the content type does **not** indicate JSON, the result is an empty string `""` (analogous to reading plain text). Typical IIS catalog JSON endpoints return a non-empty body.
144
+ - If response body size exceeds `maxResponseBytes`, the client throws `BsuirResponsePayloadTooLargeError`.
134
145
 
135
146
  ## Raw vs normalized schedule response
136
147
 
137
148
  By default, schedule methods return a **normalized** `NormalizedScheduleResponse`: `lessons` is all flattened items (weekly + exams), each tagged with `source: "schedules" | "exams"`; `scheduleLessons` / `examLessons` are the same rows split by source; `lessonsByDay` groups by weekday.
138
149
 
139
150
  ```ts
140
- const raw = await client.schedule.getGroup("053503", { raw: true });
151
+ import { createBsuirClient } from "bsuir-iis-api";
152
+
153
+ const client = createBsuirClient();
154
+ const raw = await client.schedule.getGroupRaw("053503");
141
155
  ```
142
156
 
143
- Use `defaultRaw: true` in `createBsuirClient` to change global behavior.
144
- When `raw` is omitted, `getGroup()` and `getEmployee()` return normalized payload.
157
+ Use explicit helpers `getGroupRaw` / `getEmployeeRaw` to obtain raw envelopes. `getGroup()` / `getEmployee()` return normalized payloads by default.
145
158
  In raw mode API may return `schedules: null`; normalized mode always converts it to `{}`.
146
159
  In raw mode some lesson fields may also be nullable (`weekNumber`, `lessonTypeAbbrev`), so keep null checks if you consume raw payload directly.
147
160
  README examples match the installed package version; if types and docs ever diverge, rely on `NormalizedScheduleResponse` / `ScheduleResponse` from the same release.
@@ -154,6 +167,9 @@ The SDK normalizes `current-week` payloads, including plain-text responses like
154
167
  Filtering example:
155
168
 
156
169
  ```ts
170
+ import { createBsuirClient } from "bsuir-iis-api";
171
+
172
+ const client = createBsuirClient();
157
173
  const exams = await client.schedule.getGroupFiltered("053503", {
158
174
  source: "exams",
159
175
  lessonTypeAbbrev: ["Консультация", "Экзамен"]
@@ -161,9 +177,23 @@ const exams = await client.schedule.getGroupFiltered("053503", {
161
177
  ```
162
178
 
163
179
  ```ts
180
+ import { createBsuirClient } from "bsuir-iis-api";
181
+
182
+ const client = createBsuirClient();
164
183
  const subgroupLessons = await client.schedule.getEmployeeBySubgroup("s-nesterenkov", 1);
165
184
  ```
166
185
 
186
+ ## Schedule helpers for UI
187
+
188
+ ```ts
189
+ import { buildScheduleDays, getTodayLessons } from "bsuir-iis-api";
190
+
191
+ const todayLessons = getTodayLessons(schedule, new Date());
192
+ const days = buildScheduleDays(schedule, { days: 7, includeEmptyDays: false });
193
+ ```
194
+
195
+ Use `getCurrentLesson(days[0].lessons)` / `getNextLesson(days[0].lessons)` for in-day progress indicators.
196
+
167
197
  ## Development
168
198
 
169
199
  ```bash
@@ -197,9 +227,11 @@ CI has a manual `workflow_dispatch` path that also runs live contracts (`live-co
197
227
  ## Release checklist
198
228
 
199
229
  1. Run `npm run check:full`.
200
- 2. Update version and `CHANGELOG.md` in the same release commit.
201
- 3. Push to `main` to trigger GitHub Actions release workflow.
202
- 4. Verify published package in a clean project:
230
+ 2. Add or update a `.changeset/*.md` entry for user-visible changes.
231
+ 3. Run `npx changeset version` to bump `package.json`, update `CHANGELOG.md`, and consume changesets.
232
+ 4. Run `npm run api:report:check` and `npm run release:dry`.
233
+ 5. Push to `main` to trigger GitHub Actions release workflow.
234
+ 6. Verify published package in a clean project:
203
235
 
204
236
  ```bash
205
237
  mkdir bsuir-iis-smoke && cd bsuir-iis-smoke
@@ -208,7 +240,7 @@ npm install bsuir-iis-api@latest
208
240
  node -e "import('bsuir-iis-api').then(m=>console.log(typeof m.createBsuirClient))"
209
241
  ```
210
242
 
211
- The project keeps `CHANGELOG.md` manually curated for stable release notes.
243
+ The project uses Changesets for version bumps and changelog generation; edit pending changeset text before versioning when release notes need refinement.
212
244
 
213
245
  ## License
214
246