@sendbird/actionbook-core 0.7.2 → 0.7.3
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/README.md +6 -150
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,157 +1,13 @@
|
|
|
1
|
-
# actionbook-core
|
|
1
|
+
# @sendbird/actionbook-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Framework-agnostic core library for Actionbook documents.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## 왜 필요한가
|
|
8
|
-
|
|
9
|
-
기존 Actionbook 에디터의 문서 모델은 ProseMirror 스키마에 강하게 결합되어 있어서:
|
|
10
|
-
|
|
11
|
-
- 서버 사이드에서 문서를 파싱/검증할 수 없음
|
|
12
|
-
- 에디터를 교체하려면 데이터 모델까지 함께 바꿔야 함
|
|
13
|
-
- Jinja 프리뷰 등 부가 기능이 에디터 DOM에 의존
|
|
14
|
-
|
|
15
|
-
이 라이브러리는 순수 TypeScript로 작성되어 **브라우저, Node.js, 서버리스 환경** 어디서든 동작합니다.
|
|
16
|
-
|
|
17
|
-
## 빠른 시작
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
import {
|
|
21
|
-
parseMarkdown,
|
|
22
|
-
serializeToMarkdown,
|
|
23
|
-
fromProseMirrorJSON,
|
|
24
|
-
validate,
|
|
25
|
-
doc, paragraph, text, bold, resourceTag, jumpPoint,
|
|
26
|
-
} from '@sb/actionbook-core';
|
|
27
|
-
|
|
28
|
-
// 마크다운 파싱
|
|
29
|
-
const ast = parseMarkdown('# Title\n\nUse {{tool:t1:My Tool}} at ^START^');
|
|
30
|
-
|
|
31
|
-
// 빌더로 직접 생성
|
|
32
|
-
const manual = doc(
|
|
33
|
-
paragraph(text('Hello '), text('bold', [bold()]), resourceTag('tool', 't1', 'Tool')),
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
// 스키마 검증
|
|
37
|
-
const errors = validate(ast); // [] 이면 정상
|
|
38
|
-
|
|
39
|
-
// 마크다운 출력
|
|
40
|
-
const md = serializeToMarkdown(ast);
|
|
41
|
-
|
|
42
|
-
// ProseMirror JSON 변환 (기존 editor_data 호환)
|
|
43
|
-
const ast2 = fromProseMirrorJSON(existingEditorData);
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## 모듈 구조
|
|
47
|
-
|
|
48
|
-
| 모듈 | 설명 |
|
|
49
|
-
|------|------|
|
|
50
|
-
| `ast/` | 타입 정의, 빌더, 순회, 경로 주소 체계 |
|
|
51
|
-
| `schema/` | AST 구조 검증 (URL 프로토콜 allowlist 포함) |
|
|
52
|
-
| `markdown/` | mdast 기반 파서/시리얼라이저 + 커스텀 구문 플러그인 |
|
|
53
|
-
| `json/` | v3 포맷 직렬화 + 레거시 자동 감지 역직렬화 |
|
|
54
|
-
| `compat/` | ProseMirror JSONContent → AST 변환 |
|
|
55
|
-
| `operations/` | 구조적 편집 (Insert/Delete/Replace + undo 지원) |
|
|
56
|
-
| `jinja/` | 순수 텍스트 기반 Jinja 블록 파서 + 안전한 조건식 평가기 |
|
|
57
|
-
| `utils/` | 리소스 태그 추출, 중복 Jump Point 탐지 |
|
|
58
|
-
|
|
59
|
-
## 테스트
|
|
5
|
+
## Installation
|
|
60
6
|
|
|
61
7
|
```bash
|
|
62
|
-
|
|
63
|
-
npx vitest run
|
|
8
|
+
npm install @sendbird/actionbook-core
|
|
64
9
|
```
|
|
65
10
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
## 보안 설계
|
|
69
|
-
|
|
70
|
-
이 라이브러리는 신뢰되지 않는 입력(사용자가 편집한 마크다운, 외부에서 전달된 editor_data)을 처리하도록 설계되었습니다.
|
|
71
|
-
|
|
72
|
-
| 위협 | 대응 |
|
|
73
|
-
|------|------|
|
|
74
|
-
| Jinja 조건식을 통한 임의 코드 실행 | `new Function` / `eval` 제거. 재귀 하강 파서로 화이트리스트 연산자만 평가 |
|
|
75
|
-
| 악의적 AST 주입 (malformed editor_data) | 모든 역직렬화 경계에서 `validate()` 강제 적용 |
|
|
76
|
-
| `javascript:` URL을 통한 XSS | 파서, PM 변환기, 스키마 검증 3중 차단 (http/https/mailto/tel 만 허용) |
|
|
77
|
-
| 깊게 중첩된 입력으로 stack overflow | 모든 재귀 함수에 MAX_DEPTH 가드 (128) |
|
|
78
|
-
| Operation으로 잘못된 AST 생성 | 부모-자식 타입 매트릭스 검증 + 경로 유효성 체크 |
|
|
79
|
-
|
|
80
|
-
## 현재 한계
|
|
81
|
-
|
|
82
|
-
### 기존 에디터와 아직 통합되지 않음
|
|
83
|
-
|
|
84
|
-
이 라이브러리는 독립 모듈로 동일성 테스트만 완료된 상태입니다. 기존 에디터 코드를 실제로 교체하는 작업은 아직 수행되지 않았으며, 점진적으로 진행할 계획입니다.
|
|
85
|
-
|
|
86
|
-
교체 대상:
|
|
87
|
-
- `converters.ts` → `actionbookToAST()`
|
|
88
|
-
- `processResourceTags.ts` → 파서가 직접 노드 생성하므로 삭제 가능
|
|
89
|
-
- `editorConverter.ts` → `parseMarkdown()` + `serializeToMarkdown()`
|
|
90
|
-
- `JinjaPreview/` → `jinja/` 모듈
|
|
91
|
-
|
|
92
|
-
### 마크다운 파서 간 미세한 차이
|
|
93
|
-
|
|
94
|
-
기존: tiptap-markdown (markdown-it 기반) → 이 라이브러리: mdast (micromark 기반)
|
|
95
|
-
|
|
96
|
-
대부분의 마크다운에서 동일한 결과를 내지만, edge case에서 차이가 발생할 수 있습니다:
|
|
97
|
-
|
|
98
|
-
- **Loose/tight list 판단**: 빈 줄이 포함된 리스트의 처리 방식이 다를 수 있음
|
|
99
|
-
- **리스트 들여쓰기**: 2칸 vs 4칸 인식 차이
|
|
100
|
-
- **HTML 인라인**: 이 라이브러리는 HTML을 지원하지 않음 (설계 의도)
|
|
101
|
-
|
|
102
|
-
**완화 방안**: 실제 프로덕션 데이터에서 추출한 마크다운 fixture를 추가하여 차이를 조기에 발견해야 합니다.
|
|
103
|
-
|
|
104
|
-
### Jinja evaluator 제약
|
|
105
|
-
|
|
106
|
-
안전성을 위해 재귀 하강 파서를 사용하므로, Jinja2의 전체 표현식 문법을 지원하지 않습니다.
|
|
107
|
-
|
|
108
|
-
**지원됨**: `==`, `!=`, `<`, `>`, `<=`, `>=`, `and`, `or`, `not`, `in`, `is`, `is not`, 괄호, 문자열/숫자/불리언/None 리터럴, 점 표기법 변수
|
|
109
|
-
|
|
110
|
-
**미지원**:
|
|
111
|
-
- 필터 (`value | upper`, `items | length`)
|
|
112
|
-
- 함수 호출 (`len(items)`, `range(10)`)
|
|
113
|
-
- 리스트/딕셔너리 리터럴 (`[1, 2]`, `{"k": "v"}`)
|
|
114
|
-
- 삼항 (`"a" if cond else "b"`)
|
|
115
|
-
- `not in` 연산자
|
|
116
|
-
- 슬라이싱 (`items[0]`)
|
|
117
|
-
|
|
118
|
-
실제 Actionbook에서 사용 중인 조건식이 이 범위를 넘는다면 evaluator 확장이 필요합니다.
|
|
119
|
-
|
|
120
|
-
### Operations 모듈은 기반만 구현
|
|
121
|
-
|
|
122
|
-
- **노드 단위 편집만 가능**: 텍스트 노드 내부의 문자 레벨 편집(split/merge)은 미지원
|
|
123
|
-
- **동시성 미지원**: CRDT/OT 변환 로직 없음. `NodePath` + `Transaction` 구조가 확장 포인트로 설계되어 있지만 실제 conflict resolution은 없음
|
|
124
|
-
- **빈 컨테이너 허용**: 모든 listItem을 삭제한 후 빈 bulletList가 남는 등의 의미적 무결성은 검증하지 않음 (schema validation에서는 잡힘)
|
|
125
|
-
|
|
126
|
-
### 번들 크기 미검증
|
|
127
|
-
|
|
128
|
-
`micromark` + `mdast-util` 생태계 의존성이 추가됨. 루트 프로젝트가 이미 `remark-gfm`을 쓰고 있어 중복은 적을 것으로 예상하지만, 실제 tree-shaking 후 번들 크기 측정은 아직 하지 않았습니다.
|
|
129
|
-
|
|
130
|
-
## 향후 계획
|
|
131
|
-
|
|
132
|
-
### 단기 (통합 단계)
|
|
133
|
-
|
|
134
|
-
1. **프로덕션 fixture 확보**: 실제 고객 Actionbook 데이터에서 마크다운 + PM JSON 쌍을 추출하여 동일성 테스트 보강
|
|
135
|
-
2. **기존 코드 점진적 교체**: 가장 리스크가 낮은 읽기 전용 경로(프리뷰, 내보내기)부터 이 라이브러리로 전환
|
|
136
|
-
3. **번들 크기 측정**: Vite 빌드에서의 실제 기여도 확인
|
|
137
|
-
|
|
138
|
-
### 중기 (에디터 독립화)
|
|
139
|
-
|
|
140
|
-
4. **actionbook-renderer**: 자체 AST를 입력으로 받는 React 읽기 전용 렌더러. 프리뷰에 먼저 적용
|
|
141
|
-
5. **Jinja evaluator 확장**: 필터, `not in`, 리스트 리터럴 등 실제 사용되는 패턴 추가
|
|
142
|
-
6. **서버 사이드 검증**: Node.js 서버에서 마크다운 파싱/Jinja 변수 추출 수행
|
|
143
|
-
|
|
144
|
-
### 장기 (에디터 교체)
|
|
145
|
-
|
|
146
|
-
7. **actionbook-editor**: 자체 AST + Operation 기반의 편집 가능한 에디터
|
|
147
|
-
8. **CRDT 협업 편집**: Operation 모델 위에 Yjs/Automerge 어댑터
|
|
148
|
-
9. **History 시스템**: `Transaction` + `invertOperation()` 기반 undo/redo 스택
|
|
149
|
-
|
|
150
|
-
## 리스크
|
|
11
|
+
## License
|
|
151
12
|
|
|
152
|
-
|
|
153
|
-
|--------|--------|------|------|
|
|
154
|
-
| remark↔markdown-it 파싱 차이로 데이터 깨짐 | 중간 | 높음 | 프로덕션 fixture 테스트, normalize 함수, 이중 실행 비교 |
|
|
155
|
-
| Jinja evaluator가 실제 사용 패턴을 커버 못함 | 낮음 | 중간 | 실사용 조건식 수집 → tokenizer/parser 확장 |
|
|
156
|
-
| 번들 크기 증가 | 낮음 | 낮음 | tree-shaking 확인, lazy import 검토 |
|
|
157
|
-
| `^id^` 와 기존 에디터의 caret 충돌 | 낮음 | 낮음 | 알파벳+언더스코어 제한으로 범위 축소 |
|
|
13
|
+
Proprietary - Sendbird, Inc. All rights reserved.
|