"""Open Meet Exchange types, version 1.0. Generated from meet-document-v1.schema.json by `npm run sync:omx`; the schema is the authority. Readers ignore keys they do not know, so a received document may carry more than these types name; a reader ignores them (OMX-R129). Dedicated to the public domain under CC0 1.0. """ from __future__ import annotations from typing import Any, Literal, NotRequired, TypedDict Id = str ExternalIds = dict[str, str] LaterValue = str DateTime = str CalendarDate = str AthleteGender = Literal["M", "F", "X"] EventGender = Literal["M", "F", "X", "C"] Sport = Literal["xc", "tf-indoor", "tf-outdoor", "run"] | LaterValue MarkUnit = Literal["ms", "mm", "in", "pt"] | LaterValue EntryStatus = Literal["e", "scr", "wait", "s", "dnf", "dns", "dq", "fs", "nr"] EventCode = str | LaterValue class Mark(TypedDict): """A seed or performance. `value` is a number in the unit the writer measured in, so nothing is converted before the reader sees it: ms for times, mm or in for distances and heights, pt for points, as the event's code ranks. ms, mm, and pt are integers; in is decimal inches to at most two places (16-06.25 is 198.25). Compare on `value`; print `display`, the writer's own formatting, which is never parsed.""" value: float unit: MarkUnit display: NotRequired[str] source: NotRequired[str] """On a seed: where the mark came from, e.g. `season_best`, `coach_entered`, `previous_meet`. Free text; shown to the timer, never interpreted.""" achieved_on: NotRequired[CalendarDate] class Split(TypedDict): """One intermediate time: where it was taken (a marker, a relay leg, or both) and the elapsed time there.""" marker_id: NotRequired[Id] """Where the split was taken, by its `id` in the event's `markers`.""" leg: NotRequired[int] """For a relay, the leg this split ends: `1` is the first leg.""" time_ms: int """Elapsed milliseconds from the same start as `result`: the gun for the athlete's race or wave. A relay leg's split is the running clock when that leg finished. A Publisher subtracts two splits to show one stretch.""" class HeaderGenerator(TypedDict): """The product that wrote this copy: Registration's product in a registration document, Meet Operations' product in a results document.""" id: str """The writer's system id: lowercase letters, digits, and `_`, at most 32, any name the writer picks, chosen once and never changed, such as `2t` for 2Timer; nobody assigns it. Other documents carry this product's ids in `external_ids` under it.""" name: str """The product's name as people know it, e.g. ExampleRegistration or 2Timer.""" version: NotRequired[str] """The product's own version, e.g. 3.4.""" class Header(TypedDict): """About this copy of the document: the format version, its kind, which product wrote it, and, in a results document, what it covers and when the meet last changed.""" version: str """Format version as MAJOR.MINOR. A reader accepts any minor within a major it implements and ignores fields it does not know; a major it does not implement is refused with a message naming both versions. A draft document carries its draft number (`0.1` to `0.9`), which a 1.x reader refuses; a reader checks the version before validating.""" kind: Literal["registration", "results"] """Which handoff this is. `registration`: written by Registration, who entered. `results`: written by Meet Operations, what happened. Closed: a reader refuses a document whose kind it does not know, or that is not the kind it reads (Meet Operations reads registration documents; a Publisher reads results documents).""" update: NotRequired[Literal["full", "partial"] | LaterValue] """Results documents only: what the document covers. `full`: the whole meet as it stands; the Publisher replaces everything it holds for the meet. `partial`: only the rounds it carries, each whole; the Publisher replaces those rounds and the team scores the document carries, adds or updates the meet, divisions, groups, waves, events, teams, and athletes it carries by `id`, and changes nothing else. A Publisher refuses an `update` it does not know with 422 and never reads it as `full`.""" updated_at: NotRequired[str] """Results documents only, required there: when the meet's data last changed, not when this copy was sent. Orders documents: a Publisher applies a newer one, treats an equal one as a no-op, and refuses an older one with 409, whatever its `update`, comparing instants rather than text. Written to at least the millisecond, with a UTC offset; a reader accepts one with less. Any change moves it forward, including a deletion; it never goes backwards.""" generator: HeaderGenerator """The product that wrote this copy: Registration's product in a registration document, Meet Operations' product in a results document.""" class MeetVenue(TypedDict): name: NotRequired[str] address: NotRequired[str] city: NotRequired[str] region: NotRequired[str] """State, province, or county.""" postal_code: NotRequired[str] country: NotRequired[str] """ISO 3166-1 alpha-2, e.g. US.""" latitude: NotRequired[float] longitude: NotRequired[float] class MeetTrack(TypedDict): """Results documents only: the track the meet was run on, written by Meet Operations. Track and field only.""" length_m: NotRequired[float] """Lap length in metres. A 160-yard track is `146.304`.""" lane_count: NotRequired[int] straight_lane_count: NotRequired[int] shape: NotRequired[Literal["oval_flat", "oval_banked"] | LaterValue] """Open. A reader treats a value it does not know as absent.""" class MeetOrigin(TypedDict): """Results documents only: the product this meet started in. A meet's entries come from one Registration product. Registration's system id and name when the meet was built from a registration document, so records from Registration carry their ids in `external_ids` under `origin.id`; Meet Operations' own when the timer built the meet, so no record carries a Registration id.""" id: str """That product's system id: its `omx.generator.id`.""" name: str """That product's name: its `omx.generator.name`, e.g. ExampleRegistration.""" class Meet(TypedDict): id: Id external_ids: NotRequired[ExternalIds] name: str sport: Sport start_date: CalendarDate end_date: NotRequired[CalendarDate] time_zone: NotRequired[str] """IANA time zone, e.g. America/New_York: the zone the meet's dates and schedule are in. Optional. Without it, dates are the meet's own local calendar dates as written, and each date-time is read by its own UTC offset.""" venue: NotRequired[MeetVenue] track: NotRequired[MeetTrack] """Results documents only: the track the meet was run on, written by Meet Operations. Track and field only.""" notes: NotRequired[str] """For the timer only. Meet Operations leaves it out of every results document, and a Publisher never publishes it.""" origin: NotRequired[MeetOrigin] """Results documents only: the product this meet started in. A meet's entries come from one Registration product. Registration's system id and name when the meet was built from a registration document, so records from Registration carry their ids in `external_ids` under `origin.id`; Meet Operations' own when the timer built the meet, so no record carries a Registration id.""" class Division(TypedDict): id: Id name: str short_name: NotRequired[str] sequence: int gender_names: NotRequired[dict[str, str]] """What this division calls each gender's contest, keyed by event gender, e.g. {"M": "Boys", "F": "Girls", "C": "Mixed"}.""" class Span(TypedDict): min: NotRequired[int] max: NotRequired[int] class GradeSpan(TypedDict): """Grades as Registration labels them ("9", "12", "K").""" min: NotRequired[str] max: NotRequired[str] class Group(TypedDict): """An award group within a race: an age group in a road race, JV within a varsity cross country race. Age and grade spans are inclusive at both ends; an age span is matched against the athlete's `age`.""" id: Id name: str event_id: NotRequired[Id] """The race this group awards within. Absent means every event.""" gender: EventGender """Who the group is for. `C` groups everyone in the age or grade span; `X` is a non-binary group.""" age: NotRequired[Span] grade: NotRequired[GradeSpan] award_count: NotRequired[int] class EventAdaptive(TypedDict): """Marks an adaptive or para event: an event of the same code contested in an adaptive form. An adaptive event is a different event from the standard one with the same code; a reader that cannot hold adaptive events tells the operator and never merges one into the standard event.""" mode: Literal["wheelchair", "seated", "guided", "ambulatory"] | LaterValue """`wheelchair` a wheelchair race, `seated` a seated throw, `guided` run with a guide, `ambulatory` an adaptive event contested standing or running without a chair or guide. Open: a reader that does not know the value shows the event as adaptive with no mode.""" class EventMarkers(TypedDict): id: Id name: str """How the point is named on results: `1 Mile`, `2K`, `Swim`, `T1`.""" class Event(TypedDict): id: Id external_ids: NotRequired[ExternalIds] number: NotRequired[int] """Event number if one is assigned. Otherwise Meet Operations numbers in array order.""" name: str code: EventCode division_id: NotRequired[Id] gender: EventGender hurdle_height_mm: NotRequired[int] """Registration may suggest it; a results document carries the height used.""" implement_weight_g: NotRequired[int] """Registration may suggest it; a results document carries the weight used.""" multi_event_id: NotRequired[Id] """Results documents only: for a component of a multi-event (the 100 m of a decathlon), the id of the multi-event it belongs to. Meet Operations builds the component events; Registration sends the multi-event alone.""" notes: NotRequired[str] """For the timer only. Meet Operations leaves it out of every results document, and a Publisher never publishes it.""" adaptive: NotRequired[EventAdaptive] """Marks an adaptive or para event: an event of the same code contested in an adaptive form. An adaptive event is a different event from the standard one with the same code; a reader that cannot hold adaptive events tells the operator and never merges one into the standard event.""" markers: NotRequired[list[EventMarkers]] """Results documents only: the timing points on the course or track where splits are taken, in course order. An entry's `splits` name them by `id`. A relay's leg splits need no marker.""" rounds: NotRequired[list[Round]] """Results documents only: the rounds of this event, written by Meet Operations. Entries point at a round by number.""" class Team(TypedDict): id: Id external_ids: NotRequired[ExternalIds] code: str """Short display code, unique within the document (`LHS`, `NIKE`), at most 16 characters in a written document. A writer that holds a longer code writes a shortened one of its own, still unique; it never holds back the meet for it. An athlete with no team leaves out `team_id`; a team listed by name for unattached athletes sets `unattached`.""" name: str city: NotRequired[str] region: NotRequired[str] country: NotRequired[str] unattached: NotRequired[bool] """A team listed by name, such as Unattached, whose athletes compete for no team: they carry no points and take no scoring position.""" class Athlete(TypedDict): id: Id """Stable within the meet.""" external_ids: NotRequired[ExternalIds] first_name: NotRequired[str] """Given name. Absent for an athlete with one name.""" middle_name: NotRequired[str] last_name: str """Family name, or the athlete's only name when they have one.""" gender: NotRequired[AthleteGender] birth_date: NotRequired[CalendarDate] """Registration documents only: the athlete's birth date, sent instead of `age`, never with it. It never leaves Meet Operations.""" age: NotRequired[int] """In a registration document, the age Registration computed for this meet; an athlete carries `age` or `birth_date`, never both. In a results document, the age Meet Operations placed the athlete by, whether Registration sent an age or a birth date.""" grade: NotRequired[str] team_id: NotRequired[Id] """The athlete's team. An athlete with no team_id competes for no team: it carries no points and takes no scoring position.""" bib: NotRequired[str] """The athlete's bib for the meet. Registration may assign it, or leave it to the timer. In a results document it is the bib the athlete raced under. A runner with two bibs in one meet is two athletes.""" chip: NotRequired[str] """Registration documents only: the transponder id, when Registration assigned one.""" city: NotRequired[str] region: NotRequired[str] country: NotRequired[str] """ISO 3166-1 alpha-2 country code, upper case (`US`, `CA`).""" email: NotRequired[str] """Registration documents only, for the timer's use on meet day. Never in a results document, and a Publisher never publishes it.""" phone: NotRequired[str] """Registration documents only, for the timer's use on meet day. Never in a results document, and a Publisher never publishes it.""" exhibition: NotRequired[bool] """Exhibition, non-scoring athlete. Places and wins awards normally; never scores, never displaces, never takes a scoring slot, in any event the athlete enters. Separate from the team's `unattached` flag.""" notes: NotRequired[str] """For the timer only. Meet Operations leaves it out of every results document, and a Publisher never publishes it.""" class EntryRelay(TypedDict): """Relay entries. Team + letter + event is unique among the relay entries of a registration document.""" team_id: Id letter: str """The team's squad in this event: one upper-case letter, A for its first.""" legs: NotRequired[list[Id]] """Athlete ids in running order. May be shorter than the event's legs, may be empty, may name alternates after the running legs.""" class EntryGroupPlaces(TypedDict): group_id: Id """The award group, by its `id` in `groups`.""" place: int class EntryFieldSeries(TypedDict): order: int mark: NotRequired[Mark] """For a horizontal jump or throw, the measured mark, present when `outcome` is `o`. For a vertical jump, the bar height attempted, present on every attempt so a miss says what was missed.""" outcome: Literal["o", "x", "-", "r"] | LaterValue """`o` a valid attempt (a measured mark, or a height cleared), `x` a foul or miss, `-` a pass, `r` retired from the competition. Open: a reader treats a value it does not know as an attempt with no valid mark.""" wind_mps: NotRequired[float] """Wind for this attempt in metres per second, where the event records one per attempt.""" class Entry(TypedDict): """In a registration document: one athlete or relay entered in one event, with its seed and status, and no result fields. In a results document: one athlete or relay in one round of one event, with `round` required. A prelim and a final are two entries, each with its own `id`. No entry carries `external_ids`: a Publisher joins an entry to Registration through its athlete and event (a relay's team, letter, and event).""" id: Id event_id: Id athlete_id: NotRequired[Id] """Individual entries. Exactly one of `athlete_id` or `relay`. In a registration document, athlete + event is unique among individual entries.""" relay: NotRequired[EntryRelay] """Relay entries. Team + letter + event is unique among the relay entries of a registration document.""" seed: NotRequired[Mark] status: NotRequired[EntryStatus] group_id: NotRequired[Id] """Registration documents only: the award group Registration placed this entry in, when it does not follow from age and gender alone.""" wave_id: NotRequired[Id] """The start wave this entry runs in, by its `id` in `waves`. A wave runner's `result` is timed from the wave's own gun.""" round: NotRequired[int] """Results documents only, required there: the round of the event this entry is in. Round-level state lives in `events[].rounds`. An athlete who competed in two rounds appears as two entries.""" heat: NotRequired[int] """Heat or flight number.""" lane: NotRequired[int] """Lane or position. Omitted where the event does not use lanes.""" result: NotRequired[Mark] """The recorded time or mark. For a timed event, the gun time: from the start signal for the athlete's race or wave, however the finish was captured. `value` is the stored value: times store to thousandths even where an event shows hundredths, and two results tie only when equal at stored value. Absent on a finisher with no recorded value.""" net_result: NotRequired[Mark] """Net time: from the moment the athlete crossed the start line to the finish, where a start mat recorded it. Never a substitute for `result`, which stays the gun time. The round's `place_by` says which of the two decided places.""" overall_place: NotRequired[int] """Place across the whole round; on the round marked `final`, that is the event's place. A results entry carries exactly one of `overall_place` and `status`: a placed entry has no status. In a `started` round it is the place so far, which may still move. Two entries in one round with the same place are tied.""" heat_place: NotRequired[int] """Place within the heat.""" gender_place: NotRequired[int] """Place among athletes of the same gender, by the same clock as `overall_place`.""" group_places: NotRequired[list[EntryGroupPlaces]] """Places within the award groups the entry placed in.""" qualified: NotRequired[Literal["Q", "q", "qD", "qR", "qJ"] | LaterValue] """The letter the results print after this entry's result in a round before the event's last, as it advanced: `Q` by place, `q` by time or mark, `qD` won a draw for the last spot, `qR` advanced by the referee, `qJ` advanced by the Jury of Appeal (World Athletics CR 25.4). A field qualifier is `q`. Absent on a final and on any result that prints no letter. Open: a reader shows a value it does not know as written.""" flags: NotRequired[list[str]] """The timer's own flags on this result, in the order typed, as typed: a record (`MR`), a best (`PB`, `SB`), a standard met, a state qualifier at a regional (`Q`). Printed after the result and its `qualified`. Never a qualifier letter in a round before the event's last. Absent when there are none, which does not mean the result is not a record.""" wind_mps: NotRequired[float] """For a field result only: the wind in metres per second for the mark that counted. A race's wind is on its heat (`rounds[].heats[].wind_mps`).""" reaction_time_ms: NotRequired[int] """Reaction time from the start signal, in milliseconds, where the start was monitored.""" points: NotRequired[float] """Team-scoring value, whether or not it counted: the track points earned, or the cross country scoring position. One value per entry: every team score block that lists the entry uses it. The team standing's `role` says whether it counted. Absent for a runner on an incomplete or unattached team.""" multi_points: NotRequired[float] """On a component entry of a multi-event: the points that component earned. A multi-event entry's total is its `result`, in `pt`.""" splits: NotRequired[list[Split]] """Intermediate times, in the order they were taken.""" field_series: NotRequired[list[EntryFieldSeries]] """A field-event series in order. For a horizontal jump or throw, each attempt is one jump or throw. For a vertical jump, each attempt is one try at a bar height.""" official_note: NotRequired[str] """A note from the officials about this result, published with it: the rule a disqualification was under, a jump-off, a protest outcome.""" class PublishDestination(TypedDict): """One Publisher Meet Operations hands the results to. The credential here is separate from the document URL's; holding the read link never grants the right to write.""" id: Id """Identifier for this destination, unique within the document and stable for the life of the meet.""" label: NotRequired[str] """Human name for this destination, shown to the timer when they are asked to approve it. Strongly recommended: without one the timer is asked to trust a bare URL.""" url: str """Where Meet Operations POSTs each results document.""" token: str """Sent as `Authorization: Bearer ` on every handoff. Never placed in a query string. Issued by whoever runs this destination, with at least 128 bits from a cryptographically secure generator (22 or more base62 characters; 32 recommended). A readable prefix is allowed and does not count toward the 128 bits. The Publisher decides how long it works and answers 410 once it stops.""" deliver: NotRequired[Literal["final", "progressive", "live"] | LaterValue] """How often this destination wants results. `final` (the default): `full` documents once every round is official or cancelled, and again for each correction. `progressive`: a first `full` document, then `partial` ones as each round is seeded, goes official, or changes. `live`: everything `progressive` gets, plus a `partial` document every few seconds while a round runs. Meet Operations may always send `full` instead of `partial`. Open: a value Meet Operations does not know is read as `final`.""" content: NotRequired[list[Literal["results", "start_lists"] | LaterValue]] """What this destination wants. `results` (the default): entries once a round is under way. `start_lists`: also heat-sheet entries for rounds that have not run yet. Open: Meet Operations ignores a value it does not know.""" accepts: NotRequired[list[str]] """The Open Meet Exchange versions this destination reads, newest first, such as ["1.0"]. Listing a version accepts every later minor of its major: ["1.0"] reads every 1.x. Optional: without it, Meet Operations writes a version of the major of the document or card that named this destination. Meet Operations sends only a major listed here.""" class RoundPlaceBy(TypedDict): """Which time decided places in a round that has net times: `gun` (`result`) or `net` (`net_result`). Absent when the round has gun times only, which then decide every place.""" overall: NotRequired[Literal["gun", "net"]] """Overall and gender places.""" groups: NotRequired[Literal["gun", "net"]] """Places within award groups (`group_places`).""" class RoundHeats(TypedDict): heat: int started_at: NotRequired[DateTime] """When the heat's start signal went, as recorded.""" wind_mps: NotRequired[float] """Official wind for the heat in metres per second, where one is recorded.""" class Round(TypedDict): """Round-level state, written by Meet Operations. Entries point at a round by `round` number.""" round: int label: NotRequired[str] """How the round is named on paperwork, e.g. Prelims, Final. Shown, never used to decide which round is the final.""" final: NotRequired[bool] """True on the round whose places are the event's result, including the only round of a single-round event. Omitted on every other round, and on every round while the final is not yet known. On a round that is not the final, `overall_place` is the place across that round only.""" status: Literal["upcoming", "started", "cancelled", "unofficial", "under_review", "official"] | LaterValue """Where the round stands. `upcoming` not run yet; `started` under way, some results may be in; `cancelled` will not run; `unofficial` every heat has run and results may still change; `under_review` a protest or review is open; `official` final, unless a correction follows. Open, and fails safe: a reader treats a value it does not know as not official.""" scheduled_at: NotRequired[DateTime] """When the round is planned to start. The meet's only schedule: a registration document carries none. A plan, never a start: when a heat went is its `started_at`.""" timing: NotRequired[Literal["hand", "fat", "transponder"] | LaterValue] """How times in this round were taken: `hand` (stopwatch or hand-operated timer), `fat` (fully automatic, photo-finish), `transponder` (chip). Omitted when Meet Operations does not record it. Open; a reader treats a value it does not know as absent.""" place_by: NotRequired[RoundPlaceBy] """Which time decided places in a round that has net times: `gun` (`result`) or `net` (`net_result`). Absent when the round has gun times only, which then decide every place.""" heats: NotRequired[list[RoundHeats]] """Heat or flight records for this round, where Meet Operations holds something about a heat itself. Entries still name their heat by number. A round run as one race, such as a cross country or road race, lists at most heat 1, to carry its started_at; an entry with no heat belongs to it.""" class TeamScoresScope(TypedDict): """What this standing covers: one event, one division across its events, or the whole meet, and whose standings they are.""" type: Literal["event", "division", "meet"] | LaterValue """Open: a reader that does not know the value skips the block rather than show standings it cannot label.""" id: NotRequired[Id] """The event or division id. Absent when `type` is `meet`.""" gender: EventGender """Whose standings these are, always present: `M`, `F`, or `X` when teams are scored separately by gender (a co-ed school's boys' and girls' scores are two blocks), `C` when the standings count every gender together.""" class TeamScoresStandingsEntries(TypedDict): entry_id: Id role: Literal["scorer", "displacer"] | LaterValue """`scorer` counted in the team total; `displacer` did not count but pushed other teams' runners back. Open; a reader treats a value it does not know as absent.""" class TeamScoresStandings(TypedDict): team_id: Id """The team, by its `id` in `teams`.""" place: NotRequired[int] """Two standings in one block with the same place are tied.""" points: NotRequired[float] complete: NotRequired[bool] """Whether the team fielded enough scorers to score. An incomplete team carries no `place`, no `points`, and no `entries`.""" entries: NotRequired[list[TeamScoresStandingsEntries]] """The entries that scored or displaced for this standing, so a results page can print a team's line without recomputing it. Each entry's own `points` is its value. Optional; Meet Operations writes it where it holds it.""" class TeamScores(TypedDict): """Team standings, written by Meet Operations when the meet is scored. Values arrive computed; render them, never recompute them.""" id: Id """This block's id, the same from one document to the next. A `partial` document replaces the blocks it carries by `id`.""" scope: TeamScoresScope """What this standing covers: one event, one division across its events, or the whole meet, and whose standings they are.""" standings: list[TeamScoresStandings] class Wave(TypedDict): """A start wave in a road or trail race. An entry names its wave with `wave_id`. Registration may assign waves; a results document carries the waves run.""" id: Id name: str offset_ms: NotRequired[int] """How long after the start of the athlete's event this wave started, in milliseconds. A `result` is already timed from the wave's own start.""" class MeetDocument(TypedDict): """One JSON document that describes a meet, handed forward in one direction: Registration → Meet Operations → Publisher. `omx.kind` says which handoff it is: a registration document says who entered; a results document says what happened, one entry per athlete or relay per round. Readers ignore unknown fields. `id` is always the identifier of the product that wrote the document; `external_ids` carries the same record's ids in other products, keyed by system id, on the meet, events, teams, and athletes.""" omx: Header meet: Meet divisions: NotRequired[list[Division]] """Competition groupings that events belong to (Varsity, Masters 40–44, U12).""" groups: NotRequired[list[Group]] """Award groups within a race: age groups in a road race, JV within a varsity cross country race. Each names an event (or all events), a gender, and an age or grade span.""" waves: NotRequired[list[Wave]] """Start waves in road and trail races.""" events: list[Event] """What is contested, in running order. A results document adds `rounds`, and lists the component events of a multi-event.""" teams: list[Team] athletes: list[Athlete] entries: list[Entry] """In a registration document, one entry per athlete or relay per event: who entered. In a results document, one entry per athlete or relay per round, with `round` required: what happened. A scratch in a registration document is an entry with `status: "scr"`, never a missing entry.""" publish: NotRequired[list[PublishDestination]] """Registration only: the destinations Meet Operations hands the results to, each with its own credential. Absent or empty means Registration does not want the meet back, which is a complete implementation. A results document carries no `publish`.""" team_scores: NotRequired[list[TeamScores]] """Team standings. Only in a results document, written by Meet Operations."""