deliveryapi 0.1.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/README.md ADDED
@@ -0,0 +1,252 @@
1
+ # deliveryapi
2
+
3
+ Official JavaScript/TypeScript SDK for the [DeliveryAPI](https://deliveryapi.co.kr) — Korea's unified courier tracking API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install deliveryapi
9
+ # or
10
+ yarn add deliveryapi
11
+ # or
12
+ pnpm add deliveryapi
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { DeliverySaasClient } from 'deliveryapi'
19
+
20
+ const client = new DeliverySaasClient({
21
+ apiKey: 'your-api-key',
22
+ secretKey: 'your-secret-key',
23
+ })
24
+ ```
25
+
26
+ API keys can be issued at [deliveryapi.co.kr](https://deliveryapi.co.kr).
27
+
28
+ ---
29
+
30
+ ## Tracking
31
+
32
+ ### Single tracking
33
+
34
+ ```typescript
35
+ const result = await client.tracking.getOne('LOTTE', '1234567890')
36
+
37
+ console.log(result.results[0].status) // 'DELIVERED'
38
+ console.log(result.results[0].progresses) // delivery history
39
+ ```
40
+
41
+ ### Multiple tracking at once
42
+
43
+ ```typescript
44
+ const result = await client.tracking.get([
45
+ { courierCode: 'LOTTE', trackingNumber: '1234567890' },
46
+ { courierCode: 'CJ', trackingNumber: '9876543210' },
47
+ ])
48
+
49
+ for (const item of result.results) {
50
+ console.log(item.trackingNumber, item.status)
51
+ }
52
+ ```
53
+
54
+ ### Without delivery history (faster)
55
+
56
+ ```typescript
57
+ const result = await client.tracking.getOne('CJ', '1234567890', {
58
+ includeProgresses: false,
59
+ })
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Webhook Endpoints
65
+
66
+ Register a URL to receive real-time delivery status change notifications.
67
+
68
+ ### Register endpoint
69
+
70
+ ```typescript
71
+ const endpoint = await client.webhooks.create({
72
+ url: 'https://your-server.com/webhook',
73
+ name: 'Production Webhook',
74
+ })
75
+
76
+ console.log(endpoint.id) // 'ep_xxxxxxxxxxxx'
77
+ ```
78
+
79
+ ### List endpoints
80
+
81
+ ```typescript
82
+ const { endpoints } = await client.webhooks.list()
83
+ ```
84
+
85
+ ### Test endpoint
86
+
87
+ ```typescript
88
+ const result = await client.webhooks.test('ep_xxxxxxxxxxxx')
89
+ console.log(result.success) // true
90
+ ```
91
+
92
+ ### Delete endpoint
93
+
94
+ ```typescript
95
+ await client.webhooks.delete('ep_xxxxxxxxxxxx')
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Tracking Subscriptions
101
+
102
+ Subscribe to a tracking number and receive webhook notifications when status changes.
103
+
104
+ ### Create subscription
105
+
106
+ ```typescript
107
+ const subscription = await client.subscriptions.create({
108
+ courierCode: 'LOTTE',
109
+ trackingNumber: '1234567890',
110
+ endpointId: 'ep_xxxxxxxxxxxx',
111
+ })
112
+
113
+ console.log(subscription.id) // 'sub_xxxxxxxxxxxx'
114
+ ```
115
+
116
+ ### Subscribe to specific statuses only
117
+
118
+ ```typescript
119
+ const subscription = await client.subscriptions.create({
120
+ courierCode: 'CJ',
121
+ trackingNumber: '9876543210',
122
+ endpointId: 'ep_xxxxxxxxxxxx',
123
+ subscribedStatuses: ['IN_TRANSIT', 'DELIVERED'],
124
+ })
125
+ ```
126
+
127
+ ### List subscriptions
128
+
129
+ ```typescript
130
+ const { subscriptions, total } = await client.subscriptions.list({
131
+ status: 'ACTIVE',
132
+ page: 1,
133
+ pageSize: 20,
134
+ })
135
+ ```
136
+
137
+ ### Retrieve subscription
138
+
139
+ ```typescript
140
+ const subscription = await client.subscriptions.retrieve('sub_xxxxxxxxxxxx')
141
+ console.log(subscription.status) // 'ACTIVE'
142
+ ```
143
+
144
+ ### Cancel subscription
145
+
146
+ ```typescript
147
+ await client.subscriptions.cancel('sub_xxxxxxxxxxxx')
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Couriers
153
+
154
+ ### List supported couriers
155
+
156
+ ```typescript
157
+ const { couriers } = await client.couriers.list()
158
+
159
+ for (const courier of couriers) {
160
+ console.log(courier.code, courier.name) // 'LOTTE', '롯데택배'
161
+ }
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Webhook Payload
167
+
168
+ When a tracking status changes, your endpoint receives a POST request with the following payload:
169
+
170
+ ```typescript
171
+ import type { WebhookPayload } from 'deliveryapi'
172
+
173
+ app.post('/webhook', (req, res) => {
174
+ const payload: WebhookPayload = req.body
175
+
176
+ console.log(payload.subscriptionId)
177
+ console.log(payload.courierCode)
178
+ console.log(payload.trackingNumber)
179
+ console.log(payload.status) // 'DELIVERED'
180
+ console.log(payload.changedAt) // ISO 8601 timestamp
181
+
182
+ res.sendStatus(200)
183
+ })
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Error Handling
189
+
190
+ ```typescript
191
+ import {
192
+ DeliverySaasClient,
193
+ AuthenticationError,
194
+ RateLimitError,
195
+ NotFoundError,
196
+ DeliverySaasError,
197
+ } from 'deliveryapi'
198
+
199
+ try {
200
+ const result = await client.tracking.getOne('LOTTE', '1234567890')
201
+ } catch (error) {
202
+ if (error instanceof AuthenticationError) {
203
+ // Invalid API key or secret key
204
+ console.error('Authentication failed')
205
+ } else if (error instanceof RateLimitError) {
206
+ // Request limit exceeded
207
+ console.error('Rate limit exceeded, retry later')
208
+ } else if (error instanceof NotFoundError) {
209
+ // Resource not found
210
+ console.error('Not found')
211
+ } else if (error instanceof DeliverySaasError) {
212
+ // Other API errors
213
+ console.error(error.message, error.statusCode)
214
+ }
215
+ }
216
+ ```
217
+
218
+ ---
219
+
220
+ ## TypeScript
221
+
222
+ Full TypeScript support is included out of the box.
223
+
224
+ ```typescript
225
+ import type {
226
+ TrackingResponse,
227
+ TrackingSubscription,
228
+ WebhookEndpoint,
229
+ WebhookPayload,
230
+ CourierDeliveryStatus,
231
+ } from 'deliveryapi'
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Supported Couriers
237
+
238
+ | Code | Name |
239
+ |------|------|
240
+ | `LOTTE` | 롯데택배 |
241
+ | `CJ` | CJ대한통운 |
242
+ | `HANJIN` | 한진택배 |
243
+ | `POST` | 우체국택배 |
244
+ | `LOGEN` | 로젠택배 |
245
+
246
+ Full list available via `client.couriers.list()`.
247
+
248
+ ---
249
+
250
+ ## License
251
+
252
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,210 @@
1
+ 'use strict';
2
+
3
+ // src/errors.ts
4
+ var DeliverySaasError = class extends Error {
5
+ constructor(message, statusCode, code) {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ this.code = code;
9
+ this.name = "DeliverySaasError";
10
+ }
11
+ };
12
+ var AuthenticationError = class extends DeliverySaasError {
13
+ constructor(message = "Invalid API key or secret key") {
14
+ super(message, 401, "AUTHENTICATION_ERROR");
15
+ this.name = "AuthenticationError";
16
+ }
17
+ };
18
+ var RateLimitError = class extends DeliverySaasError {
19
+ constructor(message = "Rate limit exceeded") {
20
+ super(message, 429, "RATE_LIMIT_ERROR");
21
+ this.name = "RateLimitError";
22
+ }
23
+ };
24
+ var NotFoundError = class extends DeliverySaasError {
25
+ constructor(message = "Resource not found") {
26
+ super(message, 404, "NOT_FOUND");
27
+ this.name = "NotFoundError";
28
+ }
29
+ };
30
+
31
+ // src/http.ts
32
+ var HttpClient = class {
33
+ constructor(apiKey, secretKey, baseUrl) {
34
+ this.baseUrl = baseUrl.replace(/\/$/, "");
35
+ this.authHeader = `Bearer ${apiKey}:${secretKey}`;
36
+ }
37
+ async get(path, params) {
38
+ const url = new URL(`${this.baseUrl}${path}`);
39
+ if (params) {
40
+ Object.entries(params).forEach(([key, value]) => url.searchParams.set(key, value));
41
+ }
42
+ return this.request("GET", url.toString());
43
+ }
44
+ async post(path, body) {
45
+ return this.request("POST", `${this.baseUrl}${path}`, body);
46
+ }
47
+ async patch(path, body) {
48
+ return this.request("PATCH", `${this.baseUrl}${path}`, body);
49
+ }
50
+ async delete(path) {
51
+ return this.request("DELETE", `${this.baseUrl}${path}`);
52
+ }
53
+ async request(method, url, body) {
54
+ const headers = {
55
+ Authorization: this.authHeader,
56
+ "Content-Type": "application/json"
57
+ };
58
+ const response = await fetch(url, {
59
+ method,
60
+ headers,
61
+ body: body !== void 0 ? JSON.stringify(body) : void 0
62
+ });
63
+ const json = await response.json();
64
+ if (!response.ok) {
65
+ if (response.status === 401) throw new AuthenticationError(json.message);
66
+ if (response.status === 404) throw new NotFoundError(json.message);
67
+ if (response.status === 429) throw new RateLimitError(json.message);
68
+ throw new DeliverySaasError(json.message ?? "Request failed", response.status, json.error);
69
+ }
70
+ if (!json.isSuccess) {
71
+ throw new DeliverySaasError(json.message ?? "API returned failure", response.status, json.error);
72
+ }
73
+ return json.data;
74
+ }
75
+ };
76
+
77
+ // src/resources/tracking.ts
78
+ var TrackingResource = class {
79
+ constructor(http) {
80
+ this.http = http;
81
+ }
82
+ /**
83
+ * 택배 조회 (공개 API, 계정 불필요)
84
+ * @param items 조회할 택배 목록 (1건도 배열로)
85
+ * @param includeProgresses 진행 내역 포함 여부 (기본값: true)
86
+ */
87
+ async get(items, includeProgresses = true) {
88
+ return this.http.post("/v1/courier/track", {
89
+ items,
90
+ includeProgresses
91
+ });
92
+ }
93
+ /**
94
+ * 단건 택배 조회 (편의 메서드)
95
+ */
96
+ async getOne(courierCode, trackingNumber, options) {
97
+ return this.get(
98
+ [{ courierCode, trackingNumber, clientId: options?.clientId }],
99
+ options?.includeProgresses ?? true
100
+ );
101
+ }
102
+ };
103
+
104
+ // src/resources/subscriptions.ts
105
+ var SubscriptionsResource = class {
106
+ constructor(http) {
107
+ this.http = http;
108
+ }
109
+ /**
110
+ * 택배 구독 생성
111
+ * 상태 변경 시 등록된 웹훅 엔드포인트로 알림 전송
112
+ */
113
+ async create(data) {
114
+ return this.http.post("/v1/tracking/subscriptions", data);
115
+ }
116
+ /**
117
+ * 택배 구독 목록 조회
118
+ */
119
+ async list(options) {
120
+ const params = {};
121
+ if (options?.status) params["status"] = options.status;
122
+ if (options?.page) params["page"] = String(options.page);
123
+ if (options?.pageSize) params["pageSize"] = String(options.pageSize);
124
+ return this.http.get("/v1/tracking/subscriptions", params);
125
+ }
126
+ /**
127
+ * 택배 구독 상세 조회
128
+ */
129
+ async retrieve(subscriptionId) {
130
+ return this.http.get(`/v1/tracking/subscriptions/${subscriptionId}`);
131
+ }
132
+ /**
133
+ * 택배 구독 취소
134
+ */
135
+ async cancel(subscriptionId) {
136
+ await this.http.delete(`/v1/tracking/subscriptions/${subscriptionId}`);
137
+ }
138
+ };
139
+
140
+ // src/resources/webhooks.ts
141
+ var WebhooksResource = class {
142
+ constructor(http) {
143
+ this.http = http;
144
+ }
145
+ /**
146
+ * 웹훅 엔드포인트 등록
147
+ */
148
+ async create(data) {
149
+ return this.http.post("/v1/webhook-v2/endpoints", data);
150
+ }
151
+ /**
152
+ * 웹훅 엔드포인트 목록 조회
153
+ */
154
+ async list() {
155
+ return this.http.get("/v1/webhook-v2/endpoints");
156
+ }
157
+ /**
158
+ * 웹훅 엔드포인트 상세 조회
159
+ */
160
+ async retrieve(endpointId) {
161
+ return this.http.get(`/v1/webhook-v2/endpoints/${endpointId}`);
162
+ }
163
+ /**
164
+ * 웹훅 엔드포인트 삭제
165
+ */
166
+ async delete(endpointId) {
167
+ await this.http.delete(`/v1/webhook-v2/endpoints/${endpointId}`);
168
+ }
169
+ /**
170
+ * 웹훅 엔드포인트 테스트 전송
171
+ */
172
+ async test(endpointId) {
173
+ return this.http.post(`/v1/webhook-v2/endpoints/${endpointId}/test`);
174
+ }
175
+ };
176
+
177
+ // src/resources/couriers.ts
178
+ var CouriersResource = class {
179
+ constructor(http) {
180
+ this.http = http;
181
+ }
182
+ /**
183
+ * 지원 택배사 목록 조회
184
+ */
185
+ async list() {
186
+ return this.http.get("/v1/courier/list");
187
+ }
188
+ };
189
+
190
+ // src/client.ts
191
+ var DEFAULT_BASE_URL = "https://api.deliveryapi.co.kr";
192
+ var DeliverySaasClient = class {
193
+ constructor(config) {
194
+ const http = new HttpClient(
195
+ config.apiKey,
196
+ config.secretKey,
197
+ config.baseUrl ?? DEFAULT_BASE_URL
198
+ );
199
+ this.tracking = new TrackingResource(http);
200
+ this.subscriptions = new SubscriptionsResource(http);
201
+ this.webhooks = new WebhooksResource(http);
202
+ this.couriers = new CouriersResource(http);
203
+ }
204
+ };
205
+
206
+ exports.AuthenticationError = AuthenticationError;
207
+ exports.DeliverySaasClient = DeliverySaasClient;
208
+ exports.DeliverySaasError = DeliverySaasError;
209
+ exports.NotFoundError = NotFoundError;
210
+ exports.RateLimitError = RateLimitError;