@simplysm/core-common 13.0.97 → 13.0.99
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 +160 -0
- package/docs/errors.md +119 -0
- package/docs/extensions.md +387 -0
- package/docs/features.md +143 -0
- package/docs/types.md +287 -0
- package/docs/utils.md +757 -0
- package/package.json +2 -2
package/docs/features.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Features
|
|
2
|
+
|
|
3
|
+
Feature classes for async control flow and event handling.
|
|
4
|
+
|
|
5
|
+
Source: `src/features/*.ts`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## `EventEmitter`
|
|
10
|
+
|
|
11
|
+
Type-safe event emitter that can be used in both browsers and Node.js. Internally implemented using `EventTarget`. Supports the `using` statement (`Symbol.dispose`).
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
export class EventEmitter<
|
|
15
|
+
TEvents extends { [K in keyof TEvents]: unknown } = Record<string, unknown>,
|
|
16
|
+
> {
|
|
17
|
+
/**
|
|
18
|
+
* Register an event listener
|
|
19
|
+
* @note Duplicate registration of the same listener to the same event is ignored
|
|
20
|
+
*/
|
|
21
|
+
on<TEventName extends keyof TEvents & string>(
|
|
22
|
+
type: TEventName,
|
|
23
|
+
listener: (data: TEvents[TEventName]) => void,
|
|
24
|
+
): void;
|
|
25
|
+
|
|
26
|
+
/** Remove an event listener */
|
|
27
|
+
off<TEventName extends keyof TEvents & string>(
|
|
28
|
+
type: TEventName,
|
|
29
|
+
listener: (data: TEvents[TEventName]) => void,
|
|
30
|
+
): void;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Emit an event
|
|
34
|
+
* @param args Event data (omitted if void type)
|
|
35
|
+
*/
|
|
36
|
+
emit<TEventName extends keyof TEvents & string>(
|
|
37
|
+
type: TEventName,
|
|
38
|
+
...args: TEvents[TEventName] extends void ? [] : [data: TEvents[TEventName]]
|
|
39
|
+
): void;
|
|
40
|
+
|
|
41
|
+
/** Return the number of listeners for a specific event */
|
|
42
|
+
listenerCount<TEventName extends keyof TEvents & string>(type: TEventName): number;
|
|
43
|
+
|
|
44
|
+
/** Remove all event listeners */
|
|
45
|
+
dispose(): void;
|
|
46
|
+
|
|
47
|
+
[Symbol.dispose](): void;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Example:**
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
interface MyEvents {
|
|
55
|
+
data: string;
|
|
56
|
+
error: Error;
|
|
57
|
+
done: void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class MyEmitter extends EventEmitter<MyEvents> {}
|
|
61
|
+
|
|
62
|
+
const emitter = new MyEmitter();
|
|
63
|
+
emitter.on("data", (data) => console.log(data)); // data: string
|
|
64
|
+
emitter.emit("data", "hello");
|
|
65
|
+
emitter.emit("done"); // void type is called without arguments
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## `DebounceQueue`
|
|
71
|
+
|
|
72
|
+
Asynchronous debounce queue. When called multiple times within a short time, only the last request is executed and previous requests are ignored. Extends `EventEmitter<{ error: SdError }>`. Supports the `using` statement.
|
|
73
|
+
|
|
74
|
+
Requests added during execution are processed immediately after the current execution completes without debounce delay.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
export class DebounceQueue extends EventEmitter<{ error: SdError }> {
|
|
78
|
+
/**
|
|
79
|
+
* @param _delay Debounce delay time (milliseconds). If omitted, executes immediately (next event loop)
|
|
80
|
+
*/
|
|
81
|
+
constructor(delay?: number);
|
|
82
|
+
|
|
83
|
+
/** Clean up pending tasks and timers */
|
|
84
|
+
dispose(): void;
|
|
85
|
+
|
|
86
|
+
[Symbol.dispose](): void;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Add a function to the queue
|
|
90
|
+
* If there was a previously added function, it will be replaced
|
|
91
|
+
*/
|
|
92
|
+
run(fn: () => void | Promise<void>): void;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Error handling:** If there are `"error"` event listeners, errors are emitted as events. Otherwise, errors are logged via `consola`.
|
|
97
|
+
|
|
98
|
+
**Example:**
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const queue = new DebounceQueue(300); // 300ms delay
|
|
102
|
+
queue.run(() => console.log("1")); // ignored
|
|
103
|
+
queue.run(() => console.log("2")); // ignored
|
|
104
|
+
queue.run(() => console.log("3")); // executed after 300ms
|
|
105
|
+
|
|
106
|
+
queue.on("error", (err) => console.error(err));
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## `SerialQueue`
|
|
112
|
+
|
|
113
|
+
Asynchronous serial queue. Functions added to the queue are executed sequentially. The next task starts only after one task completes. Subsequent tasks continue to execute even if an error occurs. Extends `EventEmitter<{ error: SdError }>`. Supports the `using` statement.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
export class SerialQueue extends EventEmitter<{ error: SdError }> {
|
|
117
|
+
/**
|
|
118
|
+
* @param gap Gap between each task (ms). Default: 0
|
|
119
|
+
*/
|
|
120
|
+
constructor(gap?: number);
|
|
121
|
+
|
|
122
|
+
/** Clear pending queue (currently executing task will complete) */
|
|
123
|
+
dispose(): void;
|
|
124
|
+
|
|
125
|
+
[Symbol.dispose](): void;
|
|
126
|
+
|
|
127
|
+
/** Add a function to the queue and execute it */
|
|
128
|
+
run(fn: () => void | Promise<void>): void;
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Error handling:** Same as `DebounceQueue` -- emitted as event if listeners exist, otherwise logged.
|
|
133
|
+
|
|
134
|
+
**Example:**
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const queue = new SerialQueue();
|
|
138
|
+
queue.run(async () => { await fetch("/api/1"); });
|
|
139
|
+
queue.run(async () => { await fetch("/api/2"); }); // executed after 1 completes
|
|
140
|
+
queue.run(async () => { await fetch("/api/3"); }); // executed after 2 completes
|
|
141
|
+
|
|
142
|
+
queue.on("error", (err) => console.error(err));
|
|
143
|
+
```
|
package/docs/types.md
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Types
|
|
2
|
+
|
|
3
|
+
Data types and common type definitions.
|
|
4
|
+
|
|
5
|
+
Source: `src/types/*.ts`, `src/common.types.ts`, `src/env.ts`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## `Uuid`
|
|
10
|
+
|
|
11
|
+
UUID v4 class. Generates cryptographically secure UUIDs based on `crypto.getRandomValues` (Chrome 79+, Node.js compatible).
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
export class Uuid {
|
|
15
|
+
/** Create new UUID v4 instance */
|
|
16
|
+
static generate(): Uuid;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create UUID from 16-byte Uint8Array
|
|
20
|
+
* @throws {ArgumentError} If byte size is not 16
|
|
21
|
+
*/
|
|
22
|
+
static fromBytes(bytes: Bytes): Uuid;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param uuid UUID string (format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
|
|
26
|
+
* @throws {ArgumentError} If format is invalid
|
|
27
|
+
*/
|
|
28
|
+
constructor(uuid: string);
|
|
29
|
+
|
|
30
|
+
/** Convert UUID to string */
|
|
31
|
+
toString(): string;
|
|
32
|
+
|
|
33
|
+
/** Convert UUID to 16-byte Uint8Array */
|
|
34
|
+
toBytes(): Bytes;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## `DateTime`
|
|
41
|
+
|
|
42
|
+
Immutable date+time class wrapping JavaScript `Date`. Supports millisecond precision and operates based on local timezone.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
export class DateTime {
|
|
46
|
+
readonly date: Date;
|
|
47
|
+
|
|
48
|
+
/** Create with current time */
|
|
49
|
+
constructor();
|
|
50
|
+
/** Create with year, month, day, hour, minute, second, millisecond */
|
|
51
|
+
constructor(year: number, month: number, day: number, hour?: number, minute?: number, second?: number, millisecond?: number);
|
|
52
|
+
/** Create from tick (millisecond) */
|
|
53
|
+
constructor(tick: number);
|
|
54
|
+
/** Create from Date object */
|
|
55
|
+
constructor(date: Date);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Parse a string to create DateTime instance
|
|
59
|
+
* Supported formats: 'yyyy-MM-dd HH:mm:ss', 'yyyy-MM-dd HH:mm:ss.fff', 'yyyyMMddHHmmss',
|
|
60
|
+
* 'yyyy-MM-dd AM/PM HH:mm:ss', Korean AM/PM (오전/오후), ISO 8601
|
|
61
|
+
* @throws ArgumentError If unsupported format
|
|
62
|
+
*/
|
|
63
|
+
static parse(str: string): DateTime;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Getters** (read-only): `year`, `month`, `day`, `hour`, `minute`, `second`, `millisecond`, `tick`, `dayOfWeek` (0=Sunday), `timezoneOffsetMinutes`, `isValid`
|
|
68
|
+
|
|
69
|
+
**Immutable setters** (return new instance): `setYear(year)`, `setMonth(month)`, `setDay(day)`, `setHour(hour)`, `setMinute(minute)`, `setSecond(second)`, `setMillisecond(millisecond)`
|
|
70
|
+
|
|
71
|
+
**Arithmetic** (return new instance): `addYears(n)`, `addMonths(n)`, `addDays(n)`, `addHours(n)`, `addMinutes(n)`, `addSeconds(n)`, `addMilliseconds(n)`
|
|
72
|
+
|
|
73
|
+
**Formatting**: `toFormatString(formatStr)`, `toString()` (default: `"yyyy-MM-ddTHH:mm:ss.fffzzz"`)
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## `DateOnly`
|
|
78
|
+
|
|
79
|
+
Immutable date class (without time: `yyyy-MM-dd`). Operates based on local timezone.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
export class DateOnly {
|
|
83
|
+
readonly date: Date;
|
|
84
|
+
|
|
85
|
+
/** Current date */
|
|
86
|
+
constructor();
|
|
87
|
+
/** Initialize with year, month, day */
|
|
88
|
+
constructor(year: number, month: number, day: number);
|
|
89
|
+
/** Create from tick (millisecond) */
|
|
90
|
+
constructor(tick: number);
|
|
91
|
+
/** Create from Date type */
|
|
92
|
+
constructor(date: Date);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Parse a string into DateOnly
|
|
96
|
+
* Supported formats: 'yyyy-MM-dd', 'yyyyMMdd', ISO 8601
|
|
97
|
+
*/
|
|
98
|
+
static parse(str: string): DateOnly;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get the start date of a week based on week information
|
|
102
|
+
*/
|
|
103
|
+
static getDateByYearWeekSeq(
|
|
104
|
+
arg: { year: number; month?: number; weekSeq: number },
|
|
105
|
+
weekStartDay?: number,
|
|
106
|
+
minDaysInFirstWeek?: number,
|
|
107
|
+
): DateOnly;
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Getters** (read-only): `year`, `month`, `day`, `tick`, `dayOfWeek`, `isValid`
|
|
112
|
+
|
|
113
|
+
**Immutable setters**: `setYear(year)`, `setMonth(month)`, `setDay(day)`
|
|
114
|
+
|
|
115
|
+
**Arithmetic**: `addYears(n)`, `addMonths(n)`, `addDays(n)`
|
|
116
|
+
|
|
117
|
+
**Week calculation methods**:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
getBaseYearMonthSeqForWeekSeq(weekStartDay?: number, minDaysInFirstWeek?: number): { year: number; monthSeq: number };
|
|
121
|
+
getWeekSeqStartDate(weekStartDay?: number, minDaysInFirstWeek?: number): DateOnly;
|
|
122
|
+
getWeekSeqOfYear(weekStartDay?: number, minDaysInFirstWeek?: number): { year: number; weekSeq: number };
|
|
123
|
+
getWeekSeqOfMonth(weekStartDay?: number, minDaysInFirstWeek?: number): { year: number; monthSeq: number; weekSeq: number };
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Defaults: `weekStartDay = 1` (Monday), `minDaysInFirstWeek = 4` (ISO 8601 standard).
|
|
127
|
+
|
|
128
|
+
**Formatting**: `toFormatString(formatStr)`, `toString()` (default: `"yyyy-MM-dd"`)
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## `Time`
|
|
133
|
+
|
|
134
|
+
Immutable time class (without date: `HH:mm:ss.fff`). Values exceeding 24 hours or negative values are automatically normalized (24-hour wraparound).
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
export class Time {
|
|
138
|
+
/** Create with current time */
|
|
139
|
+
constructor();
|
|
140
|
+
/** Create with hour, minute, second, millisecond */
|
|
141
|
+
constructor(hour: number, minute: number, second?: number, millisecond?: number);
|
|
142
|
+
/** Create from tick (millisecond) */
|
|
143
|
+
constructor(tick: number);
|
|
144
|
+
/** Create by extracting time part only from Date object */
|
|
145
|
+
constructor(date: Date);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Parse a string to create Time instance
|
|
149
|
+
* Supported formats: 'HH:mm:ss', 'HH:mm:ss.fff', 'AM/PM HH:mm:ss', ISO 8601 (extract time part)
|
|
150
|
+
* @throws ArgumentError If unsupported format
|
|
151
|
+
*/
|
|
152
|
+
static parse(str: string): Time;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Getters**: `hour`, `minute`, `second`, `millisecond`, `tick`, `isValid`
|
|
157
|
+
|
|
158
|
+
**Immutable setters**: `setHour(hour)`, `setMinute(minute)`, `setSecond(second)`, `setMillisecond(millisecond)`
|
|
159
|
+
|
|
160
|
+
**Arithmetic** (24-hour wraparound): `addHours(n)`, `addMinutes(n)`, `addSeconds(n)`, `addMilliseconds(n)`
|
|
161
|
+
|
|
162
|
+
**Formatting**: `toFormatString(formatStr)`, `toString()` (default: `"HH:mm:ss.fff"`)
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## `LazyGcMap`
|
|
167
|
+
|
|
168
|
+
Map with automatic expiration feature. Updates access time in LRU manner; auto-deletes if not accessed for specified time. Supports the `using` statement (`Symbol.dispose`).
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
export class LazyGcMap<TKey, TValue> {
|
|
172
|
+
/**
|
|
173
|
+
* @param options.gcInterval GC interval in ms. Default: 1/10 of expireTime (minimum 1000ms)
|
|
174
|
+
* @param options.expireTime Expiration time in ms since last access
|
|
175
|
+
* @param options.onExpire Callback called on expiration (can be async)
|
|
176
|
+
*/
|
|
177
|
+
constructor(options: {
|
|
178
|
+
gcInterval?: number;
|
|
179
|
+
expireTime: number;
|
|
180
|
+
onExpire?: (key: TKey, value: TValue) => void | Promise<void>;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
get size(): number;
|
|
184
|
+
has(key: TKey): boolean;
|
|
185
|
+
get(key: TKey): TValue | undefined;
|
|
186
|
+
set(key: TKey, value: TValue): void;
|
|
187
|
+
delete(key: TKey): boolean;
|
|
188
|
+
clear(): void;
|
|
189
|
+
getOrCreate(key: TKey, factory: () => TValue): TValue;
|
|
190
|
+
values(): IterableIterator<TValue>;
|
|
191
|
+
keys(): IterableIterator<TKey>;
|
|
192
|
+
entries(): IterableIterator<[TKey, TValue]>;
|
|
193
|
+
dispose(): void;
|
|
194
|
+
[Symbol.dispose](): void;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Example:**
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
using map = new LazyGcMap({ gcInterval: 10000, expireTime: 60000 });
|
|
202
|
+
map.set("session", data);
|
|
203
|
+
const val = map.getOrCreate("key", () => computeExpensive());
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## `Bytes`
|
|
209
|
+
|
|
210
|
+
Binary type alias used instead of `Buffer`.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
export type Bytes = Uint8Array;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## `PrimitiveTypeMap`
|
|
219
|
+
|
|
220
|
+
Primitive type mapping shared with orm-common.
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
export type PrimitiveTypeMap = {
|
|
224
|
+
string: string;
|
|
225
|
+
number: number;
|
|
226
|
+
boolean: boolean;
|
|
227
|
+
DateTime: DateTime;
|
|
228
|
+
DateOnly: DateOnly;
|
|
229
|
+
Time: Time;
|
|
230
|
+
Uuid: Uuid;
|
|
231
|
+
Bytes: Bytes;
|
|
232
|
+
};
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## `PrimitiveTypeStr`
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
export type PrimitiveTypeStr = keyof PrimitiveTypeMap;
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## `PrimitiveType`
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
export type PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined;
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## `DeepPartial<T>`
|
|
254
|
+
|
|
255
|
+
Recursively makes all properties of an object optional. Primitive types are kept as-is.
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
export type DeepPartial<TObject> = Partial<{
|
|
259
|
+
[K in keyof TObject]: TObject[K] extends PrimitiveType ? TObject[K] : DeepPartial<TObject[K]>;
|
|
260
|
+
}>;
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## `Type<T>`
|
|
266
|
+
|
|
267
|
+
Constructor type used for dependency injection, factory patterns, and `instanceof` checks.
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
export interface Type<TInstance> extends Function {
|
|
271
|
+
new (...args: unknown[]): TInstance;
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## `env`
|
|
278
|
+
|
|
279
|
+
Unified environment variable accessor. Merges `import.meta.env` and `process.env`. `DEV` is parsed as boolean, `VER` as optional string.
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
export const env: {
|
|
283
|
+
DEV: boolean;
|
|
284
|
+
VER?: string;
|
|
285
|
+
[key: string]: unknown;
|
|
286
|
+
};
|
|
287
|
+
```
|