Compare commits

...

49 Commits

Author SHA1 Message Date
2a267ce961 chore: Allow protobuf >=4.25.3 for hatchet-sdk v1 compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 15:21:46 -08:00
bde669a608 fix: Run black on protobuf Python files in CI check
The assert-no-changes.sh script was missing black formatting for
the generated Python protobuf files, causing CI to fail after
commit aa9c561 applied black formatting to those files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 11:42:44 -08:00
aa9c561e9d style: Apply black formatting to protobuf generated files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 07:42:04 -08:00
3def8c97c8 Merge pull request 'Add android recording format to deployed config' (#221) from loewy/add-recording-format-to-deployed-config into master
Reviewed-on: #221
2026-01-04 00:45:37 +00:00
88de1ef807 add android recording format to deployed config
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2026-01-03 10:17:58 -08:00
2bb4fdd08f Merge pull request 'Add cancellation feedback schema and operations' (#220) from loewy/add-cancellation-feedback-schema-and-ops into master
Reviewed-on: #220
2025-12-26 18:17:11 +00:00
8649673f1b add missing field
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2025-12-16 17:09:18 -08:00
f5e6459882 add schema and operations for submit cancellation feedback, along with associated enum 2025-12-16 16:51:08 -08:00
ced1b153de Merge pull request 'Remove package-lock.json' (#219) from loewy/remove-package-lock-json into master
Reviewed-on: #219
2025-12-17 00:46:30 +00:00
425a8ec103 remove package-lock.json
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2025-12-16 16:45:06 -08:00
04f408ab5d Merge pull request 'feat: Add following and followers to GetUser query' (#218) from dean/add-followers-to-get-user into master
Reviewed-on: #218
2025-12-16 23:59:17 +00:00
dean
5fbc134c42 feat: Add following and followers to GetUser query
All checks were successful
Tests / Tests (pull_request) Successful in 21s
Adds following and followers arrays to the GetUser query to support
displaying follower/following counts on other users' profiles.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 15:53:59 -08:00
f67288d387 Merge pull request 'feat: Add GetAverageDifficultyForVideo query' (#216) from dean/add-avg-difficulty-for-video-query into master
Reviewed-on: #216
2025-12-16 04:22:56 +00:00
dean
71425a22a6 feat: Add GetAverageDifficultyForVideo query
All checks were successful
Tests / Tests (pull_request) Successful in 10s
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 20:21:22 -08:00
47339caa74 Merge pull request 'Add averageDifficulty to aggregate operation' (#215) from loewy/add-average-difficulty-field into master
Reviewed-on: #215
2025-12-16 04:06:05 +00:00
3c8be1d647 add averageDifficulty to aggregate operation
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2025-12-10 11:43:58 -08:00
09267529cd Merge pull request 'dean/add-challenge-feature' (#212) from dean/add-challenge-feature into master
Reviewed-on: #212
2025-12-10 19:11:18 +00:00
2b48ec48d5 Merge pull request 'feat: Add pocketSize to VideoCardFields fragment' (#214) from dean/feed-pocket-size-v2 into master
Reviewed-on: #214
2025-12-10 18:33:30 +00:00
dean
93bf341c0f feat: Add pocketSize to VideoCardFields fragment
All checks were successful
Tests / Tests (pull_request) Successful in 8s
2025-12-10 10:31:36 -08:00
dean
9f735b61bb chore: Regenerate schema from backend
All checks were successful
Tests / Tests (pull_request) Successful in 9s
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 08:49:41 -08:00
dean
fda8e4eb9d feat: Add challenge dismissal GQL operations
All checks were successful
Tests / Tests (pull_request) Successful in 9s
- Add DismissChallenge/UndismissChallenge mutations
- Add IsChallengeDismissed query
- Add GetMyDismissedChallenges query
- Update schema with dismissal fields

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 08:23:27 -08:00
dean
338c45d59b feat: Add challenge invitations fields and fix feed hasFollowing query
- Add invitations query fields with invitee data to GetChallenge
- Add participantCount field to GetChallenge
- Add GetMyChallengeEntries query (was missing)
- Add hasFollowing to GetVideoFeed response (fixes feed ordering)
- Sync schema with backend challenge types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 08:22:50 -08:00
dean
e879c5008f chore: Regenerate GraphQL TypeScript types
Regenerate gql/src/index.tsx to match current schema and fix
codegen hash mismatch in CI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 08:22:50 -08:00
dean
2d67e076f7 Add GraphQL queries and mutations for challenge feature
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 08:22:49 -08:00
dean
ec534769f3 chore: regenerate schema and types 2025-11-28 08:22:49 -08:00
dean
f8e8c7b7d4 merge: sync gql submodule, keeping local notification fragment 2025-11-28 08:22:49 -08:00
dean
372fd6e26b schema: add challenge notification types 2025-11-28 08:22:49 -08:00
dean
d9ef5ed79a WIP: Add challenges feature schema and operations
- Add Challenge, ChallengeEntry, ChallengeInvitation, RuleSet types
- Add queries: challenges, challenge, challengeLeaderboard, myChallengeInvitations, myChallengeEntries, ruleSets
- Add mutations: createChallenge, createRuleSet, inviteUsersToChallenge, respondToChallengeInvitation, startChallenge, submitChallengeEntry, recalculateChallengeEntry

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 08:22:49 -08:00
f14e117416 Merge pull request 'Add videoId field to playlist in ShotWithAllFeatures fragment' (#210) from loewy/add-video-id-to-playlist-shots-fragment into master
Reviewed-on: #210
2025-11-12 22:16:58 +00:00
3d86c13291 add videoId field to playlist in shot w features fragment
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2025-11-12 14:08:49 -08:00
e63f8600aa Merge pull request 'Add pocket size field to GraphQL schema and operations' (#209) from dean/add-pocket-size-clean into master
Reviewed-on: #209
2025-11-11 21:09:28 +00:00
7e822446da Merge branch 'master' into dean/add-pocket-size-clean
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2025-11-11 20:34:55 +00:00
75ecc5894b Merge pull request 'dean/add-home-feed-option' (#208) from dean/add-home-feed-option into master
Reviewed-on: #208
2025-11-10 22:09:09 +00:00
73c8dd5f57 Merge branch 'master' into dean/add-home-feed-option
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2025-11-10 19:55:16 +00:00
dean
ce8d2aaec8 Add pocket size field to GraphQL schema and operations
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2025-11-10 10:55:08 -08:00
0f89f97006 Merge pull request 'Add playlist with segment durations to ShotWithAllFeaturesFragment' (#207) from loewy/include-playlist-in-shot-features into master
Reviewed-on: #207
Reviewed-by: dean <deanwenstrand@gmail.com>
2025-11-10 18:15:41 +00:00
dean
e4223a1a17 Add isFollowedByCurrentUser field and hasFollowing to feed query
All checks were successful
Tests / Tests (pull_request) Successful in 9s
Updated GraphQL operations to support efficient follow status checking:
- Added isFollowedByCurrentUser field to UserSocialsFields fragment
- Removed nested followers array from UserSocialsFields (over-fetching)
- Simplified followUser/unfollowUser mutations to return minimal data
- Added hasFollowing field to GetVideoFeed query for feed mode detection
- Updated getUserFollowingFollowers query to include isFollowedByCurrentUser

These changes enable the mobile app to:
- Display correct follow/unfollow button states without client-side lookups
- Differentiate between "Following" and "Popular" feed modes
- Reduce payload size by removing unnecessary nested data

Backend handles efficient resolution via request-scoped caching.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 23:44:39 -08:00
dean
83b7f0d0f6 Add home feed and isFollowedByCurrentUser field
- Add home option to VideoFeedInputGQL for automatic feed selection
- Add hasFollowing field to VideoHistoryGQL response
- Add isFollowedByCurrentUser field to UserGQL to replace followers N+1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:15:39 -08:00
dean
a882f98d91 Add home option to VideoFeedInputGQL
The home feed option enables smart feed selection on the backend:
- If user has following: returns FOLLOWING feed
- If user has no following: returns ALL feed
- Always includes hasFollowing flag so frontend knows which feed it got

This allows frontend to make a single query instead of needing to
check following status separately.
2025-11-07 12:16:01 -08:00
cdf438c089 add playlist w/ segment durations in gql return
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2025-11-07 11:53:13 -08:00
7dbfadf13a Merge pull request 'Notifications Operation' (#206) from loewy/notifications-operations into master
Reviewed-on: #206
2025-11-07 00:15:28 +00:00
a74a11e789 update notif operations
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2025-11-06 16:06:32 -08:00
3b2f88c0e0 update naming of notification fragment 2025-11-06 16:06:32 -08:00
a3ac769cd4 notifications operations 2025-11-06 16:06:32 -08:00
00fc2ab44b Merge pull request 'Notifications schema' (#205) from loewy/notifications-schema into master
Reviewed-on: #205
2025-11-07 00:05:04 +00:00
58ab272289 add follow enum
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2025-11-06 15:33:41 -08:00
242afae92b notifications schema 2025-11-06 15:33:41 -08:00
6bf597a2ec Merge pull request 'add has follwer to feed query' (#204) from dean/add-has-following-to-feed into master
Reviewed-on: #204
2025-11-06 23:30:07 +00:00
5c62d45068 Merge pull request 'Add marketing opt in to schema' (#203) from loewy/add-agrees-to-marketing-schema into master
Reviewed-on: #203
2025-10-20 20:52:17 +00:00
17 changed files with 3461 additions and 255 deletions

View File

@@ -9,6 +9,7 @@ for proto in $(find ./rbproto -iname '*.proto'); do
protoc -I=./rbproto --python_out=./rbproto/python --pyi_out=./rbproto/python ./rbproto/shot.proto protoc -I=./rbproto --python_out=./rbproto/python --pyi_out=./rbproto/python ./rbproto/shot.proto
yarn pbjs ./rbproto/shot.proto --ts ./rbproto/ts/shot.ts yarn pbjs ./rbproto/shot.proto --ts ./rbproto/ts/shot.ts
done done
black rbproto/python
prettier ./rbproto --write prettier ./rbproto --write
git ls-files | xargs md5sum > after.txt git ls-files | xargs md5sum > after.txt

View File

@@ -15,7 +15,7 @@
"@apollo/client": "^3.11.10", "@apollo/client": "^3.11.10",
"@graphql-codegen/cli": "^5.0.0", "@graphql-codegen/cli": "^5.0.0",
"@graphql-codegen/typescript": "^4.0.1", "@graphql-codegen/typescript": "^4.0.1",
"@graphql-codegen/typescript-operations": "^4.0.1", "@graphql-codegen/typescript-operations": "^5.0.4",
"@graphql-codegen/typescript-react-apollo": "^4.2.0", "@graphql-codegen/typescript-react-apollo": "^4.2.0",
"graphql": "^16.8.1", "graphql": "^16.8.1",
"pbjs": "^0.0.14", "pbjs": "^0.0.14",

View File

@@ -8,7 +8,7 @@ packages = [{include = "rbproto"}]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = ">=3.10,<=3.13" python = ">=3.10,<=3.13"
protobuf = "^4.25.3" protobuf = ">=4.25.3"
[build-system] [build-system]

View File

@@ -6,44 +6,45 @@ from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports) # @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default() _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
b'\n\nshot.proto\x12\x0fserialized_shot"?\n\x03\x42ox\x12\x0c\n\x04left\x18\x01 \x01(\x02\x12\x0b\n\x03top\x18\x02 \x01(\x02\x12\r\n\x05width\x18\x03 \x01(\x02\x12\x0e\n\x06height\x18\x04 \x01(\x02"\x1d\n\x05Point\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02"\x7f\n\rBallDetection\x12.\n\x0eplane_position\x18\x01 \x01(\x0b\x32\x16.serialized_shot.Point\x12(\n\nannotation\x18\x02 \x01(\x0b\x32\x14.serialized_shot.Box\x12\x14\n\x0cinterpolated\x18\x03 \x01(\x08"T\n\x10RLEBallDetection\x12\x31\n\tdetection\x18\x01 \x01(\x0b\x32\x1e.serialized_shot.BallDetection\x12\r\n\x05\x63ount\x18\x02 \x01(\r"L\n\x13RLEDetectionHistory\x12\x35\n\ndetections\x18\x01 \x03(\x0b\x32!.serialized_shot.RLEBallDetection"F\n\x10\x44\x65tectionHistory\x12\x32\n\ndetections\x18\x01 \x03(\x0b\x32\x1e.serialized_shot.BallDetection"\xfc\x01\n\rCollisionInfo\x12\x0e\n\x06source\x18\x01 \x01(\r\x12M\n\x10\x62\x61ll_identifiers\x18\x02 \x03(\x0b\x32\x33.serialized_shot.CollisionInfo.BallIdentifiersEntry\x12\x17\n\x0fwall_identifier\x18\x03 \x01(\r\x12\x13\n\x0b\x66rame_index\x18\x04 \x01(\r\x12\x0e\n\x06static\x18\x05 \x01(\x08\x1aN\n\x14\x42\x61llIdentifiersEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12%\n\x05value\x18\x02 \x01(\x0b\x32\x16.serialized_shot.Point:\x02\x38\x01"\xcc\x02\n\x04Path\x12\x13\n\x0bstart_frame\x18\x01 \x01(\r\x12\x11\n\tend_frame\x18\x02 \x01(\r\x12\x37\n\ndetections\x18\x03 \x01(\x0b\x32!.serialized_shot.DetectionHistoryH\x00\x12>\n\x0erle_detections\x18\x04 \x01(\x0b\x32$.serialized_shot.RLEDetectionHistoryH\x00\x12\x15\n\x0bnot_present\x18\x05 \x01(\x08H\x00\x12\x11\n\tis_static\x18\x06 \x01(\x08\x12\x32\n\nstart_info\x18\x07 \x01(\x0b\x32\x1e.serialized_shot.CollisionInfo\x12\x30\n\x08\x65nd_info\x18\x08 \x01(\x0b\x32\x1e.serialized_shot.CollisionInfoB\x13\n\x11\x64\x65tection_history"R\n\x11IdentifierHistory\x12\x17\n\x0f\x62\x61ll_identifier\x18\x01 \x01(\r\x12$\n\x05paths\x18\x02 \x03(\x0b\x32\x15.serialized_shot.Path"\xf4\x01\n\x12KeyBallIdentifiers\x12\x10\n\x08\x63ue_ball\x18\x01 \x01(\r\x12\x13\n\x0bobject_ball\x18\x02 \x01(\r\x12\x13\n\x0btarget_ball\x18\x03 \x01(\r\x12\x18\n\x10\x63ontact_sequence\x18\x04 \x03(\r\x12\x18\n\x0b\x63ue_ball_id\x18\x05 \x01(\rH\x00\x88\x01\x01\x12\x1b\n\x0eobject_ball_id\x18\x06 \x01(\rH\x01\x88\x01\x01\x12\x1b\n\x0etarget_ball_id\x18\x07 \x01(\rH\x02\x88\x01\x01\x42\x0e\n\x0c_cue_ball_idB\x11\n\x0f_object_ball_idB\x11\n\x0f_target_ball_id"\xa8\x01\n\x04Shot\x12@\n\x14identifier_histories\x18\x03 \x03(\x0b\x32".serialized_shot.IdentifierHistory\x12\x36\n\tkey_balls\x18\x04 \x01(\x0b\x32#.serialized_shot.KeyBallIdentifiers\x12\x13\n\x0bstart_index\x18\x05 \x01(\r\x12\x11\n\tend_index\x18\x06 \x01(\rb\x06proto3'
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nshot.proto\x12\x0fserialized_shot\"?\n\x03\x42ox\x12\x0c\n\x04left\x18\x01 \x01(\x02\x12\x0b\n\x03top\x18\x02 \x01(\x02\x12\r\n\x05width\x18\x03 \x01(\x02\x12\x0e\n\x06height\x18\x04 \x01(\x02\"\x1d\n\x05Point\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\"\x7f\n\rBallDetection\x12.\n\x0eplane_position\x18\x01 \x01(\x0b\x32\x16.serialized_shot.Point\x12(\n\nannotation\x18\x02 \x01(\x0b\x32\x14.serialized_shot.Box\x12\x14\n\x0cinterpolated\x18\x03 \x01(\x08\"T\n\x10RLEBallDetection\x12\x31\n\tdetection\x18\x01 \x01(\x0b\x32\x1e.serialized_shot.BallDetection\x12\r\n\x05\x63ount\x18\x02 \x01(\r\"L\n\x13RLEDetectionHistory\x12\x35\n\ndetections\x18\x01 \x03(\x0b\x32!.serialized_shot.RLEBallDetection\"F\n\x10\x44\x65tectionHistory\x12\x32\n\ndetections\x18\x01 \x03(\x0b\x32\x1e.serialized_shot.BallDetection\"\xfc\x01\n\rCollisionInfo\x12\x0e\n\x06source\x18\x01 \x01(\r\x12M\n\x10\x62\x61ll_identifiers\x18\x02 \x03(\x0b\x32\x33.serialized_shot.CollisionInfo.BallIdentifiersEntry\x12\x17\n\x0fwall_identifier\x18\x03 \x01(\r\x12\x13\n\x0b\x66rame_index\x18\x04 \x01(\r\x12\x0e\n\x06static\x18\x05 \x01(\x08\x1aN\n\x14\x42\x61llIdentifiersEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12%\n\x05value\x18\x02 \x01(\x0b\x32\x16.serialized_shot.Point:\x02\x38\x01\"\xcc\x02\n\x04Path\x12\x13\n\x0bstart_frame\x18\x01 \x01(\r\x12\x11\n\tend_frame\x18\x02 \x01(\r\x12\x37\n\ndetections\x18\x03 \x01(\x0b\x32!.serialized_shot.DetectionHistoryH\x00\x12>\n\x0erle_detections\x18\x04 \x01(\x0b\x32$.serialized_shot.RLEDetectionHistoryH\x00\x12\x15\n\x0bnot_present\x18\x05 \x01(\x08H\x00\x12\x11\n\tis_static\x18\x06 \x01(\x08\x12\x32\n\nstart_info\x18\x07 \x01(\x0b\x32\x1e.serialized_shot.CollisionInfo\x12\x30\n\x08\x65nd_info\x18\x08 \x01(\x0b\x32\x1e.serialized_shot.CollisionInfoB\x13\n\x11\x64\x65tection_history\"R\n\x11IdentifierHistory\x12\x17\n\x0f\x62\x61ll_identifier\x18\x01 \x01(\r\x12$\n\x05paths\x18\x02 \x03(\x0b\x32\x15.serialized_shot.Path\"\xf4\x01\n\x12KeyBallIdentifiers\x12\x10\n\x08\x63ue_ball\x18\x01 \x01(\r\x12\x13\n\x0bobject_ball\x18\x02 \x01(\r\x12\x13\n\x0btarget_ball\x18\x03 \x01(\r\x12\x18\n\x10\x63ontact_sequence\x18\x04 \x03(\r\x12\x18\n\x0b\x63ue_ball_id\x18\x05 \x01(\rH\x00\x88\x01\x01\x12\x1b\n\x0eobject_ball_id\x18\x06 \x01(\rH\x01\x88\x01\x01\x12\x1b\n\x0etarget_ball_id\x18\x07 \x01(\rH\x02\x88\x01\x01\x42\x0e\n\x0c_cue_ball_idB\x11\n\x0f_object_ball_idB\x11\n\x0f_target_ball_id\"\xa8\x01\n\x04Shot\x12@\n\x14identifier_histories\x18\x03 \x03(\x0b\x32\".serialized_shot.IdentifierHistory\x12\x36\n\tkey_balls\x18\x04 \x01(\x0b\x32#.serialized_shot.KeyBallIdentifiers\x12\x13\n\x0bstart_index\x18\x05 \x01(\r\x12\x11\n\tend_index\x18\x06 \x01(\rb\x06proto3') )
_globals = globals() _globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'shot_pb2', _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "shot_pb2", _globals)
if _descriptor._USE_C_DESCRIPTORS == False: if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
_globals['_COLLISIONINFO_BALLIDENTIFIERSENTRY']._options = None _globals["_COLLISIONINFO_BALLIDENTIFIERSENTRY"]._options = None
_globals['_COLLISIONINFO_BALLIDENTIFIERSENTRY']._serialized_options = b'8\001' _globals["_COLLISIONINFO_BALLIDENTIFIERSENTRY"]._serialized_options = b"8\001"
_globals['_BOX']._serialized_start=31 _globals["_BOX"]._serialized_start = 31
_globals['_BOX']._serialized_end=94 _globals["_BOX"]._serialized_end = 94
_globals['_POINT']._serialized_start=96 _globals["_POINT"]._serialized_start = 96
_globals['_POINT']._serialized_end=125 _globals["_POINT"]._serialized_end = 125
_globals['_BALLDETECTION']._serialized_start=127 _globals["_BALLDETECTION"]._serialized_start = 127
_globals['_BALLDETECTION']._serialized_end=254 _globals["_BALLDETECTION"]._serialized_end = 254
_globals['_RLEBALLDETECTION']._serialized_start=256 _globals["_RLEBALLDETECTION"]._serialized_start = 256
_globals['_RLEBALLDETECTION']._serialized_end=340 _globals["_RLEBALLDETECTION"]._serialized_end = 340
_globals['_RLEDETECTIONHISTORY']._serialized_start=342 _globals["_RLEDETECTIONHISTORY"]._serialized_start = 342
_globals['_RLEDETECTIONHISTORY']._serialized_end=418 _globals["_RLEDETECTIONHISTORY"]._serialized_end = 418
_globals['_DETECTIONHISTORY']._serialized_start=420 _globals["_DETECTIONHISTORY"]._serialized_start = 420
_globals['_DETECTIONHISTORY']._serialized_end=490 _globals["_DETECTIONHISTORY"]._serialized_end = 490
_globals['_COLLISIONINFO']._serialized_start=493 _globals["_COLLISIONINFO"]._serialized_start = 493
_globals['_COLLISIONINFO']._serialized_end=745 _globals["_COLLISIONINFO"]._serialized_end = 745
_globals['_COLLISIONINFO_BALLIDENTIFIERSENTRY']._serialized_start=667 _globals["_COLLISIONINFO_BALLIDENTIFIERSENTRY"]._serialized_start = 667
_globals['_COLLISIONINFO_BALLIDENTIFIERSENTRY']._serialized_end=745 _globals["_COLLISIONINFO_BALLIDENTIFIERSENTRY"]._serialized_end = 745
_globals['_PATH']._serialized_start=748 _globals["_PATH"]._serialized_start = 748
_globals['_PATH']._serialized_end=1080 _globals["_PATH"]._serialized_end = 1080
_globals['_IDENTIFIERHISTORY']._serialized_start=1082 _globals["_IDENTIFIERHISTORY"]._serialized_start = 1082
_globals['_IDENTIFIERHISTORY']._serialized_end=1164 _globals["_IDENTIFIERHISTORY"]._serialized_end = 1164
_globals['_KEYBALLIDENTIFIERS']._serialized_start=1167 _globals["_KEYBALLIDENTIFIERS"]._serialized_start = 1167
_globals['_KEYBALLIDENTIFIERS']._serialized_end=1411 _globals["_KEYBALLIDENTIFIERS"]._serialized_end = 1411
_globals['_SHOT']._serialized_start=1414 _globals["_SHOT"]._serialized_start = 1414
_globals['_SHOT']._serialized_end=1582 _globals["_SHOT"]._serialized_end = 1582
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -1,7 +1,13 @@
from google.protobuf.internal import containers as _containers from google.protobuf.internal import containers as _containers
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union from typing import (
ClassVar as _ClassVar,
Iterable as _Iterable,
Mapping as _Mapping,
Optional as _Optional,
Union as _Union,
)
DESCRIPTOR: _descriptor.FileDescriptor DESCRIPTOR: _descriptor.FileDescriptor
@@ -15,7 +21,13 @@ class Box(_message.Message):
top: float top: float
width: float width: float
height: float height: float
def __init__(self, left: _Optional[float] = ..., top: _Optional[float] = ..., width: _Optional[float] = ..., height: _Optional[float] = ...) -> None: ... def __init__(
self,
left: _Optional[float] = ...,
top: _Optional[float] = ...,
width: _Optional[float] = ...,
height: _Optional[float] = ...,
) -> None: ...
class Point(_message.Message): class Point(_message.Message):
__slots__ = ["x", "y"] __slots__ = ["x", "y"]
@@ -23,7 +35,9 @@ class Point(_message.Message):
Y_FIELD_NUMBER: _ClassVar[int] Y_FIELD_NUMBER: _ClassVar[int]
x: float x: float
y: float y: float
def __init__(self, x: _Optional[float] = ..., y: _Optional[float] = ...) -> None: ... def __init__(
self, x: _Optional[float] = ..., y: _Optional[float] = ...
) -> None: ...
class BallDetection(_message.Message): class BallDetection(_message.Message):
__slots__ = ["plane_position", "annotation", "interpolated"] __slots__ = ["plane_position", "annotation", "interpolated"]
@@ -33,7 +47,12 @@ class BallDetection(_message.Message):
plane_position: Point plane_position: Point
annotation: Box annotation: Box
interpolated: bool interpolated: bool
def __init__(self, plane_position: _Optional[_Union[Point, _Mapping]] = ..., annotation: _Optional[_Union[Box, _Mapping]] = ..., interpolated: bool = ...) -> None: ... def __init__(
self,
plane_position: _Optional[_Union[Point, _Mapping]] = ...,
annotation: _Optional[_Union[Box, _Mapping]] = ...,
interpolated: bool = ...,
) -> None: ...
class RLEBallDetection(_message.Message): class RLEBallDetection(_message.Message):
__slots__ = ["detection", "count"] __slots__ = ["detection", "count"]
@@ -41,29 +60,49 @@ class RLEBallDetection(_message.Message):
COUNT_FIELD_NUMBER: _ClassVar[int] COUNT_FIELD_NUMBER: _ClassVar[int]
detection: BallDetection detection: BallDetection
count: int count: int
def __init__(self, detection: _Optional[_Union[BallDetection, _Mapping]] = ..., count: _Optional[int] = ...) -> None: ... def __init__(
self,
detection: _Optional[_Union[BallDetection, _Mapping]] = ...,
count: _Optional[int] = ...,
) -> None: ...
class RLEDetectionHistory(_message.Message): class RLEDetectionHistory(_message.Message):
__slots__ = ["detections"] __slots__ = ["detections"]
DETECTIONS_FIELD_NUMBER: _ClassVar[int] DETECTIONS_FIELD_NUMBER: _ClassVar[int]
detections: _containers.RepeatedCompositeFieldContainer[RLEBallDetection] detections: _containers.RepeatedCompositeFieldContainer[RLEBallDetection]
def __init__(self, detections: _Optional[_Iterable[_Union[RLEBallDetection, _Mapping]]] = ...) -> None: ... def __init__(
self, detections: _Optional[_Iterable[_Union[RLEBallDetection, _Mapping]]] = ...
) -> None: ...
class DetectionHistory(_message.Message): class DetectionHistory(_message.Message):
__slots__ = ["detections"] __slots__ = ["detections"]
DETECTIONS_FIELD_NUMBER: _ClassVar[int] DETECTIONS_FIELD_NUMBER: _ClassVar[int]
detections: _containers.RepeatedCompositeFieldContainer[BallDetection] detections: _containers.RepeatedCompositeFieldContainer[BallDetection]
def __init__(self, detections: _Optional[_Iterable[_Union[BallDetection, _Mapping]]] = ...) -> None: ... def __init__(
self, detections: _Optional[_Iterable[_Union[BallDetection, _Mapping]]] = ...
) -> None: ...
class CollisionInfo(_message.Message): class CollisionInfo(_message.Message):
__slots__ = ["source", "ball_identifiers", "wall_identifier", "frame_index", "static"] __slots__ = [
"source",
"ball_identifiers",
"wall_identifier",
"frame_index",
"static",
]
class BallIdentifiersEntry(_message.Message): class BallIdentifiersEntry(_message.Message):
__slots__ = ["key", "value"] __slots__ = ["key", "value"]
KEY_FIELD_NUMBER: _ClassVar[int] KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int] VALUE_FIELD_NUMBER: _ClassVar[int]
key: int key: int
value: Point value: Point
def __init__(self, key: _Optional[int] = ..., value: _Optional[_Union[Point, _Mapping]] = ...) -> None: ... def __init__(
self,
key: _Optional[int] = ...,
value: _Optional[_Union[Point, _Mapping]] = ...,
) -> None: ...
SOURCE_FIELD_NUMBER: _ClassVar[int] SOURCE_FIELD_NUMBER: _ClassVar[int]
BALL_IDENTIFIERS_FIELD_NUMBER: _ClassVar[int] BALL_IDENTIFIERS_FIELD_NUMBER: _ClassVar[int]
WALL_IDENTIFIER_FIELD_NUMBER: _ClassVar[int] WALL_IDENTIFIER_FIELD_NUMBER: _ClassVar[int]
@@ -74,10 +113,26 @@ class CollisionInfo(_message.Message):
wall_identifier: int wall_identifier: int
frame_index: int frame_index: int
static: bool static: bool
def __init__(self, source: _Optional[int] = ..., ball_identifiers: _Optional[_Mapping[int, Point]] = ..., wall_identifier: _Optional[int] = ..., frame_index: _Optional[int] = ..., static: bool = ...) -> None: ... def __init__(
self,
source: _Optional[int] = ...,
ball_identifiers: _Optional[_Mapping[int, Point]] = ...,
wall_identifier: _Optional[int] = ...,
frame_index: _Optional[int] = ...,
static: bool = ...,
) -> None: ...
class Path(_message.Message): class Path(_message.Message):
__slots__ = ["start_frame", "end_frame", "detections", "rle_detections", "not_present", "is_static", "start_info", "end_info"] __slots__ = [
"start_frame",
"end_frame",
"detections",
"rle_detections",
"not_present",
"is_static",
"start_info",
"end_info",
]
START_FRAME_FIELD_NUMBER: _ClassVar[int] START_FRAME_FIELD_NUMBER: _ClassVar[int]
END_FRAME_FIELD_NUMBER: _ClassVar[int] END_FRAME_FIELD_NUMBER: _ClassVar[int]
DETECTIONS_FIELD_NUMBER: _ClassVar[int] DETECTIONS_FIELD_NUMBER: _ClassVar[int]
@@ -94,7 +149,17 @@ class Path(_message.Message):
is_static: bool is_static: bool
start_info: CollisionInfo start_info: CollisionInfo
end_info: CollisionInfo end_info: CollisionInfo
def __init__(self, start_frame: _Optional[int] = ..., end_frame: _Optional[int] = ..., detections: _Optional[_Union[DetectionHistory, _Mapping]] = ..., rle_detections: _Optional[_Union[RLEDetectionHistory, _Mapping]] = ..., not_present: bool = ..., is_static: bool = ..., start_info: _Optional[_Union[CollisionInfo, _Mapping]] = ..., end_info: _Optional[_Union[CollisionInfo, _Mapping]] = ...) -> None: ... def __init__(
self,
start_frame: _Optional[int] = ...,
end_frame: _Optional[int] = ...,
detections: _Optional[_Union[DetectionHistory, _Mapping]] = ...,
rle_detections: _Optional[_Union[RLEDetectionHistory, _Mapping]] = ...,
not_present: bool = ...,
is_static: bool = ...,
start_info: _Optional[_Union[CollisionInfo, _Mapping]] = ...,
end_info: _Optional[_Union[CollisionInfo, _Mapping]] = ...,
) -> None: ...
class IdentifierHistory(_message.Message): class IdentifierHistory(_message.Message):
__slots__ = ["ball_identifier", "paths"] __slots__ = ["ball_identifier", "paths"]
@@ -102,10 +167,22 @@ class IdentifierHistory(_message.Message):
PATHS_FIELD_NUMBER: _ClassVar[int] PATHS_FIELD_NUMBER: _ClassVar[int]
ball_identifier: int ball_identifier: int
paths: _containers.RepeatedCompositeFieldContainer[Path] paths: _containers.RepeatedCompositeFieldContainer[Path]
def __init__(self, ball_identifier: _Optional[int] = ..., paths: _Optional[_Iterable[_Union[Path, _Mapping]]] = ...) -> None: ... def __init__(
self,
ball_identifier: _Optional[int] = ...,
paths: _Optional[_Iterable[_Union[Path, _Mapping]]] = ...,
) -> None: ...
class KeyBallIdentifiers(_message.Message): class KeyBallIdentifiers(_message.Message):
__slots__ = ["cue_ball", "object_ball", "target_ball", "contact_sequence", "cue_ball_id", "object_ball_id", "target_ball_id"] __slots__ = [
"cue_ball",
"object_ball",
"target_ball",
"contact_sequence",
"cue_ball_id",
"object_ball_id",
"target_ball_id",
]
CUE_BALL_FIELD_NUMBER: _ClassVar[int] CUE_BALL_FIELD_NUMBER: _ClassVar[int]
OBJECT_BALL_FIELD_NUMBER: _ClassVar[int] OBJECT_BALL_FIELD_NUMBER: _ClassVar[int]
TARGET_BALL_FIELD_NUMBER: _ClassVar[int] TARGET_BALL_FIELD_NUMBER: _ClassVar[int]
@@ -120,7 +197,16 @@ class KeyBallIdentifiers(_message.Message):
cue_ball_id: int cue_ball_id: int
object_ball_id: int object_ball_id: int
target_ball_id: int target_ball_id: int
def __init__(self, cue_ball: _Optional[int] = ..., object_ball: _Optional[int] = ..., target_ball: _Optional[int] = ..., contact_sequence: _Optional[_Iterable[int]] = ..., cue_ball_id: _Optional[int] = ..., object_ball_id: _Optional[int] = ..., target_ball_id: _Optional[int] = ...) -> None: ... def __init__(
self,
cue_ball: _Optional[int] = ...,
object_ball: _Optional[int] = ...,
target_ball: _Optional[int] = ...,
contact_sequence: _Optional[_Iterable[int]] = ...,
cue_ball_id: _Optional[int] = ...,
object_ball_id: _Optional[int] = ...,
target_ball_id: _Optional[int] = ...,
) -> None: ...
class Shot(_message.Message): class Shot(_message.Message):
__slots__ = ["identifier_histories", "key_balls", "start_index", "end_index"] __slots__ = ["identifier_histories", "key_balls", "start_index", "end_index"]
@@ -132,4 +218,12 @@ class Shot(_message.Message):
key_balls: KeyBallIdentifiers key_balls: KeyBallIdentifiers
start_index: int start_index: int
end_index: int end_index: int
def __init__(self, identifier_histories: _Optional[_Iterable[_Union[IdentifierHistory, _Mapping]]] = ..., key_balls: _Optional[_Union[KeyBallIdentifiers, _Mapping]] = ..., start_index: _Optional[int] = ..., end_index: _Optional[int] = ...) -> None: ... def __init__(
self,
identifier_histories: _Optional[
_Iterable[_Union[IdentifierHistory, _Mapping]]
] = ...,
key_balls: _Optional[_Union[KeyBallIdentifiers, _Mapping]] = ...,
start_index: _Optional[int] = ...,
end_index: _Optional[int] = ...,
) -> None: ...

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ query GetAggregatedShotMetrics($aggregateInput: AggregateInputGQL!) {
targetMetrics { targetMetrics {
count count
makePercentage makePercentage
averageDifficulty
} }
} }
} }

View File

@@ -0,0 +1,282 @@
query GetChallenges {
challenges {
id
name
description
minimumShots
startDate
endDate
createdAt
updatedAt
requiredTableSize
requiredPocketSize
isPublic
maxAttempts
ruleSet {
id
name
description
}
createdBy {
id
username
profileImageUri
}
}
}
query GetMyDismissedChallenges {
myDismissedChallenges {
id
name
description
minimumShots
startDate
endDate
createdAt
updatedAt
requiredTableSize
requiredPocketSize
isPublic
maxAttempts
ruleSet {
id
name
description
}
createdBy {
id
username
profileImageUri
}
}
}
query GetChallenge($id: ID!) {
challenge(id: $id) {
id
name
description
minimumShots
startDate
endDate
createdAt
updatedAt
requiredTableSize
requiredPocketSize
isPublic
maxAttempts
participantCount
ruleSet {
id
name
description
}
createdBy {
id
username
profileImageUri
}
invitations {
id
status
createdAt
invitee {
id
username
profileImageUri
}
inviter {
id
username
profileImageUri
}
}
}
}
query GetRuleSets {
ruleSets {
id
name
description
}
}
query GetChallengeLeaderboard($challengeId: ID!, $limit: Int) {
challengeLeaderboard(challengeId: $challengeId, limit: $limit) {
id
status
shotsCount
makesCount
makeRate
qualified
createdAt
attemptCount
user {
id
username
profileImageUri
}
video {
id
createdAt
}
}
}
query GetMyChallengeInvitations {
myChallengeInvitations {
id
status
createdAt
challenge {
id
name
description
startDate
endDate
createdBy {
id
username
profileImageUri
}
}
inviter {
id
username
profileImageUri
}
}
}
query GetMyChallengeEntries {
myChallengeEntries {
id
status
shotsCount
makesCount
makeRate
qualified
createdAt
challenge {
id
name
}
video {
id
}
}
}
mutation CreateRuleSet($name: String!, $description: String) {
createRuleSet(name: $name, description: $description) {
id
name
description
}
}
mutation CreateChallenge(
$name: String!
$ruleSetId: ID!
$minimumShots: Int!
$startDate: DateTime!
$endDate: DateTime!
$description: String
$requiredTableSize: Float
$requiredPocketSize: Float
$isPublic: Boolean! = false
$maxAttempts: Int
) {
createChallenge(
name: $name
ruleSetId: $ruleSetId
minimumShots: $minimumShots
startDate: $startDate
endDate: $endDate
description: $description
requiredTableSize: $requiredTableSize
requiredPocketSize: $requiredPocketSize
isPublic: $isPublic
maxAttempts: $maxAttempts
) {
id
name
description
requiredTableSize
requiredPocketSize
isPublic
maxAttempts
}
}
mutation InviteUsersToChallenge($challengeId: ID!, $userIds: [ID!]!) {
inviteUsersToChallenge(challengeId: $challengeId, userIds: $userIds) {
id
status
inviter {
id
username
}
}
}
mutation RespondToChallengeInvitation($invitationId: ID!, $accept: Boolean!) {
respondToChallengeInvitation(invitationId: $invitationId, accept: $accept) {
id
status
challenge {
id
}
}
}
mutation StartChallenge($challengeId: ID!) {
startChallenge(challengeId: $challengeId) {
id
status
createdAt
challenge {
id
name
}
}
}
mutation SubmitChallengeEntry($entryId: ID!, $videoId: ID!) {
submitChallengeEntry(entryId: $entryId, videoId: $videoId) {
id
status
qualified
makeRate
shotsCount
makesCount
video {
id
}
}
}
mutation RecalculateChallengeEntry($entryId: ID!) {
recalculateChallengeEntry(entryId: $entryId) {
id
status
qualified
makeRate
shotsCount
makesCount
}
}
query IsChallengeDismissed($challengeId: ID!) {
isChallengeDismissed(challengeId: $challengeId)
}
mutation DismissChallenge($challengeId: ID!) {
dismissChallenge(challengeId: $challengeId)
}
mutation UndismissChallenge($challengeId: ID!) {
undismissChallenge(challengeId: $challengeId)
}

View File

@@ -14,5 +14,6 @@ query getDeployedConfig {
message message
priority priority
} }
defaultAndroidRecordingFormat
} }
} }

View File

@@ -19,11 +19,7 @@ fragment UserSocialsFields on UserGQL {
id id
username username
profileImageUri profileImageUri
followers { isFollowedByCurrentUser
id
username
profileImageUri
}
} }
fragment VideoCardFields on VideoGQL { fragment VideoCardFields on VideoGQL {
@@ -54,6 +50,7 @@ fragment VideoCardFields on VideoGQL {
streamSegmentType streamSegmentType
} }
tableSize tableSize
pocketSize
tags { tags {
tagClasses { tagClasses {
name name
@@ -116,5 +113,6 @@ query GetVideoFeed(
hasNextPage hasNextPage
endCursor endCursor
} }
hasFollowing
} }
} }

View File

@@ -0,0 +1,63 @@
query GetNotifications(
$limit: Int! = 20
$offset: Int! = 0
$filters: NotificationFilters = null
) {
notifications(limit: $limit, offset: $offset, filters: $filters) {
notifications {
...Notification
}
totalCount
unreadCount
hasMore
}
}
query GetUnreadNotificationCount {
unreadNotificationCount
}
mutation MarkNotificationAsRead($notificationId: Int!) {
markNotificationAsRead(notificationId: $notificationId)
}
mutation MarkNotificationsAsRead($notificationIds: [Int!]!) {
markNotificationsAsRead(notificationIds: $notificationIds)
}
mutation MarkAllNotificationsAsRead {
markAllNotificationsAsRead
}
mutation DeleteNotification($notificationId: Int!) {
deleteNotification(notificationId: $notificationId)
}
fragment Notification on NotificationGQL {
id
notificationType
actor {
id
username
profileImageUri
}
videoId
challengeId
challenge {
id
name
}
comment {
id
message
user {
id
username
profileImageUri
}
}
reactionType
isRead
createdAt
readAt
}

View File

@@ -63,3 +63,14 @@ mutation CancelSubscription {
stripeSubscriptionId stripeSubscriptionId
} }
} }
mutation SubmitCancellationFeedback(
$reasons: [CancellationReasonEnum!]
$feedback: String
$metadata: CancellationFeedbackMetadataInput
) {
submitCancellationFeedback(
reasons: $reasons
feedback: $feedback
metadata: $metadata
)
}

View File

@@ -191,6 +191,10 @@ fragment ShotWithAllFeatures on ShotGQL {
id id
streamSegmentType streamSegmentType
} }
playlist {
videoId
segmentDurations
}
} }
} }

View File

@@ -34,6 +34,12 @@ query getLoggedInUser {
query GetUser($userId: Int!) { query GetUser($userId: Int!) {
getUser(userId: $userId) { getUser(userId: $userId) {
...UserFragment ...UserFragment
following {
id
}
followers {
id
}
} }
} }
@@ -88,31 +94,15 @@ query GetUserTags {
mutation followUser($followedUserId: Int!) { mutation followUser($followedUserId: Int!) {
followUser(followedUserId: $followedUserId) { followUser(followedUserId: $followedUserId) {
username
id id
following { username
id
username
}
followers {
id
username
}
} }
} }
mutation unfollowUser($followedUserId: Int!) { mutation unfollowUser($followedUserId: Int!) {
unfollowUser(followedUserId: $followedUserId) { unfollowUser(followedUserId: $followedUserId) {
username
id id
following { username
id
username
}
followers {
id
username
}
} }
} }
@@ -123,11 +113,13 @@ query getUserFollowingFollowers {
id id
username username
profileImageUri profileImageUri
isFollowedByCurrentUser
} }
followers { followers {
id id
username username
profileImageUri profileImageUri
isFollowedByCurrentUser
} }
} }
} }
@@ -177,3 +169,13 @@ fragment UserFragment on UserGQL {
videosPrivateByDefault videosPrivateByDefault
agreesToMarketing agreesToMarketing
} }
query GetUsersMatching(
$matchString: String = null
$limit: Int = null
$after: String = null
) {
getUsersMatching(matchString: $matchString, limit: $limit, after: $after) {
...UserFragment
}
}

View File

@@ -36,6 +36,7 @@ query GetVideoUpdatePageDetails($videoId: Int!) {
makePercentage makePercentage
elapsedTime elapsedTime
tableSize tableSize
pocketSize
private private
tags { tags {
tagClasses { tagClasses {
@@ -60,12 +61,14 @@ query GetVideoDetails($videoId: Int!) {
endTime endTime
makePercentage makePercentage
medianRun medianRun
averageDifficulty
startTime startTime
totalShots totalShots
totalShotsMade totalShotsMade
createdAt createdAt
updatedAt updatedAt
tableSize tableSize
pocketSize
private private
owner { owner {
id id
@@ -86,17 +89,16 @@ fragment UserSocialsFields on UserGQL {
id id
username username
profileImageUri profileImageUri
followers { isFollowedByCurrentUser
id
username
profileImageUri
}
} }
query GetVideoSocialDetailsById($videoId: Int!) { query GetVideoSocialDetailsById($videoId: Int!) {
getVideo(videoId: $videoId) { getVideo(videoId: $videoId) {
id id
name name
screenshotUri
makePercentage
totalShots
owner { owner {
id id
firebaseUid firebaseUid
@@ -210,6 +212,13 @@ query GetMedianRunForVideo($videoId: Int!) {
} }
} }
query GetAverageDifficultyForVideo($videoId: Int!) {
getVideo(videoId: $videoId) {
id
averageDifficulty
}
}
fragment StreamWithEndFrames on UploadStreamGQL { fragment StreamWithEndFrames on UploadStreamGQL {
id id
streamSegmentType streamSegmentType

View File

@@ -3,6 +3,14 @@ type Query {
aggregateInput: AggregateInputGQL! aggregateInput: AggregateInputGQL!
): [AggregateResultGQL!]! ): [AggregateResultGQL!]!
getBucketSet(keyName: String!): BucketSetGQL getBucketSet(keyName: String!): BucketSetGQL
challenges(includeDismissed: Boolean! = false): [Challenge!]!
myDismissedChallenges: [Challenge!]!
isChallengeDismissed(challengeId: ID!): Boolean!
challenge(id: ID!): Challenge
challengeLeaderboard(challengeId: ID!, limit: Int! = 50): [ChallengeEntry!]!
myChallengeInvitations: [ChallengeInvitation!]!
ruleSets: [RuleSet!]!
myChallengeEntries: [ChallengeEntry!]!
getDeployedConfig: DeployedConfigGQL! getDeployedConfig: DeployedConfigGQL!
waitFor(duration: Float!): Float! waitFor(duration: Float!): Float!
getFeedVideos( getFeedVideos(
@@ -28,6 +36,12 @@ type Query {
when: DateTime = null when: DateTime = null
): CountLeaderboardGQL! ): CountLeaderboardGQL!
getMedals(scope: MedalScope!, userId: Int = null): RequestedMedalsGQL! getMedals(scope: MedalScope!, userId: Int = null): RequestedMedalsGQL!
notifications(
limit: Int! = 20
offset: Int! = 0
filters: NotificationFilters = null
): NotificationConnection!
unreadNotificationCount: Int!
getRuns( getRuns(
filterInput: RunFilterInput! filterInput: RunFilterInput!
runIds: [Int!] = null runIds: [Int!] = null
@@ -292,35 +306,72 @@ type BucketGQL {
lowerBound: Float! lowerBound: Float!
} }
type DeployedConfigGQL { type Challenge {
allowNewUsers: Boolean! id: ID!
firebase: Boolean! name: String!
devMode: Boolean! description: String
environment: String! minimumShots: Int!
minimumAllowedAppVersion: String! requiredTableSize: Float
subscriptionGatingEnabled: Boolean! requiredPocketSize: Float
bannerMessages: [BannerGQL!]! isPublic: Boolean!
maxAttempts: Int
startDate: DateTime!
endDate: DateTime!
createdAt: DateTime!
updatedAt: DateTime!
ruleSet: RuleSet!
createdBy: UserGQL!
invitations: [ChallengeInvitation!]!
participantCount: Int!
} }
type BannerGQL { type RuleSet {
id: ID!
name: String!
description: String
createdAt: DateTime!
updatedAt: DateTime!
}
type UserGQL {
id: Int! id: Int!
message: String! firebaseUid: String
color: String! username: String!
kind: BannerKindEnum! isAdmin: Boolean
dismissible: Boolean! fargoRating: Int
priority: Int! activeVideoId: Int
stripeCustomerId: String
profileImageUri: String
createdAt: DateTime
updatedAt: DateTime
videosPrivateByDefault: Boolean
agreesToMarketing: Boolean
following: [UserGQL!]
followers: [UserGQL!]
isFollowedByCurrentUser: Boolean
} }
enum BannerKindEnum { type ChallengeInvitation {
INFO id: ID!
WARNING status: String!
ERROR createdAt: DateTime!
challenge: Challenge!
inviter: UserGQL!
invitee: UserGQL!
} }
type VideoHistoryGQL { type ChallengeEntry {
videos: [VideoGQL!]! id: ID!
pageInfo: PageInfoGQL! status: String!
hasFollowing: Boolean! shotsCount: Int
makesCount: Int
makeRate: Float
qualified: Boolean
createdAt: DateTime!
attemptCount: Int
challenge: Challenge!
video: VideoGQL
user: UserGQL!
} }
type VideoGQL { type VideoGQL {
@@ -342,6 +393,7 @@ type VideoGQL {
elapsedTime: Float elapsedTime: Float
framesPerSecond: Float! framesPerSecond: Float!
tableSize: Float! tableSize: Float!
pocketSize: Float
private: Boolean! private: Boolean!
stream: UploadStreamGQL stream: UploadStreamGQL
playlist: HLSPlaylistGQL playlist: HLSPlaylistGQL
@@ -353,23 +405,6 @@ type VideoGQL {
comments: [CommentGQL!]! comments: [CommentGQL!]!
} }
type UserGQL {
id: Int!
firebaseUid: String
username: String!
isAdmin: Boolean
fargoRating: Int
activeVideoId: Int
stripeCustomerId: String
profileImageUri: String
createdAt: DateTime
updatedAt: DateTime
videosPrivateByDefault: Boolean
agreesToMarketing: Boolean
following: [UserGQL!]
followers: [UserGQL!]
}
type ShotGQL { type ShotGQL {
id: Int! id: Int!
videoId: Int! videoId: Int!
@@ -625,6 +660,38 @@ type CommentGQL {
replies: [CommentGQL!]! replies: [CommentGQL!]!
} }
type DeployedConfigGQL {
allowNewUsers: Boolean!
firebase: Boolean!
devMode: Boolean!
environment: String!
minimumAllowedAppVersion: String!
subscriptionGatingEnabled: Boolean!
bannerMessages: [BannerGQL!]!
defaultAndroidRecordingFormat: StreamSegmentTypeEnum!
}
type BannerGQL {
id: Int!
message: String!
color: String!
kind: BannerKindEnum!
dismissible: Boolean!
priority: Int!
}
enum BannerKindEnum {
INFO
WARNING
ERROR
}
type VideoHistoryGQL {
videos: [VideoGQL!]!
pageInfo: PageInfoGQL!
hasFollowing: Boolean!
}
type PageInfoGQL { type PageInfoGQL {
hasNextPage: Boolean! hasNextPage: Boolean!
endCursor: String endCursor: String
@@ -647,6 +714,7 @@ input VideoFeedInputGQL @oneOf {
followedByUserId: Int followedByUserId: Int
userId: Int userId: Int
allUsers: Boolean allUsers: Boolean
home: Boolean
} }
type MakePercentageIntervalGQL { type MakePercentageIntervalGQL {
@@ -715,6 +783,40 @@ input MedalScope @oneOf {
datetimeRange: DatetimeRangeAggregationInput datetimeRange: DatetimeRangeAggregationInput
} }
type NotificationConnection {
notifications: [NotificationGQL!]!
totalCount: Int!
unreadCount: Int!
hasMore: Boolean!
}
type NotificationGQL {
id: Int!
notificationType: NotificationTypeEnum!
actor: UserGQL!
videoId: Int
challengeId: Int
challenge: Challenge
comment: CommentGQL
reactionType: String
isRead: Boolean!
createdAt: DateTime!
readAt: DateTime
}
enum NotificationTypeEnum {
COMMENT
COMMENT_REPLY
REACTION
FOLLOW
CHALLENGE_INVITE
}
input NotificationFilters {
isRead: Boolean = null
notificationTypes: [NotificationTypeEnum!] = null
}
type GetRunsResult { type GetRunsResult {
runs: [RunGQL!]! runs: [RunGQL!]!
count: Int count: Int
@@ -900,6 +1002,32 @@ scalar JSON
type Mutation { type Mutation {
createBucketSet(params: CreateBucketSetInput!): BucketSetGQL! createBucketSet(params: CreateBucketSetInput!): BucketSetGQL!
createRuleSet(name: String!, description: String = null): RuleSet!
createChallenge(
name: String!
ruleSetId: ID!
minimumShots: Int!
startDate: DateTime!
endDate: DateTime!
description: String = null
requiredTableSize: Float = null
requiredPocketSize: Float = null
isPublic: Boolean! = false
maxAttempts: Int = null
): Challenge!
inviteUsersToChallenge(
challengeId: ID!
userIds: [ID!]!
): [ChallengeInvitation!]!
respondToChallengeInvitation(
invitationId: ID!
accept: Boolean!
): ChallengeInvitation!
startChallenge(challengeId: ID!): ChallengeEntry!
recalculateChallengeEntry(entryId: ID!): ChallengeEntry!
submitChallengeEntry(entryId: ID!, videoId: ID!): ChallengeEntry!
dismissChallenge(challengeId: ID!): Boolean!
undismissChallenge(challengeId: ID!): Boolean!
setLoggerLevel(path: String!, level: String!): Boolean! setLoggerLevel(path: String!, level: String!): Boolean!
reactToVideo(videoId: Int!, reaction: ReactionEnum): Boolean! reactToVideo(videoId: Int!, reaction: ReactionEnum): Boolean!
commentOnVideo( commentOnVideo(
@@ -916,6 +1044,10 @@ type Mutation {
reason: ReportReasonEnum! reason: ReportReasonEnum!
customReason: String = null customReason: String = null
): Boolean! ): Boolean!
markNotificationAsRead(notificationId: Int!): Boolean!
markAllNotificationsAsRead: Boolean!
markNotificationsAsRead(notificationIds: [Int!]!): Boolean!
deleteNotification(notificationId: Int!): Boolean!
addAnnotationToShot( addAnnotationToShot(
shotId: Int! shotId: Int!
annotationName: String! annotationName: String!
@@ -941,6 +1073,11 @@ type Mutation {
deleteUser: Boolean! deleteUser: Boolean!
createSubscription(priceId: String!): CreateSubscriptionResultGQL! createSubscription(priceId: String!): CreateSubscriptionResultGQL!
cancelSubscription: UserSubscriptionStatusGQL! cancelSubscription: UserSubscriptionStatusGQL!
submitCancellationFeedback(
reasons: [CancellationReasonEnum!] = null
feedback: String = null
metadata: CancellationFeedbackMetadataInput = null
): Boolean!
findPrerecordTableLayout(b64Image: String!, videoId: Int!): HomographyInfoGQL findPrerecordTableLayout(b64Image: String!, videoId: Int!): HomographyInfoGQL
createUploadStream( createUploadStream(
videoMetadata: VideoMetadataInput! videoMetadata: VideoMetadataInput!
@@ -1065,6 +1202,21 @@ type CreateSubscriptionResultGQL {
sessionId: String! sessionId: String!
} }
enum CancellationReasonEnum {
DONT_PLAY_ENOUGH
TOO_EXPENSIVE
MISSING_FEATURES
TECHNICAL_ISSUES
DATA_NOT_ACCURATE
OTHER
}
input CancellationFeedbackMetadataInput {
appVersion: String = null
gitRevision: String = null
platform: String = null
}
type CreateUploadStreamReturn { type CreateUploadStreamReturn {
videoId: Int! videoId: Int!
} }
@@ -1081,6 +1233,7 @@ input VideoMetadataInput {
""" """
tags: [VideoTagInput!] = null tags: [VideoTagInput!] = null
tableSize: Float = null tableSize: Float = null
pocketSize: Float = null
lastIntendedSegmentBound: Int = null lastIntendedSegmentBound: Int = null
streamSegmentType: StreamSegmentTypeEnum = null streamSegmentType: StreamSegmentTypeEnum = null
private: Boolean = null private: Boolean = null

View File

@@ -603,6 +603,18 @@
lodash "~4.17.0" lodash "~4.17.0"
tslib "~2.5.0" tslib "~2.5.0"
"@graphql-codegen/plugin-helpers@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-6.0.0.tgz#8a913c82a95b9ff36b2180f7c56611cc56268625"
integrity sha512-Z7P89vViJvQakRyMbq/JF2iPLruRFOwOB6IXsuSvV/BptuuEd7fsGPuEf8bdjjDxUY0pJZnFN8oC7jIQ8p9GKA==
dependencies:
"@graphql-tools/utils" "^10.0.0"
change-case-all "1.0.15"
common-tags "1.8.2"
import-from "4.0.0"
lodash "~4.17.0"
tslib "~2.6.0"
"@graphql-codegen/schema-ast@^4.0.0": "@graphql-codegen/schema-ast@^4.0.0":
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-4.0.0.tgz#5d60996c87b64f81847da8fcb2d8ef50ede89755" resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-4.0.0.tgz#5d60996c87b64f81847da8fcb2d8ef50ede89755"
@@ -612,16 +624,25 @@
"@graphql-tools/utils" "^10.0.0" "@graphql-tools/utils" "^10.0.0"
tslib "~2.5.0" tslib "~2.5.0"
"@graphql-codegen/typescript-operations@^4.0.1": "@graphql-codegen/schema-ast@^5.0.0":
version "4.0.1" version "5.0.0"
resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-4.0.1.tgz#930af3e2d2ae8ff06de696291be28fe7046a2fef" resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-5.0.0.tgz#9708d7484a01bb3a502685126708d7b139fd0721"
integrity sha512-GpUWWdBVUec/Zqo23aFLBMrXYxN2irypHqDcKjN78JclDPdreasAEPcIpMfqf4MClvpmvDLy4ql+djVAwmkjbw== integrity sha512-jn7Q3PKQc0FxXjbpo9trxzlz/GSFQWxL042l0iC8iSbM/Ar+M7uyBwMtXPsev/3Razk+osQyreghIz0d2+6F7Q==
dependencies: dependencies:
"@graphql-codegen/plugin-helpers" "^5.0.0" "@graphql-codegen/plugin-helpers" "^6.0.0"
"@graphql-codegen/typescript" "^4.0.1" "@graphql-tools/utils" "^10.0.0"
"@graphql-codegen/visitor-plugin-common" "4.0.1" tslib "~2.6.0"
"@graphql-codegen/typescript-operations@^5.0.4":
version "5.0.4"
resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-5.0.4.tgz#052680d41f4bab3bb85af8e906c43bde29239e7b"
integrity sha512-5Bu/BTmyNjdSfSLLBKjC0+4XWcY01uotVcnVIWIxxRdIHoRxnTW6PUkT5CoPHP5r/Uoo3OvIJxh+0LYSH5suwA==
dependencies:
"@graphql-codegen/plugin-helpers" "^6.0.0"
"@graphql-codegen/typescript" "^5.0.4"
"@graphql-codegen/visitor-plugin-common" "6.1.2"
auto-bind "~4.0.0" auto-bind "~4.0.0"
tslib "~2.5.0" tslib "~2.6.0"
"@graphql-codegen/typescript-react-apollo@^4.2.0": "@graphql-codegen/typescript-react-apollo@^4.2.0":
version "4.2.0" version "4.2.0"
@@ -645,6 +666,17 @@
auto-bind "~4.0.0" auto-bind "~4.0.0"
tslib "~2.5.0" tslib "~2.5.0"
"@graphql-codegen/typescript@^5.0.4":
version "5.0.4"
resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript/-/typescript-5.0.4.tgz#a7f51505445568fd737b01ce7fad515c2b89897f"
integrity sha512-q6S8hX+aR4BzeGgolac4gp22rBnXbLhedmOwT1UBT9e3lGNmNpYC7WJUEzAPjWf6z1lRSNmojLlwEjTnffhKNA==
dependencies:
"@graphql-codegen/plugin-helpers" "^6.0.0"
"@graphql-codegen/schema-ast" "^5.0.0"
"@graphql-codegen/visitor-plugin-common" "6.1.2"
auto-bind "~4.0.0"
tslib "~2.6.0"
"@graphql-codegen/visitor-plugin-common@2.13.1": "@graphql-codegen/visitor-plugin-common@2.13.1":
version "2.13.1" version "2.13.1"
resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.13.1.tgz#2228660f6692bcdb96b1f6d91a0661624266b76b" resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.13.1.tgz#2228660f6692bcdb96b1f6d91a0661624266b76b"
@@ -677,6 +709,22 @@
parse-filepath "^1.0.2" parse-filepath "^1.0.2"
tslib "~2.5.0" tslib "~2.5.0"
"@graphql-codegen/visitor-plugin-common@6.1.2":
version "6.1.2"
resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.1.2.tgz#e614d6606402a152686d6f90e6363150a7a55bde"
integrity sha512-zYdrhJKgk8kqE1Xz5/m/Ua42zk+rIvYB/FHh3dE1AhZ6b1IDqgKjF3LnkT+K2qenf9EfT4yNjXd5CEKMeXfHyg==
dependencies:
"@graphql-codegen/plugin-helpers" "^6.0.0"
"@graphql-tools/optimize" "^2.0.0"
"@graphql-tools/relay-operation-optimizer" "^7.0.0"
"@graphql-tools/utils" "^10.0.0"
auto-bind "~4.0.0"
change-case-all "1.0.15"
dependency-graph "^1.0.0"
graphql-tag "^2.11.0"
parse-filepath "^1.0.2"
tslib "~2.6.0"
"@graphql-tools/apollo-engine-loader@^8.0.0": "@graphql-tools/apollo-engine-loader@^8.0.0":
version "8.0.0" version "8.0.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.0.tgz#ac1f351cbe41508411784f25757f5557b0f27489" resolved "https://registry.yarnpkg.com/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.0.tgz#ac1f351cbe41508411784f25757f5557b0f27489"
@@ -1649,6 +1697,11 @@ dependency-graph@^0.11.0:
resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27"
integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==
dependency-graph@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-1.0.0.tgz#bb5e85aec1310bc13b22dbd76e3196c4ee4c10d2"
integrity sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==
detect-indent@^6.0.0: detect-indent@^6.0.0:
version "6.1.0" version "6.1.0"
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6"