npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@uninterrupted/serverless-plugin-webform

v2.0.0

Published

Powerful tool that simplifies the creation and management of forms in serverless applications.

Readme

Description

With Serverless Plugin Webform, you can automate the setup of essential AWS resources, including:

  • DynamoDB: A database to store all the necessary information about form submissions and visitors.
  • SES (Simple Email Service): Enables the sending of confirmation emails to visitors and notification emails to form owners.
  • Lambda Functions: Handles form processing and integration with other AWS services, following best coding practices.

Additionally, as a user of this plugin, you have access to the following advanced features:

  • Google reCAPTCHA Integration: Configure Google reCAPTCHA to enhance form security by preventing spam submissions from bots.
  • Slack Integration: Connect your form to a Slack channel to receive real-time notifications about new messages.

Table of Contents

  1. Prerequisites
  2. Installation
  3. Usage
  4. Configuration
    1. CORS configuration
    2. Properties used in the form
    3. reCAPTCHA configuration
    4. DynamoDB configuration
    5. Lambda configuration
    6. Simple Email Service configuration
    7. Slack configuration
    8. Log level
  5. Content files
    1. Replacement tags
    2. Default values
  6. Error codes
  7. Future development
  8. Something about us

Prerequisites

To use this plugin, you need to have the following prerequisites installed and configured:

  • Node.js (version 16.0.0 or higher)
  • Serverless Framework (version 3.26.0 or higher)
  • AWS account with appropriate IAM permissions to create and manage the required AWS resources

Installation

  1. Install the Serverless Form Plugin by running the following command in your project's root directory:
npm install @uninterrupted/serverless-plugin-webform
yarn add @uninterrupted/serverless-plugin-webform
pnpm add @uninterrupted/serverless-plugin-webform
  1. Add @uninterrupted/serverless-plugin-webform to the plugins array in your serverless.yaml file.

  2. Configure your AWS credentials. Refer to the AWS documentation for more information.

  3. Add dist to your .gitignore since that directory will be contain bundled code of lambda.

Usage

Example payload

When submitting a form to the Lambda endpoint, you need to send a POST request with a JSON payload. Here's an example of the expected request body structure:

{
  "email": "[email protected]",
  "name": "John Doe",
  "message": "Hello, I'm interested in your services.",
  "phoneNumber": "+1234567890",
  "ccMe": true,
  "acceptPrivacyPolicy": true,
  "captchaToken": "03AGdBq27..."
}

Field descriptions:

  • email (required) - Visitor's email address (must be valid email format)
  • name (required) - Visitor's full name (max 80 characters)
  • message (required) - Visitor's message content (max 2048 characters)
  • phoneNumber (optional) - Visitor's phone number (max 15 characters)
  • ccMe (optional) - Boolean flag indicating if the visitor wants to receive a copy of their message
  • acceptPrivacyPolicy (required) - Must be true to accept the privacy policy
  • captchaToken (conditionally required) - Required if reCAPTCHA is configured in your plugin settings

Note: If you've configured custom property names (as described in Properties used in the form), use those custom names instead of the default ones shown above. For example, if you set email.name: "jqxkuhh", use "jqxkuhh" as the field name instead of "email".

Example with custom property names (honeypot technique)

{
  "jqxkuhh": "[email protected]",
  "wmhhgio": "John Doe",
  "xhqpdaf": "Hello, I'm interested in your services.",
  "idocynv": "+1234567890",
  "ccMe": true,
  "acceptPrivacyPolicy": true,
  "zkrmqpa": "03AGdBq27..."
}

In this example, the actual visitor data is sent using custom field names, while the standard field names remain empty as honeypot fields to catch bots.

Configuration

Configuration of the plugin is done using the plugin parameters, which you can specify under the pluginWebform field in the custom section of your serverless.yaml file.

custom:
  pluginWebform:
    # Specify your plugin configuration here: properties, captcha, dynamoDb, lambda, ses, slack

Important: To use environment variables from a .env file, you need to enable useDotenv: true in your serverless.yaml:

useDotenv: true

This allows you to reference environment variables using ${env:VARIABLE_NAME} syntax throughout your configuration.

CORS configuration

The plugin provides two levels of CORS configuration:

1. Lambda Response Headers

Configure the Access-Control-Allow-Origin header in Lambda responses:

allowOrigin: ${env:ALLOWED_ORIGIN} # optional, default value: "*"

2. API Gateway CORS Settings

You also need to configure CORS at the API Gateway level in your serverless.yaml:

provider:
  httpApi:
    cors:
      allowedOrigins:
        - ${env:ALLOWED_ORIGIN}

Properties used in the form

properties: # optional
  email:
    name: jqxkuhh # optional, default value: "email"
  name:
    name: wmhhgio # optional, default value: "name"
  phoneNumber:
    name: idocynv # optional, default value: "phoneNumber"
  message:
    name: xhqpdaf # optional, default value: "message"
  captchaToken:
    name: zkrmqpa # optional, default value: "captchaToken"
  • email - visitor's email
  • name - visitor's name
  • phoneNumber - visitor's phone number
  • message - visitor's message
  • captchaToken - reCAPTCHA token field name

Using custom property names allows developers to use honeypot technique. Read more about it here.

reCAPTCHA configuration

This plugin uses Google reCAPTCHA Enterprise for bot protection.

captcha: # optional
  projectId: ${env:CAPTCHA_PROJECT_ID} # required if using reCAPTCHA
  siteKey: ${env:CAPTCHA_SITE_KEY} # required if using reCAPTCHA
  clientEmail: ${env:CAPTCHA_CLIENT_EMAIL} # required if using reCAPTCHA
  privateKey: ${env:CAPTCHA_PRIVATE_KEY} # required if using reCAPTCHA
  action: form_submit # required if using reCAPTCHA
  threshold: 0.8 # optional, default value: 0.5

IMPORTANT: SENSITIVE VALUES (projectId, siteKey, clientEmail, privateKey) MUST BE LOADED USING ENVIRONMENT VARIABLES, NEVER PUT SENSITIVE DATA DIRECTLY IN YOUR CODE!!!

  • projectId - Your Google Cloud Project ID where reCAPTCHA Enterprise is configured
  • siteKey - The reCAPTCHA site key associated with your site/app
  • action - Action name corresponding to the token (must match the action used in your frontend grecaptcha.enterprise.execute() call)
  • threshold - Score threshold (0.0 to 1.0) determining when a request is treated as coming from a bot. Higher values are more restrictive (check the link)
  • clientEmail - Service account email for Google Cloud authentication
  • privateKey - Service account private key for Google Cloud authentication

To set up reCAPTCHA Enterprise:

  1. Create a Google Cloud Project
  2. Enable the reCAPTCHA Enterprise API
  3. Create a site key for your website and use it as siteKey
  4. Create a service account with reCAPTCHA Enterprise Agent role
  5. Download the service account key JSON file
  6. Extract the client_email (e.g., [email protected]) and private_key values (including -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- markers) from the JSON file and use them as clientEmail and privateKey in captcha config
  7. Configure the other properties like projectId, action, and optionally threshold in your serverless.yaml

Check the Google reCAPTCHA Enterprise documentation to learn more about setup and configuration.

DynamoDB configuration

dynamoDb: # optional
  visitorsTableName: contacts # optional, default value: "visitors"
  botVisitorsTableName: bot-contacts # optional, default value: "bot-visitors"
  • visitorsTableName - name of the table where all information about visitors will be stored
  • botVisitorsTableName - name of the table where all information about bot visitors will be stored

Lambda configuration

lambda: # optional
  name: myLambda # optional, default value: "createVisitor"
  memorySize: 512 # optional, default value: "1024"
  • name - main lambda's name
  • memorySize - lambda's memory size

Simple Email Service configuration

ses: #required
  sourceAddress: [email protected] # required
  notificationAddresses: # optional
    - [email protected]
    - [email protected]
  visitorNotification:
    subject: "New message" # optional, default value: "New message"
    text: ./templates/visitor-notification.txt # optional
    html: ./templates/visitor-notification.html # optional
  visitorConfirmation:
    subject: Hello {{ name }}! # optional, default value: "Hello {{ name }}!"
    text: ./templates/visitor-confirmation.txt # optional
    html: ./templates/visitor-confirmation.html # optional
  visitorConfirmationWithMessage:
    subject: Hello {{ name }}! # optional, default value: "Hello {{ name }}!"
    text: ./templates/visitor-confirmation-with-message.txt # optional
    html: ./templates/visitor-confirmation-with-message.html # optional
  • sourceAddress - email address from which emails will be sent. Remember to confirm the email address identity in AWS.
  • notificationAddresses - list of addresses where notifications will be sent. If no values are provided, form owner notifications will be disabled.
  • visitorNotification - template of email message which will be sent to the form owner
    • subject - subject of the visitor notification email
    • text - path to the visitor notification text content file
    • html - path to the visitor notification HTML content file
  • visitorConfirmation - template of email message which is always send to the form user
    • subject - subject of the visitor confirmation email
    • text - path to the visitor confirmation text content file
    • html - path to the visitor confirmation HTML content file
  • visitorConfirmationWithMessage - template of email message which will be sent to the form user if ccMe: true
    • subject - subject of the visitor confirmation with message email
    • text - path to the visitor confirmation with message text content file
    • html - path to the visitor confirmation with message HTML content file

Since the HTML file is used to define visually appealing messages, you also need to define a text message. Recipients whose email clients don't display HTML email will see this version of the email. Each email template requires two versions:

  1. HTML file (.html) - Rich formatted version
  2. Text file (.txt) - Plain text fallback

⚠️ CRITICAL WARNING: The content in both files must match exactly. Any discrepancy between HTML and text versions will cause SES to silently fail - emails won't be sent and no error will be thrown.

Example:

<!-- template.html -->
<h1>Thank you!</h1>
<p>We received your mail.</p>
// template.txt
Thank you!
We received your mail.

Slack configuration

slack: # optional
  token: xoxb-your-bot-token # required
  channel: "#web-form-notifications" # required
  username: webhook-bot # required
  message: ./slack/message.txt # required
  iconEmoji: ":email:" # optional, default value: ":email:"
  • token - Slack Bot User OAuth Token (starts with xoxb-)
  • channel - Slack channel name (e.g., #web-form-notifications) or channel ID
  • username - author's username for messages
  • message - path to the message content file
  • iconEmoji - icon emoji of the channel. You can use any emoji declared here

To get a Slack Bot token:

  1. Create a new Slack App at api.slack.com/apps
  2. Add the chat:write bot token scope under "OAuth & Permissions"
  3. Install the app to your workspace
  4. Copy the "Bot User OAuth Token" (starts with xoxb-)
  5. Invite the bot to your target channel

Log level

logLevel: debug # optional, default value: "info"

The plugin uses Pino for logging under the hood. You can set the following log levels:

  • fatal
  • error
  • warn
  • info (default)
  • debug
  • trace

Setting a specific level will show all logs of that level and higher. For example, setting logLevel: debug will show debug logs and all levels above it (info, warn, error, fatal).

Content files

Both Slack and SES use content files to load content for messages/mails, where you can easily define your own messages.

Replacement tags

You can use replacement tags in templates such as:

  • {{ firstName }} - will be replaced with the visitor's first name
  • {{ fullName }} - will be replaced with the visitor's full name (first name and last name)
  • {{ email }} - will be replaced with the visitor's email
  • {{ message }} - will be replaced with the message attached to the form by the visitor

Note that you can also use tags without spaces before and after curly braces if you want, e.g., {{firstName}}.

Default values

You can use default values for templates. If you don't provide any values for the visitorConfirmation and visitorNotification templates, your emails will look like this:

Visitor Notification

Hello, a new message was received from {{ firstName }} ({{ email }}) ({{ phoneNumber }}):
{{ message }}

Visitor Confirmation

Thank you {{ firstName }} for reaching out.
We received your email and will get back to you as soon as possible.

Visitor Confirmation With Message

Thank you {{ firstName }} for reaching out.
We received your email and will get back to you as soon as possible.
Please see your message below:
{{ message }}

Error codes

If an error occurs, the lambda returns a short number that indicates the root cause of the error. Here is a table of all possible errors:

| Error code | Description | | :--------: | :--------------------- | | 10000 | Unknown error | | 10001 | Honeypot check failed | | 10002 | reCAPTCHA check failed | | 10003 | SES error | | 10004 | DynamoDB error | | 10005 | Slack error |

Future development

We believe that collaboration and community involvement are vital for creating a robust and effective solution. As the creators of the plugin, we are excited to open it up for development and invite your contributions to make it even better.

You can get involved by tackling various tasks and improvements through GitHub Issues. Whether it's fixing bugs, adding new features, improving documentation, or enhancing overall usability, every contribution is valuable and greatly appreciated.

To contribute, simply head over to our GitHub repository, check out the existing issues, and feel free to open new ones if you have ideas or find areas that need attention.

Something about us

Check u11d.com to meet our company and explore our range of professional services.

Don't forget to explore our blog as well! It's a treasure trove of valuable content covering various topics such as web development, DevOps, observability, and management.