@simplysm/core-common 14.0.47 → 14.0.49
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 +255 -0
- package/dist/utils/transferable.d.ts.map +1 -1
- package/dist/utils/transferable.js +7 -3
- package/dist/utils/transferable.js.map +1 -1
- package/docs/errors.md +82 -0
- package/docs/extensions.md +167 -0
- package/docs/features.md +136 -0
- package/docs/types.md +245 -0
- package/docs/utils.md +591 -0
- package/package.json +4 -3
- package/src/utils/transferable.ts +8 -3
package/docs/features.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Features
|
|
2
|
+
|
|
3
|
+
## `EventEmitter<TEvents>`
|
|
4
|
+
|
|
5
|
+
EventTarget 기반의 타입 안전한 이벤트 이미터. 브라우저와 Node.js 모두에서 사용 가능하다.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export class EventEmitter<
|
|
9
|
+
TEvents extends { [K in keyof TEvents]: unknown } = Record<string, unknown>,
|
|
10
|
+
> {
|
|
11
|
+
on<TEventName extends keyof TEvents & string>(
|
|
12
|
+
type: TEventName,
|
|
13
|
+
listener: (data: TEvents[TEventName]) => void,
|
|
14
|
+
): void;
|
|
15
|
+
|
|
16
|
+
off<TEventName extends keyof TEvents & string>(
|
|
17
|
+
type: TEventName,
|
|
18
|
+
listener: (data: TEvents[TEventName]) => void,
|
|
19
|
+
): void;
|
|
20
|
+
|
|
21
|
+
emit<TEventName extends keyof TEvents & string>(
|
|
22
|
+
type: TEventName,
|
|
23
|
+
...args: TEvents[TEventName] extends void ? [] : [data: TEvents[TEventName]]
|
|
24
|
+
): void;
|
|
25
|
+
|
|
26
|
+
listenerCount<TEventName extends keyof TEvents & string>(type: TEventName): number;
|
|
27
|
+
|
|
28
|
+
dispose(): void;
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 메서드
|
|
33
|
+
|
|
34
|
+
| Method | Description |
|
|
35
|
+
|--------|-------------|
|
|
36
|
+
| `on(type, listener)` | 이벤트 리스너 등록. 같은 리스너를 같은 이벤트에 중복 등록하면 무시됨 |
|
|
37
|
+
| `off(type, listener)` | 이벤트 리스너 제거 |
|
|
38
|
+
| `emit(type, data?)` | 이벤트 발행. `void` 타입 이벤트는 인자 없이 호출 |
|
|
39
|
+
| `listenerCount(type)` | 특정 이벤트의 등록된 리스너 수 반환 |
|
|
40
|
+
| `dispose()` | 모든 이벤트 리스너 제거 |
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
interface MyEvents {
|
|
44
|
+
data: string;
|
|
45
|
+
error: Error;
|
|
46
|
+
done: void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class MyService extends EventEmitter<MyEvents> {}
|
|
50
|
+
|
|
51
|
+
const svc = new MyService();
|
|
52
|
+
svc.on("data", (data) => console.log(data)); // data: string
|
|
53
|
+
svc.emit("data", "hello");
|
|
54
|
+
svc.emit("done"); // void 타입은 인자 없이 호출
|
|
55
|
+
svc.dispose(); // 모든 리스너 정리
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## `DebounceQueue`
|
|
61
|
+
|
|
62
|
+
짧은 시간 내에 여러 번 호출되면 마지막 요청만 실행하는 비동기 디바운스 큐.
|
|
63
|
+
|
|
64
|
+
`EventEmitter<{ error: SdError }>`를 상속한다. 에러 리스너가 없으면 `consola`로 로그 출력한다.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
export class DebounceQueue extends EventEmitter<{ error: SdError }> {
|
|
68
|
+
constructor(delay?: number);
|
|
69
|
+
|
|
70
|
+
run(fn: () => void | Promise<void>): void;
|
|
71
|
+
|
|
72
|
+
override dispose(): void;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
| Parameter | Type | Description |
|
|
77
|
+
|-----------|------|-------------|
|
|
78
|
+
| `delay` | `number \| undefined` | 디바운스 지연 시간 (ms). 생략 시 즉시 실행 (다음 이벤트 루프) |
|
|
79
|
+
|
|
80
|
+
실행 중에 추가된 요청은 디바운스 지연 없이 현재 실행 완료 직후 즉시 처리된다.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const dq = new DebounceQueue(300);
|
|
84
|
+
dq.on("error", (err) => console.error(err));
|
|
85
|
+
dq.run(() => console.log("1")); // 무시됨
|
|
86
|
+
dq.run(() => console.log("2")); // 무시됨
|
|
87
|
+
dq.run(() => console.log("3")); // 300ms 후 실행
|
|
88
|
+
|
|
89
|
+
// 자원 정리
|
|
90
|
+
const dq2 = new DebounceQueue(100);
|
|
91
|
+
try {
|
|
92
|
+
dq2.run(() => { /* ... */ });
|
|
93
|
+
} finally {
|
|
94
|
+
dq2.dispose();
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## `SerialQueue`
|
|
101
|
+
|
|
102
|
+
큐에 추가된 함수들을 순차적으로 실행하는 비동기 직렬 큐. 하나의 작업이 완료된 후에야 다음 작업이 시작된다. 에러가 발생해도 후속 작업은 계속 실행된다.
|
|
103
|
+
|
|
104
|
+
`EventEmitter<{ error: SdError }>`를 상속한다. 에러 리스너가 없으면 `consola`로 로그 출력한다.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
export class SerialQueue extends EventEmitter<{ error: SdError }> {
|
|
108
|
+
constructor(gap?: number);
|
|
109
|
+
|
|
110
|
+
run(fn: () => void | Promise<void>): void;
|
|
111
|
+
|
|
112
|
+
override dispose(): void;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| Parameter | Type | Description |
|
|
117
|
+
|-----------|------|-------------|
|
|
118
|
+
| `gap` | `number` | 각 작업 사이의 간격 (ms). 기본값: 0 |
|
|
119
|
+
|
|
120
|
+
`dispose()`는 대기 중인 큐를 비운다 (현재 실행 중인 작업은 완료됨).
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const sq = new SerialQueue();
|
|
124
|
+
sq.on("error", (err) => console.error(err));
|
|
125
|
+
sq.run(async () => await fetch("/api/1"));
|
|
126
|
+
sq.run(async () => await fetch("/api/2")); // 1 완료 후 실행
|
|
127
|
+
sq.run(async () => await fetch("/api/3")); // 2 완료 후 실행
|
|
128
|
+
|
|
129
|
+
// 100ms 간격으로 실행, 자원 정리
|
|
130
|
+
const sq2 = new SerialQueue(100);
|
|
131
|
+
try {
|
|
132
|
+
sq2.run(async () => { /* ... */ });
|
|
133
|
+
} finally {
|
|
134
|
+
sq2.dispose();
|
|
135
|
+
}
|
|
136
|
+
```
|
package/docs/types.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Types (Value Objects)
|
|
2
|
+
|
|
3
|
+
## `DateTime`
|
|
4
|
+
|
|
5
|
+
불변 날짜시간 클래스. 밀리초 정밀도를 지원하고 로컬 타임존 기준으로 동작한다.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export class DateTime {
|
|
9
|
+
readonly date: Date;
|
|
10
|
+
|
|
11
|
+
constructor();
|
|
12
|
+
constructor(year: number, month: number, day: number, hour?: number, minute?: number, second?: number, millisecond?: number);
|
|
13
|
+
constructor(tick: number);
|
|
14
|
+
constructor(date: Date);
|
|
15
|
+
|
|
16
|
+
static parse(str: string): DateTime;
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 지원 파싱 형식
|
|
21
|
+
|
|
22
|
+
- `yyyy-MM-dd HH:mm:ss`
|
|
23
|
+
- `yyyy-MM-dd HH:mm:ss.fff`
|
|
24
|
+
- `yyyyMMddHHmmss`
|
|
25
|
+
- `yyyy-MM-dd AM/PM HH:mm:ss`
|
|
26
|
+
- `yyyy-MM-dd 오전/오후 HH:mm:ss`
|
|
27
|
+
- ISO 8601
|
|
28
|
+
|
|
29
|
+
### Getters (읽기 전용)
|
|
30
|
+
|
|
31
|
+
| Property | Type | Description |
|
|
32
|
+
|----------|------|-------------|
|
|
33
|
+
| `year` | `number` | 연도 |
|
|
34
|
+
| `month` | `number` | 월 (1-12) |
|
|
35
|
+
| `day` | `number` | 일 |
|
|
36
|
+
| `hour` | `number` | 시 |
|
|
37
|
+
| `minute` | `number` | 분 |
|
|
38
|
+
| `second` | `number` | 초 |
|
|
39
|
+
| `millisecond` | `number` | 밀리초 |
|
|
40
|
+
| `tick` | `number` | Unix 타임스탬프 (ms) |
|
|
41
|
+
| `dayOfWeek` | `number` | 요일 (0=일요일 ~ 6=토요일) |
|
|
42
|
+
| `timezoneOffsetMinutes` | `number` | 타임존 오프셋 (분) |
|
|
43
|
+
| `isValid` | `boolean` | 유효한 날짜시간 여부 |
|
|
44
|
+
|
|
45
|
+
### 불변 변환 메서드 (새 인스턴스 반환)
|
|
46
|
+
|
|
47
|
+
`setYear(year)`, `setMonth(month)`, `setDay(day)`, `setHour(hour)`, `setMinute(minute)`, `setSecond(second)`, `setMillisecond(millisecond)`
|
|
48
|
+
|
|
49
|
+
`addYears(years)`, `addMonths(months)`, `addDays(days)`, `addHours(hours)`, `addMinutes(minutes)`, `addSeconds(seconds)`, `addMilliseconds(milliseconds)`
|
|
50
|
+
|
|
51
|
+
### 포맷 메서드
|
|
52
|
+
|
|
53
|
+
| Method | Description |
|
|
54
|
+
|--------|-------------|
|
|
55
|
+
| `toFormatString(formatStr)` | 형식 문자열로 변환. 형식 패턴은 `dt.format()` 참조 |
|
|
56
|
+
| `toString()` | `"yyyy-MM-ddTHH:mm:ss.fffzzz"` 형식으로 변환 |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## `DateOnly`
|
|
61
|
+
|
|
62
|
+
시간 정보 없이 날짜만 저장하는 불변 클래스.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
export class DateOnly {
|
|
66
|
+
readonly date: Date;
|
|
67
|
+
|
|
68
|
+
constructor();
|
|
69
|
+
constructor(year: number, month: number, day: number);
|
|
70
|
+
constructor(tick: number);
|
|
71
|
+
constructor(date: Date);
|
|
72
|
+
|
|
73
|
+
static parse(str: string): DateOnly;
|
|
74
|
+
static getDateByYearWeekSeq(
|
|
75
|
+
arg: { year: number; month?: number; weekSeq: number },
|
|
76
|
+
weekStartDay?: number,
|
|
77
|
+
minDaysInFirstWeek?: number,
|
|
78
|
+
): DateOnly;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Getters (읽기 전용)
|
|
83
|
+
|
|
84
|
+
| Property | Type | Description |
|
|
85
|
+
|----------|------|-------------|
|
|
86
|
+
| `year` | `number` | 연도 |
|
|
87
|
+
| `month` | `number` | 월 (1-12) |
|
|
88
|
+
| `day` | `number` | 일 |
|
|
89
|
+
| `tick` | `number` | Unix 타임스탬프 (ms) |
|
|
90
|
+
| `dayOfWeek` | `number` | 요일 (0=일요일 ~ 6=토요일) |
|
|
91
|
+
| `isValid` | `boolean` | 유효한 날짜 여부 |
|
|
92
|
+
|
|
93
|
+
### 불변 변환 메서드 (새 인스턴스 반환)
|
|
94
|
+
|
|
95
|
+
`setYear(year)`, `setMonth(month)`, `setDay(day)`
|
|
96
|
+
|
|
97
|
+
`addYears(years)`, `addMonths(months)`, `addDays(days)`
|
|
98
|
+
|
|
99
|
+
### 주차 계산 메서드
|
|
100
|
+
|
|
101
|
+
| Method | Description |
|
|
102
|
+
|--------|-------------|
|
|
103
|
+
| `getBaseYearMonthSeqForWeekSeq(weekStartDay?, minDaysInFirstWeek?)` | 주차 기준 연도와 월 반환 |
|
|
104
|
+
| `getWeekSeqStartDate(weekStartDay?, minDaysInFirstWeek?)` | 해당 주의 시작 날짜 반환 |
|
|
105
|
+
| `getWeekSeqOfYear(weekStartDay?, minDaysInFirstWeek?)` | 연도 내 주차 번호 반환 (`{ year, weekSeq }`) |
|
|
106
|
+
| `getWeekSeqOfMonth(weekStartDay?, minDaysInFirstWeek?)` | 월 내 주차 번호 반환 (`{ year, monthSeq, weekSeq }`) |
|
|
107
|
+
|
|
108
|
+
`weekStartDay` 기본값: 1(월요일). `minDaysInFirstWeek` 기본값: 4 (ISO 8601).
|
|
109
|
+
|
|
110
|
+
### 포맷 메서드
|
|
111
|
+
|
|
112
|
+
| Method | Description |
|
|
113
|
+
|--------|-------------|
|
|
114
|
+
| `toFormatString(formatStr)` | 형식 문자열로 변환 |
|
|
115
|
+
| `toString()` | `"yyyy-MM-dd"` 형식으로 변환 |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## `Time`
|
|
120
|
+
|
|
121
|
+
날짜 정보 없이 시간만 저장하는 불변 클래스. 24시간을 초과하거나 음수인 값은 자동으로 정규화된다.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
export class Time {
|
|
125
|
+
constructor();
|
|
126
|
+
constructor(hour: number, minute: number, second?: number, millisecond?: number);
|
|
127
|
+
constructor(tick: number);
|
|
128
|
+
constructor(date: Date);
|
|
129
|
+
|
|
130
|
+
static parse(str: string): Time;
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 지원 파싱 형식
|
|
135
|
+
|
|
136
|
+
- `HH:mm:ss`
|
|
137
|
+
- `HH:mm:ss.fff`
|
|
138
|
+
- `AM/PM HH:mm:ss`
|
|
139
|
+
- ISO 8601 (시간 부분만 추출)
|
|
140
|
+
|
|
141
|
+
### Getters (읽기 전용)
|
|
142
|
+
|
|
143
|
+
| Property | Type | Description |
|
|
144
|
+
|----------|------|-------------|
|
|
145
|
+
| `hour` | `number` | 시 |
|
|
146
|
+
| `minute` | `number` | 분 |
|
|
147
|
+
| `second` | `number` | 초 |
|
|
148
|
+
| `millisecond` | `number` | 밀리초 |
|
|
149
|
+
| `tick` | `number` | 자정 이후 경과 밀리초 |
|
|
150
|
+
| `isValid` | `boolean` | 유효한 시간 여부 |
|
|
151
|
+
|
|
152
|
+
### 불변 변환 메서드 (새 인스턴스 반환)
|
|
153
|
+
|
|
154
|
+
`setHour(hour)`, `setMinute(minute)`, `setSecond(second)`, `setMillisecond(millisecond)`
|
|
155
|
+
|
|
156
|
+
`addHours(hours)`, `addMinutes(minutes)`, `addSeconds(seconds)`, `addMilliseconds(milliseconds)` — 모두 24시간 순환
|
|
157
|
+
|
|
158
|
+
### 포맷 메서드
|
|
159
|
+
|
|
160
|
+
| Method | Description |
|
|
161
|
+
|--------|-------------|
|
|
162
|
+
| `toFormatString(formatStr)` | 형식 문자열로 변환 |
|
|
163
|
+
| `toString()` | `"HH:mm:ss.fff"` 형식으로 변환 |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## `Uuid`
|
|
168
|
+
|
|
169
|
+
UUID v4 클래스. `crypto.getRandomValues` 기반으로 암호학적으로 안전한 UUID를 생성한다.
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
export class Uuid {
|
|
173
|
+
constructor(uuid: string);
|
|
174
|
+
|
|
175
|
+
static generate(): Uuid;
|
|
176
|
+
static fromBytes(bytes: Bytes): Uuid;
|
|
177
|
+
|
|
178
|
+
toString(): string;
|
|
179
|
+
toBytes(): Bytes;
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
| Method/Property | Description |
|
|
184
|
+
|-----------------|-------------|
|
|
185
|
+
| `constructor(uuid)` | UUID 문자열로 생성. 형식이 유효하지 않으면 `ArgumentError` 발생 |
|
|
186
|
+
| `Uuid.generate()` | 새 UUID v4 인스턴스 생성 |
|
|
187
|
+
| `Uuid.fromBytes(bytes)` | 16바이트 Uint8Array로 UUID 생성 |
|
|
188
|
+
| `toString()` | UUID 문자열 반환 (`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) |
|
|
189
|
+
| `toBytes()` | 16바이트 Uint8Array로 변환 |
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## `LazyGcMap<TKey, TValue>`
|
|
194
|
+
|
|
195
|
+
LRU 방식으로 접근 시간을 갱신하고, 지정된 시간 동안 접근하지 않으면 자동 삭제하는 Map.
|
|
196
|
+
|
|
197
|
+
반드시 `try-finally` 블록에서 `dispose()`를 호출해야 GC 타이머가 정리된다.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
export class LazyGcMap<TKey, TValue> {
|
|
201
|
+
constructor(options: {
|
|
202
|
+
gcInterval?: number;
|
|
203
|
+
expireTime: number;
|
|
204
|
+
onExpire?: (key: TKey, value: TValue) => void | Promise<void>;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 생성자 옵션
|
|
210
|
+
|
|
211
|
+
| Field | Type | Description |
|
|
212
|
+
|-------|------|-------------|
|
|
213
|
+
| `gcInterval` | `number \| undefined` | GC 간격 (ms). 기본값: `expireTime / 10` (최소 1000ms) |
|
|
214
|
+
| `expireTime` | `number` | 만료 시간 (ms). 마지막 접근 이후 이 시간이 지나면 삭제됨 |
|
|
215
|
+
| `onExpire` | `(key, value) => void \| Promise<void>` | 만료 시 호출되는 콜백 |
|
|
216
|
+
|
|
217
|
+
### 메서드
|
|
218
|
+
|
|
219
|
+
| Method | Description |
|
|
220
|
+
|--------|-------------|
|
|
221
|
+
| `get size` | 저장된 항목 수 |
|
|
222
|
+
| `has(key)` | key 존재 여부 확인 (접근 시간 갱신하지 않음) |
|
|
223
|
+
| `get(key)` | 값 조회 (접근 시간 갱신) |
|
|
224
|
+
| `set(key, value)` | 값 저장 및 GC 타이머 시작 |
|
|
225
|
+
| `delete(key)` | 항목 삭제 |
|
|
226
|
+
| `clear()` | 모든 항목 삭제 (인스턴스 재사용 가능) |
|
|
227
|
+
| `getOrCreate(key, factory)` | key가 없으면 팩토리로 생성 후 저장 |
|
|
228
|
+
| `values()` | 값만 순회 |
|
|
229
|
+
| `keys()` | key만 순회 |
|
|
230
|
+
| `entries()` | `[key, value]` 순회 |
|
|
231
|
+
| `dispose()` | GC 타이머 중지 및 데이터 삭제 |
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
const cache = new LazyGcMap<string, Data>({
|
|
235
|
+
expireTime: 60_000,
|
|
236
|
+
onExpire: async (key, value) => { await value.cleanup(); },
|
|
237
|
+
});
|
|
238
|
+
try {
|
|
239
|
+
cache.set("key", data);
|
|
240
|
+
const val = cache.get("key"); // 접근 시간 갱신
|
|
241
|
+
const val2 = cache.getOrCreate("key2", () => new Data());
|
|
242
|
+
} finally {
|
|
243
|
+
cache.dispose();
|
|
244
|
+
}
|
|
245
|
+
```
|