entity-server-client 0.2.5 → 0.3.0

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.
Files changed (50) hide show
  1. package/README.md +32 -1
  2. package/build.mjs +11 -1
  3. package/docs/api/alimtalk.md +62 -0
  4. package/docs/api/auth.md +256 -0
  5. package/docs/api/email.md +37 -0
  6. package/docs/api/entity.md +273 -0
  7. package/docs/api/file.md +80 -0
  8. package/docs/api/health.md +41 -0
  9. package/docs/api/identity.md +32 -0
  10. package/docs/api/import.md +34 -0
  11. package/docs/api/packet.md +25 -0
  12. package/docs/api/pg.md +90 -0
  13. package/docs/api/push.md +107 -0
  14. package/docs/api/react.md +141 -0
  15. package/docs/api/setup.md +43 -0
  16. package/docs/api/sms.md +45 -0
  17. package/docs/api/smtp.md +33 -0
  18. package/docs/api/transaction.md +50 -0
  19. package/docs/api/utils.md +52 -0
  20. package/docs/apis.md +22 -787
  21. package/docs/react.md +64 -7
  22. package/package.json +7 -1
  23. package/src/EntityServerClient.ts +28 -546
  24. package/src/client/base.ts +305 -0
  25. package/src/client/packet.ts +16 -52
  26. package/src/client/request.ts +46 -9
  27. package/src/client/utils.ts +17 -2
  28. package/src/hooks/useEntityServer.ts +3 -4
  29. package/src/mixins/auth.ts +143 -0
  30. package/src/mixins/entity.ts +205 -0
  31. package/src/mixins/file.ts +99 -0
  32. package/src/mixins/push.ts +109 -0
  33. package/src/mixins/smtp.ts +20 -0
  34. package/src/mixins/utils.ts +106 -0
  35. package/src/packet.ts +84 -0
  36. package/src/types.ts +93 -1
  37. package/tests/packet.test.mjs +50 -0
  38. package/dist/EntityServerClient.d.ts +0 -203
  39. package/dist/client/hmac.d.ts +0 -8
  40. package/dist/client/packet.d.ts +0 -22
  41. package/dist/client/request.d.ts +0 -16
  42. package/dist/client/utils.d.ts +0 -4
  43. package/dist/hooks/useEntityServer.d.ts +0 -63
  44. package/dist/index.d.ts +0 -4
  45. package/dist/index.js +0 -2
  46. package/dist/index.js.map +0 -7
  47. package/dist/react.d.ts +0 -1
  48. package/dist/react.js +0 -2
  49. package/dist/react.js.map +0 -7
  50. package/dist/types.d.ts +0 -165
@@ -0,0 +1,141 @@
1
+ # React Hook
2
+
3
+ ## `useEntityServer(options?)`
4
+
5
+ React 컴포넌트에서 EntityServerClient를 사용할 때 권장되는 훅입니다.
6
+ `submit` / `del` / `query` 의 `isPending`, `error` 상태를 자동으로 관리합니다.
7
+
8
+ ```ts
9
+ import { useEntityServer } from "entity-server-client/react";
10
+ ```
11
+
12
+ ### 옵션
13
+
14
+ | 옵션 | 타입 | 기본값 | 설명 |
15
+ | ------------------ | ----------------------------------- | ------ | ----------------------------------------------------------------------------------------------- |
16
+ | `singleton` | `boolean` | `true` | `true`이면 전역 `entityServer` 인스턴스 사용 |
17
+ | `baseUrl` | `string` | — | 서버 주소 (singleton일 때 `configure()` 호출) |
18
+ | `token` | `string` | — | JWT Access Token |
19
+ | `tokenResolver` | `() => string \| undefined \| null` | — | 렌더 시점에 토큰을 동적으로 주입하는 함수 |
20
+ | `keepSession` | `boolean` | — | 세션 유지 활성화 |
21
+ | `onTokenRefreshed` | `(accessToken, expiresIn) => void` | — | 세션 유지 성공 콜백 |
22
+ | `onSessionExpired` | `(error: Error) => void` | — | 세션 만료 콜백 (refresh_token 만료 등) |
23
+ | `resumeSession` | `string` | — | 저장된 refresh_token. 마운트 시 `refreshToken()` 호출해 토큰 복원 + `keepSession` 타이머 재시작 |
24
+
25
+ ### 반환값
26
+
27
+ | 필드 | 타입 | 설명 |
28
+ | ----------- | -------------------- | ----------------------------------------------------- |
29
+ | `client` | `EntityServerClient` | **모든 API 메서드에 접근 가능한 클라이언트 인스턴스** |
30
+ | `isPending` | `boolean` | `submit` / `del` / `query` 진행 중 여부 |
31
+ | `error` | `Error \| null` | 마지막 mutation 에러. 성공 또는 `reset()` 시 `null` |
32
+ | `reset` | `() => void` | `isPending`, `error` 초기화 |
33
+ | `submit` | function | `client.submit()` 래퍼 — 상태 자동 관리 |
34
+ | `del` | function | `client.delete()` 래퍼 — 상태 자동 관리 |
35
+ | `query` | function | `client.query()` 래퍼 — 상태 자동 관리 |
36
+
37
+ > **`client`는 `EntityServerClient` 인스턴스 그대로입니다.**
38
+ > `submit` / `del` / `query` 래퍼는 `isPending` / `error` 상태를 자동 관리해주는 편의 메서드일 뿐이며,
39
+ > 인증, 푸시, 파일, SMS, PG 등 **모든 API**는 `client.메서드명()`으로 직접 호출합니다.
40
+
41
+ ### `client`로 사용 가능한 모든 API
42
+
43
+ `client`를 통해 아래 모든 섹션의 메서드를 그대로 사용할 수 있습니다.
44
+
45
+ | 카테고리 | 주요 메서드 (예시) | 상세 문서 |
46
+ | ------------------ | ---------------------------------------------------------------------------------- | -------------------------------- |
47
+ | 인증 | `login`, `logout`, `register`, `refreshToken`, `oauthLogin`, `enable2FA` … | [auth.md](auth.md) |
48
+ | 트랜잭션 | `transStart`, `transCommit`, `transRollback` | [transaction.md](transaction.md) |
49
+ | 엔티티 CRUD / 조회 | `get`, `find`, `list`, `count`, `query`, `submit`, `delete`, `history`, `rollback` | [entity.md](entity.md) |
50
+ | 푸시 | `pushSend`, `pushSendAll`, `pushStatus`, `registerPushDevice` … | [push.md](push.md) |
51
+ | 이메일 인증 | `emailVerificationSend`, `emailVerificationConfirm`, `emailChange` | [email.md](email.md) |
52
+ | SMS | `smsSend`, `smsVerificationSend`, `smsVerificationVerify` | [sms.md](sms.md) |
53
+ | SMTP 메일 | `smtpSend`, `smtpStatus` | [smtp.md](smtp.md) |
54
+ | 알림톡 / 친구톡 | `alimtalkSend`, `alimtalkTemplates`, `friendtalkSend` | [alimtalk.md](alimtalk.md) |
55
+ | PG 결제 | `pgCreateOrder`, `pgConfirmPayment`, `pgCancelPayment`, `pgConfig` | [pg.md](pg.md) |
56
+ | 파일 스토리지 | `fileUpload`, `fileDownload`, `fileDelete`, `fileList`, `fileToken`, `fileUrl` | [file.md](file.md) |
57
+ | 본인인증 | `identityRequest`, `identityResult`, `identityVerifyCI` | [identity.md](identity.md) |
58
+ | QR코드 / 바코드 | `qrcode`, `qrcodeBase64`, `barcode` | [utils.md](utils.md) |
59
+
60
+ ### 기본 사용 예시
61
+
62
+ ```tsx
63
+ import { useEntityServer } from "entity-server-client/react";
64
+
65
+ function AccountForm() {
66
+ const { submit, del, isPending, error, reset } = useEntityServer();
67
+
68
+ const handleSave = async () => {
69
+ reset();
70
+ await submit("account", { name: "홍길동", email: "hong@example.com" });
71
+ };
72
+
73
+ const handleDelete = async (seq: number) => {
74
+ await del("account", seq);
75
+ };
76
+
77
+ return (
78
+ <div>
79
+ {isPending && <span>저장 중...</span>}
80
+ {error && <span style={{ color: "red" }}>{error.message}</span>}
81
+ <button onClick={handleSave} disabled={isPending}>
82
+ 저장
83
+ </button>
84
+ <button onClick={() => handleDelete(1)} disabled={isPending}>
85
+ 삭제
86
+ </button>
87
+ </div>
88
+ );
89
+ }
90
+ ```
91
+
92
+ ### 동적 토큰 주입
93
+
94
+ ```tsx
95
+ const { submit } = useEntityServer({
96
+ tokenResolver: () => localStorage.getItem("access_token"),
97
+ });
98
+ ```
99
+
100
+ ### 페이지 새로고침 후 세션 복원
101
+
102
+ `resumeSession`에 저장된 refresh_token을 넘기면 마운트 시 `refreshToken()`을 호출해
103
+ 새 access_token을 발급받고, `keepSession: true`이면 타이머도 자동 재시작됩니다.
104
+
105
+ ```tsx
106
+ // App.tsx 또는 로그인 복원을 담당하는 컴포넌트
107
+ export function AppShell() {
108
+ const storedRefreshToken =
109
+ localStorage.getItem("auth_refresh_token") ?? undefined;
110
+
111
+ useEntityServer({
112
+ resumeSession: storedRefreshToken,
113
+ keepSession: true,
114
+ onTokenRefreshed: (accessToken) => {
115
+ localStorage.setItem("auth_access_token", accessToken);
116
+ },
117
+ onSessionExpired: () => {
118
+ window.location.href = "/login";
119
+ },
120
+ });
121
+
122
+ return <RouterOutlet />;
123
+ }
124
+ ```
125
+
126
+ 마운트 시 `resumeSession`이 있으면:
127
+
128
+ 1. `refreshToken(storedRefreshToken)` 호출 → 서버에서 새 access_token 발급
129
+ 2. 패키지 내부 `this.token` 자동 교체
130
+ 3. `onTokenRefreshed` 콜백 호출
131
+ 4. `keepSession: true`이면 다음 만료 전 타이머 자동 예약
132
+ 5. 실패 시 `onSessionExpired` 콜백 호출
133
+
134
+ ### 컴포넌트별 독립 인스턴스
135
+
136
+ ```tsx
137
+ const { client } = useEntityServer({
138
+ singleton: false,
139
+ baseUrl: "https://other-server.example.com",
140
+ });
141
+ ```
@@ -0,0 +1,43 @@
1
+ # 인스턴스 생성/설정
2
+
3
+ ## `new EntityServerClient(options?)`
4
+
5
+ | 옵션 | 타입 | 기본값 | 설명 |
6
+ | ------------------ | ---------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
7
+ | `baseUrl` | `string` | `VITE_ENTITY_SERVER_URL` 또는 `http://localhost:47200` | 서버 주소 |
8
+ | `token` | `string` | `""` | JWT Access Token |
9
+ | `encryptRequests` | `boolean` | `false` | `true` 로 설정하면 인증된 POST/PUT/PATCH 요청 바디를 XChaCha20-Poly1305 로 암호화하여 전송합니다. 서버에서 `requirePacketEncryption = true` 로 설정된 경우 반드시 활성화해야 합니다. |
10
+ | `keepSession` | `boolean` | `false` | `true`이면 `login()` 성공 후 Access Token 만료 전에 자동으로 갱신합니다. |
11
+ | `refreshBuffer` | `number` | `60` | 만료 몇 초 전에 갱신을 시도할지 설정합니다. 예: `expires_in=3600`, `refreshBuffer=60` → 3540초 후 갱신 |
12
+ | `onTokenRefreshed` | `(accessToken, expiresIn) => void` | — | 자동 갱신 성공 시 호출됩니다. 새 `access_token`을 받아 앱 레벨 저장소에 업데이트하세요. |
13
+ | `onSessionExpired` | `(error: Error) => void` | — | 세션 유지 갱신 실패 시 호출됩니다 (refresh_token 만료 등). 로그인 페이지로 이동하는 등의 처리를 여기서 합니다. |
14
+
15
+ ```ts
16
+ // 직접 생성
17
+ const client = new EntityServerClient({
18
+ baseUrl: "https://api.example.com",
19
+ token: "eyJhbGciOi...",
20
+ encryptRequests: true, // 요청 바디 암호화 활성화
21
+ });
22
+
23
+ // 싱글톤 (환경변수 자동 읽기)
24
+ import { entityServer } from "entity-server-client";
25
+ ```
26
+
27
+ ## `configure(options)`
28
+
29
+ 런타임에 설정을 갱신합니다.
30
+
31
+ ```ts
32
+ client.configure({
33
+ baseUrl: "https://api.example.com",
34
+ token: "new-access-token",
35
+ encryptRequests: true,
36
+ });
37
+ ```
38
+
39
+ ## `setToken(token)`
40
+
41
+ ```ts
42
+ client.setToken("eyJhbGciOi...");
43
+ ```
@@ -0,0 +1,45 @@
1
+ # SMS
2
+
3
+ ## `smsSend(req)`
4
+
5
+ SMS를 직접 발송합니다.
6
+
7
+ | 필드 | 타입 | 설명 |
8
+ | ------ | -------- | ---------------------------------- |
9
+ | `to` | `string` | 수신 전화번호 (`01012345678` 형식) |
10
+ | `text` | `string` | 메시지 내용 |
11
+ | `from` | `string` | 발신 번호 (미지정 시 설정값 사용) |
12
+
13
+ ```ts
14
+ const res = await client.smsSend({
15
+ to: "01012345678",
16
+ text: "안녕하세요. 인증번호는 123456입니다.",
17
+ });
18
+ res.seq; // 발송 로그 seq
19
+ ```
20
+
21
+ ## `smsStatus(seq)`
22
+
23
+ SMS 발송 처리 상태를 조회합니다.
24
+
25
+ ```ts
26
+ const res = await client.smsStatus(10);
27
+ res.status; // "sent" | "failed" | "pending"
28
+ ```
29
+
30
+ ## `smsVerificationSend(phone)`
31
+
32
+ SMS 인증번호를 발송합니다. 인증 불필요 (공개 API).
33
+
34
+ ```ts
35
+ await client.smsVerificationSend("01012345678");
36
+ ```
37
+
38
+ ## `smsVerificationVerify(phone, code)`
39
+
40
+ 발송된 SMS 인증번호를 검증합니다. 인증 불필요 (공개 API).
41
+
42
+ ```ts
43
+ const res = await client.smsVerificationVerify("01012345678", "123456");
44
+ res.verified; // true | false
45
+ ```
@@ -0,0 +1,33 @@
1
+ # SMTP 메일
2
+
3
+ ## `smtpSend(req)`
4
+
5
+ SMTP를 통해 이메일을 발송합니다.
6
+
7
+ | 필드 | 타입 | 설명 |
8
+ | --------- | ---------- | ---------------------------- |
9
+ | `to` | `string` | 수신 이메일 주소 |
10
+ | `subject` | `string` | 이메일 제목 |
11
+ | `html` | `string` | HTML 본문 |
12
+ | `text` | `string` | 텍스트 본문 (HTML 대체) |
13
+ | `from` | `string` | 발신 주소 (미지정 시 설정값) |
14
+ | `cc` | `string[]` | 참조 수신자 목록 |
15
+ | `bcc` | `string[]` | 숨은 참조 수신자 목록 |
16
+
17
+ ```ts
18
+ const res = await client.smtpSend({
19
+ to: "user@example.com",
20
+ subject: "가입을 환영합니다!",
21
+ html: "<h1>안녕하세요</h1><p>가입해주셔서 감사합니다.</p>",
22
+ });
23
+ res.seq; // 발송 로그 seq
24
+ ```
25
+
26
+ ## `smtpStatus(seq)`
27
+
28
+ SMTP 발송 로그의 처리 상태를 조회합니다.
29
+
30
+ ```ts
31
+ const res = await client.smtpStatus(5);
32
+ res.status; // "sent" | "failed" | "pending"
33
+ ```
@@ -0,0 +1,50 @@
1
+ # 트랜잭션
2
+
3
+ 여러 submit/delete를 하나의 DB 트랜잭션으로 묶습니다.
4
+ 트랜잭션은 **5분 TTL**을 가집니다. 이 안에 commit 또는 rollback을 해야 합니다.
5
+
6
+ ```
7
+ transStart → submit/delete (여러 개) → transCommit
8
+ └→ transRollback (실패 시)
9
+ ```
10
+
11
+ ## `transStart()`
12
+
13
+ 트랜잭션을 시작하고 내부 활성 트랜잭션 ID를 저장합니다.
14
+ 이후 `submit()`/`delete()`는 `X-Transaction-ID` 헤더를 자동 포함합니다.
15
+
16
+ ```ts
17
+ const txId = await client.transStart();
18
+ ```
19
+
20
+ ## `transCommit(transactionId?)`
21
+
22
+ 큐에 쌓인 모든 작업을 단일 DB 트랜잭션으로 일괄 실행합니다.
23
+ 하나라도 실패하면 전체 ROLLBACK됩니다.
24
+
25
+ ```ts
26
+ await client.transStart();
27
+ await client.submit("order", { product_seq: 1, qty: 2 });
28
+ await client.submit("inventory", { seq: 1, stock: 48 });
29
+ const result = await client.transCommit();
30
+ // result.results → [{ entity: "order", action: "submit", seq: 55 }, ...]
31
+ ```
32
+
33
+ > **트랜잭션 중 submit 응답**: commit 전에는 `{ ok: true, queued: true, seq: "$tx.0" }` 형태의
34
+ > placeholder가 반환됩니다. `$tx.0`, `$tx.1` 값은 commit 시 실제 seq로 자동 치환되므로
35
+ > 후속 submit의 외래키 값으로 그대로 사용할 수 있습니다.
36
+
37
+ ## `transRollback(transactionId?)`
38
+
39
+ - 아직 commit 전 (큐에 남아있음): 큐를 버립니다. DB에 아무 변경 없음.
40
+ - 이미 commit 후: history 기반으로 전체 되돌립니다.
41
+
42
+ ```ts
43
+ try {
44
+ await client.transStart();
45
+ await client.submit("order", { ... });
46
+ await client.transCommit();
47
+ } catch (e) {
48
+ await client.transRollback(); // 활성 트랜잭션 자동 참조
49
+ }
50
+ ```
@@ -0,0 +1,52 @@
1
+ # QR코드 / 바코드
2
+
3
+ ## `qrcode(content, opts?)`
4
+
5
+ QR 코드 PNG를 생성합니다. `ArrayBuffer`를 반환합니다.
6
+
7
+ | 옵션 | 타입 | 설명 |
8
+ | -------- | -------- | --------------------------------- |
9
+ | `size` | `number` | 이미지 크기 (px). 기본값 `256` |
10
+ | `level` | `string` | 오류 정정 레벨 `L \| M \| Q \| H` |
11
+ | `format` | `string` | 출력 포맷. 기본값 `"png"` |
12
+
13
+ ```ts
14
+ const buf = await client.qrcode("https://example.com", { size: 300 });
15
+ const blob = new Blob([buf], { type: "image/png" });
16
+ img.src = URL.createObjectURL(blob);
17
+ ```
18
+
19
+ ## `qrcodeBase64(content, opts?)`
20
+
21
+ QR 코드를 base64 / data URI JSON으로 반환합니다.
22
+
23
+ ```ts
24
+ const res = await client.qrcodeBase64("https://example.com");
25
+ res.data_uri; // "data:image/png;base64,..."
26
+ res.data; // base64 문자열
27
+ img.src = res.data_uri;
28
+ ```
29
+
30
+ ## `qrcodeText(content, opts?)`
31
+
32
+ QR 코드를 ASCII 아트 텍스트로 반환합니다.
33
+
34
+ ```ts
35
+ const res = await client.qrcodeText("https://example.com");
36
+ console.log(res.text); // ASCII 아트 QR 코드
37
+ ```
38
+
39
+ ## `barcode(content, opts?)`
40
+
41
+ 바코드 PNG를 생성합니다. `ArrayBuffer`를 반환합니다.
42
+
43
+ | 옵션 | 타입 | 설명 |
44
+ | ------ | -------- | -------------------------------------------------- |
45
+ | `type` | `string` | 바코드 형식. 예: `"code128"`, `"ean13"`, `"qr"` 등 |
46
+ | `size` | `number` | 이미지 크기 |
47
+
48
+ ```ts
49
+ const buf = await client.barcode("1234567890128", { type: "ean13" });
50
+ const blob = new Blob([buf], { type: "image/png" });
51
+ img.src = URL.createObjectURL(blob);
52
+ ```