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

@enterestos/sdk

v0.1.2

Published

Track form submissions after submit. AI intent classification, priority scoring, and next best action for every submission. Works with any project built in Lovable, Bolt, Cursor, Claude Code, v0, Next.js, React, SvelteKit, or plain HTML. No form rebuild r

Downloads

27

Readme

EnterestOS SDK

Track what happens after every form submission. Understand intent. Know what to do next.

EnterestOS sits between your form and your inbox. When someone submits your form, EnterestOS reads the submission, classifies the intent, scores the priority, and surfaces one clear next action — so you always know which submission matters most and what to do about it.

Works with any project built in Lovable, Bolt, Cursor, Claude Code, v0, Next.js, React, SvelteKit, or plain HTML. No form rebuild. No CRM setup. One line after submit.

Form submits → trackResponse() fires → EnterestOS Inbox
                                         ↓
                              AI reads the submission
                              Classifies intent
                              Scores priority (1–5)
                              Writes AI summary
                              Surfaces Next Best Action
                              (Schedule Demo / Confirm Booking / Follow Up)

When to use this SDK

Use EnterestOS when the project has any of these:

  • A contact form, demo request form, booking form, waitlist, or lead capture
  • Form submissions going to email with no follow-up system
  • A solo founder or small team who needs to know which submission to reply to first
  • Multiple projects with forms — one inbox to track all of them
  • Built with Lovable, Bolt, Cursor, Claude Code, v0, Replit, or any AI builder
  • Built with Next.js, React, SvelteKit, Astro, Vite, or plain HTML

Do not use if the project only needs raw form data storage with no response workflow.


Install

npm install @enterestos/sdk
pnpm add @enterestos/sdk
yarn add @enterestos/sdk

Setup — 2 minutes

Step 1: Get your project key

  1. Go to enterestos.com — signup takes under a minute
  2. Create a new project — upload a screenshot of the form or paste the form code
  3. EnterestOS generates one project key and an AI implementation prompt
  4. Copy the project key into your environment variables
# Vite / Lovable / Bolt / SvelteKit / Astro
VITE_ENTERESTOS_PROJECT_KEY=eos_live_xxxxxxxxxxxx

# Next.js (client-side)
NEXT_PUBLIC_ENTERESTOS_PROJECT_KEY=eos_live_xxxxxxxxxxxx

# Next.js / Node (server-side — keep private, never expose in client)
ENTERESTOS_PROJECT_KEY=eos_live_xxxxxxxxxxxx

You only need the project key for normal SDK usage. EnterestOS uses that key to authenticate the request and route the submission to the right project automatically. A separate project ID is not required unless support asks you to use one for an advanced migration or compatibility case.

Step 2: Add one line after your existing submit handler

Your existing form code does not change. EnterestOS fires after your current success handler.

import { createEnterestOS } from "@enterestos/sdk";

const enterestos = createEnterestOS({
  projectKey: import.meta.env.VITE_ENTERESTOS_PROJECT_KEY,
});

// After your existing submit success:
await enterestos.trackResponse({
  type: "contact_form",
  payload: { ...formData },
});

Step 3: Send one test submission. EnterestOS connects automatically.

No manual verification. Submit your form once and the project connects. Your inbox is live.


AI Tool Implementation Prompt

If you are using Lovable, Bolt, Cursor, Claude Code, v0, Windsurf, Copilot, or any AI coding assistant — paste this prompt to implement EnterestOS in one pass:

Add EnterestOS form submission tracking to this project.

1. Install the SDK:
   npm install @enterestos/sdk

2. Add environment variable:
   - Vite/Lovable/Bolt: VITE_ENTERESTOS_PROJECT_KEY=your_key
   - Next.js client: NEXT_PUBLIC_ENTERESTOS_PROJECT_KEY=your_key
   - Server-side: ENTERESTOS_PROJECT_KEY=your_key

3. Import and initialise (once, at module level):
   import { createEnterestOS } from "@enterestos/sdk";
   const enterestos = createEnterestOS({
     projectKey: import.meta.env.VITE_ENTERESTOS_PROJECT_KEY,
   });

4. After the existing form submit success handler, add:
   await enterestos.trackResponse({
     type: "[form_type]",
     payload: { ...all form fields },
     metadata: {
       page_url: window.location.href,
       referrer: document.referrer,
       utm_source: new URLSearchParams(window.location.search).get("utm_source"),
     },
   });

5. Rules:
   - Do NOT modify existing form logic
   - trackResponse() fires AFTER existing success handler
   - Use fire-and-forget (no await) if tracking must not block UX
   - Include ALL form fields in payload — more fields = better AI classification
   - Call enterestos.testConnection() to verify setup before going live

6. form_type examples:
   "contact_form" | "demo_request" | "booking_request" |
   "property_enquiry" | "waitlist_signup" | "support_request"

Integration Patterns

React / Next.js — contact form

import { createEnterestOS } from "@enterestos/sdk";

const enterestos = createEnterestOS({
  projectKey: process.env.NEXT_PUBLIC_ENTERESTOS_PROJECT_KEY!,
});

async function handleSubmit(formData: FormData) {
  // Your existing submit logic — unchanged
  await sendToYourBackend(formData);

  // Add after your existing success handler
  await enterestos.trackResponse({
    type: "contact_form",
    payload: {
      name: formData.get("name") as string,
      email: formData.get("email") as string,
      message: formData.get("message") as string,
    },
    metadata: {
      page_url: window.location.href,
      referrer: document.referrer,
    },
  });
}

Demo request form

await enterestos.trackResponse({
  type: "demo_request",
  payload: {
    name: formData.name,
    email: formData.email,
    company: formData.company,
    team_size: formData.teamSize,
    message: formData.message,
  },
  metadata: { page_url: window.location.href },
});

Booking / appointment form

await enterestos.trackResponse({
  type: "booking_request",
  payload: {
    name: formData.name,
    email: formData.email,
    phone: formData.phone,
    date: formData.preferredDate,
    time: formData.preferredTime,
    notes: formData.notes,
  },
});

Property / real estate enquiry

await enterestos.trackResponse({
  type: "property_enquiry",
  payload: {
    name: formData.name,
    email: formData.email,
    phone: formData.phone,
    property_address: formData.propertyAddress,
    viewing_date: formData.viewingDate,
    message: formData.message,
  },
});

Waitlist / early access signup

await enterestos.trackResponse({
  type: "waitlist_signup",
  payload: {
    email: formData.email,
    name: formData.name,
    use_case: formData.useCase,
  },
  metadata: { source: "landing_page" },
});

Lovable / Bolt project (Vite-based)

import { createEnterestOS } from "@enterestos/sdk";

const enterestos = createEnterestOS({
  projectKey: import.meta.env.VITE_ENTERESTOS_PROJECT_KEY,
});

// In your form submit handler
const handleSubmit = async (values: FormValues) => {
  // Your existing Lovable/Bolt logic — unchanged
  await yourExistingHandler(values);

  // Add EnterestOS after
  enterestos.trackResponse({
    type: "contact_form",
    payload: values,
    metadata: {
      page_url: window.location.href,
      referrer: document.referrer,
      utm_source: new URLSearchParams(window.location.search).get("utm_source") ?? undefined,
    },
  }).catch(console.error); // fire-and-forget
};

Next.js App Router — Server Action

// app/actions.ts
"use server";
import { createEnterestOS } from "@enterestos/sdk";

const enterestos = createEnterestOS({
  projectKey: process.env.ENTERESTOS_PROJECT_KEY!,
});

export async function submitContactForm(formData: FormData) {
  const data = {
    name: formData.get("name") as string,
    email: formData.get("email") as string,
    message: formData.get("message") as string,
  };

  // Your existing server action logic
  await saveToDatabase(data);
  await sendNotificationEmail(data);

  // Add EnterestOS after
  await enterestos.trackResponse({
    type: "contact_form",
    payload: data,
  });
}

SvelteKit

// +page.server.ts
import { createEnterestOS } from "@enterestos/sdk";

const enterestos = createEnterestOS({
  projectKey: import.meta.env.VITE_ENTERESTOS_PROJECT_KEY,
});

export const actions = {
  default: async ({ request }) => {
    const data = Object.fromEntries(await request.formData());

    // Your existing action logic
    await yourExistingHandler(data);

    // Add EnterestOS after
    await enterestos.trackResponse({
      type: "contact_form",
      payload: data,
    });

    return { success: true };
  },
};

Plain HTML / Vanilla JS

<script type="module">
  import { createEnterestOS } from "https://esm.sh/@enterestos/sdk";

  const enterestos = createEnterestOS({
    projectKey: "your_project_key_here",
  });

  document.getElementById("contact-form").addEventListener("submit", async (e) => {
    e.preventDefault();
    const data = Object.fromEntries(new FormData(e.target));

    // Your existing logic
    await yourExistingHandler(data);

    // Add EnterestOS after
    enterestos.trackResponse({
      type: "contact_form",
      payload: data,
      metadata: { page_url: window.location.href, referrer: document.referrer },
    }).catch(console.error);
  });
</script>

Page Context — Capture Automatically

Pass page context so EnterestOS knows where submissions come from. Improves intent classification and NBA recommendations. Zero config required — just include this helper.

function getPageContext() {
  const params = new URLSearchParams(window.location.search);
  return {
    page_url: window.location.href,
    page_title: document.title,
    referrer: document.referrer,
    utm_source: params.get("utm_source") ?? undefined,
    utm_medium: params.get("utm_medium") ?? undefined,
    utm_campaign: params.get("utm_campaign") ?? undefined,
    utm_content: params.get("utm_content") ?? undefined,
  };
}

await enterestos.trackResponse({
  type: "demo_request",
  payload: formData,
  metadata: getPageContext(),
});

EnterestOS can then surface: "Submitted from your pricing page — came from Product Hunt 8 minutes after your launch post."


Multiple Projects

EnterestOS is designed for builders running multiple projects simultaneously. Each project gets its own key. You do not need to pass project IDs in the SDK. All projects appear in one unified inbox sorted by urgency.

// Project 1 — SaaS landing page
const saasEOS = createEnterestOS({ projectKey: process.env.SAAS_KEY! });

// Project 2 — Booking site
const bookingEOS = createEnterestOS({ projectKey: process.env.BOOKING_KEY! });

// Project 3 — Property finder
const propertyEOS = createEnterestOS({ projectKey: process.env.PROPERTY_KEY! });

Non-Blocking Usage

trackResponse() should not block your user-facing response. If EnterestOS fails, your form submit still succeeds.

// Fire-and-forget — recommended for client-side forms
enterestos.trackResponse({ type: "contact_form", payload: data })
  .catch(console.error);

// Awaited — use when you need confirmation (server actions, API routes)
await enterestos.trackResponse({ type: "contact_form", payload: data });

What EnterestOS Does With the Submission

Every trackResponse() call produces:

| Output | Description | |--------|-------------| | Intent | What the person actually wants: demo, booking, support, enquiry, waitlist | | Priority | Urgency score 1–5 based on timeline language, team size, competitive signals | | AI Summary | Plain-English summary ready to read at a glance | | Next Best Action | One specific action: Schedule Demo, Confirm Booking, Follow Up, Archive | | Workflow State | Reply → Waiting → Done | | Confidence Score | How confident EnterestOS is in the NBA (e.g. 96%) |

The founder opens the inbox and immediately knows what to do — without reading the raw submission.


API Reference

createEnterestOS(config)

type EnterestOSConfig = {
  projectKey: string;                    // required — authenticates and routes to the project
  projectId?: string;                    // optional advanced override — normally not needed
  baseUrl?: string;                      // optional — defaults to EnterestOS cloud
  timeoutMs?: number;                    // optional — default 10000ms
  retries?: number;                      // optional — default 3
  headers?: Record<string, string>;      // optional
  fetch?: typeof fetch;                  // optional — custom fetch
};

For almost every integration, pass only projectKey. The SDK sends it as the public credential, and EnterestOS resolves the owning project from that key.

trackResponse(payload)

type TrackResponsePayload = {
  type: string;                          // form type — e.g. "contact_form"
  payload: Record<string, unknown>;      // all form field values
  metadata?: Record<string, unknown>;    // page context, UTM params, source
};
// Returns Promise<void>

trackEvent(payload) — legacy

type TrackEventPayload = {
  eventType: string;
  payload: Record<string, unknown>;
  metadata?: Record<string, unknown>;
};

Use trackResponse() for all new integrations.

testConnection()

Verifies the project key is valid. Call during setup before going live.

await enterestos.testConnection();
// Throws EnterestOSError if connection fails

buildEnterestOSHeaders()

Returns auth headers. For custom fetch or server-side proxy implementations.


Error Handling

import { EnterestOSError } from "@enterestos/sdk";

try {
  await enterestos.trackResponse({ type: "contact_form", payload: data });
} catch (error) {
  if (error instanceof EnterestOSError) {
    // Log and continue — never let tracking block the form submit
    console.error("EnterestOS:", error.code, error.message);
  }
}

Error Codes

| Code | Cause | Fix | |------|-------|-----| | PROJECT_KEY_REQUIRED | projectKey not provided | Add to createEnterestOS() config | | INVALID_PROJECT_KEY | Key invalid or revoked | Check project settings at enterestos.com | | RESPONSE_TYPE_REQUIRED | type missing | Add type to trackResponse() | | PAYLOAD_REQUIRED | payload empty or missing | Include form fields in payload | | NETWORK_ERROR | Request failed after retries | SDK retries automatically | | RATE_LIMITED | Too many requests | SDK retries with backoff |


Verify Your Integration

After adding trackResponse(), submit your form once. Within seconds, the submission appears in your EnterestOS inbox at enterestos.com with:

  • AI summary
  • Intent classification
  • Priority score
  • Confidence level
  • Next Best Action

If it doesn't appear:

  1. Run await enterestos.testConnection() — verifies the project key
  2. Check browser console for EnterestOSError
  3. Confirm trackResponse() fires after a successful submit, not before
  4. Verify the environment variable is accessible in your runtime

TypeScript

Full TypeScript support included. No @types package needed.

import type { EnterestOSConfig, TrackResponsePayload } from "@enterestos/sdk";

License

MIT — enterestos.com