Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/deploy-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
packages: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Inject Environment variables
run: |
Expand Down Expand Up @@ -49,7 +49,7 @@ jobs:
mv ${{ env.ARTIFACT_PATH }} ./docker-compose.yml ./start.sh ./build

- name: Transport Image
uses: appleboy/scp-action@v0.1.7
uses: appleboy/scp-action@v1
with:
source: ./build/*.*
target: /tmp/${{ env.BOX_NAME }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/init-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
contents: write
actions: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: transform Repository variables to lower case
run: |
Expand All @@ -30,6 +30,6 @@ jobs:
${{ env.REPOSITORY_OWNER }} ${{ env.REPOSITORY_NAME }}
git checkout -- .github/workflows/init-template.yml

- uses: stefanzweifel/git-auto-commit-action@v5
- uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: '[fix] replace Repository Name'
90 changes: 55 additions & 35 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,68 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}

- uses: actions/setup-node@v6
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}
with:
node-version: 24

- name: Deploy to Vercel
id: vercel-deployment
uses: amondnet/vercel-action@v25
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
working-directory: ./
vercel-args: ${{ github.ref == 'refs/heads/main' && ' --prod' || '' }}
shell: bash
run: |
set -euo pipefail

npm install vercel -g

if [[ "$GITHUB_REF" == 'refs/heads/main' ]]; then
DeployOutput=$(vercel -t "$VERCEL_TOKEN" --prod)
else
DeployOutput=$(vercel -t "$VERCEL_TOKEN")
fi
Comment on lines +28 to +37

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Vercel deploy step checks for VERCEL_ORG_ID/VERCEL_PROJECT_ID, but the script never uses them (and there is no .vercel/ project linkage in the repo). In CI, vercel commonly prompts to link/select a project unless --yes/--confirm and project/scope options are provided, which can hang the job. Please pass the org/project explicitly (or commit a .vercel/project.json), and add non-interactive flags so the deployment is deterministic.

Copilot uses AI. Check for mistakes.
echo "$DeployOutput"

ParsedURL=$(echo "$DeployOutput" | grep -Eo 'https://[^[:space:]]*\.vercel\.app' | tail -n 1)

if [[ -z "$ParsedURL" ]]; then
echo "Failed to parse Vercel URL from deploy output"
exit 1
fi
vercel inspect "$ParsedURL" -t "$VERCEL_TOKEN" -F json > vercel-inspect.json

InspectURL=$(jq -r '.url // empty' vercel-inspect.json)

if [[ -z "$InspectURL" ]]; then
echo "Failed to parse inspect url from vercel-inspect.json"
exit 1
fi
if [[ "$InspectURL" != http* ]]; then
InspectURL="https://$InspectURL"
fi
echo "preview-url=$InspectURL" >> "$GITHUB_OUTPUT"

- name: Lark notification
uses: foxundermoon/feishu-action@v2
uses: Open-Source-Bazaar/feishu-action@v3
with:
url: ${{ secrets.LARK_CHATBOT_HOOK_URL }}
msg_type: post
msg_type: interactive
content: |
post:
en_us:
title: "Vercel Preview Environment"
content:
- - tag: text
text: "Git Repository: "
- tag: a
text: ${{ github.server_url }}/${{ github.repository }}
href: ${{ github.server_url }}/${{ github.repository }}
- - tag: text
text: "Code Branch: "
- tag: a
text: ${{ github.ref }}
href: ${{ github.server_url }}/${{ github.repository }}/tree/${{ github.ref_name }}
- - tag: text
text: "Commit Author: "
- tag: a
text: ${{ github.actor }}
href: ${{ github.server_url }}/${{ github.actor }}
- - tag: text
text: "Preview Link: "
- tag: a
text: ${{ steps.vercel-deployment.outputs.preview-url }}
href: ${{ steps.vercel-deployment.outputs.preview-url }}
schema: "2.0"
config:
wide_screen_mode: true
header:
title:
tag: plain_text
content: Vercel deployment
template: blue
body:
elements:
- tag: markdown
content: |
- **Git Repository**: [${{ github.server_url }}/${{ github.repository }}](${{ github.server_url }}/${{ github.repository }})
- **Code Branch**: [${{ github.ref }}](${{ github.server_url }}/${{ github.repository }}/tree/${{ github.ref_name }})
- **Commit Author**: [${{ github.actor }}](${{ github.server_url }}/${{ github.actor }})
- **Preview Link**: [${{ steps.vercel-deployment.outputs.preview-url }}](${{ steps.vercel-deployment.outputs.preview-url }})
3 changes: 1 addition & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@
"redhat.vscode-yaml",
"clinyong.vscode-css-modules",
"akamud.vscode-caniuse",
"visualstudioexptteam.intellicode-api-usage-examples",
"pflannery.vscode-versionlens",
"christian-kohler.npm-intellisense",
"esbenp.prettier-vscode",
"rangav.vscode-thunder-client",
"eamodio.gitlens",
"github.vscode-pull-request-github",
"github.vscode-github-actions",
"GitHub.copilot"
"GitHub.copilot-chat"
]
}
76 changes: 38 additions & 38 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"dependencies": {
"@editorjs/code": "^2.9.4",
"@editorjs/editorjs": "^2.31.0",
"@editorjs/editorjs": "^2.31.5",
"@editorjs/header": "^2.8.8",
"@editorjs/image": "^2.10.3",
"@editorjs/link": "^2.6.2",
Expand All @@ -17,79 +17,79 @@
"@editorjs/quote": "^2.7.6",
"@mdx-js/loader": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@next/mdx": "^16.1.1",
"@sentry/nextjs": "^10.32.1",
"copy-webpack-plugin": "^13.0.1",
"core-js": "^3.47.0",
"@next/mdx": "^16.2.2",
"@sentry/nextjs": "^10.47.0",
"copy-webpack-plugin": "^14.0.0",
"core-js": "^3.49.0",
"editorjs-html": "^4.0.5",
"file-type": "^21.2.0",
"file-type": "^22.0.0",
"formidable": "^3.5.4",
"idea-react": "^2.0.0-rc.13",
"jsonwebtoken": "^9.0.3",
"koa": "^3.1.1",
"koa": "^3.2.0",
"koa-jwt": "^4.0.4",
"koajax": "^3.1.2",
"less": "^4.5.1",
"less-loader": "^12.3.0",
"lodash": "^4.17.21",
"marked": "^17.0.1",
"koajax": "^3.3.0",
"less": "^4.6.4",
"less-loader": "^12.3.2",
"lodash": "^4.18.1",
"marked": "^17.0.6",
"mime": "^4.1.0",
"mobx": "^6.15.0",
"mobx-github": "^0.6.2",
"mobx-i18n": "^0.7.2",
"mobx-lark": "^2.6.0",
"mobx-lark": "^2.8.1",
"mobx-react": "^9.2.1",
"mobx-react-helper": "^0.5.1",
"mobx-restful": "^2.1.4",
"mobx-restful-table": "^2.6.3",
"next": "^16.1.1",
"next": "^16.2.2",
"next-pwa": "~5.6.0",
"next-ssr-middleware": "^1.1.0",
"next-with-less": "^3.0.1",
"prismjs": "^1.30.0",
"react": "^19.2.3",
"react": "^19.2.4",
"react-bootstrap": "^2.10.10",
"react-bootstrap-editor": "^2.1.1",
"react-dom": "^19.2.3",
"react-dom": "^19.2.4",
"react-editor-js": "^2.1.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",
"remark-mdx-frontmatter": "^5.2.0",
"undici": "^7.16.0",
"web-utility": "^4.6.4",
"webpack": "^5.104.1",
"yaml": "^2.8.2"
"undici": "^8.0.2",
"web-utility": "^4.6.5",
"webpack": "^5.105.4",
"yaml": "^2.8.3"
},
"devDependencies": {
"@babel/plugin-proposal-decorators": "^7.28.0",
"@babel/plugin-transform-typescript": "^7.28.5",
"@babel/plugin-proposal-decorators": "^7.29.0",
"@babel/plugin-transform-typescript": "^7.28.6",
"@babel/preset-react": "^7.28.5",
"@cspell/eslint-plugin": "^9.4.0",
"@eslint/js": "^9.39.2",
"@next/eslint-plugin-next": "^16.1.1",
"@cspell/eslint-plugin": "^10.0.0",
"@eslint/js": "^10.0.1",
"@next/eslint-plugin-next": "^16.2.2",
"@softonus/prettier-plugin-duplicate-remover": "^1.1.2",
"@stylistic/eslint-plugin": "^5.6.1",
"@stylistic/eslint-plugin": "^5.10.0",
"@types/eslint-config-prettier": "^6.11.3",
"@types/formidable": "^3.4.6",
"@types/formidable": "^3.5.0",
"@types/jsonwebtoken": "^9.0.10",
"@types/koa": "^3.0.1",
"@types/lodash": "^4.17.21",
"@types/koa": "^3.0.2",
"@types/lodash": "^4.17.24",
"@types/next-pwa": "^5.6.9",
"@types/node": "^22.19.3",
"@types/react": "^19.2.7",
"eslint": "^9.39.2",
"eslint-config-next": "^16.1.1",
"@types/node": "^24.12.2",
"@types/react": "^19.2.14",
"eslint": "^10.2.0",
"eslint-config-next": "^16.2.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-simple-import-sort": "^12.1.1",
"globals": "^16.5.0",
"globals": "^17.4.0",
"husky": "^9.1.7",
"jiti": "^2.6.1",
"lint-staged": "^16.2.7",
"prettier": "^3.7.4",
"prettier-plugin-css-order": "^2.1.2",
"lint-staged": "^16.4.0",
"prettier": "^3.8.1",
"prettier-plugin-css-order": "^2.2.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.50.1"
"typescript-eslint": "^8.58.0"
},
"resolutions": {
"next": "$next"
Expand Down
52 changes: 3 additions & 49 deletions pages/api/Lark/bitable/v1/[...slug].ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,6 @@
import { Context } from 'koa';
import { LarkPageData, TableRecord, TableRecordData } from 'mobx-lark';
import { DataObject } from 'mobx-restful';
import { createKoaRouter, withKoaRouter } from 'next-ssr-middleware';

import { safeAPI } from '../../../core';
import { proxyLark, proxyLarkAll } from '../../core';
import { withSafeKoa } from '../../../core';
import { proxyLarkAll } from '../../core';

export const config = { api: { bodyParser: false } };

const router = createKoaRouter(import.meta.url);

function filterData(fields: DataObject) {
for (const key of Object.keys(fields))
if (!/^\w+$/.test(key)) delete fields[key];
}

router.get(
'/apps/:app/tables/:table/records/:record',
safeAPI,
async (context: Context) => {
const { status, body } =
await proxyLark<TableRecordData<DataObject>>(context);

const { fields } = body!.data!.record;

filterData(fields);

context.status = status;
context.body = body;
},
);

router.get(
'/apps/:app/tables/:table/records',
safeAPI,
async (context: Context) => {
const { status, body } =
await proxyLark<LarkPageData<TableRecord<DataObject>>>(context);

const list = body!.data!.items || [];

for (const { fields } of list) filterData(fields);

context.status = status;
context.body = body;
},
);

router.all('/(.*)', safeAPI, proxyLarkAll);

export default withKoaRouter(router);
export default withSafeKoa(proxyLarkAll);
2 changes: 1 addition & 1 deletion pages/api/Lark/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const normalizeMarkdownArray = (list: TableCellText[]) =>
export const proxyLark = async <T extends LarkData>({
method,
url,
headers: { host, authorization, ...headers },
headers: { host, authorization, 'content-length': _, ...headers },

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The destructuring introduces a _ binding for content-length that is never used. With @typescript-eslint/no-unused-vars enabled, this will raise lint warnings. Consider renaming it to something matching an ignore pattern (e.g. _contentLength) or adjusting the rule options / destructuring approach to omit the header without creating an unused variable.

Suggested change
headers: { host, authorization, 'content-length': _, ...headers },
headers: { host, authorization, 'content-length': _contentLength, ...headers },

Copilot uses AI. Check for mistakes.
request,
}: Context) => {
await lark.getAccessToken();
Expand Down
33 changes: 27 additions & 6 deletions pages/api/Lark/document/copy/[...slug].ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Context } from 'koa';
import { LarkDocumentPathType } from 'mobx-lark';
import { createKoaRouter, withKoaRouter } from 'next-ssr-middleware';

import { safeAPI, verifyJWT } from '../../../core';
Expand All @@ -10,13 +11,33 @@ const router = createKoaRouter(import.meta.url);

router.post('/:type/:id', safeAPI, verifyJWT, async (context: Context) => {
const { type, id } = context.params,
{ name, parentToken } = Reflect.get(context.request, 'body');
{ name, parentToken, ownerType, ownerId } = Reflect.get(
context.request,
'body',
);

context.body = await lark.copyFile(
`${type as 'wiki'}/${id}`,
name,
parentToken,
);
const copiedFile =
type === 'wiki'
? await lark.copyFile(`${type as 'wiki'}/${id}`, name, parentToken)
: await lark.copyFile(
`${type as LarkDocumentPathType}/${id}`,
name,
parentToken,
);
Comment on lines +19 to +26

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type comes from the URL params but is only narrowed via TypeScript casts before being used to build the Lark path. This allows arbitrary/unsupported values to be forwarded to lark.copyFile(...), which can yield confusing upstream errors. Consider validating type at runtime against an explicit allow-list of supported document types and returning 400 for anything else.

Copilot uses AI. Check for mistakes.

const newId =
'token' in copiedFile ? copiedFile.token : copiedFile.node_token;

if (ownerType && ownerId)
try {
await lark.driveFileStore.transferOwner(type, newId, {
member_type: ownerType,
member_id: ownerId,
});
Comment on lines +31 to +36

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint now accepts ownerType/ownerId from the request body and performs transferOwner(...) using the app's credentials. With only verifyJWT in place, any authenticated user can potentially transfer ownership of newly copied files to arbitrary members. Please add an authorization check (e.g., restrict transfers to the caller, or require an admin role / server-side allow-list) and/or validate ownerType/ownerId against the JWT identity.

Copilot uses AI. Check for mistakes.
} catch (error) {
console.error(JSON.stringify(error, null, 2));
}
context.body = copiedFile;
Comment on lines +31 to +40

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transferOwner(...) failures are caught and only logged, but the API still returns the copied file as if the overall operation succeeded. This can lead to silent partial success and make client-side error handling impossible. Consider returning a non-2xx status (or including an explicit warning/result field) when ownership transfer fails.

Copilot uses AI. Check for mistakes.
});

export default withKoaRouter(router);
Loading
Loading