Repository: withastro/astro
File: packages/astro/src/actions/runtime/virtual/server.ts (TypeScript)

Code before:
	deserializeActionResult: typeof deserializeActionResult;
};

/**
 * Access information about Action requests from middleware.
 */
export function getActionContext(context: APIContext): ActionMiddlewareContext {
	const callerInfo = getCallerInfo(context);

	// Prevents action results from being handled on a rewrite.
	// Also prevents our *own* fallback middleware from running
	// if the user's middleware has already handled the result.
	const actionResultAlreadySet = Boolean((context.locals as Locals)._actionPayload);

	let action: ActionMiddlewareContext['action'] = undefined;

	if (callerInfo && context.request.method === 'POST' && !actionResultAlreadySet) {
		action = {
			calledFrom: callerInfo.from,
			name: callerInfo.name,
			handler: async () => {
				const pipeline: Pipeline = Reflect.get(context, apiContextRoutesSymbol);

				const baseAction = await getAction(
					pipeline.manifest.trailingSlash === 'always' ? callerInfo.name.replace(/\/$/, '') : callerInfo.name,
				);
				// const baseAction = await getAction(callerInfo.name);
				let input;
				try {
					input = await parseRequestBody(context.request);
				} catch (e) {
					if (e instanceof TypeError) {
						return { data: undefined, error: new ActionError({ code: 'UNSUPPORTED_MEDIA_TYPE' }) };
					}
					throw e;
				}
				const {
					props: _props,
					getActionResult: _getActionResult,
					callAction: _callAction,
					redirect: _redirect,
					...actionAPIContext
				} = context;
				Reflect.set(actionAPIContext, ACTION_API_CONTEXT_SYMBOL, true);
				const handler = baseAction.bind(actionAPIContext satisfies ActionAPIContext);
				return handler(input);
			},
		};
	}

	function setActionResult(actionName: string, actionResult: SerializedActionResult) {

Review comment (suggestion):
We have three utilities for manage the trailing slash, you should use them. Here's an example from the source code:

https://github.com/withastro/astro/blob/72c1d5d531d1fb59e29707986405a6aa7f9ca835/packages/astro/src/core/routing/rewrite.ts#L48-L50


Code after:
	 * Deserialize an action result to access data and error objects.
	 */
	deserializeActionResult: typeof deserializeActionResult;
};

/**
 * Access information about Action requests from middleware.
 */
export function getActionContext(context: APIContext): ActionMiddlewareContext {
	const callerInfo = getCallerInfo(context);

	// Prevents action results from being handled on a rewrite.
	// Also prevents our *own* fallback middleware from running
	// if the user's middleware has already handled the result.
	const actionResultAlreadySet = Boolean((context.locals as Locals)._actionPayload);

	let action: ActionMiddlewareContext['action'] = undefined;

	if (callerInfo && context.request.method === 'POST' && !actionResultAlreadySet) {
		action = {
			calledFrom: callerInfo.from,
			name: callerInfo.name,
			handler: async () => {
				const pipeline: Pipeline = Reflect.get(context, apiContextRoutesSymbol);
				const callerInfoName = shouldAppendForwardSlash(
					pipeline.manifest.trailingSlash,
					pipeline.manifest.buildFormat,
				)
					? removeTrailingForwardSlash(callerInfo.name)
					: callerInfo.name;

				const baseAction = await getAction(callerInfoName);
				let input;
				try {
					input = await parseRequestBody(context.request);
				} catch (e) {
					if (e instanceof TypeError) {
						return { data: undefined, error: new ActionError({ code: 'UNSUPPORTED_MEDIA_TYPE' }) };
					}
					throw e;
				}
				const {
					props: _props,
					getActionResult: _getActionResult,
					callAction: _callAction,
					redirect: _redirect,
					...actionAPIContext
				} = context;
				Reflect.set(actionAPIContext, ACTION_API_CONTEXT_SYMBOL, true);
				const handler = baseAction.bind(actionAPIContext satisfies ActionAPIContext);
				return handler(input);