@@ -22,19 +22,8 @@ const DEFAULT_API_ALLOWED_HEADERS =
2222const WORKFLOW_EXECUTE_HEADERS =
2323 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, X-API-Key'
2424
25- /**
26- * Workspace-internal segments under /api/{chat,form}/* that must NOT
27- * receive the embed policy. They serve the workspace UI with session
28- * cookies and need the default credentialed policy.
29- */
3025const EMBED_RESERVED_SEGMENTS = new Set ( [ 'manage' , 'validate' ] )
3126
32- /**
33- * True for /api/{chat,form}/[identifier] and any deeper subroute
34- * (e.g. /otp, /sso). The identifier segment is explicitly checked
35- * against EMBED_RESERVED_SEGMENTS so workspace-internal routes fall
36- * through to the default credentialed policy.
37- */
3827function isEmbedPath ( pathname : string ) : boolean {
3928 const segments = pathname . split ( '/' )
4029 if ( segments . length < 4 ) return false
@@ -79,22 +68,12 @@ const CORS_RULES: readonly CorsRule[] = [
7968 } ) ,
8069 } ,
8170 {
82- // Embed endpoints: /api/chat/[identifier] and /api/form/[identifier]
83- // (plus their /otp and /sso subroutes). These run on customer domains
84- // and authenticate via the `chat_auth_<id>` / form auth cookie set by
85- // setDeploymentAuthCookie, so we must reflect the request origin AND
86- // allow credentials. Workspace-internal subpaths (`manage`, `validate`,
87- // and the bare collection routes) are excluded by isEmbedPath and
88- // continue to receive the default credentialed policy.
8971 match : ( p ) => isEmbedPath ( p ) ,
9072 policy : ( request ) => {
9173 const requestOrigin = request . headers . get ( 'origin' )
9274 return {
93- // Without an Origin header, fall back to '*' and drop credentials —
94- // the CORS spec rejects '*' paired with Allow-Credentials: true.
9575 origin : requestOrigin || '*' ,
9676 credentials : ! ! requestOrigin ,
97- // PUT is required for OTP verification on /[identifier]/otp.
9877 methods : 'GET, POST, PUT, OPTIONS' ,
9978 headers : 'Content-Type, X-Requested-With' ,
10079 }
@@ -111,10 +90,6 @@ const CORS_RULES: readonly CorsRule[] = [
11190 } ,
11291]
11392
114- /**
115- * Single source of truth for CORS on /api/* — next.config.ts headers are
116- * baked at build time and would freeze NEXT_PUBLIC_APP_URL into the image.
117- */
11893export function resolveApiCorsPolicy ( request : NextRequest ) : CorsPolicy {
11994 const { pathname } = request . nextUrl
12095 for ( const rule of CORS_RULES ) {
@@ -140,10 +115,6 @@ function applyCorsHeaders(response: NextResponse, policy: CorsPolicy): void {
140115 }
141116}
142117
143- /**
144- * Short-circuit preflight: Next's auto-OPTIONS for route handlers without
145- * an explicit OPTIONS export does not carry middleware headers.
146- */
147118function buildPreflightResponse ( policy : CorsPolicy ) : NextResponse {
148119 const response = new NextResponse ( null , { status : 204 } )
149120 applyCorsHeaders ( response , policy )
0 commit comments