@uniai-fe/uds-templates 0.6.25 → 0.6.27

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.
@@ -1,5 +1,4 @@
1
1
  import type { API_Res_Base } from "@uniai-fe/util-api";
2
- import type { NextRequest } from "next/server";
3
2
 
4
3
  /**
5
4
  * CCTV; api getCompanyList params
@@ -298,7 +297,6 @@ export type API_Res_CctvCompany = API_Res_Base<API_Res_CctvCompanyData>;
298
297
  * @property {string} company_id 업체 id코드
299
298
  * @property {string} cam_id 카메라 id코드
300
299
  * @property {string} username 사용자 계정 아이디
301
- * @property {string} [password] 사용자 계정 비밀번호. 생략 시 서버 route에서 tokenPreset.password 또는 username fallback을 사용
302
300
  */
303
301
  export interface API_Req_CctvRtcToken {
304
302
  /**
@@ -313,54 +311,6 @@ export interface API_Req_CctvRtcToken {
313
311
  * 사용자 계정 아이디
314
312
  */
315
313
  username: string;
316
- /**
317
- * 사용자 계정 비밀번호
318
- * - 서버 route에서 tokenPreset.password 또는 username fallback을 사용하는 경우 생략 가능
319
- */
320
- password?: string;
321
- }
322
-
323
- /**
324
- * CCTV; 실시간 스트리밍 토큰 요청 (백엔드 요청)
325
- * @property {string} site company_id 맵핑 (ex. farm102)
326
- * @property {string} username 사용자 계정 아이디
327
- * @property {string} password 사용자 계정 비밀번호
328
- * @property {string} action "read"
329
- * @property {string} path cam_id 맵핑 (ex. cam3)
330
- * @property {number} ttl_seconds 시간? (default 300)
331
- * @property {string} kid "streaming-auth-1"
332
- */
333
- export interface API_Req_CctvRtcTokenOrigin {
334
- /**
335
- * company_id 맵핑
336
- * ex) farm102
337
- */
338
- site: string;
339
- /**
340
- * 사용자 계정 아이디
341
- */
342
- username: string;
343
- /**
344
- * 사용자 계정 비밀번호
345
- */
346
- password: string;
347
- /**
348
- * "read"
349
- */
350
- action: string;
351
- /**
352
- * cam_id 맵핑
353
- * ex) cam3
354
- */
355
- path: string;
356
- /**
357
- * default) 300
358
- */
359
- ttl_seconds: number;
360
- /**
361
- * "streaming-auth-1"
362
- */
363
- kid: string;
364
314
  }
365
315
 
366
316
  /**
@@ -411,47 +361,3 @@ export interface API_Req_CctvStreamToken {
411
361
  */
412
362
  cam_id: string;
413
363
  }
414
-
415
- /**
416
- * CCTV; 서버 토큰 요청 파라미터
417
- * @property {string} domain API 요청 도메인(서버)
418
- * @property {string} routeUrl Next.js app/api 이하 경로 url
419
- * @property {string} [queryUrl] 백엔드 요청 url
420
- * @property {string} username 사용자 아이디
421
- * @property {string} company_id 업체 id코드(site)
422
- * @property {string} cam_id 카메라 id코드
423
- * @property {string} [password] 서버 route에서 주입할 사용자 비밀번호
424
- * @property {number} [ttl_seconds] 토큰 만료시간
425
- * @property {string} [kid] 키 id
426
- * @property {Record<string, string>} [headers] 추가 요청 헤더
427
- */
428
- export type API_Req_CctvTokenPreset = Partial<
429
- Pick<API_Req_CctvRtcTokenOrigin, "password" | "ttl_seconds" | "kid">
430
- >;
431
-
432
- export interface API_Req_GetCctvTokenParams {
433
- /**
434
- * API 도메인
435
- */
436
- domain: string;
437
- /**
438
- * Next.js /app/api 라우트 주소
439
- */
440
- routeUrl: string;
441
- /**
442
- * 백엔드 요청 url
443
- */
444
- queryUrl?: string;
445
- /**
446
- * Next.js API 요청 body
447
- */
448
- req: NextRequest;
449
- /**
450
- * 추가 요청 헤더
451
- */
452
- headers?: Record<string, string>;
453
- /**
454
- * 서버 route에서 주입할 CCTV 토큰 요청 preset
455
- */
456
- tokenPreset?: API_Req_CctvTokenPreset;
457
- }
@@ -55,6 +55,22 @@ export interface CctvApiUrlContext {
55
55
  tokenUrl?: string;
56
56
  }
57
57
 
58
+ /**
59
+ * CCTV; RTC stream lazy loading 옵션
60
+ * @property {number} [batchSize] 한 번에 token/WHEP 시작 권한을 받을 stream 개수 (default: 4)
61
+ * @property {number} [batchIntervalMs] 다음 batch 시작까지 대기할 시간(ms) (default: 1200)
62
+ */
63
+ export interface CctvRtcStreamOptions {
64
+ /**
65
+ * 한 번에 token/WHEP 시작 권한을 받을 stream 개수
66
+ */
67
+ batchSize?: number;
68
+ /**
69
+ * 다음 batch 시작까지 대기할 시간(ms)
70
+ */
71
+ batchIntervalMs?: number;
72
+ }
73
+
58
74
  /**
59
75
  * CCTV; 실시간 영상보기 컨텍스트
60
76
  * @property {string} [company_id] 선택된 업체 id코드
@@ -125,6 +141,7 @@ export type CctvContext<ContextExtension extends object = object> =
125
141
  * @property {string} [username] CCTV 조회시 권한 확인을 위한 계정명
126
142
  * @property {string} [whepUsername] WHEP endpoint username 덮어쓰기 값
127
143
  * @property {ContextExtension} [defaultValues] 서비스 확장 context 기본값
144
+ * @property {CctvRtcStreamOptions} [streamOptions] stream lazy loading 옵션
128
145
  * @property {React.ReactNode} children
129
146
  */
130
147
  export type CctvProviderProps<ContextExtension extends object = object> =
@@ -142,6 +159,10 @@ export type CctvProviderProps<ContextExtension extends object = object> =
142
159
  * 서비스 확장 context 기본값
143
160
  */
144
161
  defaultValues?: ContextExtension;
162
+ /**
163
+ * stream lazy loading 옵션
164
+ */
165
+ streamOptions?: CctvRtcStreamOptions;
145
166
  /**
146
167
  * Provider 하위 콘텐츠
147
168
  */
@@ -20,6 +20,24 @@ export type CctvRtcReconnectTrigger = (
20
20
  options?: RefetchOptions,
21
21
  ) => Promise<QueryObserverResult<API_Res_CctvRtcToken>>;
22
22
 
23
+ /**
24
+ * CCTV; RTC stream scheduler 상태
25
+ */
26
+ export type CctvRtcStreamScheduleStatus = "idle" | "queued" | "granted";
27
+
28
+ /**
29
+ * CCTV; RTC stream 표시 단계
30
+ */
31
+ export type CctvRtcStreamStage =
32
+ | "idle"
33
+ | "queued"
34
+ | "token-loading"
35
+ | "connecting"
36
+ | "live"
37
+ | "recovering"
38
+ | "error"
39
+ | "skipped-offline";
40
+
23
41
  /**
24
42
  * CCTV; useCctvRtcStream params
25
43
  * @property {CctvCompanyCameraData} [cam] 스트리밍 카메라 정보
@@ -64,6 +82,7 @@ export interface UseCctvRtcStreamError {
64
82
  * @property {boolean} isTokenLoading UI 표시 기준 토큰 발급 요청 진행 여부
65
83
  * @property {boolean} isTokenError 토큰 발급 실패 여부
66
84
  * @property {string | null} streamError 스트림 오류 메시지
85
+ * @property {CctvRtcStreamStage} streamStage stream 표시 단계
67
86
  */
68
87
  export interface UseCctvRtcStreamState extends UseCctvRtcStreamError {
69
88
  /**
@@ -88,6 +107,10 @@ export interface UseCctvRtcStreamState extends UseCctvRtcStreamError {
88
107
  * 재발급 중에는 기존 화면과 live count를 유지하기 위해 false로 smoothing될 수 있다.
89
108
  */
90
109
  isTokenLoading: boolean;
110
+ /**
111
+ * stream 표시 단계
112
+ */
113
+ streamStage: CctvRtcStreamStage;
91
114
  }
92
115
 
93
116
  /**
@@ -98,6 +121,7 @@ export interface UseCctvRtcStreamState extends UseCctvRtcStreamError {
98
121
  * @property {boolean} isStreaming UI 표시 기준 startWhepStream 진행 여부
99
122
  * @property {boolean} isTokenLoading UI 표시 기준 토큰 발급 요청 진행 여부
100
123
  * @property {boolean} isTokenError 토큰 발급 실패 여부
124
+ * @property {CctvRtcStreamStage} streamStage stream 표시 단계
101
125
  * @property {boolean} canReconnect UDS 내부 허용 사유와 grace/stagger를 통과해 재연결 호출이 가능한지 여부
102
126
  * @property {() => Promise<void>} refetchToken 토큰 재발급 함수
103
127
  * @property {() => Promise<QueryObserverResult<API_Res_CctvRtcToken>>} reconnectStream 재연결 trigger 함수
@@ -1,5 +1,5 @@
1
1
  import type { CctvCompanyCameraData, CctvCompanyCameraList } from "./list";
2
- import type { CctvRtcReconnectTrigger } from "./hook";
2
+ import type { CctvRtcReconnectTrigger, CctvRtcStreamStage } from "./hook";
3
3
 
4
4
  /**
5
5
  * CCTV; custom overlay render context
@@ -9,6 +9,7 @@ import type { CctvRtcReconnectTrigger } from "./hook";
9
9
  * @property {boolean | undefined} [isError] 영상 에러 상태 여부
10
10
  * @property {boolean | undefined} [isLive] 영상 live 상태 여부
11
11
  * @property {React.ReactNode} [overlayMessage] 기본 안내/에러 메시지 콘텐츠
12
+ * @property {CctvRtcStreamStage | undefined} [streamStage] stream 표시 단계
12
13
  * @property {boolean | undefined} [canReconnect] UDS 내부 허용 사유와 grace/stagger를 통과해 재연결 호출이 가능한지 여부
13
14
  * @property {CctvRtcReconnectTrigger | undefined} [reconnectStream] 재연결 trigger 함수
14
15
  */
@@ -37,6 +38,10 @@ export interface CctvVideoRenderOverlayContext {
37
38
  * 기본 안내/에러 메시지 콘텐츠
38
39
  */
39
40
  overlayMessage?: React.ReactNode;
41
+ /**
42
+ * stream 표시 단계
43
+ */
44
+ streamStage?: CctvRtcStreamStage;
40
45
  /**
41
46
  * UDS 내부 허용 사유와 grace/stagger를 통과해 재연결 호출이 가능한지 여부
42
47
  * @desc
@@ -130,6 +135,7 @@ export interface CctvVideoOverlayFooterProps {
130
135
  * @property {boolean} [isError] 에러 상태 여부
131
136
  * @property {boolean} [isLive] 영상이 정상적으로 재생 중인지 여부
132
137
  * @property {React.ReactNode} [overlayMessage] 에러/안내 메시지 콘텐츠
138
+ * @property {CctvRtcStreamStage} [streamStage] stream 표시 단계
133
139
  * @property {boolean} [canReconnect] UDS 내부 허용 사유와 grace/stagger를 통과해 재연결 호출이 가능한지 여부
134
140
  * @property {CctvRtcReconnectTrigger} [reconnectStream] 재연결 trigger 함수
135
141
  */
@@ -146,6 +152,10 @@ export interface CctvVideoStateProps {
146
152
  * 오버레이 메시지 콘텐츠
147
153
  */
148
154
  overlayMessage?: React.ReactNode;
155
+ /**
156
+ * stream 표시 단계
157
+ */
158
+ streamStage?: CctvRtcStreamStage;
149
159
  /**
150
160
  * UDS 내부 허용 사유와 grace/stagger를 통과해 재연결 호출이 가능한지 여부
151
161
  */
@@ -164,6 +174,7 @@ export interface CctvVideoStateProps {
164
174
  * @property {boolean} [isError] 에러 상태 여부
165
175
  * @property {boolean} [isLive] 영상이 정상적으로 재생 중인지 여부
166
176
  * @property {React.ReactNode} [overlayMessage] 에러/안내 메시지 콘텐츠
177
+ * @property {CctvRtcStreamStage} [streamStage] stream 표시 단계
167
178
  * @property {CctvVideoRenderOverlay} [renderOverlay] custom overlay 렌더 함수
168
179
  */
169
180
  export interface CctvVideoTemplateProps extends CctvVideoStateProps {
@@ -1,5 +1,9 @@
1
1
  import type { CctvCompanyCameraData } from "./list";
2
- import type { UseCctvRtcStreamError, UseCctvRtcStreamState } from "./hook";
2
+ import type {
3
+ CctvRtcStreamStage,
4
+ UseCctvRtcStreamError,
5
+ UseCctvRtcStreamState,
6
+ } from "./hook";
3
7
 
4
8
  /**
5
9
  * CCTV; getOverlayMessage() params
@@ -11,10 +15,14 @@ import type { UseCctvRtcStreamError, UseCctvRtcStreamState } from "./hook";
11
15
  * @property {boolean} isTokenLoading UI 표시 기준 토큰 발급 요청 진행 여부
12
16
  * @property {boolean} isTokenError 토큰 발급 실패 여부
13
17
  * @property {string | null} streamError 스트림 오류 메시지
18
+ * @property {CctvRtcStreamStage} [streamStage] stream 표시 단계
14
19
  * @property {boolean} [canReconnect] UDS 내부 허용 사유와 grace/stagger를 통과해 재연결 호출이 가능한지 여부.
15
20
  * 오류 스타일 판정에는 직접 사용하지 않는다.
16
21
  */
17
- export interface CctvVideoOverlayMessageParams extends UseCctvRtcStreamState {
22
+ export interface CctvVideoOverlayMessageParams extends Omit<
23
+ UseCctvRtcStreamState,
24
+ "streamStage"
25
+ > {
18
26
  /**
19
27
  * 카메라 데이터
20
28
  */
@@ -27,6 +35,10 @@ export interface CctvVideoOverlayMessageParams extends UseCctvRtcStreamState {
27
35
  * 서버에서 cam 리스트를 가져오는 중인지 여부
28
36
  */
29
37
  isFetching?: boolean;
38
+ /**
39
+ * stream 표시 단계
40
+ */
41
+ streamStage?: CctvRtcStreamStage;
30
42
  /**
31
43
  * UDS 내부 허용 사유와 grace/stagger를 통과해 재연결 호출이 가능한지 여부
32
44
  * @desc
@@ -44,7 +56,10 @@ export interface CctvVideoOverlayMessageParams extends UseCctvRtcStreamState {
44
56
  * @property {boolean} isTokenError 토큰 발급 실패 여부
45
57
  * @property {string | null} streamError 스트림 오류 메시지
46
58
  */
47
- export interface CctvVideoLiveParams extends UseCctvRtcStreamState {
59
+ export interface CctvVideoLiveParams extends Omit<
60
+ UseCctvRtcStreamState,
61
+ "streamStage"
62
+ > {
48
63
  /**
49
64
  * 카메라 데이터
50
65
  */
@@ -7,6 +7,7 @@ import type {
7
7
  export const CCTV_MESSAGE = {
8
8
  selectCam: "카메라를 선택하세요.",
9
9
  fetching: "CCTV 데이터를 불러오는 중입니다.",
10
+ queued: "CCTV 연결 순서를 기다리고 있습니다.",
10
11
  preparing: "CCTV 영상을 연결하고 있습니다.",
11
12
  sessionEnded:
12
13
  "장시간 미사용으로 연결이 종료되었습니다. 계속 확인하시려면 다시 연결해 주세요.",
@@ -47,6 +48,7 @@ export function getOverlayMessage({
47
48
  isTokenLoading,
48
49
  isTokenError,
49
50
  isStreaming,
51
+ streamStage,
50
52
  streamError,
51
53
  }: CctvVideoOverlayMessageParams): string | null {
52
54
  if (!cam) {
@@ -62,6 +64,7 @@ export function getOverlayMessage({
62
64
  if (canReconnect && RTC_SESSION_ENDED_RECONNECT_STATES.has(connectionState)) {
63
65
  return CCTV_MESSAGE.sessionEnded;
64
66
  }
67
+ if (streamStage === "queued") return CCTV_MESSAGE.queued;
65
68
  // raw disconnected는 useCctvRtcStream에서 post-connected connected로 smoothing한다.
66
69
  if (isTokenLoading || isStreaming) return CCTV_MESSAGE.preparing;
67
70
  if (RTC_PREPARING_STATES.has(connectionState)) return CCTV_MESSAGE.preparing;