k-dhlottery-api 0.2.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fhwang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ # 비공식 동행복권 API (Node.js)
2
+
3
+ [동행복권](https://dhlottery.co.kr/) 사이트를 터미널에서 이용할 수 있게 랩핑한 API입니다.
4
+ 원본 Python 프로젝트 [roeniss/dhlottery-api](https://github.com/roeniss/dhlottery-api)를 Node.js로 마이그레이션한 버전입니다.
5
+
6
+ ## 요구사항
7
+
8
+ - Node.js 18 이상
9
+
10
+ ## 설치 및 사용법
11
+
12
+ ### npm 패키지로 설치 (배포 후)
13
+
14
+ ```bash
15
+ npm install -g k-dhlottery-api
16
+ # 또는
17
+ npx k-dhlottery-api --help
18
+
19
+ dhapi buy-lotto645 -y
20
+ ```
21
+
22
+ 설치 후 실행 명령어는 `dhapi`입니다 (패키지 이름은 `k-dhlottery-api`).
23
+
24
+ ### 소스에서 설치
25
+
26
+ ```bash
27
+ git clone <this-repo>
28
+ cd k-dhlottery-api
29
+ npm install
30
+ npm run build
31
+
32
+ # 기본 도움말
33
+ dhapi --help
34
+ # 또는
35
+ node dist/cli.js --help
36
+
37
+ # 로또6/45 구매 도움말
38
+ dhapi buy-lotto645 --help
39
+
40
+ # 자동모드 5장 구매 & 확인절차 스킵
41
+ dhapi buy-lotto645 -y
42
+ ```
43
+
44
+ 전역 설치 후 사용:
45
+
46
+ ```bash
47
+ npm link
48
+ dhapi buy-lotto645 -y
49
+ ```
50
+
51
+ ## 구현된 기능들
52
+
53
+ - [로또6/45 구매](https://dhlottery.co.kr/gameInfo.do?method=gameMethod&wiselog=H_B_1_1) (`buy-lotto645`)
54
+ - 자동, 수동, 반자동 모드로 구매 가능합니다.
55
+ - 한 번에 최대 5장까지 구매 가능합니다.
56
+ - 매주 최대 5장까지 구매 가능합니다 (동행복권 측의 온라인 구매 관련 정책입니다).
57
+ - [예치금 현황 조회](https://dhlottery.co.kr/userSsl.do?method=myPage) (`show-balance`)
58
+ - 현재 보유한 예치금 정보를 조회합니다.
59
+ - [고정 가상계좌 입금을 위한 세팅](https://dhlottery.co.kr/userSsl.do?method=myPage) (`assign-virtual-account`)
60
+ - 개인에게 할당된 가상계좌에 입금하는 형태로 예치금을 충전할 수 있습니다. 이 때 얼마를 입금할건지 사이트에서 미리 선택해두어야 하는데, 이 작업을 대신 수행합니다.
61
+ - 입금은 직접 진행해야 합니다.
62
+ - 간편 충전 기능은 구현되지 않았습니다.
63
+
64
+ ### 유틸성 기능들
65
+
66
+ - 복수 프로필 지정
67
+ - 두 개 이상의 프로필을 사용할 수 있습니다. 고급 설정 섹션을 참고해주세요.
68
+ - 프로필 목록 조회 (`show-profiles`)
69
+ - 설정된 프로필 이름들을 확인할 수 있습니다.
70
+
71
+ ## 고급 설정
72
+
73
+ ### 프로필 (계정) 설정
74
+
75
+ > [!NOTE] 최초 프로그램을 실행할 때 프로필 정보를 세팅하는 과정이 진행됩니다. 이 섹션에선 직접 프로필 정보 파일을 수정하는 법을 안내합니다.
76
+
77
+ `~/.dhapi/credentials` (Windows: `%USERPROFILE%\.dhapi\credentials`) 파일을 사용해 프로필 정보를 수정하거나 여러 계정을 설정할 수 있습니다. toml 포맷을 사용하고 있으며, 아래와 같은 형식으로 작성할 수 있습니다.
78
+
79
+ ```toml
80
+ [default]
81
+ username = "dhlotter_id"
82
+ password = "****"
83
+
84
+ [another_profile]
85
+ username = "dhlotter_second_id"
86
+ password = "****"
87
+ ```
88
+
89
+ 이후 `-p` 플래그로 프로필을 골라 사용합니다.
90
+
91
+ ## 명령어 예시
92
+
93
+ ```bash
94
+ # 자동 5장 (기본)
95
+ dhapi buy-lotto645
96
+
97
+ # 자동 1장
98
+ dhapi buy-lotto645 ""
99
+
100
+ # 수동 1장
101
+ dhapi buy-lotto645 "1,2,3,4,5,6"
102
+
103
+ # 반자동 1장 (1,2,3 고정)
104
+ dhapi buy-lotto645 "1,2,3"
105
+
106
+ # 수동 1장 + 반자동 1장
107
+ dhapi buy-lotto645 "1,2,3,4,5,6" "7,8,9"
108
+
109
+ # 확인 없이 자동 5장
110
+ dhapi buy-lotto645 -y
111
+
112
+ # 예치금 조회
113
+ dhapi show-balance
114
+
115
+ # 구매 내역 (최근 14일)
116
+ dhapi show-buy-list -f json
117
+
118
+ # 기간 지정
119
+ dhapi show-buy-list -s 20250101 -e 20250131
120
+ ```
121
+
122
+ ## 백엔드 API 서버 (REST API)
123
+
124
+ CLI 외에 HTTP API 서버로 같은 기능을 사용할 수 있습니다.
125
+
126
+ ```bash
127
+ npm run server
128
+ # 포트 지정 (Windows: set PORT=4000 && npm run server)
129
+ PORT=4000 npm run server
130
+ ```
131
+
132
+ | 메서드 | 경로 | 설명 |
133
+ |--------|------|------|
134
+ | GET | `/api/profiles` | 프로필 목록 |
135
+ | GET | `/api/balance` | 예치금 현황 (query: `profile`) |
136
+ | POST | `/api/buy-lotto645` | 로또 구매 (body: `profile`, `tickets`, `skipConfirm`) |
137
+ | GET | `/api/buy-list` | 구매 내역 (query: `profile`, `format`, `startDate`, `endDate`) |
138
+ | POST | `/api/assign-virtual-account` | 가상계좌 세팅 (body: `profile`, `amount`) |
139
+
140
+ 성공 시 `{ "success": true, "data": ... }`, 실패 시 `{ "success": false, "error": "메시지" }` 형식입니다.
141
+
142
+ ## npm 패키지 배포
143
+
144
+ 이 프로젝트를 npm에 배포하려면:
145
+
146
+ 1. [npmjs.com](https://www.npmjs.com/) 회원가입 후 `npm login`
147
+ 2. 패키지 이름: 이 프로젝트는 `k-dhlottery-api`로 npm에 배포됩니다. 스코프 패키지(예: `@내계정/dhapi`)로 쓰려면 `name`을 변경하면 됩니다.
148
+ 3. 버전 업데이트 후 배포:
149
+
150
+ ```bash
151
+ npm run build
152
+ npm test
153
+ npm publish
154
+ ```
155
+
156
+ - `prepublishOnly` 스크립트로 publish 전에 자동으로 `npm run build`가 실행됩니다.
157
+ - 스코프 패키지(`@xxx/dhapi`)로 배포할 때는 `npm publish --access public`이 필요할 수 있습니다. (`publishConfig.access`가 이미 `public`으로 설정되어 있음)
158
+
159
+ 배포 전에 포함되는 파일 확인: `npm pack --dry-run`
160
+
161
+ ### GitHub Actions로 태그 푸시 시 자동 배포
162
+
163
+ `v*` 형태의 태그를 푸시하면 자동으로 npm에 배포됩니다.
164
+
165
+ 1. **npm 인증 토큰 발급**
166
+ [npm → Access Tokens](https://www.npmjs.com/account/tokens)에서 "Generate New Token" → "Automation" 또는 "Classic" 선택 후 토큰 복사.
167
+
168
+ 2. **GitHub 저장소에 시크릿 추가**
169
+ 저장소 **Settings → Secrets and variables → Actions**에서 New repository secret 추가:
170
+ - Name: `NPM_TOKEN`
171
+ - Value: 위에서 복사한 npm 토큰
172
+
173
+ 3. **버전 올리고 태그 푸시**
174
+
175
+ ```bash
176
+ # package.json의 version 수정 후 (예: 1.0.1)
177
+ git add package.json
178
+ git commit -m "chore: release 1.0.1"
179
+ git tag v1.0.1
180
+ git push origin main
181
+ git push origin v1.0.1
182
+ ```
183
+
184
+ 태그 `v1.0.1`을 푸시하면 `.github/workflows/publish-npm.yml`이 실행되어 빌드·테스트 후 npm에 publish됩니다.
185
+
186
+ ## 기부하기
187
+
188
+ 이 프로그램을 사용해서 1등에 당첨된다면, [원작자 roeniss](https://github.com/roeniss)에게 꼭 1000만원을 기부해주시길 바랍니다.
189
+
190
+ 원본 Python 프로젝트: [Buy Me A Coffee](https://www.buymeacoffee.com/roeniss)
191
+
192
+ ## 기여하기
193
+
194
+ 기여는 대환영합니다! [CONTRIBUTING.md](docs/CONTRIBUTING.md) 파일을 참고해주세요.
195
+
196
+ ## 라이선스
197
+
198
+ MIT. 원본 [dhlottery-api](https://github.com/roeniss/dhlottery-api)는 Apache-2.0 라이선스입니다.
@@ -0,0 +1,2 @@
1
+ import { Router } from "express";
2
+ export declare function createApiRouter(): Router;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createApiRouter = createApiRouter;
4
+ const express_1 = require("express");
5
+ const deposit_1 = require("../domain/deposit");
6
+ const lotto645_ticket_1 = require("../domain/lotto645-ticket");
7
+ const lottery_api_endpoint_1 = require("../endpoint/lottery-api-endpoint");
8
+ const credentials_provider_1 = require("../port/credentials-provider");
9
+ const lottery_client_1 = require("../port/lottery-client");
10
+ function getProfile(req) {
11
+ return req.query.profile || req.body?.profile || "default";
12
+ }
13
+ function jsonSuccess(res, data, status = 200) {
14
+ res.status(status).json({ success: true, data });
15
+ }
16
+ function jsonError(res, message, status = 500) {
17
+ res.status(status).json({ success: false, error: message });
18
+ }
19
+ function createApiRouter() {
20
+ const router = (0, express_1.Router)();
21
+ /** GET /api/profiles - 등록된 프로필 목록 */
22
+ router.get("/profiles", (req, res) => {
23
+ try {
24
+ const profiles = credentials_provider_1.CredentialsProvider.listProfiles();
25
+ jsonSuccess(res, { profiles });
26
+ }
27
+ catch (e) {
28
+ jsonError(res, e.message || "프로필 목록을 불러올 수 없습니다.", 404);
29
+ }
30
+ });
31
+ /** GET /api/balance - 예치금 현황 (query: profile) */
32
+ router.get("/balance", async (req, res) => {
33
+ const profile = getProfile(req);
34
+ try {
35
+ const user = new credentials_provider_1.CredentialsProvider(profile).getUser();
36
+ const endpoint = new lottery_api_endpoint_1.LotteryApiEndpoint();
37
+ const client = new lottery_client_1.LotteryClient(user, endpoint);
38
+ await client.showBalance();
39
+ if (!endpoint.result.showBalance) {
40
+ return jsonError(res, "예치금 정보를 가져오지 못했습니다.", 502);
41
+ }
42
+ jsonSuccess(res, endpoint.result.showBalance);
43
+ }
44
+ catch (e) {
45
+ jsonError(res, e.message || "예치금 조회에 실패했습니다.", 500);
46
+ }
47
+ });
48
+ /** POST /api/buy-lotto645 - 로또 6/45 구매 (body: { profile?, tickets?: string[], skipConfirm?: boolean }) */
49
+ router.post("/buy-lotto645", async (req, res) => {
50
+ const profile = getProfile(req);
51
+ const ticketsInput = req.body?.tickets;
52
+ const skipConfirm = !!req.body?.skipConfirm;
53
+ try {
54
+ const user = new credentials_provider_1.CredentialsProvider(profile).getUser();
55
+ const tickets = ticketsInput && ticketsInput.length > 0
56
+ ? lotto645_ticket_1.Lotto645Ticket.createTickets(ticketsInput)
57
+ : lotto645_ticket_1.Lotto645Ticket.createAutoTickets(5);
58
+ if (!skipConfirm && tickets.length > 0) {
59
+ // API에서는 기본적으로 확인 스킵 (skipConfirm=true 권장)
60
+ }
61
+ const endpoint = new lottery_api_endpoint_1.LotteryApiEndpoint();
62
+ const client = new lottery_client_1.LotteryClient(user, endpoint);
63
+ await client.buyLotto645(tickets);
64
+ if (!endpoint.result.buyLotto645) {
65
+ return jsonError(res, "구매 결과를 가져오지 못했습니다.", 502);
66
+ }
67
+ jsonSuccess(res, endpoint.result.buyLotto645);
68
+ }
69
+ catch (e) {
70
+ jsonError(res, e.message || "로또 구매에 실패했습니다.", 500);
71
+ }
72
+ });
73
+ /** GET /api/buy-list - 구매 내역 (query: profile, format?, startDate?, endDate?) */
74
+ router.get("/buy-list", async (req, res) => {
75
+ const profile = getProfile(req);
76
+ const format = req.query.format || "json";
77
+ const startDate = req.query.startDate;
78
+ const endDate = req.query.endDate;
79
+ try {
80
+ const user = new credentials_provider_1.CredentialsProvider(profile).getUser();
81
+ const endpoint = new lottery_api_endpoint_1.LotteryApiEndpoint();
82
+ const client = new lottery_client_1.LotteryClient(user, endpoint);
83
+ await client.showBuyList(format, startDate, endDate);
84
+ if (!endpoint.result.showBuyList) {
85
+ return jsonError(res, "구매 내역을 가져오지 못했습니다.", 502);
86
+ }
87
+ jsonSuccess(res, endpoint.result.showBuyList);
88
+ }
89
+ catch (e) {
90
+ jsonError(res, e.message || "구매 내역 조회에 실패했습니다.", 500);
91
+ }
92
+ });
93
+ /** POST /api/assign-virtual-account - 가상계좌 세팅 (body: { profile?, amount: number }) */
94
+ router.post("/assign-virtual-account", async (req, res) => {
95
+ const profile = getProfile(req);
96
+ const amount = req.body?.amount != null ? Number(req.body.amount) : 50000;
97
+ try {
98
+ const user = new credentials_provider_1.CredentialsProvider(profile).getUser();
99
+ const deposit = new deposit_1.Deposit(amount);
100
+ const endpoint = new lottery_api_endpoint_1.LotteryApiEndpoint();
101
+ const client = new lottery_client_1.LotteryClient(user, endpoint);
102
+ await client.assignVirtualAccount(deposit);
103
+ if (!endpoint.result.assignVirtualAccount) {
104
+ return jsonError(res, "가상계좌 정보를 가져오지 못했습니다.", 502);
105
+ }
106
+ jsonSuccess(res, endpoint.result.assignVirtualAccount);
107
+ }
108
+ catch (e) {
109
+ jsonError(res, e.message || "가상계좌 할당에 실패했습니다.", 500);
110
+ }
111
+ });
112
+ return router;
113
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const commander_1 = require("commander");
7
+ const cli_table3_1 = __importDefault(require("cli-table3"));
8
+ const deposit_1 = require("./domain/deposit");
9
+ const lotto645_ticket_1 = require("./domain/lotto645-ticket");
10
+ const lottery_stdout_printer_1 = require("./endpoint/lottery-stdout-printer");
11
+ const credentials_provider_1 = require("./port/credentials-provider");
12
+ const lottery_client_1 = require("./port/lottery-client");
13
+ const lotto645_buy_confirmer_1 = require("./purchase/lotto645-buy-confirmer");
14
+ const pkg = require("../package.json");
15
+ const program = new commander_1.Command();
16
+ program
17
+ .name("dhapi")
18
+ .description("동행복권 비공식 API\n\n각 명령어에 대한 자세한 도움말은 'dhapi [명령어] -h'를 입력하세요.")
19
+ .version(pkg.version, "-V, --version", "dhapi 버전을 출력합니다.");
20
+ program
21
+ .command("assign-virtual-account")
22
+ .description("예치금 충전용 가상계좌를 세팅합니다. dhapi에서는 본인 전용 계좌를 발급받는 것까지만 가능합니다. 출력되는 계좌로 직접 입금해주세요.")
23
+ .argument("[amount]", "입금할 금액 (5천원, 1만원, 2만원, 3만원, 5만원, 10만원, 20만원, 30만원, 50만원, 70만원, 100만원 중 하나)", "50000")
24
+ .option("-p, --profile <name>", "프로필을 지정합니다", "default")
25
+ .option("-d, --debug", "debug 로그를 활성화합니다")
26
+ .action(async (amountStr, opts) => {
27
+ const user = new credentials_provider_1.CredentialsProvider(opts.profile).getUser();
28
+ const amount = parseInt(amountStr, 10);
29
+ const deposit = new deposit_1.Deposit(amount);
30
+ const endpoint = new lottery_stdout_printer_1.LotteryStdoutPrinter();
31
+ const client = new lottery_client_1.LotteryClient(user, endpoint);
32
+ await client.assignVirtualAccount(deposit);
33
+ });
34
+ program
35
+ .command("show-balance")
36
+ .description("예치금 현황을 조회합니다.")
37
+ .option("-p, --profile <name>", "프로필을 지정합니다", "default")
38
+ .option("-d, --debug", "debug 로그를 활성화합니다")
39
+ .action(async (opts) => {
40
+ const user = new credentials_provider_1.CredentialsProvider(opts.profile).getUser();
41
+ const endpoint = new lottery_stdout_printer_1.LotteryStdoutPrinter();
42
+ const client = new lottery_client_1.LotteryClient(user, endpoint);
43
+ await client.showBalance();
44
+ });
45
+ program
46
+ .command("show-buy-list")
47
+ .description("구매 내역을 조회합니다. 기본적으로 최근 14일간의 내역을 조회하며, --start-date 및 --end-date 옵션을 통해 조회 기간을 지정할 수 있습니다.")
48
+ .option("-p, --profile <name>", "프로필을 지정합니다", "default")
49
+ .option("-f, --format <format>", "출력 형식 (table, json)", "table")
50
+ .option("-s, --start-date <YYYYMMDD>", "조회 시작 날짜")
51
+ .option("-e, --end-date <YYYYMMDD>", "조회 종료 날짜")
52
+ .option("-d, --debug", "debug 로그를 활성화합니다")
53
+ .action(async (opts) => {
54
+ const user = new credentials_provider_1.CredentialsProvider(opts.profile).getUser();
55
+ const endpoint = new lottery_stdout_printer_1.LotteryStdoutPrinter();
56
+ const client = new lottery_client_1.LotteryClient(user, endpoint);
57
+ await client.showBuyList(opts.format, opts.startDate, opts.endDate);
58
+ });
59
+ program
60
+ .command("show-profiles")
61
+ .description("등록된 프로필 목록을 출력합니다.")
62
+ .action(() => {
63
+ try {
64
+ const profiles = credentials_provider_1.CredentialsProvider.listProfiles();
65
+ const table = new cli_table3_1.default({ head: ["profiles"], style: { head: [] } });
66
+ profiles.forEach((name) => table.push([name]));
67
+ console.log(table.toString());
68
+ }
69
+ catch (e) {
70
+ console.error("❌", e.message);
71
+ process.exit(1);
72
+ }
73
+ });
74
+ program
75
+ .command("buy-lotto645")
76
+ .description(`로또6/45 복권을 구매합니다. 매주 최대 다섯 장까지 구매할 수 있습니다.
77
+
78
+ 예시:
79
+ dhapi buy-lotto645 자동모드 5장 (default)
80
+ dhapi buy-lotto645 '' 자동모드 1장
81
+ dhapi buy-lotto645 '1,2,3,4,5,6' 수동모드 1장
82
+ dhapi buy-lotto645 '1,2,3' 반자동모드 1장
83
+ dhapi buy-lotto645 '1,2,3,4,5,6' '7,8,9' 수동 1장 + 반자동 1장
84
+ dhapi buy-lotto645 -y 확인 스킵하고 자동 5장 구매`)
85
+ .argument("[tickets...]", "구매할 번호 (생략 시 자동 5장)")
86
+ .option("-y, --yes", "구매 전 확인 절차를 스킵합니다.")
87
+ .option("-p, --profile <name>", "프로필을 지정합니다", "default")
88
+ .option("-d, --debug", "debug 로그를 활성화합니다")
89
+ .action(async (ticketArgs, opts) => {
90
+ const user = new credentials_provider_1.CredentialsProvider(opts.profile).getUser();
91
+ const tickets = ticketArgs && ticketArgs.length > 0
92
+ ? lotto645_ticket_1.Lotto645Ticket.createTickets(ticketArgs)
93
+ : lotto645_ticket_1.Lotto645Ticket.createAutoTickets(5);
94
+ const endpoint = new lottery_stdout_printer_1.LotteryStdoutPrinter();
95
+ const client = new lottery_client_1.LotteryClient(user, endpoint);
96
+ const confirmer = new lotto645_buy_confirmer_1.Lotto645BuyConfirmer();
97
+ const ok = confirmer.confirm(tickets, !!opts.yes);
98
+ if (!ok)
99
+ process.exit(0);
100
+ await client.buyLotto645(tickets);
101
+ });
102
+ program.parse();
@@ -0,0 +1,4 @@
1
+ export declare class Deposit {
2
+ readonly amount: number;
3
+ constructor(amount: number | string);
4
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Deposit = void 0;
4
+ const ALLOWED_AMOUNTS = [
5
+ 5000, 10000, 20000, 30000, 50000, 100000, 200000, 300000, 500000, 700000,
6
+ 1000000,
7
+ ];
8
+ class Deposit {
9
+ constructor(amount) {
10
+ const n = typeof amount === "string" ? parseInt(amount, 10) : amount;
11
+ if (Number.isNaN(n)) {
12
+ throw new Error(`숫자를 입력하세요 (입력된 값: ${amount}).`);
13
+ }
14
+ if (!ALLOWED_AMOUNTS.includes(n)) {
15
+ throw new Error("입금 가능한 금액은 5천원, 1만원, 2만원, 3만원, 5만원, 10만원, 20만원, 30만원, 50만원, 70만원, 100만원입니다 (입력된 값: " +
16
+ amount +
17
+ ").");
18
+ }
19
+ this.amount = n;
20
+ }
21
+ }
22
+ exports.Deposit = Deposit;
@@ -0,0 +1,13 @@
1
+ export declare enum Lotto645Mode {
2
+ AUTO = "auto",
3
+ SEMIAUTO = "semiauto",
4
+ MANUAL = "manual"
5
+ }
6
+ export declare class Lotto645Ticket {
7
+ readonly numbers: number[];
8
+ readonly mode: Lotto645Mode;
9
+ constructor(numbersStr?: string);
10
+ get modeKor(): string;
11
+ static createAutoTickets(count: number): Lotto645Ticket[];
12
+ static createTickets(numbersList: string[]): Lotto645Ticket[];
13
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Lotto645Ticket = exports.Lotto645Mode = void 0;
4
+ var Lotto645Mode;
5
+ (function (Lotto645Mode) {
6
+ Lotto645Mode["AUTO"] = "auto";
7
+ Lotto645Mode["SEMIAUTO"] = "semiauto";
8
+ Lotto645Mode["MANUAL"] = "manual";
9
+ })(Lotto645Mode || (exports.Lotto645Mode = Lotto645Mode = {}));
10
+ class Lotto645Ticket {
11
+ constructor(numbersStr) {
12
+ if (!numbersStr || numbersStr.trim() === "") {
13
+ this.numbers = [];
14
+ this.mode = Lotto645Mode.AUTO;
15
+ return;
16
+ }
17
+ const parts = numbersStr.split(",").map((s) => s.trim());
18
+ const numbers = parts
19
+ .map((s) => {
20
+ const n = parseInt(s, 10);
21
+ if (Number.isNaN(n))
22
+ throw new Error(`숫자를 입력하세요 (입력된 값: ${numbersStr}).`);
23
+ return n;
24
+ })
25
+ .sort((a, b) => a - b);
26
+ const unique = [...new Set(numbers)];
27
+ if (numbers.length !== unique.length) {
28
+ throw new Error(`중복되지 않도록 숫자들을 입력하세요 (입력된 값: ${numbersStr}).`);
29
+ }
30
+ for (const n of numbers) {
31
+ if (n < 1 || n > 45) {
32
+ throw new Error(`각 번호는 1부터 45까지의 숫자만 사용할 수 있습니다 (입력된 값: ${n}).`);
33
+ }
34
+ }
35
+ this.numbers = numbers;
36
+ if (numbers.length === 6) {
37
+ this.mode = Lotto645Mode.MANUAL;
38
+ }
39
+ else if (numbers.length >= 1 && numbers.length <= 5) {
40
+ this.mode = Lotto645Mode.SEMIAUTO;
41
+ }
42
+ else if (numbers.length === 0) {
43
+ this.mode = Lotto645Mode.AUTO;
44
+ }
45
+ else {
46
+ throw new Error(`숫자는 0개 이상 6개 이하의 숫자를 입력해야 합니다 (입력된 값: ${numbersStr}).`);
47
+ }
48
+ }
49
+ get modeKor() {
50
+ switch (this.mode) {
51
+ case Lotto645Mode.AUTO:
52
+ return "자동";
53
+ case Lotto645Mode.SEMIAUTO:
54
+ return "반자동";
55
+ case Lotto645Mode.MANUAL:
56
+ return "수동";
57
+ default:
58
+ throw new Error("지원하지 않는 게임 타입입니다.");
59
+ }
60
+ }
61
+ static createAutoTickets(count) {
62
+ return Array.from({ length: count }, () => new Lotto645Ticket());
63
+ }
64
+ static createTickets(numbersList) {
65
+ return numbersList.map((n) => new Lotto645Ticket(n));
66
+ }
67
+ }
68
+ exports.Lotto645Ticket = Lotto645Ticket;
@@ -0,0 +1,5 @@
1
+ export declare class User {
2
+ readonly username: string;
3
+ readonly password: string;
4
+ constructor(username: string, password: string);
5
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.User = void 0;
4
+ class User {
5
+ constructor(username, password) {
6
+ this.username = username;
7
+ this.password = password;
8
+ }
9
+ }
10
+ exports.User = User;
@@ -0,0 +1,55 @@
1
+ import type { LotteryEndpoint } from "../port/lottery-endpoint";
2
+ /**
3
+ * Endpoint adapter that captures results for API responses (no stdout).
4
+ */
5
+ export interface ApiResult {
6
+ buyLotto645?: {
7
+ slots: Array<{
8
+ slot: string;
9
+ mode: string;
10
+ numbers: string[];
11
+ }>;
12
+ };
13
+ showBalance?: {
14
+ totalDeposit: number;
15
+ purchaseAvailable: number;
16
+ reservedAmount: number;
17
+ withdrawalPending: number;
18
+ purchaseUnavailable: number;
19
+ lastMonthTotalPurchase: number;
20
+ };
21
+ showBuyList?: {
22
+ startDate: string;
23
+ endDate: string;
24
+ format: string;
25
+ data: Array<{
26
+ headers: string[];
27
+ rows: string[][];
28
+ }>;
29
+ };
30
+ assignVirtualAccount?: {
31
+ accountNumber: string;
32
+ amount: string;
33
+ };
34
+ }
35
+ export declare class LotteryApiEndpoint implements LotteryEndpoint {
36
+ readonly result: ApiResult;
37
+ printResultOfBuyLotto645(slots: Array<{
38
+ slot: string;
39
+ mode: string;
40
+ numbers: string[];
41
+ }>): void;
42
+ printResultOfShowBalance(data: {
43
+ totalDeposit: number;
44
+ purchaseAvailable: number;
45
+ reservedAmount: number;
46
+ withdrawalPending: number;
47
+ purchaseUnavailable: number;
48
+ lastMonthTotalPurchase: number;
49
+ }): void;
50
+ printResultOfShowBuyList(data: Array<{
51
+ headers: string[];
52
+ rows: string[][];
53
+ }>, outputFormat: string, startDate: string, endDate: string): void;
54
+ printResultOfAssignVirtualAccount(accountNumber: string, amount: string): void;
55
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LotteryApiEndpoint = void 0;
4
+ class LotteryApiEndpoint {
5
+ constructor() {
6
+ this.result = {};
7
+ }
8
+ printResultOfBuyLotto645(slots) {
9
+ this.result.buyLotto645 = { slots };
10
+ }
11
+ printResultOfShowBalance(data) {
12
+ this.result.showBalance = { ...data };
13
+ }
14
+ printResultOfShowBuyList(data, outputFormat, startDate, endDate) {
15
+ this.result.showBuyList = {
16
+ startDate,
17
+ endDate,
18
+ format: outputFormat,
19
+ data,
20
+ };
21
+ }
22
+ printResultOfAssignVirtualAccount(accountNumber, amount) {
23
+ this.result.assignVirtualAccount = { accountNumber, amount };
24
+ }
25
+ }
26
+ exports.LotteryApiEndpoint = LotteryApiEndpoint;
@@ -0,0 +1,21 @@
1
+ import type { LotteryEndpoint } from "../port/lottery-endpoint";
2
+ export declare class LotteryStdoutPrinter implements LotteryEndpoint {
3
+ printResultOfAssignVirtualAccount(accountNumber: string, amountStr: string): void;
4
+ printResultOfShowBalance(data: {
5
+ totalDeposit: number;
6
+ purchaseAvailable: number;
7
+ reservedAmount: number;
8
+ withdrawalPending: number;
9
+ purchaseUnavailable: number;
10
+ lastMonthTotalPurchase: number;
11
+ }): void;
12
+ printResultOfBuyLotto645(slots: Array<{
13
+ slot: string;
14
+ mode: string;
15
+ numbers: string[];
16
+ }>): void;
17
+ printResultOfShowBuyList(data: Array<{
18
+ headers: string[];
19
+ rows: string[][];
20
+ }>, outputFormat: string, startDate: string, endDate: string): void;
21
+ }