@readerseye2/cr_type 1.0.74 → 1.0.76
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/dist/socket/index.d.ts +1 -0
- package/dist/socket/index.js +1 -0
- package/dist/socket/recording.types.d.ts +236 -0
- package/dist/socket/recording.types.js +19 -0
- package/dist/socket/socket-clientToServerEvents.type.d.ts +7 -1
- package/dist/socket/socket-serverToClientEvents.type.d.ts +13 -1
- package/package.json +1 -1
package/dist/socket/index.d.ts
CHANGED
package/dist/socket/index.js
CHANGED
|
@@ -21,3 +21,4 @@ __exportStar(require("./socket-message.types"), exports);
|
|
|
21
21
|
__exportStar(require("./reading-section.types"), exports);
|
|
22
22
|
__exportStar(require("./connected-user.types"), exports);
|
|
23
23
|
__exportStar(require("./monitor.types"), exports);
|
|
24
|
+
__exportStar(require("./recording.types"), exports);
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import type { ViewerSnapshot, SocketViewerEvent } from './reading-section.types';
|
|
2
|
+
/** 녹화 요청자 타입 */
|
|
3
|
+
export type RecordingRequesterType = 'admin' | 'parent';
|
|
4
|
+
/** 뷰어 사용자 타입 (실제로 책 읽는 사람) */
|
|
5
|
+
export type ViewerUserType = 'parent' | 'child';
|
|
6
|
+
/** 녹화 상태 */
|
|
7
|
+
export type RecordingStatus = 'recording' | 'ended';
|
|
8
|
+
/** 세그먼트 상태 */
|
|
9
|
+
export type SegmentStatus = 'active' | 'ended';
|
|
10
|
+
/**
|
|
11
|
+
* 청크 파일 (S3: segments/{n}/chunks/{startTs}-{endTs}.json)
|
|
12
|
+
* - 10초 단위 이벤트 묶음
|
|
13
|
+
*/
|
|
14
|
+
export interface ChunkFile {
|
|
15
|
+
startTimestamp: number;
|
|
16
|
+
endTimestamp: number;
|
|
17
|
+
events: SocketViewerEvent[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 스냅샷 파일 (S3: segments/{n}/snapshots/{ts}.json)
|
|
21
|
+
* - 30초 단위 뷰어 전체 상태
|
|
22
|
+
* - Seek 시 이 시점부터 재생 가능
|
|
23
|
+
*/
|
|
24
|
+
export interface SnapshotFile {
|
|
25
|
+
timestamp: number;
|
|
26
|
+
viewerState: ViewerSnapshot;
|
|
27
|
+
}
|
|
28
|
+
/** 청크 참조 정보 (meta.json 내) */
|
|
29
|
+
export interface ChunkRef {
|
|
30
|
+
start: number;
|
|
31
|
+
end: number;
|
|
32
|
+
key: string;
|
|
33
|
+
eventCount: number;
|
|
34
|
+
}
|
|
35
|
+
/** 스냅샷 참조 정보 (meta.json 내) */
|
|
36
|
+
export interface SnapshotRef {
|
|
37
|
+
timestamp: number;
|
|
38
|
+
key: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 세그먼트 메타데이터
|
|
42
|
+
* - 뷰어가 열린 하나의 구간
|
|
43
|
+
* - 뷰어 열기 → 닫기 (또는 섹션 변경)
|
|
44
|
+
*/
|
|
45
|
+
export interface SegmentMeta {
|
|
46
|
+
/** 세그먼트 인덱스 (0부터) */
|
|
47
|
+
segmentIndex: number;
|
|
48
|
+
/** 상태 */
|
|
49
|
+
status: SegmentStatus;
|
|
50
|
+
/** 뷰어 소켓 세션 ID */
|
|
51
|
+
socketSessionId: string;
|
|
52
|
+
bookIdx: number;
|
|
53
|
+
bookTitle?: string;
|
|
54
|
+
sectionId: string;
|
|
55
|
+
sectionTitle?: string;
|
|
56
|
+
/** 뷰어 열린 시간 (ms) */
|
|
57
|
+
startedAt: number;
|
|
58
|
+
/** 뷰어 닫힌 시간 (ms), null이면 진행중 */
|
|
59
|
+
endedAt: number | null;
|
|
60
|
+
/** 마지막 업데이트 */
|
|
61
|
+
updatedAt: number;
|
|
62
|
+
chunks: ChunkRef[];
|
|
63
|
+
snapshots: SnapshotRef[];
|
|
64
|
+
totalEvents: number;
|
|
65
|
+
durationMs: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 세그먼트 요약 정보 (manifest 내)
|
|
69
|
+
* - Seek 시 이 정보로 어떤 segment를 봐야 할지 판단
|
|
70
|
+
* - 전체 정보는 segments/{n}/meta.json 참조
|
|
71
|
+
*/
|
|
72
|
+
export interface SegmentSummary {
|
|
73
|
+
/** 세그먼트 인덱스 (0부터, 시간순) */
|
|
74
|
+
segmentIndex: number;
|
|
75
|
+
/** 상태 */
|
|
76
|
+
status: SegmentStatus;
|
|
77
|
+
bookIdx: number;
|
|
78
|
+
bookTitle?: string;
|
|
79
|
+
sectionId: string;
|
|
80
|
+
sectionTitle?: string;
|
|
81
|
+
/** 세그먼트 시작 timestamp (ms) - 이 시간 이후 이벤트는 이 segment에 */
|
|
82
|
+
startedAt: number;
|
|
83
|
+
/** 세그먼트 종료 timestamp (ms) - null이면 진행중 (Live) */
|
|
84
|
+
endedAt: number | null;
|
|
85
|
+
/** 세그먼트 길이 (ms) - endedAt이 null이면 현재까지 길이 */
|
|
86
|
+
durationMs: number;
|
|
87
|
+
chunkCount: number;
|
|
88
|
+
eventCount: number;
|
|
89
|
+
/** meta.json S3 key */
|
|
90
|
+
metaKey: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 녹화 Manifest (전체 요청 단위)
|
|
94
|
+
* - Admin/Parent가 모니터링 시작 → 종료까지
|
|
95
|
+
* - S3: manifest.json
|
|
96
|
+
*/
|
|
97
|
+
export interface RecordingManifest {
|
|
98
|
+
/** 녹화 ID */
|
|
99
|
+
recordingId: string;
|
|
100
|
+
/** 상태 */
|
|
101
|
+
status: RecordingStatus;
|
|
102
|
+
requestedBy: RecordingRequesterType;
|
|
103
|
+
requesterSocketId: string;
|
|
104
|
+
requesterId?: number;
|
|
105
|
+
requesterName?: string;
|
|
106
|
+
viewerUserId: number;
|
|
107
|
+
viewerUserType: ViewerUserType;
|
|
108
|
+
viewerUserName: string;
|
|
109
|
+
familyId: number;
|
|
110
|
+
/** 요청 시작 시간 (불변, Admin/Parent가 모니터링 시작한 시점) */
|
|
111
|
+
requestedAt: number;
|
|
112
|
+
/** 요청 종료 시간 (Admin/Parent가 모니터링 종료한 시점) */
|
|
113
|
+
endedAt: number | null;
|
|
114
|
+
/** 마지막 업데이트 */
|
|
115
|
+
updatedAt: number;
|
|
116
|
+
/** 첫 번째 세그먼트 시작 시간 (실제 녹화 시작) */
|
|
117
|
+
firstSegmentStartedAt: number | null;
|
|
118
|
+
/** 마지막 세그먼트 종료 시간 (실제 녹화 끝, null이면 Live) */
|
|
119
|
+
lastSegmentEndedAt: number | null;
|
|
120
|
+
/** segments[0].startedAt < segments[1].startedAt < ... */
|
|
121
|
+
segments: SegmentSummary[];
|
|
122
|
+
totalSegments: number;
|
|
123
|
+
totalChunks: number;
|
|
124
|
+
totalEvents: number;
|
|
125
|
+
/** 실제 녹화 시간 합계 (Gap 제외) */
|
|
126
|
+
totalDurationMs: number;
|
|
127
|
+
}
|
|
128
|
+
/** 녹화 시작 요청 */
|
|
129
|
+
export interface RecordingStartPayload {
|
|
130
|
+
targetSocketId: string;
|
|
131
|
+
}
|
|
132
|
+
/** 녹화 중지 요청 */
|
|
133
|
+
export interface RecordingStopPayload {
|
|
134
|
+
targetSocketId: string;
|
|
135
|
+
}
|
|
136
|
+
/** 녹화 시작됨 */
|
|
137
|
+
export interface RecordingStartedPayload {
|
|
138
|
+
recordingId: string;
|
|
139
|
+
requestedAt: number;
|
|
140
|
+
viewerInfo: {
|
|
141
|
+
userId: number;
|
|
142
|
+
userType: ViewerUserType;
|
|
143
|
+
userName: string;
|
|
144
|
+
familyId: number;
|
|
145
|
+
};
|
|
146
|
+
/** 현재 활성 세그먼트 (뷰어가 열려있으면, 여기에 책/섹션 정보 포함) */
|
|
147
|
+
currentSegment: SegmentMeta | null;
|
|
148
|
+
}
|
|
149
|
+
/** 녹화 종료됨 */
|
|
150
|
+
export interface RecordingStoppedPayload {
|
|
151
|
+
recordingId: string;
|
|
152
|
+
endedAt: number;
|
|
153
|
+
stats: {
|
|
154
|
+
totalSegments: number;
|
|
155
|
+
totalChunks: number;
|
|
156
|
+
totalEvents: number;
|
|
157
|
+
totalDurationMs: number;
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/** 실시간 청크 전송 */
|
|
161
|
+
export interface RecordingChunkPayload {
|
|
162
|
+
recordingId: string;
|
|
163
|
+
segmentIndex: number;
|
|
164
|
+
chunk: ChunkFile;
|
|
165
|
+
snapshot?: ViewerSnapshot;
|
|
166
|
+
}
|
|
167
|
+
/** 세그먼트 시작됨 (뷰어 열림) */
|
|
168
|
+
export interface SegmentStartedPayload {
|
|
169
|
+
recordingId: string;
|
|
170
|
+
segment: SegmentMeta;
|
|
171
|
+
}
|
|
172
|
+
/** 세그먼트 종료됨 (뷰어 닫힘) */
|
|
173
|
+
export interface SegmentEndedPayload {
|
|
174
|
+
recordingId: string;
|
|
175
|
+
segmentIndex: number;
|
|
176
|
+
endedAt: number;
|
|
177
|
+
}
|
|
178
|
+
/** 녹화 목록 조회 응답 */
|
|
179
|
+
export interface RecordingListResponse {
|
|
180
|
+
recordings: RecordingManifest[];
|
|
181
|
+
}
|
|
182
|
+
/** 녹화 상세 조회 응답 */
|
|
183
|
+
export interface RecordingDetailResponse {
|
|
184
|
+
manifest: RecordingManifest;
|
|
185
|
+
}
|
|
186
|
+
/** 세그먼트 상세 조회 응답 */
|
|
187
|
+
export interface SegmentDetailResponse {
|
|
188
|
+
segment: SegmentMeta;
|
|
189
|
+
}
|
|
190
|
+
/** 청크 조회 파라미터 */
|
|
191
|
+
export interface ChunksQueryParams {
|
|
192
|
+
segmentIndex: number;
|
|
193
|
+
from?: number;
|
|
194
|
+
to?: number;
|
|
195
|
+
}
|
|
196
|
+
/** 청크 조회 응답 */
|
|
197
|
+
export interface ChunksResponse {
|
|
198
|
+
chunks: ChunkFile[];
|
|
199
|
+
nearestSnapshot?: SnapshotFile;
|
|
200
|
+
}
|
|
201
|
+
/** 활성 녹화 (서버 메모리) */
|
|
202
|
+
export interface ActiveRecording {
|
|
203
|
+
recordingId: string;
|
|
204
|
+
s3Prefix: string;
|
|
205
|
+
requestedBy: RecordingRequesterType;
|
|
206
|
+
requesterSocketId: string;
|
|
207
|
+
requesterId?: number;
|
|
208
|
+
requesterName?: string;
|
|
209
|
+
viewerUserId: number;
|
|
210
|
+
viewerUserType: ViewerUserType;
|
|
211
|
+
viewerUserName: string;
|
|
212
|
+
familyId: number;
|
|
213
|
+
viewerSocketId: string;
|
|
214
|
+
requestedAt: number;
|
|
215
|
+
currentSegment: ActiveSegment | null;
|
|
216
|
+
completedSegments: SegmentSummary[];
|
|
217
|
+
totalEvents: number;
|
|
218
|
+
chunkIntervalHandle: ReturnType<typeof setInterval> | null;
|
|
219
|
+
snapshotIntervalHandle: ReturnType<typeof setInterval> | null;
|
|
220
|
+
}
|
|
221
|
+
/** 활성 세그먼트 (서버 메모리) */
|
|
222
|
+
export interface ActiveSegment {
|
|
223
|
+
segmentIndex: number;
|
|
224
|
+
socketSessionId: string;
|
|
225
|
+
bookIdx: number;
|
|
226
|
+
bookTitle?: string;
|
|
227
|
+
sectionId: string;
|
|
228
|
+
sectionTitle?: string;
|
|
229
|
+
startedAt: number;
|
|
230
|
+
eventBuffer: SocketViewerEvent[];
|
|
231
|
+
chunkStartTimestamp: number;
|
|
232
|
+
lastSnapshot: ViewerSnapshot | null;
|
|
233
|
+
chunks: ChunkRef[];
|
|
234
|
+
snapshots: SnapshotRef[];
|
|
235
|
+
totalEvents: number;
|
|
236
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/socket/recording.types.ts
|
|
3
|
+
// P2.2: S3 녹화 시스템 타입 정의
|
|
4
|
+
//
|
|
5
|
+
// 구조:
|
|
6
|
+
// - Recording (Request 단위): Admin/Parent가 모니터링 요청 ~ 종료
|
|
7
|
+
// - Segment (뷰어 열림 단위): 뷰어 열기 ~ 닫기 (섹션 변경 포함)
|
|
8
|
+
//
|
|
9
|
+
// S3 경로:
|
|
10
|
+
// live-recordings/{familyId}/{viewerUserId}/{recordingId}/
|
|
11
|
+
// ├── manifest.json (RecordingManifest)
|
|
12
|
+
// └── segments/
|
|
13
|
+
// ├── 0/
|
|
14
|
+
// │ ├── meta.json (SegmentMeta)
|
|
15
|
+
// │ ├── snapshots/{ts}.json
|
|
16
|
+
// │ └── chunks/{startTs}-{endTs}.json
|
|
17
|
+
// └── 1/
|
|
18
|
+
// └── ...
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ChatMessageReadRequest, ChatMessageRefreshRequest, MessageRequest } from "./socket-message.types";
|
|
2
2
|
import { SessionStartPayload, SessionEndPayload, SessionProgressPayload, SessionEventPayload, SessionSubscribePayload } from "./reading-section.types";
|
|
3
3
|
import { MonitorStartPayload, MonitorStopPayload } from "./monitor.types";
|
|
4
|
+
import { RecordingStartPayload, RecordingStopPayload } from "./recording.types";
|
|
4
5
|
export interface ClientToServerEvents {
|
|
5
6
|
'chat-message:send': (msg: MessageRequest) => void;
|
|
6
7
|
'chat-message:refresh': (msg: ChatMessageRefreshRequest) => void;
|
|
@@ -24,5 +25,10 @@ export interface MonitorAdminToServerEvents {
|
|
|
24
25
|
'monitor:start': (payload: MonitorStartPayload) => void;
|
|
25
26
|
'monitor:stop': (payload: MonitorStopPayload) => void;
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
+
/** 녹화 이벤트 (Admin/Parent → Server) - P2.2 Recording System */
|
|
29
|
+
export interface RecordingAdminToServerEvents {
|
|
30
|
+
'recording:start': (payload: RecordingStartPayload) => void;
|
|
31
|
+
'recording:stop': (payload: RecordingStopPayload) => void;
|
|
32
|
+
}
|
|
33
|
+
export interface AdminClientToServerEvents extends ClientToServerEvents, NoticeToServerEvents, ReadingAdminToServerEvents, MonitorAdminToServerEvents, RecordingAdminToServerEvents {
|
|
28
34
|
}
|
|
@@ -2,6 +2,7 @@ import { MessageReadResponse, MessageResponse, NoticeMessageResult } from "./soc
|
|
|
2
2
|
import { ReadingSessionInfo, SocketViewerEvent, ViewerSnapshot } from "./reading-section.types";
|
|
3
3
|
import { ConnectedUser, ConnectedUsersGrouped } from "./connected-user.types";
|
|
4
4
|
import { MonitorStartedPayload, MonitorChunkPayload, MonitorSessionChangedPayload, MonitorStoppedPayload, MonitorErrorPayload } from "./monitor.types";
|
|
5
|
+
import { RecordingStartedPayload, RecordingStoppedPayload, RecordingChunkPayload, SegmentStartedPayload, SegmentEndedPayload } from "./recording.types";
|
|
5
6
|
export interface ServerToClientEvents {
|
|
6
7
|
connect: () => void;
|
|
7
8
|
disconnect: () => void;
|
|
@@ -69,5 +70,16 @@ export interface MonitorServerToClientEvents {
|
|
|
69
70
|
'monitor:stopped': (payload: MonitorStoppedPayload) => void;
|
|
70
71
|
'monitor:error': (payload: MonitorErrorPayload) => void;
|
|
71
72
|
}
|
|
72
|
-
|
|
73
|
+
/** 녹화 이벤트 (Admin/Parent에게 전송) - P2.2 Recording System */
|
|
74
|
+
export interface RecordingServerToClientEvents {
|
|
75
|
+
'recording:started': (payload: RecordingStartedPayload) => void;
|
|
76
|
+
'recording:stopped': (payload: RecordingStoppedPayload) => void;
|
|
77
|
+
'recording:chunk': (payload: RecordingChunkPayload) => void;
|
|
78
|
+
'recording:segment-started': (payload: SegmentStartedPayload) => void;
|
|
79
|
+
'recording:segment-ended': (payload: SegmentEndedPayload) => void;
|
|
80
|
+
'recording:error': (payload: {
|
|
81
|
+
message: string;
|
|
82
|
+
}) => void;
|
|
83
|
+
}
|
|
84
|
+
export interface AdminServerToClientEvents extends ServerToClientEvents, NoticeToClientEvents, ReadingServerToClientEvents, UserServerToClientEvents, MonitorServerToClientEvents, RecordingServerToClientEvents {
|
|
73
85
|
}
|