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

@brandlab-digital/site-next

v3.17.0

Published

Proprietary software © Brandlab Digital Marketing. All rights reserved. Published for Brandlab client sites.

Readme

@brandlab-digital/site-next

Proprietary software © Brandlab Digital Marketing. All rights reserved. Published for Brandlab client sites.

Reviews: refresh on change, not every day (3.13.0)

The shared reviews fetch (getBusinessProfileReviews, ./google-business-reviews/server) carries the tags brandlab-reviews and brandlab-reviews:<site>. By default it still keeps a successful answer for one day (BUSINESS_PROFILE_REVIEWS_REVALIDATE_SECONDS), so a site that installs 3.13.0 for another reason keeps daily reviews.

A site opts into refresh on change by passing refresh: 'on-change', in the same call that already names the site, once it has the route below deployed with its secret and is registered with the daily reviews checker:

// src/lib/reviews.ts
getBusinessProfileReviews({ site: 'hr-kitchens', refresh: 'on-change' })

The answer is then kept for 7 days (BUSINESS_PROFILE_REVIEWS_ON_CHANGE_REVALIDATE_SECONDS) as a safety net only. Once a day the checker hashes each site's feed and, when the reviews have really changed, calls the site's signed revalidate route, which refreshes the tag. A new review still shows within a day; pages are rewritten only after a real change. If a call fails, pages refresh themselves within the week. The choice sits on the fetch, not in brandlab.config.ts, because the fetch is where Next reads it at build time and a site's config file is not imported at runtime.

The route, at src/app/api/brandlab/reviews-revalidate/route.ts:

import { createBrandlabReviewsRevalidateRoute } from '@brandlab-digital/site-next/google-business-reviews/server'

export const { POST } = createBrandlabReviewsRevalidateRoute({ site: 'hr-kitchens' })

Set BRANDLAB_REVALIDATE_SECRET (at least 32 characters) in the site's Vercel project and on the checker; never in git. The call contract:

| | | | --- | --- | | Request | POST /api/brandlab/reviews-revalidate, body {"site":"<slug>","hash":"<64 hex>"} (1 KB at most) | | Signature | x-brandlab-timestamp: <Unix seconds> and x-brandlab-signature: v1=<hex HMAC-SHA256 of "<timestamp>.<body>">; site-core createBusinessProfileReviewsRevalidateRequest builds both | | Hash | site-core hashBusinessProfileReviews(feed): the rating, the count and each review's id, rating, text, author, times and reply, sorted by id | | Who decides | The checker keeps the last hash each site accepted with a 200 and calls only when today's differs. The route also skips a hash it already applied, but only per server instance | | 200 | { ok: true, revalidated: true } after revalidateTag('brandlab-reviews:<site>', 'max'), or revalidated: false, reason: 'unchanged' | | Errors | 400 malformed body or another site's slug; 401 missing or wrong signature, or a timestamp more than 5 minutes off; 413 body over 1 KB; 429 with Retry-After past 10 requests per IP in 10 minutes; 503 secret not set; 500 refresh failed. The checker records the hash only after a 200 |

Refused requests log one line without the secret or signature, for example {"event":"brandlab_reviews_revalidate","site":"hr-kitchens","result":"refused","reason":"signature"}.

Estate segment preset (./estate-segment)

Service-in-suburb and suburb pages export revalidate = false, written literally because Next reads segment config statically, and a site test calls assertBrandlabEstateSegment(page). Deploys and the reviews tag rewrite them. A page that shows reviews follows the reviews fetch: daily by default, weekly with refresh: 'on-change'. Ready-gate check W3 (full tier, from 3.13.0) fails an estate family that refreshes more often than every 7 days, so a full-tier estate that shows reviews adopts on-change with the route, or records the family in siteSystem.refreshExceptions in brandlab.config.ts: { family, revalidateSeconds, reason, decisionId }.

Contact delivery: accepted is not delivered (3.14.0)

When Resend accepts an enquiry it is queued, not delivered. Resend can still bounce it, drop it because the business inbox is on the account's suppression list, or have it reported as spam, while the site has already said "sent". That is how BL Roofing lost enquiries. contact_form keeps its analytics-v4 meaning (Resend accepted the enquiry) and fires exactly as before; delivery is now tracked beside it.

Before sending. createBrandlabContactRouteHandler asks Resend's suppression list about each business inbox (GET /suppressions/{email}, cached for 5 minutes per inbox, at most 2.5 seconds per lookup). The check only records and alerts; it never blocks a send. When an inbox is suppressed the route logs and alerts recipient_suppressed, and the enquiry still goes to the client's own inbox (never rerouted, never copied to Brandlab) with the normal "sent" result and contact_form as usual. Keeping the inbox and its email billing in order is the client's responsibility; the alert lets Brandlab tell them the same day. A site can opt in to refusing instead with refuseWhenAllSuppressed: true: when every inbox is suppressed the visitor then gets the form's "could not send, please call" answer and no conversion fires. A failed or refused lookup never stops an enquiry: it is sent as before and logged once per 5 minutes as brandlab_contact_suppression_check_unavailable. The lookup needs a full-access key: set RESEND_LOOKUP_API_KEY so RESEND_API_KEY can stay sending-only (without it the lookup uses RESEND_API_KEY). A sending-only key is refused with restricted_api_key, and the warning line names the missing permission ("needs":"full-access key (RESEND_LOOKUP_API_KEY)"). suppressionCheck: false turns the check off; a route that replaces the provider with createResendSend (synthetic tests) has it off unless it passes one.

After sending. A signed webhook route records what happened to the business copy. Add src/app/api/brandlab/resend-webhook/route.ts:

import { createBrandlabResendWebhookRoute } from '@brandlab-digital/site-next/contact/server'
import { contactContract } from '@/config/contact'

export const { POST } = createBrandlabResendWebhookRoute({ projectId: contactContract.projectId })

Then, in plain steps:

  1. Deploy the route.
  2. In Resend, open Webhooks and add an endpoint: https://<the site's domain>/api/brandlab/resend-webhook.
  3. Tick the email events: delivered, delivery delayed, bounced, complained, suppressed and failed.
  4. Open the new webhook and copy its signing secret (it starts with whsec_).
  5. In the site's Vercel project, add RESEND_WEBHOOK_SECRET with that value for Production (and Preview if previews send real enquiries). Never put it in git or .env.example values.
  6. Redeploy, send a test enquiry (?bl_test=1), and check the logs show a brandlab_contact_delivery_status line with "state":"delivered".

Resend webhooks cover the whole account, so each site's route records only the emails its own contact route sent (the project_id tag) and answers 200 to the rest. The signature is checked the Svix way Resend documents (HMAC-SHA256 over <svix-id>.<svix-timestamp>.<raw body>, 5 minutes' clock tolerance); a bad signature gets 401, a missing secret 503. Failed attempts are rate-limited per x-real-ip (10 in 10 minutes, then 429 with Retry-After; rateLimit adjusts it or false turns it off); a correctly signed request never counts. A retry with an svix-id the instance already recorded answers 200 duplicate: true without logging again; that list is small and per instance, so it is best effort and the monitor still de-duplicates.

Both halves accept onDeliveryFailure(failure), a same-day alert hook (email, Slack or a durable store). It gets the code, source, enquiry reference and Resend email id, never an address or form value. If it throws on a webhook event the route answers 500 so Resend retries the event.

| Environment variable | Where | What | | --- | --- | --- | | RESEND_API_KEY | Vercel, Production and Preview | Sends enquiries; can stay a sending-only key | | RESEND_LOOKUP_API_KEY | Vercel, Production and Preview (optional) | A full-access key used only for the suppression lookup; without it the lookup uses RESEND_API_KEY | | RESEND_WEBHOOK_SECRET | Vercel, Production | The webhook's whsec_ signing secret | | the contract's delivery.recipientEnv | Vercel, Production and Preview | The business inbox |

For the daily delivery monitor (P26). Read these JSON lines from the site's logs:

| Line | Meaning | Action | | --- | --- | --- | | {"event":"brandlab_contact_delivery_failed",…,"code":"recipient_suppressed","source":"pre-send","recipients":"all"} | The inbox is suppressed; the enquiry was still sent (Resend will drop it) and the visitor saw "sent" (unless the site opted in to refuseWhenAllSuppressed: true, when it was not sent and the visitor was asked to call) | Same day: tell the client to fix the inbox, remove it from Resend → Suppressions, tell Romie | | same, "recipients":"some" | One of several inboxes is suppressed; the others got it | Same day: fix or remove that inbox | | …"code":"recipient_bounced"/"recipient_complained"/"recipient_suppressed"/"provider_failed","source":"webhook" | Resend accepted it but the business copy did not arrive (detail gives Resend's bounce type, suppression type or failure reason) | Same day: the enquiry counted as a contact_form but the business never saw it; find it by submission (the first 16 characters of the confirmation id) or emailId in Resend and forward it | | {"event":"brandlab_contact_delivery_status","state":"delivered"} / "state":"delayed" | Delivered, or Resend is retrying a soft bounce | None; a delayed with no later delivered or failure within a day needs a look | | brandlab_contact_suppression_check_unavailable | The pre-send check could not ask Resend (code says why; needs names a missing permission) | Set a full-access RESEND_LOOKUP_API_KEY; enquiries still send | | brandlab_contact_delivery_alert_failed | The alert hook failed | Check the hook |

De-duplicate webhook lines on webhookId (Resend retries an event with the same id). Compare each day's contact_form count in GA4 with delivered lines: every accepted enquiry should end in exactly one delivered or one failure. Ready-gate check H13 (enquiry tier, from 3.14.0) checks the same inbox before launch: a real sender, MX records, the sender domain verified in Resend and the inbox not suppressed. Run brandlab-ready --launch with the inbox variable and a full-access key (RESEND_LOOKUP_API_KEY) set in the shell for that run, never written to a file. Without them H13 reports "not run" and names what to set: in an ordinary run that does not block the tier, and under --launch it fails.

Contact route: abuse limits and the test marker (3.10.0)

createBrandlabContactRouteHandler limits distinct enquiries per client IP and per email address where enquiries are delivered (production and Preview): 10 per IP in 10 minutes and 5 per address in an hour by default (BRANDLAB_CONTACT_RATE_LIMITS), held in memory per server instance. A resend of the same enquiry never counts, an enquiry that fails validation never counts, and a refused one gets a retryable 429 with Retry-After and is never sent. Adjust or turn them off with rateLimit: { perIp, perAddress } | false.

The in-memory limiter is the first layer. The second is a Vercel Firewall rate-limit rule on the route, which holds across every instance. Template (Vercel CLI, run in the linked project; check the project's Firewall tab for the plan's rate-limit support first, and keep the limit above the route's own):

vercel firewall rules add "Contact form rate limit" \
  --condition '{"type":"path","op":"eq","value":"/api/contact"}' \
  --condition '{"type":"method","op":"eq","value":"POST"}' \
  --action rate_limit \
  --rate-limit-window 600 \
  --rate-limit-requests 20 \
  --rate-limit-keys ip \
  --rate-limit-action rate_limit --yes

A Brandlab test enquiry (a launch proof or canary) opens the page with ?bl_test=1 (remembered for the tab; ?bl_test=0 ends it). Each enquiry then carries bl_test=1: the server delivers it to the configured recipient with [Test] in the subject, never writes the marker into the email and answers without a confirmation, so the browser never sends contact_form or an Ads conversion for it, and a test visit sends no lead_form_start or lead_form_error. Canary previews deliver only to the Brandlab test inbox.

Canary and launch-proof runs count against the per-address limit (5 per address per hour), so use plus-addressed test inboxes, one per run or per site (test+abloom-1@…, test+abloom-2@…), and spread repeated runs across them. A refused enquiry logs one line: {"event":"brandlab_contact_rate_limited","rule":"address","retryAfterSeconds":1800}.