chuvsu-js 4.2.0 → 5.0.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.
Files changed (80) hide show
  1. package/README.md +165 -193
  2. package/dist/browser.d.ts +1 -1
  3. package/dist/browser.js +1 -1
  4. package/dist/common/cache.js +30 -9
  5. package/dist/common/http.d.ts +6 -0
  6. package/dist/common/http.js +8 -1
  7. package/dist/common/parse.d.ts +1 -1
  8. package/dist/common/parse.js +2 -2
  9. package/dist/common/types.d.ts +8 -2
  10. package/dist/common/types.js +12 -0
  11. package/dist/core.d.ts +10 -0
  12. package/dist/core.js +5 -0
  13. package/dist/index.d.ts +5 -3
  14. package/dist/index.js +4 -4
  15. package/dist/lk/client.d.ts +8 -6
  16. package/dist/lk/client.js +51 -23
  17. package/dist/lk/types.d.ts +7 -7
  18. package/dist/node.d.ts +1 -0
  19. package/dist/node.js +1 -0
  20. package/dist/parsers.d.ts +3 -0
  21. package/dist/parsers.js +2 -0
  22. package/dist/tt/client.d.ts +55 -63
  23. package/dist/tt/client.js +477 -226
  24. package/dist/tt/domain/directory.d.ts +14 -0
  25. package/dist/tt/domain/directory.js +116 -0
  26. package/dist/tt/domain/ids.d.ts +7 -0
  27. package/dist/tt/domain/ids.js +20 -0
  28. package/dist/tt/domain/index.d.ts +7 -0
  29. package/dist/tt/domain/index.js +5 -0
  30. package/dist/tt/domain/normalize.d.ts +7 -0
  31. package/dist/tt/domain/normalize.js +65 -0
  32. package/dist/tt/domain/repository.d.ts +51 -0
  33. package/dist/tt/domain/repository.js +805 -0
  34. package/dist/tt/domain/schedule.d.ts +37 -0
  35. package/dist/tt/domain/schedule.js +292 -0
  36. package/dist/tt/domain/types.d.ts +175 -0
  37. package/dist/tt/domain/types.js +1 -0
  38. package/dist/tt/observations.d.ts +11 -0
  39. package/dist/tt/observations.js +131 -0
  40. package/dist/tt/parse/audience.d.ts +3 -3
  41. package/dist/tt/parse/audience.js +47 -15
  42. package/dist/tt/parse/entry-parts.d.ts +1 -0
  43. package/dist/tt/parse/entry-parts.js +5 -2
  44. package/dist/tt/parse/full-schedule.d.ts +9 -4
  45. package/dist/tt/parse/full-schedule.js +32 -41
  46. package/dist/tt/parse/groups.d.ts +1 -1
  47. package/dist/tt/parse/groups.js +1 -1
  48. package/dist/tt/parse/index.d.ts +4 -4
  49. package/dist/tt/parse/index.js +4 -4
  50. package/dist/tt/parse/lists.d.ts +6 -5
  51. package/dist/tt/parse/lists.js +7 -2
  52. package/dist/tt/parse/overlays.d.ts +5 -4
  53. package/dist/tt/parse/overlays.js +25 -18
  54. package/dist/tt/parse/teacher.d.ts +2 -3
  55. package/dist/tt/parse/teacher.js +14 -56
  56. package/dist/tt/parse/webinars.js +3 -4
  57. package/dist/tt/types.d.ts +54 -69
  58. package/dist/tt/utils/date.d.ts +4 -0
  59. package/dist/tt/utils/date.js +30 -1
  60. package/dist/tt/utils/index.d.ts +2 -3
  61. package/dist/tt/utils/index.js +2 -3
  62. package/dist/tt/utils/period.d.ts +4 -4
  63. package/dist/tt/utils/period.js +9 -8
  64. package/dist/tt/utils/semester.d.ts +4 -4
  65. package/dist/tt/utils/semester.js +25 -5
  66. package/dist/tt/utils/time-slots.d.ts +3 -5
  67. package/dist/tt/utils/time-slots.js +19 -34
  68. package/dist/tt/webinars.d.ts +7 -0
  69. package/dist/tt/webinars.js +38 -0
  70. package/docs/fixture-review.md +56 -0
  71. package/docs/testing.md +23 -0
  72. package/docs/v5-architecture.md +144 -0
  73. package/docs/v5-migration.md +451 -0
  74. package/package.json +17 -7
  75. package/dist/shared.d.ts +0 -9
  76. package/dist/shared.js +0 -7
  77. package/dist/tt/schedule.d.ts +0 -55
  78. package/dist/tt/schedule.js +0 -233
  79. package/dist/tt/utils/lessons.d.ts +0 -16
  80. package/dist/tt/utils/lessons.js +0 -173
@@ -1,10 +1,10 @@
1
- export declare const enum Period {
1
+ export declare enum AcademicPeriod {
2
2
  FallSemester = 1,
3
3
  WinterSession = 2,
4
4
  SpringSemester = 3,
5
5
  SummerSession = 4
6
6
  }
7
- export declare const enum EducationType {
7
+ export declare enum EducationLevel {
8
8
  HigherEducation = 1,
9
9
  VocationalEducation = 2
10
10
  }
@@ -12,6 +12,12 @@ export interface Time {
12
12
  hours: number;
13
13
  minutes: number;
14
14
  }
15
+ export interface TimeRange {
16
+ start: Time;
17
+ end: Time;
18
+ }
19
+ /** Calendar date without a timezone or time component. */
20
+ export type LocalDate = `${number}-${number}-${number}`;
15
21
  export interface WeekRange {
16
22
  from: number;
17
23
  to: number;
@@ -1,3 +1,15 @@
1
+ export var AcademicPeriod;
2
+ (function (AcademicPeriod) {
3
+ AcademicPeriod[AcademicPeriod["FallSemester"] = 1] = "FallSemester";
4
+ AcademicPeriod[AcademicPeriod["WinterSession"] = 2] = "WinterSession";
5
+ AcademicPeriod[AcademicPeriod["SpringSemester"] = 3] = "SpringSemester";
6
+ AcademicPeriod[AcademicPeriod["SummerSession"] = 4] = "SummerSession";
7
+ })(AcademicPeriod || (AcademicPeriod = {}));
8
+ export var EducationLevel;
9
+ (function (EducationLevel) {
10
+ EducationLevel[EducationLevel["HigherEducation"] = 1] = "HigherEducation";
11
+ EducationLevel[EducationLevel["VocationalEducation"] = 2] = "VocationalEducation";
12
+ })(EducationLevel || (EducationLevel = {}));
1
13
  export class AuthError extends Error {
2
14
  constructor(message) {
3
15
  super(message);
package/dist/core.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from "./tt/domain/index.js";
2
+ export { attachWebinars, findWebinar } from "./tt/webinars.js";
3
+ export type { LessonWithWebinar } from "./tt/webinars.js";
4
+ export { getAdjacentSemester, getCompensatingWorkDays, getCurrentPeriod, getEffectiveHolidays, formatLocalDate, getHolidayTransfers, getSemesterStart, getSemesterWeeks, getStandardScheduleBlocks, getWeekNumber, getWeekdayName, isHoliday, isLocalDate, isSessionPeriod, parseLocalDate, RUSSIAN_HOLIDAYS, } from "./tt/utils/index.js";
5
+ export type { Holiday, HolidayTransfer } from "./tt/utils/index.js";
6
+ export { AuthError, EducationLevel, ParseError, AcademicPeriod, } from "./common/types.js";
7
+ export type { LocalDate, Teacher, Time, TimeRange, WeekRange, } from "./common/types.js";
8
+ export type { CacheAdapter, CacheEntry } from "./common/cache.js";
9
+ export type { CacheConfig, DirectoryPreloadOptions, EntityResolutionStrategy, Faculty, GetScheduleOptions, Group, StandardScheduleBlock, Room, RoomInfo, SemesterWeek, TeacherInfo, TimetableClientOptions, Webinar, } from "./tt/types.js";
10
+ export type { StudentPortalCacheConfig, StudentPortalClientOptions, StudentProfile, } from "./lk/types.js";
package/dist/core.js ADDED
@@ -0,0 +1,5 @@
1
+ // Runtime-safe core for Node.js, browsers, Deno, and workers.
2
+ export * from "./tt/domain/index.js";
3
+ export { attachWebinars, findWebinar } from "./tt/webinars.js";
4
+ export { getAdjacentSemester, getCompensatingWorkDays, getCurrentPeriod, getEffectiveHolidays, formatLocalDate, getHolidayTransfers, getSemesterStart, getSemesterWeeks, getStandardScheduleBlocks, getWeekNumber, getWeekdayName, isHoliday, isLocalDate, isSessionPeriod, parseLocalDate, RUSSIAN_HOLIDAYS, } from "./tt/utils/index.js";
5
+ export { AuthError, EducationLevel, ParseError, AcademicPeriod, } from "./common/types.js";
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
- export * from "./shared.js";
2
- export { LkClient } from "./lk/client.js";
3
- export { TtClient } from "./tt/client.js";
1
+ export * from "./core.js";
2
+ export { StudentPortalClient } from "./lk/client.js";
3
+ export { TimetableClient } from "./tt/client.js";
4
+ export * from "./parsers.js";
5
+ export type { BlobAdapter, BlobPutOptions, } from "./common/cache.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export * from "./shared.js";
2
- // Node-only clients (depend on `undici`).
3
- export { LkClient } from "./lk/client.js";
4
- export { TtClient } from "./tt/client.js";
1
+ export * from "./core.js";
2
+ export { StudentPortalClient } from "./lk/client.js";
3
+ export { TimetableClient } from "./tt/client.js";
4
+ export * from "./parsers.js";
@@ -1,17 +1,19 @@
1
- import type { LkClientOptions, PersonalData } from "./types.js";
2
- export declare class LkClient {
1
+ import type { StudentPortalClientOptions, StudentProfile } from "./types.js";
2
+ export declare class StudentPortalClient {
3
3
  private http;
4
4
  private credentials;
5
5
  private cache;
6
6
  private blobAdapter;
7
- constructor(opts?: LkClientOptions);
7
+ constructor(opts?: StudentPortalClientOptions);
8
8
  login(opts: {
9
9
  email: string;
10
10
  password: string;
11
11
  }): Promise<void>;
12
12
  private isSessionExpired;
13
13
  private authGet;
14
- getPersonalData(): Promise<PersonalData>;
15
- getPhoto(): Promise<Buffer>;
16
- getGroupId(): Promise<number | null>;
14
+ private isBinarySessionExpired;
15
+ private authGetBuffer;
16
+ getProfile(): Promise<StudentProfile>;
17
+ getProfilePhoto(): Promise<Buffer>;
18
+ getTimetableGroupId(): Promise<number | null>;
17
19
  }
package/dist/lk/client.js CHANGED
@@ -1,18 +1,18 @@
1
- import { HttpClient } from "../common/http.js";
1
+ import { HttpClient, } from "../common/http.js";
2
2
  import { HybridCache } from "../common/cache.js";
3
- import { AuthError } from "../common/types.js";
3
+ import { AuthError, ParseError } from "../common/types.js";
4
4
  import { extractScriptValues } from "./parse.js";
5
5
  const BASE = "https://lk.chuvsu.ru";
6
6
  const LOGIN_URL = `${BASE}/info/login.php`;
7
7
  const STUDENT_BASE = `${BASE}/student`;
8
8
  function makeUniformCacheConfig(ttl) {
9
9
  return {
10
- personalData: ttl,
11
- photo: ttl,
12
- groupId: ttl,
10
+ profile: ttl,
11
+ profilePhoto: ttl,
12
+ timetableGroupId: ttl,
13
13
  };
14
14
  }
15
- export class LkClient {
15
+ export class StudentPortalClient {
16
16
  http = new HttpClient();
17
17
  credentials = null;
18
18
  cache;
@@ -40,19 +40,47 @@ export class LkClient {
40
40
  return body.includes("login.php");
41
41
  }
42
42
  async authGet(url) {
43
- const res = await this.http.get(url);
43
+ let res = await this.http.get(url);
44
44
  if (this.credentials && this.isSessionExpired(res.body)) {
45
45
  await this.login(this.credentials);
46
- return this.http.get(url);
46
+ res = await this.http.get(url);
47
+ }
48
+ if (this.isSessionExpired(res.body)) {
49
+ throw new AuthError("LK request returned an authentication page");
50
+ }
51
+ if (res.status < 200 || res.status >= 300) {
52
+ throw new Error(`LK request failed with HTTP ${res.status}: ${url}`);
47
53
  }
48
54
  return res;
49
55
  }
50
- async getPersonalData() {
51
- const cached = await this.cache?.get("personalData", "self");
56
+ isBinarySessionExpired(response) {
57
+ const prefix = response.body.subarray(0, 8_192).toString("utf8");
58
+ return this.isSessionExpired(prefix) ||
59
+ response.contentType?.toLowerCase().includes("text/html") === true;
60
+ }
61
+ async authGetBuffer(url) {
62
+ let res = await this.http.getBufferResponse(url);
63
+ if (this.credentials && this.isBinarySessionExpired(res)) {
64
+ await this.login(this.credentials);
65
+ res = await this.http.getBufferResponse(url);
66
+ }
67
+ if (res.status < 200 || res.status >= 300) {
68
+ throw new Error(`LK request failed with HTTP ${res.status}: ${url}`);
69
+ }
70
+ if (this.isBinarySessionExpired(res)) {
71
+ throw new AuthError("LK binary request returned an authentication page");
72
+ }
73
+ return res.body;
74
+ }
75
+ async getProfile() {
76
+ const cached = await this.cache?.get("profile", "self");
52
77
  if (cached)
53
78
  return cached;
54
79
  const { body } = await this.authGet(`${STUDENT_BASE}/personal_data.php`);
55
80
  const vals = extractScriptValues(body, "form_personal_data");
81
+ if (!vals.fam?.trim() || !vals.nam?.trim()) {
82
+ throw new ParseError("LK profile response has no student identity");
83
+ }
56
84
  const data = {
57
85
  lastName: vals.fam ?? "",
58
86
  firstName: vals.nam ?? "",
@@ -68,12 +96,12 @@ export class LkClient {
68
96
  email: vals.email ?? "",
69
97
  phone: vals.phone ?? "",
70
98
  };
71
- await this.cache?.set("personalData", "self", data);
99
+ await this.cache?.set("profile", "self", data);
72
100
  return data;
73
101
  }
74
- async getPhoto() {
75
- const cached = this.cache?.getLocal("photo", "self") ??
76
- await this.cache?.get("photo", "self");
102
+ async getProfilePhoto() {
103
+ const cached = this.cache?.getLocal("profilePhoto", "self") ??
104
+ await this.cache?.get("profilePhoto", "self");
77
105
  if (cached !== null && cached !== undefined) {
78
106
  const entry = cached;
79
107
  if (typeof entry === "string")
@@ -84,33 +112,33 @@ export class LkClient {
84
112
  if (entry.blobKey && this.blobAdapter) {
85
113
  const photo = await this.blobAdapter.get(entry.blobKey);
86
114
  if (photo) {
87
- this.cache?.setLocal("photo", "self", { data: photo.toString("base64") });
115
+ this.cache?.setLocal("profilePhoto", "self", { data: photo.toString("base64") });
88
116
  return photo;
89
117
  }
90
118
  }
91
119
  }
92
- const photo = await this.http.getBuffer(`${STUDENT_BASE}/face.php`);
120
+ const photo = await this.authGetBuffer(`${STUDENT_BASE}/face.php`);
93
121
  if (this.blobAdapter) {
94
122
  const blobKey = "lk/photo/self";
95
- this.cache?.setLocal("photo", "self", { data: photo.toString("base64") });
123
+ this.cache?.setLocal("profilePhoto", "self", { data: photo.toString("base64") });
96
124
  await this.blobAdapter.put(blobKey, photo, {
97
- ttl: this.cache?.ttl("photo"),
125
+ ttl: this.cache?.ttl("profilePhoto"),
98
126
  });
99
- await this.cache?.setExternal("photo", "self", { blobKey });
127
+ await this.cache?.setExternal("profilePhoto", "self", { blobKey });
100
128
  }
101
129
  else {
102
- await this.cache?.set("photo", "self", photo.toString("base64"));
130
+ await this.cache?.set("profilePhoto", "self", photo.toString("base64"));
103
131
  }
104
132
  return photo;
105
133
  }
106
- async getGroupId() {
107
- const cached = await this.cache?.get("groupId", "self");
134
+ async getTimetableGroupId() {
135
+ const cached = await this.cache?.get("timetableGroupId", "self");
108
136
  if (cached !== null && cached !== undefined)
109
137
  return cached;
110
138
  const { body } = await this.authGet(`${STUDENT_BASE}/tt.php`);
111
139
  const match = body.match(/tt\.chuvsu\.ru\/index\/grouptt\/gr\/(\d+)/);
112
140
  const groupId = match ? parseInt(match[1]) : null;
113
- await this.cache?.set("groupId", "self", groupId);
141
+ await this.cache?.set("timetableGroupId", "self", groupId);
114
142
  return groupId;
115
143
  }
116
144
  }
@@ -1,5 +1,5 @@
1
1
  import type { BlobAdapter, CacheAdapter } from "../common/cache.js";
2
- export interface PersonalData {
2
+ export interface StudentProfile {
3
3
  lastName: string;
4
4
  firstName: string;
5
5
  patronymic: string;
@@ -14,13 +14,13 @@ export interface PersonalData {
14
14
  email: string;
15
15
  phone: string;
16
16
  }
17
- export interface LkCacheConfig {
18
- personalData?: number;
19
- photo?: number;
20
- groupId?: number;
17
+ export interface StudentPortalCacheConfig {
18
+ profile?: number;
19
+ profilePhoto?: number;
20
+ timetableGroupId?: number;
21
21
  }
22
- export interface LkClientOptions {
23
- cache?: number | LkCacheConfig;
22
+ export interface StudentPortalClientOptions {
23
+ cache?: number | StudentPortalCacheConfig;
24
24
  cacheAdapter?: CacheAdapter;
25
25
  blobAdapter?: BlobAdapter;
26
26
  }
package/dist/node.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./index.js";
package/dist/node.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./index.js";
@@ -0,0 +1,3 @@
1
+ export { parseAcademicYearFromPage, parseRoomButtons, parseRoomSchedule, parseRoomInfo, parseRoomName, parseFacultyButtons, parseGroupSchedule, parseGroupName, parseGroupButtons, parseGroupsString, parsePeriodFromPage, parseTeacherButtons, parseTeacherSchedule, parseTeacherInfo, parseWebinars, } from "./tt/parse/index.js";
2
+ export { createScheduleSourceSnapshot } from "./tt/observations.js";
3
+ export type { ParsedScheduleDay, ParsedLesson, ParsedScheduleBlock, } from "./tt/types.js";
@@ -0,0 +1,2 @@
1
+ export { parseAcademicYearFromPage, parseRoomButtons, parseRoomSchedule, parseRoomInfo, parseRoomName, parseFacultyButtons, parseGroupSchedule, parseGroupName, parseGroupButtons, parseGroupsString, parsePeriodFromPage, parseTeacherButtons, parseTeacherSchedule, parseTeacherInfo, parseWebinars, } from "./tt/parse/index.js";
2
+ export { createScheduleSourceSnapshot } from "./tt/observations.js";
@@ -1,16 +1,29 @@
1
1
  import type { CacheEntry } from "../common/cache.js";
2
- import { Period } from "../common/types.js";
3
- import { Schedule } from "./schedule.js";
4
- import type { Audience, AudienceInfo, Faculty, Group, TeacherInfo, TtClientOptions, CacheConfig, Webinar } from "./types.js";
5
- export declare class TtClient {
2
+ import { Schedule } from "./domain/schedule.js";
3
+ import { TimetableRepository } from "./domain/repository.js";
4
+ import type { GroupRef, RoomRef, ScheduleOwner, TeacherRef, TimetableRepositorySnapshot } from "./domain/types.js";
5
+ import type { Room, RoomInfo, Faculty, Group, TeacherInfo, TimetableClientOptions, CacheConfig, DirectoryPreloadOptions, EntityResolutionStrategy, GetScheduleOptions, Webinar } from "./types.js";
6
+ export declare class TimetableClient {
6
7
  private http;
7
- private educationType;
8
+ private educationLevel;
8
9
  private cache;
9
10
  private blobAdapter;
11
+ private _repository;
12
+ private repositoryAdapter;
13
+ private repositoryReady;
14
+ private repositoryMutation;
10
15
  private loginMode;
11
16
  private timetableContext;
12
- constructor(opts?: TtClientOptions);
17
+ constructor(opts?: TimetableClientOptions);
13
18
  private get pertt();
19
+ get repository(): TimetableRepository;
20
+ private ensureRepository;
21
+ private mutateRepository;
22
+ private performRepositoryMutation;
23
+ exportRepository(): Promise<TimetableRepositorySnapshot>;
24
+ private rememberGroups;
25
+ private rememberTeachers;
26
+ private rememberRooms;
14
27
  clearCache(category?: keyof CacheConfig): Promise<void>;
15
28
  exportCache(): Record<string, CacheEntry>;
16
29
  importCache(data: Record<string, CacheEntry>): void;
@@ -20,25 +33,21 @@ export declare class TtClient {
20
33
  }): Promise<void>;
21
34
  loginAsGuest(): Promise<void>;
22
35
  private isSessionExpired;
36
+ private isBinarySessionExpired;
23
37
  private relogin;
24
38
  private authGet;
25
39
  private authGetBuffer;
26
40
  private authPost;
27
41
  /** Resolve the academic year and active period from tt.chuvsu.ru itself. */
28
42
  private getTimetableContext;
29
- private fetchSchedule;
30
- /**
31
- * Get schedule for all periods. The returned Schedule automatically
32
- * routes queries to the correct period based on the date.
33
- */
34
- getSchedule(groupId: number): Promise<Schedule>;
35
- /**
36
- * Get schedule for a specific period only.
37
- */
38
- getScheduleForPeriod(opts: {
39
- groupId: number;
40
- period: Period;
41
- }): Promise<Schedule>;
43
+ private fetchGroupSchedule;
44
+ private validateSchedulePage;
45
+ private ownerUrl;
46
+ private sourceKey;
47
+ private resolveOwner;
48
+ private fetchOwnerSchedule;
49
+ getSchedule(owner: ScheduleOwner, options?: GetScheduleOptions): Promise<Schedule>;
50
+ getGroupSchedule(groupId: number, options?: GetScheduleOptions): Promise<Schedule>;
42
51
  getWebinars(opts?: {
43
52
  date?: Date;
44
53
  facultyId?: number;
@@ -50,19 +59,13 @@ export declare class TtClient {
50
59
  password: string;
51
60
  }): Promise<string>;
52
61
  getFaculties(): Promise<Faculty[]>;
53
- getGroupsForFaculty(opts: {
54
- facultyId: number;
55
- }): Promise<Group[]>;
56
- searchGroup(opts: {
57
- name: string;
58
- }): Promise<Group[]>;
62
+ getFacultyGroups(facultyId: number): Promise<Group[]>;
63
+ searchGroups(name: string): Promise<GroupRef[]>;
59
64
  /**
60
65
  * Search audiences by name (substring match). The server requires at
61
66
  * least 3 characters in the query.
62
67
  */
63
- searchAudience(opts: {
64
- name: string;
65
- }): Promise<Audience[]>;
68
+ searchRooms(name: string): Promise<Room[]>;
66
69
  /**
67
70
  * Get every audience known to the system in a single request.
68
71
  *
@@ -71,61 +74,50 @@ export declare class TtClient {
71
74
  * 3-character wildcard `%%%` matches every audience at once and returns
72
75
  * the full list of (id, name) pairs.
73
76
  */
74
- getAudiences(): Promise<Audience[]>;
77
+ getRooms(): Promise<Room[]>;
78
+ resolveGroup(value: string | GroupRef, options?: {
79
+ strategy?: EntityResolutionStrategy;
80
+ }): Promise<GroupRef>;
81
+ resolveTeacher(value: string | TeacherRef, options?: {
82
+ strategy?: EntityResolutionStrategy;
83
+ }): Promise<TeacherRef>;
84
+ resolveRoom(value: string | RoomRef, options?: {
85
+ strategy?: EntityResolutionStrategy;
86
+ }): Promise<RoomRef>;
87
+ preloadDirectory(options: DirectoryPreloadOptions): Promise<void>;
75
88
  /**
76
89
  * Resolve an audience id from its exact name by searching and
77
90
  * selecting the button whose `value` equals the given name.
78
91
  */
79
- findAudienceByName(opts: {
80
- name: string;
81
- }): Promise<Audience | null>;
92
+ findRoomByName(name: string): Promise<Room | null>;
82
93
  /** Fetch the audience's display name from its schedule page. */
83
- getAudienceName(audienceId: number): Promise<string | null>;
94
+ getRoomName(roomId: number): Promise<string | null>;
84
95
  /**
85
96
  * Fetch detailed info about an audience (building, floor, usage,
86
97
  * image URLs for the audience photo, building photo and floor plan).
87
98
  */
88
- getAudienceInfo(audienceId: number): Promise<AudienceInfo | null>;
89
- private fetchAudienceSchedule;
90
- getAudienceSchedule(audienceId: number): Promise<Schedule>;
91
- getAudienceScheduleForPeriod(opts: {
92
- audienceId: number;
93
- period: Period;
94
- }): Promise<Schedule>;
95
- private getCachedAudienceImage;
99
+ getRoomInfo(roomId: number): Promise<RoomInfo | null>;
100
+ private fetchRoomSchedule;
101
+ getRoomSchedule(roomId: number, options?: GetScheduleOptions): Promise<Schedule>;
102
+ private getCachedRoomImage;
96
103
  /** Get the audience photo (audimage). Returns null if missing. */
97
- getAudienceImage(audienceId: number): Promise<Buffer | null>;
104
+ getRoomImage(roomId: number): Promise<Buffer | null>;
98
105
  /** Get the building exterior image (blockimage). Returns null if missing. */
99
- getAudienceBlockImage(audienceId: number): Promise<Buffer | null>;
106
+ getRoomBuildingImage(roomId: number): Promise<Buffer | null>;
100
107
  /** Get the floor plan image for the audience. Returns null if missing. */
101
- getAudienceFloorplan(audienceId: number): Promise<Buffer | null>;
102
- searchTeacher(opts: {
103
- name: string;
104
- }): Promise<{
105
- id: number;
106
- name: string;
107
- }[]>;
108
+ getRoomFloorPlan(roomId: number): Promise<Buffer | null>;
109
+ searchTeachers(name: string): Promise<TeacherRef[]>;
108
110
  getTeachers(): Promise<{
109
111
  id: number;
110
112
  name: string;
111
113
  }[]>;
112
114
  private fetchTeacherSchedule;
113
- getTeacherSchedule(teacherId: number): Promise<Schedule>;
114
- getTeacherScheduleForPeriod(opts: {
115
- teacherId: number;
116
- period: Period;
117
- }): Promise<Schedule>;
115
+ getTeacherSchedule(teacherId: number, options?: GetScheduleOptions): Promise<Schedule>;
118
116
  getTeacherInfo(teacherId: number): Promise<TeacherInfo | null>;
119
117
  /**
120
- * Get the teacher's photo as a Buffer.
118
+ * Get teacher photo directly by known URL pattern.
119
+ * Does not fetch or parse teacher info first.
121
120
  * Returns null if the teacher has no photo.
122
- * Uses cached teacher info when available to avoid extra requests.
123
121
  */
124
122
  getTeacherPhoto(teacherId: number): Promise<Buffer | null>;
125
- /**
126
- * Get the teacher's photo without parsing the schedule page.
127
- * Uses the known URL pattern directly — no extra page fetch needed.
128
- * Returns null if the teacher has no photo.
129
- */
130
- getTeacherPhotoLazy(teacherId: number): Promise<Buffer | null>;
131
123
  }