@3rtools/tyts-mcp 0.1.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/README.md +103 -0
- package/dist/chrome.d.ts +3 -0
- package/dist/chrome.js +36 -0
- package/dist/chrome.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +23 -0
- package/dist/cli.js.map +1 -0
- package/dist/document.d.ts +76 -0
- package/dist/document.js +101 -0
- package/dist/document.js.map +1 -0
- package/dist/image.d.ts +16 -0
- package/dist/image.js +70 -0
- package/dist/image.js.map +1 -0
- package/dist/schemas.d.ts +490 -0
- package/dist/schemas.js +49 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.js +197 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +57 -0
- package/dist/session.js +186 -0
- package/dist/session.js.map +1 -0
- package/editor/appicon/Icon 1024.png +0 -0
- package/editor/appicon/Icon 128.png +0 -0
- package/editor/appicon/Icon 16.png +0 -0
- package/editor/appicon/Icon 256.png +0 -0
- package/editor/appicon/Icon 32.png +0 -0
- package/editor/appicon/Icon 512.png +0 -0
- package/editor/appicon/Icon 64.png +0 -0
- package/editor/assets/bootstrap-icons-BeopsB42.woff +0 -0
- package/editor/assets/bootstrap-icons-mSm7cUeB.woff2 +0 -0
- package/editor/assets/html2canvas.esm-DXEQVQnt.js +5 -0
- package/editor/assets/index-Bnr_82GS.js +236 -0
- package/editor/assets/index-DkXpHR6W.css +1 -0
- package/editor/assets/index.es-COZX40-D.js +5 -0
- package/editor/assets/purify.es-C0_7NiBM.js +2 -0
- package/editor/favicon/192.png +0 -0
- package/editor/favicon/512.png +0 -0
- package/editor/favicon/apple-touch-icon.png +0 -0
- package/editor/favicon/favicon.ico +0 -0
- package/editor/favicon/favicon.svg +12 -0
- package/editor/favicon/png/favicon-16x16.png +0 -0
- package/editor/favicon/png/favicon-32x32.png +0 -0
- package/editor/favicon/png/favicon-64x64.png +0 -0
- package/editor/fonts/road-ui/RoadUI-Bold.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-Bold.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-BoldOblique.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-BoldOblique.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-ExtraBold.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-ExtraBold.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-ExtraBoldOblique.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-ExtraBoldOblique.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-ExtraLight.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-ExtraLight.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-ExtraLightOblique.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-ExtraLightOblique.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-Light.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-Light.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-LightOblique.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-LightOblique.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-Medium.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-Medium.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-MediumOblique.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-MediumOblique.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-Oblique.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-Oblique.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-Regular.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-Regular.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-SemiBold.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-SemiBold.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-SemiBoldOblique.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-SemiBoldOblique.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-Thin.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-Thin.woff2 +0 -0
- package/editor/fonts/road-ui/RoadUI-ThinOblique.woff +0 -0
- package/editor/fonts/road-ui/RoadUI-ThinOblique.woff2 +0 -0
- package/editor/fonts/road-ui/road-ui.css +113 -0
- package/editor/images/crypto/btc.svg +31 -0
- package/editor/images/crypto/eth.svg +11 -0
- package/editor/images/crypto/trx.svg +11 -0
- package/editor/images/crypto/usdt.svg +8 -0
- package/editor/index.html +23 -0
- package/editor/tyts-embed.js +242 -0
- package/package.json +43 -0
- package/static/harness.html +45 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
4
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { buildDocument, PIN_COLORS, summarizeDocument } from './document.js';
|
|
7
|
+
import { dataUrlToBuffer, extensionForFormat, loadImageSource } from './image.js';
|
|
8
|
+
import { looseDocumentSchema, renderInputShape } from './schemas.js';
|
|
9
|
+
import { EditorError, EditorSession } from './session.js';
|
|
10
|
+
export const SERVER_VERSION = '0.1.0';
|
|
11
|
+
/** Редактор масштабує полотно до 1500 px по більшій стороні (src/constants.ts MAX_LOGICAL_IMAGE_SIZE). */
|
|
12
|
+
export const MAX_LOGICAL_IMAGE_SIZE = 1500;
|
|
13
|
+
/** Експорт при scale=1 має роздільність imageSize × 2 (dprBase у handleExport). */
|
|
14
|
+
export const EXPORT_DPR_BASE = 2;
|
|
15
|
+
/** Після loadDocument редактор ще розкладає картки; чекаємо перед експортом. */
|
|
16
|
+
const SETTLE_MS = 350;
|
|
17
|
+
const PREVIEW_MAX_WIDTH = 1024;
|
|
18
|
+
export function computeEditorSize(width, height) {
|
|
19
|
+
const scale = Math.min(MAX_LOGICAL_IMAGE_SIZE / width, MAX_LOGICAL_IMAGE_SIZE / height);
|
|
20
|
+
return { w: Math.round(width * scale), h: Math.round(height * scale) };
|
|
21
|
+
}
|
|
22
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
23
|
+
export function outputPath(requested, format, env = process.env) {
|
|
24
|
+
if (requested)
|
|
25
|
+
return isAbsolute(requested) ? requested : resolve(process.cwd(), requested);
|
|
26
|
+
const dir = env.TYTS_OUTPUT_DIR ? resolve(env.TYTS_OUTPUT_DIR) : join(tmpdir(), 'tyts-mcp');
|
|
27
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
28
|
+
return join(dir, `tyts-${stamp}-${Math.random().toString(16).slice(2, 6)}.${extensionForFormat(format)}`);
|
|
29
|
+
}
|
|
30
|
+
const ANNOTATIONS_DOC = `# Анотації для tyts_render
|
|
31
|
+
|
|
32
|
+
Кожен елемент \`pins\` — фігура на картинці плюс (необовʼязково) картка-виноска з текстом.
|
|
33
|
+
Координати — пікселі **оригінальної** картинки (як її бачить vision); розмір дає \`tyts_image_info\`.
|
|
34
|
+
Редактор сам нумерує виноски (1, 2, 3…) і розкладає картки навколо картинки.
|
|
35
|
+
|
|
36
|
+
| type | геометрія | коли |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| \`point\` | \`x, y\` | одна точка з маркером |
|
|
39
|
+
| \`rectangle\` | \`x, y, width, height, rotation?\` | обʼєкт у рамці |
|
|
40
|
+
| \`ellipse\` | \`cx, cy, rx, ry, rotation?\` | обʼєкт в овалі |
|
|
41
|
+
| \`polygon\` | \`points: [{x,y}…]\` (≥3) | довільна область |
|
|
42
|
+
| \`polyline\` | \`points: [{x,y}…]\` (≥2) | маршрут, лінія |
|
|
43
|
+
| \`arrow\` | \`start, end, control?\` | напрямок; \`control\` вигинає стрілку |
|
|
44
|
+
| \`text\` | \`x, y, width, height\` | текстовий блок прямо на картинці (\`text\` — вміст) |
|
|
45
|
+
| \`compass\` | \`cx, cy, radius, rotation?\` | роза вітрів / північ |
|
|
46
|
+
| \`standalone\` | \`x, y\` | картка без фігури та лінії |
|
|
47
|
+
|
|
48
|
+
Спільні поля: \`text\` (рядки через \\n), \`color\` (CSS), \`id\`, \`strokeStyle: solid|dashed\`,
|
|
49
|
+
\`fillStyle: filled|none\`, \`card: {x,y,width,height}\` — явна позиція картки.
|
|
50
|
+
|
|
51
|
+
Палітра редактора (типово по колу): ${PIN_COLORS.join(', ')}.
|
|
52
|
+
|
|
53
|
+
Поради: 3–7 виносок на картинку; короткий текст (до 2 рядків); рамки з невеликим запасом
|
|
54
|
+
навколо обʼєкта; для напрямку руху — \`arrow\`; для області — \`polygon\`. Після рендера
|
|
55
|
+
подивись preview і, якщо фігура не там, виправ координати й повтори.
|
|
56
|
+
|
|
57
|
+
Приклад:
|
|
58
|
+
\`\`\`json
|
|
59
|
+
{ "image": "./photo.jpg", "pins": [
|
|
60
|
+
{ "type": "rectangle", "x": 130, "y": 360, "width": 220, "height": 130, "text": "Техніка" },
|
|
61
|
+
{ "type": "point", "x": 460, "y": 460, "text": "Дорога", "color": "#0088FF" },
|
|
62
|
+
{ "type": "arrow", "start": { "x": 300, "y": 120 }, "end": { "x": 520, "y": 260 }, "text": "Напрямок руху" }
|
|
63
|
+
] }
|
|
64
|
+
\`\`\`
|
|
65
|
+
`;
|
|
66
|
+
function errorResult(err) {
|
|
67
|
+
const text = err instanceof EditorError
|
|
68
|
+
? `${err.code}: ${err.message}` + (err.code === 'invalid_document' ? '. Перевір обовʼязкові поля пінів і геометрію anchor (ресурс tyts://docs/annotations).' : '')
|
|
69
|
+
: err instanceof Error ? err.message : String(err);
|
|
70
|
+
return { isError: true, content: [{ type: 'text', text }] };
|
|
71
|
+
}
|
|
72
|
+
export function createServer(options = {}) {
|
|
73
|
+
const log = options.log ?? (() => { });
|
|
74
|
+
const env = options.env ?? process.env;
|
|
75
|
+
const session = options.session ?? new EditorSession({ log });
|
|
76
|
+
const server = new McpServer({ name: 'tyts', version: SERVER_VERSION });
|
|
77
|
+
server.registerResource('annotations', 'tyts://docs/annotations', { title: 'Формат анотацій ТИЦЬ', description: 'Типи фігур, поля, палітра, поради для tyts_render', mimeType: 'text/markdown' }, async (uri) => ({ contents: [{ uri: uri.href, mimeType: 'text/markdown', text: ANNOTATIONS_DOC }] }));
|
|
78
|
+
server.registerPrompt('annotate-image', {
|
|
79
|
+
title: 'Анотувати картинку',
|
|
80
|
+
description: 'Покроково: розмір картинки → tyts_render з виносками → перевірка preview',
|
|
81
|
+
argsSchema: { image: z.string().describe('Шлях або URL картинки'), task: z.string().optional().describe('Що саме треба позначити') },
|
|
82
|
+
}, ({ image, task }) => ({
|
|
83
|
+
messages: [{
|
|
84
|
+
role: 'user',
|
|
85
|
+
content: {
|
|
86
|
+
type: 'text',
|
|
87
|
+
text: `Зроби анотований колаж ТИЦЬ для картинки ${image}.${task ? ` Завдання: ${task}.` : ''}
|
|
88
|
+
1. Виклич tyts_image_info, щоб дізнатися розмір у пікселях.
|
|
89
|
+
2. Подивись на картинку і визнач, що позначити. Прочитай ресурс tyts://docs/annotations.
|
|
90
|
+
3. Виклич tyts_render з image і pins (координати в пікселях оригіналу, короткий text у кожному піні).
|
|
91
|
+
4. Перевір preview: чи фігури на потрібних обʼєктах. Якщо ні — виправ координати і повтори.
|
|
92
|
+
5. У відповіді дай шлях до файлу з поля path.`,
|
|
93
|
+
},
|
|
94
|
+
}],
|
|
95
|
+
}));
|
|
96
|
+
server.registerTool('tyts_image_info', {
|
|
97
|
+
title: 'Розмір картинки',
|
|
98
|
+
description: 'Ширина/висота картинки в пікселях (система координат для pins) і розмір полотна редактора.',
|
|
99
|
+
inputSchema: { image: z.string().min(1).describe('Шлях до файлу, http(s) URL або data URL') },
|
|
100
|
+
}, async ({ image }) => {
|
|
101
|
+
try {
|
|
102
|
+
const dataUrl = await loadImageSource(image);
|
|
103
|
+
const info = await session.imageInfo(dataUrl);
|
|
104
|
+
const mime = dataUrl.slice(5, dataUrl.indexOf(';'));
|
|
105
|
+
const result = { width: info.width, height: info.height, mime, editorSize: computeEditorSize(info.width, info.height), coordinates: 'pins use source pixels (width × height)' };
|
|
106
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
return errorResult(err);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
server.registerTool('tyts_validate', {
|
|
113
|
+
title: 'Перевірити документ',
|
|
114
|
+
description: 'Чи приймає редактор повний TytsDocument (без рендера).',
|
|
115
|
+
inputSchema: { document: looseDocumentSchema },
|
|
116
|
+
}, async ({ document }) => {
|
|
117
|
+
try {
|
|
118
|
+
await session.loadDocument(document);
|
|
119
|
+
await session.reset();
|
|
120
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, pins: document.pins.length }) }] };
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
if (err instanceof EditorError) {
|
|
124
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, code: err.code, message: err.message }) }] };
|
|
125
|
+
}
|
|
126
|
+
return errorResult(err);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
server.registerTool('tyts_render', {
|
|
130
|
+
title: 'Зробити анотований колаж',
|
|
131
|
+
description: 'Рендерить картинку з виносками ТИЦЬ у PNG/JPEG/PDF і зберігає файл. Вхід: image + pins (координати в пікселях оригіналу) або готовий document. Повертає шлях, розмір і зменшений preview для перевірки.',
|
|
132
|
+
inputSchema: renderInputShape,
|
|
133
|
+
}, async (args) => {
|
|
134
|
+
try {
|
|
135
|
+
let document;
|
|
136
|
+
if (args.document) {
|
|
137
|
+
document = args.document;
|
|
138
|
+
await session.loadDocument(document);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (!args.image)
|
|
142
|
+
throw new Error('Pass "image" (with optional "pins") or a full "document".');
|
|
143
|
+
const dataUrl = await loadImageSource(args.image);
|
|
144
|
+
await session.loadImage(dataUrl);
|
|
145
|
+
const base = await session.getDocument();
|
|
146
|
+
if (!base)
|
|
147
|
+
throw new Error('Editor did not accept the image.');
|
|
148
|
+
document = buildDocument({
|
|
149
|
+
backgroundImage: dataUrl,
|
|
150
|
+
imageSize: base.imageSize,
|
|
151
|
+
sourceImageSize: base.sourceImageSize,
|
|
152
|
+
pins: args.pins ?? [],
|
|
153
|
+
coordinates: args.coordinates,
|
|
154
|
+
meta: { sourceTitle: args.image.startsWith('data:') ? undefined : args.image, capturedAt: Date.now() },
|
|
155
|
+
});
|
|
156
|
+
if (document.pins.length > 0)
|
|
157
|
+
await session.loadDocument(document);
|
|
158
|
+
}
|
|
159
|
+
await sleep(SETTLE_MS);
|
|
160
|
+
const current = (await session.getDocument()) ?? document;
|
|
161
|
+
const basePx = current.imageSize.w * EXPORT_DPR_BASE;
|
|
162
|
+
const scale = args.width ? Math.min(4, Math.max(0.05, args.width / basePx)) : (args.scale ?? 1);
|
|
163
|
+
const format = args.format;
|
|
164
|
+
const exported = await session.export(format, scale);
|
|
165
|
+
const buffer = dataUrlToBuffer(exported.dataUrl);
|
|
166
|
+
const path = outputPath(args.output, format, env);
|
|
167
|
+
await mkdir(dirname(path), { recursive: true });
|
|
168
|
+
await writeFile(path, buffer);
|
|
169
|
+
log(`rendered ${path} (${buffer.length} bytes)`);
|
|
170
|
+
const summary = {
|
|
171
|
+
path,
|
|
172
|
+
bytes: buffer.length,
|
|
173
|
+
mime: exported.mime,
|
|
174
|
+
width: exported.width,
|
|
175
|
+
height: exported.height,
|
|
176
|
+
imageSize: current.imageSize,
|
|
177
|
+
sourceImageSize: current.sourceImageSize,
|
|
178
|
+
pins: current.pins.map((p) => ({ id: p.id, label: p.label, type: p.anchor.type, text: p.description.replace(/<[^>]+>/g, '') })),
|
|
179
|
+
document: summarizeDocument(current),
|
|
180
|
+
};
|
|
181
|
+
const content = [
|
|
182
|
+
{ type: 'text', text: JSON.stringify(summary, null, 2) },
|
|
183
|
+
];
|
|
184
|
+
if (args.preview && format !== 'pdf') {
|
|
185
|
+
const previewScale = Math.min(scale, PREVIEW_MAX_WIDTH / basePx);
|
|
186
|
+
const preview = previewScale >= scale && format === 'png' ? exported : await session.export('png', previewScale);
|
|
187
|
+
content.push({ type: 'image', data: preview.dataUrl.slice(preview.dataUrl.indexOf(',') + 1), mimeType: 'image/png' });
|
|
188
|
+
}
|
|
189
|
+
return { content };
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
return errorResult(err);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return { server, session };
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { EditorDocument } from './document.js';
|
|
2
|
+
import type { ExportFormat } from './schemas.js';
|
|
3
|
+
export interface EditorSessionOptions {
|
|
4
|
+
/** Тека зі збіркою редактора (index.html, assets, tyts-embed.js). */
|
|
5
|
+
editorDir?: string;
|
|
6
|
+
/** Тека з harness.html. */
|
|
7
|
+
staticDir?: string;
|
|
8
|
+
chromePath?: string;
|
|
9
|
+
/** Закрити браузер після паузи без викликів. */
|
|
10
|
+
idleMs?: number;
|
|
11
|
+
/** Куди писати діагностику (stdout зайнятий MCP-транспортом). */
|
|
12
|
+
log?: (message: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare class EditorError extends Error {
|
|
15
|
+
code: string;
|
|
16
|
+
constructor(code: string, message: string);
|
|
17
|
+
}
|
|
18
|
+
export interface ExportResult {
|
|
19
|
+
dataUrl: string;
|
|
20
|
+
mime: string;
|
|
21
|
+
width: number | null;
|
|
22
|
+
height: number | null;
|
|
23
|
+
}
|
|
24
|
+
/** Тека зі збіркою редактора: env → пакет (`editor/`) → dev-збірка репозиторію. */
|
|
25
|
+
export declare function resolveEditorDir(env?: NodeJS.ProcessEnv): string;
|
|
26
|
+
/** Один headless Chrome + одна сторінка з редактором; стартує ліниво, закривається по idle. */
|
|
27
|
+
export declare class EditorSession {
|
|
28
|
+
private server;
|
|
29
|
+
private port;
|
|
30
|
+
private browser;
|
|
31
|
+
private page;
|
|
32
|
+
private idleTimer;
|
|
33
|
+
private starting;
|
|
34
|
+
private readonly editorDir;
|
|
35
|
+
private readonly staticDir;
|
|
36
|
+
private readonly idleMs;
|
|
37
|
+
private readonly log;
|
|
38
|
+
private readonly chromePath;
|
|
39
|
+
constructor(options?: EditorSessionOptions);
|
|
40
|
+
get editorBundleDir(): string;
|
|
41
|
+
private serveStatic;
|
|
42
|
+
private start;
|
|
43
|
+
private ensurePage;
|
|
44
|
+
private touch;
|
|
45
|
+
private call;
|
|
46
|
+
loadImage(dataUrl: string): Promise<void>;
|
|
47
|
+
loadDocument(document: EditorDocument | Record<string, unknown>): Promise<void>;
|
|
48
|
+
getDocument(): Promise<EditorDocument | null>;
|
|
49
|
+
export(format: ExportFormat, scale: number): Promise<ExportResult>;
|
|
50
|
+
reset(): Promise<void>;
|
|
51
|
+
imageInfo(dataUrl: string): Promise<{
|
|
52
|
+
width: number;
|
|
53
|
+
height: number;
|
|
54
|
+
}>;
|
|
55
|
+
private closeBrowser;
|
|
56
|
+
close(): Promise<void>;
|
|
57
|
+
}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { createReadStream, existsSync, statSync } from 'node:fs';
|
|
2
|
+
import { createServer } from 'node:http';
|
|
3
|
+
import { dirname, extname, join, normalize, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import puppeteer from 'puppeteer-core';
|
|
6
|
+
import { CHROME_NOT_FOUND_HINT, findChrome } from './chrome.js';
|
|
7
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const CONTENT_TYPES = {
|
|
9
|
+
'.html': 'text/html; charset=utf-8',
|
|
10
|
+
'.js': 'application/javascript; charset=utf-8',
|
|
11
|
+
'.mjs': 'application/javascript; charset=utf-8',
|
|
12
|
+
'.css': 'text/css; charset=utf-8',
|
|
13
|
+
'.json': 'application/json; charset=utf-8',
|
|
14
|
+
'.png': 'image/png',
|
|
15
|
+
'.jpg': 'image/jpeg',
|
|
16
|
+
'.svg': 'image/svg+xml',
|
|
17
|
+
'.ico': 'image/x-icon',
|
|
18
|
+
'.woff': 'font/woff',
|
|
19
|
+
'.woff2': 'font/woff2',
|
|
20
|
+
'.webmanifest': 'application/manifest+json',
|
|
21
|
+
};
|
|
22
|
+
export class EditorError extends Error {
|
|
23
|
+
code;
|
|
24
|
+
constructor(code, message) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.code = code;
|
|
27
|
+
this.name = 'EditorError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Тека зі збіркою редактора: env → пакет (`editor/`) → dev-збірка репозиторію. */
|
|
31
|
+
export function resolveEditorDir(env = process.env) {
|
|
32
|
+
const candidates = [
|
|
33
|
+
env.TYTS_EDITOR_DIR,
|
|
34
|
+
resolve(here, '../editor'),
|
|
35
|
+
resolve(here, '../../../build/embed'),
|
|
36
|
+
].filter((p) => Boolean(p));
|
|
37
|
+
for (const dir of candidates) {
|
|
38
|
+
if (existsSync(join(dir, 'index.html')) && existsSync(join(dir, 'tyts-embed.js')))
|
|
39
|
+
return dir;
|
|
40
|
+
}
|
|
41
|
+
throw new Error(`Editor bundle not found. Looked in: ${candidates.join(', ')}. Run "npm run build:embed" in the tyts repo or set TYTS_EDITOR_DIR.`);
|
|
42
|
+
}
|
|
43
|
+
/** Один headless Chrome + одна сторінка з редактором; стартує ліниво, закривається по idle. */
|
|
44
|
+
export class EditorSession {
|
|
45
|
+
server = null;
|
|
46
|
+
port = 0;
|
|
47
|
+
browser = null;
|
|
48
|
+
page = null;
|
|
49
|
+
idleTimer = null;
|
|
50
|
+
starting = null;
|
|
51
|
+
editorDir;
|
|
52
|
+
staticDir;
|
|
53
|
+
idleMs;
|
|
54
|
+
log;
|
|
55
|
+
chromePath;
|
|
56
|
+
constructor(options = {}) {
|
|
57
|
+
this.editorDir = options.editorDir ?? resolveEditorDir();
|
|
58
|
+
this.staticDir = options.staticDir ?? resolve(here, '../static');
|
|
59
|
+
this.idleMs = options.idleMs ?? 5 * 60 * 1000;
|
|
60
|
+
this.log = options.log ?? (() => { });
|
|
61
|
+
this.chromePath = options.chromePath;
|
|
62
|
+
}
|
|
63
|
+
get editorBundleDir() {
|
|
64
|
+
return this.editorDir;
|
|
65
|
+
}
|
|
66
|
+
serveStatic() {
|
|
67
|
+
if (this.server)
|
|
68
|
+
return Promise.resolve(this.port);
|
|
69
|
+
const roots = [this.editorDir, this.staticDir];
|
|
70
|
+
const server = createServer((req, res) => {
|
|
71
|
+
const urlPath = decodeURIComponent((req.url ?? '/').split('?')[0]);
|
|
72
|
+
const relative = normalize(urlPath === '/' ? '/index.html' : urlPath).replace(/^(\.\.[/\\])+/, '');
|
|
73
|
+
for (const root of roots) {
|
|
74
|
+
const file = join(root, relative);
|
|
75
|
+
if (!file.startsWith(root) || !existsSync(file) || !statSync(file).isFile())
|
|
76
|
+
continue;
|
|
77
|
+
res.writeHead(200, { 'Content-Type': CONTENT_TYPES[extname(file).toLowerCase()] ?? 'application/octet-stream', 'Cache-Control': 'no-store' });
|
|
78
|
+
createReadStream(file).pipe(res);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
res.writeHead(404);
|
|
82
|
+
res.end('not found');
|
|
83
|
+
});
|
|
84
|
+
return new Promise((resolvePort, reject) => {
|
|
85
|
+
server.once('error', reject);
|
|
86
|
+
server.listen(0, '127.0.0.1', () => {
|
|
87
|
+
this.server = server;
|
|
88
|
+
this.port = server.address().port;
|
|
89
|
+
this.log(`static server on http://127.0.0.1:${this.port} (editor: ${this.editorDir})`);
|
|
90
|
+
resolvePort(this.port);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async start() {
|
|
95
|
+
const port = await this.serveStatic();
|
|
96
|
+
const executablePath = this.chromePath ?? findChrome();
|
|
97
|
+
if (!executablePath)
|
|
98
|
+
throw new Error(CHROME_NOT_FOUND_HINT);
|
|
99
|
+
this.browser = await puppeteer.launch({
|
|
100
|
+
executablePath,
|
|
101
|
+
headless: true,
|
|
102
|
+
args: ['--disable-gpu', '--no-first-run', '--no-default-browser-check', '--hide-scrollbars'],
|
|
103
|
+
});
|
|
104
|
+
this.browser.once('disconnected', () => {
|
|
105
|
+
this.browser = null;
|
|
106
|
+
this.page = null;
|
|
107
|
+
});
|
|
108
|
+
const page = await this.browser.newPage();
|
|
109
|
+
await page.setViewport({ width: 1400, height: 900, deviceScaleFactor: 1 });
|
|
110
|
+
page.on('pageerror', (err) => this.log(`page error: ${err instanceof Error ? err.message : String(err)}`));
|
|
111
|
+
await page.goto(`http://127.0.0.1:${port}/harness.html`, { waitUntil: 'load' });
|
|
112
|
+
const ready = await page.evaluate(async () => window.__tyts.ready);
|
|
113
|
+
if (!ready.ok)
|
|
114
|
+
throw new EditorError(ready.error.code, ready.error.message);
|
|
115
|
+
this.page = page;
|
|
116
|
+
this.log('editor ready');
|
|
117
|
+
return page;
|
|
118
|
+
}
|
|
119
|
+
async ensurePage() {
|
|
120
|
+
if (this.page && this.browser?.connected)
|
|
121
|
+
return this.page;
|
|
122
|
+
if (!this.starting) {
|
|
123
|
+
this.starting = this.start().finally(() => { this.starting = null; });
|
|
124
|
+
}
|
|
125
|
+
return this.starting;
|
|
126
|
+
}
|
|
127
|
+
touch() {
|
|
128
|
+
if (this.idleTimer)
|
|
129
|
+
clearTimeout(this.idleTimer);
|
|
130
|
+
if (this.idleMs > 0) {
|
|
131
|
+
this.idleTimer = setTimeout(() => { void this.closeBrowser(); }, this.idleMs);
|
|
132
|
+
this.idleTimer.unref?.();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async call(method, ...args) {
|
|
136
|
+
const page = await this.ensurePage();
|
|
137
|
+
this.touch();
|
|
138
|
+
const result = await page.evaluate(async (name, callArgs) => {
|
|
139
|
+
const api = window.__tyts;
|
|
140
|
+
return api[name](...callArgs);
|
|
141
|
+
}, method, args);
|
|
142
|
+
if (!result.ok)
|
|
143
|
+
throw new EditorError(result.error.code, result.error.message);
|
|
144
|
+
return result.value;
|
|
145
|
+
}
|
|
146
|
+
loadImage(dataUrl) {
|
|
147
|
+
return this.call('loadImage', dataUrl);
|
|
148
|
+
}
|
|
149
|
+
loadDocument(document) {
|
|
150
|
+
return this.call('loadDocument', document);
|
|
151
|
+
}
|
|
152
|
+
getDocument() {
|
|
153
|
+
return this.call('getDocument');
|
|
154
|
+
}
|
|
155
|
+
export(format, scale) {
|
|
156
|
+
return this.call('export', format, scale);
|
|
157
|
+
}
|
|
158
|
+
reset() {
|
|
159
|
+
return this.call('reset');
|
|
160
|
+
}
|
|
161
|
+
imageInfo(dataUrl) {
|
|
162
|
+
return this.call('imageInfo', dataUrl);
|
|
163
|
+
}
|
|
164
|
+
async closeBrowser() {
|
|
165
|
+
if (this.idleTimer)
|
|
166
|
+
clearTimeout(this.idleTimer);
|
|
167
|
+
this.idleTimer = null;
|
|
168
|
+
const browser = this.browser;
|
|
169
|
+
this.browser = null;
|
|
170
|
+
this.page = null;
|
|
171
|
+
if (browser) {
|
|
172
|
+
this.log('closing browser (idle)');
|
|
173
|
+
await browser.close().catch(() => { });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async close() {
|
|
177
|
+
await this.closeBrowser();
|
|
178
|
+
const server = this.server;
|
|
179
|
+
this.server = null;
|
|
180
|
+
if (server) {
|
|
181
|
+
server.closeAllConnections();
|
|
182
|
+
await new Promise((done) => server.close(() => done()));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|