@milcho0604/velog-mcp 0.4.0
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/LICENSE +21 -0
- package/README.ko.md +366 -0
- package/README.md +381 -0
- package/dist/auth.d.ts +57 -0
- package/dist/auth.js +124 -0
- package/dist/auth.js.map +1 -0
- package/dist/capabilities.d.ts +50 -0
- package/dist/capabilities.js +60 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/client.d.ts +113 -0
- package/dist/client.js +322 -0
- package/dist/client.js.map +1 -0
- package/dist/format.d.ts +31 -0
- package/dist/format.js +66 -0
- package/dist/format.js.map +1 -0
- package/dist/graphql.d.ts +29 -0
- package/dist/graphql.js +82 -0
- package/dist/graphql.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +149 -0
- package/dist/index.js.map +1 -0
- package/dist/me.d.ts +23 -0
- package/dist/me.js +35 -0
- package/dist/me.js.map +1 -0
- package/dist/ownership.d.ts +42 -0
- package/dist/ownership.js +62 -0
- package/dist/ownership.js.map +1 -0
- package/dist/plugin-env.d.ts +67 -0
- package/dist/plugin-env.js +102 -0
- package/dist/plugin-env.js.map +1 -0
- package/dist/ratelimit.d.ts +48 -0
- package/dist/ratelimit.js +79 -0
- package/dist/ratelimit.js.map +1 -0
- package/dist/render/chrome.d.ts +77 -0
- package/dist/render/chrome.js +287 -0
- package/dist/render/chrome.js.map +1 -0
- package/dist/render/cover.d.ts +29 -0
- package/dist/render/cover.js +195 -0
- package/dist/render/cover.js.map +1 -0
- package/dist/render/icons.d.ts +22 -0
- package/dist/render/icons.js +158 -0
- package/dist/render/icons.js.map +1 -0
- package/dist/render/index.d.ts +32 -0
- package/dist/render/index.js +137 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/page.d.ts +89 -0
- package/dist/render/page.js +761 -0
- package/dist/render/page.js.map +1 -0
- package/dist/render/tones.d.ts +30 -0
- package/dist/render/tones.js +46 -0
- package/dist/render/tones.js.map +1 -0
- package/dist/slug.d.ts +42 -0
- package/dist/slug.js +79 -0
- package/dist/slug.js.map +1 -0
- package/dist/tools/discover.d.ts +6 -0
- package/dist/tools/discover.js +106 -0
- package/dist/tools/discover.js.map +1 -0
- package/dist/tools/drafts.d.ts +23 -0
- package/dist/tools/drafts.js +227 -0
- package/dist/tools/drafts.js.map +1 -0
- package/dist/tools/export.d.ts +21 -0
- package/dist/tools/export.js +132 -0
- package/dist/tools/export.js.map +1 -0
- package/dist/tools/images.d.ts +34 -0
- package/dist/tools/images.js +556 -0
- package/dist/tools/images.js.map +1 -0
- package/dist/tools/posts.d.ts +14 -0
- package/dist/tools/posts.js +82 -0
- package/dist/tools/posts.js.map +1 -0
- package/dist/tools/profile-edit.d.ts +15 -0
- package/dist/tools/profile-edit.js +216 -0
- package/dist/tools/profile-edit.js.map +1 -0
- package/dist/tools/profile.d.ts +9 -0
- package/dist/tools/profile.js +133 -0
- package/dist/tools/profile.js.map +1 -0
- package/dist/tools/publish.d.ts +16 -0
- package/dist/tools/publish.js +424 -0
- package/dist/tools/publish.js.map +1 -0
- package/dist/tools/stats.d.ts +32 -0
- package/dist/tools/stats.js +154 -0
- package/dist/tools/stats.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/docs/PRD.md +146 -0
- package/docs/api-reference.md +329 -0
- package/docs/architecture.md +112 -0
- package/docs/decisions/0001-why-build-our-own.md +89 -0
- package/docs/decisions/0002-draft-only-write.md +84 -0
- package/docs/decisions/0003-token-env-only.md +109 -0
- package/docs/decisions/0004-capability-model.md +123 -0
- package/docs/decisions/0005-render-in-server.md +117 -0
- package/docs/decisions/0006-ship-as-plugin.md +532 -0
- package/docs/security.md +384 -0
- package/docs/tools.md +404 -0
- package/npm-shrinkwrap.json +2345 -0
- package/package.json +61 -0
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 그림 도구 — 다이어그램·표지를 그리고 벨로그에 올린다.
|
|
3
|
+
*
|
|
4
|
+
* ## 왜 모델이 HTML 을 쓰게 하지 않았나
|
|
5
|
+
*
|
|
6
|
+
* 그림 스타일은 서버가 쥔다. 모델은 **무엇이 있고 무엇이 어디로 흐르는지**만 주고,
|
|
7
|
+
* 색·여백·글자 실측·선 라운딩·자가감사는 렌더러가 한다. 이유는 두 가지다.
|
|
8
|
+
*
|
|
9
|
+
* ① 품질 — 매번 다시 그리면 매번 다르게 생긴다. 규칙을 코드에 박아두면
|
|
10
|
+
* 어느 글에 넣어도 같은 인상이 나온다.
|
|
11
|
+
* ② 안전 — 모델이 임의 HTML/JS 를 넘겨 브라우저에서 실행시킬 수 있으면
|
|
12
|
+
* 그건 그냥 코드 실행 통로다. 데이터만 받으면 그 통로가 없다.
|
|
13
|
+
*
|
|
14
|
+
* ## 업로드에 건 방어
|
|
15
|
+
*
|
|
16
|
+
* `velog_upload_image` 는 로컬 파일을 받아 **공개 CDN** 으로 보낸다. 경로를 그대로
|
|
17
|
+
* 믿으면 "이미지를 올려줘" 한 마디로 아무 파일이나 인터넷에 올라갈 수 있다.
|
|
18
|
+
* 그래서 확장자가 아니라 **파일 앞부분 시그니처**로 진짜 이미지인지 확인한다.
|
|
19
|
+
* SVG 는 통과시키지 않는다 — 텍스트라 시그니처로 가릴 수 없고, 스크립트를 품은 채
|
|
20
|
+
* velcdn 도메인에서 서빙되면 그 자체가 문제가 된다.
|
|
21
|
+
*/
|
|
22
|
+
import { constants, open, readFile, realpath } from 'node:fs/promises';
|
|
23
|
+
import { basename, resolve } from 'node:path';
|
|
24
|
+
import { z } from 'zod';
|
|
25
|
+
import { textResult } from "../format.js";
|
|
26
|
+
import { ICON_NAMES, TONE_NAMES, formatAudit, formatCoverAudit, renderCover, renderDiagram, } from "../render/index.js";
|
|
27
|
+
import { isHexColor } from "../render/tones.js";
|
|
28
|
+
/** 우리가 올리는 것 — 서버 상한(30MB)보다 낮게 잡는다. */
|
|
29
|
+
const MAX_UPLOAD_BYTES = 10 * 1024 * 1024;
|
|
30
|
+
/**
|
|
31
|
+
* 자가감사에 걸려 업로드를 건너뛴 PNG 경로.
|
|
32
|
+
*
|
|
33
|
+
* `force_upload` 를 없앴더니 "감사 실패 → 그 경로를 velog_upload_image 에 넘기기"라는
|
|
34
|
+
* 두 단계 우회가 남았다. 같은 인증으로 즉시 되므로 사실상 차단이 아니었다.
|
|
35
|
+
* 그래서 **이 서버가 감사에서 떨어뜨린 산출물은 이 서버로 못 올리게** 표시해 둔다.
|
|
36
|
+
*
|
|
37
|
+
* 이게 절대적 차단은 아니다 — 파일을 다른 곳으로 복사하면 우회된다. 그건 사용자가
|
|
38
|
+
* 눈으로 보게 되는 별개의 행동이므로 그 선에서 멈춘다. 목적은 '사고 방지'이지
|
|
39
|
+
* 사용자를 막는 것이 아니다.
|
|
40
|
+
*/
|
|
41
|
+
const rejectedRenders = new Set();
|
|
42
|
+
/**
|
|
43
|
+
* 거부 목록에 걸리는지 본다. 경로 표기가 달라도 같은 파일이면 같게 취급한다.
|
|
44
|
+
*
|
|
45
|
+
* ★ 이건 **완전한 차단이 아니다.** 파일을 다른 데로 복사하거나 서버를 다시 띄우면
|
|
46
|
+
* 풀린다. 목적은 "방금 감사에서 떨어진 그림을 그대로 다시 올리는 실수"를 막는 것이지
|
|
47
|
+
* 사용자를 가두는 것이 아니다. 그 이상으로 설명하면 과장이다.
|
|
48
|
+
*/
|
|
49
|
+
async function isRejected(path) {
|
|
50
|
+
if (rejectedRenders.has(resolve(path)))
|
|
51
|
+
return true;
|
|
52
|
+
const real = await realpath(path).catch(() => null);
|
|
53
|
+
return real !== null && rejectedRenders.has(real);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 앞부분 시그니처만 보면 "PNG 머리 8바이트 + 아무 텍스트" 도 통과한다.
|
|
57
|
+
* 그건 이미지가 아니라 **이미지처럼 시작하는 파일**이다.
|
|
58
|
+
*
|
|
59
|
+
* ★ 그래서 끝맺음도 봤는데, 그것도 부족했다. `IDAT` 을 **파일 전체에서 바이트열로**
|
|
60
|
+
* 찾았더니 `IHDR 의 payload 안에 IDAT 이라는 글자` 를 넣은 파일이 통과했다
|
|
61
|
+
* (코덱스가 재현). 청크가 아니라 글자를 본 것이다.
|
|
62
|
+
* 그래서 지금은 **청크 구조를 실제로 걸어간다.** 길이 필드를 따라가며
|
|
63
|
+
* 경계가 맞는지, 필요한 청크가 제자리에 있는지 확인한다.
|
|
64
|
+
*
|
|
65
|
+
* 완전한 디코딩은 아니다 — 화소 데이터가 진짜인지까지는 안 본다.
|
|
66
|
+
* 목적은 "아무 바이트나 이미지인 척 공개 CDN 에 올라가는 것"을 막는 것이다.
|
|
67
|
+
*/
|
|
68
|
+
function readU32BE(bytes, at) {
|
|
69
|
+
return (((bytes[at] ?? 0) << 24) |
|
|
70
|
+
((bytes[at + 1] ?? 0) << 16) |
|
|
71
|
+
((bytes[at + 2] ?? 0) << 8) |
|
|
72
|
+
(bytes[at + 3] ?? 0)) >>> 0;
|
|
73
|
+
}
|
|
74
|
+
function readU32LE(bytes, at) {
|
|
75
|
+
return ((bytes[at] ?? 0) |
|
|
76
|
+
((bytes[at + 1] ?? 0) << 8) |
|
|
77
|
+
((bytes[at + 2] ?? 0) << 16) |
|
|
78
|
+
((bytes[at + 3] ?? 0) << 24)) >>> 0;
|
|
79
|
+
}
|
|
80
|
+
function fourCC(bytes, at) {
|
|
81
|
+
return String.fromCharCode(bytes[at] ?? 0, bytes[at + 1] ?? 0, bytes[at + 2] ?? 0, bytes[at + 3] ?? 0);
|
|
82
|
+
}
|
|
83
|
+
/** PNG 청크를 실제로 걸어간다: [길이4][타입4][데이터][CRC4] */
|
|
84
|
+
function pngStructureOk(bytes) {
|
|
85
|
+
let at = 8; // 시그니처 다음
|
|
86
|
+
let first = true;
|
|
87
|
+
let sawIdat = false;
|
|
88
|
+
// 청크가 아무리 많아도 유한하다. 이상하면 즉시 실패.
|
|
89
|
+
while (at + 8 <= bytes.length) {
|
|
90
|
+
const len = readU32BE(bytes, at);
|
|
91
|
+
const type = fourCC(bytes, at + 4);
|
|
92
|
+
const next = at + 12 + len; // 길이4 + 타입4 + 데이터 + CRC4
|
|
93
|
+
if (len > bytes.length || next > bytes.length)
|
|
94
|
+
return false;
|
|
95
|
+
if (first) {
|
|
96
|
+
if (type !== 'IHDR' || len !== 13)
|
|
97
|
+
return false;
|
|
98
|
+
// ★ 폭·높이 0 은 규격상 무효다. 길이만 맞춘 껍데기를 한 겹 더 거른다.
|
|
99
|
+
const w = readU32BE(bytes, at + 8);
|
|
100
|
+
const h = readU32BE(bytes, at + 12);
|
|
101
|
+
if (w === 0 || h === 0)
|
|
102
|
+
return false;
|
|
103
|
+
first = false;
|
|
104
|
+
}
|
|
105
|
+
// 빈 IDAT 은 화소가 없다는 뜻이다.
|
|
106
|
+
if (type === 'IDAT' && len > 0)
|
|
107
|
+
sawIdat = true;
|
|
108
|
+
// ★ IEND 는 규격상 **마지막** 청크다. 뒤에 뭔가 더 있으면 정상 PNG 가 아니고,
|
|
109
|
+
// 거기가 바로 polyglot 이 숨는 자리다. 파일 끝과 일치하는지까지 본다.
|
|
110
|
+
if (type === 'IEND')
|
|
111
|
+
return len === 0 && sawIdat && next === bytes.length;
|
|
112
|
+
at = next;
|
|
113
|
+
}
|
|
114
|
+
return false; // IEND 로 끝나지 않았다
|
|
115
|
+
}
|
|
116
|
+
/** RIFF/WebP 청크를 걸어간다: [FourCC4][길이4][데이터(짝수 정렬)] */
|
|
117
|
+
function webpStructureOk(bytes) {
|
|
118
|
+
const riffSize = readU32LE(bytes, 4);
|
|
119
|
+
if (riffSize + 8 > bytes.length)
|
|
120
|
+
return false;
|
|
121
|
+
let at = 12;
|
|
122
|
+
const endAt = Math.min(bytes.length, riffSize + 8);
|
|
123
|
+
let sawFrame = false;
|
|
124
|
+
while (at + 8 <= endAt) {
|
|
125
|
+
const type = fourCC(bytes, at);
|
|
126
|
+
const len = readU32LE(bytes, at + 4);
|
|
127
|
+
const next = at + 8 + len + (len % 2); // 홀수면 1바이트 패딩
|
|
128
|
+
if (next > endAt)
|
|
129
|
+
return false;
|
|
130
|
+
// 실제 화소가 든 청크. VP8X(확장 헤더)만 있는 건 이미지가 아니다.
|
|
131
|
+
// ★ ANMF 는 16바이트 프레임 헤더 뒤에 실제 비트스트림이 온다 — len>0 만으로는
|
|
132
|
+
// 1바이트짜리도 통과한다.
|
|
133
|
+
if (type === 'VP8 ' || type === 'VP8L') {
|
|
134
|
+
if (len > 0)
|
|
135
|
+
sawFrame = true;
|
|
136
|
+
}
|
|
137
|
+
else if (type === 'ANMF') {
|
|
138
|
+
if (len > 16)
|
|
139
|
+
sawFrame = true;
|
|
140
|
+
}
|
|
141
|
+
at = next;
|
|
142
|
+
}
|
|
143
|
+
// ★ 첫 프레임에서 바로 반환하면 그 뒤 청크 경계가 깨져 있어도 모른다.
|
|
144
|
+
// 끝까지 걸어 경계가 맞는지 확인한 뒤에 판정한다.
|
|
145
|
+
return sawFrame && at === endAt;
|
|
146
|
+
}
|
|
147
|
+
function looksComplete(bytes, ext) {
|
|
148
|
+
if (ext === 'png')
|
|
149
|
+
return pngStructureOk(bytes);
|
|
150
|
+
if (ext === 'webp')
|
|
151
|
+
return webpStructureOk(bytes);
|
|
152
|
+
// JPEG·GIF 는 컨테이너 구조가 PNG/WebP 만큼 단순하지 않다. 끝맺음만 본다 —
|
|
153
|
+
// 머리만 베껴 붙인 파일을 거르는 선까지다. (그 이상은 디코더가 필요하다)
|
|
154
|
+
const len = bytes.length;
|
|
155
|
+
const tailFrom = Math.max(0, len - 64);
|
|
156
|
+
const has = (...sig) => {
|
|
157
|
+
for (let i = tailFrom; i <= len - sig.length; i++) {
|
|
158
|
+
let ok = true;
|
|
159
|
+
for (let j = 0; j < sig.length; j++) {
|
|
160
|
+
if (bytes[i + j] !== sig[j]) {
|
|
161
|
+
ok = false;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (ok)
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
};
|
|
170
|
+
if (ext === 'jpg')
|
|
171
|
+
return has(0xff, 0xd9); // EOI
|
|
172
|
+
if (ext === 'gif')
|
|
173
|
+
return has(0x3b); // trailer
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* 파일 앞부분으로 형식을 판정한다. 확장자는 보지 않는다 — 이름은 누구나 바꾼다.
|
|
178
|
+
* 여기서 통과하지 못하면 업로드하지 않는다.
|
|
179
|
+
*/
|
|
180
|
+
export function sniffImage(bytes) {
|
|
181
|
+
const at = (i) => bytes[i] ?? -1;
|
|
182
|
+
if (at(0) === 0x89 && at(1) === 0x50 && at(2) === 0x4e && at(3) === 0x47 &&
|
|
183
|
+
at(4) === 0x0d && at(5) === 0x0a && at(6) === 0x1a && at(7) === 0x0a) {
|
|
184
|
+
return looksComplete(bytes, 'png') ? { mime: 'image/png', ext: 'png' } : null;
|
|
185
|
+
}
|
|
186
|
+
if (at(0) === 0xff && at(1) === 0xd8 && at(2) === 0xff) {
|
|
187
|
+
return looksComplete(bytes, 'jpg') ? { mime: 'image/jpeg', ext: 'jpg' } : null;
|
|
188
|
+
}
|
|
189
|
+
if (at(0) === 0x47 && at(1) === 0x49 && at(2) === 0x46 && at(3) === 0x38) {
|
|
190
|
+
return looksComplete(bytes, 'gif') ? { mime: 'image/gif', ext: 'gif' } : null;
|
|
191
|
+
}
|
|
192
|
+
// RIFF....WEBP
|
|
193
|
+
if (at(0) === 0x52 && at(1) === 0x49 && at(2) === 0x46 && at(3) === 0x46 &&
|
|
194
|
+
at(8) === 0x57 && at(9) === 0x45 && at(10) === 0x42 && at(11) === 0x50) {
|
|
195
|
+
return looksComplete(bytes, 'webp') ? { mime: 'image/webp', ext: 'webp' } : null;
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* 파일을 읽고 검사까지 한다. 통과 못 하면 이유를 그대로 말해준다.
|
|
201
|
+
*
|
|
202
|
+
* ★ `stat` 으로 크기를 보고 나서 `readFile` 로 다시 여는 구조였다. 그 사이에 경로가
|
|
203
|
+
* 다른 파일로 바뀌면 크기 검사가 무의미해진다. 한 번 연 **같은 핸들**에서 크기를
|
|
204
|
+
* 보고 그대로 읽어 그 틈을 없앤다.
|
|
205
|
+
*/
|
|
206
|
+
async function readImageFile(path) {
|
|
207
|
+
// ★ O_NONBLOCK 으로 연다. 그냥 열면 **FIFO 에서 open 자체가 writer 를 기다리며
|
|
208
|
+
// 멈춘다** — 요청이 몇 개만 겹쳐도 Node 의 파일 I/O 스레드풀이 고갈된다.
|
|
209
|
+
const handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK).catch(() => null);
|
|
210
|
+
if (!handle)
|
|
211
|
+
throw new Error(`파일을 찾지 못했습니다: ${path}`);
|
|
212
|
+
let bytes;
|
|
213
|
+
try {
|
|
214
|
+
const info = await handle.stat();
|
|
215
|
+
if (!info.isFile())
|
|
216
|
+
throw new Error(`파일이 아닙니다: ${path}`);
|
|
217
|
+
// ★ 크기 판정은 **실제로 읽은 바이트** 하나로만 한다.
|
|
218
|
+
// 예전엔 stat 으로 한 번 보고 read 에서 또 봤는데, 두 가지가 문제였다:
|
|
219
|
+
// ① readFile() 은 내부에서 크기를 다시 재므로 stat 이후 파일이 커지면
|
|
220
|
+
// 상한을 넘겨 읽는다 (검사가 무의미해진다)
|
|
221
|
+
// ② 검사가 둘이면 하나를 지워도 다른 하나가 가려서 **테스트가 못 잡는다**
|
|
222
|
+
// (실제로 변이가 통과했다)
|
|
223
|
+
// 상한+1 만큼만 읽고, 그 이상이면 거부한다. 10MB 버퍼는 유한하고 예측 가능하다.
|
|
224
|
+
const buf = Buffer.alloc(MAX_UPLOAD_BYTES + 1);
|
|
225
|
+
const { bytesRead } = await handle.read(buf, 0, buf.length, 0);
|
|
226
|
+
if (bytesRead > MAX_UPLOAD_BYTES) {
|
|
227
|
+
throw new Error(`파일이 너무 큽니다 — 이 도구의 상한은 ${MAX_UPLOAD_BYTES / 1024 / 1024}MB 입니다.`);
|
|
228
|
+
}
|
|
229
|
+
bytes = new Uint8Array(buf.subarray(0, bytesRead));
|
|
230
|
+
}
|
|
231
|
+
finally {
|
|
232
|
+
await handle.close().catch(() => { });
|
|
233
|
+
}
|
|
234
|
+
const kind = sniffImage(bytes);
|
|
235
|
+
if (!kind) {
|
|
236
|
+
throw new Error(`이미지 파일이 아닙니다(또는 파일이 온전하지 않습니다): ${path}\n` +
|
|
237
|
+
'PNG·JPEG·GIF·WebP 만 올립니다. 확장자가 아니라 파일 내용으로 판정하며 ' +
|
|
238
|
+
'시작 시그니처와 끝맺음을 함께 봅니다 (SVG 는 받지 않습니다).');
|
|
239
|
+
}
|
|
240
|
+
return { bytes, kind };
|
|
241
|
+
}
|
|
242
|
+
const toneField = z
|
|
243
|
+
.string()
|
|
244
|
+
.refine((v) => TONE_NAMES.includes(v), `톤 이름이어야 합니다: ${TONE_NAMES.join(', ')}`);
|
|
245
|
+
const nodeSchema = z.object({
|
|
246
|
+
id: z.string().max(64).optional().describe('선을 연결할 때 쓰는 이름. 생략하면 n0, n1 …'),
|
|
247
|
+
// 상한이 없으면 요청 하나로 수억 픽셀짜리 캔버스를 요구할 수 있다.
|
|
248
|
+
x: z
|
|
249
|
+
.number()
|
|
250
|
+
.min(-20000)
|
|
251
|
+
.max(20000)
|
|
252
|
+
.describe('왼쪽 위 x. 원점은 아무 데나 잡아도 된다 — 캔버스는 자동으로 맞춘다'),
|
|
253
|
+
y: z.number().min(-20000).max(20000),
|
|
254
|
+
w: z.number().min(60).max(2400).optional().describe('생략하면 글자 실측으로 정한다'),
|
|
255
|
+
h: z.number().min(36).max(1400).optional(),
|
|
256
|
+
title: z.string().min(1).max(120),
|
|
257
|
+
sub: z.string().max(120).optional().describe('두 번째 줄. 짧게'),
|
|
258
|
+
icon: z
|
|
259
|
+
.string()
|
|
260
|
+
.refine((v) => ICON_NAMES.includes(v), `아이콘 이름: ${ICON_NAMES.join(', ')}`)
|
|
261
|
+
.optional(),
|
|
262
|
+
icon_tone: toneField.optional(),
|
|
263
|
+
tag: z.string().max(40).optional().describe('오른쪽 위 작은 배지 (예: ":6820", "v2")'),
|
|
264
|
+
tag_tone: toneField.optional(),
|
|
265
|
+
});
|
|
266
|
+
const groupSchema = z.object({
|
|
267
|
+
name: z.string().min(1).max(80),
|
|
268
|
+
sub: z.string().max(80).optional(),
|
|
269
|
+
tone: toneField.optional(),
|
|
270
|
+
members: z
|
|
271
|
+
.array(z.string().max(64))
|
|
272
|
+
.max(60)
|
|
273
|
+
.optional()
|
|
274
|
+
.describe('이 노드들을 감싸도록 상자를 자동 계산한다. 좌표를 직접 줄 거면 생략'),
|
|
275
|
+
x: z.number().min(-20000).max(20000).optional(),
|
|
276
|
+
y: z.number().min(-20000).max(20000).optional(),
|
|
277
|
+
w: z.number().min(0).max(40000).optional(),
|
|
278
|
+
h: z.number().min(0).max(40000).optional(),
|
|
279
|
+
});
|
|
280
|
+
const edgeSchema = z.object({
|
|
281
|
+
// plane.key 와 같은 규칙. 이 값도 marker 참조로 들어간다.
|
|
282
|
+
plane: z
|
|
283
|
+
.string()
|
|
284
|
+
.regex(/^[A-Za-z0-9_-]{1,16}$/, '영숫자·밑줄·하이픈 1~16자만')
|
|
285
|
+
.optional()
|
|
286
|
+
.describe('흐름 종류 key (범례와 색이 여기서 갈린다)'),
|
|
287
|
+
from: z.string().max(80).optional().describe('노드 id. 면을 고르려면 "id:right" 처럼'),
|
|
288
|
+
to: z.string().max(80).optional(),
|
|
289
|
+
// ★ 점 개수에 상한이 없으면 감사 비용이 O(E²×S²) 로 터진다.
|
|
290
|
+
// 엣지 120개 × 점 1000개면 선분 비교가 수십억 번이다.
|
|
291
|
+
points: z
|
|
292
|
+
.array(z.tuple([z.number().min(-20000).max(20000), z.number().min(-20000).max(20000)]))
|
|
293
|
+
.max(40)
|
|
294
|
+
.optional()
|
|
295
|
+
.describe('직접 꺾는 경우. 주면 from/to 대신 이 좌표를 쓴다'),
|
|
296
|
+
label: z.string().max(120).optional(),
|
|
297
|
+
label_at: z
|
|
298
|
+
.tuple([z.number().min(-20000).max(20000), z.number().min(-20000).max(20000)])
|
|
299
|
+
.optional(),
|
|
300
|
+
label_anchor: z.enum(['start', 'middle', 'end']).optional(),
|
|
301
|
+
});
|
|
302
|
+
const planeSchema = z.object({
|
|
303
|
+
// ★ key 는 SVG marker 의 id 가 되고 `url(#arr-<key>)` 로 참조된다.
|
|
304
|
+
// 자유 문자열이면 그 참조식이 깨지거나 다른 걸 가리키게 만들 수 있다.
|
|
305
|
+
key: z
|
|
306
|
+
.string()
|
|
307
|
+
.regex(/^[A-Za-z0-9_-]{1,16}$/, '영숫자·밑줄·하이픈 1~16자만 (SVG id 가 된다)'),
|
|
308
|
+
name: z.string().min(1).max(40),
|
|
309
|
+
color: z.string().refine(isHexColor, '#rrggbb 형식만 받습니다'),
|
|
310
|
+
// stroke-dasharray 는 길이 목록이다. 숫자·공백·쉼표 외에는 받지 않는다.
|
|
311
|
+
// ★ 문자 종류만 좁히고 길이를 안 뒀다. 이 값은 엣지 120개의 stroke-dasharray 로
|
|
312
|
+
// 전부 복제되고 DOM 출력에도 그만큼 반복된다 — 1MB 입력 하나가 100MB 넘는
|
|
313
|
+
// DOM 이 된다. 점선 패턴은 원래 짧다.
|
|
314
|
+
dash: z
|
|
315
|
+
.string()
|
|
316
|
+
.max(40)
|
|
317
|
+
.regex(/^[\d.\s,]+$/, '숫자와 공백·쉼표만 (예: "6 4")')
|
|
318
|
+
.optional()
|
|
319
|
+
.describe('점선 (예: "6 4")'),
|
|
320
|
+
});
|
|
321
|
+
function markdown(alt, url) {
|
|
322
|
+
return ``;
|
|
323
|
+
}
|
|
324
|
+
export function registerImageTools(server, client) {
|
|
325
|
+
/** 렌더 결과를 올리고 결과 문구를 만든다. 감사에 걸린 게 있으면 올리지 않는다. */
|
|
326
|
+
async function finish(args) {
|
|
327
|
+
const lines = [];
|
|
328
|
+
// ★ upload 여부와 무관하게, 감사에 걸린 산출물은 거부 목록에 올린다.
|
|
329
|
+
// 예전엔 upload:true 로 막힌 경우에만 넣었는데, 그러면 upload:false 로 그린 뒤
|
|
330
|
+
// 그 경로를 velog_upload_image 에 주는 우회가 그대로 남는다.
|
|
331
|
+
if (!args.clean) {
|
|
332
|
+
rejectedRenders.add(resolve(args.pngPath));
|
|
333
|
+
const real = await realpath(args.pngPath).catch(() => null);
|
|
334
|
+
if (real)
|
|
335
|
+
rejectedRenders.add(real);
|
|
336
|
+
}
|
|
337
|
+
const px = `${args.width * args.scale}×${args.height * args.scale}px`;
|
|
338
|
+
lines.push(`${args.what} 완성 — ${px} (${(args.bytes / 1024).toFixed(0)}KB)`);
|
|
339
|
+
lines.push('');
|
|
340
|
+
lines.push(args.auditText);
|
|
341
|
+
lines.push('');
|
|
342
|
+
if (args.upload && !args.clean) {
|
|
343
|
+
// ★ 감사에 걸린 그림은 올리지 않는다. 벨로그 업로드는 되돌릴 수 없고
|
|
344
|
+
// (삭제 API 가 없다) 계정 업로드 한도도 깎는다. 고쳐서 다시 그리는 게 맞다.
|
|
345
|
+
//
|
|
346
|
+
// ★★ 예전엔 `force_upload` 파라미터로 이걸 끌 수 있었다. 그건 이 저장소가
|
|
347
|
+
// 공개 발행에서 이미 배운 것(ADR 0004)을 그대로 어긴 것이다 —
|
|
348
|
+
// **모델이 스스로 켤 수 있는 스위치는 방어가 아니다.** 그래서 없앴다.
|
|
349
|
+
// 그래도 올려야 하면 경로가 있다: upload:false 로 그린 뒤 PNG 를 직접 보고
|
|
350
|
+
// velog_upload_image 로 올리면 된다. 사람이 한 번 더 개입하게 된다.
|
|
351
|
+
// ★ 예전엔 여기서 "velog_upload_image 로 올리면 된다"고 안내했다.
|
|
352
|
+
// 그건 차단 안내문이 우회 방법을 같은 상대에게 그대로 알려주는 꼴이다.
|
|
353
|
+
// 경로는 알려주되(사람이 열어봐야 하므로) 우회를 권하지는 않는다.
|
|
354
|
+
// 그리고 이 PNG 는 아래에서 업로드 거부 목록에 올린다.
|
|
355
|
+
lines.push('올리지 않았습니다 — 위 문제를 고쳐 다시 그리세요.');
|
|
356
|
+
lines.push('아래 PNG 는 이 서버로 올릴 수 없습니다 (감사에 걸린 산출물).');
|
|
357
|
+
lines.push('');
|
|
358
|
+
lines.push(`- 로컬 PNG: ${args.pngPath}`);
|
|
359
|
+
lines.push(`- 편집용 HTML: ${args.htmlPath}`);
|
|
360
|
+
return lines;
|
|
361
|
+
}
|
|
362
|
+
if (args.upload) {
|
|
363
|
+
const bytes = new Uint8Array(await readFile(args.pngPath));
|
|
364
|
+
const uploadOptions = args.postId
|
|
365
|
+
? { type: 'post', contentType: 'image/png', refId: args.postId }
|
|
366
|
+
: { type: 'post', contentType: 'image/png' };
|
|
367
|
+
const url = await client.uploadImage(bytes, `${basename(args.pngPath, '.png')}.png`, uploadOptions);
|
|
368
|
+
lines.push('본문에 붙여넣을 마크다운:');
|
|
369
|
+
lines.push('');
|
|
370
|
+
lines.push(markdown(args.alt, url));
|
|
371
|
+
lines.push('');
|
|
372
|
+
lines.push(`- 이미지 주소: ${url}`);
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
lines.push('올리지 않았습니다 (upload: false).');
|
|
376
|
+
}
|
|
377
|
+
lines.push(`- 로컬 PNG: ${args.pngPath}`);
|
|
378
|
+
lines.push(`- 편집용 HTML: ${args.htmlPath}`);
|
|
379
|
+
return lines;
|
|
380
|
+
}
|
|
381
|
+
server.registerTool('velog_render_diagram', {
|
|
382
|
+
title: '다이어그램 그리기',
|
|
383
|
+
description: '구성도·흐름도를 그려 PNG 로 만들고 벨로그에 올린다. 본문에 붙일 마크다운을 돌려준다.\n' +
|
|
384
|
+
'좌표만 주면 나머지는 렌더러가 맞춘다 — 노드 폭·캔버스 크기·선 꺾임·라벨 위치는 ' +
|
|
385
|
+
'브라우저 실측으로 정해지고, 글자 삐져나옴/선 관통/겹침은 자가감사가 잡는다.\n' +
|
|
386
|
+
'감사에 걸리면 **올리지 않고** 무엇이 문제인지 알려준다. 이 판단은 끌 수 없고, ' +
|
|
387
|
+
'감사에 걸린 산출물은 velog_upload_image 로도 받지 않는다. 고쳐서 다시 그릴 것.\n' +
|
|
388
|
+
`아이콘: ${ICON_NAMES.join(' ')}\n톤: ${TONE_NAMES.join(' ')}`,
|
|
389
|
+
inputSchema: {
|
|
390
|
+
// ★ 글자에도 상한이 필요하다. 좌표만 묶어두면 제목 하나에 10MB 를 넣어
|
|
391
|
+
// HTML·SVG·getBBox·stdout 을 동시에 부풀릴 수 있다 (코덱스 4차).
|
|
392
|
+
title: z.string().min(1).max(200).describe('그림 제목 (좌상단)'),
|
|
393
|
+
subtitle: z.string().max(300).optional().describe('한 줄 설명·근거'),
|
|
394
|
+
// ★ id 가 겹치면 관통 감사를 피할 수 있다. NMAP 은 마지막 것만 남기는데
|
|
395
|
+
// '자기 노드 제외' 집합은 id 문자열로 같은 id 를 전부 빼기 때문이다.
|
|
396
|
+
// 생략 시 자동 부여되는 n0·n1 과의 충돌도 같은 문제라 함께 본다.
|
|
397
|
+
nodes: z
|
|
398
|
+
.array(nodeSchema)
|
|
399
|
+
.min(1)
|
|
400
|
+
.max(60)
|
|
401
|
+
.superRefine((list, ctx) => {
|
|
402
|
+
const seen = new Set();
|
|
403
|
+
list.forEach((node, i) => {
|
|
404
|
+
const id = node.id ?? `n${i}`;
|
|
405
|
+
if (seen.has(id)) {
|
|
406
|
+
ctx.addIssue({
|
|
407
|
+
code: 'custom',
|
|
408
|
+
message: `노드 id 가 겹칩니다: ${id} (생략하면 n0·n1… 이 자동 부여됩니다)`,
|
|
409
|
+
path: [i, 'id'],
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
seen.add(id);
|
|
413
|
+
});
|
|
414
|
+
}),
|
|
415
|
+
groups: z.array(groupSchema).max(12).optional(),
|
|
416
|
+
edges: z.array(edgeSchema).max(120).optional(),
|
|
417
|
+
planes: z
|
|
418
|
+
.array(planeSchema)
|
|
419
|
+
.max(6)
|
|
420
|
+
.optional()
|
|
421
|
+
.describe('흐름 종류. 생략하면 요청/외부 호출/데이터/관측 4종'),
|
|
422
|
+
legend: z.boolean().default(true),
|
|
423
|
+
alt: z.string().max(300).optional().describe('이미지 대체 텍스트'),
|
|
424
|
+
upload: z.boolean().default(true),
|
|
425
|
+
post_id: z
|
|
426
|
+
.string()
|
|
427
|
+
.max(64)
|
|
428
|
+
.optional()
|
|
429
|
+
.describe('붙일 글 id. 주면 벨로그가 내 글인지 확인한 뒤 받는다'),
|
|
430
|
+
},
|
|
431
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
432
|
+
}, async (args) => {
|
|
433
|
+
if (args.upload)
|
|
434
|
+
client.requireAuth('velog_render_diagram');
|
|
435
|
+
const spec = {
|
|
436
|
+
title: args.title,
|
|
437
|
+
nodes: args.nodes,
|
|
438
|
+
legend: args.legend,
|
|
439
|
+
};
|
|
440
|
+
if (args.subtitle !== undefined)
|
|
441
|
+
spec.subtitle = args.subtitle;
|
|
442
|
+
if (args.groups !== undefined)
|
|
443
|
+
spec.groups = args.groups;
|
|
444
|
+
if (args.edges !== undefined)
|
|
445
|
+
spec.edges = args.edges;
|
|
446
|
+
if (args.planes !== undefined)
|
|
447
|
+
spec.planes = args.planes;
|
|
448
|
+
const result = await renderDiagram(spec);
|
|
449
|
+
const a = result.audit;
|
|
450
|
+
const clean = a.over.length === 0 &&
|
|
451
|
+
a.compressed.length === 0 &&
|
|
452
|
+
a.cross.length === 0 &&
|
|
453
|
+
a.overlap.length === 0 &&
|
|
454
|
+
a.collide.length === 0 &&
|
|
455
|
+
a.label.length === 0;
|
|
456
|
+
return textResult((await finish({
|
|
457
|
+
pngPath: result.pngPath,
|
|
458
|
+
htmlPath: result.htmlPath,
|
|
459
|
+
width: result.width,
|
|
460
|
+
height: result.height,
|
|
461
|
+
scale: result.scale,
|
|
462
|
+
bytes: result.bytes,
|
|
463
|
+
auditText: formatAudit(a),
|
|
464
|
+
clean,
|
|
465
|
+
upload: args.upload,
|
|
466
|
+
alt: args.alt ?? args.title,
|
|
467
|
+
...(args.post_id ? { postId: args.post_id } : {}),
|
|
468
|
+
what: '다이어그램',
|
|
469
|
+
})).join('\n'));
|
|
470
|
+
});
|
|
471
|
+
server.registerTool('velog_render_cover', {
|
|
472
|
+
title: '글 표지 만들기',
|
|
473
|
+
description: '글 목록·SNS 미리보기에 쓸 표지 이미지(1200×630)를 만든다.\n' +
|
|
474
|
+
'제목이 길면 줄바꿈하고, 그래도 안 들어가면 글자 크기를 줄인다 — 전부 실측 기준이다.\n' +
|
|
475
|
+
'만든 뒤 velog_update_post 의 thumbnail 에 돌려받은 주소를 넣으면 표지가 된다.',
|
|
476
|
+
inputSchema: {
|
|
477
|
+
title: z.string().min(1).max(200),
|
|
478
|
+
subtitle: z.string().max(300).optional(),
|
|
479
|
+
kicker: z.string().max(60).optional().describe("상단 작은 라벨 (예: '디버깅 기록')"),
|
|
480
|
+
tags: z.array(z.string().max(40)).max(6).optional(),
|
|
481
|
+
tone: toneField.optional(),
|
|
482
|
+
footer: z.string().max(60).optional().describe("우상단 서명 (예: '@milcho0604')"),
|
|
483
|
+
upload: z.boolean().default(true),
|
|
484
|
+
post_id: z.string().max(64).optional(),
|
|
485
|
+
},
|
|
486
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
487
|
+
}, async (args) => {
|
|
488
|
+
if (args.upload)
|
|
489
|
+
client.requireAuth('velog_render_cover');
|
|
490
|
+
const spec = { title: args.title };
|
|
491
|
+
if (args.subtitle !== undefined)
|
|
492
|
+
spec.subtitle = args.subtitle;
|
|
493
|
+
if (args.kicker !== undefined)
|
|
494
|
+
spec.kicker = args.kicker;
|
|
495
|
+
if (args.tags !== undefined)
|
|
496
|
+
spec.tags = args.tags;
|
|
497
|
+
if (args.tone !== undefined)
|
|
498
|
+
spec.tone = args.tone;
|
|
499
|
+
if (args.footer !== undefined)
|
|
500
|
+
spec.footer = args.footer;
|
|
501
|
+
const result = await renderCover(spec);
|
|
502
|
+
return textResult((await finish({
|
|
503
|
+
pngPath: result.pngPath,
|
|
504
|
+
htmlPath: result.htmlPath,
|
|
505
|
+
width: result.width,
|
|
506
|
+
height: result.height,
|
|
507
|
+
scale: result.scale,
|
|
508
|
+
bytes: result.bytes,
|
|
509
|
+
auditText: formatCoverAudit(result.audit),
|
|
510
|
+
clean: result.audit.truncated.length === 0,
|
|
511
|
+
upload: args.upload,
|
|
512
|
+
alt: args.title,
|
|
513
|
+
...(args.post_id ? { postId: args.post_id } : {}),
|
|
514
|
+
what: '표지',
|
|
515
|
+
})).join('\n'));
|
|
516
|
+
});
|
|
517
|
+
server.registerTool('velog_upload_image', {
|
|
518
|
+
title: '이미지 올리기',
|
|
519
|
+
description: '로컬 이미지 파일을 벨로그에 올리고 본문용 마크다운을 돌려준다.\n' +
|
|
520
|
+
'PNG·JPEG·GIF·WebP 만 받으며, 확장자가 아니라 **파일 내용**으로 판정한다.\n' +
|
|
521
|
+
'⚠️ 올라간 주소는 공개다 — 주소를 아는 사람은 누구나 볼 수 있고, 벨로그에는 ' +
|
|
522
|
+
'이미지 삭제 API 가 없다. 올리기 전에 무슨 파일인지 확인하라.',
|
|
523
|
+
inputSchema: {
|
|
524
|
+
path: z.string().min(1).max(4096).describe('로컬 파일 경로'),
|
|
525
|
+
alt: z.string().max(300).optional(),
|
|
526
|
+
type: z
|
|
527
|
+
.enum(['post', 'profile'])
|
|
528
|
+
.default('post')
|
|
529
|
+
.describe("profile 은 프로필 사진용 분류일 뿐 — 사진 교체는 velog_update_profile_image"),
|
|
530
|
+
post_id: z.string().max(64).optional().describe('붙일 글 id (서버가 소유권을 확인한다)'),
|
|
531
|
+
},
|
|
532
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
533
|
+
}, async (args) => {
|
|
534
|
+
client.requireAuth('velog_upload_image');
|
|
535
|
+
// ★ 문자열 그대로 비교하면 `/tmp/x/./a.png` 하나로 빠져나간다.
|
|
536
|
+
// 경로를 정규화하고, 심볼릭 링크까지 푼 형태로도 본다.
|
|
537
|
+
if (await isRejected(args.path)) {
|
|
538
|
+
throw new Error('이 PNG 는 이 서버의 자가감사에서 떨어진 산출물입니다 — 올릴 수 없습니다.\n' +
|
|
539
|
+
'그림을 고쳐 다시 그리세요 (velog_render_diagram).');
|
|
540
|
+
}
|
|
541
|
+
const { bytes, kind } = await readImageFile(args.path);
|
|
542
|
+
const name = basename(args.path);
|
|
543
|
+
const uploadOptions = args.post_id
|
|
544
|
+
? { type: args.type, contentType: kind.mime, refId: args.post_id }
|
|
545
|
+
: { type: args.type, contentType: kind.mime };
|
|
546
|
+
const url = await client.uploadImage(bytes, name, uploadOptions);
|
|
547
|
+
return textResult([
|
|
548
|
+
`✅ 올렸습니다 — ${kind.mime} · ${(bytes.length / 1024).toFixed(0)}KB`,
|
|
549
|
+
'',
|
|
550
|
+
markdown(args.alt ?? name, url),
|
|
551
|
+
'',
|
|
552
|
+
`- 이미지 주소: ${url}`,
|
|
553
|
+
].join('\n'));
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
//# sourceMappingURL=images.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"images.js","sourceRoot":"","sources":["../../src/tools/images.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 글 조회 도구 — 전부 읽기 전용.
|
|
3
|
+
*
|
|
4
|
+
* 인증이 없어도 공개 글은 조회된다 (ADR 0003).
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
import type { VelogClient } from '../client.ts';
|
|
8
|
+
/** 읽기 도구 공통 표식 — 클라이언트가 위험도를 판단할 수 있게 한다. */
|
|
9
|
+
export declare const READ_ONLY: {
|
|
10
|
+
readonly readOnlyHint: true;
|
|
11
|
+
readonly destructiveHint: false;
|
|
12
|
+
readonly openWorldHint: true;
|
|
13
|
+
};
|
|
14
|
+
export declare function registerPostTools(server: McpServer, client: VelogClient): void;
|