Compare commits

..

9 Commits

Author SHA1 Message Date
d67fdd9fee Merge pull request 'Speed up Shot Lab video source queries' (#304) from codex/fix-shot-lab-video-picker into master
Reviewed-on: #304
2026-07-22 01:08:33 +00:00
d787e5e9a2 Speed up Shot Lab video source queries
All checks were successful
Tests / Tests (pull_request) Successful in 39s
2026-07-21 17:39:55 -07:00
1d73b2d67b Merge pull request 'Declare taxonomy filter variables on the makes/runs leaderboards' (#302) from dean/leaderboard-filter-operations into master
Reviewed-on: #302
2026-07-21 16:59:34 +00:00
Dean Wenstrand
aa731b85fc Declare taxonomy filter variables on the makes/runs leaderboards
All checks were successful
Tests / Tests (pull_request) Successful in 18s
The backend leaderboard resolvers gained game_type, table size and pocket
size filters, but GetMakesLeaderboard and GetRunsLeaderboard never declared
them — GraphQL silently drops undeclared variables, so anything the client
passed was ignored and both boards stayed global.

Declare and forward the five filter args on both queries, matching the
names the drill run leaderboard already uses.
2026-07-21 09:30:37 -07:00
644f70c3b0 Merge pull request 'Shot Lab: video-first GetShotLabVideos (replaces GetRecordedStreams/GetLiveStreams)' (#301) from colonelpanic/shot-lab-video-picker into master 2026-07-21 06:47:45 +00:00
1a95439ed2 Replace GetRecordedStreams/GetLiveStreams with video-first GetShotLabVideos
All checks were successful
Tests / Tests (pull_request) Successful in 44s
Shot Lab's source picker becomes video-first: one query for recent videos
regardless of stream completion (an in-progress recording with no shots
yet still appears), carrying stream recency fields so the client can hint
"actively updating" without gating on it. Operation-only change; schema
is untouched (the stream fields already exist).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 23:42:43 -07:00
5e14cd2201 Merge pull request 'Regenerate schema for leaderboard taxonomy filters' (#300) from dean/leaderboard-taxonomy into master
Reviewed-on: #300
2026-07-21 04:20:57 +00:00
4576b25dae Merge pull request 'Regenerate schema with upstream Strawberry' (#299) from codex/strawberry-upgrade into master 2026-07-20 22:08:35 +00:00
6d9cb4126e Merge pull request 'Add per-video HomographyBackendGQL selection to VideoMetadataInput' (#298) from colonelpanic/homography-backend-selection into master 2026-07-18 02:12:18 +00:00
6 changed files with 155 additions and 643 deletions

View File

@@ -2554,7 +2554,6 @@ export type Mutation = {
reactToVideo: Scalars["Boolean"]["output"]; reactToVideo: Scalars["Boolean"]["output"];
recalculateChallengeEntry: ChallengeEntry; recalculateChallengeEntry: ChallengeEntry;
reportContent: Scalars["Boolean"]["output"]; reportContent: Scalars["Boolean"]["output"];
requestSessionCoachGeneration: SessionCoachGql;
requestVideoExport: VideoExportJobGql; requestVideoExport: VideoExportJobGql;
respondToChallengeInvitation: ChallengeInvitation; respondToChallengeInvitation: ChallengeInvitation;
retireTags: Scalars["Boolean"]["output"]; retireTags: Scalars["Boolean"]["output"];
@@ -2766,10 +2765,6 @@ export type MutationReportContentArgs = {
videoId: Scalars["Int"]["input"]; videoId: Scalars["Int"]["input"];
}; };
export type MutationRequestSessionCoachGenerationArgs = {
videoId: Scalars["Int"]["input"];
};
export type MutationRequestVideoExportArgs = { export type MutationRequestVideoExportArgs = {
input: RequestVideoExportInput; input: RequestVideoExportInput;
}; };
@@ -3605,18 +3600,6 @@ export enum SessionCoachCandidateKindEnum {
UsagePattern = "USAGE_PATTERN", UsagePattern = "USAGE_PATTERN",
} }
export type SessionCoachDecisionGql = {
__typename?: "SessionCoachDecisionGQL";
body?: Maybe<Scalars["String"]["output"]>;
drillId?: Maybe<Scalars["String"]["output"]>;
drillReason?: Maybe<Scalars["String"]["output"]>;
practiceAttemptCount?: Maybe<Scalars["Int"]["output"]>;
practiceTarget?: Maybe<Scalars["String"]["output"]>;
selectedCandidateId?: Maybe<Scalars["ID"]["output"]>;
suggestedAction?: Maybe<Scalars["String"]["output"]>;
title?: Maybe<Scalars["String"]["output"]>;
};
export type SessionCoachEvidenceGql = { export type SessionCoachEvidenceGql = {
__typename?: "SessionCoachEvidenceGQL"; __typename?: "SessionCoachEvidenceGQL";
attemptCount: Scalars["Int"]["output"]; attemptCount: Scalars["Int"]["output"];
@@ -3635,7 +3618,6 @@ export type SessionCoachEvidenceGql = {
export type SessionCoachGql = { export type SessionCoachGql = {
__typename?: "SessionCoachGQL"; __typename?: "SessionCoachGQL";
agentGeneration?: Maybe<SessionCoachGenerationGql>;
analysisVersion: Scalars["String"]["output"]; analysisVersion: Scalars["String"]["output"];
analyzedShotCount: Scalars["Int"]["output"]; analyzedShotCount: Scalars["Int"]["output"];
candidates: Array<SessionCoachCandidateGql>; candidates: Array<SessionCoachCandidateGql>;
@@ -3654,44 +3636,6 @@ export type SessionCoachGql = {
videoId: Scalars["Int"]["output"]; videoId: Scalars["Int"]["output"];
}; };
export type SessionCoachGenerationDiagnosticsGql = {
__typename?: "SessionCoachGenerationDiagnosticsGQL";
abstentionReason?: Maybe<Scalars["String"]["output"]>;
analysisVersion: Scalars["String"]["output"];
attemptCount: Scalars["Int"]["output"];
cachedInputTokens?: Maybe<Scalars["Int"]["output"]>;
enqueueCount: Scalars["Int"]["output"];
failureCode?: Maybe<Scalars["String"]["output"]>;
inputHash: Scalars["String"]["output"];
inputTokens?: Maybe<Scalars["Int"]["output"]>;
lastEnqueuedAt?: Maybe<Scalars["DateTime"]["output"]>;
latencyMs?: Maybe<Scalars["Int"]["output"]>;
maxAttempts: Scalars["Int"]["output"];
modelName: Scalars["String"]["output"];
outputTokens?: Maybe<Scalars["Int"]["output"]>;
promptVersion: Scalars["String"]["output"];
providerKey: Scalars["String"]["output"];
startedAt?: Maybe<Scalars["DateTime"]["output"]>;
updatedAt: Scalars["DateTime"]["output"];
};
export type SessionCoachGenerationGql = {
__typename?: "SessionCoachGenerationGQL";
completedAt?: Maybe<Scalars["DateTime"]["output"]>;
createdAt: Scalars["DateTime"]["output"];
decision?: Maybe<SessionCoachDecisionGql>;
diagnostics?: Maybe<SessionCoachGenerationDiagnosticsGql>;
id: Scalars["ID"]["output"];
state: SessionCoachGenerationStateEnum;
};
export enum SessionCoachGenerationStateEnum {
Failed = "FAILED",
Queued = "QUEUED",
Ready = "READY",
Running = "RUNNING",
}
export enum SessionCoachIneligibilityReasonEnum { export enum SessionCoachIneligibilityReasonEnum {
Multiplayer = "MULTIPLAYER", Multiplayer = "MULTIPLAYER",
} }
@@ -5292,6 +5236,11 @@ export type GetVideoFeedQuery = {
export type GetMakesLeaderboardQueryVariables = Exact<{ export type GetMakesLeaderboardQueryVariables = Exact<{
interval?: InputMaybe<TimeInterval>; interval?: InputMaybe<TimeInterval>;
when?: InputMaybe<Scalars["DateTime"]["input"]>; when?: InputMaybe<Scalars["DateTime"]["input"]>;
gameType?: InputMaybe<Scalars["String"]["input"]>;
tableSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
tableSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
}>; }>;
export type GetMakesLeaderboardQuery = { export type GetMakesLeaderboardQuery = {
@@ -5316,6 +5265,11 @@ export type GetMakesLeaderboardQuery = {
export type GetRunsLeaderboardQueryVariables = Exact<{ export type GetRunsLeaderboardQueryVariables = Exact<{
interval?: InputMaybe<TimeInterval>; interval?: InputMaybe<TimeInterval>;
when?: InputMaybe<Scalars["DateTime"]["input"]>; when?: InputMaybe<Scalars["DateTime"]["input"]>;
gameType?: InputMaybe<Scalars["String"]["input"]>;
tableSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
tableSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
}>; }>;
export type GetRunsLeaderboardQuery = { export type GetRunsLeaderboardQuery = {
@@ -5400,43 +5354,6 @@ export type GetMyDrillRunsQuery = {
}>; }>;
}; };
export type GetLiveStreamsQueryVariables = Exact<{
limit?: Scalars["Int"]["input"];
}>;
export type GetLiveStreamsQuery = {
__typename?: "Query";
getFeedVideos: {
__typename?: "VideoHistoryGQL";
videos: Array<{
__typename?: "VideoGQL";
id: number;
name?: string | null;
startTime?: any | null;
createdAt?: any | null;
screenshotUri?: string | null;
elapsedTime?: number | null;
owner?: {
__typename?: "UserGQL";
id: number;
username: string;
profileImageUri?: string | null;
} | null;
stream?: {
__typename?: "UploadStreamGQL";
id: string;
isCompleted: boolean;
lastSegmentUploadedAt?: any | null;
} | null;
}>;
pageInfo: {
__typename?: "PageInfoGQL";
hasNextPage: boolean;
endCursor?: string | null;
};
};
};
export type GetVideoMakePercentageIntervalsQueryVariables = Exact<{ export type GetVideoMakePercentageIntervalsQueryVariables = Exact<{
videoId: Scalars["ID"]["input"]; videoId: Scalars["ID"]["input"];
intervalDuration: Scalars["Int"]["input"]; intervalDuration: Scalars["Int"]["input"];
@@ -6778,11 +6695,12 @@ export type ReactToVideoMutation = {
reactToVideo: boolean; reactToVideo: boolean;
}; };
export type GetRecordedStreamsQueryVariables = Exact<{ export type GetShotLabVideosQueryVariables = Exact<{
userId: Scalars["Int"]["input"];
limit?: Scalars["Int"]["input"]; limit?: Scalars["Int"]["input"];
}>; }>;
export type GetRecordedStreamsQuery = { export type GetShotLabVideosQuery = {
__typename?: "Query"; __typename?: "Query";
getFeedVideos: { getFeedVideos: {
__typename?: "VideoHistoryGQL"; __typename?: "VideoHistoryGQL";
@@ -6800,6 +6718,12 @@ export type GetRecordedStreamsQuery = {
username: string; username: string;
profileImageUri?: string | null; profileImageUri?: string | null;
} | null; } | null;
stream?: {
__typename?: "UploadStreamGQL";
id: string;
isCompleted: boolean;
lastSegmentUploadedAt?: any | null;
} | null;
}>; }>;
}; };
}; };
@@ -6823,29 +6747,13 @@ export type GetRecordedStreamShotsQuery = {
__typename?: "SerializedShotPathsGQL"; __typename?: "SerializedShotPathsGQL";
b64EncodedBuffer?: string | null; b64EncodedBuffer?: string | null;
} | null; } | null;
cueObjectFeatures?: {
__typename?: "CueObjectFeaturesGQL";
cueObjectDistance?: number | null;
cueObjectAngle?: number | null;
cueBallSpeed?: number | null;
shotDirection?: ShotDirectionEnum | null;
spinType?: SpinTypeEnum | null;
} | null;
pocketingIntentionFeatures?: { pocketingIntentionFeatures?: {
__typename?: "PocketingIntentionFeaturesGQL"; __typename?: "PocketingIntentionFeaturesGQL";
make?: boolean | null; make?: boolean | null;
targetPocketDistance?: number | null;
targetPocketAngle?: number | null;
targetPocketAngleDirection?: ShotDirectionEnum | null;
marginOfErrorInDegrees?: number | null;
intendedPocketType?: PocketEnum | null;
difficulty?: number | null;
} | null; } | null;
pocketingIntentionInfo?: { pocketingIntentionInfo?: {
__typename?: "PocketingIntentionInfoGQL"; __typename?: "PocketingIntentionInfoGQL";
ballId: number;
pocketId: PocketIdentifier; pocketId: PocketIdentifier;
pathMetadataIndex: number;
} | null; } | null;
}>; }>;
}; };
@@ -7003,94 +6911,6 @@ export type GetSessionCoachQuery = {
rankReason: string; rankReason: string;
}; };
}>; }>;
agentGeneration?: {
__typename?: "SessionCoachGenerationGQL";
id: string;
state: SessionCoachGenerationStateEnum;
createdAt: any;
completedAt?: any | null;
decision?: {
__typename?: "SessionCoachDecisionGQL";
selectedCandidateId?: string | null;
title?: string | null;
body?: string | null;
suggestedAction?: string | null;
drillId?: string | null;
drillReason?: string | null;
practiceAttemptCount?: number | null;
practiceTarget?: string | null;
} | null;
diagnostics?: {
__typename?: "SessionCoachGenerationDiagnosticsGQL";
analysisVersion: string;
promptVersion: string;
providerKey: string;
modelName: string;
inputHash: string;
attemptCount: number;
maxAttempts: number;
enqueueCount: number;
latencyMs?: number | null;
inputTokens?: number | null;
cachedInputTokens?: number | null;
outputTokens?: number | null;
failureCode?: string | null;
updatedAt: any;
startedAt?: any | null;
lastEnqueuedAt?: any | null;
abstentionReason?: string | null;
} | null;
} | null;
};
};
export type RequestSessionCoachGenerationMutationVariables = Exact<{
videoId: Scalars["Int"]["input"];
}>;
export type RequestSessionCoachGenerationMutation = {
__typename?: "Mutation";
requestSessionCoachGeneration: {
__typename?: "SessionCoachGQL";
state: SessionCoachStateEnum;
agentGeneration?: {
__typename?: "SessionCoachGenerationGQL";
id: string;
state: SessionCoachGenerationStateEnum;
createdAt: any;
completedAt?: any | null;
decision?: {
__typename?: "SessionCoachDecisionGQL";
selectedCandidateId?: string | null;
title?: string | null;
body?: string | null;
suggestedAction?: string | null;
drillId?: string | null;
drillReason?: string | null;
practiceAttemptCount?: number | null;
practiceTarget?: string | null;
} | null;
diagnostics?: {
__typename?: "SessionCoachGenerationDiagnosticsGQL";
analysisVersion: string;
promptVersion: string;
providerKey: string;
modelName: string;
inputHash: string;
attemptCount: number;
maxAttempts: number;
enqueueCount: number;
latencyMs?: number | null;
inputTokens?: number | null;
cachedInputTokens?: number | null;
outputTokens?: number | null;
failureCode?: string | null;
updatedAt: any;
startedAt?: any | null;
lastEnqueuedAt?: any | null;
abstentionReason?: string | null;
} | null;
} | null;
}; };
}; };
@@ -7123,45 +6943,6 @@ export type SessionCoachCandidateFieldsFragment = {
}; };
}; };
export type SessionCoachGenerationFieldsFragment = {
__typename?: "SessionCoachGenerationGQL";
id: string;
state: SessionCoachGenerationStateEnum;
createdAt: any;
completedAt?: any | null;
decision?: {
__typename?: "SessionCoachDecisionGQL";
selectedCandidateId?: string | null;
title?: string | null;
body?: string | null;
suggestedAction?: string | null;
drillId?: string | null;
drillReason?: string | null;
practiceAttemptCount?: number | null;
practiceTarget?: string | null;
} | null;
diagnostics?: {
__typename?: "SessionCoachGenerationDiagnosticsGQL";
analysisVersion: string;
promptVersion: string;
providerKey: string;
modelName: string;
inputHash: string;
attemptCount: number;
maxAttempts: number;
enqueueCount: number;
latencyMs?: number | null;
inputTokens?: number | null;
cachedInputTokens?: number | null;
outputTokens?: number | null;
failureCode?: string | null;
updatedAt: any;
startedAt?: any | null;
lastEnqueuedAt?: any | null;
abstentionReason?: string | null;
} | null;
};
export type PlayerSummaryFieldsFragment = { export type PlayerSummaryFieldsFragment = {
__typename?: "PlayerSummaryGQL"; __typename?: "PlayerSummaryGQL";
clusterId: number; clusterId: number;
@@ -9636,43 +9417,6 @@ export const SessionCoachCandidateFieldsFragmentDoc = gql`
} }
} }
`; `;
export const SessionCoachGenerationFieldsFragmentDoc = gql`
fragment SessionCoachGenerationFields on SessionCoachGenerationGQL {
id
state
createdAt
completedAt
decision {
selectedCandidateId
title
body
suggestedAction
drillId
drillReason
practiceAttemptCount
practiceTarget
}
diagnostics {
analysisVersion
promptVersion
providerKey
modelName
inputHash
attemptCount
maxAttempts
enqueueCount
latencyMs
inputTokens
cachedInputTokens
outputTokens
failureCode
updatedAt
startedAt
lastEnqueuedAt
abstentionReason
}
}
`;
export const PlayerClusterShotFieldsFragmentDoc = gql` export const PlayerClusterShotFieldsFragmentDoc = gql`
fragment PlayerClusterShotFields on PlayerClusterShotGQL { fragment PlayerClusterShotFields on PlayerClusterShotGQL {
shotId shotId
@@ -12005,8 +11749,24 @@ export type GetVideoFeedQueryResult = Apollo.QueryResult<
GetVideoFeedQueryVariables GetVideoFeedQueryVariables
>; >;
export const GetMakesLeaderboardDocument = gql` export const GetMakesLeaderboardDocument = gql`
query GetMakesLeaderboard($interval: TimeInterval, $when: DateTime) { query GetMakesLeaderboard(
getMakesLeaderboard(interval: $interval, when: $when) { $interval: TimeInterval
$when: DateTime
$gameType: String
$tableSizeMin: Float
$tableSizeMax: Float
$pocketSizeMin: Float
$pocketSizeMax: Float
) {
getMakesLeaderboard(
interval: $interval
when: $when
gameType: $gameType
tableSizeMin: $tableSizeMin
tableSizeMax: $tableSizeMax
pocketSizeMin: $pocketSizeMin
pocketSizeMax: $pocketSizeMax
) {
entries { entries {
user { user {
id id
@@ -12035,6 +11795,11 @@ export const GetMakesLeaderboardDocument = gql`
* variables: { * variables: {
* interval: // value for 'interval' * interval: // value for 'interval'
* when: // value for 'when' * when: // value for 'when'
* gameType: // value for 'gameType'
* tableSizeMin: // value for 'tableSizeMin'
* tableSizeMax: // value for 'tableSizeMax'
* pocketSizeMin: // value for 'pocketSizeMin'
* pocketSizeMax: // value for 'pocketSizeMax'
* }, * },
* }); * });
*/ */
@@ -12088,8 +11853,24 @@ export type GetMakesLeaderboardQueryResult = Apollo.QueryResult<
GetMakesLeaderboardQueryVariables GetMakesLeaderboardQueryVariables
>; >;
export const GetRunsLeaderboardDocument = gql` export const GetRunsLeaderboardDocument = gql`
query GetRunsLeaderboard($interval: TimeInterval, $when: DateTime) { query GetRunsLeaderboard(
getLongestRunsLeaderboard(interval: $interval, when: $when) { $interval: TimeInterval
$when: DateTime
$gameType: String
$tableSizeMin: Float
$tableSizeMax: Float
$pocketSizeMin: Float
$pocketSizeMax: Float
) {
getLongestRunsLeaderboard(
interval: $interval
when: $when
gameType: $gameType
tableSizeMin: $tableSizeMin
tableSizeMax: $tableSizeMax
pocketSizeMin: $pocketSizeMin
pocketSizeMax: $pocketSizeMax
) {
entries { entries {
id id
runLength runLength
@@ -12121,6 +11902,11 @@ export const GetRunsLeaderboardDocument = gql`
* variables: { * variables: {
* interval: // value for 'interval' * interval: // value for 'interval'
* when: // value for 'when' * when: // value for 'when'
* gameType: // value for 'gameType'
* tableSizeMin: // value for 'tableSizeMin'
* tableSizeMax: // value for 'tableSizeMax'
* pocketSizeMin: // value for 'pocketSizeMin'
* pocketSizeMax: // value for 'pocketSizeMax'
* }, * },
* }); * });
*/ */
@@ -12368,105 +12154,6 @@ export type GetMyDrillRunsQueryResult = Apollo.QueryResult<
GetMyDrillRunsQuery, GetMyDrillRunsQuery,
GetMyDrillRunsQueryVariables GetMyDrillRunsQueryVariables
>; >;
export const GetLiveStreamsDocument = gql`
query GetLiveStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: false, requireCursorCompletion: false }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
startTime
createdAt
screenshotUri
elapsedTime
owner {
id
username
profileImageUri
}
stream {
id
isCompleted
lastSegmentUploadedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`;
/**
* __useGetLiveStreamsQuery__
*
* To run a query within a React component, call `useGetLiveStreamsQuery` and pass it any options that fit your needs.
* When your component renders, `useGetLiveStreamsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetLiveStreamsQuery({
* variables: {
* limit: // value for 'limit'
* },
* });
*/
export function useGetLiveStreamsQuery(
baseOptions?: Apollo.QueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery<GetLiveStreamsQuery, GetLiveStreamsQueryVariables>(
GetLiveStreamsDocument,
options,
);
}
export function useGetLiveStreamsLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery<GetLiveStreamsQuery, GetLiveStreamsQueryVariables>(
GetLiveStreamsDocument,
options,
);
}
export function useGetLiveStreamsSuspenseQuery(
baseOptions?: Apollo.SuspenseQueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useSuspenseQuery<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>(GetLiveStreamsDocument, options);
}
export type GetLiveStreamsQueryHookResult = ReturnType<
typeof useGetLiveStreamsQuery
>;
export type GetLiveStreamsLazyQueryHookResult = ReturnType<
typeof useGetLiveStreamsLazyQuery
>;
export type GetLiveStreamsSuspenseQueryHookResult = ReturnType<
typeof useGetLiveStreamsSuspenseQuery
>;
export type GetLiveStreamsQueryResult = Apollo.QueryResult<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>;
export const GetVideoMakePercentageIntervalsDocument = gql` export const GetVideoMakePercentageIntervalsDocument = gql`
query GetVideoMakePercentageIntervals( query GetVideoMakePercentageIntervals(
$videoId: ID! $videoId: ID!
@@ -14765,13 +14452,13 @@ export type ReactToVideoMutationOptions = Apollo.BaseMutationOptions<
ReactToVideoMutation, ReactToVideoMutation,
ReactToVideoMutationVariables ReactToVideoMutationVariables
>; >;
export const GetRecordedStreamsDocument = gql` export const GetShotLabVideosDocument = gql`
query GetRecordedStreams($limit: Int! = 25) { query GetShotLabVideos($userId: Int!, $limit: Int! = 25) {
getFeedVideos( getFeedVideos(
limit: $limit limit: $limit
filters: { isStreamCompleted: true, excludeVideosWithNoShots: true } includeCallersVideos: false
includePrivate: MINE includePrivate: MINE
feedInput: { allUsers: true } feedInput: { userId: $userId }
) { ) {
videos { videos {
id id
@@ -14785,75 +14472,81 @@ export const GetRecordedStreamsDocument = gql`
username username
profileImageUri profileImageUri
} }
stream {
id
isCompleted
lastSegmentUploadedAt
}
} }
} }
} }
`; `;
/** /**
* __useGetRecordedStreamsQuery__ * __useGetShotLabVideosQuery__
* *
* To run a query within a React component, call `useGetRecordedStreamsQuery` and pass it any options that fit your needs. * To run a query within a React component, call `useGetShotLabVideosQuery` and pass it any options that fit your needs.
* When your component renders, `useGetRecordedStreamsQuery` returns an object from Apollo Client that contains loading, error, and data properties * When your component renders, `useGetShotLabVideosQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI. * you can use to render your UI.
* *
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
* *
* @example * @example
* const { data, loading, error } = useGetRecordedStreamsQuery({ * const { data, loading, error } = useGetShotLabVideosQuery({
* variables: { * variables: {
* userId: // value for 'userId'
* limit: // value for 'limit' * limit: // value for 'limit'
* }, * },
* }); * });
*/ */
export function useGetRecordedStreamsQuery( export function useGetShotLabVideosQuery(
baseOptions?: Apollo.QueryHookOptions< baseOptions: Apollo.QueryHookOptions<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>, >,
) { ) {
const options = { ...defaultOptions, ...baseOptions }; const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery< return Apollo.useQuery<GetShotLabVideosQuery, GetShotLabVideosQueryVariables>(
GetRecordedStreamsQuery, GetShotLabVideosDocument,
GetRecordedStreamsQueryVariables options,
>(GetRecordedStreamsDocument, options); );
} }
export function useGetRecordedStreamsLazyQuery( export function useGetShotLabVideosLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions< baseOptions?: Apollo.LazyQueryHookOptions<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>, >,
) { ) {
const options = { ...defaultOptions, ...baseOptions }; const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery< return Apollo.useLazyQuery<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>(GetRecordedStreamsDocument, options); >(GetShotLabVideosDocument, options);
} }
export function useGetRecordedStreamsSuspenseQuery( export function useGetShotLabVideosSuspenseQuery(
baseOptions?: Apollo.SuspenseQueryHookOptions< baseOptions?: Apollo.SuspenseQueryHookOptions<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>, >,
) { ) {
const options = { ...defaultOptions, ...baseOptions }; const options = { ...defaultOptions, ...baseOptions };
return Apollo.useSuspenseQuery< return Apollo.useSuspenseQuery<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>(GetRecordedStreamsDocument, options); >(GetShotLabVideosDocument, options);
} }
export type GetRecordedStreamsQueryHookResult = ReturnType< export type GetShotLabVideosQueryHookResult = ReturnType<
typeof useGetRecordedStreamsQuery typeof useGetShotLabVideosQuery
>; >;
export type GetRecordedStreamsLazyQueryHookResult = ReturnType< export type GetShotLabVideosLazyQueryHookResult = ReturnType<
typeof useGetRecordedStreamsLazyQuery typeof useGetShotLabVideosLazyQuery
>; >;
export type GetRecordedStreamsSuspenseQueryHookResult = ReturnType< export type GetShotLabVideosSuspenseQueryHookResult = ReturnType<
typeof useGetRecordedStreamsSuspenseQuery typeof useGetShotLabVideosSuspenseQuery
>; >;
export type GetRecordedStreamsQueryResult = Apollo.QueryResult< export type GetShotLabVideosQueryResult = Apollo.QueryResult<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>; >;
export const GetRecordedStreamShotsDocument = gql` export const GetRecordedStreamShotsDocument = gql`
query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) { query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) {
@@ -14870,26 +14563,11 @@ export const GetRecordedStreamShotsDocument = gql`
serializedShotPaths { serializedShotPaths {
b64EncodedBuffer b64EncodedBuffer
} }
cueObjectFeatures {
cueObjectDistance
cueObjectAngle
cueBallSpeed
shotDirection
spinType
}
pocketingIntentionFeatures { pocketingIntentionFeatures {
make make
targetPocketDistance
targetPocketAngle
targetPocketAngleDirection
marginOfErrorInDegrees
intendedPocketType
difficulty
} }
pocketingIntentionInfo { pocketingIntentionInfo {
ballId
pocketId pocketId
pathMetadataIndex
} }
} }
} }
@@ -15184,13 +14862,9 @@ export const GetSessionCoachDocument = gql`
candidates { candidates {
...SessionCoachCandidateFields ...SessionCoachCandidateFields
} }
agentGeneration {
...SessionCoachGenerationFields
}
} }
} }
${SessionCoachCandidateFieldsFragmentDoc} ${SessionCoachCandidateFieldsFragmentDoc}
${SessionCoachGenerationFieldsFragmentDoc}
`; `;
/** /**
@@ -15258,61 +14932,6 @@ export type GetSessionCoachQueryResult = Apollo.QueryResult<
GetSessionCoachQuery, GetSessionCoachQuery,
GetSessionCoachQueryVariables GetSessionCoachQueryVariables
>; >;
export const RequestSessionCoachGenerationDocument = gql`
mutation RequestSessionCoachGeneration($videoId: Int!) {
requestSessionCoachGeneration(videoId: $videoId) {
state
agentGeneration {
...SessionCoachGenerationFields
}
}
}
${SessionCoachGenerationFieldsFragmentDoc}
`;
export type RequestSessionCoachGenerationMutationFn = Apollo.MutationFunction<
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>;
/**
* __useRequestSessionCoachGenerationMutation__
*
* To run a mutation, you first call `useRequestSessionCoachGenerationMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useRequestSessionCoachGenerationMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [requestSessionCoachGenerationMutation, { data, loading, error }] = useRequestSessionCoachGenerationMutation({
* variables: {
* videoId: // value for 'videoId'
* },
* });
*/
export function useRequestSessionCoachGenerationMutation(
baseOptions?: Apollo.MutationHookOptions<
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useMutation<
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>(RequestSessionCoachGenerationDocument, options);
}
export type RequestSessionCoachGenerationMutationHookResult = ReturnType<
typeof useRequestSessionCoachGenerationMutation
>;
export type RequestSessionCoachGenerationMutationResult =
Apollo.MutationResult<RequestSessionCoachGenerationMutation>;
export type RequestSessionCoachGenerationMutationOptions =
Apollo.BaseMutationOptions<
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>;
export const VideoPlayerClustersDocument = gql` export const VideoPlayerClustersDocument = gql`
query VideoPlayerClusters($videoId: Int!) { query VideoPlayerClusters($videoId: Int!) {
videoPlayerClusters(videoId: $videoId) { videoPlayerClusters(videoId: $videoId) {

View File

@@ -1,5 +1,21 @@
query GetMakesLeaderboard($interval: TimeInterval, $when: DateTime) { query GetMakesLeaderboard(
getMakesLeaderboard(interval: $interval, when: $when) { $interval: TimeInterval
$when: DateTime
$gameType: String
$tableSizeMin: Float
$tableSizeMax: Float
$pocketSizeMin: Float
$pocketSizeMax: Float
) {
getMakesLeaderboard(
interval: $interval
when: $when
gameType: $gameType
tableSizeMin: $tableSizeMin
tableSizeMax: $tableSizeMax
pocketSizeMin: $pocketSizeMin
pocketSizeMax: $pocketSizeMax
) {
entries { entries {
user { user {
id id
@@ -13,8 +29,24 @@ query GetMakesLeaderboard($interval: TimeInterval, $when: DateTime) {
} }
} }
query GetRunsLeaderboard($interval: TimeInterval, $when: DateTime) { query GetRunsLeaderboard(
getLongestRunsLeaderboard(interval: $interval, when: $when) { $interval: TimeInterval
$when: DateTime
$gameType: String
$tableSizeMin: Float
$tableSizeMax: Float
$pocketSizeMin: Float
$pocketSizeMax: Float
) {
getLongestRunsLeaderboard(
interval: $interval
when: $when
gameType: $gameType
tableSizeMin: $tableSizeMin
tableSizeMax: $tableSizeMax
pocketSizeMin: $pocketSizeMin
pocketSizeMax: $pocketSizeMax
) {
entries { entries {
id id
runLength runLength

View File

@@ -1,34 +0,0 @@
# Lightweight listing of live (in-progress) streams for pickers like the
# Shot Lab "follow a live stream" flow. Selects only what a picker card
# needs; intentionally avoids the heavy VideoCardFields fragment.
query GetLiveStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: false, requireCursorCompletion: false }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
startTime
createdAt
screenshotUri
elapsedTime
owner {
id
username
profileImageUri
}
stream {
id
isCompleted
lastSegmentUploadedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}

View File

@@ -1,10 +1,12 @@
# Lightweight two-step picker data for loading a recorded shot into Shot Lab. # Lightweight two-step picker data for Shot Lab's video-first source: the
query GetRecordedStreams($limit: Int! = 25) { # caller's recent videos (completed or still uploading), then that video's
# shots. The stream fields hint at "actively updating" without gating.
query GetShotLabVideos($userId: Int!, $limit: Int! = 25) {
getFeedVideos( getFeedVideos(
limit: $limit limit: $limit
filters: { isStreamCompleted: true, excludeVideosWithNoShots: true } includeCallersVideos: false
includePrivate: MINE includePrivate: MINE
feedInput: { allUsers: true } feedInput: { userId: $userId }
) { ) {
videos { videos {
id id
@@ -18,6 +20,11 @@ query GetRecordedStreams($limit: Int! = 25) {
username username
profileImageUri profileImageUri
} }
stream {
id
isCompleted
lastSegmentUploadedAt
}
} }
} }
} }
@@ -36,26 +43,11 @@ query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) {
serializedShotPaths { serializedShotPaths {
b64EncodedBuffer b64EncodedBuffer
} }
cueObjectFeatures {
cueObjectDistance
cueObjectAngle
cueBallSpeed
shotDirection
spinType
}
pocketingIntentionFeatures { pocketingIntentionFeatures {
make make
targetPocketDistance
targetPocketAngle
targetPocketAngleDirection
marginOfErrorInDegrees
intendedPocketType
difficulty
} }
pocketingIntentionInfo { pocketingIntentionInfo {
ballId
pocketId pocketId
pathMetadataIndex
} }
} }
} }

View File

@@ -20,18 +20,6 @@ query GetSessionCoach($videoId: Int!) {
candidates { candidates {
...SessionCoachCandidateFields ...SessionCoachCandidateFields
} }
agentGeneration {
...SessionCoachGenerationFields
}
}
}
mutation RequestSessionCoachGeneration($videoId: Int!) {
requestSessionCoachGeneration(videoId: $videoId) {
state
agentGeneration {
...SessionCoachGenerationFields
}
} }
} }
@@ -61,39 +49,3 @@ fragment SessionCoachCandidateFields on SessionCoachCandidateGQL {
rankReason rankReason
} }
} }
fragment SessionCoachGenerationFields on SessionCoachGenerationGQL {
id
state
createdAt
completedAt
decision {
selectedCandidateId
title
body
suggestedAction
drillId
drillReason
practiceAttemptCount
practiceTarget
}
diagnostics {
analysisVersion
promptVersion
providerKey
modelName
inputHash
attemptCount
maxAttempts
enqueueCount
latencyMs
inputTokens
cachedInputTokens
outputTokens
failureCode
updatedAt
startedAt
lastEnqueuedAt
abstentionReason
}
}

View File

@@ -716,7 +716,6 @@ type Mutation {
shotId: Int! shotId: Int!
fieldsToEdit: EditableShotFieldInputGQL! fieldsToEdit: EditableShotFieldInputGQL!
): EditShotReturn! ): EditShotReturn!
requestSessionCoachGeneration(videoId: Int!): SessionCoachGQL!
getProfileImageUploadLink( getProfileImageUploadLink(
fileExt: String = ".png" fileExt: String = ".png"
): GetProfileUploadLinkReturn! ): GetProfileUploadLinkReturn!
@@ -1321,17 +1320,6 @@ enum SessionCoachCandidateKindEnum {
USAGE_PATTERN USAGE_PATTERN
} }
type SessionCoachDecisionGQL {
selectedCandidateId: ID
title: String
body: String
suggestedAction: String
drillId: String
drillReason: String
practiceAttemptCount: Int
practiceTarget: String
}
type SessionCoachEvidenceGQL { type SessionCoachEvidenceGQL {
bucketKey: String! bucketKey: String!
bucketLabel: String! bucketLabel: String!
@@ -1364,43 +1352,6 @@ type SessionCoachGQL {
makePercentage: Float makePercentage: Float
primaryCandidate: SessionCoachCandidateGQL primaryCandidate: SessionCoachCandidateGQL
candidates: [SessionCoachCandidateGQL!]! candidates: [SessionCoachCandidateGQL!]!
agentGeneration: SessionCoachGenerationGQL
}
type SessionCoachGenerationDiagnosticsGQL {
analysisVersion: String!
promptVersion: String!
providerKey: String!
modelName: String!
inputHash: String!
attemptCount: Int!
maxAttempts: Int!
enqueueCount: Int!
latencyMs: Int
inputTokens: Int
cachedInputTokens: Int
outputTokens: Int
failureCode: String
updatedAt: DateTime!
startedAt: DateTime
lastEnqueuedAt: DateTime
abstentionReason: String
}
type SessionCoachGenerationGQL {
id: ID!
state: SessionCoachGenerationStateEnum!
createdAt: DateTime!
completedAt: DateTime
decision: SessionCoachDecisionGQL
diagnostics: SessionCoachGenerationDiagnosticsGQL
}
enum SessionCoachGenerationStateEnum {
QUEUED
RUNNING
READY
FAILED
} }
enum SessionCoachIneligibilityReasonEnum { enum SessionCoachIneligibilityReasonEnum {