Publishing Governor
The Publishing Governor provides methods for controlling the public visibility of tournament information through publish state management. These methods work in conjunction with Time Items to track what's published and when.
import { publishingGovernor } from 'tods-competition-factory';
See Publishing Concepts for comprehensive coverage of publishing workflows, rationale, and best practices.
getPublishState
Returns publishing details for tournament, event(s), and/or draws, enabling queries about current publish state before making changes. See examples: Queryable Publish State, Queryable Publish State.
Return All Publish State
const { publishState } = engine.getPublishState();
// Tournament-level state
const participantsPublished = publishState.tournament.participants.published;
const orderOfPlayPublished = publishState.tournament.orderOfPlay.published;
// Event-level state (accessed by eventId)
const eventState = publishState['eventId'].status;
const {
published, // boolean - is event published?
publishedDrawIds, // array of published draw IDs
drawDetails, // granular stage/structure details
} = eventState;
Query Specific Event
const { publishState } = engine.getPublishState({ eventId });
const eventPublished = publishState.status.published;
const publishedDraws = publishState.status.publishedDrawIds;
Query Specific Draw
const { publishState } = engine.getPublishState({ drawId });
const drawPublished = publishState.status.published;
// When only specific stages or structures are published
const drawPublishDetail = publishState.status.drawDetail;
// Example structure: { stages: ['MAIN'], structures: { [structureId]: { roundLimit: 2 } } }
Embargo Status
When embargoes are present, the return includes an embargoes array summarizing all active and expired embargoes across the tournament:
const { publishState } = engine.getPublishState();
// publishState.embargoes is present when any embargoes exist
publishState.embargoes?.forEach(({ type, id, embargo, embargoActive }) => {
console.log(`${type} ${id ?? ''}: ${embargo} (active: ${embargoActive})`);
});
Each entry in the embargoes array:
| Field | Type | Description |
|---|---|---|
type | string | 'draw', 'stage', 'structure', 'scheduledRound', 'orderOfPlay', or 'participants' |
id | string? | Identifier for the element. Absent for tournament-level types (orderOfPlay, participants). |
embargo | string | ISO 8601 timestamp |
embargoActive | boolean | true if the embargo is still in the future |
getPublishState intentionally ignores embargo timestamps when determining publish status. This is for admin/reporting use — embargoed elements appear as "published" so admin UIs can display their configuration correctly. See Embargo: Admin vs Public Behavior for details.
Use Cases:
- Verify current state before publishing
- Display publish status in admin UI
- Determine if re-publishing is needed
- Query embargo status and expiry times
- Build admin dashboards showing upcoming embargo releases
See: Embargo for comprehensive embargo documentation.
bulkUpdatePublishedEventIds
Updates which events are marked as published across multiple events simultaneously. Used for bulk publish state management.
const result = engine.bulkUpdatePublishedEventIds({
tournamentRecord, // required
publishedEventIds, // array of eventIds to mark as published
});
Returns:
{
success: boolean;
updatedCount?: number;
}
Purpose: Efficiently update publish status for multiple events at once, typically during tournament-wide publish operations.
getAllEventData
Returns comprehensive data for all events in a tournament, formatted for public display.
const { eventsData, tournamentInfo, venuesData } = engine.getAllEventData({
tournamentRecord, // required
policyDefinitions, // optional - privacy policies to apply
});
// eventsData structure
eventsData.forEach((event) => {
console.log(event.eventInfo); // Event details
console.log(event.scheduleTiming); // Timing information
event.drawsData.forEach((draw) => {
console.log(draw.drawInfo);
console.log(draw.matchUps); // Categorized matchUps
});
});
Returns:
{
eventsData: Array<{
eventInfo: EventInfo;
scheduleTiming: any;
drawsData: Array<{
drawInfo: DrawInfo;
matchUps: {
abandonedMatchUps: MatchUp[];
completedMatchUps: MatchUp[];
upcomingMatchUps: MatchUp[];
pendingMatchUps: MatchUp[];
};
}>;
}>;
tournamentInfo: TournamentInfo;
venuesData: Venue[];
}
Purpose: Get complete tournament data formatted for public websites, scoreboards, or apps.
getCourtInfo
Returns detailed information about a specific court, including availability and bookings.
const { courtInfo } = engine.getCourtInfo({
courtId, // required
tournamentRecord, // required
});
console.log(courtInfo.courtName);
console.log(courtInfo.dateAvailability);
Returns:
{
courtInfo: {
courtId: string;
courtName: string;
venueId: string;
dateAvailability?: DateAvailability[];
// ... other court properties
};
}
Purpose: Get complete court details for scheduling interfaces or public venue information.
getDrawData
Returns comprehensive draw data including structures, matchUps, and participant assignments, formatted for display.
const { drawInfo, structures } = engine.getDrawData({
drawDefinition, // required
tournamentRecord, // required
event, // required
usePublishState, // optional boolean - respect publish state
includePositionAssignments, // optional boolean - include draw positions
policyDefinitions, // optional - privacy policies
inContext, // optional boolean - add context to matchUps
});
Returns:
{
drawInfo: {
drawId: string;
drawName: string;
drawType: string;
// ... other draw properties
}
structures: Array<{
structureId: string;
structureName: string;
matchUps: MatchUp[];
roundMatchUps: { [roundNumber: string]: MatchUp[] };
positionAssignments?: PositionAssignment[];
// ... other structure data
}>;
success: boolean;
}
Purpose: Primary method for getting formatted draw data for display in brackets, schedules, or results pages.
When to Use:
- Building bracket displays
- Generating draw sheets
- Exporting draw data
- Public-facing draw views
Notes:
- Respects publish state when
usePublishState: true - Applies privacy policies to participant data
- Returns only published structures/rounds when appropriate
- Enforces embargo timestamps — embargoed structures are filtered out until the embargo passes
- Used internally by
getEventData
getEventData
Returns comprehensive event data including all draws, participants, and matchUps, formatted for public display.
const { eventData, participants } = engine.getEventData({
eventId, // required (or event object)
tournamentRecord, // required
usePublishState, // optional boolean - respect publish state
hydrateParticipants, // optional boolean - add full participant details
includePositionAssignments, // optional boolean - include draw positions
participantsProfile, // optional - control participant data included
policyDefinitions, // optional - privacy policies
contextProfile, // optional - control matchUp context
allParticipantResults, // optional boolean - include all results
});
Returns:
{
eventData: {
eventInfo: EventInfo;
drawsData: Array<{
drawInfo: DrawInfo;
structures: Structure[];
}>;
tournamentInfo?: TournamentInfo;
venuesData?: Venue[];
};
participants?: HydratedParticipant[];
success: boolean;
}
Purpose: Primary method for generating complete event data payloads for websites, apps, and scoreboards.
Use Cases:
- Publishing event data to public APIs
- Generating event pages
- Creating scoreboard displays
- Exporting event data
Publish State Integration:
- When
usePublishState: true, only returns published draws/structures - Respects round limits and stage restrictions
- Enforces embargo timestamps at draw, stage, and structure levels — embargoed content is hidden until the embargo passes
- Applies privacy policies
Notes:
- Most commonly used method for public data generation
- Automatically called by
publishEventto generate payload - Respects all display and privacy extensions
- Returns hydrated participants with complete details when requested
getEventPublishStatus
Returns detailed publish status for a specific event.
const { eventPublishStatus } = engine.getEventPublishStatus({
eventId, // required
tournamentRecord, // required
event, // optional - event object if already loaded
});
console.log(eventPublishStatus.published); // boolean
console.log(eventPublishStatus.publishedDrawIds); // array of draw IDs
console.log(eventPublishStatus.drawDetails); // granular details
Returns:
{
eventPublishStatus: {
published: boolean;
publishedDrawIds?: string[];
drawDetails?: {
[drawId: string]: {
stages?: string[];
structures?: {
[structureId: string]: {
roundLimit?: number;
published?: boolean;
};
};
};
};
};
}
Purpose: Query precise publish state for an event to determine what's visible.
getTournamentPublishStatus
Returns publish status for tournament-level items (participants, order of play).
const { publishStatus } = engine.getTournamentPublishStatus({
tournamentRecord, // required
});
console.log(publishStatus.participants.published); // boolean
console.log(publishStatus.participants.publishedAt); // ISO timestamp
console.log(publishStatus.orderOfPlay.published); // boolean
Returns:
{
publishStatus: {
participants: {
published: boolean;
publishedAt?: string;
};
orderOfPlay: {
published: boolean;
publishedAt?: string;
};
};
}
Purpose: Check if tournament-wide items like participants and order of play are published.
getVenueData
Returns formatted venue data for public display.
const { venueData } = engine.getVenueData({
venueId, // required
tournamentRecord, // required
});
console.log(venueData.venueName);
console.log(venueData.courts); // Array of court objects
console.log(venueData.venueAddress);
Returns:
{
venueData: {
venueId: string;
venueName: string;
venueAbbreviation?: string;
courts: Court[];
venueAddress?: Address;
// ... other venue properties
};
}
Purpose: Get complete venue information for public display, maps, or venue guides.
publishEvent
Publishes event draws and structures with fine-grained control over visibility. Generates optimized eventData payload and triggers PUBLISH_EVENT subscription notifications. See examples in Publishing All Draws.
Key Features:
- Publishes entire events or specific draws (flights)
- Stage-level control (MAIN, QUALIFYING, CONSOLATION)
- Structure and round-level granularity
- Embargo support for scheduled publication
- Privacy policy application
- Subscription notification with prepared payload
const { eventData } = engine.publishEvent({
eventId, // required - event to publish
// Draw selection (choose one approach)
drawIdsToAdd, // array - publish specific draws
drawIdsToRemove, // array - unpublish specific draws
drawDetails, // object - granular control (see below)
// Data preparation
eventDataParams, // optional - params for getEventData (not persisted)
policyDefinitions, // optional - privacy policies to apply
// State management
removePriorValues, // optional boolean - clear previous timeItems
});
Publishing Patterns
Publish All Draws in Event
engine.publishEvent({ eventId });
Publish Specific Draws (Flights)
// Shorthand
engine.publishEvent({
eventId,
drawIdsToAdd: ['drawId1', 'drawId2'],
});
// Remove draws from publication
engine.publishEvent({
eventId,
drawIdsToRemove: ['drawId3'],
});
Publish by Stage
import { stageConstants } from 'tods-competition-factory';
engine.publishEvent({
eventId,
drawDetails: {
[drawId]: {
stagesToAdd: [stageConstants.QUALIFYING],
publishingDetail: { published: true },
},
},
});
Round-by-Round Publishing
// Publish only first round of a structure
engine.publishEvent({
eventId,
drawDetails: {
[drawId]: {
structureDetails: {
[structureId]: {
roundLimit: 1,
published: true,
},
},
},
},
});
// Expand to include more rounds
engine.publishEvent({
eventId,
drawDetails: {
[drawId]: {
structureDetails: {
[structureId]: {
roundLimit: 3, // Now shows rounds 1-3
published: true,
},
},
},
},
});
Scheduled Rounds (Per-Round Schedule Control)
Use scheduledRounds within structureDetails for fine-grained control over which rounds' matchUps appear in the schedule. This is separate from roundLimit bracket filtering (which only applies to AD_HOC draws).
// Embargo round 2 schedule, explicitly hide round 3; round 1 unlisted → passes through
engine.publishEvent({
eventId,
drawDetails: {
[drawId]: {
structureDetails: {
[structureId]: {
published: true,
roundLimit: 3, // bracket ceiling (AD_HOC only)
scheduledRounds: {
2: { published: true, embargo: '2024-06-16T08:00:00Z' },
3: { published: false },
// round 1 not listed → passes through normally
},
},
},
},
},
});
Behavior:
roundLimitalways acts as a ceiling for the schedule (all draw types)scheduledRoundsis an override map — only rounds with an explicit entry are affected; unlisted rounds pass through normally{ published: false }explicitly hides the round (matchUps removed from results){ published: true, embargo: FUTURE }returns the matchUp without schedule data (schedule stripped) until the embargo passes- When
scheduledRoundsis absent, all rounds up toroundLimitappear in the schedule
Note: roundLimit only filters the bracket (draw data) for AD_HOC draw types. For elimination draws, the bracket always shows all rounds.
Publishing with Embargo
Embargo allows content to be marked as published but hidden from public queries until a specified time. The embargo field accepts an ISO 8601 timestamp string. Embargoes can be applied at draw, stage, and structure levels.
const embargoTime = new Date('2024-06-15T10:00:00Z').toISOString();
// Draw-level embargo — entire draw hidden until embargo passes
engine.publishEvent({
eventId,
drawDetails: {
[drawId]: {
publishingDetail: {
published: true,
embargo: embargoTime,
},
},
},
});
// Stage-level embargo — qualifying visible, main embargoed
engine.publishEvent({
eventId,
drawDetails: {
[drawId]: {
publishingDetail: { published: true },
stageDetails: {
QUALIFYING: { published: true },
MAIN: { published: true, embargo: embargoTime },
},
},
},
});
// Structure-level embargo — specific structure hidden
engine.publishEvent({
eventId,
drawDetails: {
[drawId]: {
publishingDetail: { published: true },
structureDetails: {
[structureId]: { published: true, embargo: embargoTime },
},
},
},
});
Embargoed content is automatically visible once the system clock passes the embargo timestamp — no second mutation needed.
Affected queries: getEventData, getDrawData, competitionScheduleMatchUps (when usePublishState: true).
Admin visibility: getPublishState ignores embargoes and reports full publish configuration including embargo metadata.
See: Embargo for comprehensive embargo documentation including workflows and admin vs public behavior.
Publishing with Privacy Policies
import { policyConstants } from 'tods-competition-factory';
const privacyPolicy = {
participant: {
contacts: false,
addresses: false,
individualParticipants: {
contacts: false,
addresses: false,
},
},
};
const { eventData } = engine.publishEvent({
eventId,
policyDefinitions: {
[policyConstants.POLICY_TYPE_PARTICIPANT]: privacyPolicy,
},
});
Customizing Event Data Payload
Event data parameters are not persisted in publish state. Client applications must pass their own parameters when querying with usePublishState: true.
// Server-side publishing
const { eventData } = engine.publishEvent({
eventId,
eventDataParams: {
allParticipantResults: true,
participantsProfile: {
withISO2: true,
withIOC: true,
},
},
});
// Client must pass same params when querying
const { eventData: clientData } = engine.getEventData({
eventId,
usePublishState: true,
allParticipantResults: true,
participantsProfile: { withISO2: true, withIOC: true },
});
See: Publishing Concepts for details on eventData structure.
publishEventSeeding
Publishes event seeding information separately from draw structures, enabling flexible control over when seeding becomes publicly visible. See examples: Publishing Seeding, Publishing Seeding, Coordinated Event and Seeding Release.
Why Separate Seeding Publication:
- Prevent participants from knowing seeded positions before draws finalized
- Announce seeded players separately from draw structure
- Update seeding without re-publishing entire draw
- Different scales for different stages
engine.publishEventSeeding({
eventId, // required
// Scale selection
seedingScaleNames, // optional - array of scale names
stageSeedingScaleNames, // optional - { MAIN: 'scale1', QUALIFYING: 'scale2' }
// Draw selection
drawIds, // optional - publish specific draws only
// State management
removePriorValues, // optional boolean - clear previous timeItems
});
Examples
Publish All Seeding
engine.publishEventSeeding({ eventId });
Publish Specific Scales
engine.publishEventSeeding({
eventId,
seedingScaleNames: ['U18', 'WTN'],
});
Different Scales per Stage
engine.publishEventSeeding({
eventId,
stageSeedingScaleNames: {
MAIN: 'U18',
QUALIFYING: 'U18Q',
},
});
Publish Specific Flights
engine.publishEventSeeding({
eventId,
drawIds: ['flight1', 'flight2'],
});
publishOrderOfPlay
Publishes scheduled matchUps (Order of Play), controlling visibility of which matches are scheduled for which courts and times. See examples in Publishing Scheduled MatchUps.
Why Order of Play Publishing:
- Prepare schedules internally before announcing
- Make scheduling changes before public release
- Coordinate releases with media partners
- Publish each day's schedule separately
engine.publishOrderOfPlay({
scheduledDates, // optional - array of dates to publish
eventIds, // optional - array of events to publish
embargo, // optional - ISO 8601 timestamp; schedule hidden until this time
removePriorValues, // optional boolean - clear previous timeItems
});
Examples
Publish All Scheduled MatchUps
engine.publishOrderOfPlay();
Publish Specific Dates
engine.publishOrderOfPlay({
scheduledDates: ['2024-06-15', '2024-06-16'],
});
Publish Specific Events
engine.publishOrderOfPlay({
eventIds: ['singles-main', 'doubles-main'],
});
Daily Publication
// Each morning, publish that day's schedule
const today = new Date().toISOString().split('T')[0];
engine.publishOrderOfPlay({
scheduledDates: [today],
removePriorValues: false, // Keep previous days published
});
Publish with Embargo
// Schedule becomes visible after 6pm the evening before
engine.publishOrderOfPlay({
scheduledDates: ['2024-06-15'],
embargo: '2024-06-14T18:00:00Z',
});
When embargoed, competitionScheduleMatchUps with usePublishState: true returns empty dateMatchUps until the embargo passes.
See: Embargo for comprehensive embargo documentation.
Replace All Previous Publications
engine.publishOrderOfPlay({
scheduledDates: ['2024-06-15'],
eventIds: ['singles-main'],
removePriorValues: true, // Clear all previous
});
Query Published Schedules:
const { dateMatchUps } = engine.competitionScheduleMatchUps({
usePublishState: true, // Only returns published matchUps
});
See: Query Governor - competitionScheduleMatchUps
publishParticipants
Publishes the tournament participant list, controlling when participant information becomes publicly visible. See examples: Why Participant Publishing?, Why Participant Publishing?.
Why Participant Publishing:
- Accept entries internally before announcing participant list
- Control when participant information becomes public
- Coordinate announcements with promotional campaigns
- Staged announcements (wildcards separate from direct acceptances)
engine.publishParticipants({
embargo, // optional - ISO 8601 timestamp; participant list hidden until this time
removePriorValues, // optional boolean - clear previous timeItems
});
Examples
Publish Participants
engine.publishParticipants();
Publish with Embargo
// Participant list visible after 9am on June 10th
engine.publishParticipants({
embargo: '2024-06-10T09:00:00Z',
});
See: Embargo for comprehensive embargo documentation.
Replace Previous Publication
engine.publishParticipants({
removePriorValues: true,
});
setEventDisplay
Sets display configuration for event data, controlling which attributes are visible for specific draws and dates. See examples: Display Settings.
engine.setEventDisplay({
eventId, // required
displaySettings, // required - display configuration object
removePriorValues, // optional boolean - clear previous settings
});
Purpose: Fine-grained control over data visibility in published events, for privacy compliance and progressive disclosure.
unPublishEvent
Removes event from public visibility. Triggers UNPUBLISH_EVENT subscription notification. See examples: Unpublishing Events.
engine.unPublishEvent({
eventId, // required
removePriorValues, // optional boolean, defaults to true
});
Examples
// Unpublish event (removes timeItems)
engine.unPublishEvent({ eventId });
// Unpublish without removing timeItems
engine.unPublishEvent({
eventId,
removePriorValues: false,
});
Use Cases:
- Draw corrections needed before re-publishing
- Event cancelled or postponed
- Major scheduling changes requiring republication
- Remove from public site while maintaining internal data
unPublishEventSeeding
Removes seeding information from public visibility. See examples: Unpublishing Seeding.
engine.unPublishEventSeeding({
eventId, // required
stages, // optional - array of stages to unpublish
removePriorValues, // optional boolean, defaults to true
});
Examples
Unpublish All Seeding
engine.unPublishEventSeeding({ eventId });
Unpublish Specific Stages
engine.unPublishEventSeeding({
eventId,
stages: [stageConstants.MAIN, stageConstants.QUALIFYING],
});
Use Cases:
- Seeding corrections needed
- Change seeding methodology
- Remove seeding before draw changes
unPublishOrderOfPlay
Removes Order of Play from public visibility. See examples: Unpublishing Order of Play.
engine.unPublishOrderOfPlay({
removePriorValues, // optional boolean, defaults to true
});
Examples
// Unpublish all schedules
engine.unPublishOrderOfPlay();
// Keep timeItems
engine.unPublishOrderOfPlay({
removePriorValues: false,
});
Use Cases:
- Major scheduling changes
- Venue changes affecting schedule
- Weather delays requiring reschedule
- Remove from public pending updates
unPublishParticipants
Removes participant list from public visibility. See examples: Unpublishing Participants.
engine.unPublishParticipants({
removePriorValues, // optional boolean, defaults to true
});
Examples
// Unpublish participants
engine.unPublishParticipants();
Use Cases:
- Entry deadline extended
- Major withdrawals requiring list update
- Corrections to participant information
Integration Patterns
Subscription-Based Publishing
import { topicConstants } from 'tods-competition-factory';
const subscriptions = {
[topicConstants.PUBLISH_EVENT]: async (payload) => {
const { eventData, eventId } = payload;
// Update public website
await fetch('https://public-site.com/api/events', {
method: 'POST',
body: JSON.stringify(eventData),
});
},
[topicConstants.PUBLISH_ORDER_OF_PLAY]: async (payload) => {
const { dateMatchUps } = payload;
// Update schedule displays
await updateScheduleDisplay(dateMatchUps);
},
[topicConstants.UNPUBLISH_EVENT]: async (payload) => {
const { eventId } = payload;
// Remove from public site
await removeFromPublicSite(eventId);
},
};
engine.devContext({ subscriptions });
Database Synchronization
[topicConstants.PUBLISH_ORDER_OF_PLAY]: async (payload) => {
const { dateMatchUps } = payload;
await database.updatePublishedSchedule(dateMatchUps);
cache.invalidate('schedules');
}
Cache Management
[topicConstants.UNPUBLISH_EVENT]: (payload) => {
const { eventId } = payload;
cache.invalidate(`event:${eventId}`);
cache.invalidate('published-events-list');
}
Related Documentation
- Publishing Concepts - Comprehensive workflows and best practices
- Embargo - Time-based visibility control for published content
- Time Items - How publish state is stored
- Subscriptions - Notification system
- Query Governor - Methods using publish state with embargo enforcement
- Policies - Privacy and display policies