OPWS Developers

에러 처리

모든 SDK 에러는 OpenEchoError를 상속하고 code·httpStatus·message를 보존합니다. 이 가이드는 실무 처리 패턴을 다룹니다 — 전체 에러 클래스 표는 에러 레퍼런스를 참조하세요.

instanceof 분기

구체 클래스로 먼저 분기하고, 마지막에 OpenEchoError로 공통 처리합니다.

ts
try {
  await oe.broadcast.tts.send({ /* ... */ });
} catch (err) {
  if (err instanceof CapabilityDenied) {
    // TTS 권한 없음
  } else if (err instanceof UsageCapExceeded) {
    showMessage("일일 방송 한도를 초과했습니다.");
  } else if (err instanceof OpenEchoError) {
    console.error(err.code, err.httpStatus, err.message);
  }
}

SSE(broadcast.subscribe) 에러는 throw되지 않고 onError 콜백으로 전달됩니다. try/catch가 아니라 콜백에서 처리하세요.

멱등성 재시도

네트워크 오류로 재시도할 때는 같은 idempotencyKey를 재사용해 중복 방송을 막습니다. 다른 페이로드에 같은 키를 쓰면 IdempotencyKeyReused(409)가 발생합니다.

ts
const key = crypto.randomUUID();
async function sendWithRetry(input) {
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      return await oe.broadcast.tts.send({ ...input, idempotencyKey: key });
    } catch (err) {
      if (err instanceof RateLimited && attempt < 2) {
        await sleep(2 ** attempt * 500);   // 지수 백오프
        continue;
      }
      throw err;
    }
  }
}

게이트웨이 마스킹 부분 실패

dev 환경 CloudFront가 /api/* 4xx를 2xx+HTML로 치환하면 SDK는 GatewayMasked/InvalidApiResponse를 throw합니다. 여러 자원을 병렬 로드할 때 Promise.allSettled로 한 자원 실패가 전체를 무너뜨리지 않게 합니다.

ts
const [devRes, grpRes] = await Promise.allSettled([
  oe.targets.list(),
  oe.groups.list(),
]);
const devices = devRes.status === "fulfilled" ? devRes.value : [];
const groups = grpRes.status === "fulfilled" ? grpRes.value : [];
if (devRes.status === "rejected" || grpRes.status === "rejected") {
  showPartialFailureNotice();
}

도메인 잠금(OriginForbidden) 진단 절차는 에러 레퍼런스를 참조하세요.