@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 +215 -0
- package/dist/hooks/index.cjs +51 -0
- package/dist/hooks/index.cjs.map +1 -0
- package/dist/hooks/index.d.cts +15 -0
- package/dist/hooks/index.d.ts +15 -0
- package/dist/hooks/index.js +24 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/presence/index.cjs +459 -0
- package/dist/presence/index.cjs.map +1 -0
- package/dist/presence/index.d.cts +231 -0
- package/dist/presence/index.d.ts +231 -0
- package/dist/presence/index.js +425 -0
- package/dist/presence/index.js.map +1 -0
- package/package.json +73 -0
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":[]}
|