apick-api 3.4.0 → 3.4.1
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/CHANGELOG.md +10 -3
- package/LICENSE +21 -21
- package/README.md +76 -22
- package/SECURITY.md +11 -11
- package/docs/guide.en.md +71 -14
- package/docs/guide.ko.md +71 -14
- package/package.json +1 -1
- package/src/index.js +13 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 3.4.
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 3.4.1 — 2026-09-28
|
|
4
|
+
|
|
5
|
+
- README와 한국어·영어 가이드의 간편인증 5종 예제에 모든 진행 상태와 `resultAvailable` 종료 기준을 적용했습니다. 전체·부분 성공, 인증 거부·만료·실패와 `RESULT_EXPIRED`를 구분합니다.
|
|
6
|
+
- Align all five simple-auth polling examples in the README and Korean/English guides with every progress state and the `resultAvailable` completion criterion. Distinguish full/partial success, rejected/expired authentication, failure, and `RESULT_EXPIRED`.
|
|
7
|
+
- 순차 폴링 간격을 5→10→20→30초로 늘린 뒤 30초를 유지하며, 인증·전체 대기시간 제한과 자동 재접수 방지를 안내합니다. 문서 코드를 직접 실행하는 회귀 테스트를 추가했습니다.
|
|
8
|
+
- Document sequential polling at 5→10→20→30 seconds, capped at 30 seconds, with authentication/overall waiting limits and no automatic resubmission. Add regression tests that execute the documentation examples.
|
|
9
|
+
|
|
10
|
+
## 3.4.0 — 2026-09-27
|
|
4
11
|
|
|
5
12
|
- 간편인증 기반 조회 상품 5종(재직·보험료 확인, 금융소득 조회, 국민연금 가입내역, 운전면허 조회, 국가 건강검진 결과)을 추가했습니다. 각 상품은 `request*()`로 본인 간편인증을 접수하고 `get*()`로 상태·결과를 폴링합니다.
|
|
6
13
|
- Add five simple-auth-based data lookup products (employment/insurance premium check, financial income, National Pension join history, driver's license, national health checkup). Each product accepts a `request*()` call for identity verification and polls status/result with `get*()`.
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 APICK
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 APICK
|
|
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
CHANGED
|
@@ -241,28 +241,82 @@ The four document-specific methods return JSON. `maskResidentNumber` returns PNG
|
|
|
241
241
|
|
|
242
242
|
Products that require the user's own simple-auth verification (employment, income, pension, driver's license, health checkup) split the call into a `request*()` acceptance and a `get*()` poll. Use the `transactionId` from the accepted response to poll for the result.
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
244
|
+
아래 함수는 5종 모두에 공통으로 사용합니다. 같은 `transactionId`로 순차 조회하며 5→10→20→30초 간격으로 늘린 뒤 30초를 유지합니다. `resultAvailable === true`이면 즉시 결과를 반환합니다. `SUCCESS`는 전체 성공, `PARTIAL_SUCCESS`는 부분 성공이므로 `sources`에서 누락·실패 항목을 확인하세요. `AUTH_REJECTED`·`AUTH_EXPIRED`·`FAILED`는 실패 종료이며, `errorCode: 'RESULT_EXPIRED'`는 결과 보관 기간 만료입니다. 실패·만료 시 자동으로 재접수하지 않습니다.
|
|
245
|
+
|
|
246
|
+
Use this helper for all five products. Poll sequentially with the same `transactionId`, waiting 5→10→20→30 seconds and then keeping the 30-second interval. Return the result immediately when `resultAvailable === true`. `SUCCESS` means full success; `PARTIAL_SUCCESS` means partial success, so inspect `sources` for missing or failed items. `AUTH_REJECTED`, `AUTH_EXPIRED`, and `FAILED` are terminal failures; `errorCode: 'RESULT_EXPIRED'` means the retained result has expired. Never resubmit automatically after failure or expiry.
|
|
247
|
+
|
|
248
|
+
<!-- simple-auth-polling:start -->
|
|
249
|
+
```js
|
|
250
|
+
async function pollDataResult(getResult, accepted, { timeoutMs = 600_000 } = {}) {
|
|
251
|
+
const pending = new Set([
|
|
252
|
+
'AUTH_REQUESTED', 'AUTH_WAITING', 'AUTH_COMPLETED', 'COLLECTING', 'COLLECTED'
|
|
253
|
+
]);
|
|
254
|
+
const failed = new Set(['AUTH_REJECTED', 'AUTH_EXPIRED', 'FAILED']);
|
|
255
|
+
const completed = new Set(['SUCCESS', 'PARTIAL_SUCCESS']);
|
|
256
|
+
const delays = [5_000, 10_000, 20_000, 30_000];
|
|
257
|
+
const deadline = Date.now() + timeoutMs;
|
|
258
|
+
const transactionId = accepted.data.transactionId;
|
|
259
|
+
const stop = code => { throw Object.assign(new Error(code), { code }); };
|
|
260
|
+
let response = accepted;
|
|
261
|
+
let attempt = 0;
|
|
262
|
+
|
|
263
|
+
for (;;) {
|
|
264
|
+
const data = response.data;
|
|
265
|
+
if (data.errorCode === 'RESULT_EXPIRED') stop('RESULT_EXPIRED');
|
|
266
|
+
if (failed.has(data.status)) stop(data.errorCode || data.status);
|
|
267
|
+
if (data.resultAvailable === true) {
|
|
268
|
+
if (data.result == null) stop('INVALID_RESULT');
|
|
269
|
+
return response;
|
|
270
|
+
}
|
|
271
|
+
if (completed.has(data.status)) stop('RESULT_NOT_AVAILABLE');
|
|
272
|
+
if (!pending.has(data.status)) stop('UNKNOWN_STATUS');
|
|
273
|
+
|
|
274
|
+
const awaitingApproval = ['AUTH_REQUESTED', 'AUTH_WAITING'].includes(data.status);
|
|
275
|
+
const authDeadline = Date.parse(data.expiresAt || accepted.data.expiresAt);
|
|
276
|
+
const limit = awaitingApproval && Number.isFinite(authDeadline)
|
|
277
|
+
? Math.min(deadline, authDeadline) : deadline;
|
|
278
|
+
const timeoutCode = awaitingApproval && limit === authDeadline
|
|
279
|
+
? 'AUTH_WAIT_TIMEOUT' : 'CLIENT_POLL_TIMEOUT';
|
|
280
|
+
const remaining = limit - Date.now();
|
|
281
|
+
if (remaining <= 0) stop(timeoutCode);
|
|
282
|
+
await new Promise(resolve => setTimeout(resolve,
|
|
283
|
+
Math.min(delays[Math.min(attempt++, delays.length - 1)], remaining)));
|
|
284
|
+
if (Date.now() >= limit) stop(timeoutCode);
|
|
285
|
+
response = await getResult(transactionId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
<!-- simple-auth-polling:end -->
|
|
290
|
+
|
|
291
|
+
`AUTH_REQUESTED`·`AUTH_WAITING`은 사용자 승인을 기다리고, `AUTH_COMPLETED`·`COLLECTING`·`COLLECTED`는 결과가 준비될 때까지 계속 조회합니다. 과금 여부(`charged`, `success`)는 완료 기준이 아닙니다. 인증 대기에만 `expiresAt`을 적용하고 승인 후에는 전체 대기 한도를 적용합니다. 예제의 10분 한도는 클라이언트 정책이며, 진행 중인 호출의 제한 시간은 SDK의 `timeoutMs`로 별도 설정하세요. `AUTH_WAIT_TIMEOUT`·`CLIENT_POLL_TIMEOUT`·`RESULT_NOT_AVAILABLE`·`INVALID_RESULT`·`UNKNOWN_STATUS`는 예제에서 만드는 로컬 오류로, 응답 모순이나 알 수 없는 상태에서 무한 반복하지 않습니다. 통신 오류도 재시도 없이 호출자에게 전달합니다.
|
|
292
|
+
|
|
293
|
+
`AUTH_REQUESTED` and `AUTH_WAITING` wait for the user's approval; `AUTH_COMPLETED`, `COLLECTING`, and `COLLECTED` keep polling until a result is available. Billing fields (`charged`, `success`) do not indicate completion. Apply `expiresAt` only while awaiting approval, then use the overall waiting limit. The example's 10-minute limit is a client policy; configure the SDK's `timeoutMs` separately to bound each in-flight call. `AUTH_WAIT_TIMEOUT`, `CLIENT_POLL_TIMEOUT`, `RESULT_NOT_AVAILABLE`, `INVALID_RESULT`, and `UNKNOWN_STATUS` are local example errors that prevent endless polling on inconsistent responses or unknown states. Transport errors propagate without retries.
|
|
294
|
+
|
|
295
|
+
<!-- simple-auth-usage:start -->
|
|
296
|
+
```js
|
|
297
|
+
const accepted = await apick.requestEmployment({
|
|
298
|
+
name: '홍길동',
|
|
299
|
+
birthDate: '19900101',
|
|
300
|
+
phone: '01011112222',
|
|
301
|
+
authProvider: 'kakao',
|
|
302
|
+
insuranceYears: 3
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
const result = await pollDataResult(id => apick.getEmployment(id), accepted);
|
|
307
|
+
if (result.data.status === 'PARTIAL_SUCCESS') console.warn(result.data.sources);
|
|
308
|
+
console.log(result.data.result);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
if ((error.serviceCode || error.code) === 'RESULT_EXPIRED') {
|
|
311
|
+
console.error('결과 보관 기간 만료: 사용자 확인 후 새 인증을 요청하세요.');
|
|
312
|
+
} else {
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
<!-- simple-auth-usage:end -->
|
|
318
|
+
|
|
319
|
+
근거: [APICK 개발가이드](https://apick.app/dev_guide/data_health_checkup) · [MCP 3.5.0 상태 계약](https://github.com/lead788/apick-mcp/blob/a803abcb81d07377c85f49bb0b670baf0c17ed04/TOOLS.md)
|
|
266
320
|
|
|
267
321
|
지원 간편인증 방식(`authProvider`) 13종은 `AUTH_PROVIDERS`로 제공됩니다: `kakao`, `naver`, `toss`, `pass`, `samsung`, `kb`, `shinhan`, `hana`, `woori`, `ibk`, `nh`, `kakaobank`, `banksalad`.
|
|
268
322
|
The 13 supported `authProvider` values are exported as `AUTH_PROVIDERS`: `kakao`, `naver`, `toss`, `pass`, `samsung`, `kb`, `shinhan`, `hana`, `woori`, `ibk`, `nh`, `kakaobank`, `banksalad`.
|
package/SECURITY.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# Security
|
|
2
|
-
|
|
3
|
-
## API keys
|
|
4
|
-
|
|
5
|
-
Keep APICK API keys in server-side environment variables. Do not commit keys, include them in client-side browser bundles, place them in URLs, or print them in logs.
|
|
6
|
-
|
|
7
|
-
If a key may have been exposed, regenerate it from your APICK account immediately.
|
|
8
|
-
|
|
9
|
-
## Reporting a vulnerability
|
|
10
|
-
|
|
11
|
-
Please report security issues privately through the contact channel listed at <https://apick.app>. Do not open a public issue containing credentials, personal data, or exploit details.
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
## API keys
|
|
4
|
+
|
|
5
|
+
Keep APICK API keys in server-side environment variables. Do not commit keys, include them in client-side browser bundles, place them in URLs, or print them in logs.
|
|
6
|
+
|
|
7
|
+
If a key may have been exposed, regenerate it from your APICK account immediately.
|
|
8
|
+
|
|
9
|
+
## Reporting a vulnerability
|
|
10
|
+
|
|
11
|
+
Please report security issues privately through the contact channel listed at <https://apick.app>. Do not open a public issue containing credentials, personal data, or exploit details.
|
package/docs/guide.en.md
CHANGED
|
@@ -189,20 +189,77 @@ The document-specific methods are `maskResidenceCard`, `maskPassport`, `maskIdCa
|
|
|
189
189
|
|
|
190
190
|
Employment, income, pension, driver's license, and health checkup lookups require the user's own simple-auth verification, so the call is split into acceptance (`request*`) and result polling (`get*`).
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
192
|
+
Use this helper for all five products. Poll sequentially with the same `transactionId`, waiting 5→10→20→30 seconds and then keeping the 30-second interval. Return the result immediately when `resultAvailable === true`. `SUCCESS` means full success; `PARTIAL_SUCCESS` means partial success, so inspect `sources` for missing or failed items. `AUTH_REJECTED`, `AUTH_EXPIRED`, and `FAILED` are terminal failures; `errorCode: 'RESULT_EXPIRED'` means the retained result has expired. Never resubmit automatically after failure or expiry.
|
|
193
|
+
|
|
194
|
+
<!-- simple-auth-polling:start -->
|
|
195
|
+
```js
|
|
196
|
+
async function pollDataResult(getResult, accepted, { timeoutMs = 600_000 } = {}) {
|
|
197
|
+
const pending = new Set([
|
|
198
|
+
'AUTH_REQUESTED', 'AUTH_WAITING', 'AUTH_COMPLETED', 'COLLECTING', 'COLLECTED'
|
|
199
|
+
]);
|
|
200
|
+
const failed = new Set(['AUTH_REJECTED', 'AUTH_EXPIRED', 'FAILED']);
|
|
201
|
+
const completed = new Set(['SUCCESS', 'PARTIAL_SUCCESS']);
|
|
202
|
+
const delays = [5_000, 10_000, 20_000, 30_000];
|
|
203
|
+
const deadline = Date.now() + timeoutMs;
|
|
204
|
+
const transactionId = accepted.data.transactionId;
|
|
205
|
+
const stop = code => { throw Object.assign(new Error(code), { code }); };
|
|
206
|
+
let response = accepted;
|
|
207
|
+
let attempt = 0;
|
|
208
|
+
|
|
209
|
+
for (;;) {
|
|
210
|
+
const data = response.data;
|
|
211
|
+
if (data.errorCode === 'RESULT_EXPIRED') stop('RESULT_EXPIRED');
|
|
212
|
+
if (failed.has(data.status)) stop(data.errorCode || data.status);
|
|
213
|
+
if (data.resultAvailable === true) {
|
|
214
|
+
if (data.result == null) stop('INVALID_RESULT');
|
|
215
|
+
return response;
|
|
216
|
+
}
|
|
217
|
+
if (completed.has(data.status)) stop('RESULT_NOT_AVAILABLE');
|
|
218
|
+
if (!pending.has(data.status)) stop('UNKNOWN_STATUS');
|
|
219
|
+
|
|
220
|
+
const awaitingApproval = ['AUTH_REQUESTED', 'AUTH_WAITING'].includes(data.status);
|
|
221
|
+
const authDeadline = Date.parse(data.expiresAt || accepted.data.expiresAt);
|
|
222
|
+
const limit = awaitingApproval && Number.isFinite(authDeadline)
|
|
223
|
+
? Math.min(deadline, authDeadline) : deadline;
|
|
224
|
+
const timeoutCode = awaitingApproval && limit === authDeadline
|
|
225
|
+
? 'AUTH_WAIT_TIMEOUT' : 'CLIENT_POLL_TIMEOUT';
|
|
226
|
+
const remaining = limit - Date.now();
|
|
227
|
+
if (remaining <= 0) stop(timeoutCode);
|
|
228
|
+
await new Promise(resolve => setTimeout(resolve,
|
|
229
|
+
Math.min(delays[Math.min(attempt++, delays.length - 1)], remaining)));
|
|
230
|
+
if (Date.now() >= limit) stop(timeoutCode);
|
|
231
|
+
response = await getResult(transactionId);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
<!-- simple-auth-polling:end -->
|
|
236
|
+
|
|
237
|
+
`AUTH_REQUESTED` and `AUTH_WAITING` wait for the user's approval; `AUTH_COMPLETED`, `COLLECTING`, and `COLLECTED` keep polling until a result is available. Billing fields (`charged`, `success`) do not indicate completion. Apply `expiresAt` only while awaiting approval, then use the overall waiting limit. The example's 10-minute limit is a client policy; configure the SDK's `timeoutMs` separately to bound each in-flight call. `AUTH_WAIT_TIMEOUT`, `CLIENT_POLL_TIMEOUT`, `RESULT_NOT_AVAILABLE`, `INVALID_RESULT`, and `UNKNOWN_STATUS` are local example errors that prevent endless polling on inconsistent responses or unknown states. Transport errors propagate without retries.
|
|
238
|
+
|
|
239
|
+
<!-- simple-auth-usage:start -->
|
|
240
|
+
```js
|
|
241
|
+
const accepted = await client.requestDrivingLicense({
|
|
242
|
+
name: 'Hong Gildong',
|
|
243
|
+
birthDate: '19900101',
|
|
244
|
+
phone: '01011112222',
|
|
245
|
+
authProvider: 'kakao'
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
const result = await pollDataResult(id => client.getDrivingLicense(id), accepted);
|
|
250
|
+
if (result.data.status === 'PARTIAL_SUCCESS') console.warn(result.data.sources);
|
|
251
|
+
console.log(result.data.result);
|
|
252
|
+
} catch (error) {
|
|
253
|
+
if ((error.serviceCode || error.code) === 'RESULT_EXPIRED') {
|
|
254
|
+
console.error('Result expired. Ask the user before starting a new authentication request.');
|
|
255
|
+
} else {
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
<!-- simple-auth-usage:end -->
|
|
261
|
+
|
|
262
|
+
Sources: [APICK development guide](https://apick.app/dev_guide/data_health_checkup) · [MCP 3.5.0 status contract](https://github.com/lead788/apick-mcp/blob/a803abcb81d07377c85f49bb0b670baf0c17ed04/TOOLS.md)
|
|
206
263
|
|
|
207
264
|
`authProvider` is one of the 13 values in `AUTH_PROVIDERS` (kakao, naver, toss, pass, samsung, kb, shinhan, hana, woori, ibk, nh, kakaobank, banksalad). Acceptance is billed at a flat rate; the result is billed only on its first return and free to re-poll afterward. `requestEmployment` takes an optional `insuranceYears` (1-3), `requestPersonalIncome` takes `incomeYears` (1-5), and `requestNpsJoinHistory` takes optional `from`/`to` (`YYYY-MM`). The remaining products are `requestDrivingLicense` and `requestHealthCheckup`.
|
|
208
265
|
|
package/docs/guide.ko.md
CHANGED
|
@@ -191,20 +191,77 @@ console.log(result.data.result.fields);
|
|
|
191
191
|
|
|
192
192
|
재직·소득·연금·면허·건강검진 조회는 본인 간편인증이 필요해 접수(`request*`)와 결과 조회(`get*`)가 나뉩니다.
|
|
193
193
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
194
|
+
아래 함수는 5종 모두에 공통으로 사용합니다. 같은 `transactionId`로 순차 조회하며 5→10→20→30초 간격으로 늘린 뒤 30초를 유지합니다. `resultAvailable === true`이면 즉시 결과를 반환합니다. `SUCCESS`는 전체 성공, `PARTIAL_SUCCESS`는 부분 성공이므로 `sources`에서 누락·실패 항목을 확인하세요. `AUTH_REJECTED`·`AUTH_EXPIRED`·`FAILED`는 실패 종료이며, `errorCode: 'RESULT_EXPIRED'`는 결과 보관 기간 만료입니다. 실패·만료 시 자동으로 재접수하지 않습니다.
|
|
195
|
+
|
|
196
|
+
<!-- simple-auth-polling:start -->
|
|
197
|
+
```js
|
|
198
|
+
async function pollDataResult(getResult, accepted, { timeoutMs = 600_000 } = {}) {
|
|
199
|
+
const pending = new Set([
|
|
200
|
+
'AUTH_REQUESTED', 'AUTH_WAITING', 'AUTH_COMPLETED', 'COLLECTING', 'COLLECTED'
|
|
201
|
+
]);
|
|
202
|
+
const failed = new Set(['AUTH_REJECTED', 'AUTH_EXPIRED', 'FAILED']);
|
|
203
|
+
const completed = new Set(['SUCCESS', 'PARTIAL_SUCCESS']);
|
|
204
|
+
const delays = [5_000, 10_000, 20_000, 30_000];
|
|
205
|
+
const deadline = Date.now() + timeoutMs;
|
|
206
|
+
const transactionId = accepted.data.transactionId;
|
|
207
|
+
const stop = code => { throw Object.assign(new Error(code), { code }); };
|
|
208
|
+
let response = accepted;
|
|
209
|
+
let attempt = 0;
|
|
210
|
+
|
|
211
|
+
for (;;) {
|
|
212
|
+
const data = response.data;
|
|
213
|
+
if (data.errorCode === 'RESULT_EXPIRED') stop('RESULT_EXPIRED');
|
|
214
|
+
if (failed.has(data.status)) stop(data.errorCode || data.status);
|
|
215
|
+
if (data.resultAvailable === true) {
|
|
216
|
+
if (data.result == null) stop('INVALID_RESULT');
|
|
217
|
+
return response;
|
|
218
|
+
}
|
|
219
|
+
if (completed.has(data.status)) stop('RESULT_NOT_AVAILABLE');
|
|
220
|
+
if (!pending.has(data.status)) stop('UNKNOWN_STATUS');
|
|
221
|
+
|
|
222
|
+
const awaitingApproval = ['AUTH_REQUESTED', 'AUTH_WAITING'].includes(data.status);
|
|
223
|
+
const authDeadline = Date.parse(data.expiresAt || accepted.data.expiresAt);
|
|
224
|
+
const limit = awaitingApproval && Number.isFinite(authDeadline)
|
|
225
|
+
? Math.min(deadline, authDeadline) : deadline;
|
|
226
|
+
const timeoutCode = awaitingApproval && limit === authDeadline
|
|
227
|
+
? 'AUTH_WAIT_TIMEOUT' : 'CLIENT_POLL_TIMEOUT';
|
|
228
|
+
const remaining = limit - Date.now();
|
|
229
|
+
if (remaining <= 0) stop(timeoutCode);
|
|
230
|
+
await new Promise(resolve => setTimeout(resolve,
|
|
231
|
+
Math.min(delays[Math.min(attempt++, delays.length - 1)], remaining)));
|
|
232
|
+
if (Date.now() >= limit) stop(timeoutCode);
|
|
233
|
+
response = await getResult(transactionId);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
<!-- simple-auth-polling:end -->
|
|
238
|
+
|
|
239
|
+
`AUTH_REQUESTED`·`AUTH_WAITING`은 사용자 승인을 기다리고, `AUTH_COMPLETED`·`COLLECTING`·`COLLECTED`는 결과가 준비될 때까지 계속 조회합니다. 과금 여부(`charged`, `success`)는 완료 기준이 아닙니다. 인증 대기에만 `expiresAt`을 적용하고 승인 후에는 전체 대기 한도를 적용합니다. 예제의 10분 한도는 클라이언트 정책이며, 진행 중인 호출의 제한 시간은 SDK의 `timeoutMs`로 별도 설정하세요. `AUTH_WAIT_TIMEOUT`·`CLIENT_POLL_TIMEOUT`·`RESULT_NOT_AVAILABLE`·`INVALID_RESULT`·`UNKNOWN_STATUS`는 예제에서 만드는 로컬 오류로, 응답 모순이나 알 수 없는 상태에서 무한 반복하지 않습니다. 통신 오류도 재시도 없이 호출자에게 전달합니다.
|
|
240
|
+
|
|
241
|
+
<!-- simple-auth-usage:start -->
|
|
242
|
+
```js
|
|
243
|
+
const accepted = await client.requestDrivingLicense({
|
|
244
|
+
name: '홍길동',
|
|
245
|
+
birthDate: '19900101',
|
|
246
|
+
phone: '01011112222',
|
|
247
|
+
authProvider: 'kakao'
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
const result = await pollDataResult(id => client.getDrivingLicense(id), accepted);
|
|
252
|
+
if (result.data.status === 'PARTIAL_SUCCESS') console.warn(result.data.sources);
|
|
253
|
+
console.log(result.data.result);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if ((error.serviceCode || error.code) === 'RESULT_EXPIRED') {
|
|
256
|
+
console.error('결과 보관 기간 만료: 사용자 확인 후 새 인증을 요청하세요.');
|
|
257
|
+
} else {
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
<!-- simple-auth-usage:end -->
|
|
263
|
+
|
|
264
|
+
근거: [APICK 개발가이드](https://apick.app/dev_guide/data_health_checkup) · [MCP 3.5.0 상태 계약](https://github.com/lead788/apick-mcp/blob/a803abcb81d07377c85f49bb0b670baf0c17ed04/TOOLS.md)
|
|
208
265
|
|
|
209
266
|
`authProvider`는 `AUTH_PROVIDERS`(13종: kakao, naver, toss, pass, samsung, kb, shinhan, hana, woori, ibk, nh, kakaobank, banksalad) 중 하나입니다. 접수는 정액 과금, 결과는 최초 반환에서만 과금되며 재조회는 무료입니다. `requestEmployment`는 `insuranceYears`(1~3), `requestPersonalIncome`은 `incomeYears`(1~5), `requestNpsJoinHistory`는 `from`/`to`(`YYYY-MM`) 선택 입력을 받습니다. 나머지 상품은 `requestDrivingLicense`, `requestHealthCheckup`입니다.
|
|
210
267
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import sdk from './index.cjs';
|
|
2
|
-
|
|
3
|
-
export const {
|
|
4
|
-
ApickClient,
|
|
5
|
-
ApickApiError,
|
|
6
|
-
ApickBinaryResult,
|
|
7
|
-
SERVICES,
|
|
8
|
-
TTS_VOICE_IDS,
|
|
9
|
-
AUTH_PROVIDERS,
|
|
10
|
-
DEFAULT_BASE_URL
|
|
11
|
-
} = sdk;
|
|
12
|
-
|
|
13
|
-
export default ApickClient;
|
|
1
|
+
import sdk from './index.cjs';
|
|
2
|
+
|
|
3
|
+
export const {
|
|
4
|
+
ApickClient,
|
|
5
|
+
ApickApiError,
|
|
6
|
+
ApickBinaryResult,
|
|
7
|
+
SERVICES,
|
|
8
|
+
TTS_VOICE_IDS,
|
|
9
|
+
AUTH_PROVIDERS,
|
|
10
|
+
DEFAULT_BASE_URL
|
|
11
|
+
} = sdk;
|
|
12
|
+
|
|
13
|
+
export default ApickClient;
|