@ttt-productions/q-core 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants/business.js.map +1 -1
- package/dist/constants/sports.js.map +1 -1
- package/dist/constants/storage-keys.js.map +1 -1
- package/dist/doc-schemas/catalogs.js.map +1 -1
- package/dist/doc-schemas/game-location.js.map +1 -1
- package/dist/doc-schemas/game-stats.js.map +1 -1
- package/dist/doc-schemas/league-team.js.map +1 -1
- package/dist/doc-schemas/pending-media.js.map +1 -1
- package/dist/doc-schemas/registry.js.map +1 -1
- package/dist/doc-schemas/sport-game.js.map +1 -1
- package/dist/doc-schemas/system.js.map +1 -1
- package/dist/doc-schemas/user-profile.js.map +1 -1
- package/dist/doc-schemas/waiver-template.js.map +1 -1
- package/dist/doc-schemas/waivers-and-hardware.js.map +1 -1
- package/dist/ids/index.js.map +1 -1
- package/dist/ids/minted-ids.js.map +1 -1
- package/dist/ids/stats-operation-ids.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/media/file-origins.js.map +1 -1
- package/dist/paths/collection-refs.js.map +1 -1
- package/dist/paths/collections.js.map +1 -1
- package/dist/paths/path-builders.js.map +1 -1
- package/dist/paths/utils.js.map +1 -1
- package/dist/schemas/account-settings.js.map +1 -1
- package/dist/schemas/atoms.js.map +1 -1
- package/dist/schemas/awards.js.map +1 -1
- package/dist/schemas/hardware-loan-contracts.js.map +1 -1
- package/dist/schemas/schedules.js.map +1 -1
- package/dist/schemas/scoring.js.map +1 -1
- package/dist/schemas/stats.js.map +1 -1
- package/dist/schemas/team-joining.js.map +1 -1
- package/dist/schemas/teams.js.map +1 -1
- package/dist/schemas/uploads.js.map +1 -1
- package/dist/schemas/users.js.map +1 -1
- package/dist/sports/basketball-scoring.js.map +1 -1
- package/dist/sports/basketball.js.map +1 -1
- package/dist/sports/bulk-entry.js.map +1 -1
- package/dist/sports/contribution.js.map +1 -1
- package/dist/sports/curling-scoring.js.map +1 -1
- package/dist/sports/finalized-record.js.map +1 -1
- package/dist/sports/football-scoring.js.map +1 -1
- package/dist/sports/index.js.map +1 -1
- package/dist/sports/rankings.js.map +1 -1
- package/dist/sports/rollup-check.js.map +1 -1
- package/dist/sports/scoring.js.map +1 -1
- package/dist/sports/store-driver.js.map +1 -1
- package/dist/types/documents.js.map +1 -1
- package/dist/types/notifications.js.map +1 -1
- package/dist/types/picture-owners.js.map +1 -1
- package/dist/types/sports.js.map +1 -1
- package/dist/types/stats.js.map +1 -1
- package/dist/types/unions.js.map +1 -1
- package/dist/utils/account-status.js.map +1 -1
- package/dist/utils/app-config.js.map +1 -1
- package/dist/utils/app-routes.js.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/league-calendar.js.map +1 -1
- package/dist/utils/league-mode.js.map +1 -1
- package/dist/utils/team-member-actions.js.map +1 -1
- package/package.json +90 -90
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-driver.js","sourceRoot":"","sources":["../../src/sports/store-driver.ts"],"names":[],"mappings":"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","sourcesContent":["// The store driver's decision half: what one scoring write does with the batch of events it was\r\n// sent, given what the game already holds. It owns ids, the sequence, void resolution, and the fold;\r\n// everything sport-shaped is the adapter's (SPORT-003). The writing core reads the game, the stored\r\n// events the batch names, and the roster entries it names, hands them here, and writes what comes\r\n// back — one transaction, all or nothing.\r\n//\r\n// An event id is the idempotency key (SPORT-102): an id already stored, or earlier in the batch, is\r\n// acknowledged when its content matches and never applied again, so re-sending a batch whose first\r\n// send timed out after committing changes nothing. A void's id is derived from its target, so a\r\n// second undo of one event is the same document and is acknowledged too.\r\n\r\nimport type { GameStatEvent } from '../doc-schemas/game-stats.js';\r\nimport type { GameStats } from '../doc-schemas/sport-game.js';\r\nimport { buildStatVoidId } from '../ids/stat-event-ids.js';\r\nimport type { StatEventSubmission } from '../schemas/scoring.js';\r\nimport { STAT_EVENT_RECORDER_FIELD_KEYS, STAT_EVENT_SNAPSHOT_FIELD_KEYS } from '../types/stats.js';\r\nimport type { RecordedStatEventOutcome, StatEventRefusalCode } from '../types/stats.js';\r\nimport { foldStatEvent, withGameTeamLines } from './replay.js';\r\nimport {\r\n isSportStatEventIn,\r\n isStatCorrection,\r\n isStatVoid,\r\n type StatEventBody,\r\n type StatEventRoster,\r\n} from './scoring.js';\r\nimport type { AnySportAdapter, GameTeamIds } from './sport-adapter.js';\r\n\r\n/** The document id a submission is stored at. */\r\nexport function statEventSubmissionId(submission: StatEventSubmission): string {\r\n return isStatVoid(submission) ? buildStatVoidId(submission.targetEventId) : submission.eventId;\r\n}\r\n\r\n/**\r\n * The ids a batch reads before it decides anything: every submission's own id, and every void's\r\n * target — the driver needs the stored document at each, or knows none is stored. A correction's is\r\n * never read: the driver refuses one before it looks at the store.\r\n */\r\nexport function statEventIdsToRead(submissions: readonly StatEventSubmission[]): string[] {\r\n const ids = new Set<string>();\r\n for (const submission of submissions) {\r\n if (isStatCorrection(submission)) continue;\r\n ids.add(statEventSubmissionId(submission));\r\n if (isStatVoid(submission)) ids.add(submission.targetEventId);\r\n }\r\n return [...ids];\r\n}\r\n\r\n/** An event the batch stores now: its id, its place in the replay, and every field its caller sent. */\r\nexport interface AcceptedStatEvent {\r\n readonly eventId: string;\r\n readonly sequence: number;\r\n /** The document's fields but the recorder facts, which the writing core stamps (ARCH-106). */\r\n readonly fields: Readonly<Record<string, unknown>>;\r\n}\r\n\r\nexport interface RecordedStatEventResult {\r\n readonly eventId: string;\r\n readonly outcome: RecordedStatEventOutcome;\r\n readonly sequence: number;\r\n}\r\n\r\nexport type StatEventBatchDecision =\r\n | {\r\n readonly ok: true;\r\n /** The rollup after the batch — unchanged when every event was already recorded. */\r\n readonly stats: GameStats;\r\n readonly statEventSequence: number;\r\n /** Each submission's result, in the order sent. */\r\n readonly results: readonly RecordedStatEventResult[];\r\n /** The events to create, in sequence order; empty when every event was already recorded. */\r\n readonly accepted: readonly AcceptedStatEvent[];\r\n }\r\n | {\r\n readonly ok: false;\r\n readonly code: StatEventRefusalCode;\r\n /** The first submission refused; nothing of the batch is written. */\r\n readonly eventId: string;\r\n };\r\n\r\nexport interface StatEventBatch {\r\n readonly adapter: AnySportAdapter;\r\n readonly game: GameTeamIds & { readonly stats: GameStats; readonly statEventSequence: number };\r\n /** The game's teams and the roster entries the batch names that exist. */\r\n readonly roster: StatEventRoster;\r\n readonly submissions: readonly StatEventSubmission[];\r\n /** The stored event at an id `statEventIdsToRead` named, or `undefined` where none is stored. */\r\n readonly storedEvent: (eventId: string) => GameStatEvent | undefined;\r\n}\r\n\r\n// The fields of a stored event the writing core derives, which a caller's re-send never carries.\r\nconst DERIVED_FIELDS: ReadonlySet<string> = new Set([...STAT_EVENT_RECORDER_FIELD_KEYS, ...STAT_EVENT_SNAPSHOT_FIELD_KEYS]);\r\n\r\nfunction callerFields(event: Readonly<Record<string, unknown>>): Record<string, unknown> {\r\n return Object.fromEntries(Object.entries(event).filter(([field, value]) => !DERIVED_FIELDS.has(field) && value !== undefined));\r\n}\r\n\r\nfunction sameFields(left: Readonly<Record<string, unknown>>, right: Readonly<Record<string, unknown>>): boolean {\r\n const leftFields = callerFields(left);\r\n const rightFields = callerFields(right);\r\n const keys = Object.keys(leftFields);\r\n return keys.length === Object.keys(rightFields).length && keys.every((key) => Object.is(leftFields[key], rightFields[key]));\r\n}\r\n\r\n/**\r\n * Whether a submission is the event already held at its id. A void is the same void when it names\r\n * the same target; a sport event only when every field its caller supplies is the same.\r\n */\r\nfunction isSameEvent(submission: StatEventSubmission, held: Readonly<Record<string, unknown>>): boolean {\r\n if (isStatVoid(submission)) return isStatVoid(held as StatEventBody) && held.targetEventId === submission.targetEventId;\r\n return sameFields(submission as Readonly<Record<string, unknown>>, held);\r\n}\r\n\r\n/** Whether any counter, or any recorded round, of any line is below zero. */\r\nfunction holdsNegativeValue(stats: GameStats): boolean {\r\n const lines = [...Object.values(stats.teamStats), ...Object.values(stats.playerStats)] as Record<string, unknown>[];\r\n return lines.some((line) =>\r\n Object.values(line).some((value) =>\r\n Array.isArray(value)\r\n ? value.some((slot) => typeof slot === 'number' && slot < 0)\r\n : typeof value === 'number' && value < 0,\r\n ),\r\n );\r\n}\r\n\r\n/** The stored fields of a new event: the void's derived id, or the caller's own id and fields. */\r\nfunction acceptedFields(submission: StatEventSubmission, eventId: string, sequence: number): Record<string, unknown> {\r\n return { ...callerFields(submission as Readonly<Record<string, unknown>>), eventId, sequence };\r\n}\r\n\r\n/**\r\n * Decide one scoring write. Every submission in order, against a running rollup that starts from\r\n * the stored one with a team line for each of the game's teams:\r\n *\r\n * - a correction → refused; only the game-reconcile core appends one;\r\n * - an id already stored, or earlier in the batch → acknowledged when it is the same event, and\r\n * refused (`eventIdConflict`) when it is not;\r\n * - a new sport event → the adapter validates it and applies it, and it takes the next sequence;\r\n * - a new void → its target, stored or earlier in the batch, must be one of the sport's events; the\r\n * adapter undoes it, and it takes the next sequence. A void that would leave a stat below zero —\r\n * the target's field moved down by a later edit — is refused (`undoBelowZero`).\r\n *\r\n * The first refusal refuses the whole batch.\r\n */\r\nexport function decideStatEventBatch(batch: StatEventBatch): StatEventBatchDecision {\r\n const { adapter, game, roster, submissions, storedEvent } = batch;\r\n let stats = withGameTeamLines(adapter, game.stats, game);\r\n let sequence = game.statEventSequence;\r\n const results: RecordedStatEventResult[] = [];\r\n const accepted: AcceptedStatEvent[] = [];\r\n // Every event the batch has placed so far — stored or new — by id, with the sequence it holds.\r\n const placed = new Map<string, { readonly event: Readonly<Record<string, unknown>>; readonly sequence: number }>();\r\n\r\n for (const submission of submissions) {\r\n const eventId = statEventSubmissionId(submission);\r\n const refuse = (code: StatEventRefusalCode): StatEventBatchDecision => ({ ok: false, code, eventId });\r\n\r\n if (isStatCorrection(submission)) return refuse('correctionNotAccepted');\r\n\r\n const held = placed.get(eventId) ?? (() => {\r\n const stored = storedEvent(eventId);\r\n return stored === undefined ? undefined : { event: stored as Readonly<Record<string, unknown>>, sequence: stored.sequence };\r\n })();\r\n if (held !== undefined) {\r\n if (!isSameEvent(submission, held.event)) return refuse('eventIdConflict');\r\n placed.set(eventId, held);\r\n results.push({ eventId, outcome: 'alreadyRecorded', sequence: held.sequence });\r\n continue;\r\n }\r\n\r\n if (isStatVoid(submission)) {\r\n const target = placed.get(submission.targetEventId)?.event ?? storedEvent(submission.targetEventId);\r\n if (!isSportStatEventIn(adapter.eventTypes, target as StatEventBody | undefined)) {\r\n return refuse('voidTargetNotSportEvent');\r\n }\r\n const next = foldStatEvent(adapter, stats, submission, () => target as StatEventBody);\r\n if (holdsNegativeValue(next)) return refuse('undoBelowZero');\r\n stats = next;\r\n } else {\r\n const verdict = adapter.validate(stats, submission, roster);\r\n if (!verdict.ok) return refuse(verdict.code);\r\n stats = foldStatEvent(adapter, stats, submission, () => undefined);\r\n }\r\n\r\n sequence += 1;\r\n const fields = acceptedFields(submission, eventId, sequence);\r\n accepted.push({ eventId, sequence, fields });\r\n placed.set(eventId, { event: fields, sequence });\r\n results.push({ eventId, outcome: 'recorded', sequence });\r\n }\r\n\r\n return { ok: true, stats, statEventSequence: sequence, results, accepted };\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"store-driver.js","sourceRoot":"","sources":["../../src/sports/store-driver.ts"],"names":[],"mappings":"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","sourcesContent":["// The store driver's decision half: what one scoring write does with the batch of events it was\n// sent, given what the game already holds. It owns ids, the sequence, void resolution, and the fold;\n// everything sport-shaped is the adapter's (SPORT-003). The writing core reads the game, the stored\n// events the batch names, and the roster entries it names, hands them here, and writes what comes\n// back — one transaction, all or nothing.\n//\n// An event id is the idempotency key (SPORT-102): an id already stored, or earlier in the batch, is\n// acknowledged when its content matches and never applied again, so re-sending a batch whose first\n// send timed out after committing changes nothing. A void's id is derived from its target, so a\n// second undo of one event is the same document and is acknowledged too.\n\nimport type { GameStatEvent } from '../doc-schemas/game-stats.js';\nimport type { GameStats } from '../doc-schemas/sport-game.js';\nimport { buildStatVoidId } from '../ids/stat-event-ids.js';\nimport type { StatEventSubmission } from '../schemas/scoring.js';\nimport { STAT_EVENT_RECORDER_FIELD_KEYS, STAT_EVENT_SNAPSHOT_FIELD_KEYS } from '../types/stats.js';\nimport type { RecordedStatEventOutcome, StatEventRefusalCode } from '../types/stats.js';\nimport { foldStatEvent, withGameTeamLines } from './replay.js';\nimport {\n isSportStatEventIn,\n isStatCorrection,\n isStatVoid,\n type StatEventBody,\n type StatEventRoster,\n} from './scoring.js';\nimport type { AnySportAdapter, GameTeamIds } from './sport-adapter.js';\n\n/** The document id a submission is stored at. */\nexport function statEventSubmissionId(submission: StatEventSubmission): string {\n return isStatVoid(submission) ? buildStatVoidId(submission.targetEventId) : submission.eventId;\n}\n\n/**\n * The ids a batch reads before it decides anything: every submission's own id, and every void's\n * target — the driver needs the stored document at each, or knows none is stored. A correction's is\n * never read: the driver refuses one before it looks at the store.\n */\nexport function statEventIdsToRead(submissions: readonly StatEventSubmission[]): string[] {\n const ids = new Set<string>();\n for (const submission of submissions) {\n if (isStatCorrection(submission)) continue;\n ids.add(statEventSubmissionId(submission));\n if (isStatVoid(submission)) ids.add(submission.targetEventId);\n }\n return [...ids];\n}\n\n/** An event the batch stores now: its id, its place in the replay, and every field its caller sent. */\nexport interface AcceptedStatEvent {\n readonly eventId: string;\n readonly sequence: number;\n /** The document's fields but the recorder facts, which the writing core stamps (ARCH-106). */\n readonly fields: Readonly<Record<string, unknown>>;\n}\n\nexport interface RecordedStatEventResult {\n readonly eventId: string;\n readonly outcome: RecordedStatEventOutcome;\n readonly sequence: number;\n}\n\nexport type StatEventBatchDecision =\n | {\n readonly ok: true;\n /** The rollup after the batch — unchanged when every event was already recorded. */\n readonly stats: GameStats;\n readonly statEventSequence: number;\n /** Each submission's result, in the order sent. */\n readonly results: readonly RecordedStatEventResult[];\n /** The events to create, in sequence order; empty when every event was already recorded. */\n readonly accepted: readonly AcceptedStatEvent[];\n }\n | {\n readonly ok: false;\n readonly code: StatEventRefusalCode;\n /** The first submission refused; nothing of the batch is written. */\n readonly eventId: string;\n };\n\nexport interface StatEventBatch {\n readonly adapter: AnySportAdapter;\n readonly game: GameTeamIds & { readonly stats: GameStats; readonly statEventSequence: number };\n /** The game's teams and the roster entries the batch names that exist. */\n readonly roster: StatEventRoster;\n readonly submissions: readonly StatEventSubmission[];\n /** The stored event at an id `statEventIdsToRead` named, or `undefined` where none is stored. */\n readonly storedEvent: (eventId: string) => GameStatEvent | undefined;\n}\n\n// The fields of a stored event the writing core derives, which a caller's re-send never carries.\nconst DERIVED_FIELDS: ReadonlySet<string> = new Set([...STAT_EVENT_RECORDER_FIELD_KEYS, ...STAT_EVENT_SNAPSHOT_FIELD_KEYS]);\n\nfunction callerFields(event: Readonly<Record<string, unknown>>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(event).filter(([field, value]) => !DERIVED_FIELDS.has(field) && value !== undefined));\n}\n\nfunction sameFields(left: Readonly<Record<string, unknown>>, right: Readonly<Record<string, unknown>>): boolean {\n const leftFields = callerFields(left);\n const rightFields = callerFields(right);\n const keys = Object.keys(leftFields);\n return keys.length === Object.keys(rightFields).length && keys.every((key) => Object.is(leftFields[key], rightFields[key]));\n}\n\n/**\n * Whether a submission is the event already held at its id. A void is the same void when it names\n * the same target; a sport event only when every field its caller supplies is the same.\n */\nfunction isSameEvent(submission: StatEventSubmission, held: Readonly<Record<string, unknown>>): boolean {\n if (isStatVoid(submission)) return isStatVoid(held as StatEventBody) && held.targetEventId === submission.targetEventId;\n return sameFields(submission as Readonly<Record<string, unknown>>, held);\n}\n\n/** Whether any counter, or any recorded round, of any line is below zero. */\nfunction holdsNegativeValue(stats: GameStats): boolean {\n const lines = [...Object.values(stats.teamStats), ...Object.values(stats.playerStats)] as Record<string, unknown>[];\n return lines.some((line) =>\n Object.values(line).some((value) =>\n Array.isArray(value)\n ? value.some((slot) => typeof slot === 'number' && slot < 0)\n : typeof value === 'number' && value < 0,\n ),\n );\n}\n\n/** The stored fields of a new event: the void's derived id, or the caller's own id and fields. */\nfunction acceptedFields(submission: StatEventSubmission, eventId: string, sequence: number): Record<string, unknown> {\n return { ...callerFields(submission as Readonly<Record<string, unknown>>), eventId, sequence };\n}\n\n/**\n * Decide one scoring write. Every submission in order, against a running rollup that starts from\n * the stored one with a team line for each of the game's teams:\n *\n * - a correction → refused; only the game-reconcile core appends one;\n * - an id already stored, or earlier in the batch → acknowledged when it is the same event, and\n * refused (`eventIdConflict`) when it is not;\n * - a new sport event → the adapter validates it and applies it, and it takes the next sequence;\n * - a new void → its target, stored or earlier in the batch, must be one of the sport's events; the\n * adapter undoes it, and it takes the next sequence. A void that would leave a stat below zero —\n * the target's field moved down by a later edit — is refused (`undoBelowZero`).\n *\n * The first refusal refuses the whole batch.\n */\nexport function decideStatEventBatch(batch: StatEventBatch): StatEventBatchDecision {\n const { adapter, game, roster, submissions, storedEvent } = batch;\n let stats = withGameTeamLines(adapter, game.stats, game);\n let sequence = game.statEventSequence;\n const results: RecordedStatEventResult[] = [];\n const accepted: AcceptedStatEvent[] = [];\n // Every event the batch has placed so far — stored or new — by id, with the sequence it holds.\n const placed = new Map<string, { readonly event: Readonly<Record<string, unknown>>; readonly sequence: number }>();\n\n for (const submission of submissions) {\n const eventId = statEventSubmissionId(submission);\n const refuse = (code: StatEventRefusalCode): StatEventBatchDecision => ({ ok: false, code, eventId });\n\n if (isStatCorrection(submission)) return refuse('correctionNotAccepted');\n\n const held = placed.get(eventId) ?? (() => {\n const stored = storedEvent(eventId);\n return stored === undefined ? undefined : { event: stored as Readonly<Record<string, unknown>>, sequence: stored.sequence };\n })();\n if (held !== undefined) {\n if (!isSameEvent(submission, held.event)) return refuse('eventIdConflict');\n placed.set(eventId, held);\n results.push({ eventId, outcome: 'alreadyRecorded', sequence: held.sequence });\n continue;\n }\n\n if (isStatVoid(submission)) {\n const target = placed.get(submission.targetEventId)?.event ?? storedEvent(submission.targetEventId);\n if (!isSportStatEventIn(adapter.eventTypes, target as StatEventBody | undefined)) {\n return refuse('voidTargetNotSportEvent');\n }\n const next = foldStatEvent(adapter, stats, submission, () => target as StatEventBody);\n if (holdsNegativeValue(next)) return refuse('undoBelowZero');\n stats = next;\n } else {\n const verdict = adapter.validate(stats, submission, roster);\n if (!verdict.ok) return refuse(verdict.code);\n stats = foldStatEvent(adapter, stats, submission, () => undefined);\n }\n\n sequence += 1;\n const fields = acceptedFields(submission, eventId, sequence);\n accepted.push({ eventId, sequence, fields });\n placed.set(eventId, { event: fields, sequence });\n results.push({ eventId, outcome: 'recorded', sequence });\n }\n\n return { ok: true, stats, statEventSequence: sequence, results, accepted };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.js","sourceRoot":"","sources":["../../src/types/documents.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,qGAAqG;AACrG,sCAAsC","sourcesContent":["// Document types. Every shape is defined as a zod schema in ../doc-schemas and its type inferred\
|
|
1
|
+
{"version":3,"file":"documents.js","sourceRoot":"","sources":["../../src/types/documents.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,qGAAqG;AACrG,sCAAsC","sourcesContent":["// Document types. Every shape is defined as a zod schema in ../doc-schemas and its type inferred\n// there; this file re-exports the TYPES so they reach the root barrel while the runtime schemas stay\n// behind the `./doc-schemas` subpath.\n\nexport type { FirestoreTimestampLike } from '../doc-schemas/firestore-primitives.js';\nexport type { GrantedAward, HistoricalStats, UserProfile } from '../doc-schemas/user-profile.js';\nexport type { PublicUser } from '../doc-schemas/publicUser.js';\nexport type { SportLeague } from '../doc-schemas/sport-league.js';\nexport type { LeagueTeam, LeagueTeamContact } from '../doc-schemas/league-team.js';\nexport type {\n MembershipRosterSync,\n MembershipRosterSyncCursor,\n} from '../doc-schemas/membership-roster-sync.js';\nexport type {\n LeagueFreeAgent,\n TeamJoinRequest,\n TeamInvitation,\n TeamMembership,\n} from '../doc-schemas/team-membership.js';\nexport type {\n BasketballPlayerStats,\n BasketballStatEvent,\n BasketballTeamStats,\n CurlingBlankEndEvent,\n CurlingRoundScoreEvent,\n CurlingStatEvent,\n CurlingTeamStats,\n FootballStatEvent,\n FootballTeamStats,\n GameStatEvent,\n GameStatEventType,\n StatCorrectionEvent,\n StatVoidEvent,\n} from '../doc-schemas/game-stats.js';\nexport type {\n BasketballGame,\n BasketballGameStats,\n CurlingGame,\n CurlingGameStats,\n FootballGame,\n FootballGameStats,\n GameRosterPlayer,\n GameStats,\n GameTeam,\n SportGame,\n} from '../doc-schemas/sport-game.js';\nexport type {\n GameStatHistoryContinuationPage,\n GameStatHistoryFirstPage,\n GameStatHistoryPage,\n} from '../doc-schemas/game-stat-history.js';\nexport type {\n BasketballPlayerTotals,\n BasketballTeamSeasonStats,\n GamesPlayedStats,\n PlayerSeasonStats,\n SportHallOfFame,\n TeamSeasonBaseStats,\n TeamSeasonStats,\n UserLifetimeStats,\n} from '../doc-schemas/aggregate-stats.js';\nexport type {\n StatsDestinationChange,\n StatsOperation,\n StatsOperationCounts,\n} from '../doc-schemas/stats-operation.js';\nexport type {\n HardwareLoanContract,\n HardwareItem,\n SignedWaiver,\n} from '../doc-schemas/waivers-and-hardware.js';\nexport type { WaiverTemplate, WaiverTemplateVersion } from '../doc-schemas/waiver-template.js';\nexport type { GameLocation } from '../doc-schemas/game-location.js';\nexport type { AwardDefinition } from '../doc-schemas/catalogs.js';\nexport type {\n StatusReconcileQueueAccountStatusEntry,\n StatusReconcileQueueEntry,\n StatusReconcileQueueRoleClaimsEntry,\n} from '../doc-schemas/status-reconcile-queue.js';\nexport type { AdminStats } from '../schemas/admin-stats.js';\nexport type { GalleryPicture, GallerySummary } from '../doc-schemas/gallery.js';\nexport type {\n PendingMedia,\n PendingMediaCompleted,\n PendingMediaErrorCategory,\n PendingMediaFailed,\n PendingMediaPending,\n PendingMediaProcessing,\n PendingMediaResult,\n PendingMediaTarget,\n PictureOwnerRef,\n StorageObjectRef,\n} from '../doc-schemas/pending-media.js';\nexport type { PictureRetirement, PictureRetirementTarget } from '../doc-schemas/picture-retirement.js';\nexport type {\n AppConfig,\n LandingPageConfig,\n AdminList,\n StatsBeacon,\n StatsDiscrepancy,\n StatsValidationReport,\n StatsValidationScope,\n StatsValidationSummary,\n} from '../doc-schemas/system.js';\nexport type {\n ActiveAdminNotification,\n AdminNotificationHistory,\n AdminNotificationMetadataByType,\n LeagueFreeAgentSignedUpNotificationMetadata,\n LeagueTeamCreatedNotificationMetadata,\n NotificationArchiveAllJob,\n NotificationDelivery,\n NotificationDeliveryPayload,\n} from '../doc-schemas/admin-notifications.js';\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/types/notifications.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,4FAA4F;AAC5F,+FAA+F;AAC/F,mGAAmG;AACnG,gDAAgD;AAShD,oGAAoG;AACpG,kGAAkG;AAClG,oGAAoG;AACpG,uDAAuD;AACvD,SAAS,WAAW;IAClB,OAAO,CACL,IAAmH,EAC7G,EAAE,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,OAAO,CAAU,CAAC;AAE7D,MAAM,CAAC,MAAM,2BAA2B,GAAG,OAA+C,CAAC;AAE3F,oGAAoG;AACpG,qCAAqC;AACrC,MAAM,CAAC,MAAM,kCAAkC,GAAG,QAAQ,CAAC;AAE3D,kGAAkG;AAClG,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,mBAAmB,EAAE,yBAAyB,CAAU,CAAC;AAGtG,uGAAuG;AACvG,iGAAiG;AACjG,oFAAoF;AACpF,MAAM,CAAC,MAAM,gCAAgC,GAAG,WAAW,EAAiB,CAAC;IAC3E,QAAQ;IACR,cAAc;IACd,SAAS;IACT,YAAY;CACb,CAAC,CAAC;AAGH,gDAAgD;AAChD,MAAM,CAAC,MAAM,sCAAsC,GAAG,WAAW,EAAsB,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAEjH,mGAAmG;AACnG,kGAAkG;AAClG,gGAAgG;AAChG,uGAAuG;AACvG,yBAAyB;AACzB,MAAM,CAAC,MAAM,uCAAuC,GAAG,WAAW,EAAiD,CAAC;IAClH,cAAc;IACd,kBAAkB;IAClB,OAAO;CACR,CAAC,CAAC;AAGH,mGAAmG;AACnG,kEAAkE;AAClE,MAAM,CAAC,MAAM,qCAAqC,GAAG,CAAC,CAAC;AAEvD,yFAAyF;AACzF,MAAM,CAAC,MAAM,uCAAuC,GAAG,WAAW,EAAkC,CAAC;IACnG,aAAa;IACb,UAAU;IACV,YAAY;IACZ,QAAQ;CACT,CAAC,CAAC","sourcesContent":["// The admin notification vocabulary. Q-Sports notifies admins only, through one shared audience:\
|
|
1
|
+
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/types/notifications.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,4FAA4F;AAC5F,+FAA+F;AAC/F,mGAAmG;AACnG,gDAAgD;AAShD,oGAAoG;AACpG,kGAAkG;AAClG,oGAAoG;AACpG,uDAAuD;AACvD,SAAS,WAAW;IAClB,OAAO,CACL,IAAmH,EAC7G,EAAE,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,OAAO,CAAU,CAAC;AAE7D,MAAM,CAAC,MAAM,2BAA2B,GAAG,OAA+C,CAAC;AAE3F,oGAAoG;AACpG,qCAAqC;AACrC,MAAM,CAAC,MAAM,kCAAkC,GAAG,QAAQ,CAAC;AAE3D,kGAAkG;AAClG,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,mBAAmB,EAAE,yBAAyB,CAAU,CAAC;AAGtG,uGAAuG;AACvG,iGAAiG;AACjG,oFAAoF;AACpF,MAAM,CAAC,MAAM,gCAAgC,GAAG,WAAW,EAAiB,CAAC;IAC3E,QAAQ;IACR,cAAc;IACd,SAAS;IACT,YAAY;CACb,CAAC,CAAC;AAGH,gDAAgD;AAChD,MAAM,CAAC,MAAM,sCAAsC,GAAG,WAAW,EAAsB,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAEjH,mGAAmG;AACnG,kGAAkG;AAClG,gGAAgG;AAChG,uGAAuG;AACvG,yBAAyB;AACzB,MAAM,CAAC,MAAM,uCAAuC,GAAG,WAAW,EAAiD,CAAC;IAClH,cAAc;IACd,kBAAkB;IAClB,OAAO;CACR,CAAC,CAAC;AAGH,mGAAmG;AACnG,kEAAkE;AAClE,MAAM,CAAC,MAAM,qCAAqC,GAAG,CAAC,CAAC;AAEvD,yFAAyF;AACzF,MAAM,CAAC,MAAM,uCAAuC,GAAG,WAAW,EAAkC,CAAC;IACnG,aAAa;IACb,UAAU;IACV,YAAY;IACZ,QAAQ;CACT,CAAC,CAAC","sourcesContent":["// The admin notification vocabulary. Q-Sports notifies admins only, through one shared audience:\n// every admin reads the same cards, and seeing or archiving a card does so for all of them.\n// `@ttt-productions/notification-core` owns the delivery, seen, and archive mechanism; what is\n// declared here is Q-Sports' side of it — the category, the notification types, and the states the\n// ledger and the archive-all jobs move through.\n\nimport type { ArchiveAllJobSnapshot } from '@ttt-productions/notification-core';\nimport type {\n DeliverySkipReason,\n DeliveryState,\n MaterializationClass,\n} from '@ttt-productions/notification-core/server';\n\n// The package exports these vocabularies as types only, so each is restated here as a tuple the doc\n// schemas build their enums from. `everyMember<Union>()` accepts a tuple only when it names every\n// member of `Union` and nothing else, so a vocabulary the package grows or renames fails to compile\n// here instead of failing a row's parse in production.\nfunction everyMember<Union extends string>() {\n return <const Keys extends readonly Union[]>(\n keys: Keys & ([Exclude<Union, Keys[number]>] extends [never] ? unknown : { missing: Exclude<Union, Keys[number]> }),\n ): Keys => keys;\n}\n\n// The one notification category. It is shared, so a card has no recipient.\nexport const NOTIFICATION_CATEGORY_KEYS = ['admin'] as const;\nexport type NotificationCategory = (typeof NOTIFICATION_CATEGORY_KEYS)[number];\nexport const ADMIN_NOTIFICATION_CATEGORY = 'admin' as const satisfies NotificationCategory;\n\n// The audience scope notification-core records on an archived shared card, and hashes into a shared\n// card's id in place of a recipient.\nexport const SHARED_NOTIFICATION_AUDIENCE_SCOPE = 'shared';\n\n// What an admin is notified of: a team joining a league, and a player signing up as a free agent.\nexport const ADMIN_NOTIFICATION_TYPE_KEYS = ['leagueTeamCreated', 'leagueFreeAgentSignedUp'] as const;\nexport type AdminNotificationType = (typeof ADMIN_NOTIFICATION_TYPE_KEYS)[number];\n\n// A delivery row's life on the ledger, as notification-core writes it. `skipped` is the terminal state\n// of a row whose recipient may no longer receive; a Q-Sports row names no recipient, so it never\n// reaches it, but the state is the package's and a row is read against all of them.\nexport const NOTIFICATION_DELIVERY_STATE_KEYS = everyMember<DeliveryState>()([\n 'queued',\n 'materialized',\n 'skipped',\n 'deadLetter',\n]);\nexport type NotificationDeliveryState = (typeof NOTIFICATION_DELIVERY_STATE_KEYS)[number];\n\n// Why notification-core turned a row `skipped`.\nexport const NOTIFICATION_DELIVERY_SKIP_REASON_KEYS = everyMember<DeliverySkipReason>()(['recipientIneligible']);\n\n// The worker lane a delivery row waits in: `directQueued` for a type only the worker materializes,\n// `realtimeFallback` for a type its owning callable also materializes right after its commit, and\n// `retry`, which notification-core moves a row into after a failed attempt. notification-core's\n// fourth lane, `fanoutOrphan`, holds rows of an audience fanout, which Q-Sports does not run, so it is\n// the one lane left out.\nexport const NOTIFICATION_MATERIALIZATION_CLASS_KEYS = everyMember<Exclude<MaterializationClass, 'fanoutOrphan'>>()([\n 'directQueued',\n 'realtimeFallback',\n 'retry',\n]);\nexport type NotificationMaterializationClass = (typeof NOTIFICATION_MATERIALIZATION_CLASS_KEYS)[number];\n\n// The shape of the occurrence payload every delivery row carries. A change to it is a new version,\n// so a row written under the old one is still read as what it is.\nexport const NOTIFICATION_DELIVERY_PAYLOAD_VERSION = 1;\n\n// An archive-all job's state, which the status read hands the client's poller unchanged.\nexport const NOTIFICATION_ARCHIVE_ALL_JOB_STATE_KEYS = everyMember<ArchiveAllJobSnapshot['state']>()([\n 'in-progress',\n 'complete',\n 'incomplete',\n 'failed',\n]);\nexport type NotificationArchiveAllJobState = (typeof NOTIFICATION_ARCHIVE_ALL_JOB_STATE_KEYS)[number];\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"picture-owners.js","sourceRoot":"","sources":["../../src/types/picture-owners.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,iGAAiG;AACjG,iGAAiG;AAEjG,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,aAAa;IACb,YAAY;IACZ,aAAa;IACb,cAAc;IACd,iBAAiB;CACT,CAAC;AAGX,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,aAAa;IACb,YAAY;IACZ,aAAa;CACiC,CAAC;AAIjD,mEAAmE;AACnE,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAqD,CAAC;AAEjG,6DAA6D;AAC7D,MAAM,CAAC,MAAM,8BAA8B,GAAG,YAAgD,CAAC;AAE/F,6EAA6E;AAC7E,MAAM,UAAU,kBAAkB,CAAC,IAAsB;IACvD,OAAQ,uBAAuD,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjF,CAAC","sourcesContent":["// Which document owns a picture (ARCH-102). An upload's target, its indexes, and a picture's\
|
|
1
|
+
{"version":3,"file":"picture-owners.js","sourceRoot":"","sources":["../../src/types/picture-owners.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,iGAAiG;AACjG,iGAAiG;AAEjG,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,aAAa;IACb,YAAY;IACZ,aAAa;IACb,cAAc;IACd,iBAAiB;CACT,CAAC;AAGX,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,aAAa;IACb,YAAY;IACZ,aAAa;CACiC,CAAC;AAIjD,mEAAmE;AACnE,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAqD,CAAC;AAEjG,6DAA6D;AAC7D,MAAM,CAAC,MAAM,8BAA8B,GAAG,YAAgD,CAAC;AAE/F,6EAA6E;AAC7E,MAAM,UAAU,kBAAkB,CAAC,IAAsB;IACvD,OAAQ,uBAAuD,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjF,CAAC","sourcesContent":["// Which document owns a picture (ARCH-102). An upload's target, its indexes, and a picture's\n// removal take the full union; a gallery picture document takes the gallery subset, because only\n// those three owners hold a gallery — a location and an award hold one picture in a single slot.\n\nexport const PICTURE_OWNER_KIND_KEYS = [\n 'sportLeague',\n 'leagueTeam',\n 'landingPage',\n 'gameLocation',\n 'awardDefinition',\n] as const;\nexport type PictureOwnerKind = (typeof PICTURE_OWNER_KIND_KEYS)[number];\n\nexport const GALLERY_OWNER_KIND_KEYS = [\n 'sportLeague',\n 'leagueTeam',\n 'landingPage',\n] as const satisfies readonly PictureOwnerKind[];\nexport type GalleryOwnerKind = (typeof GALLERY_OWNER_KIND_KEYS)[number];\nexport type PictureSlotOwnerKind = Exclude<PictureOwnerKind, GalleryOwnerKind>;\n\n// An award's badge slot, which the award catalog's own core fills.\nexport const AWARD_DEFINITION_OWNER_KIND = 'awardDefinition' as const satisfies PictureOwnerKind;\n\n// A team's gallery, which the team's deletion retires whole.\nexport const LEAGUE_TEAM_GALLERY_OWNER_KIND = 'leagueTeam' as const satisfies GalleryOwnerKind;\n\n/** Whether an owner holds a gallery, as opposed to a single picture slot. */\nexport function isGalleryOwnerKind(kind: PictureOwnerKind): kind is GalleryOwnerKind {\n return (GALLERY_OWNER_KIND_KEYS as readonly PictureOwnerKind[]).includes(kind);\n}\n"]}
|
package/dist/types/sports.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sports.js","sourceRoot":"","sources":["../../src/types/sports.ts"],"names":[],"mappings":"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","sourcesContent":["// The canonical sport discriminator (ARCH-108), and each sport's declared vocabulary (SPORT-007).\
|
|
1
|
+
{"version":3,"file":"sports.js","sourceRoot":"","sources":["../../src/types/sports.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,EAAE;AACF,iGAAiG;AACjG,mGAAmG;AACnG,iGAAiG;AACjG,gGAAgG;AAEhG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,YAAY,EAAE,SAAS,EAAE,UAAU,CAAU,CAAC;AAG/E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,YAAY,EAAE,SAAS,EAAE,UAAU,CAAU,CAAC;AAGzE,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,UAAU,EAAE,YAAY;IACxB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;CAC2B,CAAC;AAElD,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,UAAU,EAAE,YAAY;IACxB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;CAC2B,CAAC;AAElD,gGAAgG;AAChG,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,gBAAgB,EAAE,cAAc,EAAE,cAAc,CAAU,CAAC;AAG3F,mGAAmG;AACnG,2EAA2E;AAC3E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAU,CAAC;AAGjG,gGAAgG;AAChG,gFAAgF;AAChF,gGAAgG;AAEhG,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,OAAO,EAAE,UAAU,CAA8C,CAAC;AAG5G,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,CAA8C,CAAC;AAG1H,iDAAiD;AACjD,MAAM,CAAC,MAAM,yBAAyB,GAAG,2BAA2B,CAAC;AAGrE,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,CAAC;AACrD,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,CAAC;AACrD,MAAM,CAAC,MAAM,iCAAiC,GAAG,KAAK,CAAC;AACvD,yEAAyE;AACzE,MAAM,CAAC,MAAM,0CAA0C,GAAG;IACxD,+BAA+B;IAC/B,iCAAiC;CACzB,CAAC;AACX,MAAM,CAAC,MAAM,gCAAgC,GAAG;IAC9C,+BAA+B;IAC/B,GAAG,0CAA0C;CACrC,CAAC;AACX,MAAM,CAAC,MAAM,6BAA6B,GAAG,SAAS,CAAC;AACvD,MAAM,CAAC,MAAM,4BAA4B,GAAG,QAAQ,CAAC;AACrD,MAAM,CAAC,MAAM,uCAAuC,GAAG;IACrD,6BAA6B;IAC7B,4BAA4B;CACpB,CAAC;AACX,+CAA+C;AAC/C,MAAM,CAAC,MAAM,6BAA6B,GAAG,SAAS,CAAC;AACvD,MAAM,CAAC,MAAM,+BAA+B,GAAG,WAAW,CAAC;AAE3D,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,GAAG,gCAAgC;IACnC,GAAG,uCAAuC;IAC1C,6BAA6B;IAC7B,+BAA+B;CACvB,CAAC;AAGX,gGAAgG;AAChG,iDAAiD;AACjD,gGAAgG;AAEhG,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAAO,CAA8C,CAAC;AAE7F,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAA+C,CAAC;AAExF,MAAM,CAAC,MAAM,8BAA8B,GAAG,qBAAqB,CAAC;AACpE,0CAA0C;AAC1C,MAAM,CAAC,MAAM,8BAA8B,GAAG,qBAAqB,CAAC;AACpE,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,8BAA8B;IAC9B,8BAA8B;CACtB,CAAC;AAGX,gGAAgG;AAChG,2CAA2C;AAC3C,gGAAgG;AAEhG,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,OAAO,CAA8C,CAAC;AAE9F,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAA+C,CAAC;AAEzF,qGAAqG;AACrG,MAAM,CAAC,MAAM,6BAA6B,GAAG,cAAc,CAAC;AAC5D,MAAM,CAAC,MAAM,6BAA6B,GAAG,cAAc,CAAC;AAC5D,MAAM,CAAC,MAAM,6BAA6B,GAAG,cAAc,CAAC;AAC5D,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,6BAA6B;IAC7B,6BAA6B;IAC7B,6BAA6B;CACrB,CAAC;AACX,MAAM,CAAC,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAClE,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC3C,GAAG,8BAA8B;IACjC,6BAA6B;CACrB,CAAC","sourcesContent":["// The canonical sport discriminator (ARCH-108), and each sport's declared vocabulary (SPORT-007).\n//\n// `leagueType` identifies a sport everywhere. The lowercase sport key is the storage key derived\n// from it — the `sportHallOfFame/{sportKey}` and `historicalStats/{sportKey}` document ids and the\n// `lifetimeStats.{sportKey}` field. Both directions of the mapping live here, never in an inline\n// conditional. What each sport DOES belongs to its sport adapter (SPORT-003), not to this file.\n\nexport const LEAGUE_TYPE_KEYS = ['Basketball', 'Curling', 'Football'] as const;\nexport type LeagueType = (typeof LEAGUE_TYPE_KEYS)[number];\n\nexport const SPORT_KEYS = ['basketball', 'curling', 'football'] as const;\nexport type SportKey = (typeof SPORT_KEYS)[number];\n\nexport const SPORT_KEY_BY_LEAGUE_TYPE = {\n Basketball: 'basketball',\n Curling: 'curling',\n Football: 'football',\n} as const satisfies Record<LeagueType, SportKey>;\n\nexport const LEAGUE_TYPE_BY_SPORT_KEY = {\n basketball: 'Basketball',\n curling: 'Curling',\n football: 'Football',\n} as const satisfies Record<SportKey, LeagueType>;\n\n// The glyph a sport renders, named by its adapter's `display.iconKey`. The app's one sport-icon\n// component maps each key to a glyph, so no surface picks an icon by sport.\nexport const SPORT_ICON_KEYS = ['basketballBall', 'curlingStone', 'footballBall'] as const;\nexport type SportIconKey = (typeof SPORT_ICON_KEYS)[number];\n\n// Every counter a stat line holds, across every sport. Each sport's team and player counters are a\n// subset; a derived field (basketball's `fantasyPoints`) is not a counter.\nexport const STAT_COUNTER_KEYS = ['score', 'timeouts', 'points', 'rebounds', 'assists'] as const;\nexport type StatCounterKey = (typeof STAT_COUNTER_KEYS)[number];\n\n// ---------------------------------------------------------------------------------------------\n// Basketball — player-scored: a team's score is the sum of its players' points.\n// ---------------------------------------------------------------------------------------------\n\nexport const BASKETBALL_TEAM_STAT_KEYS = ['score', 'timeouts'] as const satisfies readonly StatCounterKey[];\nexport type BasketballTeamStatKey = (typeof BASKETBALL_TEAM_STAT_KEYS)[number];\n\nexport const BASKETBALL_PLAYER_STAT_KEYS = ['points', 'rebounds', 'assists'] as const satisfies readonly StatCounterKey[];\nexport type BasketballPlayerStatKey = (typeof BASKETBALL_PLAYER_STAT_KEYS)[number];\n\n// A bulk edit names the player counter it moves.\nexport const BASKETBALL_BULK_STAT_KEYS = BASKETBALL_PLAYER_STAT_KEYS;\nexport type BasketballBulkStatKey = BasketballPlayerStatKey;\n\nexport const BASKETBALL_ONE_POINT_EVENT_TYPE = '1PT';\nexport const BASKETBALL_TWO_POINT_EVENT_TYPE = '2PT';\nexport const BASKETBALL_THREE_POINT_EVENT_TYPE = '3PT';\n// Only a two- or three-point shot may name the teammate who assisted it.\nexport const BASKETBALL_ASSISTABLE_SHOT_EVENT_TYPE_KEYS = [\n BASKETBALL_TWO_POINT_EVENT_TYPE,\n BASKETBALL_THREE_POINT_EVENT_TYPE,\n] as const;\nexport const BASKETBALL_SCORE_EVENT_TYPE_KEYS = [\n BASKETBALL_ONE_POINT_EVENT_TYPE,\n ...BASKETBALL_ASSISTABLE_SHOT_EVENT_TYPE_KEYS,\n] as const;\nexport const BASKETBALL_REBOUND_EVENT_TYPE = 'REBOUND';\nexport const BASKETBALL_ASSIST_EVENT_TYPE = 'ASSIST';\nexport const BASKETBALL_PLAYER_TALLY_EVENT_TYPE_KEYS = [\n BASKETBALL_REBOUND_EVENT_TYPE,\n BASKETBALL_ASSIST_EVENT_TYPE,\n] as const;\n// A timeout is the team's; it names no player.\nexport const BASKETBALL_TIMEOUT_EVENT_TYPE = 'TIMEOUT';\nexport const BASKETBALL_BULK_EDIT_EVENT_TYPE = 'BULK_EDIT';\n\nexport const BASKETBALL_STAT_EVENT_TYPE_KEYS = [\n ...BASKETBALL_SCORE_EVENT_TYPE_KEYS,\n ...BASKETBALL_PLAYER_TALLY_EVENT_TYPE_KEYS,\n BASKETBALL_TIMEOUT_EVENT_TYPE,\n BASKETBALL_BULK_EDIT_EVENT_TYPE,\n] as const;\nexport type BasketballStatEventType = (typeof BASKETBALL_STAT_EVENT_TYPE_KEYS)[number];\n\n// ---------------------------------------------------------------------------------------------\n// Curling — team-scored by end; no player lines.\n// ---------------------------------------------------------------------------------------------\n\nexport const CURLING_TEAM_STAT_KEYS = ['score'] as const satisfies readonly StatCounterKey[];\nexport type CurlingTeamStatKey = (typeof CURLING_TEAM_STAT_KEYS)[number];\nexport const CURLING_PLAYER_STAT_KEYS = [] as const satisfies readonly StatCounterKey[];\n\nexport const CURLING_ROUND_SCORE_EVENT_TYPE = 'CURLING_ROUND_SCORE';\n// An end nobody scored; it names no team.\nexport const CURLING_ROUND_BLANK_EVENT_TYPE = 'CURLING_ROUND_BLANK';\nexport const CURLING_STAT_EVENT_TYPE_KEYS = [\n CURLING_ROUND_SCORE_EVENT_TYPE,\n CURLING_ROUND_BLANK_EVENT_TYPE,\n] as const;\nexport type CurlingStatEventType = (typeof CURLING_STAT_EVENT_TYPE_KEYS)[number];\n\n// ---------------------------------------------------------------------------------------------\n// Football — team-scored; no player lines.\n// ---------------------------------------------------------------------------------------------\n\nexport const FOOTBALL_TEAM_STAT_KEYS = ['score'] as const satisfies readonly StatCounterKey[];\nexport type FootballTeamStatKey = (typeof FOOTBALL_TEAM_STAT_KEYS)[number];\nexport const FOOTBALL_PLAYER_STAT_KEYS = [] as const satisfies readonly StatCounterKey[];\n\n// Named by the points each adds: a +2 is a safety or a conversion, and the game records only points.\nexport const FOOTBALL_SIX_POINT_EVENT_TYPE = 'FOOTBALL_6PT';\nexport const FOOTBALL_TWO_POINT_EVENT_TYPE = 'FOOTBALL_2PT';\nexport const FOOTBALL_ONE_POINT_EVENT_TYPE = 'FOOTBALL_1PT';\nexport const FOOTBALL_SCORE_EVENT_TYPE_KEYS = [\n FOOTBALL_SIX_POINT_EVENT_TYPE,\n FOOTBALL_TWO_POINT_EVENT_TYPE,\n FOOTBALL_ONE_POINT_EVENT_TYPE,\n] as const;\nexport const FOOTBALL_BULK_EDIT_EVENT_TYPE = 'FOOTBALL_BULK_EDIT';\nexport const FOOTBALL_STAT_EVENT_TYPE_KEYS = [\n ...FOOTBALL_SCORE_EVENT_TYPE_KEYS,\n FOOTBALL_BULK_EDIT_EVENT_TYPE,\n] as const;\nexport type FootballStatEventType = (typeof FOOTBALL_STAT_EVENT_TYPE_KEYS)[number];\n"]}
|
package/dist/types/stats.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/types/stats.ts"],"names":[],"mappings":"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","sourcesContent":["// Canonical unions of the stat event store and the stats operations (ARCH-102). What each sport's\r\n// own events and lines are is ./sports.ts; these are the sport-agnostic halves every sport shares.\r\n\r\nimport { CAPTAIN_TEAM_ROLES, SYSTEM_ROLE_KEYS } from './unions.js';\r\n\r\n// The two store-level events, members of every sport's event union. A void undoes the one event it\r\n// targets; a correction adds a signed value to one correctable field of one line.\r\nexport const STAT_VOID_EVENT_TYPE = 'STAT_VOID';\r\nexport const STAT_CORRECTION_EVENT_TYPE = 'STAT_CORRECTION';\r\nexport const STAT_STORE_EVENT_TYPE_KEYS = [STAT_VOID_EVENT_TYPE, STAT_CORRECTION_EVENT_TYPE] as const;\r\nexport type StatStoreEventType = (typeof STAT_STORE_EVENT_TYPE_KEYS)[number];\r\n\r\n// The fields of a stored stat event the writing core derives — its place in the replay, and who\r\n// recorded it under which authority — so a caller never sends them (ARCH-106).\r\nexport const STAT_EVENT_RECORDER_FIELD_KEYS = [\r\n 'sequence',\r\n 'acceptedAt',\r\n 'recordedByUserId',\r\n 'recordedByAuthority',\r\n 'recordedByTeamId',\r\n] as const;\r\nexport type StatEventRecorderField = (typeof STAT_EVENT_RECORDER_FIELD_KEYS)[number];\r\n\r\n// The name snapshots only a copied event carries; nothing writes one on a new event (SPORT-104).\r\nexport const STAT_EVENT_SNAPSHOT_FIELD_KEYS = ['displayNameSnapshot', 'assistedByDisplayNameSnapshot'] as const;\r\nexport type StatEventSnapshotField = (typeof STAT_EVENT_SNAPSHOT_FIELD_KEYS)[number];\r\n\r\n// Who appended a correction: an admin reconciling a game, or the copy that carries a recorded\r\n// result its events do not explain.\r\nexport const STAT_CORRECTION_SOURCE_KEYS = ['admin', 'migration'] as const;\r\nexport type StatCorrectionSource = (typeof STAT_CORRECTION_SOURCE_KEYS)[number];\r\n\r\n// The authority the writing core confirmed for an event: a global role, or a team role on one of\r\n// the game's teams.\r\nexport const STAT_EVENT_AUTHORITY_KEYS = [...SYSTEM_ROLE_KEYS, ...CAPTAIN_TEAM_ROLES] as const;\r\nexport type StatEventAuthority = (typeof STAT_EVENT_AUTHORITY_KEYS)[number];\r\n\r\n// Every kind of stat line: the four player kinds, then the two team kinds. A sport's line of each\r\n// kind is declared once, in `SPORT_LINE_SCHEMAS`; a kind a sport has no line for is `never` there.\r\nexport const PLAYER_STAT_LINE_KIND_KEYS = ['gamePlayer', 'membershipRow', 'lifetime', 'hallOfFame'] as const;\r\nexport const TEAM_STAT_LINE_KIND_KEYS = ['gameTeam', 'teamSeason'] as const;\r\nexport const STAT_LINE_KIND_KEYS = [...PLAYER_STAT_LINE_KIND_KEYS, ...TEAM_STAT_LINE_KIND_KEYS] as const;\r\nexport type StatLineKind = (typeof STAT_LINE_KIND_KEYS)[number];\r\nexport type PlayerStatLineKind = (typeof PLAYER_STAT_LINE_KIND_KEYS)[number];\r\n\r\n// One logical run of a stats action, recorded on its `statsOperations` document.\r\nexport const STATS_OPERATION_KIND_KEYS = [\r\n 'leagueStatsRebuild',\r\n 'lifetimeStatsRebuild',\r\n 'hallOfFameRebuild',\r\n 'statsValidation',\r\n 'gameStatsCorrection',\r\n 'gameStatsRecalculation',\r\n 'historicalStatsUpdate',\r\n 'ghostPlayerStats',\r\n 'gameDeletion',\r\n] as const;\r\nexport type StatsOperationKind = (typeof STATS_OPERATION_KIND_KEYS)[number];\r\n\r\n// The rebuilds: each replaces one destination from the finalized games, a unit at a time, and shares\r\n// one paged run.\r\nexport const STATS_REBUILD_OPERATION_KIND_KEYS = [\r\n 'leagueStatsRebuild',\r\n 'lifetimeStatsRebuild',\r\n 'hallOfFameRebuild',\r\n] as const satisfies readonly StatsOperationKind[];\r\nexport type StatsRebuildOperationKind = (typeof STATS_REBUILD_OPERATION_KIND_KEYS)[number];\r\n\r\nexport const STATS_OPERATION_STATUS_KEYS = ['running', 'complete', 'stopped'] as const;\r\nexport type StatsOperationStatus = (typeof STATS_OPERATION_STATUS_KEYS)[number];\r\n\r\n// A validation run checks every game first, then the destinations those games feed.\r\nexport const STATS_VALIDATION_PHASE_KEYS = ['games', 'destinations'] as const;\r\nexport type StatsValidationPhase = (typeof STATS_VALIDATION_PHASE_KEYS)[number];\r\n\r\n// A ghost has one operation for both of its ways out, so a link and a removal refuse each other.\r\nexport const GHOST_STATS_OPERATION_ACTION_KEYS = ['link', 'removal'] as const;\r\nexport type GhostStatsOperationAction = (typeof GHOST_STATS_OPERATION_ACTION_KEYS)[number];\r\n\r\n// Why a scoring write refused an event. The first ten are a sport adapter's `validate`; the last\r\n// four are the store driver's own: an id already stored, or earlier in the batch, with different\r\n// content; a void whose target is missing, a void, or a correction; a correction sent to a scoring\r\n// entry, which only the game-reconcile core appends; and a void that would leave a stat below zero,\r\n// because a later edit already moved its target's field down.\r\nexport const STAT_EVENT_REFUSAL_KEYS = [\r\n 'eventTypeNotInSport',\r\n 'teamNotInGame',\r\n 'playerNotRostered',\r\n 'assisterNotRostered',\r\n 'assistNotAllowed',\r\n 'playerNotAllowed',\r\n 'roundNotNext',\r\n 'roundsComplete',\r\n 'bulkValueInvalid',\r\n 'bulkStale',\r\n 'eventIdConflict',\r\n 'voidTargetNotSportEvent',\r\n 'correctionNotAccepted',\r\n 'undoBelowZero',\r\n] as const;\r\nexport type StatEventRefusalCode = (typeof STAT_EVENT_REFUSAL_KEYS)[number];\r\n\r\n// Why a game may not be finalized yet — a sport played in rounds with an end still unrecorded.\r\nexport const FINALIZATION_NOT_READY_KEYS = ['roundsIncomplete'] as const;\r\nexport type FinalizationNotReadyReason = (typeof FINALIZATION_NOT_READY_KEYS)[number];\r\n\r\n// The scoring panel a sport's adapter names; the scoring screen renders one component per kind.\r\nexport const SCORING_PANEL_KIND_KEYS = ['playerEvents', 'teamPoints', 'rounds'] as const;\r\nexport type ScoringPanelKind = (typeof SCORING_PANEL_KIND_KEYS)[number];\r\n\r\n// The bulk-entry form body a sport's adapter names; the bulk-entry dialog renders one per kind.\r\nexport const BULK_ENTRY_KIND_KEYS = ['playerLines', 'teamScores', 'rounds'] as const;\r\nexport type BulkEntryKind = (typeof BULK_ENTRY_KIND_KEYS)[number];\r\n\r\n// What a scoring write did with each event it was sent: stored it now, or found it already stored\r\n// by an earlier send and acknowledged it without applying it again.\r\nexport const RECORDED_STAT_EVENT_OUTCOME_KEYS = ['recorded', 'alreadyRecorded'] as const;\r\nexport type RecordedStatEventOutcome = (typeof RECORDED_STAT_EVENT_OUTCOME_KEYS)[number];\r\n\r\n// What finalize did: made the game's numbers permanent, or found it already finalized and changed\r\n// nothing (SPORT-203).\r\nexport const GAME_FINALIZE_OUTCOME_KEYS = ['finalized', 'alreadyFinalized'] as const;\r\nexport type GameFinalizeOutcome = (typeof GAME_FINALIZE_OUTCOME_KEYS)[number];\r\n\r\n// What reopen did: took a finalized game's numbers back out, or found the game already open and\r\n// changed nothing.\r\nexport const GAME_REOPEN_OUTCOME_KEYS = ['reopened', 'alreadyOpen'] as const;\r\nexport type GameReopenOutcome = (typeof GAME_REOPEN_OUTCOME_KEYS)[number];\r\n\r\n// Why a path that makes numbers permanent, or takes them back, refused a game whose stored numbers\r\n// disagree with what produced them — something changed them outside the app, and an admin\r\n// reconciles the game in Fix stats first. Finalize, reopen, and a ghost link never adopt or discard\r\n// an unexplained difference (ENG-009):\r\n// statsOutOfBand the rollup or score mirror is not the replay of the game's events or record\r\n// finalRecordMissing a completed game has no finalized record\r\n// aggregateBelowZero a stored derived line holds less than the game put into it\r\nexport const STATS_INTEGRITY_REFUSAL_KEYS = ['statsOutOfBand', 'finalRecordMissing', 'aggregateBelowZero'] as const;\r\nexport type StatsIntegrityRefusal = (typeof STATS_INTEGRITY_REFUSAL_KEYS)[number];\r\n\r\n// What a game repair in Fix stats did: changed the game (`reconciled`), found nothing to change\r\n// (`unchanged`), or found its operation already committed and acknowledged the retry\r\n// (`alreadyApplied`).\r\nexport const GAME_STATS_REPAIR_OUTCOME_KEYS = ['reconciled', 'unchanged', 'alreadyApplied'] as const;\r\nexport type GameStatsRepairOutcome = (typeof GAME_STATS_REPAIR_OUTCOME_KEYS)[number];\r\n\r\n// Why a game repair in Fix stats was refused, in the refusal's details, so the form says what to do:\r\n// eventUnreadable an event document no longer parses or replays — fix it in the console first\r\n// sourcesDisagree the record, the stored rollup, and the events all disagree: no one of them\r\n// says what finalize applied\r\n// scoreAmbiguous keep-stored: the team line's score and the score mirror were both edited, to\r\n// different values — give the score as a target instead\r\n// fieldNotCorrectable a field the sport's adapter does not let a correction change — restore from\r\n// the events instead, or reopen and re-score\r\n// lineNotRostered a line for someone not on the game's roster\r\n// teamNotInGame a target names a team the game does not hold\r\n// gameTooLarge the repair would not fit in one commit\r\nexport const GAME_REPAIR_REFUSAL_KEYS = [\r\n 'eventUnreadable',\r\n 'sourcesDisagree',\r\n 'scoreAmbiguous',\r\n 'fieldNotCorrectable',\r\n 'lineNotRostered',\r\n 'teamNotInGame',\r\n 'gameTooLarge',\r\n] as const;\r\nexport type GameRepairRefusal = (typeof GAME_REPAIR_REFUSAL_KEYS)[number];\r\n\r\n// What a ghost link did with the team's memberships: the ghost's membership became the account's\r\n// (`handedOver`); the account had none and the ghost none either, so the closed-league link gave the\r\n// account one (`created`); both held one and one survives with the higher role (`merged`); or only\r\n// the account held one, and it stands (`kept`).\r\nexport const GHOST_LINK_MEMBERSHIP_OUTCOME_KEYS = ['handedOver', 'created', 'merged', 'kept'] as const;\r\nexport type GhostLinkMembershipOutcome = (typeof GHOST_LINK_MEMBERSHIP_OUTCOME_KEYS)[number];\r\n\r\n// What the migration's placement of an unplaceable V1 stat line did: `alreadyResolved` when the game\r\n// already held the entry it would write — nothing was written.\r\nexport const UNROSTERED_STAT_LINE_RESOLUTION_OUTCOME_KEYS = ['resolved', 'alreadyResolved'] as const;\r\nexport type UnrosteredStatLineResolutionOutcome = (typeof UNROSTERED_STAT_LINE_RESOLUTION_OUTCOME_KEYS)[number];\r\n\r\n// Why a ghost's removal was refused, in the refusal's details, so the client answers each one: the\r\n// ghost has played (link it instead) or its removal stopped on finding it had; a game the removal\r\n// needs is held by another operation (try again shortly); the ghost is being, or was, linked; the\r\n// ghost is the team's captain (change the captain first).\r\nexport const GHOST_REMOVAL_REFUSAL_KEYS = ['ghostHasPlayed', 'removalStopped', 'gameHeld', 'ghostBeingLinked', 'captainNotRemovable'] as const;\r\nexport type GhostRemovalRefusal = (typeof GHOST_REMOVAL_REFUSAL_KEYS)[number];\r\n\r\n"]}
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/types/stats.ts"],"names":[],"mappings":"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","sourcesContent":["// Canonical unions of the stat event store and the stats operations (ARCH-102). What each sport's\n// own events and lines are is ./sports.ts; these are the sport-agnostic halves every sport shares.\n\nimport { CAPTAIN_TEAM_ROLES, SYSTEM_ROLE_KEYS } from './unions.js';\n\n// The two store-level events, members of every sport's event union. A void undoes the one event it\n// targets; a correction adds a signed value to one correctable field of one line.\nexport const STAT_VOID_EVENT_TYPE = 'STAT_VOID';\nexport const STAT_CORRECTION_EVENT_TYPE = 'STAT_CORRECTION';\nexport const STAT_STORE_EVENT_TYPE_KEYS = [STAT_VOID_EVENT_TYPE, STAT_CORRECTION_EVENT_TYPE] as const;\nexport type StatStoreEventType = (typeof STAT_STORE_EVENT_TYPE_KEYS)[number];\n\n// The fields of a stored stat event the writing core derives — its place in the replay, and who\n// recorded it under which authority — so a caller never sends them (ARCH-106).\nexport const STAT_EVENT_RECORDER_FIELD_KEYS = [\n 'sequence',\n 'acceptedAt',\n 'recordedByUserId',\n 'recordedByAuthority',\n 'recordedByTeamId',\n] as const;\nexport type StatEventRecorderField = (typeof STAT_EVENT_RECORDER_FIELD_KEYS)[number];\n\n// The name snapshots only a copied event carries; nothing writes one on a new event (SPORT-104).\nexport const STAT_EVENT_SNAPSHOT_FIELD_KEYS = ['displayNameSnapshot', 'assistedByDisplayNameSnapshot'] as const;\nexport type StatEventSnapshotField = (typeof STAT_EVENT_SNAPSHOT_FIELD_KEYS)[number];\n\n// Who appended a correction: an admin reconciling a game, or the copy that carries a recorded\n// result its events do not explain.\nexport const STAT_CORRECTION_SOURCE_KEYS = ['admin', 'migration'] as const;\nexport type StatCorrectionSource = (typeof STAT_CORRECTION_SOURCE_KEYS)[number];\n\n// The authority the writing core confirmed for an event: a global role, or a team role on one of\n// the game's teams.\nexport const STAT_EVENT_AUTHORITY_KEYS = [...SYSTEM_ROLE_KEYS, ...CAPTAIN_TEAM_ROLES] as const;\nexport type StatEventAuthority = (typeof STAT_EVENT_AUTHORITY_KEYS)[number];\n\n// Every kind of stat line: the four player kinds, then the two team kinds. A sport's line of each\n// kind is declared once, in `SPORT_LINE_SCHEMAS`; a kind a sport has no line for is `never` there.\nexport const PLAYER_STAT_LINE_KIND_KEYS = ['gamePlayer', 'membershipRow', 'lifetime', 'hallOfFame'] as const;\nexport const TEAM_STAT_LINE_KIND_KEYS = ['gameTeam', 'teamSeason'] as const;\nexport const STAT_LINE_KIND_KEYS = [...PLAYER_STAT_LINE_KIND_KEYS, ...TEAM_STAT_LINE_KIND_KEYS] as const;\nexport type StatLineKind = (typeof STAT_LINE_KIND_KEYS)[number];\nexport type PlayerStatLineKind = (typeof PLAYER_STAT_LINE_KIND_KEYS)[number];\n\n// One logical run of a stats action, recorded on its `statsOperations` document.\nexport const STATS_OPERATION_KIND_KEYS = [\n 'leagueStatsRebuild',\n 'lifetimeStatsRebuild',\n 'hallOfFameRebuild',\n 'statsValidation',\n 'gameStatsCorrection',\n 'gameStatsRecalculation',\n 'historicalStatsUpdate',\n 'ghostPlayerStats',\n 'gameDeletion',\n] as const;\nexport type StatsOperationKind = (typeof STATS_OPERATION_KIND_KEYS)[number];\n\n// The rebuilds: each replaces one destination from the finalized games, a unit at a time, and shares\n// one paged run.\nexport const STATS_REBUILD_OPERATION_KIND_KEYS = [\n 'leagueStatsRebuild',\n 'lifetimeStatsRebuild',\n 'hallOfFameRebuild',\n] as const satisfies readonly StatsOperationKind[];\nexport type StatsRebuildOperationKind = (typeof STATS_REBUILD_OPERATION_KIND_KEYS)[number];\n\nexport const STATS_OPERATION_STATUS_KEYS = ['running', 'complete', 'stopped'] as const;\nexport type StatsOperationStatus = (typeof STATS_OPERATION_STATUS_KEYS)[number];\n\n// A validation run checks every game first, then the destinations those games feed.\nexport const STATS_VALIDATION_PHASE_KEYS = ['games', 'destinations'] as const;\nexport type StatsValidationPhase = (typeof STATS_VALIDATION_PHASE_KEYS)[number];\n\n// A ghost has one operation for both of its ways out, so a link and a removal refuse each other.\nexport const GHOST_STATS_OPERATION_ACTION_KEYS = ['link', 'removal'] as const;\nexport type GhostStatsOperationAction = (typeof GHOST_STATS_OPERATION_ACTION_KEYS)[number];\n\n// Why a scoring write refused an event. The first ten are a sport adapter's `validate`; the last\n// four are the store driver's own: an id already stored, or earlier in the batch, with different\n// content; a void whose target is missing, a void, or a correction; a correction sent to a scoring\n// entry, which only the game-reconcile core appends; and a void that would leave a stat below zero,\n// because a later edit already moved its target's field down.\nexport const STAT_EVENT_REFUSAL_KEYS = [\n 'eventTypeNotInSport',\n 'teamNotInGame',\n 'playerNotRostered',\n 'assisterNotRostered',\n 'assistNotAllowed',\n 'playerNotAllowed',\n 'roundNotNext',\n 'roundsComplete',\n 'bulkValueInvalid',\n 'bulkStale',\n 'eventIdConflict',\n 'voidTargetNotSportEvent',\n 'correctionNotAccepted',\n 'undoBelowZero',\n] as const;\nexport type StatEventRefusalCode = (typeof STAT_EVENT_REFUSAL_KEYS)[number];\n\n// Why a game may not be finalized yet — a sport played in rounds with an end still unrecorded.\nexport const FINALIZATION_NOT_READY_KEYS = ['roundsIncomplete'] as const;\nexport type FinalizationNotReadyReason = (typeof FINALIZATION_NOT_READY_KEYS)[number];\n\n// The scoring panel a sport's adapter names; the scoring screen renders one component per kind.\nexport const SCORING_PANEL_KIND_KEYS = ['playerEvents', 'teamPoints', 'rounds'] as const;\nexport type ScoringPanelKind = (typeof SCORING_PANEL_KIND_KEYS)[number];\n\n// The bulk-entry form body a sport's adapter names; the bulk-entry dialog renders one per kind.\nexport const BULK_ENTRY_KIND_KEYS = ['playerLines', 'teamScores', 'rounds'] as const;\nexport type BulkEntryKind = (typeof BULK_ENTRY_KIND_KEYS)[number];\n\n// What a scoring write did with each event it was sent: stored it now, or found it already stored\n// by an earlier send and acknowledged it without applying it again.\nexport const RECORDED_STAT_EVENT_OUTCOME_KEYS = ['recorded', 'alreadyRecorded'] as const;\nexport type RecordedStatEventOutcome = (typeof RECORDED_STAT_EVENT_OUTCOME_KEYS)[number];\n\n// What finalize did: made the game's numbers permanent, or found it already finalized and changed\n// nothing (SPORT-203).\nexport const GAME_FINALIZE_OUTCOME_KEYS = ['finalized', 'alreadyFinalized'] as const;\nexport type GameFinalizeOutcome = (typeof GAME_FINALIZE_OUTCOME_KEYS)[number];\n\n// What reopen did: took a finalized game's numbers back out, or found the game already open and\n// changed nothing.\nexport const GAME_REOPEN_OUTCOME_KEYS = ['reopened', 'alreadyOpen'] as const;\nexport type GameReopenOutcome = (typeof GAME_REOPEN_OUTCOME_KEYS)[number];\n\n// Why a path that makes numbers permanent, or takes them back, refused a game whose stored numbers\n// disagree with what produced them — something changed them outside the app, and an admin\n// reconciles the game in Fix stats first. Finalize, reopen, and a ghost link never adopt or discard\n// an unexplained difference (ENG-009):\n// statsOutOfBand the rollup or score mirror is not the replay of the game's events or record\n// finalRecordMissing a completed game has no finalized record\n// aggregateBelowZero a stored derived line holds less than the game put into it\nexport const STATS_INTEGRITY_REFUSAL_KEYS = ['statsOutOfBand', 'finalRecordMissing', 'aggregateBelowZero'] as const;\nexport type StatsIntegrityRefusal = (typeof STATS_INTEGRITY_REFUSAL_KEYS)[number];\n\n// What a game repair in Fix stats did: changed the game (`reconciled`), found nothing to change\n// (`unchanged`), or found its operation already committed and acknowledged the retry\n// (`alreadyApplied`).\nexport const GAME_STATS_REPAIR_OUTCOME_KEYS = ['reconciled', 'unchanged', 'alreadyApplied'] as const;\nexport type GameStatsRepairOutcome = (typeof GAME_STATS_REPAIR_OUTCOME_KEYS)[number];\n\n// Why a game repair in Fix stats was refused, in the refusal's details, so the form says what to do:\n// eventUnreadable an event document no longer parses or replays — fix it in the console first\n// sourcesDisagree the record, the stored rollup, and the events all disagree: no one of them\n// says what finalize applied\n// scoreAmbiguous keep-stored: the team line's score and the score mirror were both edited, to\n// different values — give the score as a target instead\n// fieldNotCorrectable a field the sport's adapter does not let a correction change — restore from\n// the events instead, or reopen and re-score\n// lineNotRostered a line for someone not on the game's roster\n// teamNotInGame a target names a team the game does not hold\n// gameTooLarge the repair would not fit in one commit\nexport const GAME_REPAIR_REFUSAL_KEYS = [\n 'eventUnreadable',\n 'sourcesDisagree',\n 'scoreAmbiguous',\n 'fieldNotCorrectable',\n 'lineNotRostered',\n 'teamNotInGame',\n 'gameTooLarge',\n] as const;\nexport type GameRepairRefusal = (typeof GAME_REPAIR_REFUSAL_KEYS)[number];\n\n// What a ghost link did with the team's memberships: the ghost's membership became the account's\n// (`handedOver`); the account had none and the ghost none either, so the closed-league link gave the\n// account one (`created`); both held one and one survives with the higher role (`merged`); or only\n// the account held one, and it stands (`kept`).\nexport const GHOST_LINK_MEMBERSHIP_OUTCOME_KEYS = ['handedOver', 'created', 'merged', 'kept'] as const;\nexport type GhostLinkMembershipOutcome = (typeof GHOST_LINK_MEMBERSHIP_OUTCOME_KEYS)[number];\n\n// What the migration's placement of an unplaceable V1 stat line did: `alreadyResolved` when the game\n// already held the entry it would write — nothing was written.\nexport const UNROSTERED_STAT_LINE_RESOLUTION_OUTCOME_KEYS = ['resolved', 'alreadyResolved'] as const;\nexport type UnrosteredStatLineResolutionOutcome = (typeof UNROSTERED_STAT_LINE_RESOLUTION_OUTCOME_KEYS)[number];\n\n// Why a ghost's removal was refused, in the refusal's details, so the client answers each one: the\n// ghost has played (link it instead) or its removal stopped on finding it had; a game the removal\n// needs is held by another operation (try again shortly); the ghost is being, or was, linked; the\n// ghost is the team's captain (change the captain first).\nexport const GHOST_REMOVAL_REFUSAL_KEYS = ['ghostHasPlayed', 'removalStopped', 'gameHeld', 'ghostBeingLinked', 'captainNotRemovable'] as const;\nexport type GhostRemovalRefusal = (typeof GHOST_REMOVAL_REFUSAL_KEYS)[number];\n\n"]}
|
package/dist/types/unions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unions.js","sourceRoot":"","sources":["../../src/types/unions.ts"],"names":[],"mappings":"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","sourcesContent":["// Canonical unions (ARCH-102): an `as const` key array with the type derived from it. Zod enums,\r\n// type positions, query filters, and option lists all derive from these arrays — never a quoted\r\n// member.\r\n\r\n// The two global roles. Each is a roster on `_systemData/adminList` and a boolean custom claim of\r\n// the same name; the roster is the authority, the claim a fast hint.\r\nexport const SYSTEM_ROLE_KEYS = ['admin', 'referee'] as const;\r\nexport type SystemRole = (typeof SYSTEM_ROLE_KEYS)[number];\r\n\r\n// Account status on the private profile. Only an exact `active` passes the server auth assertion.\r\nexport const USER_STATUS_KEYS = ['active', 'banned'] as const;\r\nexport type UserStatus = (typeof USER_STATUS_KEYS)[number];\r\n/** The one status that lets an account act. */\r\nexport const ACTIVE_USER_STATUS = 'active' satisfies UserStatus;\r\n/** The status an admin's ban sets: the account keeps its data and cannot sign in. */\r\nexport const BANNED_USER_STATUS = 'banned' satisfies UserStatus;\r\n\r\n// Which post-commit Auth effect queued an account on `statusReconcileQueue/{userId}`:\r\n// `accountStatus` — a status change's disabled flag, status claim, and token revocation, queued in\r\n// the status transaction itself; `roleClaims` — the `admin` / `referee` claims after a failed roster\r\n// claim write.\r\nexport const STATUS_RECONCILE_QUEUE_AUTH_EFFECTS = ['accountStatus', 'roleClaims'] as const;\r\nexport type StatusReconcileQueueAuthEffect = (typeof STATUS_RECONCILE_QUEUE_AUTH_EFFECTS)[number];\r\nexport const ACCOUNT_STATUS_AUTH_EFFECT = 'accountStatus' as const satisfies StatusReconcileQueueAuthEffect;\r\nexport const ROLE_CLAIMS_EFFECT = 'roleClaims' as const satisfies StatusReconcileQueueAuthEffect;\r\n\r\nexport const TEAM_ROLE_KEYS = ['captain', 'coCaptain', 'player'] as const;\r\nexport type TeamRole = (typeof TEAM_ROLE_KEYS)[number];\r\n\r\n// The roles that carry captain authority. `firestore.rules` restates this list, because a rules file\r\n// cannot import it.\r\nexport const CAPTAIN_TEAM_ROLES = ['captain', 'coCaptain'] as const satisfies readonly TeamRole[];\r\n\r\n// The one role a team holds at most one of: team creation, the admin captain change, and ghost\r\n// linking write it, and nothing else does.\r\nexport const TEAM_CAPTAIN_ROLE = 'captain' as const satisfies TeamRole;\r\n\r\n// The two roles below the captain. A co-captain holds every captain power except managing\r\n// co-captains; a player holds none.\r\nexport const TEAM_CO_CAPTAIN_ROLE = 'coCaptain' as const satisfies TeamRole;\r\nexport const TEAM_PLAYER_ROLE = 'player' as const satisfies TeamRole;\r\n\r\n// The roles a member's role change moves a membership between — promoting a player to co-captain,\r\n// or demoting a co-captain to player. The captain's role moves only through the admin's captain\r\n// change, so it is never one of them.\r\nexport const MEMBER_ASSIGNABLE_TEAM_ROLES = [TEAM_CO_CAPTAIN_ROLE, TEAM_PLAYER_ROLE] as const satisfies readonly TeamRole[];\r\nexport type MemberAssignableTeamRole = (typeof MEMBER_ASSIGNABLE_TEAM_ROLES)[number];\r\n\r\n// A ghost link that merges a ghost's membership into the account's keeps one membership with the\r\n// higher of the two roles: `TEAM_ROLE_KEYS` runs from the highest role down.\r\nexport function higherTeamRole(left: TeamRole, right: TeamRole): TeamRole {\r\n return TEAM_ROLE_KEYS.indexOf(left) <= TEAM_ROLE_KEYS.indexOf(right) ? left : right;\r\n}\r\n\r\nexport const TEAM_MEMBERSHIP_STATUS_KEYS = ['active'] as const;\r\nexport type TeamMembershipStatus = (typeof TEAM_MEMBERSHIP_STATUS_KEYS)[number];\r\n\r\n// The status a membership grants authority in. Every membership-based check reads it with the role\r\n// (BACKEND-006), so a status added later grants nothing until a check names it.\r\nexport const ACTIVE_TEAM_MEMBERSHIP_STATUS = 'active' as const satisfies TeamMembershipStatus;\r\n\r\n// How a membership came to exist; absent on a membership whose provenance was never recorded.\r\nexport const TEAM_JOIN_METHOD_KEYS = [\r\n 'teamCreation',\r\n 'invite',\r\n 'joinRequest',\r\n 'freeAgent',\r\n 'ghostAdd',\r\n] as const;\r\nexport type TeamJoinMethod = (typeof TEAM_JOIN_METHOD_KEYS)[number];\r\n\r\nexport const LEAGUE_STATUS_KEYS = ['pending', 'upcoming', 'active', 'closed'] as const;\r\nexport type LeagueStatus = (typeof LEAGUE_STATUS_KEYS)[number];\r\n\r\n// Every league is created unpublished; the admin moves it forward from here.\r\nexport const LEAGUE_STATUS_ON_CREATE = 'pending' as const satisfies LeagueStatus;\r\n\r\n// A finished season. Its settings stay editable; its status and mode never change again.\r\nexport const CLOSED_LEAGUE_STATUS = 'closed' as const satisfies LeagueStatus;\r\n\r\n// The two published statuses before a league closes: its teams are forming, then it is in play.\r\nexport const UPCOMING_LEAGUE_STATUS = 'upcoming' as const satisfies LeagueStatus;\r\nexport const ACTIVE_LEAGUE_STATUS = 'active' as const satisfies LeagueStatus;\r\n\r\n// The statuses a league may move to from each status. Movement is forward only, and `closed` is\r\n// final; the status callable refuses any other move.\r\nexport const LEAGUE_STATUS_TRANSITIONS: Readonly<Record<LeagueStatus, readonly LeagueStatus[]>> = {\r\n pending: ['upcoming', 'closed'],\r\n upcoming: ['active', 'closed'],\r\n active: ['closed'],\r\n closed: [],\r\n};\r\n\r\n// Every status but closed: a league still being set up, published, or played. Whatever such a\r\n// league is configured with — its waiver template among them — is still in use.\r\nexport const OPEN_LEAGUE_STATUS_KEYS: readonly Exclude<LeagueStatus, typeof CLOSED_LEAGUE_STATUS>[] =\r\n LEAGUE_STATUS_KEYS.filter(\r\n (status): status is Exclude<LeagueStatus, typeof CLOSED_LEAGUE_STATUS> => status !== CLOSED_LEAGUE_STATUS,\r\n );\r\n\r\n// A league players are part of now or next: published and not yet closed. The admin dashboard's\r\n// active free-agent count covers only these leagues.\r\nexport const CURRENT_LEAGUE_STATUS_KEYS = [\r\n UPCOMING_LEAGUE_STATUS,\r\n ACTIVE_LEAGUE_STATUS,\r\n] as const satisfies readonly LeagueStatus[];\r\n\r\nexport const LEAGUE_MODE_KEYS = ['Regular', 'Competitive/Recreational'] as const;\r\nexport type LeagueMode = (typeof LEAGUE_MODE_KEYS)[number];\r\n\r\n// Present only on teams in a Competitive/Recreational league. In any other mode a team has no type:\r\n// the field is absent, never null.\r\nexport const TEAM_TYPE_KEYS = ['Competitive', 'Recreational'] as const;\r\nexport type TeamType = (typeof TEAM_TYPE_KEYS)[number];\r\n\r\n// The one mode whose teams each carry a `teamType`.\r\nexport const TEAM_TYPED_LEAGUE_MODE = 'Competitive/Recreational' as const satisfies LeagueMode;\r\n\r\n// The type every team takes when its league switches into `TEAM_TYPED_LEAGUE_MODE`.\r\nexport const TEAM_TYPE_ON_MODE_SWITCH = 'Recreational' as const satisfies TeamType;\r\n\r\nexport const GAME_STATUS_KEYS = ['scheduled', 'inprogress', 'completed'] as const;\r\nexport type GameStatus = (typeof GAME_STATUS_KEYS)[number];\r\n\r\n// The one status a finished game holds: it was played, and its stats count. Every reader asking\r\n// whether a game was played compares against this rather than naming a status of its own.\r\nexport const COMPLETED_GAME_STATUS = 'completed' as const satisfies GameStatus;\r\n\r\n// The status a newly scheduled game is created in.\r\nexport const GAME_STATUS_ON_CREATE = 'scheduled' as const satisfies GameStatus;\r\n\r\n// The status reopen returns a finalized game to: open for scoring again, its record of who played\r\n// kept.\r\nexport const GAME_STATUS_ON_REOPEN = 'inprogress' as const satisfies GameStatus;\r\n\r\n// An invitation is pending until the invitee accepts (`approved`) or declines (`rejected`) it, or the\r\n// team withdraws it (`cancelled`). A membership on its team made any other way closes it `approved`.\r\nexport const TEAM_INVITATION_STATUS_KEYS = ['pending', 'approved', 'rejected', 'cancelled'] as const;\r\nexport type TeamInvitationStatus = (typeof TEAM_INVITATION_STATUS_KEYS)[number];\r\n\r\nexport const PENDING_TEAM_INVITATION_STATUS = 'pending' as const satisfies TeamInvitationStatus;\r\nexport const APPROVED_TEAM_INVITATION_STATUS = 'approved' as const satisfies TeamInvitationStatus;\r\nexport const REJECTED_TEAM_INVITATION_STATUS = 'rejected' as const satisfies TeamInvitationStatus;\r\nexport const CANCELLED_TEAM_INVITATION_STATUS = 'cancelled' as const satisfies TeamInvitationStatus;\r\n\r\n// A join request is pending until the team's leaders accept (`approved`) or reject (`rejected`) it,\r\n// or the requester withdraws it (`cancelled`). A membership on its team made any other way closes it\r\n// `approved`.\r\nexport const TEAM_JOIN_REQUEST_STATUS_KEYS = ['pending', 'approved', 'rejected', 'cancelled'] as const;\r\nexport type TeamJoinRequestStatus = (typeof TEAM_JOIN_REQUEST_STATUS_KEYS)[number];\r\n\r\nexport const PENDING_TEAM_JOIN_REQUEST_STATUS = 'pending' as const satisfies TeamJoinRequestStatus;\r\nexport const APPROVED_TEAM_JOIN_REQUEST_STATUS = 'approved' as const satisfies TeamJoinRequestStatus;\r\nexport const REJECTED_TEAM_JOIN_REQUEST_STATUS = 'rejected' as const satisfies TeamJoinRequestStatus;\r\nexport const CANCELLED_TEAM_JOIN_REQUEST_STATUS = 'cancelled' as const satisfies TeamJoinRequestStatus;\r\n\r\nexport const HARDWARE_LOAN_CONTRACT_STATUS_KEYS = ['pending', 'loaned', 'returned'] as const;\r\nexport type HardwareLoanContractStatus = (typeof HARDWARE_LOAN_CONTRACT_STATUS_KEYS)[number];\r\n// Why an award grant passed over an account its teams or leagues named: it has no profile, or it is\r\n// a ghost, which holds no account.\r\nexport const AWARD_GRANT_SKIP_REASON_KEYS = ['noProfile', 'ghost'] as const;\r\nexport type AwardGrantSkipReason = (typeof AWARD_GRANT_SKIP_REASON_KEYS)[number];\r\n\r\nexport const PENDING_HARDWARE_LOAN_CONTRACT_STATUS = 'pending' as const satisfies HardwareLoanContractStatus;\r\nexport const LOANED_HARDWARE_LOAN_CONTRACT_STATUS = 'loaned' as const satisfies HardwareLoanContractStatus;\r\nexport const RETURNED_HARDWARE_LOAN_CONTRACT_STATUS = 'returned' as const satisfies HardwareLoanContractStatus;\r\n\r\n// What deleting a waiver template did. A template nothing names is deleted with its versions; one a\r\n// signature or a closed league still names is retired — kept for them, offered to no new league.\r\nexport const WAIVER_TEMPLATE_DELETE_OUTCOME_KEYS = ['deleted', 'retired'] as const;\r\nexport type WaiverTemplateDeleteOutcome = (typeof WAIVER_TEMPLATE_DELETE_OUTCOME_KEYS)[number];\r\n\r\n// What last changed the stats, as announced on the stats beacon; `link` is a ghost link moving a\r\n// game's lines onto an account.\r\nexport const STATS_BEACON_ACTION_KEYS = ['finalize', 'reopen', 'recalculate', 'correct', 'historical-update', 'link'] as const;\r\nexport type StatsBeaconAction = (typeof STATS_BEACON_ACTION_KEYS)[number];\r\n\r\n// The actions that describe one game, so a beacon announcing one names the game, its league, and its\r\n// teams; every other action names no game, and a game id left beside it would point at a stale one.\r\nexport const GAME_SCOPED_STATS_BEACON_ACTION_KEYS = ['finalize', 'reopen'] as const satisfies readonly StatsBeaconAction[];\r\nexport type GameScopedStatsBeaconAction = (typeof GAME_SCOPED_STATS_BEACON_ACTION_KEYS)[number];\r\n\r\n// The statuses a game's roster still follows its teams' memberships in: listed explicitly, so a\r\n// status added later is closed until it is named here, never open by default.\r\nexport const OPEN_GAME_STATUS_KEYS = ['scheduled', 'inprogress'] as const satisfies readonly GameStatus[];\r\nexport type OpenGameStatus = (typeof OPEN_GAME_STATUS_KEYS)[number];\r\n\r\n// Whether a game is still open — not yet finalized — so a scorer may still change it. Both app roots\r\n// ask this one predicate.\r\nexport function isOpenGameStatus(status: GameStatus): status is OpenGameStatus {\r\n return (OPEN_GAME_STATUS_KEYS as readonly GameStatus[]).includes(status);\r\n}\r\n\r\n// Where one membership's roster obligation stands. `pending` waits for the reconciliation worker;\r\n// `failed` has spent its retries and waits for an admin's retry; `reconciled` owes nothing.\r\nexport const MEMBERSHIP_ROSTER_SYNC_STATUS_KEYS = ['pending', 'reconciled', 'failed'] as const;\r\nexport type MembershipRosterSyncStatus = (typeof MEMBERSHIP_ROSTER_SYNC_STATUS_KEYS)[number];\r\nexport const PENDING_ROSTER_SYNC_STATUS = 'pending' as const satisfies MembershipRosterSyncStatus;\r\nexport const RECONCILED_ROSTER_SYNC_STATUS = 'reconciled' as const satisfies MembershipRosterSyncStatus;\r\nexport const FAILED_ROSTER_SYNC_STATUS = 'failed' as const satisfies MembershipRosterSyncStatus;\r\n\r\n// The authority a ghost's waiver was signed under: the witness's captaincy on the ghost's team, or\r\n// the global role the admin entry confirmed.\r\nexport const WAIVER_WITNESS_AUTHORITY_KEYS = ['captain', 'coCaptain', 'admin', 'referee'] as const;\r\nexport type WaiverWitnessAuthority = (typeof WAIVER_WITNESS_AUTHORITY_KEYS)[number];\r\n\r\n// Why a signing was refused, named in its details so the signing dialog answers it: `waiverChanged`\r\n// when the wording the signer saw — the template id and version the dialog sent — is no longer the\r\n// league's, so the dialog loads the current wording to read again.\r\nexport const WAIVER_SIGNING_REFUSAL_KEYS = ['waiverChanged'] as const;\r\nexport type WaiverSigningRefusal = (typeof WAIVER_SIGNING_REFUSAL_KEYS)[number];\r\n\r\n// The icon a team picks at creation; the persisted value is the icon component's name.\r\nexport const TEAM_ICON_KEYS = [\r\n 'Shield',\r\n 'Swords',\r\n 'Skull',\r\n 'Ghost',\r\n 'Cat',\r\n 'Dog',\r\n 'Bird',\r\n 'Fish',\r\n 'Rabbit',\r\n 'Snail',\r\n 'Turtle',\r\n 'Cherry',\r\n 'Apple',\r\n 'Grape',\r\n 'Rocket',\r\n 'Plane',\r\n 'Ship',\r\n 'Train',\r\n 'Car',\r\n 'Bike',\r\n 'Bolt',\r\n 'Star',\r\n 'Sun',\r\n 'Moon',\r\n 'Cloud',\r\n 'Crown',\r\n 'Diamond',\r\n 'Gem',\r\n 'Anchor',\r\n // Appended — the set only grows, and no stored key is ever renamed or removed. Seasonal and events.\r\n 'TreePine',\r\n 'Trees',\r\n 'TreeDeciduous',\r\n 'TreePalm',\r\n 'Snowflake',\r\n 'MountainSnow',\r\n 'Gift',\r\n 'PartyPopper',\r\n 'CandyCane',\r\n 'Candy',\r\n 'Lollipop',\r\n 'Cake',\r\n 'Egg',\r\n 'Clover',\r\n 'Heart',\r\n 'Flower',\r\n 'Flower2',\r\n 'Rose',\r\n 'Leaf',\r\n 'Sprout',\r\n 'Wheat',\r\n 'Sunrise',\r\n 'Rainbow',\r\n 'Bell',\r\n // Awards and sport.\r\n 'Trophy',\r\n 'Medal',\r\n 'Award',\r\n 'Ribbon',\r\n 'Flag',\r\n 'Target',\r\n 'Crosshair',\r\n 'Goal',\r\n 'Dumbbell',\r\n 'Footprints',\r\n // Power and the elements.\r\n 'Zap',\r\n 'Flame',\r\n 'FlameKindling',\r\n 'Bomb',\r\n 'Atom',\r\n 'Orbit',\r\n 'Sparkles',\r\n 'WandSparkles',\r\n 'Mountain',\r\n 'Tornado',\r\n 'Wind',\r\n 'Droplet',\r\n 'CloudLightning',\r\n 'MoonStar',\r\n // Arms and strongholds.\r\n 'Sword',\r\n 'Axe',\r\n 'Hammer',\r\n 'Pickaxe',\r\n 'ShieldHalf',\r\n 'Castle',\r\n // Animals.\r\n 'Squirrel',\r\n 'Rat',\r\n 'Panda',\r\n 'Shrimp',\r\n 'Worm',\r\n 'Bug',\r\n 'Shell',\r\n 'PawPrint',\r\n 'Feather',\r\n 'Bone',\r\n 'Origami',\r\n // Food.\r\n 'Citrus',\r\n 'Banana',\r\n 'Carrot',\r\n 'Pizza',\r\n 'Cookie',\r\n 'Donut',\r\n 'Coffee',\r\n // Games and music.\r\n 'Dices',\r\n 'Puzzle',\r\n 'Gamepad2',\r\n 'Spade',\r\n 'Club',\r\n 'Music',\r\n 'Guitar',\r\n 'Hexagon',\r\n 'Triangle',\r\n // Travel.\r\n 'Sailboat',\r\n 'Tractor',\r\n 'Truck',\r\n] as const;\r\nexport type TeamIcon = (typeof TEAM_ICON_KEYS)[number];\r\n\r\n// A picture's processed sizes, smallest first: every picture kind declares all three, and a display\r\n// asks for the smallest one that covers its slot.\r\nexport const PICTURE_VARIANT_KEYS = ['sm', 'md', 'lg'] as const;\r\nexport type PictureVariantKey = (typeof PICTURE_VARIANT_KEYS)[number];\r\n\r\n// What a stats check found, game tier first — a game's own numbers are the cause of the aggregate\r\n// findings, so Fix stats repairs games before it rebuilds what they feed.\r\nexport const GAME_TIER_DISCREPANCY_KIND_KEYS = [\r\n 'invalidEvent',\r\n 'eventSequenceMismatch',\r\n 'rollupMismatch',\r\n 'scoreMirrorMismatch',\r\n 'unrosteredStatLine',\r\n 'fantasyPointsStale',\r\n 'finalRecordMissing',\r\n 'finalRecordMismatch',\r\n 'participationSnapshotMismatch',\r\n 'gameHeld',\r\n] as const;\r\nexport const AGGREGATE_TIER_DISCREPANCY_KIND_KEYS = [\r\n 'aggregateMismatch',\r\n 'aggregateEntryStale',\r\n 'aggregateEntryMissing',\r\n 'hallOfFameLifetimeMismatch',\r\n] as const;\r\nexport const STATS_DISCREPANCY_KIND_KEYS = [\r\n ...GAME_TIER_DISCREPANCY_KIND_KEYS,\r\n ...AGGREGATE_TIER_DISCREPANCY_KIND_KEYS,\r\n] as const;\r\nexport type StatsDiscrepancyKind = (typeof STATS_DISCREPANCY_KIND_KEYS)[number];\r\n"]}
|
|
1
|
+
{"version":3,"file":"unions.js","sourceRoot":"","sources":["../../src/types/unions.ts"],"names":[],"mappings":"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","sourcesContent":["// Canonical unions (ARCH-102): an `as const` key array with the type derived from it. Zod enums,\n// type positions, query filters, and option lists all derive from these arrays — never a quoted\n// member.\n\n// The two global roles. Each is a roster on `_systemData/adminList` and a boolean custom claim of\n// the same name; the roster is the authority, the claim a fast hint.\nexport const SYSTEM_ROLE_KEYS = ['admin', 'referee'] as const;\nexport type SystemRole = (typeof SYSTEM_ROLE_KEYS)[number];\n\n// Account status on the private profile. Only an exact `active` passes the server auth assertion.\nexport const USER_STATUS_KEYS = ['active', 'banned'] as const;\nexport type UserStatus = (typeof USER_STATUS_KEYS)[number];\n/** The one status that lets an account act. */\nexport const ACTIVE_USER_STATUS = 'active' satisfies UserStatus;\n/** The status an admin's ban sets: the account keeps its data and cannot sign in. */\nexport const BANNED_USER_STATUS = 'banned' satisfies UserStatus;\n\n// Which post-commit Auth effect queued an account on `statusReconcileQueue/{userId}`:\n// `accountStatus` — a status change's disabled flag, status claim, and token revocation, queued in\n// the status transaction itself; `roleClaims` — the `admin` / `referee` claims after a failed roster\n// claim write.\nexport const STATUS_RECONCILE_QUEUE_AUTH_EFFECTS = ['accountStatus', 'roleClaims'] as const;\nexport type StatusReconcileQueueAuthEffect = (typeof STATUS_RECONCILE_QUEUE_AUTH_EFFECTS)[number];\nexport const ACCOUNT_STATUS_AUTH_EFFECT = 'accountStatus' as const satisfies StatusReconcileQueueAuthEffect;\nexport const ROLE_CLAIMS_EFFECT = 'roleClaims' as const satisfies StatusReconcileQueueAuthEffect;\n\nexport const TEAM_ROLE_KEYS = ['captain', 'coCaptain', 'player'] as const;\nexport type TeamRole = (typeof TEAM_ROLE_KEYS)[number];\n\n// The roles that carry captain authority. `firestore.rules` restates this list, because a rules file\n// cannot import it.\nexport const CAPTAIN_TEAM_ROLES = ['captain', 'coCaptain'] as const satisfies readonly TeamRole[];\n\n// The one role a team holds at most one of: team creation, the admin captain change, and ghost\n// linking write it, and nothing else does.\nexport const TEAM_CAPTAIN_ROLE = 'captain' as const satisfies TeamRole;\n\n// The two roles below the captain. A co-captain holds every captain power except managing\n// co-captains; a player holds none.\nexport const TEAM_CO_CAPTAIN_ROLE = 'coCaptain' as const satisfies TeamRole;\nexport const TEAM_PLAYER_ROLE = 'player' as const satisfies TeamRole;\n\n// The roles a member's role change moves a membership between — promoting a player to co-captain,\n// or demoting a co-captain to player. The captain's role moves only through the admin's captain\n// change, so it is never one of them.\nexport const MEMBER_ASSIGNABLE_TEAM_ROLES = [TEAM_CO_CAPTAIN_ROLE, TEAM_PLAYER_ROLE] as const satisfies readonly TeamRole[];\nexport type MemberAssignableTeamRole = (typeof MEMBER_ASSIGNABLE_TEAM_ROLES)[number];\n\n// A ghost link that merges a ghost's membership into the account's keeps one membership with the\n// higher of the two roles: `TEAM_ROLE_KEYS` runs from the highest role down.\nexport function higherTeamRole(left: TeamRole, right: TeamRole): TeamRole {\n return TEAM_ROLE_KEYS.indexOf(left) <= TEAM_ROLE_KEYS.indexOf(right) ? left : right;\n}\n\nexport const TEAM_MEMBERSHIP_STATUS_KEYS = ['active'] as const;\nexport type TeamMembershipStatus = (typeof TEAM_MEMBERSHIP_STATUS_KEYS)[number];\n\n// The status a membership grants authority in. Every membership-based check reads it with the role\n// (BACKEND-006), so a status added later grants nothing until a check names it.\nexport const ACTIVE_TEAM_MEMBERSHIP_STATUS = 'active' as const satisfies TeamMembershipStatus;\n\n// How a membership came to exist; absent on a membership whose provenance was never recorded.\nexport const TEAM_JOIN_METHOD_KEYS = [\n 'teamCreation',\n 'invite',\n 'joinRequest',\n 'freeAgent',\n 'ghostAdd',\n] as const;\nexport type TeamJoinMethod = (typeof TEAM_JOIN_METHOD_KEYS)[number];\n\nexport const LEAGUE_STATUS_KEYS = ['pending', 'upcoming', 'active', 'closed'] as const;\nexport type LeagueStatus = (typeof LEAGUE_STATUS_KEYS)[number];\n\n// Every league is created unpublished; the admin moves it forward from here.\nexport const LEAGUE_STATUS_ON_CREATE = 'pending' as const satisfies LeagueStatus;\n\n// A finished season. Its settings stay editable; its status and mode never change again.\nexport const CLOSED_LEAGUE_STATUS = 'closed' as const satisfies LeagueStatus;\n\n// The two published statuses before a league closes: its teams are forming, then it is in play.\nexport const UPCOMING_LEAGUE_STATUS = 'upcoming' as const satisfies LeagueStatus;\nexport const ACTIVE_LEAGUE_STATUS = 'active' as const satisfies LeagueStatus;\n\n// The statuses a league may move to from each status. Movement is forward only, and `closed` is\n// final; the status callable refuses any other move.\nexport const LEAGUE_STATUS_TRANSITIONS: Readonly<Record<LeagueStatus, readonly LeagueStatus[]>> = {\n pending: ['upcoming', 'closed'],\n upcoming: ['active', 'closed'],\n active: ['closed'],\n closed: [],\n};\n\n// Every status but closed: a league still being set up, published, or played. Whatever such a\n// league is configured with — its waiver template among them — is still in use.\nexport const OPEN_LEAGUE_STATUS_KEYS: readonly Exclude<LeagueStatus, typeof CLOSED_LEAGUE_STATUS>[] =\n LEAGUE_STATUS_KEYS.filter(\n (status): status is Exclude<LeagueStatus, typeof CLOSED_LEAGUE_STATUS> => status !== CLOSED_LEAGUE_STATUS,\n );\n\n// A league players are part of now or next: published and not yet closed. The admin dashboard's\n// active free-agent count covers only these leagues.\nexport const CURRENT_LEAGUE_STATUS_KEYS = [\n UPCOMING_LEAGUE_STATUS,\n ACTIVE_LEAGUE_STATUS,\n] as const satisfies readonly LeagueStatus[];\n\nexport const LEAGUE_MODE_KEYS = ['Regular', 'Competitive/Recreational'] as const;\nexport type LeagueMode = (typeof LEAGUE_MODE_KEYS)[number];\n\n// Present only on teams in a Competitive/Recreational league. In any other mode a team has no type:\n// the field is absent, never null.\nexport const TEAM_TYPE_KEYS = ['Competitive', 'Recreational'] as const;\nexport type TeamType = (typeof TEAM_TYPE_KEYS)[number];\n\n// The one mode whose teams each carry a `teamType`.\nexport const TEAM_TYPED_LEAGUE_MODE = 'Competitive/Recreational' as const satisfies LeagueMode;\n\n// The type every team takes when its league switches into `TEAM_TYPED_LEAGUE_MODE`.\nexport const TEAM_TYPE_ON_MODE_SWITCH = 'Recreational' as const satisfies TeamType;\n\nexport const GAME_STATUS_KEYS = ['scheduled', 'inprogress', 'completed'] as const;\nexport type GameStatus = (typeof GAME_STATUS_KEYS)[number];\n\n// The one status a finished game holds: it was played, and its stats count. Every reader asking\n// whether a game was played compares against this rather than naming a status of its own.\nexport const COMPLETED_GAME_STATUS = 'completed' as const satisfies GameStatus;\n\n// The status a newly scheduled game is created in.\nexport const GAME_STATUS_ON_CREATE = 'scheduled' as const satisfies GameStatus;\n\n// The status reopen returns a finalized game to: open for scoring again, its record of who played\n// kept.\nexport const GAME_STATUS_ON_REOPEN = 'inprogress' as const satisfies GameStatus;\n\n// An invitation is pending until the invitee accepts (`approved`) or declines (`rejected`) it, or the\n// team withdraws it (`cancelled`). A membership on its team made any other way closes it `approved`.\nexport const TEAM_INVITATION_STATUS_KEYS = ['pending', 'approved', 'rejected', 'cancelled'] as const;\nexport type TeamInvitationStatus = (typeof TEAM_INVITATION_STATUS_KEYS)[number];\n\nexport const PENDING_TEAM_INVITATION_STATUS = 'pending' as const satisfies TeamInvitationStatus;\nexport const APPROVED_TEAM_INVITATION_STATUS = 'approved' as const satisfies TeamInvitationStatus;\nexport const REJECTED_TEAM_INVITATION_STATUS = 'rejected' as const satisfies TeamInvitationStatus;\nexport const CANCELLED_TEAM_INVITATION_STATUS = 'cancelled' as const satisfies TeamInvitationStatus;\n\n// A join request is pending until the team's leaders accept (`approved`) or reject (`rejected`) it,\n// or the requester withdraws it (`cancelled`). A membership on its team made any other way closes it\n// `approved`.\nexport const TEAM_JOIN_REQUEST_STATUS_KEYS = ['pending', 'approved', 'rejected', 'cancelled'] as const;\nexport type TeamJoinRequestStatus = (typeof TEAM_JOIN_REQUEST_STATUS_KEYS)[number];\n\nexport const PENDING_TEAM_JOIN_REQUEST_STATUS = 'pending' as const satisfies TeamJoinRequestStatus;\nexport const APPROVED_TEAM_JOIN_REQUEST_STATUS = 'approved' as const satisfies TeamJoinRequestStatus;\nexport const REJECTED_TEAM_JOIN_REQUEST_STATUS = 'rejected' as const satisfies TeamJoinRequestStatus;\nexport const CANCELLED_TEAM_JOIN_REQUEST_STATUS = 'cancelled' as const satisfies TeamJoinRequestStatus;\n\nexport const HARDWARE_LOAN_CONTRACT_STATUS_KEYS = ['pending', 'loaned', 'returned'] as const;\nexport type HardwareLoanContractStatus = (typeof HARDWARE_LOAN_CONTRACT_STATUS_KEYS)[number];\n// Why an award grant passed over an account its teams or leagues named: it has no profile, or it is\n// a ghost, which holds no account.\nexport const AWARD_GRANT_SKIP_REASON_KEYS = ['noProfile', 'ghost'] as const;\nexport type AwardGrantSkipReason = (typeof AWARD_GRANT_SKIP_REASON_KEYS)[number];\n\nexport const PENDING_HARDWARE_LOAN_CONTRACT_STATUS = 'pending' as const satisfies HardwareLoanContractStatus;\nexport const LOANED_HARDWARE_LOAN_CONTRACT_STATUS = 'loaned' as const satisfies HardwareLoanContractStatus;\nexport const RETURNED_HARDWARE_LOAN_CONTRACT_STATUS = 'returned' as const satisfies HardwareLoanContractStatus;\n\n// What deleting a waiver template did. A template nothing names is deleted with its versions; one a\n// signature or a closed league still names is retired — kept for them, offered to no new league.\nexport const WAIVER_TEMPLATE_DELETE_OUTCOME_KEYS = ['deleted', 'retired'] as const;\nexport type WaiverTemplateDeleteOutcome = (typeof WAIVER_TEMPLATE_DELETE_OUTCOME_KEYS)[number];\n\n// What last changed the stats, as announced on the stats beacon; `link` is a ghost link moving a\n// game's lines onto an account.\nexport const STATS_BEACON_ACTION_KEYS = ['finalize', 'reopen', 'recalculate', 'correct', 'historical-update', 'link'] as const;\nexport type StatsBeaconAction = (typeof STATS_BEACON_ACTION_KEYS)[number];\n\n// The actions that describe one game, so a beacon announcing one names the game, its league, and its\n// teams; every other action names no game, and a game id left beside it would point at a stale one.\nexport const GAME_SCOPED_STATS_BEACON_ACTION_KEYS = ['finalize', 'reopen'] as const satisfies readonly StatsBeaconAction[];\nexport type GameScopedStatsBeaconAction = (typeof GAME_SCOPED_STATS_BEACON_ACTION_KEYS)[number];\n\n// The statuses a game's roster still follows its teams' memberships in: listed explicitly, so a\n// status added later is closed until it is named here, never open by default.\nexport const OPEN_GAME_STATUS_KEYS = ['scheduled', 'inprogress'] as const satisfies readonly GameStatus[];\nexport type OpenGameStatus = (typeof OPEN_GAME_STATUS_KEYS)[number];\n\n// Whether a game is still open — not yet finalized — so a scorer may still change it. Both app roots\n// ask this one predicate.\nexport function isOpenGameStatus(status: GameStatus): status is OpenGameStatus {\n return (OPEN_GAME_STATUS_KEYS as readonly GameStatus[]).includes(status);\n}\n\n// Where one membership's roster obligation stands. `pending` waits for the reconciliation worker;\n// `failed` has spent its retries and waits for an admin's retry; `reconciled` owes nothing.\nexport const MEMBERSHIP_ROSTER_SYNC_STATUS_KEYS = ['pending', 'reconciled', 'failed'] as const;\nexport type MembershipRosterSyncStatus = (typeof MEMBERSHIP_ROSTER_SYNC_STATUS_KEYS)[number];\nexport const PENDING_ROSTER_SYNC_STATUS = 'pending' as const satisfies MembershipRosterSyncStatus;\nexport const RECONCILED_ROSTER_SYNC_STATUS = 'reconciled' as const satisfies MembershipRosterSyncStatus;\nexport const FAILED_ROSTER_SYNC_STATUS = 'failed' as const satisfies MembershipRosterSyncStatus;\n\n// The authority a ghost's waiver was signed under: the witness's captaincy on the ghost's team, or\n// the global role the admin entry confirmed.\nexport const WAIVER_WITNESS_AUTHORITY_KEYS = ['captain', 'coCaptain', 'admin', 'referee'] as const;\nexport type WaiverWitnessAuthority = (typeof WAIVER_WITNESS_AUTHORITY_KEYS)[number];\n\n// Why a signing was refused, named in its details so the signing dialog answers it: `waiverChanged`\n// when the wording the signer saw — the template id and version the dialog sent — is no longer the\n// league's, so the dialog loads the current wording to read again.\nexport const WAIVER_SIGNING_REFUSAL_KEYS = ['waiverChanged'] as const;\nexport type WaiverSigningRefusal = (typeof WAIVER_SIGNING_REFUSAL_KEYS)[number];\n\n// The icon a team picks at creation; the persisted value is the icon component's name.\nexport const TEAM_ICON_KEYS = [\n 'Shield',\n 'Swords',\n 'Skull',\n 'Ghost',\n 'Cat',\n 'Dog',\n 'Bird',\n 'Fish',\n 'Rabbit',\n 'Snail',\n 'Turtle',\n 'Cherry',\n 'Apple',\n 'Grape',\n 'Rocket',\n 'Plane',\n 'Ship',\n 'Train',\n 'Car',\n 'Bike',\n 'Bolt',\n 'Star',\n 'Sun',\n 'Moon',\n 'Cloud',\n 'Crown',\n 'Diamond',\n 'Gem',\n 'Anchor',\n // Appended — the set only grows, and no stored key is ever renamed or removed. Seasonal and events.\n 'TreePine',\n 'Trees',\n 'TreeDeciduous',\n 'TreePalm',\n 'Snowflake',\n 'MountainSnow',\n 'Gift',\n 'PartyPopper',\n 'CandyCane',\n 'Candy',\n 'Lollipop',\n 'Cake',\n 'Egg',\n 'Clover',\n 'Heart',\n 'Flower',\n 'Flower2',\n 'Rose',\n 'Leaf',\n 'Sprout',\n 'Wheat',\n 'Sunrise',\n 'Rainbow',\n 'Bell',\n // Awards and sport.\n 'Trophy',\n 'Medal',\n 'Award',\n 'Ribbon',\n 'Flag',\n 'Target',\n 'Crosshair',\n 'Goal',\n 'Dumbbell',\n 'Footprints',\n // Power and the elements.\n 'Zap',\n 'Flame',\n 'FlameKindling',\n 'Bomb',\n 'Atom',\n 'Orbit',\n 'Sparkles',\n 'WandSparkles',\n 'Mountain',\n 'Tornado',\n 'Wind',\n 'Droplet',\n 'CloudLightning',\n 'MoonStar',\n // Arms and strongholds.\n 'Sword',\n 'Axe',\n 'Hammer',\n 'Pickaxe',\n 'ShieldHalf',\n 'Castle',\n // Animals.\n 'Squirrel',\n 'Rat',\n 'Panda',\n 'Shrimp',\n 'Worm',\n 'Bug',\n 'Shell',\n 'PawPrint',\n 'Feather',\n 'Bone',\n 'Origami',\n // Food.\n 'Citrus',\n 'Banana',\n 'Carrot',\n 'Pizza',\n 'Cookie',\n 'Donut',\n 'Coffee',\n // Games and music.\n 'Dices',\n 'Puzzle',\n 'Gamepad2',\n 'Spade',\n 'Club',\n 'Music',\n 'Guitar',\n 'Hexagon',\n 'Triangle',\n // Travel.\n 'Sailboat',\n 'Tractor',\n 'Truck',\n] as const;\nexport type TeamIcon = (typeof TEAM_ICON_KEYS)[number];\n\n// A picture's processed sizes, smallest first: every picture kind declares all three, and a display\n// asks for the smallest one that covers its slot.\nexport const PICTURE_VARIANT_KEYS = ['sm', 'md', 'lg'] as const;\nexport type PictureVariantKey = (typeof PICTURE_VARIANT_KEYS)[number];\n\n// What a stats check found, game tier first — a game's own numbers are the cause of the aggregate\n// findings, so Fix stats repairs games before it rebuilds what they feed.\nexport const GAME_TIER_DISCREPANCY_KIND_KEYS = [\n 'invalidEvent',\n 'eventSequenceMismatch',\n 'rollupMismatch',\n 'scoreMirrorMismatch',\n 'unrosteredStatLine',\n 'fantasyPointsStale',\n 'finalRecordMissing',\n 'finalRecordMismatch',\n 'participationSnapshotMismatch',\n 'gameHeld',\n] as const;\nexport const AGGREGATE_TIER_DISCREPANCY_KIND_KEYS = [\n 'aggregateMismatch',\n 'aggregateEntryStale',\n 'aggregateEntryMissing',\n 'hallOfFameLifetimeMismatch',\n] as const;\nexport const STATS_DISCREPANCY_KIND_KEYS = [\n ...GAME_TIER_DISCREPANCY_KIND_KEYS,\n ...AGGREGATE_TIER_DISCREPANCY_KIND_KEYS,\n] as const;\nexport type StatsDiscrepancyKind = (typeof STATS_DISCREPANCY_KIND_KEYS)[number];\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-status.js","sourceRoot":"","sources":["../../src/utils/account-status.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,yGAAyG;AACzG,oGAAoG;AACpG,+EAA+E;AAE/E,OAAO,EAAE,kBAAkB,EAAmB,MAAM,oBAAoB,CAAC;AAEzE,MAAM,UAAU,eAAe,CAAC,OAAsD;IACpF,OAAO,OAAO,EAAE,UAAU,KAAK,kBAAkB,CAAC;AACpD,CAAC","sourcesContent":["// Whether an account may act as a member: it has finished registration — its profile exists — and that\
|
|
1
|
+
{"version":3,"file":"account-status.js","sourceRoot":"","sources":["../../src/utils/account-status.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,yGAAyG;AACzG,oGAAoG;AACpG,+EAA+E;AAE/E,OAAO,EAAE,kBAAkB,EAAmB,MAAM,oBAAoB,CAAC;AAEzE,MAAM,UAAU,eAAe,CAAC,OAAsD;IACpF,OAAO,OAAO,EAAE,UAAU,KAAK,kBAAkB,CAAC;AACpD,CAAC","sourcesContent":["// Whether an account may act as a member: it has finished registration — its profile exists — and that\n// profile's status is exactly `active`. Fail closed: a missing profile, or any other status, is refused.\n// The callable auth assertion refuses every other account before a member callable runs, and a door\n// is offered only to an account this answers true for (ENG-006, FRONTEND-110).\n\nimport { ACTIVE_USER_STATUS, type UserStatus } from '../types/unions.js';\n\nexport function isActiveAccount(profile: { userStatus: UserStatus } | null | undefined): boolean {\n return profile?.userStatus === ACTIVE_USER_STATUS;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-config.js","sourceRoot":"","sources":["../../src/utils/app-config.ts"],"names":[],"mappings":"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","sourcesContent":["// The `_appConfig/app` singleton at rest, and the one rule each for writing it and reading it.\r\n//\r\n// WRITE. `mergeAppConfigUpdate(existing, update)`: the writer's update on top of the document it\r\n// read, any field that document lacks taken from DEFAULT_APP_CONFIG, the whole result validated.\r\n// A writer that runs first on a fresh environment therefore still writes a complete, valid\r\n// document rather than a partial one. A stored field that does not parse — a hand edit in the\r\n// console — is never written over by a save that does not send it: the merge refuses, and the\r\n// writer answers with the field, so the operator corrects it at the source. A save that sends the\r\n// field replaces it.\r\n//\r\n// READ. The stored document is untrusted — an operator can edit any field in the console into any\r\n// shape — and a config read must never take the product down by itself. `readAppConfigLever`\r\n// answers one lever at a time: the stored value when its schema field accepts it, otherwise the\r\n// lever's DEFAULT_APP_CONFIG value, so one bad field never costs the good ones. The server's cached\r\n// snapshot reader and the client's readers both read through it.\r\n\r\nimport { AppConfigSchema } from '../doc-schemas/system.js';\r\nimport type { AppConfig } from '../doc-schemas/system.js';\r\n\r\n/** Every operator lever of `_appConfig/app`, each at a value its schema field accepts. */\r\nexport type AppConfigLevers = Readonly<Required<AppConfig>>;\r\n\r\n/** The name of one operator lever. */\r\nexport type AppConfigLeverKey = keyof AppConfigLevers;\r\n\r\n/** Every lever name, derived from the document schema. */\r\nexport const APP_CONFIG_LEVER_KEYS = AppConfigSchema.keyof().options;\r\n\r\n/**\r\n * The document a fresh environment behaves as if it held, and the value each reader falls back to\r\n * for a missing or unreadable field: maintenance off, registration open, no banner.\r\n *\r\n * `appVersion` is `''` — no version has been published — so the version gate stays dormant until an\r\n * operator sets a real one through `updateAppConfig`, whose input refuses `''`.\r\n */\r\nexport const DEFAULT_APP_CONFIG: AppConfigLevers = Object.freeze({\r\n appVersion: '',\r\n maintenanceMode: false,\r\n maintenanceMessage: '',\r\n registrationEnabled: true,\r\n announcementMessage: '',\r\n});\r\n\r\n/**\r\n * The line shown while maintenance is on and the operator left `maintenanceMessage` blank — on the\r\n * maintenance screen and in the callable refusal alike.\r\n */\r\nexport const DEFAULT_MAINTENANCE_MESSAGE =\r\n 'Q-Sports is down for maintenance right now. We will be back shortly — thank you for your patience.';\r\n\r\n/**\r\n * The code the callable maintenance refusal is thrown with. `unavailable` is also what a real outage\r\n * produces, so the code alone never identifies the refusal — its details do.\r\n */\r\nexport const MAINTENANCE_REFUSAL_CODE = 'unavailable' as const;\r\n\r\n/** The `details.reason` the callable maintenance refusal carries. */\r\nexport const MAINTENANCE_REFUSAL_REASON = 'maintenance' as const;\r\n\r\n/** Structured details carried by the callable maintenance refusal. */\r\nexport interface MaintenanceRefusalDetails {\r\n readonly reason: typeof MAINTENANCE_REFUSAL_REASON;\r\n}\r\n\r\n// The refusal code as the server (`unavailable`) and the Firebase client SDK\r\n// (`functions/unavailable`) spell it.\r\nconst MAINTENANCE_REFUSAL_CODES: ReadonlySet<string> = new Set([\r\n MAINTENANCE_REFUSAL_CODE,\r\n `functions/${MAINTENANCE_REFUSAL_CODE}`,\r\n]);\r\n\r\n/** True when `details` is the maintenance refusal's structured details. */\r\nexport function isMaintenanceRefusalDetails(details: unknown): details is MaintenanceRefusalDetails {\r\n if (!details || typeof details !== 'object') return false;\r\n return (details as Record<string, unknown>).reason === MAINTENANCE_REFUSAL_REASON;\r\n}\r\n\r\n/**\r\n * True when `err` is the callable maintenance refusal — an `unavailable` error in either spelling\r\n * whose details carry `reason: 'maintenance'`. Works on the server-side error and on the client-side\r\n * callable error alike, and is decided by the code and the details, never the message, so a genuine\r\n * outage is never mistaken for the designed refusal.\r\n */\r\nexport function isMaintenanceRefusalError(err: unknown): boolean {\r\n if (!err || typeof err !== 'object') return false;\r\n const candidate = err as { code?: unknown; details?: unknown };\r\n return (\r\n typeof candidate.code === 'string' &&\r\n MAINTENANCE_REFUSAL_CODES.has(candidate.code) &&\r\n isMaintenanceRefusalDetails(candidate.details)\r\n );\r\n}\r\n\r\nfunction definedFields(fields: Readonly<Record<string, unknown>>): Record<string, unknown> {\r\n return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== undefined));\r\n}\r\n\r\n/**\r\n * The complete `_appConfig/app` document to write after applying `update` to `existing` (the\r\n * document as read in the writer's transaction; `null` or `undefined` when it does not exist). The\r\n * update's fields win, `existing` supplies the rest, and any field still missing comes from\r\n * DEFAULT_APP_CONFIG. An `undefined` update field changes nothing. Pure.\r\n *\r\n * Throws when the result would not parse — the update itself, or a stored field the update does not\r\n * replace — so an invalid document is never written.\r\n */\r\nexport function mergeAppConfigUpdate(\r\n existing: Readonly<Record<string, unknown>> | null | undefined,\r\n update: Readonly<Partial<AppConfig>>,\r\n): AppConfig {\r\n const parsed = AppConfigSchema.safeParse({\r\n ...DEFAULT_APP_CONFIG,\r\n ...definedFields(existing ?? {}),\r\n ...definedFields(update),\r\n });\r\n if (!parsed.success) {\r\n const issue = parsed.error.issues[0];\r\n const field = issue?.path.join('.') || 'document';\r\n throw new Error(\r\n `_appConfig/app would not match its schema after this update (${field}: ${issue?.message ?? 'invalid'}). Nothing should be written.`,\r\n );\r\n }\r\n return parsed.data;\r\n}\r\n\r\n/**\r\n * One operator lever off an unvalidated `_appConfig/app` snapshot (`null` or `undefined` when the\r\n * document is missing or not yet read): the stored value when its schema field accepts it, otherwise\r\n * the lever's DEFAULT_APP_CONFIG value — for an absent field and a refused one alike. Never throws.\r\n */\r\nexport function readAppConfigLever<L extends AppConfigLeverKey>(\r\n snapshot: Readonly<Record<string, unknown>> | null | undefined,\r\n lever: L,\r\n): AppConfigLevers[L] {\r\n const parsed = AppConfigSchema.shape[lever].safeParse(snapshot?.[lever]);\r\n return parsed.success && parsed.data !== undefined\r\n ? (parsed.data as AppConfigLevers[L])\r\n : DEFAULT_APP_CONFIG[lever];\r\n}\r\n\r\n/**\r\n * True when an unvalidated `_appConfig/app` snapshot holds `lever` with a value its schema field\r\n * refuses — the value every reader passes over for the default. An absent field is not refused.\r\n * Never throws.\r\n */\r\nexport function isAppConfigLeverRefused(\r\n snapshot: Readonly<Record<string, unknown>> | null | undefined,\r\n lever: AppConfigLeverKey,\r\n): boolean {\r\n const stored = snapshot?.[lever];\r\n return stored !== undefined && !AppConfigSchema.shape[lever].safeParse(stored).success;\r\n}\r\n\r\n/** Every lever off an unvalidated snapshot, each through `readAppConfigLever`. Never throws. */\r\nexport function readAppConfigLevers(\r\n snapshot: Readonly<Record<string, unknown>> | null | undefined,\r\n): AppConfigLevers {\r\n const levers: Partial<Record<AppConfigLeverKey, unknown>> = {};\r\n for (const lever of APP_CONFIG_LEVER_KEYS) {\r\n levers[lever] = readAppConfigLever(snapshot, lever);\r\n }\r\n return levers as AppConfigLevers;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"app-config.js","sourceRoot":"","sources":["../../src/utils/app-config.ts"],"names":[],"mappings":"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","sourcesContent":["// The `_appConfig/app` singleton at rest, and the one rule each for writing it and reading it.\n//\n// WRITE. `mergeAppConfigUpdate(existing, update)`: the writer's update on top of the document it\n// read, any field that document lacks taken from DEFAULT_APP_CONFIG, the whole result validated.\n// A writer that runs first on a fresh environment therefore still writes a complete, valid\n// document rather than a partial one. A stored field that does not parse — a hand edit in the\n// console — is never written over by a save that does not send it: the merge refuses, and the\n// writer answers with the field, so the operator corrects it at the source. A save that sends the\n// field replaces it.\n//\n// READ. The stored document is untrusted — an operator can edit any field in the console into any\n// shape — and a config read must never take the product down by itself. `readAppConfigLever`\n// answers one lever at a time: the stored value when its schema field accepts it, otherwise the\n// lever's DEFAULT_APP_CONFIG value, so one bad field never costs the good ones. The server's cached\n// snapshot reader and the client's readers both read through it.\n\nimport { AppConfigSchema } from '../doc-schemas/system.js';\nimport type { AppConfig } from '../doc-schemas/system.js';\n\n/** Every operator lever of `_appConfig/app`, each at a value its schema field accepts. */\nexport type AppConfigLevers = Readonly<Required<AppConfig>>;\n\n/** The name of one operator lever. */\nexport type AppConfigLeverKey = keyof AppConfigLevers;\n\n/** Every lever name, derived from the document schema. */\nexport const APP_CONFIG_LEVER_KEYS = AppConfigSchema.keyof().options;\n\n/**\n * The document a fresh environment behaves as if it held, and the value each reader falls back to\n * for a missing or unreadable field: maintenance off, registration open, no banner.\n *\n * `appVersion` is `''` — no version has been published — so the version gate stays dormant until an\n * operator sets a real one through `updateAppConfig`, whose input refuses `''`.\n */\nexport const DEFAULT_APP_CONFIG: AppConfigLevers = Object.freeze({\n appVersion: '',\n maintenanceMode: false,\n maintenanceMessage: '',\n registrationEnabled: true,\n announcementMessage: '',\n});\n\n/**\n * The line shown while maintenance is on and the operator left `maintenanceMessage` blank — on the\n * maintenance screen and in the callable refusal alike.\n */\nexport const DEFAULT_MAINTENANCE_MESSAGE =\n 'Q-Sports is down for maintenance right now. We will be back shortly — thank you for your patience.';\n\n/**\n * The code the callable maintenance refusal is thrown with. `unavailable` is also what a real outage\n * produces, so the code alone never identifies the refusal — its details do.\n */\nexport const MAINTENANCE_REFUSAL_CODE = 'unavailable' as const;\n\n/** The `details.reason` the callable maintenance refusal carries. */\nexport const MAINTENANCE_REFUSAL_REASON = 'maintenance' as const;\n\n/** Structured details carried by the callable maintenance refusal. */\nexport interface MaintenanceRefusalDetails {\n readonly reason: typeof MAINTENANCE_REFUSAL_REASON;\n}\n\n// The refusal code as the server (`unavailable`) and the Firebase client SDK\n// (`functions/unavailable`) spell it.\nconst MAINTENANCE_REFUSAL_CODES: ReadonlySet<string> = new Set([\n MAINTENANCE_REFUSAL_CODE,\n `functions/${MAINTENANCE_REFUSAL_CODE}`,\n]);\n\n/** True when `details` is the maintenance refusal's structured details. */\nexport function isMaintenanceRefusalDetails(details: unknown): details is MaintenanceRefusalDetails {\n if (!details || typeof details !== 'object') return false;\n return (details as Record<string, unknown>).reason === MAINTENANCE_REFUSAL_REASON;\n}\n\n/**\n * True when `err` is the callable maintenance refusal — an `unavailable` error in either spelling\n * whose details carry `reason: 'maintenance'`. Works on the server-side error and on the client-side\n * callable error alike, and is decided by the code and the details, never the message, so a genuine\n * outage is never mistaken for the designed refusal.\n */\nexport function isMaintenanceRefusalError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const candidate = err as { code?: unknown; details?: unknown };\n return (\n typeof candidate.code === 'string' &&\n MAINTENANCE_REFUSAL_CODES.has(candidate.code) &&\n isMaintenanceRefusalDetails(candidate.details)\n );\n}\n\nfunction definedFields(fields: Readonly<Record<string, unknown>>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== undefined));\n}\n\n/**\n * The complete `_appConfig/app` document to write after applying `update` to `existing` (the\n * document as read in the writer's transaction; `null` or `undefined` when it does not exist). The\n * update's fields win, `existing` supplies the rest, and any field still missing comes from\n * DEFAULT_APP_CONFIG. An `undefined` update field changes nothing. Pure.\n *\n * Throws when the result would not parse — the update itself, or a stored field the update does not\n * replace — so an invalid document is never written.\n */\nexport function mergeAppConfigUpdate(\n existing: Readonly<Record<string, unknown>> | null | undefined,\n update: Readonly<Partial<AppConfig>>,\n): AppConfig {\n const parsed = AppConfigSchema.safeParse({\n ...DEFAULT_APP_CONFIG,\n ...definedFields(existing ?? {}),\n ...definedFields(update),\n });\n if (!parsed.success) {\n const issue = parsed.error.issues[0];\n const field = issue?.path.join('.') || 'document';\n throw new Error(\n `_appConfig/app would not match its schema after this update (${field}: ${issue?.message ?? 'invalid'}). Nothing should be written.`,\n );\n }\n return parsed.data;\n}\n\n/**\n * One operator lever off an unvalidated `_appConfig/app` snapshot (`null` or `undefined` when the\n * document is missing or not yet read): the stored value when its schema field accepts it, otherwise\n * the lever's DEFAULT_APP_CONFIG value — for an absent field and a refused one alike. Never throws.\n */\nexport function readAppConfigLever<L extends AppConfigLeverKey>(\n snapshot: Readonly<Record<string, unknown>> | null | undefined,\n lever: L,\n): AppConfigLevers[L] {\n const parsed = AppConfigSchema.shape[lever].safeParse(snapshot?.[lever]);\n return parsed.success && parsed.data !== undefined\n ? (parsed.data as AppConfigLevers[L])\n : DEFAULT_APP_CONFIG[lever];\n}\n\n/**\n * True when an unvalidated `_appConfig/app` snapshot holds `lever` with a value its schema field\n * refuses — the value every reader passes over for the default. An absent field is not refused.\n * Never throws.\n */\nexport function isAppConfigLeverRefused(\n snapshot: Readonly<Record<string, unknown>> | null | undefined,\n lever: AppConfigLeverKey,\n): boolean {\n const stored = snapshot?.[lever];\n return stored !== undefined && !AppConfigSchema.shape[lever].safeParse(stored).success;\n}\n\n/** Every lever off an unvalidated snapshot, each through `readAppConfigLever`. Never throws. */\nexport function readAppConfigLevers(\n snapshot: Readonly<Record<string, unknown>> | null | undefined,\n): AppConfigLevers {\n const levers: Partial<Record<AppConfigLeverKey, unknown>> = {};\n for (const lever of APP_CONFIG_LEVER_KEYS) {\n levers[lever] = readAppConfigLever(snapshot, lever);\n }\n return levers as AppConfigLevers;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-routes.js","sourceRoot":"","sources":["../../src/utils/app-routes.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,sGAAsG;AACtG,oGAAoG;AACpG,sDAAsD;AAEtD,MAAM,WAAW,GAAG,SAAS,CAAC;AAE9B,iEAAiE;AACjE,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC;AAEnC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC,0DAA0D;AAC1D,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAE3C,2FAA2F;AAC3F,MAAM,CAAC,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AAExD,mGAAmG;AACnG,kDAAkD;AAClD,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,CAAU,CAAC;AAG7G,2EAA2E;AAC3E,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAgD,CAAC;AAExF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAA6C,CAAC;AAElF,4FAA4F;AAC5F,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC,8EAA8E;AAC9E,MAAM,CAAC,MAAM,0BAA0B,GAAG,aAAmD,CAAC;AAE9F,sFAAsF;AACtF,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,OAAe;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9C,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,mBAAmB,IAAI,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,GAAG,WAAW,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,MAAc;IAC7D,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,MAAc;IAC5D,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,MAAc;IACnE,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;AACpD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAqC;IACrF,MAAM,IAAI,GAAG,GAAG,kBAAkB,IAAI,kBAAkB,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC3F,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,MAAc;IAClE,OAAO,GAAG,eAAe,CAAC,QAAQ,EAAE,oBAAoB,CAAC,IAAI,gBAAgB,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AAChH,CAAC","sourcesContent":["// The app addresses a link is built to: a league's pages — the league, one of its teams, one of its\
|
|
1
|
+
{"version":3,"file":"app-routes.js","sourceRoot":"","sources":["../../src/utils/app-routes.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,sGAAsG;AACtG,oGAAoG;AACpG,sDAAsD;AAEtD,MAAM,WAAW,GAAG,SAAS,CAAC;AAE9B,iEAAiE;AACjE,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC;AAEnC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC,0DAA0D;AAC1D,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAE3C,2FAA2F;AAC3F,MAAM,CAAC,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AAExD,mGAAmG;AACnG,kDAAkD;AAClD,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,CAAU,CAAC;AAG7G,2EAA2E;AAC3E,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAgD,CAAC;AAExF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAA6C,CAAC;AAElF,4FAA4F;AAC5F,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC,8EAA8E;AAC9E,MAAM,CAAC,MAAM,0BAA0B,GAAG,aAAmD,CAAC;AAE9F,sFAAsF;AACtF,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,OAAe;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9C,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,mBAAmB,IAAI,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,GAAG,WAAW,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,MAAc;IAC7D,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,MAAc;IAC5D,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,MAAc;IACnE,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;AACpD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAqC;IACrF,MAAM,IAAI,GAAG,GAAG,kBAAkB,IAAI,kBAAkB,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC3F,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,MAAc;IAClE,OAAO,GAAG,eAAe,CAAC,QAAQ,EAAE,oBAAoB,CAAC,IAAI,gBAAgB,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AAChH,CAAC","sourcesContent":["// The app addresses a link is built to: a league's pages — the league, one of its teams, one of its\n// games and that game's scoring page — and the admin Leagues workspace. Both roots build these links:\n// the server writes one onto an admin notification card, and the app links to every one of them, so\n// each address shape has one change point (ARCH-101).\n\nconst LEAGUE_PATH = '/league';\n\n/** The one admin page; every admin group is a `?view=` of it. */\nexport const ADMIN_PATH = '/admin';\n\n/** The query-string key the admin page's groups live under. */\nexport const ADMIN_VIEW_PARAM = 'view';\n\n/** The query-string key a group's sections live under. */\nexport const ADMIN_SECTION_PARAM = 'section';\n\n/** The query-string key the Leagues group names the league whose workspace is open under. */\nexport const ADMIN_LEAGUE_PARAM = 'league';\n\n/** The admin Leagues group: the league list, each league's workspace nested beneath it. */\nexport const ADMIN_LEAGUES_HREF = '/admin?view=leagues';\n\n// The sections a league's admin workspace is addressed by. The workspace declares which of them it\n// has built as tabs; a link may name any of them.\nexport const ADMIN_LEAGUE_WORKSPACE_SECTION_KEYS = ['settings', 'schedule', 'teams', 'free-agents'] as const;\nexport type AdminLeagueWorkspaceSection = (typeof ADMIN_LEAGUE_WORKSPACE_SECTION_KEYS)[number];\n\n/** The league workspace's section holding the league's weeks and games. */\nexport const LEAGUE_SCHEDULE_SECTION = 'schedule' satisfies AdminLeagueWorkspaceSection;\n\n/** The league workspace's section listing the league's teams, each opening its admin view. */\nexport const LEAGUE_TEAMS_SECTION = 'teams' satisfies AdminLeagueWorkspaceSection;\n\n/** The query-string key the Teams section names the team whose admin view is open under. */\nexport const ADMIN_TEAM_PARAM = 'team';\n\n/** The league workspace's section listing the league's free-agent signups. */\nexport const LEAGUE_FREE_AGENTS_SECTION = 'free-agents' satisfies AdminLeagueWorkspaceSection;\n\n/** An admin address on one of its sections — the one place a section joins a link. */\nexport function withAdminSection(href: string, section: string): string {\n const joiner = href.includes('?') ? '&' : '?';\n return `${href}${joiner}${ADMIN_SECTION_PARAM}=${encodeURIComponent(section)}`;\n}\n\nexport function leagueHref(leagueId: string): string {\n return `${LEAGUE_PATH}/${encodeURIComponent(leagueId)}`;\n}\n\nexport function leagueTeamHref(leagueId: string, teamId: string): string {\n return `${leagueHref(leagueId)}/team/${encodeURIComponent(teamId)}`;\n}\n\nexport function sportGameHref(leagueId: string, gameId: string): string {\n return `${leagueHref(leagueId)}/game/${encodeURIComponent(gameId)}`;\n}\n\n/** A game's scoring page, where a scorer records its stats. */\nexport function sportGameScoringHref(leagueId: string, gameId: string): string {\n return `${sportGameHref(leagueId, gameId)}/stats`;\n}\n\n/** A league's admin workspace, on one of its sections when one is named. */\nexport function adminLeagueHref(leagueId: string, section?: AdminLeagueWorkspaceSection): string {\n const href = `${ADMIN_LEAGUES_HREF}&${ADMIN_LEAGUE_PARAM}=${encodeURIComponent(leagueId)}`;\n return section === undefined ? href : withAdminSection(href, section);\n}\n\n/** One team's admin view, inside its league's workspace on the Teams section. */\nexport function adminLeagueTeamHref(leagueId: string, teamId: string): string {\n return `${adminLeagueHref(leagueId, LEAGUE_TEAMS_SECTION)}&${ADMIN_TEAM_PARAM}=${encodeURIComponent(teamId)}`;\n}\n"]}
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC","sourcesContent":["export * from './display-name.js';\
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC","sourcesContent":["export * from './display-name.js';\nexport * from './app-config.js';\nexport * from './league-calendar.js';\nexport * from './team-creation.js';\nexport * from './account-status.js';\nexport * from './league-join-warning.js';\nexport * from './schedules.js';\nexport * from './app-routes.js';\nexport * from './team-member-actions.js';\nexport * from './league-mode.js';\nexport * from './league-joining.js';\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"league-calendar.js","sourceRoot":"","sources":["../../src/utils/league-calendar.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,qGAAqG;AACrG,+FAA+F;AAC/F,oGAAoG;AACpG,wCAAwC;AAExC,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,0EAA0E;AAC1E,MAAM,iBAAiB,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;IACzD,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnC,iEAAiE;AACjE,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,iBAAiB,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,IAAY;IAC1D,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,MAAM,gBAAgB,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,UAAU,CAAC,yBAAyB,MAAM,IAAI,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,qGAAqG;AACrG,MAAM,wBAAwB,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;IAChE,QAAQ,EAAE,gBAAgB;IAC1B,SAAS,EAAE,KAAK;IAChB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;CAClB,CAAC,CAAC;AAEH,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AACvD,MAAM,iBAAiB,GAAG,6BAA6B,CAAC;AAExD,iGAAiG;AACjG,SAAS,oBAAoB,CAAC,OAAe;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAC9B,wBAAwB,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CACjG,CAAC;IACF,OAAO,IAAI,CAAC,GAAG,CACb,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAClB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EACvB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EACjB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAClB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EACpB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CACrB,CAAC;AACJ,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACnE,OAAO,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,SAAiB;IAC/D,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,UAAU,CAAC,wCAAwC,MAAM,MAAM,SAAS,IAAI,CAAC,CAAC;IAC3G,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjH,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,MAAM,EAAE,CAAC;QAC9D,MAAM,IAAI,UAAU,CAAC,wBAAwB,MAAM,IAAI,CAAC,CAAC;IAC3D,CAAC;IACD,oGAAoG;IACpG,gGAAgG;IAChG,MAAM,UAAU,GAAG,SAAS,GAAG,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC;IAC7E,OAAO,SAAS,GAAG,CAAC,oBAAoB,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,CAAC;AACrE,CAAC","sourcesContent":["// Calendar days and times of day in the leagues' own time zone. A league's dates and a game's `dayKey`\
|
|
1
|
+
{"version":3,"file":"league-calendar.js","sourceRoot":"","sources":["../../src/utils/league-calendar.ts"],"names":[],"mappings":"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","sourcesContent":["// Calendar days and times of day in the leagues' own time zone. A league's dates and a game's `dayKey`\n// are calendar dates with no time or zone (`YYYY-MM-DD`), so \"today\" is read in LEAGUE_TIME_ZONE and\n// every comparison is between two calendar dates, never between instants. A game's start is an\n// instant, entered and shown as a day and a time of day (`HH:MM`) in LEAGUE_TIME_ZONE, whatever the\n// zone of the browser it is entered in.\n\nimport { LEAGUE_TIME_ZONE } from '../constants/business.js';\n\n// `en-CA` formats a date as `YYYY-MM-DD`, the stored calendar-date shape.\nconst LEAGUE_DAY_FORMAT = new Intl.DateTimeFormat('en-CA', {\n timeZone: LEAGUE_TIME_ZONE,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n});\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/** The calendar date an instant falls on in LEAGUE_TIME_ZONE. */\nexport function toLeagueDayKey(epochMs: number): string {\n return LEAGUE_DAY_FORMAT.format(new Date(epochMs));\n}\n\n/**\n * The calendar date `days` days after `dayKey` (before it, when negative). Pure calendar arithmetic\n * on the date itself, so no time zone or daylight-saving change moves it.\n */\nexport function addCalendarDays(dayKey: string, days: number): string {\n const day = new Date(`${dayKey}T00:00:00.000Z`);\n if (Number.isNaN(day.getTime())) {\n throw new RangeError(`Not a calendar date: '${dayKey}'.`);\n }\n return new Date(day.getTime() + days * DAY_MS).toISOString().slice(0, 10);\n}\n\n// Every part of an instant's wall-clock reading in LEAGUE_TIME_ZONE. `h23` keeps midnight at hour 0.\nconst LEAGUE_WALL_CLOCK_FORMAT = new Intl.DateTimeFormat('en-US', {\n timeZone: LEAGUE_TIME_ZONE,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n});\n\nconst CALENDAR_DAY_SHAPE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\nconst TIME_OF_DAY_SHAPE = /^([01]\\d|2[0-3]):([0-5]\\d)$/;\n\n/** The instant's wall-clock reading in LEAGUE_TIME_ZONE, written as if that reading were UTC. */\nfunction leagueWallClockAsUtc(epochMs: number): number {\n const parts = Object.fromEntries(\n LEAGUE_WALL_CLOCK_FORMAT.formatToParts(new Date(epochMs)).map((part) => [part.type, part.value]),\n );\n return Date.UTC(\n Number(parts.year),\n Number(parts.month) - 1,\n Number(parts.day),\n Number(parts.hour),\n Number(parts.minute),\n Number(parts.second),\n );\n}\n\n/** The time of day an instant falls at in LEAGUE_TIME_ZONE, as `HH:MM` on a 24-hour clock. */\nexport function toLeagueTimeOfDay(epochMs: number): string {\n const wallClock = new Date(leagueWallClockAsUtc(epochMs));\n const hours = String(wallClock.getUTCHours()).padStart(2, '0');\n const minutes = String(wallClock.getUTCMinutes()).padStart(2, '0');\n return `${hours}:${minutes}`;\n}\n\n/**\n * The instant a calendar day and a time of day (`HH:MM`, 24-hour) name in LEAGUE_TIME_ZONE, in epoch\n * milliseconds. The zone's offset is read at the instant itself, so a day on either side of a\n * daylight-saving change reads its own offset. Throws on a day or a time that is not one.\n */\nexport function leagueInstantOf(dayKey: string, timeOfDay: string): number {\n const day = CALENDAR_DAY_SHAPE.exec(dayKey);\n const time = TIME_OF_DAY_SHAPE.exec(timeOfDay);\n if (!day || !time) throw new RangeError(`Not a calendar day and time of day: '${dayKey}' '${timeOfDay}'.`);\n const wallClock = Date.UTC(Number(day[1]), Number(day[2]) - 1, Number(day[3]), Number(time[1]), Number(time[2]));\n if (new Date(wallClock).toISOString().slice(0, 10) !== dayKey) {\n throw new RangeError(`Not a calendar day: '${dayKey}'.`);\n }\n // The offset at the wall-clock reading taken as UTC is within a day of the right one; read again at\n // the instant that offset gives, so a reading on the other side of a change settles on its own.\n const firstGuess = wallClock - (leagueWallClockAsUtc(wallClock) - wallClock);\n return wallClock - (leagueWallClockAsUtc(firstGuess) - firstGuess);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"league-mode.js","sourceRoot":"","sources":["../../src/utils/league-mode.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,qGAAqG;AACrG,oGAAoG;AAEpG,OAAO,EAAE,sBAAsB,EAAmB,MAAM,oBAAoB,CAAC;AAE7E,6FAA6F;AAC7F,MAAM,UAAU,0BAA0B,CAAC,IAAgB;IACzD,OAAO,IAAI,KAAK,sBAAsB,CAAC;AACzC,CAAC","sourcesContent":["// Whether a league sorts its teams by type. It is the one reading every surface makes — the team\
|
|
1
|
+
{"version":3,"file":"league-mode.js","sourceRoot":"","sources":["../../src/utils/league-mode.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,qGAAqG;AACrG,oGAAoG;AAEpG,OAAO,EAAE,sBAAsB,EAAmB,MAAM,oBAAoB,CAAC;AAE7E,6FAA6F;AAC7F,MAAM,UAAU,0BAA0B,CAAC,IAAgB;IACzD,OAAO,IAAI,KAAK,sBAAsB,CAAC;AACzC,CAAC","sourcesContent":["// Whether a league sorts its teams by type. It is the one reading every surface makes — the team\n// form's required type, the type control, the standings and rankings split into pools, the team list\n// grouped by type, and the admin's mode copy — so no reader compares the mode on its own (ENG-005).\n\nimport { TEAM_TYPED_LEAGUE_MODE, type LeagueMode } from '../types/unions.js';\n\n/** Whether a league in `mode` sorts its teams by type, so each team carries a `teamType`. */\nexport function leagueModeSortsTeamsByType(mode: LeagueMode): boolean {\n return mode === TEAM_TYPED_LEAGUE_MODE;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"team-member-actions.js","sourceRoot":"","sources":["../../src/utils/team-member-actions.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,kGAAkG;AAClG,qGAAqG;AACrG,EAAE;AACF,4FAA4F;AAC5F,sGAAsG;AACtG,uCAAuC;AACvC,2FAA2F;AAC3F,EAAE;AACF,+FAA+F;AAC/F,gBAAgB;AAGhB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,GAGjB,MAAM,oBAAoB,CAAC;AAE5B,iFAAiF;AACjF,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAqC,CAAC;AAoB7E,MAAM,IAAI,GAAsB,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAEjF,MAAM,UAAU,iBAAiB,CAAC,KAAsB,EAAE,MAAwB;IAChF,IAAI,MAAM,CAAC,IAAI,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,iBAAiB,GAAG,KAAK,KAAK,uBAAuB,IAAI,KAAK,KAAK,iBAAiB,CAAC;IAC3F,OAAO;QACL,OAAO,EAAE,iBAAiB,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,MAAM,CAAC,OAAO;QACjF,MAAM,EAAE,iBAAiB,IAAI,MAAM,CAAC,IAAI,KAAK,oBAAoB;QACjE,MAAM,EAAE,iBAAiB,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB;KAC9D,CAAC;AACJ,CAAC","sourcesContent":["// What a team leader or an admin may do to one member of a team: promote a player to co-captain,\
|
|
1
|
+
{"version":3,"file":"team-member-actions.js","sourceRoot":"","sources":["../../src/utils/team-member-actions.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,kGAAkG;AAClG,qGAAqG;AACrG,EAAE;AACF,4FAA4F;AAC5F,sGAAsG;AACtG,uCAAuC;AACvC,2FAA2F;AAC3F,EAAE;AACF,+FAA+F;AAC/F,gBAAgB;AAGhB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,GAGjB,MAAM,oBAAoB,CAAC;AAE5B,iFAAiF;AACjF,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAqC,CAAC;AAoB7E,MAAM,IAAI,GAAsB,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAEjF,MAAM,UAAU,iBAAiB,CAAC,KAAsB,EAAE,MAAwB;IAChF,IAAI,MAAM,CAAC,IAAI,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,iBAAiB,GAAG,KAAK,KAAK,uBAAuB,IAAI,KAAK,KAAK,iBAAiB,CAAC;IAC3F,OAAO;QACL,OAAO,EAAE,iBAAiB,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,MAAM,CAAC,OAAO;QACjF,MAAM,EAAE,iBAAiB,IAAI,MAAM,CAAC,IAAI,KAAK,oBAAoB;QACjE,MAAM,EAAE,iBAAiB,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB;KAC9D,CAAC;AACJ,CAAC","sourcesContent":["// What a team leader or an admin may do to one member of a team: promote a player to co-captain,\n// demote a co-captain to player, or remove them. The team's management callables refuse what this\n// leaves out, and the team page and the admin Teams tab offer exactly what it allows (FRONTEND-110):\n//\n// - the captain is never moved or removed here — an admin changes the team's captain first;\n// - only the captain and an admin promote or demote, and a ghost is never made a co-captain, since no\n// one could act with that authority;\n// - a co-captain removes plain players only — never another co-captain, never the captain.\n//\n// A ghost leaves through its own removal, which decides whether it has played; that is still a\n// removal here.\n\nimport type { CaptainTeamRole } from '../types/audit.js';\nimport {\n TEAM_CAPTAIN_ROLE,\n TEAM_CO_CAPTAIN_ROLE,\n TEAM_PLAYER_ROLE,\n type SystemRole,\n type TeamRole,\n} from '../types/unions.js';\n\n/** An action on a member taken through its admin entry, under the admin role. */\nexport const TEAM_MEMBER_ADMIN_ACTOR = 'admin' as const satisfies SystemRole;\n\n/** The authority an action on a member is taken under: an admin, or the caller's role on the team. */\nexport type TeamMemberActor = typeof TEAM_MEMBER_ADMIN_ACTOR | CaptainTeamRole;\n\n/** The member acted on: their role on the team, and whether they are a ghost. */\nexport interface TeamMemberTarget {\n role: TeamRole;\n isGhost: boolean;\n}\n\nexport interface TeamMemberActions {\n /** Make the player a co-captain. */\n promote: boolean;\n /** Make the co-captain a player. */\n demote: boolean;\n /** Take them off the team — a ghost through the ghost removal. */\n remove: boolean;\n}\n\nconst NONE: TeamMemberActions = { promote: false, demote: false, remove: false };\n\nexport function teamMemberActions(actor: TeamMemberActor, target: TeamMemberTarget): TeamMemberActions {\n if (target.role === TEAM_CAPTAIN_ROLE) return NONE;\n const managesCoCaptains = actor === TEAM_MEMBER_ADMIN_ACTOR || actor === TEAM_CAPTAIN_ROLE;\n return {\n promote: managesCoCaptains && target.role === TEAM_PLAYER_ROLE && !target.isGhost,\n demote: managesCoCaptains && target.role === TEAM_CO_CAPTAIN_ROLE,\n remove: managesCoCaptains || target.role === TEAM_PLAYER_ROLE,\n };\n}\n"]}
|