1
0
Fork 0
mirror of https://github.com/imjasonh/npm-snoop synced 2026-07-07 00:32:54 +00:00
No description
Find a file
Jason Hall dab2c306d4 Update cost.md with collection-only cost analysis (~$78/month)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 10:57:37 -04:00
cmd Remove ast-diff service and Terraform 2026-03-27 10:51:46 -04:00
internal Harden ast-diff service and disable in production 2026-03-27 10:50:11 -04:00
terraform Remove ast-diff service and Terraform 2026-03-27 10:51:46 -04:00
.gitignore Move poller to cmd/npm-cron/ 2026-03-26 21:39:02 -04:00
ast-diff-plan.md Add ast-diff CLI for diffing symbols between npm package versions 2026-03-26 16:52:19 -04:00
CLAUDE.md Remove ast-diff service and Terraform 2026-03-27 10:51:46 -04:00
cost.md Update cost.md with collection-only cost analysis (~$78/month) 2026-03-27 10:57:37 -04:00
design.md Poll npm registry changes feed and record releases to BigQuery 2026-03-26 13:03:29 -04:00
go.mod Remove ast-diff service and Terraform 2026-03-27 10:51:46 -04:00
go.sum Remove ast-diff service and Terraform 2026-03-27 10:51:46 -04:00
lessons.md Stream tarballs file-by-file instead of extracting to disk 2026-03-26 21:31:35 -04:00
LICENSE Poll npm registry changes feed and record releases to BigQuery 2026-03-26 13:03:29 -04:00
queries.md Fix queries.md: use REGEXP_EXTRACT for dist-tags, add WHERE body IS NOT NULL 2026-03-26 16:23:54 -04:00
README.md Record per-version releases, metadata modifications, and raw JSON bodies 2026-03-26 16:21:58 -04:00

npm-snoop

Polls the npm registry's CouchDB changes feed and records package activity to BigQuery via CloudEvents.

Architecture

A Cloud Run cron job runs every 15 minutes:

  1. Reads state (sequence number + last poll timestamp) from a GCS bucket
  2. Polls https://replicate.npmjs.com/registry/_changes for new changes
  3. Fetches metadata for each changed package from https://registry.npmjs.org/<name>
  4. Classifies each change and emits CloudEvents to a broker (Chainguard cloudevent-broker)
  5. The recorder (Chainguard cloudevent-recorder) writes events to BigQuery via GCS + DTS

The poller loops through batches until fully caught up, saving progress after each batch.

Event types

dev.npm.package.released.v1

One event per version published. The poller compares the package's time map against the last poll timestamp to find newly published versions. A single package change can produce multiple release events if several versions were published between polls.

Fields: name, version, description, license, homepage, published_at, body (raw package metadata JSON, versions key stripped).

dev.npm.package.modified.v1

A package was changed but no new versions were published. This covers metadata-only changes like description edits, maintainer updates, dist-tag moves, ownership transfers, or npm security actions.

Fields: name, modified_at, body (raw package metadata JSON, versions key stripped). To determine what changed, diff the body against a previous modified or released event for the same package.

dev.npm.package.deleted.v1

An entire package was removed from npm. This is a package-level deletion, not a version unpublish — version removals appear as modified events (the version disappears from the metadata).

Fields: name, deleted_at.

Deploy

Requires gcloud auth, terraform, and ko.

cd terraform
terraform init
terraform apply -var=project_id=YOUR_PROJECT_ID

Key variables (see terraform/variables.tf):

Variable Default Description
project_id (required) GCP project
region us-east4 GCP region
schedule */15 * * * * Cron schedule
bq_retention_days 365 BigQuery retention
deletion_protection false Protect resources from deletion

Manual run

gcloud run jobs execute npm-snoop-cron --project YOUR_PROJECT_ID --region us-east4 --wait

Queries

See queries.md for example queries, including how to diff consecutive metadata modifications using window functions.