@@ -5,7 +5,7 @@ import { render_page } from './page/index.js';
55import { render_response } from './page/render.js' ;
66import { respond_with_error } from './page/respond_with_error.js' ;
77import { is_form_content_type } from '../../utils/http.js' ;
8- import { handle_fatal_error , redirect_response } from './utils.js' ;
8+ import { handle_fatal_error , method_not_allowed , redirect_response } from './utils.js' ;
99import {
1010 decode_pathname ,
1111 decode_params ,
@@ -42,6 +42,10 @@ const default_filter = () => false;
4242/** @type {import('types').RequiredResolveOptions['preload'] } */
4343const default_preload = ( { type } ) => type === 'js' || type === 'css' ;
4444
45+ const page_methods = new Set ( [ 'GET' , 'HEAD' , 'POST' ] ) ;
46+
47+ const allowed_page_methods = new Set ( [ 'GET' , 'HEAD' , 'OPTIONS' ] ) ;
48+
4549/**
4650 * @param {Request } request
4751 * @param {import('types').SSROptions } options
@@ -343,7 +347,6 @@ export async function respond(request, options, manifest, state) {
343347 }
344348
345349 /**
346- *
347350 * @param {import('@sveltejs/kit').RequestEvent } event
348351 * @param {import('@sveltejs/kit').ResolveOptions } [opts]
349352 */
@@ -379,6 +382,8 @@ export async function respond(request, options, manifest, state) {
379382 }
380383
381384 if ( route ) {
385+ const method = /** @type {import('types').HttpMethod } */ ( event . request . method ) ;
386+
382387 /** @type {Response } */
383388 let response ;
384389
@@ -395,7 +400,32 @@ export async function respond(request, options, manifest, state) {
395400 } else if ( route . endpoint && ( ! route . page || is_endpoint_request ( event ) ) ) {
396401 response = await render_endpoint ( event , await route . endpoint ( ) , state ) ;
397402 } else if ( route . page ) {
398- response = await render_page ( event , route . page , options , manifest , state , resolve_opts ) ;
403+ if ( page_methods . has ( method ) ) {
404+ response = await render_page ( event , route . page , options , manifest , state , resolve_opts ) ;
405+ } else {
406+ const allowed_methods = new Set ( allowed_page_methods ) ;
407+ const node = await manifest . _ . nodes [ route . page . leaf ] ( ) ;
408+ if ( node ?. server ?. actions ) {
409+ allowed_methods . add ( 'POST' ) ;
410+ }
411+
412+ if ( method === 'OPTIONS' ) {
413+ // This will deny CORS preflight requests implicitly because we don't
414+ // add the required CORS headers to the response.
415+ response = new Response ( null , {
416+ status : 204 ,
417+ headers : {
418+ allow : Array . from ( allowed_methods . values ( ) ) . join ( ', ' )
419+ }
420+ } ) ;
421+ } else {
422+ const mod = [ ...allowed_methods ] . reduce ( ( acc , curr ) => {
423+ acc [ curr ] = true ;
424+ return acc ;
425+ } , /** @type {Record<string, any> } */ ( { } ) ) ;
426+ response = method_not_allowed ( mod , method ) ;
427+ }
428+ }
399429 } else {
400430 // a route will always have a page or an endpoint, but TypeScript
401431 // doesn't know that
0 commit comments