MCPcopy
hub / github.com/1weiho/open-slide / registerEditRoutes

Function registerEditRoutes

packages/core/src/vite/routes/edit.ts:24–124  ·  view source on GitHub ↗
(server: ViteDevServer, ctx: ApiContext)

Source from the content-addressed store, hash-verified

22};
23
24export function registerEditRoutes(server: ViteDevServer, ctx: ApiContext): void {
25 server.middlewares.use('/__edit', async (req, res, next) => {
26 const url = new URL(req.url ?? '/', 'http://local');
27 const method = req.method ?? 'GET';
28 if (method !== 'POST') return next();
29 const requestCheck = validateMutationRequest(req, { requireJsonBody: true });
30 if (!requestCheck.ok) return json(res, requestCheck.status, { error: requestCheck.error });
31
32 try {
33 if (url.pathname === '/') {
34 const body = (await readBody(req)) as EditBody;
35 const slideId = body.slideId ?? '';
36 const file = resolveSlideEntryPath(ctx, slideId);
37 if (!file) return json(res, 400, { error: 'invalid slideId' });
38 if (!body.line || body.line < 1) return json(res, 400, { error: 'invalid line' });
39 if (!Array.isArray(body.ops)) return json(res, 400, { error: 'missing ops' });
40
41 let source: string;
42 try {
43 source = await fs.readFile(file, 'utf8');
44 } catch {
45 return json(res, 404, { error: 'slide not found' });
46 }
47
48 const result = applyEdit(source, body.line, body.column ?? 0, body.ops);
49 if (!result.ok) return json(res, result.status, { error: result.error });
50 const changed = result.source !== source;
51 if (changed) await fs.writeFile(file, result.source, 'utf8');
52 return json(res, 200, { ok: true, changed });
53 }
54
55 if (url.pathname === '/revert-asset') {
56 const body = (await readBody(req)) as { slideId?: string; assetPath?: string };
57 const slideId = body.slideId ?? '';
58 const assetPath = body.assetPath;
59 const file = resolveSlideEntryPath(ctx, slideId);
60 if (!file) return json(res, 400, { error: 'invalid slideId' });
61 if (typeof assetPath !== 'string' || !assetPath) {
62 return json(res, 400, { error: 'missing assetPath' });
63 }
64 if (!assetPath.startsWith('./assets/') && !assetPath.startsWith('@assets/')) {
65 return json(res, 400, { error: 'asset path must start with ./assets/ or @assets/' });
66 }
67
68 let source: string;
69 try {
70 source = await fs.readFile(file, 'utf8');
71 } catch {
72 return json(res, 404, { error: 'slide not found' });
73 }
74
75 const result = applyRevertAsset(source, assetPath);
76 if (!result.ok) return json(res, result.status, { error: result.error });
77 const changed = result.source !== source;
78 if (changed) await fs.writeFile(file, result.source, 'utf8');
79 return json(res, 200, { ok: true, changed });
80 }
81

Callers 1

configureServerFunction · 0.90

Calls 6

validateMutationRequestFunction · 0.90
jsonFunction · 0.90
readBodyFunction · 0.90
resolveSlideEntryPathFunction · 0.90
applyEditFunction · 0.90
applyRevertAssetFunction · 0.90

Tested by

no test coverage detected