deliveryapi 0.1.4 → 0.2.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.
package/dist/index.js CHANGED
@@ -1,226 +1,309 @@
1
- // src/errors.ts
2
- var DeliverySaasError = class extends Error {
3
- constructor(message, statusCode, code) {
1
+ // src/http.ts
2
+ var ApiError = class extends Error {
3
+ constructor(statusCode, errorCode, message) {
4
4
  super(message);
5
5
  this.statusCode = statusCode;
6
- this.code = code;
7
- this.name = "DeliverySaasError";
8
- }
9
- };
10
- var AuthenticationError = class extends DeliverySaasError {
11
- constructor(message = "Invalid API key or secret key") {
12
- super(message, 401, "AUTHENTICATION_ERROR");
13
- this.name = "AuthenticationError";
6
+ this.errorCode = errorCode;
7
+ this.name = "ApiError";
14
8
  }
15
9
  };
16
- var RateLimitError = class extends DeliverySaasError {
17
- constructor(message = "Rate limit exceeded") {
18
- super(message, 429, "RATE_LIMIT_ERROR");
19
- this.name = "RateLimitError";
10
+ async function request(baseUrl, path, options = {}) {
11
+ const { token, ...fetchOptions } = options;
12
+ const headers = {
13
+ "Content-Type": "application/json",
14
+ ...fetchOptions.headers
15
+ };
16
+ if (token) {
17
+ headers["Authorization"] = `Bearer ${token}`;
20
18
  }
21
- };
22
- var NotFoundError = class extends DeliverySaasError {
23
- constructor(message = "Resource not found") {
24
- super(message, 404, "NOT_FOUND");
25
- this.name = "NotFoundError";
19
+ const res = await fetch(`${baseUrl}${path}`, {
20
+ ...fetchOptions,
21
+ headers
22
+ });
23
+ const body = await res.json();
24
+ if (!res.ok || !body.isSuccess) {
25
+ throw new ApiError(
26
+ res.status,
27
+ body.errorCode,
28
+ body.error ?? `Request failed with status ${res.status}`
29
+ );
26
30
  }
27
- };
31
+ return body.data;
32
+ }
28
33
 
29
- // src/http.ts
30
- var HttpClient = class {
31
- constructor(apiKey, secretKey, baseUrl) {
32
- this.baseUrl = baseUrl.replace(/\/$/, "");
33
- this.authHeader = `Bearer ${apiKey}:${secretKey}`;
34
- }
35
- async get(path, params) {
36
- const url = new URL(`${this.baseUrl}${path}`);
37
- if (params) {
38
- Object.entries(params).forEach(([key, value]) => url.searchParams.set(key, value));
39
- }
40
- return this.request("GET", url.toString());
41
- }
42
- async post(path, body) {
43
- return this.request("POST", `${this.baseUrl}${path}`, body);
44
- }
45
- async put(path, body) {
46
- return this.request("PUT", `${this.baseUrl}${path}`, body);
47
- }
48
- async patch(path, body) {
49
- return this.request("PATCH", `${this.baseUrl}${path}`, body);
50
- }
51
- async delete(path) {
52
- return this.request("DELETE", `${this.baseUrl}${path}`);
53
- }
54
- async request(method, url, body) {
55
- const headers = {
56
- Authorization: this.authHeader,
57
- "Content-Type": "application/json"
58
- };
59
- const response = await fetch(url, {
60
- method,
61
- headers,
62
- body: body !== void 0 ? JSON.stringify(body) : void 0
63
- });
64
- const json = await response.json();
65
- if (!response.ok) {
66
- if (response.status === 401) throw new AuthenticationError(json.message);
67
- if (response.status === 404) throw new NotFoundError(json.message);
68
- if (response.status === 429) throw new RateLimitError(json.message);
69
- throw new DeliverySaasError(json.message ?? "Request failed", response.status, json.error);
70
- }
71
- if (!json.isSuccess) {
72
- throw new DeliverySaasError(json.message ?? "API returned failure", response.status, json.error);
73
- }
74
- return json.data;
34
+ // src/resources/auth.ts
35
+ var AuthResource = class {
36
+ constructor(baseUrl, getToken) {
37
+ this.baseUrl = baseUrl;
38
+ this.getToken = getToken;
39
+ }
40
+ /** Step 1: 이메일 인증 코드 요청 */
41
+ async requestVerification(params) {
42
+ await request(this.baseUrl, "/v1/homepage/register/request", {
43
+ method: "POST",
44
+ body: JSON.stringify(params)
45
+ });
46
+ }
47
+ /** Step 2: 인증 코드 검증 + Firebase 계정 생성 → customToken 반환 */
48
+ async verifyAndRegister(params) {
49
+ return request(this.baseUrl, "/v1/homepage/register/verify", {
50
+ method: "POST",
51
+ body: JSON.stringify(params)
52
+ });
53
+ }
54
+ /** Google 로그인 후 HP 사용자 문서 확인/생성 */
55
+ async ensureUser() {
56
+ const token = await this.getToken();
57
+ return request(this.baseUrl, "/v1/homepage/ensure-user", {
58
+ method: "POST",
59
+ body: JSON.stringify({}),
60
+ token
61
+ });
75
62
  }
76
63
  };
77
64
 
78
- // src/resources/tracking.ts
79
- var TrackingResource = class {
80
- constructor(http) {
81
- this.http = http;
82
- }
83
- /**
84
- * 택배 조회 (공개 API, 계정 불필요)
85
- * @param items 조회할 택배 목록 (1건도 배열로)
86
- * @param includeProgresses 진행 내역 포함 여부 (기본값: true)
87
- */
88
- async get(items, includeProgresses = true) {
89
- return this.http.post("/v1/tracking/trace", {
90
- items,
91
- includeProgresses
92
- });
93
- }
94
- /**
95
- * 단건 택배 조회 (편의 메서드)
96
- */
97
- async getOne(courierCode, trackingNumber, options) {
98
- return this.get(
99
- [{ courierCode, trackingNumber, clientId: options?.clientId }],
100
- options?.includeProgresses ?? true
101
- );
65
+ // src/resources/dashboard.ts
66
+ var DashboardResource = class {
67
+ constructor(baseUrl, getToken) {
68
+ this.baseUrl = baseUrl;
69
+ this.getToken = getToken;
70
+ }
71
+ /** 대시보드 데이터 조회 (API 목록, 사용량, 플랜 정보) */
72
+ async get() {
73
+ const token = await this.getToken();
74
+ return request(this.baseUrl, "/v1/homepage/dashboard", { token });
75
+ }
76
+ /** API 키 발급 */
77
+ async issueKey() {
78
+ const token = await this.getToken();
79
+ return request(this.baseUrl, "/v1/homepage/dashboard/issue-key", {
80
+ method: "POST",
81
+ body: JSON.stringify({}),
82
+ token
83
+ });
102
84
  }
103
85
  };
104
86
 
105
- // src/resources/subscriptions.ts
106
- var SubscriptionsResource = class {
107
- constructor(http) {
108
- this.http = http;
109
- }
110
- /**
111
- * 택배 구독 생성 (단건)
112
- * 상태 변경 등록된 웹훅 엔드포인트로 알림 전송
113
- */
114
- async create(data) {
115
- return this.http.post("/v1/tracking/subscriptions", {
116
- items: [data]
117
- });
118
- }
119
- /**
120
- * 택배 구독 일괄 생성 (최대 100건)
121
- */
122
- async createBatch(items) {
123
- return this.http.post("/v1/tracking/subscriptions", { items });
124
- }
125
- /**
126
- * 택배 구독 목록 조회
127
- */
128
- async list(options) {
129
- const params = {};
130
- if (options?.status) params["status"] = options.status;
131
- if (options?.limit) params["limit"] = String(options.limit);
132
- if (options?.cursor) params["cursor"] = options.cursor;
133
- return this.http.get("/v1/tracking/subscriptions", params);
134
- }
135
- /**
136
- * 택배 구독 상세 조회
137
- */
138
- async retrieve(subscriptionId) {
139
- return this.http.get(`/v1/tracking/subscriptions/${subscriptionId}`);
140
- }
141
- /**
142
- * 택배 구독 취소 (ID)
143
- */
144
- async cancel(subscriptionId) {
145
- await this.http.delete(`/v1/tracking/subscriptions/${subscriptionId}`);
146
- }
147
- /**
148
- * 택배 구독 취소 (송장번호)
149
- */
150
- async cancelByTracking(courierCode, trackingNumber) {
151
- return this.http.delete(
152
- `/v1/tracking/subscriptions?courierCode=${encodeURIComponent(courierCode)}&trackingNumber=${encodeURIComponent(trackingNumber)}`
153
- );
87
+ // src/resources/qna.ts
88
+ var QnaResource = class {
89
+ constructor(baseUrl, getToken) {
90
+ this.baseUrl = baseUrl;
91
+ this.getToken = getToken;
92
+ }
93
+ /** 게시글 목록 조회 (비회원도 공개글 열람 가능) */
94
+ async listPosts(params = {}) {
95
+ const token = await this.getToken();
96
+ const qs = new URLSearchParams();
97
+ if (params.cursor) qs.set("cursor", params.cursor);
98
+ if (params.pageSize) qs.set("pageSize", String(params.pageSize));
99
+ const query = qs.toString() ? `?${qs.toString()}` : "";
100
+ return request(this.baseUrl, `/v1/homepage/posts${query}`, { token });
101
+ }
102
+ /** 게시글 상세 조회 */
103
+ async getPost(postId) {
104
+ const token = await this.getToken();
105
+ return request(this.baseUrl, `/v1/homepage/posts/${postId}`, { token });
106
+ }
107
+ /** 게시글 작성 (로그인 필요) */
108
+ async createPost(params) {
109
+ const token = await this.getToken();
110
+ return request(this.baseUrl, "/v1/homepage/posts", {
111
+ method: "POST",
112
+ body: JSON.stringify(params),
113
+ token
114
+ });
115
+ }
116
+ /** 게시글 수정 (작성자/관리자만) */
117
+ async updatePost(postId, params) {
118
+ const token = await this.getToken();
119
+ return request(this.baseUrl, `/v1/homepage/posts/${postId}`, {
120
+ method: "PUT",
121
+ body: JSON.stringify(params),
122
+ token
123
+ });
124
+ }
125
+ /** 게시글 삭제 (작성자/관리자만) */
126
+ async deletePost(postId) {
127
+ const token = await this.getToken();
128
+ await request(this.baseUrl, `/v1/homepage/posts/${postId}`, {
129
+ method: "DELETE",
130
+ token
131
+ });
132
+ }
133
+ /** 댓글 목록 조회 */
134
+ async listComments(postId) {
135
+ const token = await this.getToken();
136
+ return request(this.baseUrl, `/v1/homepage/posts/${postId}/comments`, { token });
137
+ }
138
+ /** 댓글 작성 (로그인 필요) */
139
+ async createComment(postId, params) {
140
+ const token = await this.getToken();
141
+ return request(this.baseUrl, `/v1/homepage/posts/${postId}/comments`, {
142
+ method: "POST",
143
+ body: JSON.stringify(params),
144
+ token
145
+ });
146
+ }
147
+ /** 댓글 삭제 (작성자/관리자만) */
148
+ async deleteComment(commentId) {
149
+ const token = await this.getToken();
150
+ await request(this.baseUrl, `/v1/homepage/comments/${commentId}`, {
151
+ method: "DELETE",
152
+ token
153
+ });
154
154
  }
155
155
  };
156
156
 
157
- // src/resources/webhooks.ts
158
- var WebhooksResource = class {
159
- constructor(http) {
160
- this.http = http;
161
- }
162
- /**
163
- * 웹훅 엔드포인트 등록
164
- */
165
- async create(data) {
166
- return this.http.post("/v1/webhook-v2/endpoints", data);
167
- }
168
- /**
169
- * 웹훅 엔드포인트 목록 조회
170
- */
171
- async list() {
172
- return this.http.get("/v1/webhook-v2/endpoints");
173
- }
174
- /**
175
- * 웹훅 엔드포인트 이름 수정
176
- */
177
- async update(endpointId, data) {
178
- await this.http.put(`/v1/webhook-v2/endpoints/${endpointId}`, data);
179
- }
180
- /**
181
- * 웹훅 엔드포인트 삭제
182
- */
183
- async delete(endpointId) {
184
- await this.http.delete(`/v1/webhook-v2/endpoints/${endpointId}`);
185
- }
186
- /**
187
- * 웹훅 시크릿 재발급
188
- */
189
- async rotateSecret(endpointId, webhookSecret) {
190
- return this.http.post(
191
- `/v1/webhook-v2/endpoints/${endpointId}/rotate`,
192
- webhookSecret ? { webhookSecret } : void 0
157
+ // src/resources/admin.ts
158
+ var AdminResource = class {
159
+ constructor(baseUrl, getToken) {
160
+ this.baseUrl = baseUrl;
161
+ this.getToken = getToken;
162
+ }
163
+ async token() {
164
+ return this.getToken();
165
+ }
166
+ /** 전체 통계 조회 */
167
+ async getStats() {
168
+ return request(this.baseUrl, "/v1/homepage/admin/stats", {
169
+ token: await this.token()
170
+ });
171
+ }
172
+ /** 최근 14일 일별 가입자 수 */
173
+ async getDailySignups() {
174
+ return request(this.baseUrl, "/v1/homepage/admin/daily-signups", {
175
+ token: await this.token()
176
+ });
177
+ }
178
+ /** 사용자 목록 조회 */
179
+ async listUsers() {
180
+ return request(this.baseUrl, "/v1/homepage/admin/users", {
181
+ token: await this.token()
182
+ });
183
+ }
184
+ /** 사용자 정보 수정 */
185
+ async updateUser(uid, params) {
186
+ await request(this.baseUrl, `/v1/homepage/admin/users/${uid}`, {
187
+ method: "PATCH",
188
+ body: JSON.stringify(params),
189
+ token: await this.token()
190
+ });
191
+ }
192
+ /** 사용자 상세 조회 (API + 사용량 포함) */
193
+ async getUserDetail(uid) {
194
+ return request(this.baseUrl, `/v1/homepage/admin/users/${uid}/detail`, {
195
+ token: await this.token()
196
+ });
197
+ }
198
+ /** customers 목록 조회 */
199
+ async listCustomers() {
200
+ return request(this.baseUrl, "/v1/homepage/admin/customers", {
201
+ token: await this.token()
202
+ });
203
+ }
204
+ /** API 키 목록 조회 */
205
+ async listKeys() {
206
+ return request(this.baseUrl, "/v1/homepage/admin/keys", {
207
+ token: await this.token()
208
+ });
209
+ }
210
+ /** API 키 플랜 변경 */
211
+ async updateKeyPlan(apiKeyHash, params) {
212
+ await request(this.baseUrl, `/v1/homepage/admin/keys/${apiKeyHash}/plan`, {
213
+ method: "PATCH",
214
+ body: JSON.stringify(params),
215
+ token: await this.token()
216
+ });
217
+ }
218
+ /** API 키 플랜 일괄 변경 */
219
+ async bulkUpdateKeyPlan(params) {
220
+ await request(this.baseUrl, "/v1/homepage/admin/keys/bulk/plan", {
221
+ method: "PATCH",
222
+ body: JSON.stringify(params),
223
+ token: await this.token()
224
+ });
225
+ }
226
+ /** Secret Key limits 수정 */
227
+ async updateKeyLimits(apiKeyHash, params) {
228
+ await request(this.baseUrl, `/v1/homepage/admin/keys/${apiKeyHash}/limits`, {
229
+ method: "PATCH",
230
+ body: JSON.stringify(params),
231
+ token: await this.token()
232
+ });
233
+ }
234
+ /** 데모 키 생성 */
235
+ async createDemoKey(params = {}) {
236
+ return request(this.baseUrl, "/v1/homepage/admin/demo-keys", {
237
+ method: "POST",
238
+ body: JSON.stringify(params),
239
+ token: await this.token()
240
+ });
241
+ }
242
+ /** 데모 키 목록 조회 */
243
+ async listDemoKeys() {
244
+ return request(this.baseUrl, "/v1/homepage/admin/demo-keys", {
245
+ token: await this.token()
246
+ });
247
+ }
248
+ /** 데모 키 비활성화 */
249
+ async deactivateDemoKey(apiKeyHash) {
250
+ await request(this.baseUrl, `/v1/homepage/admin/demo-keys/${apiKeyHash}/deactivate`, {
251
+ method: "PATCH",
252
+ body: JSON.stringify({}),
253
+ token: await this.token()
254
+ });
255
+ }
256
+ /** 데모 키 활성화 */
257
+ async activateDemoKey(apiKeyHash) {
258
+ await request(this.baseUrl, `/v1/homepage/admin/demo-keys/${apiKeyHash}/activate`, {
259
+ method: "PATCH",
260
+ body: JSON.stringify({}),
261
+ token: await this.token()
262
+ });
263
+ }
264
+ /** 조회 로그 목록 */
265
+ async listTrackingLogs(page = 1) {
266
+ return request(
267
+ this.baseUrl,
268
+ `/v1/homepage/admin/tracking-logs?page=${page}`,
269
+ { token: await this.token() }
193
270
  );
194
271
  }
195
272
  };
196
273
 
197
- // src/resources/couriers.ts
198
- var CouriersResource = class {
199
- constructor(http) {
200
- this.http = http;
274
+ // src/resources/public.ts
275
+ var PublicResource = class {
276
+ constructor(baseUrl) {
277
+ this.baseUrl = baseUrl;
201
278
  }
202
- /**
203
- * 지원 택배사 목록 조회
204
- */
205
- async list() {
206
- return this.http.get("/v1/tracking/couriers");
279
+ /** 요금제 목록 조회 */
280
+ async getPlans() {
281
+ return request(this.baseUrl, "/v1/homepage/plans");
282
+ }
283
+ /** Secret Key 프리셋 목록 조회 */
284
+ async getSecretPresets() {
285
+ return request(this.baseUrl, "/v1/homepage/secret-presets");
286
+ }
287
+ /** 개발 의뢰 문의 전송 */
288
+ async sendContactInquiry(params) {
289
+ await request(this.baseUrl, "/v1/homepage/contact/inquiry", {
290
+ method: "POST",
291
+ body: JSON.stringify(params)
292
+ });
207
293
  }
208
294
  };
209
295
 
210
296
  // src/client.ts
211
- var DEFAULT_BASE_URL = "https://api.deliveryapi.co.kr";
212
- var DeliverySaasClient = class {
213
- constructor(config) {
214
- const http = new HttpClient(
215
- config.apiKey,
216
- config.secretKey,
217
- config.baseUrl ?? DEFAULT_BASE_URL
218
- );
219
- this.tracking = new TrackingResource(http);
220
- this.subscriptions = new SubscriptionsResource(http);
221
- this.webhooks = new WebhooksResource(http);
222
- this.couriers = new CouriersResource(http);
297
+ var noToken = async () => null;
298
+ var HomepageClient = class {
299
+ constructor(options) {
300
+ const { baseUrl, getToken = noToken } = options;
301
+ this.auth = new AuthResource(baseUrl, getToken);
302
+ this.dashboard = new DashboardResource(baseUrl, getToken);
303
+ this.qna = new QnaResource(baseUrl, getToken);
304
+ this.admin = new AdminResource(baseUrl, getToken);
305
+ this.public = new PublicResource(baseUrl);
223
306
  }
224
307
  };
225
308
 
226
- export { AuthenticationError, DeliverySaasClient, DeliverySaasError, NotFoundError, RateLimitError };
309
+ export { ApiError, HomepageClient };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deliveryapi",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Official JavaScript/TypeScript SDK for the DeliveryAPI",
5
5
  "keywords": [
6
6
  "delivery",
@@ -37,14 +37,11 @@
37
37
  "README.md"
38
38
  ],
39
39
  "scripts": {
40
- "build": "tsup && dts-bundle-generator --out-file dist/index.d.ts src/index.ts && cp dist/index.d.ts dist/index.d.cts",
40
+ "build": "tsup && cp dist/index.d.ts dist/index.d.cts",
41
41
  "typecheck": "tsc --noEmit",
42
42
  "clean": "rimraf dist"
43
43
  },
44
44
  "devDependencies": {
45
- "@delivery-saas/shared-constants": "workspace:*",
46
- "@delivery-saas/shared-types": "workspace:*",
47
- "dts-bundle-generator": "^9.5.1",
48
45
  "rimraf": "^6.0.0",
49
46
  "tsup": "^8.0.0",
50
47
  "typescript": "^5.7.0"