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

@wral/hsot-score-report

v0.1.5

Published

Lit web component for the HighSchoolOT "Report a Score" page: an anonymous form, driven by an api-forms document, that e-mails the HSOT desk through the HSOT stage of api-forms. Purely an e-mail — a person reads every report before a score is entered.

Readme

@wral/hsot-score-report

Lit web component for the HighSchoolOT "Report a Score" page. An anonymous form — sport, where the game stands, both teams with scores, and optionally the game date, time, who is reporting and a note — that replaces the legacy Diesel form at /content/page/12766776/ and keeps its model.

It is purely an e-mail. The report goes to the HSOT stage of api-forms, which e-mails the HSOT desk. A person reads every report before a score is entered, because reports are sometimes wrong or fake. Nothing here writes to a game; the api-hsot calls this component makes are reads.

Self-contained on purpose: no runtime dependency on web-components.hsot-data. Those components link to this page (the box score's "Report a score for this game", the scoreboard's "report a score", via their report-href template); the page itself is mounted by templates.hsot-web.data-page at /report-a-score/.

Usage

From the CDN (self-contained, registers the element):

<script type="module"
	src="https://web-components.cdn.highschoolot.com/hsot-score-report/v0/define.standalone.js"></script>
<hsot-score-report
	api="https://api.highschoolot.com/hsot/v1/public"
	forms-api="https://api.highschoolot.com/forms"></hsot-score-report>

From npm:

import '@wral/hsot-score-report/define';   // registers hsot-score-report
// or
import { HsotScoreReport } from '@wral/hsot-score-report';

Attributes and properties

| Name | Kind | Default | Purpose | | --- | --- | --- | --- | | forms-api | attribute | https://api.highschoolot.com/forms | The HSOT api-forms stage: the form document and the anonymous submit | | form-id | attribute | hsot-score | The form document to render and submit | | api | attribute | https://api.highschoolot.com/hsot/v1/public | api-hsot's public read surface: pre-fill from a game, school typeahead | | game-id | attribute | — | Pre-fill from the game on record; also read from ?game= in the page URL | | game-href, section-href | attributes | /{sport}/game/{id}/, /{sport}/{view}/ | Link templates for the pre-fill banner's box score and the done view's "back to scores" | | promo-image, promo-href, promo-alt | attributes | — | Sponsor banner across the top of the view (image required; unlinked without an href) | | slot="rail" | light-DOM children | — | Right rail (300px column at 1200px and up, stacked below on smaller screens) | | formsClient | property | — | Any object with getListing (or listForms), createAnonSession, putRequest (see src/lib/forms-client.mjs); wins over forms-api | | client | property | — | Any object with getGame, getTeam, getSchool, searchSchools (see src/lib/hsot-client.mjs); wins over api |

Styling: design tokens are read as var(--color-…, fallback) with the HSOT style-guide literals as fallbacks (mirroring hsot-data's styles.mjs), so the component renders correctly with no token stylesheet on the page.

How it works

The fields come from the form document. On load the component fetches the hsot-score document from the forms stage — the HSOT content stage holds only this form, so the stage's public listing is the fetch — and, when a game-id is present, the game with its teams and schools from api-hsot. The document opens with a choice of the 26 gendered sports; each option leads to a collect node holding that sport's period family (quarters, halves, innings, or final-only) — the quarters and halves nodes also carry an optional "time left in the period" text field, which the component shows only for those sports — then the shared team, score and detail fields. src/lib/score-report.mjs walks it, so the select options, the field limits, the request path and the confirmation copy all come from the seeded document (seed/form-hsot-score.json in api-forms, copied to src/demo/fixtures/), and the server validates against the same document.

The listing also says what the stage allows. GET /v1/forms carries anonymous: { enabled, humanCheck } (api-forms DEV-1270). When enabled is false the page says score reporting is unavailable at load rather than at submit; when humanCheck names a proof-of-human provider, the page says the same, because this component renders no captcha widget — adding one is the next step if a stage ever turns a provider on. A stage from before the block sends nothing, which reads as enabled.

Client-side validation mirrors the server: required fields, whole-number scores from 0 to 999, lengths from the document, a real calendar date, a 24-hour time. The team inputs are free text with a typeahead against api-hsot's school search; picking a school also records its id (homeSchoolId / awaySchoolId), and typing over it drops the id.

Submit is api-forms' anonymous flow (DEV-1270):

  1. Mint a uuid requestId once per report and keep it across retries.
  2. POST /v1/anon/sessions with { formId, requestId } → a session token, cached until shortly before it expires.
  3. PUT /v1/requests/{requestId} with the token and keyed string answers for the walked path (text/select/textarea kinds only — api-forms has no numeric field, so scores travel as strings). The response carries the RI-… reference and the confirmation copy the done view shows.

The HSOT stage keeps no record. Its ANON_SAVE_CONTENT is false (api-forms DEV-1270; the listing advertises it as anonymous.saveContent), so a report is validated and e-mailed with nothing written to the HSOT content stage — the desk e-mail is the only copy, and a person reads it before any score is entered. Two consequences the component relies on: a failed desk e-mail comes back as a 502 (shown as a retryable banner) rather than a saved record with routing.state: failed, and a retry sends a fresh e-mail rather than replaying a stored submission. The done view's routing.state: failed copy remains for a stage that does save records.

A 401 re-mints the session once and retries. A 409 (the document changed) refetches it and asks the visitor to check their answers. Everything else is a banner by kind: unreachable, throttled (the server's message), a refused field, "temporarily unavailable" (anonymous submission off on the stage, or the form not published there), or a commit error that is safe to retry. A second click while a send is in flight is ignored, and the request id never changes across retries.

Development

Requires Node 18+.

npm install
npm run dev     # harness on http://localhost:5175
npm test        # node --test over src/lib
npm run lint
npm run build   # dist/index.mjs + dist/define.mjs (lit external)
                # and dist/define.standalone.js (self-contained, for <script src>)

The harness (index.html) mounts the component against the in-memory demo client (src/demo/demo-client.mjs), which stands in for both backends: #/game_015 pre-fills from a final, #/game_016 from a scheduled game, ?rail turns on the promo and right rail, ?demofail=1 makes the first commit fail as a network error, ?anonoff=1 shows the stage-has-anonymous-off state. Submits are logged to the console.

Release

Push a vX.Y.Z tag: the pipeline tests, builds, publishes to npm, and uploads dist/ to the HSOT components CDN at /hsot-score-report/vX.Y.Z/ (immutable) plus the rolling aliases /hsot-score-report/vX/, /vX.Y/ and /latest/ (5-minute TTL). Pages pin the major alias (/hsot-score-report/v0/). Repo variables: NPM_TOKEN, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, S3_BUCKET (the bucket behind web-components.cdn.highschoolot.com), S3_PREFIX=hsot-score-report, AWS_DISTRIBUTION_ID.

Before the page works on a stage

The component itself needs nothing deployed; the HSOT api-forms stage does:

  • An api-forms-hsot lambda with CONTENT_API at the HSOT content stage, a service JWT with email:send, ANON_SUBMIT_ENABLED plus a signing secret, FORMS_EMAIL_LIST_OVERRIDE set to the desk's Sailthru list, and a verified sender — and a /forms resource in the gateway stage that api.highschoolot.com fronts.
  • The score form seeded there: node scripts/seed-forms.mjs hsot-score in api-forms, pointed at the HSOT content stage.

Until then the page says score reporting is temporarily unavailable.