Skip to content

Commit 4825d1a

Browse files
committed
[add] Markdown export & Document copy API of Lark documents
[add] JWT parser & verifier middlewares [optimize] update Upstream packages
1 parent 41801f8 commit 4825d1a

File tree

6 files changed

+348
-216
lines changed

6 files changed

+348
-216
lines changed

package.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,28 @@
1717
"@koa/router": "^15.1.1",
1818
"@mdx-js/loader": "^3.1.1",
1919
"@mdx-js/react": "^3.1.1",
20-
"@next/mdx": "^16.1.0",
20+
"@next/mdx": "^16.1.1",
2121
"core-js": "^3.47.0",
2222
"echarts-jsx": "^0.6.0",
23-
"file-type": "^21.1.1",
23+
"file-type": "^21.2.0",
2424
"idea-react": "^2.0.0-rc.13",
25+
"jsonwebtoken": "^9.0.3",
2526
"koa": "^3.1.1",
27+
"koa-jwt": "^4.0.4",
2628
"koajax": "^3.1.2",
2729
"license-filter": "^0.2.5",
2830
"marked": "^17.0.1",
2931
"mime": "^4.1.0",
3032
"mobx": "^6.15.0",
3133
"mobx-github": "^0.6.2",
3234
"mobx-i18n": "^0.7.2",
33-
"mobx-lark": "^2.5.0",
35+
"mobx-lark": "^2.6.0",
3436
"mobx-react": "^9.2.1",
3537
"mobx-react-helper": "^0.5.1",
3638
"mobx-restful": "^2.1.4",
3739
"mobx-restful-table": "^2.6.3",
3840
"mobx-strapi": "^0.8.1",
39-
"next": "^16.1.0",
41+
"next": "^16.1.1",
4042
"next-pwa": "^5.6.0",
4143
"next-ssr-middleware": "^1.1.0",
4244
"open-react-map": "^0.9.1",
@@ -56,18 +58,19 @@
5658
"@babel/preset-react": "^7.28.5",
5759
"@cspell/eslint-plugin": "^9.4.0",
5860
"@eslint/js": "^9.39.2",
59-
"@next/eslint-plugin-next": "^16.1.0",
61+
"@next/eslint-plugin-next": "^16.1.1",
6062
"@open-source-bazaar/china-ngo-database": "^0.6.0",
6163
"@softonus/prettier-plugin-duplicate-remover": "^1.1.2",
6264
"@stylistic/eslint-plugin": "^5.6.1",
6365
"@types/eslint-config-prettier": "^6.11.3",
66+
"@types/jsonwebtoken": "^9.0.10",
6467
"@types/koa": "^3.0.1",
6568
"@types/next-pwa": "^5.6.9",
6669
"@types/node": "^22.19.3",
6770
"@types/react": "^19.2.7",
6871
"@types/react-dom": "^19.2.3",
6972
"eslint": "^9.39.2",
70-
"eslint-config-next": "^16.1.0",
73+
"eslint-config-next": "^16.1.1",
7174
"eslint-config-prettier": "^10.1.8",
7275
"eslint-plugin-react": "^7.37.5",
7376
"eslint-plugin-simple-import-sort": "^12.1.1",
@@ -82,7 +85,7 @@
8285
"prettier-plugin-css-order": "^2.1.2",
8386
"sass": "^1.97.1",
8487
"typescript": "~5.9.3",
85-
"typescript-eslint": "^8.50.0"
88+
"typescript-eslint": "^8.50.1"
8689
},
8790
"resolutions": {
8891
"mobx-react-helper": "$mobx-react-helper",
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Context } from 'koa';
2+
import { createKoaRouter, withKoaRouter } from 'next-ssr-middleware';
3+
4+
import { safeAPI, verifyJWT } from '../../../core';
5+
import { lark } from '../../core';
6+
7+
export const config = { api: { bodyParser: false } };
8+
9+
const router = createKoaRouter(import.meta.url);
10+
11+
router.post('/:type/:id', safeAPI, verifyJWT, async (context: Context) => {
12+
const { type, id } = context.params,
13+
{ name, parentToken } = Reflect.get(context.request, 'body');
14+
15+
context.body = await lark.copyFile(`${type as 'wiki'}/${id}`, name, parentToken);
16+
});
17+
18+
export default withKoaRouter(router);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { createKoaRouter, withKoaRouter } from 'next-ssr-middleware';
2+
3+
import { safeAPI, verifyJWT } from '../../../core';
4+
import { lark } from '../../core';
5+
6+
const router = createKoaRouter(import.meta.url);
7+
8+
router.get('/:type/:id', safeAPI, verifyJWT, async context => {
9+
const { type, id } = context.params;
10+
11+
const markdown = await lark.downloadMarkdown(`${type}/${id}`);
12+
13+
context.set('Content-Type', 'text/markdown; charset=utf-8');
14+
context.body = markdown;
15+
});
16+
17+
export default withKoaRouter(router);

pages/api/Lark/file/[id]/[name].ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ const downloader: Middleware = async context => {
3030
if (!ok) {
3131
context.status = status;
3232

33-
return (context.body = await response.json());
33+
try {
34+
return (context.body = await response.json());
35+
} catch {
36+
return (context.body = await response.text());
37+
}
3438
}
35-
3639
const mime = headers.get('Content-Type'),
3740
[stream1, stream2] = body!.tee();
3841

@@ -44,9 +47,8 @@ const downloader: Middleware = async context => {
4447
context.set('Content-Disposition', headers.get('Content-Disposition') || '');
4548
context.set('Content-Length', headers.get('Content-Length') || '');
4649

47-
if (method === 'GET')
48-
// @ts-expect-error Web type compatibility
49-
context.body = Readable.fromWeb(stream2);
50+
// @ts-expect-error Web type compatibility
51+
context.body = method === 'GET' ? Readable.fromWeb(stream2) : '';
5052
};
5153

5254
router.head('/:id/:name', safeAPI, downloader).get('/:id/:name', safeAPI, downloader);

pages/api/core.ts

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,37 @@
11
import 'core-js/full/array/from-async';
22

3-
import { Context, Middleware } from 'koa';
3+
import { JsonWebTokenError, sign } from 'jsonwebtoken';
4+
import { Context, Middleware, ParameterizedContext } from 'koa';
5+
import JWT from 'koa-jwt';
46
import { HTTPError } from 'koajax';
57
import { Content } from 'mobx-github';
68
import { DataObject } from 'mobx-restful';
79
import { KoaOption, withKoa } from 'next-ssr-middleware';
8-
import Path from 'path';
910
import { ProxyAgent, setGlobalDispatcher } from 'undici';
10-
import YAML from 'yaml';
11+
import { parse } from 'yaml';
12+
13+
import { LarkAppMeta } from '../../models/configuration';
1114

1215
const { HTTP_PROXY } = process.env;
1316

1417
if (HTTP_PROXY) setGlobalDispatcher(new ProxyAgent(HTTP_PROXY));
1518

19+
export type JWTContext = ParameterizedContext<
20+
{ jwtOriginalError: JsonWebTokenError } | { user: DataObject }
21+
>;
22+
23+
export const parseJWT = JWT({
24+
secret: LarkAppMeta.secret,
25+
cookie: 'token',
26+
passthrough: true,
27+
});
28+
29+
export const verifyJWT = JWT({ secret: LarkAppMeta.secret, cookie: 'token' });
30+
31+
const RobotToken = sign({ id: 0, name: 'Robot' }, LarkAppMeta.secret);
32+
33+
console.table({ RobotToken });
34+
1635
export const safeAPI: Middleware<any, any> = async (context: Context, next) => {
1736
try {
1837
return await next();
@@ -64,7 +83,7 @@ export function splitFrontMatter(raw: string) {
6483
if (!frontMatter) return { markdown: raw };
6584

6685
try {
67-
const meta = YAML.parse(frontMatter) as DataObject;
86+
const meta = parse(frontMatter) as DataObject;
6887

6988
return { markdown, meta };
7089
} catch (error) {
@@ -80,34 +99,31 @@ export async function* pageListOf(path: string, prefix = 'pages'): AsyncGenerato
8099
const list = await readdir(prefix + path, { withFileTypes: true });
81100

82101
for (const node of list) {
83-
let { name, path } = node;
102+
let { name, parentPath } = node;
84103

85104
if (name.startsWith('.')) continue;
86105

87106
const isMDX = MDX_pattern.test(name);
88107

89-
({ name } = Path.parse(name));
90-
path = `${path}/${name}`.replace(new RegExp(`^${prefix}`), '');
108+
name = name.replace(MDX_pattern, '');
109+
const path = `${parentPath}/${name}`.replace(new RegExp(`^${prefix}`), '');
91110

92-
if (node.isFile()) {
111+
if (node.isFile() && isMDX) {
93112
const article: ArticleMeta = { name, path, subs: [] };
94113

95-
if (isMDX)
96-
try {
97-
const rawFile = await readFile(`${node.path}/${node.name}`, { encoding: 'utf-8' });
114+
const file = await readFile(`${parentPath}/${node.name}`, 'utf-8');
98115

99-
const { meta } = splitFrontMatter(rawFile);
116+
const { meta } = splitFrontMatter(file);
100117

101-
if (meta) article.meta = meta;
102-
} catch (error) {
103-
console.error(`Error reading front matter for ${node.path}/${node.name}:`, error);
104-
}
105-
yield article;
106-
} else if (node.isDirectory()) {
107-
const subs = await Array.fromAsync(pageListOf(path, prefix));
118+
if (meta) article.meta = meta;
108119

109-
if (subs[0]) yield { name, subs };
120+
yield article;
110121
}
122+
if (!node.isDirectory()) continue;
123+
124+
const subs = await Array.fromAsync(pageListOf(path, prefix));
125+
126+
if (subs[0]) yield { name, subs };
111127
}
112128
}
113129

0 commit comments

Comments
 (0)