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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@alufie/form

v0.1.1

Published

Verified submission workflows for contact forms, comments, reviews, and feedback with tree-shakeable subpath exports.

Readme

@alufie/form

@alufie/form is a reusable verified submission system for contact forms, comments, reviews, feedback, and similar user-generated workflows.

It extracts an existing production contact confirmation pattern into a configurable, packageable lifecycle:

  1. accept a submission
  2. run anti-spam checks
  3. hold it in a pending state
  4. send a confirmation email
  5. confirm once with a signed token
  6. notify, queue for approval, or publish

This workspace currently provides a working headless core plus first-party adapters for Drizzle, Resend, Turnstile, and SvelteKit.

Install

npm install @alufie/form

Import only the parts you use:

import { createFormSystem } from '@alufie/form/core';
import { createSubmitAction } from '@alufie/form/sveltekit';
import { createDrizzleSubmissionStorage } from '@alufie/form/drizzle';

This package is exposed through subpath exports so consumers can avoid pulling in adapters they do not use.

Table of contents

What this is for

Use @alufie/form when you want:

  • email-confirmed contact forms
  • verified comments before moderation
  • verified reviews before publication
  • feedback or lead forms with anti-spam protection
  • a reusable backend lifecycle that can be plugged into multiple apps

This is not yet a full public comment platform with:

  • threaded discussion
  • moderation dashboard UI
  • end-user account management
  • permanent public rendering layer

Instead, this package family focuses on the verified submission workflow that sits before those higher-level product features.

What is included

The public package currently includes these subpath exports:

  • @alufie/form/core Headless workflow engine, status transitions, contracts, hooks, token lifecycle, and orchestration.
  • @alufie/form/drizzle Drizzle schema and storage adapter for persisted submissions.
  • @alufie/form/resend Resend email transport adapter.
  • @alufie/form/turnstile Cloudflare Turnstile captcha verifier.
  • @alufie/form/sveltekit SvelteKit form action and route helpers.
  • @alufie/form/ui-svelte Minimal Svelte UI helpers for status display and honeypot fields.

Architecture

The project is intentionally split into a headless core and optional integrations.

Core responsibilities

@alufie/form/core owns:

  • submission state machine
  • confirmation token generation and hashing
  • transition rules
  • orchestration of validation, anti-spam, confirmation, and notification
  • moderation actions
  • lifecycle hooks

Adapter responsibilities

Adapters plug infrastructure into the core:

  • storage
  • email transport
  • captcha verification
  • framework-specific request/response helpers
  • optional UI primitives

Design goal

The core package must not depend on:

  • SvelteKit
  • Drizzle
  • Resend
  • Turnstile
  • framework env modules

That keeps the lifecycle portable while still allowing opinionated first-party integrations.

Submission lifecycle

The current implementation supports these statuses:

  • submitted
  • pending_confirmation
  • confirmed
  • pending_approval
  • approved
  • rejected
  • published
  • expired

Typical flow

Default contact-style flow:

  1. user submits the form
  2. validator checks the payload
  3. honeypot, rate limiting, and captcha checks run if configured
  4. payload is sanitized if a sanitizer is configured
  5. system stores the submission
  6. system sends a confirmation email if confirmation is required
  7. user clicks the verification link
  8. token is consumed exactly once
  9. submission transitions and post-confirmation behavior runs

Policy options

The current policy knobs are:

  • confirmation mode: required or disabled
  • post-confirmation action: notify, await_approval, or publish
  • moderation mode: disabled or required
  • token expiry hours

Default behavior

If no policies are overridden:

  • confirmation is enabled
  • moderation is disabled
  • post-confirmation action is notify
  • token expiry is 24 hours

Package guide

@alufie/form/core

Use this when you want the lifecycle engine without any framework lock-in.

Main exports:

  • createFormSystem
  • generateToken
  • hashToken
  • types for storage, validation, transport, policies, and results

See:

  • packages/core/src/index.ts
  • packages/core/src/system.ts
  • packages/core/src/types.ts

@alufie/form/drizzle

Use this when you want a Drizzle-backed submission store.

It currently exports:

  • formSubmissionTable
  • createDrizzleSubmissionStorage

See:

  • packages/drizzle/src/index.ts

@alufie/form/resend

Use this when Resend is your email provider.

It exports:

  • createResendTransport

See:

  • packages/resend/src/index.ts

@alufie/form/turnstile

Use this when Cloudflare Turnstile is your captcha provider.

It exports:

  • createTurnstileVerifier

See:

  • packages/turnstile/src/index.ts

@alufie/form/sveltekit

Use this when your app is built with SvelteKit.

It currently exports:

  • createSubmitAction
  • createConfirmationHandler
  • createModerationHandler

See:

  • packages/sveltekit/src/index.ts

@alufie/form/ui-svelte

Optional small UI helpers for Svelte apps:

  • FormStatus
  • HiddenHoneypot

See:

  • packages/ui-svelte/src/index.ts

Core API

The main entrypoint is:

import { createFormSystem } from '@alufie/form/core';

createFormSystem(config)

Creates a configured submission system instance.

The returned object currently exposes:

  • submit({ data }, context?)
  • confirm(token, context?)
  • approve(submissionId, context?)
  • reject(submissionId, context?)
  • publish(submissionId, context?)
  • resendConfirmation(submissionId, context?)
  • cleanupExpired(context?)

Example

import { createFormSystem } from '@alufie/form/core';

const system = createFormSystem({
  type: 'contact',
  storage,
  validator,
  templates,
  emailTransport,
  generateConfirmationUrl: (token, submission) =>
    `https://example.com/contact/verify/${token}`,
});

Configuration reference

The most important config fields are below.

Required config

  • type Logical submission type like contact, comment, or review.
  • storage A storage adapter implementing the SubmissionStorage contract.
  • validator Validates raw input and returns typed payload data.
  • templates Renders confirmation and internal notification emails.
  • emailTransport Sends email messages generated by templates.
  • generateConfirmationUrl Converts a raw confirmation token into a user-facing URL.

Optional config

  • sanitizer Sanitizes validated payload data before persistence.
  • captchaVerifier Verifies captcha tokens.
  • rateLimiter Applies request rate limits.
  • duplicateChecker Rejects near-duplicate submissions if desired.
  • hooks Lifecycle hooks for submit/confirm/approve/reject/publish.
  • logger Structured logging hooks.
  • policies Workflow policy overrides.
  • generateId Custom ID generation.
  • getCaptchaToken Extracts the captcha token from raw input.
  • getHoneypotValue Extracts the honeypot field value from raw input.
  • getRateLimitKey Chooses a key for rate limiting.
  • getInternalRecipients Overrides internal email recipients.

Validator contract

Your validator should return:

{
  success: true,
  data: typedPayload
}

or:

{
  success: false,
  message: 'Validation failed',
  fieldErrors: {
    email: ['Valid email is required']
  }
}

Template contract

Templates must implement:

  • renderConfirmationEmail
  • renderInternalNotification

Optional:

  • renderApprovalRequest
  • renderDecisionEmail

Example config

const system = createFormSystem({
  type: 'contact',
  storage,
  validator: {
    validate(input) {
      return {
        success: true,
        data: {
          name: String(input.name ?? ''),
          email: String(input.email ?? ''),
          message: String(input.message ?? ''),
        },
      };
    },
  },
  sanitizer: {
    sanitize(payload) {
      return {
        ...payload,
        email: payload.email.trim().toLowerCase(),
        message: payload.message.trim(),
      };
    },
  },
  templates: {
    renderConfirmationEmail({ submission, confirmationUrl }) {
      return {
        to: submission.submitterEmail,
        subject: 'Confirm your submission',
        text: `Confirm here: ${confirmationUrl}`,
      };
    },
    renderInternalNotification({ submission }) {
      return {
        to: '[email protected]',
        replyTo: submission.submitterEmail,
        subject: `New verified ${submission.type}`,
        text: JSON.stringify(submission.payload, null, 2),
      };
    },
  },
  emailTransport,
  generateConfirmationUrl: (token) =>
    `https://example.com/contact/verify/${token}`,
});

Storage model

The generalized data model is a reusable form_submission table.

The current Drizzle adapter stores:

  • id
  • type
  • status
  • payload
  • submitter_email
  • submitter_name
  • confirmation_token_hash
  • confirmation_token_expires_at
  • confirmed_at
  • approved_at
  • published_at
  • rejected_at
  • meta
  • created_at
  • updated_at

Important storage notes

  • raw confirmation tokens are never stored
  • only the token hash is persisted
  • confirmation is one-time by design
  • the Drizzle adapter consumes confirmation tokens atomically

SvelteKit integration

Submit action

Use createSubmitAction for form actions:

import { createSubmitAction } from '@alufie/form/sveltekit';
import { system } from '$lib/server/system';

export const actions = {
  default: createSubmitAction({ system }),
};

Confirmation route

Use createConfirmationHandler for token verification:

import { createConfirmationHandler } from '@alufie/form/sveltekit';
import { system } from '$lib/server/system';

export const GET = createConfirmationHandler({
  system,
  getToken: ({ params }) => params.token ?? '',
  successRedirectTo: '/contact?verified=true',
});

Moderation routes

Use createModerationHandler for admin transitions:

import { createModerationHandler } from '@alufie/form/sveltekit';
import { system } from '$lib/server/system';

export const POST = createModerationHandler({
  system,
  action: 'approve',
  getSubmissionId: ({ params }) => params.id ?? '',
  successRedirectTo: '/admin/submissions',
});

Example workflows

1. Contact form

Recommended policy:

  • confirmation: required
  • post-confirmation action: notify
  • moderation: disabled

Meaning:

  • user must confirm email
  • after confirmation, internal admin notification is sent

2. Comment submission

Recommended policy:

  • confirmation: required
  • post-confirmation action: await_approval
  • moderation: disabled or required

Meaning:

  • user confirms ownership of email
  • comment enters approval queue
  • admin can approve, reject, or publish

3. Review submission

Recommended policy:

  • confirmation: required
  • post-confirmation action: publish

Meaning:

  • user confirms email
  • review is published immediately after confirmation

4. Internal feedback form

Recommended policy:

  • confirmation: disabled
  • post-confirmation action: notify

Meaning:

  • skip email confirmation
  • use the same validation, storage, and anti-spam pipeline

Security model

The current implementation includes these safeguards:

  • honeypot support
  • pluggable rate limiting
  • pluggable captcha verification
  • validator boundary before persistence
  • optional sanitizer boundary before persistence
  • hashed confirmation tokens
  • one-time confirmation token consumption
  • expiry-based cleanup

Security defaults

  • token hashing uses SHA-256
  • tokens are URL-safe
  • raw confirmation tokens are only sent to the user
  • expired pending confirmations can be moved to expired

Recommended production hardening

For production apps, also add:

  • request logging
  • duplicate submission detection
  • stronger audit trail persistence
  • provider retry strategy
  • admin authentication around moderation routes
  • rate limiting keyed by IP and email when appropriate

Workspace structure

alufie-form/
  packages/
    core/
    drizzle/
    resend/
    sveltekit/
    turnstile/
    ui-svelte/

Useful files:

  • packages/core/src/system.ts
  • [packages/core/test/system.test.ts]

Development

Install

pnpm install

Run checks

pnpm test
pnpm check
pnpm build

Current limitations

This workspace is functional, but still intentionally lightweight.

Current limitations include:

  • no packaged moderation dashboard UI
  • no built-in database migrations folder yet beyond exported schema/adapter
  • no webhook adapter yet
  • no job queue adapter yet
  • no first-party React/Next.js adapter yet
  • no built-in duplicate detection adapter yet
  • no localization framework for templates yet
  • no publish script or release automation yet

Roadmap ideas

Natural next steps:

  • add a more complete production integration example in docs
  • add webhook and queue adapters
  • add moderation dashboard primitives
  • add richer template composition helpers
  • add first-party Next.js and generic Express/Fetch adapters
  • add audit log persistence and metrics hooks
  • add retry and dead-letter strategies for email delivery

Reference files

  • Workspace root: [alufie-form]
  • Core API: packages/core/src/index.ts
  • SvelteKit adapter: packages/sveltekit/src/index.ts