#Problem with Astro Action when using astrojs/node adapter

1 messages · Page 1 of 1 (latest)

nimble hawk
#

Hi everyone,

I am facing a problem when I deploy my website. I am using an Astro action to send an email in hybrid output using the @astrojs/node adapter in standalone mode.

Everything works locally: the email is sent and I am redirected on success.

But when I test my website in production I get this error in the log:

13:34:16 [ERROR] [@astrojs/node] Could not render /_actions/mail.send
TypeError: Failed to parse URL from https, https://website.tld:443/_actions/mail.send
...
  [cause]: TypeError: Invalid URL
      at new URL (node:internal/url:797:36)
      at new Request (node:internal/deps/undici/undici:9269:25)
      at NodeApp.createRequest (file:///home/user/website.tld/dist/server/chunks/_@astrojs-ssr-adapter_D3rHPTjV.mjs:1098:21)
...
      at SendStream.emit (node:events:519:28)
      at SendStream.error (/home/user/website.tld/node_modules/send/index.js:270:17)
      at SendStream.onStatError (/home/user/website.tld/node_modules/send/index.js:417:12)
      at onstat (/home/user/website.tld/node_modules/send/index.js:721:26) {
    code: 'ERR_INVALID_URL',
    input: 'https, https://website.tld:443/_actions/mail.send'
  }
}

From what I understand in this log is that the req.url is https, https://website.tld:443/_actions/mail.send which breaks the URL constructor in the adapter code

I do not see from where is the protocol preprended.

The app is running using a node application setup based on phusion passenger on my host service provider.

Node version is 20.17.0

I searched already and tried many things, but I am out of ideas now...

Thanks in anticipate for any help or hints !
Have a nice day

GitHub

Home for Astro's core maintained adapters. Contribute to withastro/adapters development by creating an account on GitHub.

echo pike
#

Can I see your actions file?

nimble hawk
#

Oh Thanks!

Sure

// src/actions/mail.ts
import { ActionError, defineAction } from "astro:actions";
import { z } from "astro:schema";
import { ConfigurationError } from "@libs/errors/ConfigurationError";
import { sendMail } from "@libs/mail";

export const mail = {
  send: defineAction({
    accept: "form",
    input: z.object({
      from: z.string().email(),
      message: z.string(),
      subject: z.string(),
    }),
    handler: async (input) => {
      try {
        const response = await sendMail(input);
        return { code: 250, message: response.response };
      } catch (err) {
        // This is the specific error sent by the `sendMail` util in case the configuration to send the email is invalid
        if (err instanceof ConfigurationError) {
          throw new ActionError({
            code: "INTERNAL_SERVER_ERROR",
            message: "could not send the email",
          });
        }
        throw err;
      }
    },
  }),
};

And this is how it is called from a page

<script>
 import { actions, isInputError } from "astro:actions";
// Performing frontend validation

      const formData = new FormData(form);
      const { error } = await actions.mail.send(formData);

// Do error handling and navigate on success
</script>
#

But I think the error I have occurs before that. It could also not be related to Astro but rather to my hosting and/or Passenger...

echo pike
#

You need to export a const server variable from an index.ts file in src/actions

#

Let me know if that info clarifies things ❤️

nimble hawk
#

Ah yes sorry, this is my actions/index.ts
file

import { mail } from "./mail";

export const server = {
  mail,
};

I forgot to mention it.

echo pike
#

No worries! Just wanted to cover all bases! let me take a closer look here at that mail action, one minute

#

I think this line might be the culprit return { code: 250, message: response.response };

#

Whoops

#

Maybe returning an object constructed from the Response constructor would work

return new Response(await response.json())

nimble hawk
#

My assumption was that the action was never reached and my problem had somehow something to do with the adaptor.

Thanks a lot for the hint ! I will try and let you know.

echo pike
#

It's tough to say, I agree the error handling could be improved a bit

I usually test by logging my input right above the action call in the script to make sure it's the correct shape

And immediatly logging the input as the first step in the action to see how it looks

echo pike
nimble hawk
#

This is the sendMail function code.

import { createTransport } from "nodemailer";
import { ConfigurationError } from "@libs/errors/ConfigurationError";

type SendMailOptions = {
  from: string;
  message: string;
  subject: string;
};

export const sendMail = async ({ from, message, subject }: SendMailOptions) => {
  const { EMAIL_ACCOUNT, EMAIL_HOST, EMAIL_PASSWORD, EMAIL_PORT } = import.meta
    .env;

  if (!EMAIL_ACCOUNT || !EMAIL_HOST || !EMAIL_PASSWORD || !EMAIL_PORT) {
    throw new ConfigurationError("Missing Email transporter configuration");
  }

  const transporter = createTransport({
    host: EMAIL_HOST,
    port: EMAIL_PORT,
    secure: true,
    auth: { user: EMAIL_ACCOUNT, pass: EMAIL_PASSWORD },
  });

  const email = {
    from,
    to: EMAIL_ACCOUNT,
    subject,
    text: message,
    html: message,
  };

  return await transporter.sendMail(email);
};

Just using nodemailer. Again locally runnint astro dev or astro preview it works.

echo pike
#

Got it

#

"Form"

nimble hawk
#

I don't think I have a typo here: from is indeed a field from the Form which is sent to the action using

const formData = new FormData(form);
const { error } = await actions.mail.send(formData);
echo pike
#

Ah just kidding

nimble hawk
#

Thanks for your help !

echo pike
#

from is who sent it

#

not form

#

Thought I had it lmao

#

I would say lets log out your formdata prior to it being sent to the action and see what it looks like 😛

echo pike
nimble hawk
#

I have to go... Back at it tomorrow ! Thanks a lot for your help ! Have a nice day 🙂

echo pike
nimble hawk
#

No odd questions ! I used Astro env variables mechanism I think and imported them from import.meta.env

echo pike
#

What about where you are hosting it?

For example on netlify I have to go into the site configuration and add the environmental variables here

nimble hawk
#

Unfortunately, none of the proposed approaches worked (returning directly the object works well apparently). But I made progress !

My intuition was correct and it is the parsing of the protocol which causes me problem but I think this was fixed four days ago: https://github.com/withastro/astro/commit/e96bcae535ef2f0661f539c1d49690c531df2d4e

I will upgrade and see. Huge thanks to the team !

GitHub
  • Fixed parsing of x-forwarded-* headers

  • changeset

  • remotePort

  • port fix

  • port fix

  • port fix

  • Update .changeset/slimy-buses-agree.md

Co-authored-by: Emanuele Stoppa &amp...