chukyo-sdk 0.1.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.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +227 -0
  3. package/dist/cjs/albo/client.js +133 -0
  4. package/dist/cjs/albo/index.js +55 -0
  5. package/dist/cjs/albo/parser/albo.js +110 -0
  6. package/dist/cjs/albo/types/albo.js +351 -0
  7. package/dist/cjs/albo/types/alboCalendar.js +51 -0
  8. package/dist/cjs/albo/types/alboCommon.js +55 -0
  9. package/dist/cjs/albo/types/alboInformation.js +136 -0
  10. package/dist/cjs/albo/types/alboMenu.js +92 -0
  11. package/dist/cjs/albo/types/alboQuestionnaire.js +229 -0
  12. package/dist/cjs/albo/types/alboSharedItem.js +137 -0
  13. package/dist/cjs/albo/types/alboSystem.js +103 -0
  14. package/dist/cjs/albo/types/alboUniversalForm.js +51 -0
  15. package/dist/cjs/common/dom.js +137 -0
  16. package/dist/cjs/common/utils.js +29 -0
  17. package/dist/cjs/constants.js +127 -0
  18. package/dist/cjs/core/request.js +39 -0
  19. package/dist/cjs/cubics/client.js +49 -0
  20. package/dist/cjs/cubics/index.js +22 -0
  21. package/dist/cjs/cubics/parser/cubics.js +103 -0
  22. package/dist/cjs/cubics/types/cubics.js +90 -0
  23. package/dist/cjs/errors.js +55 -0
  24. package/dist/cjs/index.js +50 -0
  25. package/dist/cjs/manabo/client.js +135 -0
  26. package/dist/cjs/manabo/index.js +44 -0
  27. package/dist/cjs/manabo/parser/manaboClass.js +386 -0
  28. package/dist/cjs/manabo/parser/manaboEntry.js +38 -0
  29. package/dist/cjs/manabo/parser/manaboMail.js +153 -0
  30. package/dist/cjs/manabo/parser/manaboNews.js +26 -0
  31. package/dist/cjs/manabo/parser/manaboTimetable.js +93 -0
  32. package/dist/cjs/manabo/types/manaboClass.js +223 -0
  33. package/dist/cjs/manabo/types/manaboEntry.js +43 -0
  34. package/dist/cjs/manabo/types/manaboMail.js +117 -0
  35. package/dist/cjs/manabo/types/manaboNews.js +20 -0
  36. package/dist/cjs/manabo/types/manaboTimetable.js +79 -0
  37. package/dist/cjs/package.json +1 -0
  38. package/dist/cjs/shib/builder.js +239 -0
  39. package/dist/cjs/shib/index.js +32 -0
  40. package/dist/cjs/shib/parser/shibLogin.js +138 -0
  41. package/dist/cjs/shib/parser/shibUser.js +51 -0
  42. package/dist/cjs/shib/types/common.js +2 -0
  43. package/dist/cjs/shib/types/shibLogin.js +92 -0
  44. package/dist/cjs/shib/types/shibUser.js +44 -0
  45. package/dist/cjs/transports/fetch.js +84 -0
  46. package/dist/cjs/types.js +9 -0
  47. package/dist/esm/albo/client.d.ts +80 -0
  48. package/dist/esm/albo/client.d.ts.map +1 -0
  49. package/dist/esm/albo/client.js +129 -0
  50. package/dist/esm/albo/index.d.ts +12 -0
  51. package/dist/esm/albo/index.d.ts.map +1 -0
  52. package/dist/esm/albo/index.js +11 -0
  53. package/dist/esm/albo/parser/albo.d.ts +69 -0
  54. package/dist/esm/albo/parser/albo.d.ts.map +1 -0
  55. package/dist/esm/albo/parser/albo.js +84 -0
  56. package/dist/esm/albo/types/albo.d.ts +460 -0
  57. package/dist/esm/albo/types/albo.d.ts.map +1 -0
  58. package/dist/esm/albo/types/albo.js +348 -0
  59. package/dist/esm/albo/types/alboCalendar.d.ts +58 -0
  60. package/dist/esm/albo/types/alboCalendar.d.ts.map +1 -0
  61. package/dist/esm/albo/types/alboCalendar.js +48 -0
  62. package/dist/esm/albo/types/alboCommon.d.ts +52 -0
  63. package/dist/esm/albo/types/alboCommon.d.ts.map +1 -0
  64. package/dist/esm/albo/types/alboCommon.js +51 -0
  65. package/dist/esm/albo/types/alboInformation.d.ts +214 -0
  66. package/dist/esm/albo/types/alboInformation.d.ts.map +1 -0
  67. package/dist/esm/albo/types/alboInformation.js +133 -0
  68. package/dist/esm/albo/types/alboMenu.d.ts +114 -0
  69. package/dist/esm/albo/types/alboMenu.d.ts.map +1 -0
  70. package/dist/esm/albo/types/alboMenu.js +89 -0
  71. package/dist/esm/albo/types/alboQuestionnaire.d.ts +442 -0
  72. package/dist/esm/albo/types/alboQuestionnaire.d.ts.map +1 -0
  73. package/dist/esm/albo/types/alboQuestionnaire.js +226 -0
  74. package/dist/esm/albo/types/alboSharedItem.d.ts +205 -0
  75. package/dist/esm/albo/types/alboSharedItem.d.ts.map +1 -0
  76. package/dist/esm/albo/types/alboSharedItem.js +134 -0
  77. package/dist/esm/albo/types/alboSystem.d.ts +129 -0
  78. package/dist/esm/albo/types/alboSystem.d.ts.map +1 -0
  79. package/dist/esm/albo/types/alboSystem.js +100 -0
  80. package/dist/esm/albo/types/alboUniversalForm.d.ts +63 -0
  81. package/dist/esm/albo/types/alboUniversalForm.d.ts.map +1 -0
  82. package/dist/esm/albo/types/alboUniversalForm.js +48 -0
  83. package/dist/esm/common/dom.d.ts +35 -0
  84. package/dist/esm/common/dom.d.ts.map +1 -0
  85. package/dist/esm/common/dom.js +120 -0
  86. package/dist/esm/common/utils.d.ts +15 -0
  87. package/dist/esm/common/utils.d.ts.map +1 -0
  88. package/dist/esm/common/utils.js +22 -0
  89. package/dist/esm/constants.d.ts +113 -0
  90. package/dist/esm/constants.d.ts.map +1 -0
  91. package/dist/esm/constants.js +124 -0
  92. package/dist/esm/core/request.d.ts +29 -0
  93. package/dist/esm/core/request.d.ts.map +1 -0
  94. package/dist/esm/core/request.js +33 -0
  95. package/dist/esm/cubics/client.d.ts +13 -0
  96. package/dist/esm/cubics/client.d.ts.map +1 -0
  97. package/dist/esm/cubics/client.js +45 -0
  98. package/dist/esm/cubics/index.d.ts +4 -0
  99. package/dist/esm/cubics/index.d.ts.map +1 -0
  100. package/dist/esm/cubics/index.js +3 -0
  101. package/dist/esm/cubics/parser/cubics.d.ts +8 -0
  102. package/dist/esm/cubics/parser/cubics.d.ts.map +1 -0
  103. package/dist/esm/cubics/parser/cubics.js +99 -0
  104. package/dist/esm/cubics/types/cubics.d.ts +94 -0
  105. package/dist/esm/cubics/types/cubics.d.ts.map +1 -0
  106. package/dist/esm/cubics/types/cubics.js +87 -0
  107. package/dist/esm/errors.d.ts +46 -0
  108. package/dist/esm/errors.d.ts.map +1 -0
  109. package/dist/esm/errors.js +46 -0
  110. package/dist/esm/index.d.ts +19 -0
  111. package/dist/esm/index.d.ts.map +1 -0
  112. package/dist/esm/index.js +25 -0
  113. package/dist/esm/manabo/client.d.ts +75 -0
  114. package/dist/esm/manabo/client.d.ts.map +1 -0
  115. package/dist/esm/manabo/client.js +131 -0
  116. package/dist/esm/manabo/index.d.ts +12 -0
  117. package/dist/esm/manabo/index.d.ts.map +1 -0
  118. package/dist/esm/manabo/index.js +11 -0
  119. package/dist/esm/manabo/parser/manaboClass.d.ts +9 -0
  120. package/dist/esm/manabo/parser/manaboClass.d.ts.map +1 -0
  121. package/dist/esm/manabo/parser/manaboClass.js +377 -0
  122. package/dist/esm/manabo/parser/manaboEntry.d.ts +8 -0
  123. package/dist/esm/manabo/parser/manaboEntry.d.ts.map +1 -0
  124. package/dist/esm/manabo/parser/manaboEntry.js +33 -0
  125. package/dist/esm/manabo/parser/manaboMail.d.ts +8 -0
  126. package/dist/esm/manabo/parser/manaboMail.d.ts.map +1 -0
  127. package/dist/esm/manabo/parser/manaboMail.js +145 -0
  128. package/dist/esm/manabo/parser/manaboNews.d.ts +7 -0
  129. package/dist/esm/manabo/parser/manaboNews.d.ts.map +1 -0
  130. package/dist/esm/manabo/parser/manaboNews.js +22 -0
  131. package/dist/esm/manabo/parser/manaboTimetable.d.ts +4 -0
  132. package/dist/esm/manabo/parser/manaboTimetable.d.ts.map +1 -0
  133. package/dist/esm/manabo/parser/manaboTimetable.js +89 -0
  134. package/dist/esm/manabo/types/manaboClass.d.ts +294 -0
  135. package/dist/esm/manabo/types/manaboClass.d.ts.map +1 -0
  136. package/dist/esm/manabo/types/manaboClass.js +220 -0
  137. package/dist/esm/manabo/types/manaboEntry.d.ts +24 -0
  138. package/dist/esm/manabo/types/manaboEntry.d.ts.map +1 -0
  139. package/dist/esm/manabo/types/manaboEntry.js +40 -0
  140. package/dist/esm/manabo/types/manaboMail.d.ts +103 -0
  141. package/dist/esm/manabo/types/manaboMail.d.ts.map +1 -0
  142. package/dist/esm/manabo/types/manaboMail.js +114 -0
  143. package/dist/esm/manabo/types/manaboNews.d.ts +15 -0
  144. package/dist/esm/manabo/types/manaboNews.d.ts.map +1 -0
  145. package/dist/esm/manabo/types/manaboNews.js +17 -0
  146. package/dist/esm/manabo/types/manaboTimetable.d.ts +88 -0
  147. package/dist/esm/manabo/types/manaboTimetable.d.ts.map +1 -0
  148. package/dist/esm/manabo/types/manaboTimetable.js +76 -0
  149. package/dist/esm/package.json +1 -0
  150. package/dist/esm/shib/builder.d.ts +154 -0
  151. package/dist/esm/shib/builder.d.ts.map +1 -0
  152. package/dist/esm/shib/builder.js +212 -0
  153. package/dist/esm/shib/index.d.ts +15 -0
  154. package/dist/esm/shib/index.d.ts.map +1 -0
  155. package/dist/esm/shib/index.js +14 -0
  156. package/dist/esm/shib/parser/shibLogin.d.ts +47 -0
  157. package/dist/esm/shib/parser/shibLogin.d.ts.map +1 -0
  158. package/dist/esm/shib/parser/shibLogin.js +127 -0
  159. package/dist/esm/shib/parser/shibUser.d.ts +11 -0
  160. package/dist/esm/shib/parser/shibUser.d.ts.map +1 -0
  161. package/dist/esm/shib/parser/shibUser.js +46 -0
  162. package/dist/esm/shib/types/common.d.ts +20 -0
  163. package/dist/esm/shib/types/common.d.ts.map +1 -0
  164. package/dist/esm/shib/types/common.js +1 -0
  165. package/dist/esm/shib/types/shibLogin.d.ts +62 -0
  166. package/dist/esm/shib/types/shibLogin.d.ts.map +1 -0
  167. package/dist/esm/shib/types/shibLogin.js +89 -0
  168. package/dist/esm/shib/types/shibUser.d.ts +36 -0
  169. package/dist/esm/shib/types/shibUser.d.ts.map +1 -0
  170. package/dist/esm/shib/types/shibUser.js +41 -0
  171. package/dist/esm/transports/fetch.d.ts +36 -0
  172. package/dist/esm/transports/fetch.d.ts.map +1 -0
  173. package/dist/esm/transports/fetch.js +80 -0
  174. package/dist/esm/types.d.ts +71 -0
  175. package/dist/esm/types.d.ts.map +1 -0
  176. package/dist/esm/types.js +8 -0
  177. package/package.json +72 -0
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matches = exports.getChildrenElements = exports.filterElements = exports.isElement = exports.previousSiblingElement = exports.nextSiblingElement = exports.closest = exports.elementHasClass = exports.getInnerHtml = exports.getTextContent = exports.getAttribute = exports.queryOne = exports.queryAll = exports.loadDocument = void 0;
4
+ /**
5
+ * HTML パース用の薄い DOM ヘルパ層。
6
+ *
7
+ * `htmlparser2`(`parseDocument`)でパースし、`css-select` でセレクタ検索、
8
+ * `domutils` でノード走査する。各 parser はこのヘルパ経由で DOM を扱う。
9
+ */
10
+ const htmlparser2_1 = require("htmlparser2");
11
+ const css_select_1 = require("css-select");
12
+ const domutils_1 = require("domutils");
13
+ const toArray = (root) => {
14
+ if (!root) {
15
+ return [];
16
+ }
17
+ if (Array.isArray(root)) {
18
+ return root;
19
+ }
20
+ if ("children" in root && Array.isArray(root.children)) {
21
+ return root.children;
22
+ }
23
+ return [root];
24
+ };
25
+ /** HTML 文字列を Document に変換する */
26
+ const loadDocument = (html) => (0, htmlparser2_1.parseDocument)(html);
27
+ exports.loadDocument = loadDocument;
28
+ /** セレクタに一致する全 Element を返す */
29
+ const queryAll = (selector, root) => (0, css_select_1.selectAll)(selector, toArray(root));
30
+ exports.queryAll = queryAll;
31
+ /** セレクタに一致する最初の Element を返す(無ければ null) */
32
+ const queryOne = (selector, root) => (0, css_select_1.selectOne)(selector, toArray(root));
33
+ exports.queryOne = queryOne;
34
+ /** 属性値を取得する(無ければ null) */
35
+ const getAttribute = (element, name) => {
36
+ if (!element) {
37
+ return null;
38
+ }
39
+ const value = (0, domutils_1.getAttributeValue)(element, name);
40
+ return typeof value === "string" ? value : null;
41
+ };
42
+ exports.getAttribute = getAttribute;
43
+ /** ノード配下のテキストを連結して返す */
44
+ const getTextContent = (node) => {
45
+ if (!node) {
46
+ return "";
47
+ }
48
+ return (0, domutils_1.textContent)(node);
49
+ };
50
+ exports.getTextContent = getTextContent;
51
+ const decodeNumericEntities = (value) => value
52
+ .replace(/&#x([0-9a-fA-F]+);/g, (match, hex) => {
53
+ const codePoint = Number.parseInt(hex, 16);
54
+ return Number.isNaN(codePoint) ? match : String.fromCodePoint(codePoint);
55
+ })
56
+ .replace(/&#([0-9]+);/g, (match, dec) => {
57
+ const codePoint = Number.parseInt(dec, 10);
58
+ return Number.isNaN(codePoint) ? match : String.fromCodePoint(codePoint);
59
+ });
60
+ /**
61
+ * 要素の innerHTML を返す。数値文字参照の復号・改行正規化・` ` 復元・
62
+ * 値のない `alt` の補完を行い、後段のパースを安定させる。
63
+ */
64
+ const getInnerHtml = (element) => {
65
+ if (!element) {
66
+ return "";
67
+ }
68
+ const inner = (0, domutils_1.getInnerHTML)(element);
69
+ const decoded = decodeNumericEntities(inner);
70
+ const normalised = decoded.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
71
+ const withNbsp = normalised.replace(/\u00a0/g, " ");
72
+ return withNbsp.replace(/\salt(?!\s*=)(?=[\s/>])/g, ' alt=""');
73
+ };
74
+ exports.getInnerHtml = getInnerHtml;
75
+ /** 要素が指定クラスを持つか */
76
+ const elementHasClass = (element, className) => {
77
+ if (!element) {
78
+ return false;
79
+ }
80
+ const classAttr = (0, exports.getAttribute)(element, "class");
81
+ if (!classAttr) {
82
+ return false;
83
+ }
84
+ return classAttr.split(/\s+/).includes(className);
85
+ };
86
+ exports.elementHasClass = elementHasClass;
87
+ /** 自身から祖先方向へ辿り、セレクタに最初に一致する要素を返す */
88
+ const closest = (element, selector) => {
89
+ let current = element;
90
+ while (current) {
91
+ if ((0, css_select_1.is)(current, selector)) {
92
+ return current;
93
+ }
94
+ const parent = (0, domutils_1.getParent)(current);
95
+ current = parent && (0, domutils_1.isTag)(parent) ? parent : null;
96
+ }
97
+ return null;
98
+ };
99
+ exports.closest = closest;
100
+ /** 次の兄弟要素を返す */
101
+ const nextSiblingElement = (element) => {
102
+ if (!element) {
103
+ return null;
104
+ }
105
+ return (0, domutils_1.nextElementSibling)(element) ?? null;
106
+ };
107
+ exports.nextSiblingElement = nextSiblingElement;
108
+ /** 前の兄弟要素を返す */
109
+ const previousSiblingElement = (element) => {
110
+ if (!element) {
111
+ return null;
112
+ }
113
+ return (0, domutils_1.prevElementSibling)(element) ?? null;
114
+ };
115
+ exports.previousSiblingElement = previousSiblingElement;
116
+ /** ノードが Element(タグ)か */
117
+ const isElement = (node) => !!node && (0, domutils_1.isTag)(node);
118
+ exports.isElement = isElement;
119
+ /** ノード配列から Element だけを抽出する */
120
+ const filterElements = (nodes) => nodes.filter((node) => (0, domutils_1.isTag)(node));
121
+ exports.filterElements = filterElements;
122
+ /** 子ノードのうち Element だけを返す */
123
+ const getChildrenElements = (element) => {
124
+ if (!element) {
125
+ return [];
126
+ }
127
+ return (0, exports.filterElements)(element.children ?? []);
128
+ };
129
+ exports.getChildrenElements = getChildrenElements;
130
+ /** 要素がセレクタに一致するか */
131
+ const matches = (element, selector) => {
132
+ if (!element) {
133
+ return false;
134
+ }
135
+ return (0, css_select_1.is)(element, selector);
136
+ };
137
+ exports.matches = matches;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formEncodeArray = exports.formEncode = exports.extractFirstQuotedValue = exports.normalizeWhitespace = void 0;
4
+ /** 連続する空白を1つに畳み、前後を trim する */
5
+ const normalizeWhitespace = (value) => value.replace(/\s+/g, " ").trim();
6
+ exports.normalizeWhitespace = normalizeWhitespace;
7
+ /** 文字列中の最初のシングルクォート内の値を返す(onclick 引数の抽出などに使う) */
8
+ const extractFirstQuotedValue = (raw) => {
9
+ if (!raw) {
10
+ return null;
11
+ }
12
+ const match = raw.match(/'([^']+)'/);
13
+ return match ? (match[1] ?? null) : null;
14
+ };
15
+ exports.extractFirstQuotedValue = extractFirstQuotedValue;
16
+ /**
17
+ * `{ key: value }` を form-urlencoded ボディに変換する。
18
+ * shib のフォーム POST(loginuserpass 等)のボディ組み立てに使う。
19
+ */
20
+ const formEncode = (params) => Object.entries(params)
21
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
22
+ .join("&");
23
+ exports.formEncode = formEncode;
24
+ /**
25
+ * `[key, value]` ペア配列を form-urlencoded ボディに変換する(キー重複対応)。
26
+ * `Fido2DeviceAdd` のように同名キー(`procchk` を 2 回)を送る必要がある場合に使う。
27
+ */
28
+ const formEncodeArray = (params) => params.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
29
+ exports.formEncodeArray = formEncodeArray;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ /**
3
+ * ポータルのデータ系エンドポイント URL と運用値。
4
+ *
5
+ * 運用値(リトライ回数・タイムアウト)は旧 UMEBO の実運用で得た値。根拠なく変えない。
6
+ * ※ Shibboleth 認証 URL やレート制限・セッション失効時間は SDK には持たない
7
+ * (認証・レート制限は利用側 = umebo の責務)。
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.SERVICES = exports.SHIB_URLS = exports.MANABO_URLS = exports.ALBO_DEFAULT_CALENDAR_SOURCE_UUID = exports.ALBO_URLS = exports.CUBICS_URLS = exports.CUBICS_RETRY_DELAY_RANDOM_MS = exports.CUBICS_RETRY_DELAY_MS = exports.CUBICS_RETRY_COUNT = exports.HTTP_TIMEOUT_MS = void 0;
11
+ /** HTTP タイムアウト(ms) */
12
+ exports.HTTP_TIMEOUT_MS = 10_000;
13
+ /** CUBICS セッション不安定対策のリトライ回数 */
14
+ exports.CUBICS_RETRY_COUNT = 3;
15
+ /** CUBICS リトライの固定遅延(ms) */
16
+ exports.CUBICS_RETRY_DELAY_MS = 200;
17
+ /** CUBICS リトライのランダム加算遅延の上限(ms) */
18
+ exports.CUBICS_RETRY_DELAY_RANDOM_MS = 300;
19
+ // ============================================
20
+ // CUBICS(教務システム)— 画面遷移型 HTML
21
+ // ============================================
22
+ exports.CUBICS_URLS = {
23
+ /** ベース URL */
24
+ base: "https://cubics-as.chukyo-u.ac.jp",
25
+ };
26
+ // ============================================
27
+ // Albo(ポータルサイト)— 3システムで唯一の JSON REST API
28
+ // ============================================
29
+ exports.ALBO_URLS = {
30
+ /** ベース URL */
31
+ base: "https://albo.chukyo-u.ac.jp",
32
+ /** SAML ログイン起点 */
33
+ login: "https://albo.chukyo-u.ac.jp/api/saml/login",
34
+ /** 認証完了確認(ここへの到達でログイン成立) */
35
+ dashboard: "https://albo.chukyo-u.ac.jp/dashboard",
36
+ };
37
+ /**
38
+ * 学年暦(学部)カレンダーソース UUID。`GET /api/calendar-source/` が返す一覧の1件で、
39
+ * 年度更新等で値が変わり得る。`AlboClient#getCalendar` はこれをデフォルト値として使うが、
40
+ * 呼び出し側は `getCalendar({ calendarSourceUuid: ... })` で任意のソース(学部/大学院など)
41
+ * に差し替えられる。差し替え先の UUID は `getCalendarSource()` の結果から取得できる。
42
+ */
43
+ exports.ALBO_DEFAULT_CALENDAR_SOURCE_UUID = "ac304d66-b0a8-11f0-afed-06347f3ce845";
44
+ // ============================================
45
+ // MaNaBo(学習管理システム)— API なし、glexa_ajax_* POST で HTML 断片
46
+ // ============================================
47
+ exports.MANABO_URLS = {
48
+ /** ベース URL */
49
+ base: "https://manabo.cnc.chukyo-u.ac.jp",
50
+ /** Shibboleth 認証 URL */
51
+ auth: "https://manabo.cnc.chukyo-u.ac.jp/auth/shibboleth/",
52
+ };
53
+ // ============================================
54
+ // Shibboleth(共通認証 / CloudLink IdP + ACE User ポータル)
55
+ // ============================================
56
+ /**
57
+ * Shibboleth 認証系エンドポイント。
58
+ *
59
+ * ※ この SDK は認証フローを「実行」しない。`src/shib` のビルダ/パーサが、
60
+ * 各ステップのリクエスト記述子の組み立てと、レスポンスの構造化に使う。
61
+ * HTTP 実行・Cookie 管理・リダイレクト追従・パスキー暗号処理は呼び出し側の責務。
62
+ * 値は umebo の実運用 URL(acl/constants.ts)に一致。
63
+ */
64
+ exports.SHIB_URLS = {
65
+ /** Shibboleth オリジン(フォーム POST の Origin ヘッダに使う) */
66
+ origin: "https://shib.chukyo-u.ac.jp",
67
+ /** WebAuthn RP ID */
68
+ rpId: "shib.chukyo-u.ac.jp",
69
+ /** ACE User SP ログイン起点 */
70
+ clspLogin: "https://shib.chukyo-u.ac.jp/clsp/login",
71
+ /** CLSP SAML ログイン起点(パスキー登録フローの起点) */
72
+ clspSamlLogin: "https://shib.chukyo-u.ac.jp/clsp/saml/login",
73
+ /** 認証方式チェック(Password / OTP / Passkey の可否) */
74
+ checktype: "https://shib.chukyo-u.ac.jp/cloudlink/module.php/cloudlink/checktype.php",
75
+ /** ログインフォーム POST(authtype=0 PW / 2 OTP / 3 Passkey) */
76
+ cloudlinkLoginForm: "https://shib.chukyo-u.ac.jp/cloudlink/module.php/cloudlink/loginuserpass.php",
77
+ /** ログインフロー用 WebAuthn API(start/finish-authentication) */
78
+ webauthn: "https://shib.chukyo-u.ac.jp/cloudlink/module.php/cloudlink/webauthn.php",
79
+ /** ACE User メニュー */
80
+ userMenu: "https://shib.chukyo-u.ac.jp/User/Menu",
81
+ /** ACE User メニュー選択 */
82
+ userMenuSelect: "https://shib.chukyo-u.ac.jp/User/MenuSelect",
83
+ /** ACE User タイムゾーン・言語設定完了 */
84
+ userTimeZoneLangEnd: "https://shib.chukyo-u.ac.jp/User/TimeZoneLangEnd",
85
+ /** ACE User FIDO2 デバイス追加ページ */
86
+ userFido2DeviceAdd: "https://shib.chukyo-u.ac.jp/User/Fido2DeviceAdd",
87
+ /** ACE User FIDO2 デバイス追加完了 */
88
+ userFido2DeviceAddEnd: "https://shib.chukyo-u.ac.jp/User/Fido2DeviceAddEnd",
89
+ /** ACE User FIDO2 デバイス一覧 */
90
+ userFido2DeviceList: "https://shib.chukyo-u.ac.jp/User/Fido2DeviceList",
91
+ /** ACE User FIDO2 デバイス削除完了 */
92
+ userFido2DeviceDelEnd: "https://shib.chukyo-u.ac.jp/User/Fido2DeviceDelEnd",
93
+ /** ACE User 登録フロー用 WebAuthn API(start/finish-registration) */
94
+ userWebauthn: "https://shib.chukyo-u.ac.jp/User/webauthn",
95
+ /** OTP 認証方式選択チェック */
96
+ userSelectAuthTypeCheck: "https://shib.chukyo-u.ac.jp/User/SelectAuthTypeCheck",
97
+ /** OTP メールアドレス入力チェック */
98
+ userInputMailAddresCheck: "https://shib.chukyo-u.ac.jp/User/InputMailAddresCheck",
99
+ /** OTP 仮パスワード入力チェック */
100
+ userInputTemporaryOtpCheck: "https://shib.chukyo-u.ac.jp/User/InputTemporaryOtpCheck",
101
+ /** OTP アプリインストール導線表示チェック */
102
+ userDisplayInstallAppliLinkCheck: "https://shib.chukyo-u.ac.jp/User/DisplayInstallAppliLinkCheck",
103
+ /** OTP(PC 用)入力チェック */
104
+ userInputOtpForPCCheck: "https://shib.chukyo-u.ac.jp/User/InputOtpForPCCheck",
105
+ /** OTP 仮パスワード入力 */
106
+ userInputTemporaryOtp: "https://shib.chukyo-u.ac.jp/User/InputTemporaryOtp",
107
+ /** ACE User ログアウト(SLO 連鎖の起点) */
108
+ userLogout: "https://shib.chukyo-u.ac.jp/User/Logout",
109
+ };
110
+ /** サービス記述子(enterUrl / goalUrl)。SessionProvider に渡す。 */
111
+ exports.SERVICES = {
112
+ cubics: {
113
+ key: "cubics",
114
+ enterUrl: `${exports.CUBICS_URLS.base}/unias/UnSSOLoginControl2`,
115
+ goalUrl: `${exports.CUBICS_URLS.base}/unias/UnSSOLoginControl2`,
116
+ },
117
+ albo: {
118
+ key: "albo",
119
+ enterUrl: exports.ALBO_URLS.login,
120
+ goalUrl: exports.ALBO_URLS.dashboard,
121
+ },
122
+ manabo: {
123
+ key: "manabo",
124
+ enterUrl: exports.MANABO_URLS.auth,
125
+ goalUrl: exports.MANABO_URLS.auth,
126
+ },
127
+ };
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unwrap = exports.portalRequestText = exports.portalRequest = void 0;
4
+ const errors_1 = require("../errors");
5
+ /** Cookie を(あれば)注入して1回リクエストする。 */
6
+ const portalRequest = async (ctx, service, init) => {
7
+ const headers = {
8
+ "Accept-Language": "ja",
9
+ ...init.headers,
10
+ };
11
+ if (ctx.session) {
12
+ headers["cookie"] = await ctx.session.getCookieHeader(service);
13
+ }
14
+ return ctx.transport.request({
15
+ method: init.method,
16
+ url: init.url,
17
+ headers,
18
+ ...(init.body != null ? { body: init.body } : {}),
19
+ ...(init.signal ? { signal: init.signal } : {}),
20
+ });
21
+ };
22
+ exports.portalRequest = portalRequest;
23
+ /** Cookie を注入してボディ文字列だけを返す。 */
24
+ const portalRequestText = async (ctx, service, init) => {
25
+ const res = await (0, exports.portalRequest)(ctx, service, init);
26
+ return res.body;
27
+ };
28
+ exports.portalRequestText = portalRequestText;
29
+ /**
30
+ * parser の {@link ZodSafeParseResult} を DTO に unwrap する。失敗時は {@link ParseError}。
31
+ * 各クライアントメソッドの戻り値を「生 DTO」に統一するための共通処理。
32
+ */
33
+ const unwrap = (result) => {
34
+ if (!result.success) {
35
+ throw new errors_1.ParseError({ cause: result.error });
36
+ }
37
+ return result.data;
38
+ };
39
+ exports.unwrap = unwrap;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CubicsClient = void 0;
4
+ /**
5
+ * CUBICS クライアント。画面遷移型でセッションが不安定なため、無効を検知したら
6
+ * セッションを invalidate してランダム遅延を挟み最大 {@link CUBICS_RETRY_COUNT} 回リトライする。
7
+ */
8
+ const constants_1 = require("../constants");
9
+ const errors_1 = require("../errors");
10
+ const request_1 = require("../core/request");
11
+ const cubics_1 = require("./parser/cubics");
12
+ const INVALID_TITLES = ["<title>Missing cookie</title>", "<title>クッキーが見つかりません</title>"];
13
+ class CubicsClient {
14
+ ctx;
15
+ constructor(ctx) {
16
+ this.ctx = ctx;
17
+ }
18
+ /** セッション無効時は base 外へのリダイレクト、または "Missing cookie" タイトルが返る */
19
+ isSessionValid(res) {
20
+ if (!res.url.startsWith(constants_1.CUBICS_URLS.base)) {
21
+ return false;
22
+ }
23
+ return !INVALID_TITLES.some((title) => res.body.includes(title));
24
+ }
25
+ async waitForRetryDelay() {
26
+ const delay = constants_1.CUBICS_RETRY_DELAY_MS + Math.floor(Math.random() * constants_1.CUBICS_RETRY_DELAY_RANDOM_MS);
27
+ await new Promise((resolve) => setTimeout(resolve, delay));
28
+ }
29
+ async fetchText(path) {
30
+ for (let attempt = 0; attempt <= constants_1.CUBICS_RETRY_COUNT; attempt++) {
31
+ const res = await (0, request_1.portalRequest)(this.ctx, constants_1.SERVICES.cubics, {
32
+ method: "GET",
33
+ url: `${constants_1.CUBICS_URLS.base}${path}`,
34
+ });
35
+ if (this.isSessionValid(res)) {
36
+ return res.body;
37
+ }
38
+ this.ctx.session?.invalidate(constants_1.SERVICES.cubics.key);
39
+ await this.waitForRetryDelay();
40
+ }
41
+ throw new errors_1.ExpiredSessionError();
42
+ }
43
+ /** 週間時間割を取得する */
44
+ async getTimetable() {
45
+ const html = await this.fetchText("/unias/UnSSOLoginControl2?REQ_ACTION_DO=/ARF010.do&REQ_PRFR_MNU_ID=MNUIDSTD0103");
46
+ return (0, request_1.unwrap)((0, cubics_1.parseCubicsAsTimetable)(html));
47
+ }
48
+ }
49
+ exports.CubicsClient = CubicsClient;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.CubicsClient = exports.parseCubicsAsTimetable = void 0;
18
+ var cubics_1 = require("./parser/cubics");
19
+ Object.defineProperty(exports, "parseCubicsAsTimetable", { enumerable: true, get: function () { return cubics_1.parseCubicsAsTimetable; } });
20
+ __exportStar(require("./types/cubics"), exports);
21
+ var client_1 = require("./client");
22
+ Object.defineProperty(exports, "CubicsClient", { enumerable: true, get: function () { return client_1.CubicsClient; } });
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCubicsAsTimetable = void 0;
4
+ const dom_1 = require("../../common/dom");
5
+ const utils_1 = require("../../common/utils");
6
+ const cubics_1 = require("../types/cubics");
7
+ const BR_PATTERN = /<br\s*\/?\s*>/gi;
8
+ const emptyOrNull = (value) => {
9
+ if (value === null || value === undefined) {
10
+ return null;
11
+ }
12
+ return value.length > 0 ? value : null;
13
+ };
14
+ const getInputValue = (selector, root) => emptyOrNull((0, dom_1.getAttribute)((0, dom_1.queryOne)(selector, root), "value"));
15
+ const parseCubicsAsTimetable = (html) => {
16
+ const document = (0, dom_1.loadDocument)(html);
17
+ // --- 学生情報(table.output) ---
18
+ const studentTable = (0, dom_1.queryOne)("table.output", document);
19
+ const studentRows = studentTable ? (0, dom_1.queryAll)("tr", studentTable) : [];
20
+ const row1Cells = studentRows[0] ? (0, dom_1.queryAll)("td", studentRows[0]) : [];
21
+ const row2Cells = studentRows[1] ? (0, dom_1.queryAll)("td", studentRows[1]) : [];
22
+ const row3Cells = studentRows[2] ? (0, dom_1.queryAll)("td", studentRows[2]) : [];
23
+ const row4Cells = studentRows[3] ? (0, dom_1.queryAll)("td", studentRows[3]) : [];
24
+ const getCellText = (cells, index) => (0, utils_1.normalizeWhitespace)((0, dom_1.getTextContent)(cells[index] ?? null));
25
+ // 氏名セルは "日本語氏名<BR />(ALPHABET NAME)" 形式。<BR> で分割し、後半の括弧を除去する。
26
+ const nameCellHtml = (0, dom_1.getInnerHtml)(row1Cells[1] ?? null);
27
+ const nameParts = nameCellHtml.split(BR_PATTERN);
28
+ const name = (0, utils_1.normalizeWhitespace)((0, dom_1.getTextContent)((0, dom_1.loadDocument)(nameParts[0] ?? "")));
29
+ const alphabetRaw = (0, utils_1.normalizeWhitespace)((0, dom_1.getTextContent)((0, dom_1.loadDocument)(nameParts[1] ?? "")));
30
+ const alphabetInner = alphabetRaw.replace(/^\(/, "").replace(/\)$/, "");
31
+ const nameAlphabet = emptyOrNull((0, utils_1.normalizeWhitespace)(alphabetInner));
32
+ const student = {
33
+ id: getCellText(row1Cells, 0),
34
+ name,
35
+ nameAlphabet,
36
+ division: getCellText(row2Cells, 0),
37
+ affiliation: getCellText(row2Cells, 1),
38
+ status: getCellText(row2Cells, 2),
39
+ className: getCellText(row2Cells, 3),
40
+ faculty: getCellText(row3Cells, 0),
41
+ department: getCellText(row3Cells, 1),
42
+ course: getCellText(row3Cells, 2),
43
+ address: getCellText(row4Cells, 0),
44
+ };
45
+ // --- 表示期間 ---
46
+ const periodInput = (0, dom_1.queryOne)("input[name='lblSpcfProd']", document);
47
+ const periodRange = (0, utils_1.normalizeWhitespace)((0, dom_1.getAttribute)(periodInput, "value") ?? "");
48
+ // --- 時間割表(table.output_curriculum) ---
49
+ const curriculumTable = (0, dom_1.queryOne)("table.output_curriculum", document);
50
+ const headerRow = curriculumTable ? (0, dom_1.queryOne)("tr", curriculumTable) : null;
51
+ const headerCells = headerRow ? (0, dom_1.queryAll)("th", headerRow).slice(1) : [];
52
+ const days = headerCells.map((element) => {
53
+ // input[name$=".lblLsnDt"] の value は "月<BR/>06/16"(属性値なのでエンティティは復号済み)。
54
+ const raw = (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name$=".lblLsnDt"]', element), "value");
55
+ const parts = (raw ?? "").split(BR_PATTERN).map((part) => (0, utils_1.normalizeWhitespace)(part));
56
+ return {
57
+ weekday: parts[0] ?? "",
58
+ date: parts[1] ?? "",
59
+ };
60
+ });
61
+ const periodRows = curriculumTable ? (0, dom_1.queryAll)("tr", curriculumTable).slice(1) : [];
62
+ const periods = periodRows.map((row) => {
63
+ const periodLabel = (0, utils_1.normalizeWhitespace)((0, dom_1.getTextContent)((0, dom_1.queryOne)("th", row)));
64
+ const cells = (0, dom_1.queryAll)("td", row);
65
+ const slots = cells.map((cell) => {
66
+ const lessonCode = getInputValue('input[name$=".hdnLsnCd1"]', cell);
67
+ const lessonYear = getInputValue('input[name$=".hdnLsnOpcFcy1"]', cell);
68
+ const termCode = getInputValue('input[name$=".hdnTacTrmCd1"]', cell);
69
+ const timetableCode = getInputValue('input[name$=".hdnTmtxCd"]', cell);
70
+ const lessonDate = getInputValue('input[name$=".hdnOpcDt"]', cell);
71
+ // 科目名: hdnSbjKnjNm(完全名称)を優先し、空なら lblSbjKnjNm(表示名称)へフォールバック。
72
+ const subject = getInputValue('input[name$=".hdnSbjKnjNm"]', cell) ?? getInputValue('input[name$=".lblSbjKnjNm"]', cell);
73
+ // 教室名: hdnClrNm の <BR/> を半角スペースへ。空なら lblClrNm へフォールバック。
74
+ const classroomFull = (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name$=".hdnClrNm"]', cell), "value");
75
+ const classroomNormalized = emptyOrNull((0, utils_1.normalizeWhitespace)((classroomFull ?? "").replace(BR_PATTERN, " ")));
76
+ const classroom = classroomNormalized ?? getInputValue('input[name$=".lblClrNm"]', cell);
77
+ // 詳細URL: execPopupWindowOpen(...) を含む onclick の最初のシングルクォート引数。
78
+ const detailAnchor = (0, dom_1.queryAll)("a", cell).find((anchor) => ((0, dom_1.getAttribute)(anchor, "onclick") ?? "").includes("execPopupWindowOpen"));
79
+ const detailUrl = (0, utils_1.extractFirstQuotedValue)(detailAnchor ? (0, dom_1.getAttribute)(detailAnchor, "onclick") : null);
80
+ // ステータスアイコン: img の src で判定。
81
+ const iconSources = (0, dom_1.queryAll)("img", cell).map((img) => (0, dom_1.getAttribute)(img, "src") ?? "");
82
+ const isCancelled = iconSources.some((src) => src.includes("icon_kyukou"));
83
+ const isSupplementary = iconSources.some((src) => src.includes("icon_hokou"));
84
+ const isChanged = iconSources.some((src) => src.includes("icon_jyugyouhenkou"));
85
+ return {
86
+ subject,
87
+ classroom,
88
+ lessonCode,
89
+ lessonYear,
90
+ termCode,
91
+ timetableCode,
92
+ lessonDate,
93
+ detailUrl,
94
+ isCancelled,
95
+ isSupplementary,
96
+ isChanged,
97
+ };
98
+ });
99
+ return { periodLabel, slots };
100
+ });
101
+ return cubics_1.CubicsAsTimetableSchema.safeParse({ student, periodRange, days, periods });
102
+ };
103
+ exports.parseCubicsAsTimetable = parseCubicsAsTimetable;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CubicsAsTimetableSchema = exports.CubicsAsTimetableStudentSchema = exports.CubicsAsTimetableDaySchema = exports.CubicsAsTimetablePeriodSchema = exports.CubicsAsTimetableSlotSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ /** CUBICS 時間割の1コマ(空きコマは文字列フィールドが null / フラグが false) */
6
+ exports.CubicsAsTimetableSlotSchema = zod_1.z.object({
7
+ /** 科目名(正式名称) @example "情報リテラシー" */
8
+ subject: zod_1.z
9
+ .string()
10
+ .nullable()
11
+ .meta({ description: "科目名(正式名称。hdnSbjKnjNm から復元)", example: "情報リテラシー" }),
12
+ /** 教室名(複数教室は半角スペース区切り) @example "1731 1732" */
13
+ classroom: zod_1.z.string().nullable().meta({ description: "教室名(複数は半角スペース区切り)", example: "1731 1732" }),
14
+ /** 授業コード(hdnLsnCd1) @example "12345" */
15
+ lessonCode: zod_1.z.string().nullable().meta({ description: "授業コード(hdnLsnCd1)", example: "12345" }),
16
+ /** 開講年度(hdnLsnOpcFcy1) @example "2025" */
17
+ lessonYear: zod_1.z.string().nullable().meta({ description: "開講年度(hdnLsnOpcFcy1)", example: "2025" }),
18
+ /** 学期コード(hdnTacTrmCd1) @example "01" */
19
+ termCode: zod_1.z.string().nullable().meta({ description: "学期コード(hdnTacTrmCd1)", example: "01" }),
20
+ /** 時間割コード(hdnTmtxCd) @example "A1" */
21
+ timetableCode: zod_1.z.string().nullable().meta({ description: "時間割コード(hdnTmtxCd)", example: "A1" }),
22
+ /** 開講日(hdnOpcDt。yyyymmdd) @example "20250616" */
23
+ lessonDate: zod_1.z.string().nullable().meta({ description: "開講日(hdnOpcDt。yyyymmdd)", example: "20250616" }),
24
+ /** 授業詳細ポップアップの URL(onclick から抽出) @example "/unias/ARF010Popup.do?..." */
25
+ detailUrl: zod_1.z
26
+ .string()
27
+ .nullable()
28
+ .meta({ description: "授業詳細ポップアップの URL", example: "/unias/ARF010Popup.do?..." }),
29
+ /** 休講フラグ(icon_kyukou) @example false */
30
+ isCancelled: zod_1.z.boolean().meta({ description: "休講(icon_kyukou)", example: false }),
31
+ /** 補講フラグ(icon_hokou) @example false */
32
+ isSupplementary: zod_1.z.boolean().meta({ description: "補講(icon_hokou)", example: false }),
33
+ /** 授業変更フラグ(icon_jyugyouhenkou) @example false */
34
+ isChanged: zod_1.z.boolean().meta({ description: "授業変更(icon_jyugyouhenkou)", example: false }),
35
+ });
36
+ /** 1時限分の行(曜日順のコマ配列) */
37
+ exports.CubicsAsTimetablePeriodSchema = zod_1.z.object({
38
+ /** 時限ラベル @example "1時限" */
39
+ periodLabel: zod_1.z.string().meta({ description: "時限ラベル", example: "1時限" }),
40
+ /** 曜日順のスロット。空きコマは全フィールド null / false */
41
+ slots: zod_1.z.array(exports.CubicsAsTimetableSlotSchema).meta({ description: "曜日順のスロット" }),
42
+ });
43
+ /** 時間割表ヘッダの1日分 */
44
+ exports.CubicsAsTimetableDaySchema = zod_1.z.object({
45
+ /** 曜日 @example "月" */
46
+ weekday: zod_1.z.string().meta({ description: "曜日", example: "月" }),
47
+ /** 日付(MM/DD) @example "06/16" */
48
+ date: zod_1.z.string().meta({ description: "日付(MM/DD)", example: "06/16" }),
49
+ });
50
+ /** 学生情報ブロック(PII を含む) */
51
+ exports.CubicsAsTimetableStudentSchema = zod_1.z.object({
52
+ /** 学籍番号 @example "T000000" */
53
+ id: zod_1.z.string().meta({ description: "学籍番号", example: "T000000" }),
54
+ /** 氏名(日本語表記) @example "田中太郎" */
55
+ name: zod_1.z.string().meta({ description: "氏名(日本語表記)", example: "田中太郎" }),
56
+ /** 氏名(アルファベット表記。取得不可なら null) @example "TANAKA TARO" */
57
+ nameAlphabet: zod_1.z
58
+ .string()
59
+ .nullable()
60
+ .meta({ description: "氏名(アルファベット表記)", example: "TANAKA TARO" }),
61
+ /** 学生区分 @example "学部(正規)" */
62
+ division: zod_1.z.string().meta({ description: "学生区分", example: "学部(正規)" }),
63
+ /** 所属区分 @example "学部生" */
64
+ affiliation: zod_1.z.string().meta({ description: "所属区分", example: "学部生" }),
65
+ /** 学生状態 @example "在学" */
66
+ status: zod_1.z.string().meta({ description: "学生状態", example: "在学" }),
67
+ /** クラス @example "F" */
68
+ className: zod_1.z.string().meta({ description: "クラス", example: "F" }),
69
+ /** 学部 @example "工学部" */
70
+ faculty: zod_1.z.string().meta({ description: "学部", example: "工学部" }),
71
+ /** 学科 @example "情報工学科" */
72
+ department: zod_1.z.string().meta({ description: "学科", example: "情報工学科" }),
73
+ /** コース @example "メディア工学コース" */
74
+ course: zod_1.z.string().meta({ description: "コース", example: "メディア工学コース" }),
75
+ /** 住所・電話番号(固定)(携帯)の結合文字列 @example "愛知県名古屋市... 052-000-0000 090-0000-0000" */
76
+ address: zod_1.z
77
+ .string()
78
+ .meta({ description: "住所・電話番号の結合文字列", example: "愛知県名古屋市... 052-000-0000 090-0000-0000" }),
79
+ });
80
+ /** CUBICS 週間時間割(学生情報 + 表示期間 + 曜日ヘッダ + 時限×コマ) */
81
+ exports.CubicsAsTimetableSchema = zod_1.z.object({
82
+ /** 学生情報 */
83
+ student: exports.CubicsAsTimetableStudentSchema,
84
+ /** 表示期間 @example "2025年06月16日~2025年06月21日" */
85
+ periodRange: zod_1.z.string().meta({ description: "表示期間", example: "2025年06月16日~2025年06月21日" }),
86
+ /** 曜日ヘッダ */
87
+ days: zod_1.z.array(exports.CubicsAsTimetableDaySchema).meta({ description: "曜日ヘッダ" }),
88
+ /** 時限ごとの行 */
89
+ periods: zod_1.z.array(exports.CubicsAsTimetablePeriodSchema).meta({ description: "時限ごとの行" }),
90
+ });
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /**
3
+ * SDK が投げるエラー型。呼び出し側はこれらを `instanceof` で判別してハンドリングする。
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TimeoutError = exports.NetworkError = exports.ChukyoMaintenanceError = exports.ExpiredSessionError = exports.ParseError = exports.ChukyoSdkError = void 0;
7
+ /** すべての SDK エラーの基底 */
8
+ class ChukyoSdkError extends Error {
9
+ constructor(message, options) {
10
+ super(message, options);
11
+ this.name = new.target.name;
12
+ }
13
+ }
14
+ exports.ChukyoSdkError = ChukyoSdkError;
15
+ /**
16
+ * パース失敗。fetch は成功したがレスポンスが期待スキーマに一致しなかった場合。
17
+ * `cause` に Zod のエラーが入る(サイトの HTML/JSON 構造変化の疑い)。
18
+ */
19
+ class ParseError extends ChukyoSdkError {
20
+ constructor(options) {
21
+ super("レスポンスのパースに失敗しました", options);
22
+ }
23
+ }
24
+ exports.ParseError = ParseError;
25
+ /**
26
+ * セッション失効。Cookie が無効で、再認証を試みても回復しなかった場合。
27
+ * CUBICS のように画面遷移型でセッションが不安定なサービスで発生しうる。
28
+ */
29
+ class ExpiredSessionError extends ChukyoSdkError {
30
+ constructor(options) {
31
+ super("ポータルのセッションが失効しています", options);
32
+ }
33
+ }
34
+ exports.ExpiredSessionError = ExpiredSessionError;
35
+ /** 大学側メンテナンス(HTTP 503)。UI 側で案内を出すために区別する。 */
36
+ class ChukyoMaintenanceError extends ChukyoSdkError {
37
+ constructor(options) {
38
+ super("中京大学ポータルがメンテナンス中です", options);
39
+ }
40
+ }
41
+ exports.ChukyoMaintenanceError = ChukyoMaintenanceError;
42
+ /** ネットワーク到達失敗(DNS・接続拒否・TLS 等、HTTP レスポンスを受け取れていない)。 */
43
+ class NetworkError extends ChukyoSdkError {
44
+ constructor(options) {
45
+ super("ネットワークエラーが発生しました", options);
46
+ }
47
+ }
48
+ exports.NetworkError = NetworkError;
49
+ /** リクエストがタイムアウトした。 */
50
+ class TimeoutError extends ChukyoSdkError {
51
+ constructor(options) {
52
+ super("リクエストがタイムアウトしました", options);
53
+ }
54
+ }
55
+ exports.TimeoutError = TimeoutError;