opensoma 0.4.0 → 0.5.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 (75) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/client.d.ts +7 -1
  3. package/dist/src/client.d.ts.map +1 -1
  4. package/dist/src/client.js +13 -11
  5. package/dist/src/client.js.map +1 -1
  6. package/dist/src/commands/auth.d.ts +1 -1
  7. package/dist/src/commands/auth.d.ts.map +1 -1
  8. package/dist/src/commands/auth.js +94 -52
  9. package/dist/src/commands/auth.js.map +1 -1
  10. package/dist/src/constants.d.ts +40 -0
  11. package/dist/src/constants.d.ts.map +1 -1
  12. package/dist/src/constants.js +42 -0
  13. package/dist/src/constants.js.map +1 -1
  14. package/dist/src/formatters.d.ts.map +1 -1
  15. package/dist/src/formatters.js +42 -16
  16. package/dist/src/formatters.js.map +1 -1
  17. package/dist/src/index.d.ts +3 -0
  18. package/dist/src/index.d.ts.map +1 -1
  19. package/dist/src/index.js +2 -0
  20. package/dist/src/index.js.map +1 -1
  21. package/dist/src/shared/utils/swmaestro.d.ts.map +1 -1
  22. package/dist/src/shared/utils/swmaestro.js +1 -5
  23. package/dist/src/shared/utils/swmaestro.js.map +1 -1
  24. package/dist/src/shared/utils/toz.d.ts +23 -0
  25. package/dist/src/shared/utils/toz.d.ts.map +1 -0
  26. package/dist/src/shared/utils/toz.js +72 -0
  27. package/dist/src/shared/utils/toz.js.map +1 -0
  28. package/dist/src/token-extractor.d.ts +9 -1
  29. package/dist/src/token-extractor.d.ts.map +1 -1
  30. package/dist/src/token-extractor.js +54 -10
  31. package/dist/src/token-extractor.js.map +1 -1
  32. package/dist/src/toz-formatters.d.ts +9 -0
  33. package/dist/src/toz-formatters.d.ts.map +1 -0
  34. package/dist/src/toz-formatters.js +151 -0
  35. package/dist/src/toz-formatters.js.map +1 -0
  36. package/dist/src/toz-http.d.ts +27 -0
  37. package/dist/src/toz-http.d.ts.map +1 -0
  38. package/dist/src/toz-http.js +154 -0
  39. package/dist/src/toz-http.js.map +1 -0
  40. package/dist/src/types.d.ts +52 -0
  41. package/dist/src/types.d.ts.map +1 -1
  42. package/dist/src/types.js +46 -0
  43. package/dist/src/types.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/__fixtures__/toz/toz_all_branches.json +211 -0
  46. package/src/__fixtures__/toz/toz_booking.html +2190 -0
  47. package/src/__fixtures__/toz/toz_boothes.json +59 -0
  48. package/src/__fixtures__/toz/toz_duration.json +25 -0
  49. package/src/__fixtures__/toz/toz_mypage_response.html +388 -0
  50. package/src/__fixtures__/toz/toz_page.html +211 -0
  51. package/src/client.test.ts +135 -117
  52. package/src/client.ts +16 -12
  53. package/src/commands/auth.test.ts +7 -7
  54. package/src/commands/auth.ts +107 -50
  55. package/src/commands/helpers.test.ts +8 -8
  56. package/src/commands/report.test.ts +7 -7
  57. package/src/constants.ts +50 -0
  58. package/src/credential-manager.test.ts +5 -5
  59. package/src/formatters.test.ts +22 -22
  60. package/src/formatters.ts +44 -16
  61. package/src/http.test.ts +37 -37
  62. package/src/index.ts +3 -0
  63. package/src/shared/utils/mentoring-params.test.ts +16 -16
  64. package/src/shared/utils/swmaestro.test.ts +87 -8
  65. package/src/shared/utils/swmaestro.ts +1 -6
  66. package/src/shared/utils/toz.test.ts +138 -0
  67. package/src/shared/utils/toz.ts +100 -0
  68. package/src/token-extractor.test.ts +40 -15
  69. package/src/token-extractor.ts +65 -13
  70. package/src/toz-formatters.test.ts +197 -0
  71. package/src/toz-formatters.ts +211 -0
  72. package/src/toz-http.test.ts +157 -0
  73. package/src/toz-http.ts +188 -0
  74. package/src/types.test.ts +220 -204
  75. package/src/types.ts +58 -0
package/src/types.test.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from 'bun:test'
1
+ import { describe, expect, it } from 'bun:test'
2
2
 
3
3
  import {
4
4
  ApplicationHistoryItemSchema,
@@ -20,226 +20,242 @@ import {
20
20
  } from './types'
21
21
 
22
22
  describe('schemas', () => {
23
- test('accept valid values', () => {
24
- expect(
25
- MentoringListItemSchema.parse({
26
- id: 9572,
27
- title: 'AI 멘토링',
28
- type: '자유 멘토링',
29
- registrationPeriod: { start: '2026-04-01', end: '2026-04-10' },
30
- sessionDate: '2026-04-11',
31
- sessionTime: { start: '14:00', end: '15:30' },
32
- attendees: { current: 3, max: 4 },
33
- approved: true,
34
- status: '접수중',
35
- author: '전수열',
36
- createdAt: '2026-04-01',
37
- }),
38
- ).toBeDefined()
23
+ it('preserves valid MentoringListItem values through parse', () => {
24
+ const input = {
25
+ id: 9572,
26
+ title: 'AI 멘토링',
27
+ type: '자유 멘토링' as const,
28
+ registrationPeriod: { start: '2026-04-01', end: '2026-04-10' },
29
+ sessionDate: '2026-04-11',
30
+ sessionTime: { start: '14:00', end: '15:30' },
31
+ attendees: { current: 3, max: 4 },
32
+ approved: true,
33
+ status: '접수중' as const,
34
+ author: '전수열',
35
+ createdAt: '2026-04-01',
36
+ }
37
+ expect(MentoringListItemSchema.parse(input)).toEqual(input)
38
+ })
39
39
 
40
- expect(
41
- MentoringDetailSchema.parse({
42
- id: 9572,
43
- title: 'AI 멘토링',
44
- type: '멘토 특강',
45
- registrationPeriod: { start: '2026-04-01', end: '2026-04-10' },
46
- sessionDate: '2026-04-11',
47
- sessionTime: { start: '14:00', end: '15:30' },
48
- attendees: { current: 6, max: 20 },
49
- approved: false,
50
- status: '마감',
51
- author: '전수열',
52
- createdAt: '2026-04-01',
53
- content: '<p>내용</p>',
54
- venue: '온라인(Webex)',
55
- applicants: [],
56
- }),
57
- ).toBeDefined()
40
+ it('preserves valid MentoringDetail values through parse', () => {
41
+ const input = {
42
+ id: 9572,
43
+ title: 'AI 멘토링',
44
+ type: '멘토 특강' as const,
45
+ registrationPeriod: { start: '2026-04-01', end: '2026-04-10' },
46
+ sessionDate: '2026-04-11',
47
+ sessionTime: { start: '14:00', end: '15:30' },
48
+ attendees: { current: 6, max: 20 },
49
+ approved: false,
50
+ status: '마감' as const,
51
+ author: '전수열',
52
+ createdAt: '2026-04-01',
53
+ content: '<p>내용</p>',
54
+ venue: '온라인(Webex)',
55
+ applicants: [],
56
+ }
57
+ expect(MentoringDetailSchema.parse(input)).toEqual(input)
58
+ })
58
59
 
59
- expect(
60
- RoomCardSchema.parse({
61
- itemId: 17,
62
- name: '스페이스 A1',
63
- capacity: 4,
64
- availablePeriod: { start: '2026-04-01', end: '2026-12-31' },
65
- description: '소회의실 : 4인',
66
- timeSlots: [
67
- { time: '09:00', available: true },
68
- { time: '09:30', available: false, reservation: { title: '팀 회의', bookedBy: '전수열' } },
69
- ],
70
- }),
71
- ).toBeDefined()
60
+ it('preserves valid RoomCard values through parse', () => {
61
+ const input = {
62
+ itemId: 17,
63
+ name: '스페이스 A1',
64
+ capacity: 4,
65
+ availablePeriod: { start: '2026-04-01', end: '2026-12-31' },
66
+ description: '소회의실 : 4인',
67
+ timeSlots: [
68
+ { time: '09:00', available: true },
69
+ { time: '09:30', available: false, reservation: { title: '팀 회의', bookedBy: '전수열' } },
70
+ ],
71
+ }
72
+ expect(RoomCardSchema.parse(input)).toEqual(input)
73
+ })
72
74
 
73
- expect(
74
- DashboardSchema.parse({
75
- name: '전수열',
76
- role: '멘토',
77
- organization: 'Indent',
78
- position: '',
79
- team: { name: '오픈소마', members: '전수열, 김개발', mentor: '전수열' },
80
- mentoringSessions: [{ title: 'AI 멘토링', url: '/mentoring/1', status: '접수중' }],
81
- roomReservations: [{ title: 'A1 회의', url: '/room/1', status: '예약완료' }],
82
- }),
83
- ).toBeDefined()
75
+ it('preserves valid Dashboard values through parse', () => {
76
+ const input = {
77
+ name: '전수열',
78
+ role: '멘토',
79
+ organization: 'Indent',
80
+ position: '',
81
+ team: { name: '오픈소마', members: '전수열, 김개발', mentor: '전수열' },
82
+ mentoringSessions: [{ title: 'AI 멘토링', url: '/mentoring/1', status: '접수중' }],
83
+ roomReservations: [{ title: 'A1 회의', url: '/room/1', status: '예약완료' }],
84
+ }
85
+ expect(DashboardSchema.parse(input)).toEqual(input)
86
+ })
84
87
 
85
- expect(
86
- NoticeListItemSchema.parse({
87
- id: 1,
88
- title: '공지',
89
- author: '관리자',
90
- createdAt: '2026-04-01',
91
- }),
92
- ).toBeDefined()
88
+ it('preserves valid NoticeListItem values through parse', () => {
89
+ const input = {
90
+ id: 1,
91
+ title: '공지',
92
+ author: '관리자',
93
+ createdAt: '2026-04-01',
94
+ }
95
+ expect(NoticeListItemSchema.parse(input)).toEqual(input)
96
+ })
93
97
 
94
- expect(
95
- NoticeDetailSchema.parse({
96
- id: 1,
97
- title: '공지',
98
- author: '관리자',
99
- createdAt: '2026-04-01',
100
- content: '<p>내용</p>',
101
- }),
102
- ).toBeDefined()
98
+ it('preserves valid NoticeDetail values through parse', () => {
99
+ const input = {
100
+ id: 1,
101
+ title: '공지',
102
+ author: '관리자',
103
+ createdAt: '2026-04-01',
104
+ content: '<p>내용</p>',
105
+ }
106
+ expect(NoticeDetailSchema.parse(input)).toEqual(input)
107
+ })
103
108
 
104
- expect(
105
- TeamInfoSchema.parse({
106
- teams: [
107
- { name: '오픈소마', memberCount: 3, joinStatus: '참여중' },
108
- { name: '김앤강', memberCount: 5, joinStatus: '참여하기' },
109
- ],
110
- currentTeams: 1,
111
- maxTeams: 100,
112
- }),
113
- ).toBeDefined()
109
+ it('preserves valid TeamInfo values through parse', () => {
110
+ const input = {
111
+ teams: [
112
+ { name: '오픈소마', memberCount: 3, joinStatus: '참여중' },
113
+ { name: '김앤강', memberCount: 5, joinStatus: '참여하기' },
114
+ ],
115
+ currentTeams: 1,
116
+ maxTeams: 100,
117
+ }
118
+ expect(TeamInfoSchema.parse(input)).toEqual(input)
119
+ })
114
120
 
115
- expect(
116
- MemberInfoSchema.parse({
117
- email: 'neo@example.com',
118
- name: '전수열',
119
- gender: '남자',
120
- birthDate: '1995-01-14',
121
- phone: '01012345678',
122
- organization: 'Indent',
123
- position: '',
124
- }),
125
- ).toBeDefined()
121
+ it('preserves valid MemberInfo values through parse', () => {
122
+ const input = {
123
+ email: 'neo@example.com',
124
+ name: '전수열',
125
+ gender: '남자',
126
+ birthDate: '1995-01-14',
127
+ phone: '01012345678',
128
+ organization: 'Indent',
129
+ position: '',
130
+ }
131
+ expect(MemberInfoSchema.parse(input)).toEqual(input)
132
+ })
126
133
 
127
- expect(
128
- EventListItemSchema.parse({
129
- id: 11,
130
- category: '행사',
131
- title: '데모데이',
132
- registrationPeriod: { start: '2026-04-01', end: '2026-04-05' },
133
- eventPeriod: { start: '2026-04-10', end: '2026-04-10' },
134
- status: '접수중',
135
- createdAt: '2026-03-30',
136
- }),
137
- ).toBeDefined()
134
+ it('preserves valid EventListItem values through parse', () => {
135
+ const input = {
136
+ id: 11,
137
+ category: '행사',
138
+ title: '데모데이',
139
+ registrationPeriod: { start: '2026-04-01', end: '2026-04-05' },
140
+ eventPeriod: { start: '2026-04-10', end: '2026-04-10' },
141
+ status: '접수중',
142
+ createdAt: '2026-03-30',
143
+ }
144
+ expect(EventListItemSchema.parse(input)).toEqual(input)
145
+ })
138
146
 
139
- expect(
140
- ApplicationHistoryItemSchema.parse({
141
- id: 99,
142
- category: '멘토 특강',
143
- title: 'AI 멘토링',
144
- author: '전수열',
145
- sessionDate: '2026-04-11',
146
- appliedAt: '2026-04-02 09:00',
147
- applicationStatus: '신청완료',
148
- approvalStatus: 'OK',
149
- applicationDetail: '승인대기',
150
- note: '-',
151
- }),
152
- ).toBeDefined()
147
+ it('preserves valid ApplicationHistoryItem values through parse', () => {
148
+ const input = {
149
+ id: 99,
150
+ category: '멘토 특강',
151
+ title: 'AI 멘토링',
152
+ author: '전수열',
153
+ sessionDate: '2026-04-11',
154
+ appliedAt: '2026-04-02 09:00',
155
+ applicationStatus: '신청완료',
156
+ approvalStatus: 'OK',
157
+ applicationDetail: '승인대기',
158
+ note: '-',
159
+ }
160
+ expect(ApplicationHistoryItemSchema.parse(input)).toEqual(input)
161
+ })
153
162
 
154
- expect(PaginationSchema.parse({ total: 23, currentPage: 2, totalPages: 3 })).toBeDefined()
163
+ it('preserves valid Pagination values through parse', () => {
164
+ const input = { total: 23, currentPage: 2, totalPages: 3 }
165
+ expect(PaginationSchema.parse(input)).toEqual(input)
166
+ })
155
167
 
156
- expect(
157
- CredentialsSchema.parse({
158
- sessionCookie: 'session-token',
159
- csrfToken: 'csrf-token',
160
- username: 'neo@example.com',
161
- loggedInAt: '2026-04-09T00:00:00.000Z',
162
- }),
163
- ).toBeDefined()
168
+ it('preserves valid Credentials values through parse', () => {
169
+ const input = {
170
+ sessionCookie: 'session-token',
171
+ csrfToken: 'csrf-token',
172
+ username: 'neo@example.com',
173
+ loggedInAt: '2026-04-09T00:00:00.000Z',
174
+ }
175
+ expect(CredentialsSchema.parse(input)).toEqual(input)
176
+ })
164
177
 
165
- expect(
166
- ReportListItemSchema.parse({
167
- id: 1,
168
- category: '멘토링',
169
- title: 'AI 멘토링 보고서',
170
- progressDate: '2026-04-10',
171
- status: '승인완료',
172
- author: '전수열',
173
- createdAt: '2026-04-11',
174
- acceptedTime: '2시간',
175
- payAmount: '100000',
176
- }),
177
- ).toBeDefined()
178
+ it('preserves valid ReportListItem values through parse', () => {
179
+ const input = {
180
+ id: 1,
181
+ category: '멘토링',
182
+ title: 'AI 멘토링 보고서',
183
+ progressDate: '2026-04-10',
184
+ status: '승인완료',
185
+ author: '전수열',
186
+ createdAt: '2026-04-11',
187
+ acceptedTime: '2시간',
188
+ payAmount: '100000',
189
+ }
190
+ expect(ReportListItemSchema.parse(input)).toEqual(input)
191
+ })
178
192
 
179
- expect(
180
- ReportDetailSchema.parse({
181
- id: 1,
182
- category: '멘토링',
183
- title: 'AI 멘토링 보고서',
184
- progressDate: '2026-04-10',
185
- status: '승인완료',
186
- author: '전수열',
187
- createdAt: '2026-04-11',
188
- acceptedTime: '2시간',
189
- payAmount: '100000',
190
- content: '멘토링 진행 내용',
191
- subject: 'AI 기술 멘토링',
192
- menteeRegion: 'S',
193
- reportType: 'MRC010',
194
- teamNames: '오픈소마',
195
- venue: '스페이스 A1',
196
- attendanceCount: 4,
197
- attendanceNames: '김개발, 박코딩, 이알고, 최리즘',
198
- progressStartTime: '14:00',
199
- progressEndTime: '16:00',
200
- exceptStartTime: '',
201
- exceptEndTime: '',
202
- exceptReason: '',
203
- mentorOpinion: '우수',
204
- nonAttendanceNames: '',
205
- etc: '',
206
- files: [],
207
- }),
208
- ).toBeDefined()
193
+ it('preserves valid ReportDetail values through parse', () => {
194
+ const input = {
195
+ id: 1,
196
+ category: '멘토링',
197
+ title: 'AI 멘토링 보고서',
198
+ progressDate: '2026-04-10',
199
+ status: '승인완료',
200
+ author: '전수열',
201
+ createdAt: '2026-04-11',
202
+ acceptedTime: '2시간',
203
+ payAmount: '100000',
204
+ content: '멘토링 진행 내용',
205
+ subject: 'AI 기술 멘토링',
206
+ menteeRegion: 'S',
207
+ reportType: 'MRC010',
208
+ teamNames: '오픈소마',
209
+ venue: '스페이스 A1',
210
+ attendanceCount: 4,
211
+ attendanceNames: '김개발, 박코딩, 이알고, 최리즘',
212
+ progressStartTime: '14:00',
213
+ progressEndTime: '16:00',
214
+ exceptStartTime: '',
215
+ exceptEndTime: '',
216
+ exceptReason: '',
217
+ mentorOpinion: '우수',
218
+ nonAttendanceNames: '',
219
+ etc: '',
220
+ files: [],
221
+ }
222
+ expect(ReportDetailSchema.parse(input)).toEqual(input)
223
+ })
209
224
 
210
- expect(
211
- ApprovalListItemSchema.parse({
212
- id: 1,
213
- category: '멘토링',
214
- title: 'AI 멘토링 보고서',
215
- progressDate: '2026-04-10',
216
- status: '승인완료',
217
- author: '전수열',
218
- createdAt: '2026-04-11',
219
- acceptedTime: '2시간',
220
- travelExpense: '50000',
221
- mentoringAllowance: '100000',
222
- }),
223
- ).toBeDefined()
225
+ it('preserves valid ApprovalListItem values through parse', () => {
226
+ const input = {
227
+ id: 1,
228
+ category: '멘토링',
229
+ title: 'AI 멘토링 보고서',
230
+ progressDate: '2026-04-10',
231
+ status: '승인완료',
232
+ author: '전수열',
233
+ createdAt: '2026-04-11',
234
+ acceptedTime: '2시간',
235
+ travelExpense: '50000',
236
+ mentoringAllowance: '100000',
237
+ }
238
+ expect(ApprovalListItemSchema.parse(input)).toEqual(input)
239
+ })
224
240
 
225
- expect(
226
- ReportCreateOptionsSchema.parse({
227
- menteeRegion: 'S',
228
- reportType: 'MRC010',
229
- progressDate: '2026-04-10',
230
- venue: '스페이스 A1',
231
- attendanceCount: 4,
232
- attendanceNames: '김개발, 박코딩, 이알고, 최리즘',
233
- progressStartTime: '14:00',
234
- progressEndTime: '16:00',
235
- subject: 'AI 멘토링 진행 보고',
236
- content:
237
- '이번 멘토링에서는 AI 기술의 기초 개념과 실제 적용 사례에 대해 다루었습니다. 참가자들은 머신러닝의 기본 원리와 딥러닝의 구조에 대해 학습하고, 실습을 통해 모델을 구현해보았습니다.',
238
- }),
239
- ).toBeDefined()
241
+ it('preserves valid ReportCreateOptions values through parse', () => {
242
+ const input = {
243
+ menteeRegion: 'S',
244
+ reportType: 'MRC010',
245
+ progressDate: '2026-04-10',
246
+ venue: '스페이스 A1',
247
+ attendanceCount: 4,
248
+ attendanceNames: '김개발, 박코딩, 이알고, 최리즘',
249
+ progressStartTime: '14:00',
250
+ progressEndTime: '16:00',
251
+ subject: 'AI 멘토링 진행 보고',
252
+ content:
253
+ '이번 멘토링에서는 AI 기술의 기초 개념과 실제 적용 사례에 대해 다루었습니다. 참가자들은 머신러닝의 기본 원리와 딥러닝의 구조에 대해 학습하고, 실습을 통해 모델을 구현해보았습니다.',
254
+ }
255
+ expect(ReportCreateOptionsSchema.parse(input)).toEqual(input)
240
256
  })
241
257
 
242
- test('reject invalid values', () => {
258
+ it('rejects invalid values for every schema', () => {
243
259
  expect(() => MentoringListItemSchema.parse({})).toThrow()
244
260
  expect(() => MentoringDetailSchema.parse({ content: 123 })).toThrow()
245
261
  expect(() => RoomCardSchema.parse({ itemId: '17' })).toThrow()
package/src/types.ts CHANGED
@@ -151,9 +151,67 @@ export const CredentialsSchema = z.object({
151
151
  username: z.string().optional(),
152
152
  password: z.string().optional(),
153
153
  loggedInAt: z.string().optional(),
154
+ tozName: z.string().optional(),
155
+ tozPhone: z.string().optional(),
154
156
  })
155
157
  export type Credentials = z.infer<typeof CredentialsSchema>
156
158
 
159
+ export const TozBranchSchema = z.object({
160
+ id: z.number(),
161
+ name: z.string(),
162
+ })
163
+ export type TozBranch = z.infer<typeof TozBranchSchema>
164
+
165
+ export const TozMeetingSchema = z.object({
166
+ id: z.number(),
167
+ name: z.string(),
168
+ })
169
+ export type TozMeeting = z.infer<typeof TozMeetingSchema>
170
+
171
+ export const TozDurationSchema = z.object({
172
+ key: z.string(),
173
+ value: z.string(),
174
+ minutes: z.number(),
175
+ })
176
+ export type TozDuration = z.infer<typeof TozDurationSchema>
177
+
178
+ export const TozBoothSchema = z.object({
179
+ id: z.number(),
180
+ name: z.string(),
181
+ branchName: z.string(),
182
+ branchTel: z.string(),
183
+ minUseUserCount: z.number(),
184
+ enableMaxUserCount: z.number(),
185
+ boothGroupName: z.string(),
186
+ boothGroupUrl: z.string().nullable(),
187
+ boothMemoForUser: z.string(),
188
+ isLargeBooth: z.boolean(),
189
+ })
190
+ export type TozBooth = z.infer<typeof TozBoothSchema>
191
+
192
+ export const TozReservedSchema = z.object({
193
+ reservationId: z.string(),
194
+ branchName: z.string(),
195
+ branchTel: z.string(),
196
+ boothGroupName: z.string(),
197
+ isLargeBooth: z.boolean(),
198
+ })
199
+ export type TozReserved = z.infer<typeof TozReservedSchema>
200
+
201
+ export const TozReservationSchema = z.object({
202
+ no: z.number(),
203
+ reservationId: z.number().nullable(),
204
+ meetingName: z.string(),
205
+ date: z.string(),
206
+ startTime: z.string(),
207
+ endTime: z.string(),
208
+ branchName: z.string(),
209
+ boothName: z.string(),
210
+ reservedAt: z.string(),
211
+ status: z.string(),
212
+ })
213
+ export type TozReservation = z.infer<typeof TozReservationSchema>
214
+
157
215
  export const ReportListItemSchema = z.object({
158
216
  id: z.number(),
159
217
  category: z.string(),