> ## 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.

# 편집기 이벤트

> 편집기가 보내는 이벤트와 payload

편집기가 호스트 페이지로 보내는 메시지입니다. `session.on(action, handler)`로 구독합니다. payload 타입은 `@edicus/sdk/types`의 `EditorEventMap`에 있습니다.

```ts theme={null}
session.on('save-doc-report', (report) => { /* report의 타입이 SaveDocReport로 좁혀집니다 */ })
```

## 자주 쓰는 이벤트

### `ready-to-listen`

편집기가 메시지를 받을 준비를 마쳤습니다. payload가 없습니다. `request-feature` 같은 커맨드는 이 이벤트 직후에 보내시는 것을 권합니다.

### `project-id-created`

`createProject`나 `recycleProject`가 새 프로젝트를 만들었습니다. **이 id를 저장하지 않으면 그 프로젝트를 다시 열 수 없습니다.**

<ResponseField name="project_id" type="string">
  생성된 프로젝트 id입니다.
</ResponseField>

### `save-doc-report`

저장이 시작되거나 끝났거나 실패했습니다.

<ResponseField name="status" type="'start' | 'end' | 'error'" />

<ResponseField name="projectID" type="string">
  저장한 프로젝트 id입니다. 모든 `status`에 들어 있습니다. `docInfo.projectID`와 같은 값이고, 둘 다 camelCase입니다.
</ResponseField>

<ResponseField name="docInfo" type="object">
  프로젝트와 문서 정보입니다. `status`와 상품 종류에 따라 모양이 다릅니다. 아래 표를 보세요.
</ResponseField>

<ResponseField name="error" type="any">
  `status`가 `'error'`일 때만 존재합니다.
</ResponseField>

`status`가 `'start'`이거나 `'error'`일 때 `docInfo`에는 `projectID`만 들어 있습니다.

<Accordion title="docInfo (status: 'end', 일반 상품)">
  | 필드 | 타입 | 설명 |
  | - | - | - |
  | `projectID` | string | 프로젝트 id (camelCase입니다) |
  | `docRevision` | number | 문서 버전 |
  | `totalPageCount` | number | 전체 페이지 수 |
  | `contentPageCount` | number | 커버를 제외한 내지 페이지 수 |
  | `totalCellCount` | number | 전체 사진틀 수 |
  | `emptyCellCount` | number | 빈 사진틀 수 |
  | `lowResCellCount` | number | 저해상도 사진이 든 사진틀 수 |
  | `vdpList` | array | VDP 변수 목록 |
  | `layerDetect` | any | |
  | `tnUrlList` | array | 프리뷰 썸네일 URL 목록 |
  | `usedFontsList` | array | 사용된 폰트 목록 |
  | `unresolvedFontsList` | array | 등록되지 않은 폰트를 쓴 경우의 목록. 해당사항이 없으면 **키 자체가 없습니다** |
  | `calendarInfo` | object | 달력 정보. `year`와 `month`만 안정적으로 보장됩니다 |

  `usedFontsList`의 항목:

  ```json theme={null}
  {
    "familyName": "Noto Sans KR",
    "typeStyleName": "Regular",
    "fullName": "Noto Sans KR Regular",
    "issue": "S18dH02tV",
    "url": "https://fonts.gstatic.com/ea/notosanskr..."
  }
  ```

  `unresolvedFontsList`의 항목:

  ```json theme={null}
  {
    "page_index": 0,
    "fonts_unresolved": ["Noto Sans CJK KR/Bold"],
    "text_raw": "NAMECARD INC.\n"
  }
  ```

  <Note>
    `usedFontsList`의 항목은 camelCase인데 `unresolvedFontsList`의 항목은 snake\_case입니다. 같은 객체 안에서 형제 리스트끼리 케이싱이 다릅니다. 실제 이름 그대로 옮긴 것입니다.
  </Note>
</Accordion>

<Accordion title="docInfo (status: 'end', 사진인화 상품)">
  | 필드 | 타입 | 설명 |
  | - | - | - |
  | `projectID` | string | 프로젝트 id |
  | `docRevision` | number | 문서 버전 |
  | `totalPrintCount` | number | 사진 개수 |
  | `totalOrderCount` | number | 각 사진의 개별 수량을 합산한 값 |
  | `totalLoadingCount` | number | |
  | `paperType` | string | `matte` 또는 `gloss` |
  | `lowResPrintCount` | number | 저해상도 이미지 개수 |
  | `tnUrlList` | array | 프리뷰 썸네일 URL 목록 |
  | `prints` | array | 사진별 정보. 예: `[{ orderCount: 1 }, { orderCount: 3 }]` |
</Accordion>

<Warning>
  `save-doc-report` 핸들러에서 내 서버로 요청을 보낸다면 [닫기와 저장 후처리](/docs/sdk/exit)를 꼭 읽으세요. 그냥 두면 반영이 끝나기 전에 화면을 떠나 유실됩니다.
</Warning>

### `goto-cart` / `close`

편집기가 장바구니로 이동하거나 편집기를 닫아 달라고 요청합니다. payload가 없습니다. 사용자가 편집기 안에서 나가기를 눌렀을 때 옵니다.

### `doc-changed`

문서가 로드되거나 변경됐습니다.

<ResponseField name="ps_code" type="string">상품의 `ps_code`입니다.</ResponseField>
<ResponseField name="page_count" type="number">로드된 문서의 페이지 수입니다.</ResponseField>

<ResponseField name="vdp_catalog" type="unknown">
  이 문서에 어떤 VDP 변수가 정의돼 있는지의 목록입니다. 선택 필드이고, SDK는 타입을 `unknown`으로 둡니다. 항목 구조의 참고용 타입은 `VDPItem`입니다. 주입용 `VariableDataRow`와는 별개 타입이니 혼동하지 마세요. [TnView와 VDP](/docs/sdk/tnview#vdp-카탈로그)를 보세요.
</ResponseField>

### `download-tn-report`

썸네일 파일 저장이 끝났습니다. 호스트가 `save-snapshot` 커맨드를 보냈을 때와 사용자가 편집기 툴바에서 다운로드를 눌렀을 때 모두 옵니다. payload 타입은 `DownloadTnReport`입니다.

<ResponseField name="status" type="'end' | string">
  저장이 끝난 뒤에만 오므로 사실상 `'end'` 하나입니다.
</ResponseField>

<ResponseField name="filename" type="string">
  저장한 파일 이름입니다. 선택 필드입니다.
</ResponseField>

<Warning>
  한 장짜리 파일 저장은 실패해도 편집기가 오류를 삼키고 `status: 'end'`를 보냅니다. 이 보고만으로 저장 성공 여부를 판단하지 마세요.
</Warning>

### `error-report`

초기 로드가 실패했습니다.

<ResponseField name="error" type="string">
  `'load-prodinfo-failed'`는 `ps_code`로 상품 정보를 얻지 못한 경우이고, `'load-template-failed'`는 `template_uri`로 템플릿을 얻지 못한 경우입니다.
</ResponseField>

### `request-user-token`

인증이 끊겨 새 토큰이 필요합니다. `createEdicusClient({ getToken })`을 설정하셨다면 SDK가 자동으로 응답하고 이 이벤트는 핸들러로 오지 않습니다. [토큰 자동 갱신](/docs/concepts/authentication#토큰-자동-갱신)을 보세요.

### `request-help-message`

모바일 편집 모드에서 도움말 버튼을 눌렀습니다.

<ResponseField name="case" type="string">
  현재 알려진 값은 `'photo-import'`입니다.
</ResponseField>

### `page-changed`

<ResponseField name="page_index" type="number">선택된 페이지 인덱스입니다.</ResponseField>
<ResponseField name="page_type" type="string">선택된 페이지 종류입니다. 기본값은 `'content'`입니다.</ResponseField>

### `load-project-report` / `change-project-report` / `change-template-report`

<ResponseField name="status" type="'start' | 'end' | 'denied' | 'error'" />

<ResponseField name="error" type="any">`status`가 `'error'`일 때만 존재합니다.</ResponseField>

<ResponseField name="project_id" type="string">
  `load-project-report`와 `change-project-report`에 있습니다.
</ResponseField>

<ResponseField name="ps_code" type="string">
  `change-template-report`에 있습니다.
</ResponseField>

<ResponseField name="template_uri" type="string">
  `change-template-report`에 있습니다.
</ResponseField>

## 전체 이벤트 목록

`type`은 전부 `from-edicus`입니다. payload 타입은 `@edicus/sdk/types`에서 가져옵니다.

| action | payload 타입 | 비고 |
| - | - | - |
| `ready-to-listen` | `undefined` | |
| `load-project-report` | `LoadProjectReport` | |
| `change-project-report` | `LoadProjectReport` | |
| `change-template-report` | `ChangeTemplateReport` | |
| `project-id-created` | `{ project_id: string }` | |
| `doc-changed` | `DocChanged` | |
| `page-changed` | `PageChanged` | |
| `page-count-changed` | `PageCountChanged` | |
| `page-group-print-count-changed` | `PageGroupPrintCountChanged` | |
| `doc-report` | `DocReport` | |
| `scene-info-report` | `SceneInfoReport` | |
| `select-edit` | `SelectEdit` | |
| `zoom-scale-changed` | `ZoomScaleChanged` | |
| `command-completed` | `CommandInfo` | |
| `command-rejected` | `CommandRejected` | |
| `dpp-execute-report` | `DppExecuteReport` | |
| `save-doc-report` | `SaveDocReport` | |
| `update-tn-report` | `TnReport` | |
| `export-tn-report` | `TnReport` | |
| `save-snapshot-report` | `SaveSnapshotReport` | 실패 시 필드명이 `error`가 아니라 `err`입니다 |
| `capture-gallery-report` | `CaptureGalleryReport` | 실패 시 필드명이 `error`가 아니라 `err`입니다 |
| `download-tn-report` | `DownloadTnReport` | 예전 이름은 오타 `donwload-tn-report`였습니다. 아래 안내를 보세요 |
| `upload-tn-report` | `UploadTnReport` | |
| `import-project-report` | `ImportProjectReport` | |
| `browse-photo-report` | `BrowsePhotoReport` | |
| `crop-photo-report` | `CropPhotoReport` | |
| `prod-var-changed` | `unknown` | `customTab` 옵션이 켜졌을 때만 옵니다 |
| `request-user-token` | `RequestUserTokenInfo` | `{ uid }`가 옵니다. `getToken` 설정 시 핸들러로 전달되지 않습니다 |
| `request-help-message` | `{ case: 'photo-import' \| string }` | |
| `error-report` | `{ error: string }` | |
| `label-history` | `LabelHistory` | embeded 모드 전용 |
| `notify-button-click` | `NotifyButtonClick` | |
| `notify-scroll-height-changed` | `NotifyScrollHeightChanged` | |
| `preview-closed` | `null` | |
| `close` | `undefined` | |
| `goto-cart` | `undefined` | |
| `promo-external-report` | `PromoExternalReport` | |
| `plugin-request-open` | `PluginRequestOpen` | |
| `plugin-message` | `PluginMessage` | |
| `plugin-report` | `PluginReport` | |
| `auto-fill-photo-report` | `AutoFillPhotoReport` | |
| `request-page-size-change` | `RequestPageSizeChange` | |
| `request-photo-browse` | `RequestPhotoBrowse` | |
| `request-reform` | `RequestReform` | |
| `request-auto-import` | `RequestAutoImport` | |
| `imgpool-notify` | `ImgpoolNotify` | |
| `request-album-set-photo-link` | `RequestAlbumSetPhotoLink` | |

<Note>
  `download-tn-report`는 예전 편집기가 `donwload-tn-report`라는 오타로 보내던 이벤트입니다. 2026-10-06에 확인한 운영 편집기는 바른 이름으로 보냅니다. 기존 코드에 옛 이름을 확인하는 분기가 있다면 바른 이름으로 바꾸면 됩니다.
</Note>

## 다음 단계

<Columns cols={2}>
  <Card title="편집기 커맨드" icon="arrow-right" href="/docs/sdk/commands">
    편집기로 보낼 수 있는 커맨드를 봅니다.
  </Card>

  <Card title="용어집" icon="book" href="/docs/reference/glossary">
    이벤트에 나오는 이름과 개념을 봅니다.
  </Card>
</Columns>


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