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

@originmap/no-scan

v2.0.0

Published

Opt out of Origin Map scanning — meta tag, well-known file, multi-framework support, security middleware

Downloads

405

Readme


Qué hace

Origin Map es un toolkit de ingeniería inversa para apps web. Si quieres que tu sitio no sea escaneado, instala este paquete.

Emite dos señales que Origin Map detecta antes de escanear:

| Señal | Dónde | Cómo | |-------|-------|------| | <meta name="originmap" content="no-scan"> | HTML <head> | Inyectado client-side (React, Vue, Svelte, Angular, vanilla JS) | | /.well-known/originmap.jsonc | Ruta del servidor | Servido via middleware Express o archivo estático |

Cualquiera de las dos es suficiente. Ambas juntas dan máxima cobertura.

Además incluye middleware de seguridad: bot guard, rate limiter y shield (todo en uno).


Instalación

npm install @originmap/no-scan
yarn add @originmap/no-scan
pnpm add @originmap/no-scan
bun add @originmap/no-scan

Inicio rápido

React / Next.js / Remix

import { OriginMapNoScan } from "@originmap/no-scan"

export default function App() {
  return (
    <>
      <OriginMapNoScan domain="tusitio.com" />
      {/* tu app */}
    </>
  )
}

Funciona con React 16.8+ (hooks). El prop domain es opcional — usa window.location.hostname por default.

Vue 3

<script setup>
import { useOriginMapNoScan } from "@originmap/no-scan/vue"

useOriginMapNoScan("tusitio.com")
</script>

O como componente:

<template>
  <OriginMapNoScanVue domain="tusitio.com" />
</template>

<script setup>
import { OriginMapNoScanVue } from "@originmap/no-scan/vue"
</script>

Svelte

<script>
  import { originMapNoScan } from "@originmap/no-scan/svelte"
</script>

<div use:originMapNoScan={"tusitio.com"}></div>

O en el script:

<script>
  import { injectNoScan } from "@originmap/no-scan/svelte"
  import { onMount } from "svelte"

  onMount(() => injectNoScan("tusitio.com"))
</script>

Angular

import { Component } from "@angular/core"
import { OriginMapNoScanService } from "@originmap/no-scan/angular"

@Component({ selector: "app-root", template: "..." })
export class AppComponent {
  constructor(private noScan: OriginMapNoScanService) {
    noScan.activate("tusitio.com")
  }
}

Sin inyección de dependencias:

import { activateNoScan } from "@originmap/no-scan/angular"

activateNoScan("tusitio.com")

Vanilla JS

<script type="module">
  import { injectMetaTag } from "@originmap/no-scan"
  injectMetaTag("tusitio.com")
</script>

Express / Connect / Fastify

import express from "express"
import { originMapNoScan } from "@originmap/no-scan/middleware"

const app = express()
app.use(originMapNoScan({ domain: "tusitio.com" }))

El domain es opcional — se auto-detecta desde req.hostname.

Shield (todo en uno)

import express from "express"
import { originMapShield } from "@originmap/no-scan/middleware"

const app = express()
app.use(originMapShield({ domain: "tusitio.com" }))

Un solo middleware que aplica: rate limitbot guardwell-known.

Archivo estático (SSG / CDN)

import { generateWellKnown } from "@originmap/no-scan"
import { writeFileSync, mkdirSync } from "fs"

const content = await generateWellKnown("tusitio.com")
mkdirSync("public/.well-known", { recursive: true })
writeFileSync("public/.well-known/originmap.jsonc", content)

Manual (sin paquete)

Meta tag HTML:

<meta name="originmap" content="no-scan">

Archivo estático en /.well-known/originmap.jsonc:

{
  "originmap": "no-scan",
  "domain": "tusitio.com"
}

API

Cliente — @originmap/no-scan

| Export | Tipo | Descripción | |--------|------|-------------| | OriginMapNoScan | Componente React | Inyecta meta tag via useEffect. Props: { domain?: string } | | injectMetaTag(domain?) | Promise<void> | Vanilla JS — agrega meta tag al <head> | | generateWellKnown(domain) | Promise<string> | Genera el contenido JSONC del well-known file | | generateToken(domain) | Promise<string> | Genera token de verificación HMAC-SHA256 |

Vue — @originmap/no-scan/vue

| Export | Tipo | Descripción | |--------|------|-------------| | useOriginMapNoScan(domain?) | Composable | Vue 3 composable — inyecta en onMounted | | OriginMapNoScanVue | Componente | Componente Vue 3 con prop domain | | injectMetaTag(domain?) | Promise<void> | Re-export de la función base |

Svelte — @originmap/no-scan/svelte

| Export | Tipo | Descripción | |--------|------|-------------| | originMapNoScan(node, domain?) | Action | Svelte action | | injectNoScan(domain?) | Promise<void> | Alias de injectMetaTag | | injectMetaTag(domain?) | Promise<void> | Re-export de la función base |

Angular — @originmap/no-scan/angular

| Export | Tipo | Descripción | |--------|------|-------------| | OriginMapNoScanService | Servicio | Angular service con activate(domain?) — SSR-safe | | activateNoScan(domain?) | void | Función standalone sin DI | | injectMetaTag(domain?) | Promise<void> | Re-export de la función base |

Middleware — @originmap/no-scan/middleware

| Export | Tipo | Descripción | |--------|------|-------------| | originMapNoScan(opts?) | Middleware | Sirve /.well-known/originmap.jsonc | | botGuard(opts?) | Middleware | Bloquea bots/scrapers por User-Agent | | rateLimit(opts?) | Middleware | Rate limit por IP (50 req/s default) | | originMapShield(opts?) | Middleware | Todo en uno: rate limit + bot guard + well-known |


Seguridad

Bot Guard

Bloquea user-agents de bots, scrapers y herramientas de automatización. Los bots legítimos de buscadores pasan automáticamente.

import { botGuard } from "@originmap/no-scan/middleware"

app.use(botGuard({
  blockEmptyUA: true,          // bloquea requests sin User-Agent (default: true)
  customPatterns: [/my-bot/i], // patrones adicionales a bloquear
  allowList: [/mi-crawler/i],  // bots custom a permitir
  onBlocked: (req, res) => {   // respuesta personalizada (default: 403)
    res.statusCode = 403
    res.end("Bloqueado")
  },
}))

Bloqueados: curl, wget, httpie, python-requests, aiohttp, httpx, scrapy, phantomjs, puppeteer, playwright, selenium, nikto, sqlmap, nmap, dirbuster, gobuster, wpscan, burpsuite, bot, crawler, spider, scraper.

Permitidos: googlebot, bingbot, duckduckbot, facebookexternalhit, twitterbot, linkedinbot, whatsapp, telegrambot, discordbot, applebot, gptbot, slackbot, pinterestbot, yandexbot.

Rate Limiter

Rate limit por IP con fixed-window counter. Devuelve 429 Too Many Requests con header Retry-After.

import { rateLimit } from "@originmap/no-scan/middleware"

app.use(rateLimit({
  maxRequests: 50,          // requests por ventana (default: 50)
  windowMs: 1000,           // ventana en ms (default: 1s)
  cleanupIntervalMs: 60000, // limpieza de entries viejas (default: 60s)
  keyGenerator: (req) => getIP(req), // key personalizada
}))

Headers en cada respuesta:

  • X-RateLimit-Limit — límite máximo
  • X-RateLimit-Remaining — requests restantes
  • X-RateLimit-Reset — timestamp de reset (epoch seconds)

Shield

Middleware combinado que aplica todo en orden:

  1. Rate limit — configurable o desactivable con false
  2. Bot guard — configurable o desactivable con false
  3. Well-known — sirve /.well-known/originmap.jsonc
import { originMapShield } from "@originmap/no-scan/middleware"

// Configuración personalizada
app.use(originMapShield({
  domain: "tusitio.com",
  rateLimit: { maxRequests: 100, windowMs: 2000 },
  botGuard: { blockEmptyUA: false },
}))

// Desactivar una capa
app.use(originMapShield({
  domain: "tusitio.com",
  rateLimit: false, // sin rate limit
}))

Cómo funciona la detección

Cuando un usuario apunta Origin Map a tu sitio, el scanner ejecuta estos checks antes de analizar código:

  1. Busca <meta name="originmap" content="no-scan"> en el DOM
  2. Hace GET /.well-known/originmap.jsonc a tu dominio (timeout 3s)

Si cualquier check devuelve una señal válida de opt-out, el escaneo se aborta y el usuario ve un aviso de "Sitio Protegido".

El token HMAC-SHA256 incluido en ambas señales verifica que el opt-out fue configurado intencionalmente por el dueño del sitio.


Licencia

MIT — Rurylox LLC