Conversation
|
@zhangweia is attempting to deploy a commit to the OpenCut OSS Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughDevelopment environment port updated from 3000 to 5555 across configuration, documentation, and Docker setup. New Super Agent API environment variable added. Next.js app pages refactored with Suspense boundaries and routing logic restructured to support search parameter preservation. Development startup scripts created. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User/Browser
participant Editor as Editor Page
participant API as Super Agent API
participant Storage as OpenCut Storage
User->>Editor: Visit /editor/[project_id]?token=X&material_ids=Y
Editor->>Editor: Parse URL search params
Editor->>Editor: Wait 1 second
Editor->>API: POST /gallery/batch-query<br/>(token, material_ids, tenant_id, user_id)
API-->>Editor: Return { result.data.items }
Editor->>Storage: TODO: Wire results to media storage
Editor->>User: Render editor with loaded materials
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Important Merge conflicts detected (Beta)
✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip Migrating from UI to YAML configuration.Use the |
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (3)
packages/auth/src/server.ts (1)
3-3: Useimport typefor type-only import.
RateLimitis only used as a type annotation (line 38). Per coding guidelines, useimport typefor types.Suggested fix
-import { betterAuth, RateLimit } from "better-auth"; +import { betterAuth } from "better-auth"; +import type { RateLimit } from "better-auth";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/auth/src/server.ts` at line 3, The import currently brings in RateLimit at runtime; change it to a type-only import so RateLimit isn't emitted in compiled code by replacing the runtime import of RateLimit with a type import (i.e., use "import type { RateLimit } from 'better-auth'") while keeping the runtime import for betterAuth unchanged—update the import statement that currently reads importing both betterAuth and RateLimit so that betterAuth remains a normal import and RateLimit is imported only as a type for its use in the type annotation (e.g., the annotation referencing RateLimit around line 38).apps/web/src/app/landing/page.tsx (1)
15-15: Unnecessaryasyncmodifier.The function doesn't use
await, so it can be a regular synchronous function.Suggested fix
-export default async function LandingPage() { +export default function LandingPage() {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/app/landing/page.tsx` at line 15, The exported component function LandingPage is marked async but contains no awaits; remove the async modifier so the declaration becomes a synchronous export (change "export default async function LandingPage()" to "export default function LandingPage()") and run a quick search for any code that might expect a Promise from LandingPage to ensure no callers rely on the function being async.apps/web/src/app/page.tsx (1)
16-18: Use a descriptive loop variable here.
vmakes the repeated-parameter branch harder to scan than it needs to be. A name likeparameterValuekeeps this aligned with the repo naming rule.As per coding guidelines,
**/*.{js,ts,tsx,jsx,py,java,cs,go,rb,php}: Never abbreviate variable and parameter names.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/app/page.tsx` around lines 16 - 18, The loop uses a non-descriptive variable name `v`; update the Array branch in the code that builds the query string (the for...of loop where `queryString.append(key, v)` occurs) to use a descriptive name such as `parameterValue` instead of `v` so it matches repo naming rules and improves readability; ensure you replace `v` with `parameterValue` in both the loop header and the `queryString.append` call (no other behavior changes).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/.env.example`:
- Line 36: The .env example is missing a trailing newline which causes
dotenv-linter to fail; open the apps web .env example and add a single newline
character after the LAST line containing NEXT_PUBLIC_ND_SUPER_AGENT_API_URL (the
env variable line) so the file ends with a trailing newline; save the file and
commit the change.
In `@apps/web/src/app/editor/`[project_id]/page.tsx:
- Around line 59-103: The page currently reads sensitive values (token, user_id,
tenant_id) from searchParams and logs/forwards them in the client-side fetch
(see token, userId, tenantId, materialIds, apiBaseUrl and the fetch to
`${apiBaseUrl}/gallery/batch-query` in page.tsx); move the exchange to a
server-side API route or use a first-party session: accept material_ids on the
client, call your new server endpoint which reads auth from secure server-side
storage (not from query), performs the POST to /gallery/batch-query, and returns
only non-sensitive results to the client; strip/remove the sensitive query
params before rendering the editor (do not expose token/user/tenant in URLs or
history) and remove all console.* usages per linting rules.
- Around line 106-122: The fetched assets are only logged and not added to the
app state; import and use the existing Zustand media/editor store (e.g.,
useMediaStore or the editor/media store in apps/web/src/stores) and, inside the
success branch where result.success && result.data && result.data.items,
transform result.data.items into the media store's expected shape (map id,
name/title, type, url/preview fields) and call the store's mutation (e.g.,
addMedia, addItems, addAssets) to persist them so they appear in the editor;
ensure this runs on the client-side context where useMediaStore is usable and
keep logging for success/failure around the store update.
In `@apps/web/src/app/editor/page.tsx`:
- Around line 6-39: The effect in EditorIndexContent calls the non-idempotent
createNewProject on every mount, which can run twice in React 18 Strict Mode;
protect it with a ref-based guard: create a local ref (e.g., hasStartedRef)
checked at the start of the useEffect (or inside createAndRedirect) to return
early if true, set hasStartedRef.current = true immediately before invoking
createNewProject, and leave the rest of the logic (building queryString,
router.replace on success/failure) unchanged; reference the functions/vars
createNewProject, createAndRedirect, router, and searchParams so you only add
the guard and not alter the redirect flow.
In `@apps/web/src/app/landing/page.tsx`:
- Around line 7-13: The page exports a hardcoded Chinese metadata object (export
const metadata: Metadata) which is inconsistent with the app’s English content;
update the title and description to English or wire them to your localization
system (i18n) instead of hardcoding Chinese—either replace the strings in
metadata (title/description) with their English equivalents or read localized
values (e.g., from a locale-aware config or translation function) and keep the
alternates canonical using SITE_URL/landing so metadata remains consistent with
the rest of the site.
In `@apps/web/src/app/projects/page.tsx`:
- Line 66: The page currently reads const searchParams = useSearchParams() but
only applies it to the "create-new" path; update all navigation/Link/href
constructions that target the editor (e.g. the code building
`/editor/${project.id}` for existing project cards and the create-new path
referenced around lines 97-103) to preserve the current query string by
appending the serialized searchParams when non-empty (e.g. if
searchParams.toString() is truthy, append `?${searchParams.toString()}` to the
href or include it in the router push). Ensure every place that navigates to
`/editor/${project.id}` or constructs the create-new editor URL uses the same
searchParams preservation logic so import tokens/material_ids are retained.
In `@apps/web/start.sh`:
- Around line 63-79: The script currently checks and kills processes (check_port
-> kill_port_processes) before verifying Bun exists; move the Bun availability
check to run before calling check_port so the script fails fast if Bun is
missing. Specifically, add a pre-check that verifies the bun binary (used by
"bun install" and "bun run dev") is available and exits with an error if not,
then proceed to call check_port and kill_port_processes only after that
validation; ensure messages reference bun when failing so the user knows why the
script exited.
In `@packages/auth/src/server.ts`:
- Line 47: Replace the hardcoded trustedOrigins array with the same env var used
for baseURL so they remain consistent: change the trustedOrigins reference
(symbol: trustedOrigins) to derive its value from
process.env.NEXT_PUBLIC_BETTER_AUTH_URL (the same value used for baseURL) and
ensure you normalize it to an origin string if necessary (remove trailing
slashes) before inserting into the array so trustedOrigins and baseURL stay in
sync.
In `@start.sh`:
- Around line 24-70: The kill_port_processes function currently unconditionally
sends TERM/KILL to any listener on $PORT which is unsafe; change it to only list
the occupying processes (use lsof output via PIDS and PROCESS_INFO) and exit
nonzero by default, and make destructive termination occur only when an explicit
force flag or env var is provided (e.g., check a FORCE_KILL or --force flag
before sending TERM/KILL); ensure the final existence check still uses
check_port and retains messaging, and apply the same change to the duplicate
helper in apps/web/start.sh so both scripts remain aligned.
---
Nitpick comments:
In `@apps/web/src/app/landing/page.tsx`:
- Line 15: The exported component function LandingPage is marked async but
contains no awaits; remove the async modifier so the declaration becomes a
synchronous export (change "export default async function LandingPage()" to
"export default function LandingPage()") and run a quick search for any code
that might expect a Promise from LandingPage to ensure no callers rely on the
function being async.
In `@apps/web/src/app/page.tsx`:
- Around line 16-18: The loop uses a non-descriptive variable name `v`; update
the Array branch in the code that builds the query string (the for...of loop
where `queryString.append(key, v)` occurs) to use a descriptive name such as
`parameterValue` instead of `v` so it matches repo naming rules and improves
readability; ensure you replace `v` with `parameterValue` in both the loop
header and the `queryString.append` call (no other behavior changes).
In `@packages/auth/src/server.ts`:
- Line 3: The import currently brings in RateLimit at runtime; change it to a
type-only import so RateLimit isn't emitted in compiled code by replacing the
runtime import of RateLimit with a type import (i.e., use "import type {
RateLimit } from 'better-auth'") while keeping the runtime import for betterAuth
unchanged—update the import statement that currently reads importing both
betterAuth and RateLimit so that betterAuth remains a normal import and
RateLimit is imported only as a type for its use in the type annotation (e.g.,
the annotation referencing RateLimit around line 38).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 29d6a101-bfd4-4dfb-a097-eee56e4797ca
📒 Files selected for processing (15)
CLAUDE.mdREADME.mdapps/web/.env.exampleapps/web/Dockerfileapps/web/package.jsonapps/web/src/app/editor/[project_id]/page.tsxapps/web/src/app/editor/page.tsxapps/web/src/app/landing/page.tsxapps/web/src/app/page.tsxapps/web/src/app/projects/page.tsxapps/web/src/components/header.tsxapps/web/start.shdocker-compose.yamlpackages/auth/src/server.tsstart.sh
| MODAL_TRANSCRIPTION_URL=https://your-username--opencut-transcription-transcribe-audio.modal.run | ||
|
|
||
| # ND Super Agent Integration | ||
| NEXT_PUBLIC_ND_SUPER_AGENT_API_URL=http://localhost:3001/api/base No newline at end of file |
There was a problem hiding this comment.
Add the trailing newline.
dotenv-linter will keep flagging this example file until it ends with a trailing newline.
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 36-36: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/.env.example` at line 36, The .env example is missing a trailing
newline which causes dotenv-linter to fail; open the apps web .env example and
add a single newline character after the LAST line containing
NEXT_PUBLIC_ND_SUPER_AGENT_API_URL (the env variable line) so the file ends with
a trailing newline; save the file and commit the change.
| const token = searchParams.get('token'); | ||
| const userId = searchParams.get('user_id'); | ||
| const tenantId = searchParams.get('tenant_id'); | ||
| const materialIds = searchParams.get('material_ids'); | ||
|
|
||
| // 从环境变量获取 API 基础 URL | ||
| const apiBaseUrl = process.env.NEXT_PUBLIC_ND_SUPER_AGENT_API_URL; | ||
|
|
||
| console.log('📋 外部参数检查:', { | ||
| hasToken: !!token, | ||
| hasUserId: !!userId, | ||
| hasTenantId: !!tenantId, | ||
| hasMaterialIds: !!materialIds, | ||
| hasApiBaseUrl: !!apiBaseUrl, | ||
| materialIds | ||
| }); | ||
|
|
||
|
|
||
| // 如果有外部参数,处理素材加载 | ||
| if (token && materialIds && apiBaseUrl) { | ||
| console.log('检测到外部参数,开始加载素材:', { | ||
| token: token.substring(0, 10) + '...', | ||
| userId, | ||
| tenantId, | ||
| materialIds, | ||
| apiBaseUrl: apiBaseUrl?.substring(0, 30) + '...' | ||
| }); | ||
|
|
||
| try { | ||
| // 解析素材ID列表 | ||
| const ids = materialIds.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id)); | ||
|
|
||
| if (ids.length > 0) { | ||
| console.log('🔗 调用素材接口:', { ids, apiUrl: `${apiBaseUrl}/gallery/batch-query` }); | ||
|
|
||
| // 调用 nd-super-agent 的素材接口 | ||
| const response = await fetch(`${apiBaseUrl}/gallery/batch-query`, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| 'Authorization': `Bearer ${token}`, | ||
| ...(tenantId && { 'X-Tenant-ID': tenantId }), | ||
| ...(userId && { 'X-User-ID': userId }) | ||
| }, | ||
| body: JSON.stringify({ ids }) |
There was a problem hiding this comment.
Keep auth context out of client-side query params and logs.
This effect reads token, user_id, and tenant_id from the URL, logs parts of that context, and then forwards it as request headers from the browser. That leaves credentials and tenant metadata in copied URLs, browser history, and any request logs that capture those URLs, and the new query-preservation redirects elsewhere in this PR keep replaying them through more routes. Move this exchange behind a server route or first-party session, then strip the sensitive params before rendering the editor.
As per coding guidelines, **/*.{ts,tsx,js,jsx}: Don't use console.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/app/editor/`[project_id]/page.tsx around lines 59 - 103, The
page currently reads sensitive values (token, user_id, tenant_id) from
searchParams and logs/forwards them in the client-side fetch (see token, userId,
tenantId, materialIds, apiBaseUrl and the fetch to
`${apiBaseUrl}/gallery/batch-query` in page.tsx); move the exchange to a
server-side API route or use a first-party session: accept material_ids on the
client, call your new server endpoint which reads auth from secure server-side
storage (not from query), performs the POST to /gallery/batch-query, and returns
only non-sensitive results to the client; strip/remove the sensitive query
params before rendering the editor (do not expose token/user/tenant in URLs or
history) and remove all console.* usages per linting rules.
| if (response.ok) { | ||
| const result = await response.json(); | ||
| console.log('✅ 素材加载成功:', { | ||
| 找到数量: result.data?.found_count || 0, | ||
| 请求数量: result.data?.requested_count || 0 | ||
| }); | ||
|
|
||
| if (result.success && result.data && result.data.items) { | ||
| console.log('📋 获取到素材:', result.data.items.map(item => ({ | ||
| id: item.id, | ||
| name: item.name || item.title, | ||
| type: item.type | ||
| }))); | ||
|
|
||
| // TODO: 将素材添加到 OpenCut 的媒体存储中 | ||
| // 可能需要调用 useMediaStore 或相关的存储管理 | ||
| } |
There was a problem hiding this comment.
The success path still drops the fetched assets.
After batch-query succeeds, the code only logs result.data.items and stops at a TODO, so none of the new env/query/API plumbing produces an editor-visible result. Please hand these items to the existing media/editor store before merging. If helpful, I can sketch that integration in a follow-up issue.
Based on learnings, utilize Zustand stores from apps/web/src/stores for state management.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/app/editor/`[project_id]/page.tsx around lines 106 - 122, The
fetched assets are only logged and not added to the app state; import and use
the existing Zustand media/editor store (e.g., useMediaStore or the editor/media
store in apps/web/src/stores) and, inside the success branch where
result.success && result.data && result.data.items, transform result.data.items
into the media store's expected shape (map id, name/title, type, url/preview
fields) and call the store's mutation (e.g., addMedia, addItems, addAssets) to
persist them so they appear in the editor; ensure this runs on the client-side
context where useMediaStore is usable and keep logging for success/failure
around the store update.
| import { Suspense, useEffect } from "react"; | ||
|
|
||
| function EditorIndexContent() { | ||
| const { createNewProject } = useProjectStore(); | ||
| const router = useRouter(); | ||
| const searchParams = useSearchParams(); | ||
|
|
||
| useEffect(() => { | ||
| const createAndRedirect = async () => { | ||
| try { | ||
| // 创建新项目 | ||
| const projectId = await createNewProject("新项目"); | ||
|
|
||
| // 保留查询参数 | ||
| const queryString = searchParams.toString(); | ||
| const redirectUrl = queryString | ||
| ? `/editor/${projectId}?${queryString}` | ||
| : `/editor/${projectId}`; | ||
|
|
||
| // 重定向到编辑器页面 | ||
| router.replace(redirectUrl); | ||
| } catch (error) { | ||
| console.error("创建项目失败:", error); | ||
| // 如果创建失败,重定向到项目列表页 | ||
| const queryString = searchParams.toString(); | ||
| const fallbackUrl = queryString | ||
| ? `/projects?${queryString}` | ||
| : "/projects"; | ||
| router.replace(fallbackUrl); | ||
| } | ||
| }; | ||
|
|
||
| createAndRedirect(); | ||
| }, [createNewProject, router, searchParams]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Locate the file and verify content
fd "page.tsx" apps/web/src/app/editor/ --type fRepository: OpenCut-app/OpenCut
Length of output: 141
🏁 Script executed:
# Search for createNewProject implementation
rg "createNewProject" --type ts --type tsx -A 5 -B 2Repository: OpenCut-app/OpenCut
Length of output: 90
🏁 Script executed:
# Find the project store file to understand createNewProject
fd "project.*store" --type ts --type tsxRepository: OpenCut-app/OpenCut
Length of output: 232
🏁 Script executed:
# Check for useRouter and useSearchParams imports in the file
rg "useRouter|useSearchParams" apps/web/src/app/editor/ --type tsx -B 2 -A 2Repository: OpenCut-app/OpenCut
Length of output: 90
🏁 Script executed:
# Read the page.tsx file
cat -n apps/web/src/app/editor/page.tsxRepository: OpenCut-app/OpenCut
Length of output: 2494
🏁 Script executed:
# Search for createNewProject across all files
rg "createNewProject" -A 5 -B 2Repository: OpenCut-app/OpenCut
Length of output: 5381
🏁 Script executed:
# Find project store
fd "project" -type f -name "*store*"Repository: OpenCut-app/OpenCut
Length of output: 233
🏁 Script executed:
# Read the project store file to see full createNewProject implementation
cat -n apps/web/src/stores/project-store.ts | head -200Repository: OpenCut-app/OpenCut
Length of output: 7468
🏁 Script executed:
# See more of the project-store
wc -l apps/web/src/stores/project-store.tsRepository: OpenCut-app/OpenCut
Length of output: 103
🏁 Script executed:
# Read lines 200-230 to see the rest of createNewProject
sed -n '200,230p' apps/web/src/stores/project-store.tsRepository: OpenCut-app/OpenCut
Length of output: 950
🏁 Script executed:
# Also check how other files use createNewProject with guards
rg -B 10 -A 10 "createAndRedirect|hasStarted"Repository: OpenCut-app/OpenCut
Length of output: 2792
🏁 Script executed:
# Verify if there are any other guards or mechanisms in related code
rg "useRef.*false|once.*true|completed" apps/web/src/app/editor/ -A 3Repository: OpenCut-app/OpenCut
Length of output: 325
🏁 Script executed:
# See how isInitializingRef is used in the [project_id]/page.tsx
rg -B 5 -A 15 "isInitializingRef" apps/web/src/app/editor/Repository: OpenCut-app/OpenCut
Length of output: 7788
Guard the mount effect to prevent duplicate project creation.
This route executes a non-idempotent write (createNewProject) on mount without any guard, causing React 18 strict mode or component remounts to create and persist multiple duplicate projects before the redirect completes. The issue is reproducible on first visit to /editor in development mode.
Fix using ref-based guard
-import { Suspense, useEffect } from "react";
+import { Suspense, useEffect, useRef } from "react";
function EditorIndexContent() {
const { createNewProject } = useProjectStore();
const router = useRouter();
const searchParams = useSearchParams();
+ const hasStartedCreationRef = useRef(false);
useEffect(() => {
+ if (hasStartedCreationRef.current) {
+ return;
+ }
+ hasStartedCreationRef.current = true;
+
const createAndRedirect = async () => {
try {
// 创建新项目
const projectId = await createNewProject("新项目");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/app/editor/page.tsx` around lines 6 - 39, The effect in
EditorIndexContent calls the non-idempotent createNewProject on every mount,
which can run twice in React 18 Strict Mode; protect it with a ref-based guard:
create a local ref (e.g., hasStartedRef) checked at the start of the useEffect
(or inside createAndRedirect) to return early if true, set hasStartedRef.current
= true immediately before invoking createNewProject, and leave the rest of the
logic (building queryString, router.replace on success/failure) unchanged;
reference the functions/vars createNewProject, createAndRedirect, router, and
searchParams so you only add the guard and not alter the redirect flow.
| export const metadata: Metadata = { | ||
| title: "OpenCut - 免费开源视频编辑器", | ||
| description: "一个免费、开源的网页、桌面和移动端视频编辑器。保护隐私,功能完整,无水印。", | ||
| alternates: { | ||
| canonical: `${SITE_URL}/landing`, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Hardcoded Chinese metadata may be inconsistent with the rest of the application.
The title and description are in Chinese while other parts of the application appear to use English. If this is intentional for a specific locale, consider using i18n/l10n patterns for consistency. Otherwise, update to English to match the rest of the site.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/app/landing/page.tsx` around lines 7 - 13, The page exports a
hardcoded Chinese metadata object (export const metadata: Metadata) which is
inconsistent with the app’s English content; update the title and description to
English or wire them to your localization system (i18n) instead of hardcoding
Chinese—either replace the strings in metadata (title/description) with their
English equivalents or read localized values (e.g., from a locale-aware config
or translation function) and keep the alternates canonical using
SITE_URL/landing so metadata remains consistent with the rest of the site.
| const [searchQuery, setSearchQuery] = useState(""); | ||
| const [sortOption, setSortOption] = useState("createdAt-desc"); | ||
| const router = useRouter(); | ||
| const searchParams = useSearchParams(); |
There was a problem hiding this comment.
Preserve the query string for existing-project navigation too.
This only carries searchParams through the create-new path. Line 586 still sends existing cards to /editor/${project.id} with no query string, so flows that land on /projects?token=...&material_ids=... lose the import context as soon as the user opens an existing project.
Also applies to: 97-103
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/app/projects/page.tsx` at line 66, The page currently reads
const searchParams = useSearchParams() but only applies it to the "create-new"
path; update all navigation/Link/href constructions that target the editor (e.g.
the code building `/editor/${project.id}` for existing project cards and the
create-new path referenced around lines 97-103) to preserve the current query
string by appending the serialized searchParams when non-empty (e.g. if
searchParams.toString() is truthy, append `?${searchParams.toString()}` to the
href or include it in the router push). Ensure every place that navigates to
`/editor/${project.id}` or constructs the create-new editor URL uses the same
searchParams preservation logic so import tokens/material_ids are retained.
| # 检查并处理端口占用 | ||
| if check_port; then | ||
| kill_port_processes | ||
| fi | ||
|
|
||
| echo "🔧 检查依赖..." | ||
| if [ ! -d "node_modules" ]; then | ||
| echo "📦 安装依赖..." | ||
| bun install | ||
| fi | ||
|
|
||
| echo "🎯 启动开发服务器..." | ||
| echo "🌐 应用将在 http://localhost:$PORT 启动" | ||
| echo "" | ||
|
|
||
| # 启动开发服务器 | ||
| exec bun run dev |
There was a problem hiding this comment.
Check for bun before freeing the port.
Right now the script can terminate the listener on 5555 and only then fail on bun install or bun run dev if Bun is missing. Move the Bun availability check above Line 63 so this fails fast before touching any existing process.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/start.sh` around lines 63 - 79, The script currently checks and
kills processes (check_port -> kill_port_processes) before verifying Bun exists;
move the Bun availability check to run before calling check_port so the script
fails fast if Bun is missing. Specifically, add a pre-check that verifies the
bun binary (used by "bun install" and "bun run dev") is available and exits with
an error if not, then proceed to call check_port and kill_port_processes only
after that validation; ensure messages reference bun when failing so the user
knows why the script exited.
| baseURL: NEXT_PUBLIC_BETTER_AUTH_URL, | ||
| appName: "OpenCut", | ||
| trustedOrigins: ["http://localhost:3000"], | ||
| trustedOrigins: ["http://localhost:5555"], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if there are multiple auth server configurations and their trustedOrigins setup
echo "=== Checking auth server configurations ==="
rg -n "trustedOrigins" --type ts -C 2
echo ""
echo "=== Checking how NEXT_PUBLIC_SITE_URL is used ==="
rg -n "NEXT_PUBLIC_SITE_URL" --type ts -C 1Repository: OpenCut-app/OpenCut
Length of output: 424
🏁 Script executed:
# Search for auth-related configurations in apps/web
find . -name "server.ts" -o -name "auth*.ts" | grep -E "(apps/web|auth)" | head -20Repository: OpenCut-app/OpenCut
Length of output: 92
🏁 Script executed:
# Check environment variable definitions
rg -n "NEXT_PUBLIC_BETTER_AUTH_URL|NEXT_PUBLIC_SITE_URL" --type ts --type js --type env -B 2 -A 2Repository: OpenCut-app/OpenCut
Length of output: 90
🏁 Script executed:
# Check if localhost:5555 appears anywhere else in the codebase
rg "localhost:5555" -C 3Repository: OpenCut-app/OpenCut
Length of output: 2538
🏁 Script executed:
# Examine the full context of packages/auth/src/server.ts around the config
sed -n '40,55p' packages/auth/src/server.tsRepository: OpenCut-app/OpenCut
Length of output: 299
🏁 Script executed:
# Check if there's any environment-specific logic or production configuration
rg "production|PRODUCTION|NODE_ENV" packages/auth/src/server.ts -A 3 -B 3Repository: OpenCut-app/OpenCut
Length of output: 45
🏁 Script executed:
# Search for any other trustedOrigins configuration or comments explaining the hardcoding
rg "trustedOrigins|trusted.*origin" -i --type ts -B 5 -A 5Repository: OpenCut-app/OpenCut
Length of output: 479
Hardcoded trustedOrigins should use environment variable for consistency.
The baseURL on line 45 uses NEXT_PUBLIC_BETTER_AUTH_URL, but trustedOrigins on line 47 is hardcoded to "http://localhost:5555". This creates an inconsistency—both should reference the same environment variable to ensure they stay in sync across environments.
Suggested fix
- trustedOrigins: ["http://localhost:5555"],
+ trustedOrigins: [NEXT_PUBLIC_BETTER_AUTH_URL],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| trustedOrigins: ["http://localhost:5555"], | |
| trustedOrigins: [NEXT_PUBLIC_BETTER_AUTH_URL], |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/auth/src/server.ts` at line 47, Replace the hardcoded trustedOrigins
array with the same env var used for baseURL so they remain consistent: change
the trustedOrigins reference (symbol: trustedOrigins) to derive its value from
process.env.NEXT_PUBLIC_BETTER_AUTH_URL (the same value used for baseURL) and
ensure you normalize it to an origin string if necessary (remove trailing
slashes) before inserting into the array so trustedOrigins and baseURL stay in
sync.
| kill_port_processes() { | ||
| echo "⚠️ 检测到端口 $PORT 被占用" | ||
|
|
||
| # 获取占用端口的进程ID | ||
| PIDS=$(lsof -Pi :$PORT -sTCP:LISTEN -t 2>/dev/null || true) | ||
|
|
||
| if [ -n "$PIDS" ]; then | ||
| echo "🔍 发现以下进程占用端口 $PORT:" | ||
| for PID in $PIDS; do | ||
| PROCESS_INFO=$(ps -p $PID -o pid,ppid,comm,args --no-headers 2>/dev/null || echo "$PID unknown unknown") | ||
| echo " PID: $PROCESS_INFO" | ||
| done | ||
|
|
||
| echo "🛑 正在停止占用端口的进程..." | ||
|
|
||
| # 尝试优雅地终止进程 | ||
| for PID in $PIDS; do | ||
| if kill -TERM $PID 2>/dev/null; then | ||
| echo " ✅ 已发送 TERM 信号给进程 $PID" | ||
| fi | ||
| done | ||
|
|
||
| # 等待进程优雅退出 | ||
| sleep 2 | ||
|
|
||
| # 检查是否还有进程占用端口 | ||
| REMAINING_PIDS=$(lsof -Pi :$PORT -sTCP:LISTEN -t 2>/dev/null || true) | ||
|
|
||
| if [ -n "$REMAINING_PIDS" ]; then | ||
| echo "⚡ 强制终止剩余进程..." | ||
| for PID in $REMAINING_PIDS; do | ||
| if kill -KILL $PID 2>/dev/null; then | ||
| echo " ✅ 已强制终止进程 $PID" | ||
| fi | ||
| done | ||
| sleep 1 | ||
| fi | ||
|
|
||
| # 最终检查 | ||
| if check_port; then | ||
| echo "❌ 无法释放端口 $PORT,请手动检查" | ||
| exit 1 | ||
| else | ||
| echo "✅ 端口 $PORT 已释放" | ||
| fi | ||
| fi | ||
| } |
There was a problem hiding this comment.
Don't automatically kill whatever owns port 5555.
This script sends TERM/KILL to any listener on that port, even if it's unrelated to OpenCut, which is risky on a shared dev machine. Safer defaults are to print the process and exit, prompt for confirmation, or gate the current behavior behind an explicit force flag. The same helper is duplicated in apps/web/start.sh, so please keep both scripts aligned.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@start.sh` around lines 24 - 70, The kill_port_processes function currently
unconditionally sends TERM/KILL to any listener on $PORT which is unsafe; change
it to only list the occupying processes (use lsof output via PIDS and
PROCESS_INFO) and exit nonzero by default, and make destructive termination
occur only when an explicit force flag or env var is provided (e.g., check a
FORCE_KILL or --force flag before sending TERM/KILL); ensure the final existence
check still uses check_port and retains messaging, and apply the same change to
the duplicate helper in apps/web/start.sh so both scripts remain aligned.
We are not currently accepting PRs except for critical bugs.
If this is a bug fix:
If this is a feature:
This PR will be closed. Please open an issue to discuss first.
Summary by CodeRabbit
New Features
Chores