> ## Documentation Index
> Fetch the complete documentation index at: https://make.edicus.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK v2에서 옮기기

> edicus-sdk-v2.js를 쓰던 코드를 @edicus/sdk v3으로 옮기는 두 가지 경로

<Note>
  이 페이지는 브라우저 SDK `edicus-sdk-v2.js`에서 `@edicus/sdk` v3으로 옮기는 방법입니다. Server API의 v2 경로(`/v2/...`)와는 관계가 없습니다.
</Note>

`edicus-sdk-v2.js`(`<script src>`로 사이트에 직접 추가하던 기존 SDK, ver 2.0.3)를 쓰고 계시다면 선택지가 둘입니다.

<Columns cols={2}>
  <Card title="무수정 경로" icon="wand-magic-sparkles">
    `<script src>` 한 줄만 바꿉니다. 기존 메서드를 v2와 같은 이름, 같은 콜백 모양으로 계속 씁니다.
  </Card>

  <Card title="새 API로 전환" icon="code">
    `createEdicusClient` 기반의 타입 지정 세션 API로 옮깁니다. 신규 코드에는 이 경로를 권합니다.
  </Card>
</Columns>

두 경로 모두 같은 코어 위에서 동작하므로, 아래 "달라진 동작"의 버그 수정이 legacy 층에도 그대로 적용됩니다.

## 1. 무수정 경로

기존:

```html theme={null}
<script src="edicus-sdk-v2.js"></script>
```

교체:

```html theme={null}
<script src="https://cdn.jsdelivr.net/npm/@edicus/sdk@3.0.0-alpha.2/dist/edicus-sdk.iife.js"></script>
```

지금은 정확한 버전(`@3.0.0-alpha.2`)을 적어 주세요. `@3` 같은 버전 범위는 프리릴리스를 고르지 않아서 `3.0.0` 정식 버전이 나오기 전에는 파일을 찾지 못합니다. 정식 버전이 나온 뒤에는 major 버전(`@3`)만 고정해서 쓰시기를 권합니다. 이 한 줄 교체 뒤에는 `window.edicusSDK.init(config)`부터 `editor.create_project(params, callback)` 같은 기존 호출 코드를 그대로 두셔도 됩니다.

npm으로 번들링하는 프로젝트라면 `@edicus/sdk/legacy`를 직접 임포트해도 같은 표면을 씁니다.

```ts theme={null}
import { edicusSDK } from '@edicus/sdk/legacy'
const editor = edicusSDK.init({})
```

편집기 호스트를 직접 지정하려면 v2와 같은 키인 `base_url`을 씁니다. 새 API의 `baseUrl`과 철자가 다릅니다.

```ts theme={null}
const editor = edicusSDK.init({ base_url: 'https://editor.edicus.io' })
```

`edicusSDK.ver`는 이제 v2의 `2.0.3`이 아니라 패키지 버전(`'3.0.0-alpha.2'`)을 돌려줍니다. 버전 문자열로 분기하던 코드가 있다면 확인하세요.

### 기본 편집기 호스트가 바뀝니다

`base_url`을 주지 않으면 편집기 iframe이 `https://editor.edicus.io`에서 뜹니다. v2의 기본 호스트와는 주소가 다릅니다. 새 API의 `createEdicusClient()`도 기본값이 `https://editor.edicus.io`입니다. 두 주소는 같은 서비스를 가리킵니다.

<Warning>
  사이트에 Content Security Policy(CSP)나 도메인 허용 목록이 있다면 `https://editor.edicus.io`를 추가하세요. `frame-src`(또는 `child-src`)에 이 주소가 없으면 브라우저가 편집기 iframe을 막습니다. `base_url`이나 `baseUrl`을 직접 지정하던 코드는 영향이 없습니다.
</Warning>

## 2. 메서드 대응표

`init()`이 반환하는 객체의 공개 메서드와 새 API의 대응입니다.

| v2 / legacy 메서드 | 새 API | 비고 |
| - | - | - |
| `destroy(params?)` | `client.destroy()` | 모든 세션을 닫습니다. 하나만 닫으려면 `session.close()` |
| `open_portal(params, cb)` | `client.openPortal(o)` | experimental |
| `create_project(params, cb)` | `client.createProject(o)` | |
| `open_project(params, cb)` | `client.openProject(o)` | `params.prjid` → `o.project_id` |
| `recycle_project(params, cb)` | `client.recycleProject(o)` | `prjid` → `project_id` |
| `reform_project(params, cb)` | `client.reformProject(o)` | experimental, `prjid` → `project_id` |
| `fit_project(params, cb)` | `client.fitProject(o)` | experimental, `prjid` → `project_id` |
| `change_project(projectID)` | `session.changeProject(project_id)` | |
| `change_template_v2(option)` | `session.changeTemplate({ ps_code, template_uri, content_uri?, command? })` | `option.psCode` → `ps_code` |
| `change_template(psCode, template_uri)` | `session.changeTemplate({ ps_code: psCode, template_uri })` | |
| `execute_ddp_block(ddp_block, history_label?)` | `session.post('execute-ddp-block', { ddp_block, history_label })` | |
| `open_preview(params, cb)` | `client.openPreview(o)` | `prjid` → `project_id` |
| `show_tnview(params, cb)` | `client.showTnview(o)` | |
| `create_tnview(params, cb)` | `client.createTnview(o)` | |
| `open_tnview(params, cb)` | `client.openTnview(o)` | `prjid` → `project_id` |
| `show_gallery(params, cb)` | `client.showGallery(o)` | experimental |
| `create_lite_project(params, cb)` | `client.createLiteProject(o)` | experimental |
| `open_lite_project(params, cb)` | `client.openLiteProject(o)` | experimental, `prjid` → `project_id` |
| `show_lite_editor(params, cb)` | `client.showLiteEditor(o)` | experimental |
| `show_test(params, cb)` | `client.showTest(o)` | experimental |
| `post_to_editor(action, info)` | `editorSession.post(action, info)` | |
| `post_to_tnview(action, info)` | `tnviewSession.post(action, info)` | |
| `post_to_preview(action, info)` | `previewSession.post(action, info)` | |

## 3. 콜백을 이벤트로

v2의 `function(err, data)`에서 `err`는 항상 `null`이었습니다. 새 API에서는 `session.on(action, handler)`로 바뀝니다. `data.action`으로 분기하던 코드가 그대로 `on()`의 첫 인자가 됩니다.

<CodeGroup>
  ```js v2 theme={null}
  editor.create_project(params, function (err, data) {
    if (data.action === 'goto-cart') editor.destroy(...)
  })
  ```

  ```ts 새 API theme={null}
  const session = client.createProject(o)
  session.on('goto-cart', () => session.close())
  ```
</CodeGroup>

모든 action을 한 곳에서 받고 싶으시면 `session.onAny(envelope => ...)`를 쓰시면 됩니다.

### legacy 콜백은 원본 action 이름을 받습니다

legacy 층의 콜백에는 편집기가 보낸 메시지가 이름을 고치지 않고 그대로 옵니다. 썸네일 저장 완료 보고는 예전 편집기가 오타 이름(`donwload-tn-report`)으로 보냈지만, 2026-10-06에 확인한 운영 편집기는 바른 이름 `download-tn-report`로 보냅니다. v2 코드가 옛 이름으로 분기하고 있다면 바른 이름으로 바꾸세요.

```js theme={null}
editor.create_project(params, function (err, data) {
  if (data.action === 'download-tn-report') {
    onThumbnailSaved(data.info)
  }
})
```

### legacy의 보내기 메서드는 가장 최근 iframe으로 갑니다

`post_to_editor`, `post_to_tnview`, `post_to_preview`, `change_project`, `change_template`, `change_template_v2`, `execute_ddp_block`은 메서드 이름과 상관없이 **가장 최근에 띄운 iframe**으로 보냅니다. v2가 iframe을 하나만 기억했기 때문이고, legacy 층도 같게 동작합니다.

편집기를 띄운 뒤 TnView를 띄웠다면 `post_to_editor`도 TnView로 갑니다. 여러 iframe을 함께 쓴다면 세션별로 보내는 새 API로 옮기세요.

## 4. 달라진 동작

새 코어는 v2의 관찰 가능한 버그 몇 가지를 고쳤습니다. legacy 층도 이 코어 위에서 동작하므로 무수정 경로를 택하셔도 아래는 전부 적용됩니다.

<Steps>
  <Step title="postMessage의 targetOrigin">
    v2는 항상 `'*'`로 보냈습니다. 새 코어는 띄울 때 쓰인 origin(`baseUrl`의 origin)으로 고정해서 보냅니다.
  </Step>

  <Step title="template_list 지연 파라미터 응답">
    v2는 `waiting-for-extra-param`의 `template_list` 응답을 `zoom` 키로 잘못 보내는 복붙 버그가 있었습니다. 새 코어는 `template_list` 키로 정확히 응답합니다.
  </Step>

  <Step title="title 미지정">
    v2는 `title`이 없어도 URL에 `title=undefined`라는 문자열을 그대로 넣었습니다. 새 코어는 그 파라미터 자체를 생략합니다.
  </Step>

  <Step title="action 없는 메시지">
    v2가 다루던 임의의 `postMessage` 중 `action` 필드가 없거나 문자열이 아닌 것은 새 코어가 조용히 무시합니다. `type`과 `action`이 둘 다 문자열인 경우만 유효한 메시지로 봅니다.
  </Step>

  <Step title="필수 옵션 누락">
    v2는 필수 파라미터가 빠지면 검증 없이 깨진 URL을 만들었습니다. 새 코어는 호출하는 시점에 동기로 `Error`를 던집니다.

    ```
    [edicus-sdk] createProject: 'ps_code' is required
    ```
  </Step>

  <Step title="띄우기 전 post_to_* 호출">
    v2는 아직 아무것도 띄우지 않은 상태에서 `post_to_editor` 같은 함수를 부르면 raw `TypeError`가 났습니다. legacy 층은 이제 `[edicus-sdk] legacy: no session has been launched yet`이라는 명확한 에러를 던집니다.
  </Step>
</Steps>

## 5. 새로 생긴 것

### `getToken` 자동 응답

v2에는 없던 opt-in 기능입니다. `createEdicusClient({ getToken })`을 설정해야만 `request-user-token`에 SDK가 자동으로 `send-user-token`을 보냅니다. 설정하지 않으면 v2처럼 이벤트가 그대로 전달됩니다. [토큰 자동 갱신](/docs/concepts/authentication#토큰-자동-갱신)을 보세요.

### `waitForExit()`

v2에는 없던 기능입니다. 새 API 전용이고 legacy 층에는 없습니다.

v2의 단일 콜백에서는 `save-doc-report` 핸들러의 비동기 후처리가 끝나기 전에 `close`가 도착하는 문제를 호스트가 플래그나 `setTimeout` 같은 보일러플레이트로 직접 막아야 했습니다.

<CodeGroup>
  ```js v2 theme={null}
  async function callback(err, data) {
    if (data.action === 'save-doc-report' && data.info.status === 'end') {
      saving = true
      await persist(data.info.docInfo); saving = false; notifyDone()
    } else if (data.action === 'close') {
      if (saving) waitUntilDone(() => leave()); else leave()
    }
  }
  ```

  ```ts 새 API theme={null}
  session.on('save-doc-report', async (r) => { if (r.status === 'end') await persist(r.docInfo) })
  await session.waitForExit()
  leave()
  ```
</CodeGroup>

자세한 내용은 [닫기와 저장 후처리](/docs/sdk/exit)에 있습니다.

### 세션 분리

v2는 인스턴스당 콜백이 하나여서 띄울 때마다 덮어써졌습니다. 새 API는 띄우기 한 번이 세션 하나이므로, 편집기와 미리보기를 동시에 띄워도 메시지가 섞이지 않습니다.

## 유지되는 것

legacy 층은 위 목록에 없는 v2 동작을 그대로 유지합니다. 단일 콜백이 띄울 때마다 덮어써지는 것, `open_project`와 `open_tnview` 등의 `params.prjid` 파라미터 이름, 메서드의 이름과 시그니처가 그렇습니다. 무수정 경로로 옮긴 코드가 계속 동작해야 하기 때문입니다.

## 참고

* 새 API의 전체 세션 표면은 [세션 API](/docs/sdk/session)에 있습니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.