
Security News
Free Certified Patch for Critical Rails Active Storage Vulnerability
Socket has released a free Certified Patch for a critical Rails Active Storage vulnerability, giving developers time to upgrade to a secure Rails version.
@wral/hsot-score-report
Advanced tools
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.
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/.
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';
| 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.
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):
requestId once per report and keep it across retries.POST /v1/anon/sessions with { formId, requestId } → a session token,
cached until shortly before it expires.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.
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.
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.
The component itself needs nothing deployed; the HSOT api-forms stage does:
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.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.
FAQs
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.
We found that @wral/hsot-score-report demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 7 open source maintainers collaborating on the project.

Security News
Socket has released a free Certified Patch for a critical Rails Active Storage vulnerability, giving developers time to upgrade to a secure Rails version.

Security News
/Threat Research
A malicious Ruby gem runs a credential-stealing worm during installation, poisons AI coding tools, and can wipe files when a stolen GitHub token is revoked.

Security News
GitHub is tightening GitHub Actions security with new restrictions on privileged pull request workflows. Here's what changes and how maintainers are affected.