@cmarket/embed
v0.5.0
Published
CMARKET 파트너 임베드(iframe) SDK — launch code postMessage 핸드셰이크를 origin 고정으로 캡슐화
Readme
@cmarket/embed
CMARKET 파트너 임베드(iframe) SDK — 발주기관 ERP 페이지 안에 cmarket 화면(공고 등록 등)을 재로그인 없이 띄웁니다. iframe 생성과 launch code postMessage 핸드셰이크의 보안 로직 (origin 고정, code 를 URL 밖으로)을 SDK 가 대신 강제합니다.
- 런타임 의존성 0 (zero dependencies)
- npm(ESM/CJS) + CDN(UMD 전역
CMarketEmbed) 동시 제공
통합 개요 — 두 레이어
| 레이어 | 누가 | 도구 |
| --------------------- | --------------------------------------------------- | ----------------------------------- |
| ① launch code 발급 | ERP 백엔드 (client_secret 필요 — 브라우저 금지) | Partner API POST /v2/embed/launch |
| ② iframe + 핸드셰이크 | ERP 프론트 | 이 SDK 의 mount() |
launch code 는 일회성·60초 TTL 입니다. 페이지 진입(또는 세션 만료) 시마다 ERP 백엔드에서 새로 발급해 프론트에 내려주세요. code 를 URL 쿼리/해시에 싣지 마세요 — SDK 도 postMessage 로만 전달합니다.
① ERP 백엔드 — launch code 발급
OAuth2 client_credentials 토큰(scope embed:launch)으로 호출합니다:
# 1. 토큰 발급 (scope 에 embed:launch 포함) — token endpoint 는 버전 프리픽스 없음(/oauth/token), JSON body
curl -X POST https://partner-api.c-market.net/oauth/token \
-H "Content-Type: application/json" \
-d "{\"grant_type\":\"client_credentials\",\"client_id\":\"$CMARKET_CLIENT_ID\",\"client_secret\":\"$CMARKET_CLIENT_SECRET\",\"scope\":\"embed:launch\"}"
# 2. launch code 발급 (memberId = cmarket 계정, screen = 임베드 화면 키)
curl -X POST https://partner-api.c-market.net/v2/embed/launch \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"memberId": "M123456", "screen": "bid-register"}'
# → { "launchCode": "...", "expiresIn": 60 }발급된 launchCode 를 ERP 프론트로 내려주세요 (페이지 렌더 응답에 포함하거나 별도 XHR).
② ERP 프론트 — mount
npm
npm install @cmarket/embedimport { mount } from '@cmarket/embed';
const controller = mount('#cmarket-slot', {
launchCode, // ERP 백엔드가 발급한 일회성 code
screen: 'bid-register',
onSuccess: ({ bidId }) => console.log('공고 등록 완료:', bidId),
onCancel: () => console.log('사용자 취소'),
onSessionExpired: async () => {
controller.destroy();
const fresh = await fetchNewLaunchCodeFromMyBackend(); // ①을 다시 호출
mount('#cmarket-slot', { launchCode: fresh, screen: 'bid-register' });
},
onError: (err) => console.error('임베드 실패:', err.code, err.message),
});CDN (script tag)
버전 핀 규율: 반드시 아래처럼 버전을 핀하세요.
latest/무핀 URL 은 사용 금지 — 예고 없는 major 변경이 라이브 페이지를 깨뜨릴 수 있습니다. 1.0.0 GA 이후에는 major-pin(@1)을 권장합니다 (비파괴 개선 자동 수신):https://cdn.jsdelivr.net/npm/@cmarket/embed@1/dist/embed.umd.js0.x 파일럿 기간에는 정확 버전 핀을 사용하세요:
<div id="cmarket-slot" style="width: 100%; height: 720px"></div>
<script src="https://cdn.jsdelivr.net/npm/@cmarket/[email protected]/dist/embed.umd.js"></script>
<script>
var controller = CMarketEmbed.mount('#cmarket-slot', {
launchCode: window.__CMARKET_LAUNCH_CODE__, // 서버 렌더 시 주입
screen: 'bid-register',
onSuccess: function (e) {
console.log('공고 등록 완료:', e.bidId);
},
onCancel: function () {
console.log('사용자 취소');
},
onError: function (err) {
console.error(err.code, err.message);
},
});
</script>API
CMarketEmbed.mount(container, options) => { destroy() }
| 옵션 | 타입 | 기본값 | 설명 |
| ------------------ | ---------------------------------- | ---------------------- | ------------------------------------------- |
| launchCode | string | (필수) | 일회성 launch code (60s TTL) |
| screen | 'bid-register' | (필수) | 임베드 화면 키 (화이트리스트 검증) |
| baseUrl | string | https://c-market.net | cmarket 프론트 origin (staging 은 명시) |
| prefill | EmbedBidPrefillV1 | — | 폼 기본값 (비권위 — 제출 검증은 cmarket 측) |
| onSuccess | (e: {screen, bidId}) => void | — | 등록 완료 |
| onCancel | () => void | — | 사용자 취소 |
| onSessionExpired | () => void | — | 세션(30분) 만료 — 새 code 로 재-mount |
| onError | (err: CMarketEmbedError) => void | — | 비동기 실패 (err.code: 'READY_TIMEOUT') |
| timeoutMs | number | 10000 | iframe ready 대기 한도 |
- 잘못된 통합(미존재 container, 화이트리스트 외
screen, 빈launchCode, 불량baseUrl)은mount()가 동기 throw 합니다 — 개발 중에 즉시 드러납니다. destroy()는 멱등이며 리스너·타임아웃·iframe 을 정리합니다.
보안 설계 (SDK 가 강제하는 것)
- launch code 는 iframe URL 에 절대 실리지 않고 postMessage 로만 전달됩니다 (브라우저 히스토리/Referer/서버 로그 유출 차단).
- 모든 발신 postMessage 의
targetOrigin은 cmarket origin 으로 고정됩니다 ('*'없음). - 수신 메시지는
event.origin(cmarket origin) +event.source(우리 iframe) 2중 검증. - iframe sandbox:
allow-scripts allow-same-origin allow-forms allow-downloads만 부여 (allow-downloads는 assistant 화면의 리포트 엑셀 export 용 — 없으면 브라우저가 조용히 차단한다) — top-navigation/popup/download 불가.
버전 정책
SemVer. CDN 산출물이 파트너 라이브 페이지에서 로드되므로 breaking change 는 반드시 major 로만 나갑니다. 문서/통합 코드에는 항상 핀된 URL 만 사용하세요.
