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

@devdogsuga/events

v0.1.7

Published

Config-as-code for the club's meetings and workshops: the Zod schema, the publishability validator, and the authored data itself

Readme

@devdogsuga/events

Config-as-code for the club's meetings and workshops and the check-in survey's questions: Zod schemas, a publishability validator, and the authored data itself (src/data/meetings.json, src/data/questions.json).

import { getClubConfig } from "@devdogsuga/events";

const config = getClubConfig(); // parses + validates src/data/meetings.json, or throws

Editing the data files

Each data file names its JSON Schema in $schema (src/data/meetings.schema.json, src/data/questions.schema.json), so VS Code, JetBrains and other JSON-aware editors complete keys and choices, show each field's description on hover, and flag a misspelled key or an over-long title as you type. Both schemas are generated from the Zod schemas below; after changing one, run

pnpm --filter @devdogsuga/events codegen

(a test fails when the committed files drift). The editor catches shape mistakes only; rules across fields or files (endsAt after startsAt, a meeting listing a question that exists) are check:events's.

Every meeting has a slug: its address on the platform (/events/<slug>) and the URL printed on its posters. It is the meeting's Eastern date (2026-10-14), plus a lowercase descriptor when another meeting shares the date (2026-10-05-judging and 2026-10-05-workshop). check:events refuses a duplicate slug or one whose date isn't the meeting's own.

The slug is also the meeting's identity: the platform matches its rows on it. Changing one makes a new meeting, and the old one is archived along with the attendance recorded against it, so set it once. A workshop's identity is its title within its meeting, so two workshops in one meeting can't share a title.

questions.json holds every survey question (src/questions.ts). A member question is one answer per person, asked until answered and then editable; a meeting question is asked at each meeting whose questions lists its id. Ids are permanent once answered: retire a question or option rather than deleting it.

Two kinds of "is this config good"

  • schema.ts is the STRUCTURAL half: does a file have the right shape and types. It mirrors the meetings and workshops columns the product actually reads today, minus everything that exists only for a synced wire format (foreign record ids, sync-status bookkeeping, attendance counts) — config has no such plumbing. Its length/host constants (e.g. MEETING_SUMMARY_MAX_LENGTH, RSVP_URL_ALLOWED_HOSTS) are duplicated from, and must never be looser than, the check constraints in the product's own supabase/migrations/*_platform_events_core.sql — config is upstream of Postgres, so a file this schema accepts must always be a row Postgres accepts too.
  • validator.ts is the PUBLISHABILITY half: whether a structurally valid file's content can go on a public page — a summary that fits its card, an RSVP link on an allowlisted host. Run separately from the schema so a shape error and a publishability error are never confused for each other in CI output.

getClubConfig() (and parseClubConfig(), its in-memory counterpart) run both steps in order and throw a readable ClubConfigError if either fails.

check — the CI gate

pnpm --filter @devdogsuga/events check:events

Checks the committed src/data/meetings.json and src/data/questions.json, each against its schema and then together, and prints a pass/fail summary. This is the only place a config author gets a readable validation error — the runtime reader trusts what it parses and refuses to partially apply a bad file rather than re-validating field by field. Wired into .github/workflows/ci.yaml as a merge-blocking step, matching how it gates merges in the product repo.

Consumers

DevDogsUGA's platform app (server/config/reconcile.ts) and its packages/devtools both import @devdogsuga/events for the published config; packages/events no longer exists in that repo.