Compare commits

..

2 Commits

Author SHA1 Message Date
8111042936 Add pool hall camera claim schema
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2026-06-16 15:41:16 -07:00
d6fd68c1f6 add quotaEnforcementEnabled to deployed config
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2026-05-28 14:40:31 -07:00
7 changed files with 263 additions and 882 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -101,27 +101,6 @@ query GetVideoFeedSessionCount(
}
}
# Minimal query for the Home recency nudge ("you haven't recorded in N days").
# Only the most recent session's start time — avoids pulling the full
# VideoCardFields payload (reactions, comments, player summaries, etc.).
query GetLastSessionDate(
$filters: VideoFilterInput = null
$includePrivate: IncludePrivateEnum = MINE
$feedInput: VideoFeedInputGQL = null
) {
getFeedVideos(
limit: 1
filters: $filters
includePrivate: $includePrivate
feedInput: $feedInput
) {
videos {
id
startTime
}
}
}
query GetVideoFeed(
$limit: Int! = 5
$after: String = null

View File

@@ -30,33 +30,3 @@ query GetRunsLeaderboard($interval: TimeInterval, $when: DateTime) {
}
}
}
query GetDrillRunLeaderboard(
$drillTag: String!
$interval: TimeInterval
$limit: Int = 50
) {
getDrillRunLeaderboard(
drillTag: $drillTag
interval: $interval
limit: $limit
) {
entries {
id
runLength
videoId
user {
id
username
profileImageUri
}
}
youRun {
id
runLength
videoId
}
youRank
totalPlayers
}
}

View File

@@ -132,38 +132,6 @@ query GetShotsByIds($ids: [Int!]!) {
}
}
# Lightweight clip boundaries for condensed session playback. The inline
# session player only needs each shot's frame/time window to seek between
# shots — this skips the heavy ShotWithAllFeatures payload (cue/pocketing
# features, serialized shot paths, annotations, nested video/playlist). The
# startTime/endTime @client resolvers derive their values from the frame
# fields + the video (looked up internally), so this is all they require.
fragment ShotClipRange on ShotGQL {
id
videoId
startFrame
endFrame
startTime @client
endTime @client
}
query GetShotClipRanges(
$filterInput: FilterInput!
$shotsOrdering: GetShotsOrdering
$limit: Int
) {
getOrderedShots(
filterInput: $filterInput
shotsOrdering: $shotsOrdering
limit: $limit
) {
count
shots {
...ShotClipRange
}
}
}
fragment ShotWithAllFeatures on ShotGQL {
id
videoId

View File

@@ -49,39 +49,6 @@ query GetUserPlayTime($userId: Int!, $filters: VideoFilterInput) {
}
}
query GetUploadQuotaStatus {
getQuotaStatus {
tierName
periodStart
periodEnd
durationUsedSeconds
durationLimitSeconds
maxVideoDurationSeconds
durationRemainingSeconds
canUpload
importQuotaBuckets {
quotaKey
appliesToUploadKind
periodStart
periodEnd
durationUsedSeconds
durationLimitSeconds
durationRemainingSeconds
canUpload
}
recordingQuotaBuckets {
quotaKey
appliesToUploadKind
periodStart
periodEnd
durationUsedSeconds
durationLimitSeconds
durationRemainingSeconds
canUpload
}
}
}
query getUsernames(
$matchString: String!
$limit: Int = null

View File

@@ -139,15 +139,6 @@ query GetVideoSocialDetailsById($videoId: Int!) {
}
}
# Full card payload for a single video — reuses the same VideoCardFields
# fragment the feed list uses, so the session-detail meta header shares one
# source of truth (and the normalized Apollo cache) with the feed card.
query GetVideoCard($videoId: Int!) {
getVideo(videoId: $videoId) {
...VideoCardFields
}
}
query GetVideos($videoIds: [Int!]!) {
getVideos(videoIds: $videoIds) {
...VideoStreamMetadata

View File

@@ -31,11 +31,6 @@ type Query {
limit: Int! = 50
requiredTags: [String!] = null
): RunLeaderboardGQL!
getDrillRunLeaderboard(
drillTag: String!
interval: TimeInterval = null
limit: Int! = 50
): DrillRunLeaderboardGQL!
getMakesLeaderboard(
interval: TimeInterval = null
when: DateTime = null
@@ -47,6 +42,12 @@ type Query {
filters: NotificationFilters = null
): NotificationConnection!
unreadNotificationCount: Int!
poolHalls: [PoolHall!]!
claimablePoolHalls: [PoolHall!]!
poolHallCameras(poolHallId: ID!): [PoolHallCamera!]!
claimableCameras(poolHallId: ID!): [PoolHallCamera!]!
cameraClaimSession(id: ID!): CameraClaimSession
activeCameraLease: CameraLease
getRuns(
filterInput: RunFilterInput!
runIds: [Int!] = null
@@ -103,7 +104,6 @@ type Query {
): UserRelationshipsResult!
getAvailableSubscriptionOptions: StripeSubscriptionOptionsGQL!
getUserSubscriptionStatus: UserSubscriptionStatusGQL!
getAppleAppAccountToken: String!
getQuotaStatus: QuotaStatusGQL!
getPlayTime(userId: Int!, filters: VideoFilterInput = null): UserPlayTimeGQL!
getUserVideos(
@@ -755,13 +755,6 @@ type RunLeaderboardGQL {
entries: [RunGQL!]!
}
type DrillRunLeaderboardGQL {
entries: [RunGQL!]!
youRun: RunGQL
youRank: Int
totalPlayers: Int!
}
type CountLeaderboardGQL {
entries: [UserShotCountEntry!]!
}
@@ -853,6 +846,63 @@ input NotificationFilters {
notificationTypes: [NotificationTypeEnum!] = null
}
type PoolHall {
id: ID!
name: String!
address: String
latitude: Float
longitude: Float
timezone: String
status: String!
createdAt: DateTime!
updatedAt: DateTime!
}
type PoolHallCamera {
id: ID!
poolHallId: ID!
name: String!
tableLabel: String
streamPath: String!
status: String!
lastPublishedAt: DateTime
lastUnpublishedAt: DateTime
createdAt: DateTime!
updatedAt: DateTime!
poolHall: PoolHall!
}
type CameraClaimSession {
id: ID!
cameraId: ID!
userId: ID!
challengeCode: String!
status: String!
expiresAt: DateTime!
detectedAt: DateTime
failedAt: DateTime
failureReason: String
createdAt: DateTime!
updatedAt: DateTime!
camera: PoolHallCamera!
}
type CameraLease {
id: ID!
cameraId: ID!
claimSessionId: ID
userId: ID!
videoId: ID
status: String!
startedAt: DateTime!
endedAt: DateTime
expiresAt: DateTime
endReason: String
createdAt: DateTime!
updatedAt: DateTime!
camera: PoolHallCamera!
}
type GetRunsResult {
runs: [RunGQL!]!
count: Int
@@ -1033,7 +1083,6 @@ enum EntitlementSourceTypeEnum {
ADMIN
MANUAL
STRIPE
APPLE
ALPHA_LEGACY
}
@@ -1163,6 +1212,15 @@ type Mutation {
markAllNotificationsAsRead: Boolean!
markNotificationsAsRead(notificationIds: [Int!]!): Boolean!
deleteNotification(notificationId: Int!): Boolean!
createPoolHall(input: CreatePoolHallInput!): PoolHall!
updatePoolHall(input: UpdatePoolHallInput!): PoolHall!
createPoolHallCamera(
input: CreatePoolHallCameraInput!
): PoolHallCameraStreamCredentials!
updatePoolHallCamera(input: UpdatePoolHallCameraInput!): PoolHallCamera!
rotatePoolHallCameraStreamKey(cameraId: ID!): PoolHallCameraStreamCredentials!
createCameraClaimSession(cameraId: ID!): CameraClaimSession!
cancelCameraClaimSession(claimSessionId: ID!): CameraClaimSession!
finalizePlayerAssignments(
input: FinalizePlayerAssignmentsInput!
): [PlayerClusterGQL!]!
@@ -1189,9 +1247,6 @@ type Mutation {
retireTags(tagIds: [Int!]!): Boolean!
ensureStripeCustomerExists: UserGQL!
deleteUser: Boolean!
syncAppleSubscription(
input: SyncAppleSubscriptionInputGQL!
): SyncAppleSubscriptionResultGQL!
createSubscription(priceId: String!): CreateSubscriptionResultGQL!
createCustomerPortalSession: CreateCustomerPortalSessionResultGQL!
cancelSubscription: UserSubscriptionStatusGQL!
@@ -1240,6 +1295,44 @@ enum ReportReasonEnum {
OTHER
}
input CreatePoolHallInput {
name: String!
address: String = null
latitude: Float = null
longitude: Float = null
timezone: String = null
}
input UpdatePoolHallInput {
id: ID!
name: String = null
address: String = null
latitude: Float = null
longitude: Float = null
timezone: String = null
status: String = null
}
type PoolHallCameraStreamCredentials {
camera: PoolHallCamera!
streamKey: String!
rtmpPath: String!
}
input CreatePoolHallCameraInput {
poolHallId: ID!
name: String!
tableLabel: String = null
streamPath: String = null
}
input UpdatePoolHallCameraInput {
id: ID!
name: String = null
tableLabel: String = null
status: String = null
}
input FinalizePlayerAssignmentsInput {
videoId: Int!
clusterAssignments: [ClusterAssignmentInput!]! = []
@@ -1345,26 +1438,6 @@ input EditUserInputGQL {
agreesToMarketing: Boolean = null
}
type SyncAppleSubscriptionResultGQL {
ok: Boolean!
errorCode: String
errorMessage: String
hasActiveSubscription: Boolean!
entitlementSource: EntitlementSourceTypeEnum
entitlementStartsAt: DateTime
entitlementEndsAt: DateTime
appleStatus: Int
originalTransactionId: String
latestTransactionId: String
productId: String
expiresAt: DateTime
}
input SyncAppleSubscriptionInputGQL {
signedTransactionInfo: String!
signedRenewalInfo: String = null
}
type CreateSubscriptionResultGQL {
checkoutUrl: String!
sessionId: String!