@rencar-dev/feature-modules-public 0.0.7

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/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # @rencar-dev/feature-modules-public
2
+
3
+ Rencar 기능 모듈 모음 - hooks, utils, UI 컴포넌트 등을 포함합니다.
4
+
5
+ ## 설치
6
+
7
+ ```bash
8
+ npm install @rencar-dev/feature-modules-public
9
+ # 또는
10
+ yarn add @rencar-dev/feature-modules-public
11
+ ```
12
+
13
+ ## 사용법
14
+
15
+ ```typescript
16
+ // hooks 모듈 가져오기
17
+ import { useExample } from "@rencar-dev/feature-modules-public/hooks";
18
+
19
+ function MyComponent() {
20
+ const { count, increment, decrement, reset } = useExample(0);
21
+
22
+ return (
23
+ <div>
24
+ <p>Count: {count}</p>
25
+ <button onClick={increment}>+</button>
26
+ <button onClick={decrement}>-</button>
27
+ <button onClick={reset}>Reset</button>
28
+ </div>
29
+ );
30
+ }
31
+ ```
32
+
33
+ ## Presence 모듈
34
+
35
+ 실시간 사용자 프레즌스(현재 접속자) 기능을 위한 모듈입니다.
36
+
37
+ ### Socket 초기화
38
+
39
+ 프레즌스 훅을 사용하기 전에 반드시 소켓을 초기화해야 합니다.
40
+
41
+ #### initPresenceSocket
42
+
43
+ 소켓 연결을 설정합니다. **앱 시작 시 1회 호출**해야 합니다.
44
+
45
+ ```tsx
46
+ import { initPresenceSocket } from "@rencar-dev/feature-modules-public/presence";
47
+
48
+ // 앱 초기화 시 (예: App.tsx 또는 index.tsx)
49
+ initPresenceSocket({
50
+ url: "https://your-socket-server.com",
51
+ transports: ["websocket"], // 선택사항, 기본값: ["websocket"]
52
+ });
53
+ ```
54
+
55
+ **PresenceConfig:**
56
+
57
+ | 옵션 | 타입 | 필수 | 기본값 | 설명 |
58
+ | ------------ | ------------------------------ | ---- | --------------- | ------------- |
59
+ | `url` | `string` | ✅ | - | 소켓 서버 URL |
60
+ | `transports` | `("websocket" \| "polling")[]` | - | `["websocket"]` | 전송 방식 |
61
+
62
+ ---
63
+
64
+ #### getPresenceSocket
65
+
66
+ 공유 소켓 인스턴스를 반환합니다. 초기화되지 않은 경우 에러를 발생시킵니다.
67
+
68
+ ```tsx
69
+ import { getPresenceSocket } from "@rencar-dev/feature-modules-public/presence";
70
+
71
+ const socket = getPresenceSocket();
72
+ socket.emit("custom-event", { data: "example" });
73
+ ```
74
+
75
+ ---
76
+
77
+ #### disconnectPresenceSocket
78
+
79
+ 소켓 연결을 종료하고 정리합니다. 앱 종료 시 또는 로그아웃 시 호출할 수 있습니다.
80
+
81
+ ```tsx
82
+ import { disconnectPresenceSocket } from "@rencar-dev/feature-modules-public/presence";
83
+
84
+ // 로그아웃 시
85
+ function handleLogout() {
86
+ disconnectPresenceSocket();
87
+ // ... 기타 로그아웃 로직
88
+ }
89
+ ```
90
+
91
+ ---
92
+
93
+ #### isPresenceSocketInitialized
94
+
95
+ 소켓 초기화 여부를 확인합니다.
96
+
97
+ ```tsx
98
+ import { isPresenceSocketInitialized } from "@rencar-dev/feature-modules-public/presence";
99
+
100
+ if (!isPresenceSocketInitialized()) {
101
+ initPresenceSocket({ url: "..." });
102
+ }
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Presence Hooks
108
+
109
+ 실시간 사용자 프레즌스(현재 접속자) 기능을 위한 훅입니다.
110
+
111
+ ### usePresence
112
+
113
+ 특정 룸에 참여하고 해당 룸의 사용자 목록을 추적합니다. 현재 사용자가 해당 룸에 참여자로 등록됩니다.
114
+
115
+ **Options:**
116
+
117
+ | 옵션 | 타입 | 필수 | 기본값 | 설명 |
118
+ | ------------------- | -------------- | ---- | --------------- | -------------------------------------------------- |
119
+ | `roomId` | `string` | ✅ | - | 참여할 룸 ID |
120
+ | `currentUser` | `PresenceUser` | ✅ | - | 현재 사용자 정보 (`{ userId, name, ...추가속성 }`) |
121
+ | `enabled` | `boolean` | - | `true` | 훅 활성화 여부 |
122
+ | `heartbeatInterval` | `number` | - | `600000` (10분) | 하트비트 간격 (ms) |
123
+
124
+ **Returns:** `PresenceUser[]` - 현재 룸에 있는 사용자 목록
125
+
126
+ **사용 예시:**
127
+
128
+ ```tsx
129
+ import { usePresence } from "@rencar-dev/feature-modules-public/presence";
130
+
131
+ function MyPage() {
132
+ const users = usePresence({
133
+ roomId: "my-app:page-123",
134
+ currentUser: { userId: "1", name: "John Doe" },
135
+ });
136
+
137
+ return (
138
+ <div>
139
+ <p>현재 접속자: {users.length}명</p>
140
+ <ul>
141
+ {users.map((user) => (
142
+ <li key={user.userId}>{user.name}</li>
143
+ ))}
144
+ </ul>
145
+ </div>
146
+ );
147
+ }
148
+ ```
149
+
150
+ **조건부 활성화:**
151
+
152
+ ```tsx
153
+ // 로그인한 경우에만 프레즌스 활성화
154
+ const users = usePresence({
155
+ roomId: "my-room",
156
+ currentUser: { userId: user.id, name: user.name },
157
+ enabled: isLoggedIn,
158
+ });
159
+ ```
160
+
161
+ ---
162
+
163
+ ### usePresenceWatch
164
+
165
+ 여러 룸을 **참여 없이** 관찰(watch)합니다. 읽기 전용으로 다른 룸들의 접속자를 모니터링할 때 사용합니다.
166
+
167
+ **Options:**
168
+
169
+ | 옵션 | 타입 | 필수 | 기본값 | 설명 |
170
+ | --------- | ---------- | ---- | ------ | ----------------- |
171
+ | `roomIds` | `string[]` | ✅ | - | 관찰할 룸 ID 배열 |
172
+ | `enabled` | `boolean` | - | `true` | 훅 활성화 여부 |
173
+
174
+ **Returns:** `Record<string, PresenceUser[]>` - 룸 ID → 사용자 목록 맵
175
+
176
+ **사용 예시:**
177
+
178
+ ```tsx
179
+ import { usePresenceWatch } from "@rencar-dev/feature-modules-public/presence";
180
+
181
+ function Dashboard() {
182
+ const roomsUsers = usePresenceWatch({
183
+ roomIds: ["page-1", "page-2", "page-3"],
184
+ });
185
+
186
+ return (
187
+ <div>
188
+ {Object.entries(roomsUsers).map(([roomId, users]) => (
189
+ <div key={roomId}>
190
+ <h3>{roomId}</h3>
191
+ <p>{users.length}명 접속 중</p>
192
+ </div>
193
+ ))}
194
+ </div>
195
+ );
196
+ }
197
+ ```
198
+
199
+ **동적 룸 ID:**
200
+
201
+ ```tsx
202
+ // 룸 ID가 변경되면 자동으로 watch/unwatch 처리
203
+ const [selectedRooms, setSelectedRooms] = useState(["room-a"]);
204
+ const roomsUsers = usePresenceWatch({ roomIds: selectedRooms });
205
+ ```
206
+
207
+ ---
208
+
209
+ ### usePresence vs usePresenceWatch 비교
210
+
211
+ | 항목 | usePresence | usePresenceWatch |
212
+ | ----------- | -------------------------------- | ----------------------------- |
213
+ | **룸 참여** | ✅ 참여함 (다른 사용자에게 보임) | ❌ 참여 안함 (관찰만) |
214
+ | **룸 개수** | 1개 | 여러 개 |
215
+ | **용도** | 현재 페이지 접속자 표시 | 대시보드에서 여러 룸 모니터링 |
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/hooks/index.ts
21
+ var hooks_exports = {};
22
+ __export(hooks_exports, {
23
+ useExample: () => useExample
24
+ });
25
+ module.exports = __toCommonJS(hooks_exports);
26
+
27
+ // src/hooks/useExample.ts
28
+ var import_react = require("react");
29
+ function useExample(initialValue = 0) {
30
+ const [count, setCount] = (0, import_react.useState)(initialValue);
31
+ const increment = (0, import_react.useCallback)(() => {
32
+ setCount((prev) => prev + 1);
33
+ }, []);
34
+ const decrement = (0, import_react.useCallback)(() => {
35
+ setCount((prev) => prev - 1);
36
+ }, []);
37
+ const reset = (0, import_react.useCallback)(() => {
38
+ setCount(initialValue);
39
+ }, [initialValue]);
40
+ return {
41
+ count,
42
+ increment,
43
+ decrement,
44
+ reset
45
+ };
46
+ }
47
+ // Annotate the CommonJS export names for ESM import in node:
48
+ 0 && (module.exports = {
49
+ useExample
50
+ });
51
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/index.ts","../../src/hooks/useExample.ts"],"sourcesContent":["/**\n * hooks 모듈 진입점\n * 모든 hook을 여기서 re-export 합니다.\n */\n\nexport { useExample } from \"./useExample\";\n","import { useState, useCallback } from \"react\";\n\n/**\n * 예시 hook - 카운터 기능\n * 이 파일은 구조 예시용입니다. 삭제하거나 수정해서 사용하세요.\n *\n * @example\n * const { count, increment, decrement, reset } = useExample(0);\n */\nexport function useExample(initialValue: number = 0) {\n const [count, setCount] = useState(initialValue);\n\n const increment = useCallback(() => {\n setCount((prev) => prev + 1);\n }, []);\n\n const decrement = useCallback(() => {\n setCount((prev) => prev - 1);\n }, []);\n\n const reset = useCallback(() => {\n setCount(initialValue);\n }, [initialValue]);\n\n return {\n count,\n increment,\n decrement,\n reset,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAsC;AAS/B,SAAS,WAAW,eAAuB,GAAG;AACnD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,YAAY;AAE/C,QAAM,gBAAY,0BAAY,MAAM;AAClC,aAAS,CAAC,SAAS,OAAO,CAAC;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAY,0BAAY,MAAM;AAClC,aAAS,CAAC,SAAS,OAAO,CAAC;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,YAAQ,0BAAY,MAAM;AAC9B,aAAS,YAAY;AAAA,EACvB,GAAG,CAAC,YAAY,CAAC;AAEjB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 예시 hook - 카운터 기능
3
+ * 이 파일은 구조 예시용입니다. 삭제하거나 수정해서 사용하세요.
4
+ *
5
+ * @example
6
+ * const { count, increment, decrement, reset } = useExample(0);
7
+ */
8
+ declare function useExample(initialValue?: number): {
9
+ count: number;
10
+ increment: () => void;
11
+ decrement: () => void;
12
+ reset: () => void;
13
+ };
14
+
15
+ export { useExample };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 예시 hook - 카운터 기능
3
+ * 이 파일은 구조 예시용입니다. 삭제하거나 수정해서 사용하세요.
4
+ *
5
+ * @example
6
+ * const { count, increment, decrement, reset } = useExample(0);
7
+ */
8
+ declare function useExample(initialValue?: number): {
9
+ count: number;
10
+ increment: () => void;
11
+ decrement: () => void;
12
+ reset: () => void;
13
+ };
14
+
15
+ export { useExample };
@@ -0,0 +1,24 @@
1
+ // src/hooks/useExample.ts
2
+ import { useState, useCallback } from "react";
3
+ function useExample(initialValue = 0) {
4
+ const [count, setCount] = useState(initialValue);
5
+ const increment = useCallback(() => {
6
+ setCount((prev) => prev + 1);
7
+ }, []);
8
+ const decrement = useCallback(() => {
9
+ setCount((prev) => prev - 1);
10
+ }, []);
11
+ const reset = useCallback(() => {
12
+ setCount(initialValue);
13
+ }, [initialValue]);
14
+ return {
15
+ count,
16
+ increment,
17
+ decrement,
18
+ reset
19
+ };
20
+ }
21
+ export {
22
+ useExample
23
+ };
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/useExample.ts"],"sourcesContent":["import { useState, useCallback } from \"react\";\n\n/**\n * 예시 hook - 카운터 기능\n * 이 파일은 구조 예시용입니다. 삭제하거나 수정해서 사용하세요.\n *\n * @example\n * const { count, increment, decrement, reset } = useExample(0);\n */\nexport function useExample(initialValue: number = 0) {\n const [count, setCount] = useState(initialValue);\n\n const increment = useCallback(() => {\n setCount((prev) => prev + 1);\n }, []);\n\n const decrement = useCallback(() => {\n setCount((prev) => prev - 1);\n }, []);\n\n const reset = useCallback(() => {\n setCount(initialValue);\n }, [initialValue]);\n\n return {\n count,\n increment,\n decrement,\n reset,\n };\n}\n"],"mappings":";AAAA,SAAS,UAAU,mBAAmB;AAS/B,SAAS,WAAW,eAAuB,GAAG;AACnD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,YAAY;AAE/C,QAAM,YAAY,YAAY,MAAM;AAClC,aAAS,CAAC,SAAS,OAAO,CAAC;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,YAAY,YAAY,MAAM;AAClC,aAAS,CAAC,SAAS,OAAO,CAAC;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,YAAY,MAAM;AAC9B,aAAS,YAAY;AAAA,EACvB,GAAG,CAAC,YAAY,CAAC;AAEjB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}