Demo using Slices Network GraphQL Relay API to make a teal.fm client

Compare changes

Choose any two refs to compare.

+3 -3
README.md
··· 39 39 2. **Fetch the GraphQL schema** 40 40 41 41 ```bash 42 - npm run schema 42 + npm run schema:prod 43 43 ``` 44 44 45 45 3. **Generate Relay types** ··· 63 63 The project connects to the Slices API. To update the schema: 64 64 65 65 ```bash 66 - npm run schema 66 + npm run schema:prod 67 67 npx relay-compiler 68 68 ``` 69 69 ··· 109 109 - `npm run build` - Build for production 110 110 - `npm run preview` - Preview production build 111 111 - `npm run lint` - Run ESLint 112 - - `npm run schema` - Fetch GraphQL schema from production API 112 + - `npm run schema:prod` - Fetch GraphQL schema from production API 113 113 114 114 ## Features in Detail 115 115
+2 -2
package.json
··· 8 8 "build": "tsc -b && vite build", 9 9 "lint": "eslint .", 10 10 "preview": "vite preview", 11 - "schema:dev": "npx get-graphql-schema 'http://localhost:3000/graphql?slice=at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/network.slices.slice/3m257yljpbg2a' > schema.graphql", 12 - "schema:prod": "npx get-graphql-schema 'https://api.slices.network/graphql?slice=at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/network.slices.slice/3m257yljpbg2a' > schema.graphql" 11 + "schema:dev": "npx get-graphql-schema 'http://localhost:8080/graphql' > schema.graphql", 12 + "schema:prod": "npx get-graphql-schema 'https://quickslice-production-d668.up.railway.app/graphql' > schema.graphql" 13 13 }, 14 14 "dependencies": { 15 15 "graphql-ws": "^6.0.6",
+836 -790
schema.graphql
··· 1 - """ 2 - Indicates that an Input Object is a OneOf Input Object (and thus requires exactly one of its field be provided) 3 - """ 4 - directive @oneOf on INPUT_OBJECT 5 - 6 - """ 7 - Provides a scalar specification URL for specifying the behavior of custom scalar types. 8 - """ 9 - directive @specifiedBy( 10 - """URL that specifies the behavior of this scalar.""" 11 - url: String! 12 - ) on SCALAR 13 - 1 + """Order aggregation results by count""" 14 2 input AggregationOrderBy { 3 + """Order by count (asc or desc)""" 15 4 count: SortDirection 16 5 } 17 6 7 + """Record type: app.bsky.actor.profile""" 18 8 type AppBskyActorProfile { 19 - uri: String! 20 - cid: String! 21 - did: String! 22 - indexedAt: String! 9 + """Record URI""" 10 + uri: String 11 + 12 + """Record CID""" 13 + cid: String 14 + 15 + """DID of record author""" 16 + did: String 17 + 18 + """Collection name""" 19 + collection: String 20 + 21 + """When record was indexed""" 22 + indexedAt: String 23 + 24 + """Handle of the actor who created this record""" 23 25 actorHandle: String 26 + 27 + """Field from lexicon""" 24 28 avatar: Blob 29 + 30 + """Field from lexicon""" 25 31 banner: Blob 32 + 33 + """Field from lexicon""" 26 34 createdAt: String 35 + 36 + """Field from lexicon""" 27 37 description: String 38 + 39 + """Field from lexicon""" 28 40 displayName: String 29 - joinedViaStarterPack: JSON 30 - labels: JSON 31 - pinnedPost: JSON 32 - appBskyActorProfile: AppBskyActorProfile 33 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 34 - appBskyFeedPostgatesCount: Int! 35 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 36 - appBskyFeedThreadgatesCount: Int! 37 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 38 - appBskyActorProfilesCount: Int! 39 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 40 - fmTealAlphaFeedPlaysCount: Int! 41 + 42 + """Field from lexicon""" 43 + joinedViaStarterPack: String 44 + 45 + """Field from lexicon""" 46 + labels: String 47 + 48 + """Field from lexicon""" 49 + pinnedPost: String 50 + 51 + """Field from lexicon""" 52 + pronouns: String 53 + 54 + """Field from lexicon""" 55 + website: String 56 + 57 + """Forward join to referenced record""" 58 + pinnedPostResolved: Record 59 + 60 + """Forward join to referenced record""" 61 + joinedViaStarterPackResolved: Record 62 + 63 + """ 64 + DID join: records in fm.teal.alpha.feed.play that share the same DID as this record 65 + """ 66 + fmTealAlphaFeedPlayByDid( 67 + """Returns the first n items from the list""" 68 + first: Int 69 + 70 + """Returns items after the given cursor""" 71 + after: String 72 + 73 + """Returns the last n items from the list""" 74 + last: Int 75 + 76 + """Returns items before the given cursor""" 77 + before: String 78 + 79 + """Sort order for the connection""" 80 + sortBy: [FmTealAlphaFeedPlaySortFieldInput!] 81 + 82 + """Filter conditions for the query""" 83 + where: FmTealAlphaFeedPlayWhereInput 84 + ): FmTealAlphaFeedPlayConnection 41 85 } 42 86 87 + """Aggregated results for app.bsky.actor.profile""" 43 88 type AppBskyActorProfileAggregated { 44 - avatar: JSON 45 - banner: JSON 46 - createdAt: JSON 47 - description: JSON 48 - displayName: JSON 49 - joinedViaStarterPack: JSON 50 - labels: JSON 51 - pinnedPost: JSON 89 + """Grouped field value""" 90 + uri: String 91 + 92 + """Grouped field value""" 93 + cid: String 94 + 95 + """Grouped field value""" 96 + did: String 97 + 98 + """Grouped field value""" 99 + collection: String 100 + 101 + """Grouped field value""" 102 + indexed_at: String 103 + 104 + """Grouped field value""" 105 + avatar: String 106 + 107 + """Grouped field value""" 108 + banner: String 109 + 110 + """Grouped field value""" 111 + createdAt: String 112 + 113 + """Grouped field value""" 114 + description: String 115 + 116 + """Grouped field value""" 117 + displayName: String 118 + 119 + """Grouped field value""" 120 + joinedViaStarterPack: String 121 + 122 + """Grouped field value""" 123 + labels: String 124 + 125 + """Grouped field value""" 126 + pinnedPost: String 127 + 128 + """Grouped field value""" 129 + pronouns: String 130 + 131 + """Grouped field value""" 132 + website: String 133 + 134 + """Count of records in this group""" 52 135 count: Int! 53 136 } 54 137 138 + """A connection to a list of items for AppBskyActorProfile""" 55 139 type AppBskyActorProfileConnection { 56 - totalCount: Int! 140 + """A list of edges""" 141 + edges: [AppBskyActorProfileEdge!]! 142 + 143 + """Information to aid in pagination""" 57 144 pageInfo: PageInfo! 58 - edges: [AppBskyActorProfileEdge!]! 59 - nodes: [AppBskyActorProfile!]! 145 + 146 + """Total number of items in the connection""" 147 + totalCount: Int 60 148 } 61 149 150 + """An edge in a connection for AppBskyActorProfile""" 62 151 type AppBskyActorProfileEdge { 152 + """The item at the end of the edge""" 63 153 node: AppBskyActorProfile! 154 + 155 + """A cursor for use in pagination""" 64 156 cursor: String! 65 157 } 66 158 159 + """Filter operators for AppBskyActorProfile fields""" 160 + input AppBskyActorProfileFieldCondition { 161 + """Exact match (equals)""" 162 + eq: String 163 + 164 + """Match any value in the list""" 165 + in: [String!] 166 + 167 + """Case-insensitive substring match (string fields only)""" 168 + contains: String 169 + 170 + """Greater than""" 171 + gt: String 172 + 173 + """Greater than or equal to""" 174 + gte: String 175 + 176 + """Less than""" 177 + lt: String 178 + 179 + """Less than or equal to""" 180 + lte: String 181 + } 182 + 183 + """Available groupBy fields for AppBskyActorProfile""" 67 184 enum AppBskyActorProfileGroupByField { 185 + """Group by uri""" 186 + uri 187 + 188 + """Group by cid""" 189 + cid 190 + 191 + """Group by did""" 192 + did 193 + 194 + """Group by collection""" 195 + collection 196 + 197 + """Group by indexedAt""" 68 198 indexedAt 69 - avatar 70 - banner 199 + 200 + """Group by actorHandle""" 201 + actorHandle 202 + 203 + """Group by createdAt""" 71 204 createdAt 205 + 206 + """Group by description""" 72 207 description 208 + 209 + """Group by displayName""" 73 210 displayName 74 - joinedViaStarterPack 211 + 212 + """Group by labels""" 75 213 labels 76 - pinnedPost 214 + 215 + """Group by pronouns""" 216 + pronouns 217 + 218 + """Group by website""" 219 + website 77 220 } 78 221 222 + """Specifies a field to group by with optional date truncation""" 79 223 input AppBskyActorProfileGroupByFieldInput { 224 + """Field name to group by""" 80 225 field: AppBskyActorProfileGroupByField! 226 + 227 + """Date truncation interval (for datetime fields)""" 81 228 interval: DateInterval 82 229 } 83 230 84 - input AppBskyActorProfileSortFieldInput { 85 - field: AppBskyActorProfileGroupByField! 86 - direction: SortDirection 87 - } 231 + """Input type for AppBskyActorProfileInput""" 232 + input AppBskyActorProfileInput { 233 + """Input field for avatar""" 234 + avatar: BlobInput 88 235 89 - input AppBskyActorProfileWhereInput { 90 - indexedAt: DateTimeFilter 91 - uri: StringFilter 92 - cid: StringFilter 93 - did: StringFilter 94 - collection: StringFilter 95 - actorHandle: StringFilter 96 - avatar: StringFilter 97 - banner: StringFilter 98 - createdAt: StringFilter 99 - description: StringFilter 100 - displayName: StringFilter 101 - joinedViaStarterPack: StringFilter 102 - labels: StringFilter 103 - pinnedPost: StringFilter 104 - } 236 + """Input field for banner""" 237 + banner: BlobInput 105 238 106 - type AppBskyEmbedExternal { 107 - uri: String! 108 - cid: String! 109 - did: String! 110 - indexedAt: String! 111 - actorHandle: String 112 - external: JSON! 113 - appBskyActorProfile: AppBskyActorProfile 114 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 115 - appBskyFeedPostgatesCount: Int! 116 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 117 - appBskyFeedThreadgatesCount: Int! 118 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 119 - appBskyActorProfilesCount: Int! 120 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 121 - fmTealAlphaFeedPlaysCount: Int! 122 - } 239 + """Input field for createdAt""" 240 + createdAt: String 123 241 124 - type AppBskyEmbedExternalAggregated { 125 - external: JSON 126 - count: Int! 127 - } 242 + """Input field for description""" 243 + description: String 128 244 129 - type AppBskyEmbedExternalConnection { 130 - totalCount: Int! 131 - pageInfo: PageInfo! 132 - edges: [AppBskyEmbedExternalEdge!]! 133 - nodes: [AppBskyEmbedExternal!]! 134 - } 245 + """Input field for displayName""" 246 + displayName: String 135 247 136 - type AppBskyEmbedExternalEdge { 137 - node: AppBskyEmbedExternal! 138 - cursor: String! 139 - } 248 + """Input field for joinedViaStarterPack""" 249 + joinedViaStarterPack: String 140 250 141 - enum AppBskyEmbedExternalGroupByField { 142 - indexedAt 143 - external 144 - } 251 + """Input field for labels""" 252 + labels: String 145 253 146 - input AppBskyEmbedExternalGroupByFieldInput { 147 - field: AppBskyEmbedExternalGroupByField! 148 - interval: DateInterval 149 - } 254 + """Input field for pinnedPost""" 255 + pinnedPost: String 150 256 151 - input AppBskyEmbedExternalSortFieldInput { 152 - field: AppBskyEmbedExternalGroupByField! 153 - direction: SortDirection 154 - } 257 + """Input field for pronouns""" 258 + pronouns: String 155 259 156 - input AppBskyEmbedExternalWhereInput { 157 - indexedAt: DateTimeFilter 158 - uri: StringFilter 159 - cid: StringFilter 160 - did: StringFilter 161 - collection: StringFilter 162 - actorHandle: StringFilter 163 - external: StringFilter 260 + """Input field for website""" 261 + website: String 164 262 } 165 263 166 - type AppBskyEmbedImages { 167 - uri: String! 168 - cid: String! 169 - did: String! 170 - indexedAt: String! 171 - actorHandle: String 172 - images: JSON! 173 - appBskyActorProfile: AppBskyActorProfile 174 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 175 - appBskyFeedPostgatesCount: Int! 176 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 177 - appBskyFeedThreadgatesCount: Int! 178 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 179 - appBskyActorProfilesCount: Int! 180 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 181 - fmTealAlphaFeedPlaysCount: Int! 182 - } 264 + """Available sort fields for AppBskyActorProfile""" 265 + enum AppBskyActorProfileSortField { 266 + """Sort by uri""" 267 + uri 183 268 184 - type AppBskyEmbedImagesAggregated { 185 - images: JSON 186 - count: Int! 187 - } 269 + """Sort by cid""" 270 + cid 188 271 189 - type AppBskyEmbedImagesConnection { 190 - totalCount: Int! 191 - pageInfo: PageInfo! 192 - edges: [AppBskyEmbedImagesEdge!]! 193 - nodes: [AppBskyEmbedImages!]! 194 - } 272 + """Sort by did""" 273 + did 195 274 196 - type AppBskyEmbedImagesEdge { 197 - node: AppBskyEmbedImages! 198 - cursor: String! 199 - } 275 + """Sort by collection""" 276 + collection 200 277 201 - enum AppBskyEmbedImagesGroupByField { 278 + """Sort by indexedAt""" 202 279 indexedAt 203 - images 204 - } 205 280 206 - input AppBskyEmbedImagesGroupByFieldInput { 207 - field: AppBskyEmbedImagesGroupByField! 208 - interval: DateInterval 209 - } 281 + """Sort by createdAt""" 282 + createdAt 210 283 211 - input AppBskyEmbedImagesSortFieldInput { 212 - field: AppBskyEmbedImagesGroupByField! 213 - direction: SortDirection 214 - } 284 + """Sort by description""" 285 + description 286 + 287 + """Sort by displayName""" 288 + displayName 215 289 216 - input AppBskyEmbedImagesWhereInput { 217 - indexedAt: DateTimeFilter 218 - uri: StringFilter 219 - cid: StringFilter 220 - did: StringFilter 221 - collection: StringFilter 222 - actorHandle: StringFilter 223 - images: StringFilter 224 - } 290 + """Sort by labels""" 291 + labels 225 292 226 - type AppBskyEmbedRecord { 227 - uri: String! 228 - cid: String! 229 - did: String! 230 - indexedAt: String! 231 - actorHandle: String 232 - record: JSON! 233 - appBskyActorProfile: AppBskyActorProfile 234 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 235 - appBskyFeedPostgatesCount: Int! 236 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 237 - appBskyFeedThreadgatesCount: Int! 238 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 239 - appBskyActorProfilesCount: Int! 240 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 241 - fmTealAlphaFeedPlaysCount: Int! 242 - } 293 + """Sort by pronouns""" 294 + pronouns 243 295 244 - type AppBskyEmbedRecordAggregated { 245 - record: JSON 246 - count: Int! 296 + """Sort by website""" 297 + website 247 298 } 248 299 249 - type AppBskyEmbedRecordConnection { 250 - totalCount: Int! 251 - pageInfo: PageInfo! 252 - edges: [AppBskyEmbedRecordEdge!]! 253 - nodes: [AppBskyEmbedRecord!]! 254 - } 300 + """Specifies a field to sort by and its direction for AppBskyActorProfile""" 301 + input AppBskyActorProfileSortFieldInput { 302 + """Field to sort by""" 303 + field: AppBskyActorProfileSortField! 255 304 256 - type AppBskyEmbedRecordEdge { 257 - node: AppBskyEmbedRecord! 258 - cursor: String! 305 + """Sort direction (ASC or DESC)""" 306 + direction: SortDirection! 259 307 } 260 308 261 - enum AppBskyEmbedRecordGroupByField { 262 - indexedAt 263 - record 264 - } 309 + """Filter conditions for AppBskyActorProfile with nested AND/OR support""" 310 + input AppBskyActorProfileWhereInput { 311 + """Filter by uri""" 312 + uri: AppBskyActorProfileFieldCondition 265 313 266 - input AppBskyEmbedRecordGroupByFieldInput { 267 - field: AppBskyEmbedRecordGroupByField! 268 - interval: DateInterval 269 - } 314 + """Filter by cid""" 315 + cid: AppBskyActorProfileFieldCondition 270 316 271 - input AppBskyEmbedRecordSortFieldInput { 272 - field: AppBskyEmbedRecordGroupByField! 273 - direction: SortDirection 274 - } 317 + """Filter by did""" 318 + did: AppBskyActorProfileFieldCondition 275 319 276 - input AppBskyEmbedRecordWhereInput { 277 - indexedAt: DateTimeFilter 278 - uri: StringFilter 279 - cid: StringFilter 280 - did: StringFilter 281 - collection: StringFilter 282 - actorHandle: StringFilter 283 - record: StringFilter 284 - } 320 + """Filter by collection""" 321 + collection: AppBskyActorProfileFieldCondition 285 322 286 - type AppBskyEmbedRecordWithMedia { 287 - uri: String! 288 - cid: String! 289 - did: String! 290 - indexedAt: String! 291 - actorHandle: String 292 - media: JSON! 293 - record: JSON! 294 - appBskyActorProfile: AppBskyActorProfile 295 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 296 - appBskyFeedPostgatesCount: Int! 297 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 298 - appBskyFeedThreadgatesCount: Int! 299 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 300 - appBskyActorProfilesCount: Int! 301 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 302 - fmTealAlphaFeedPlaysCount: Int! 303 - } 323 + """Filter by indexedAt""" 324 + indexedAt: AppBskyActorProfileFieldCondition 304 325 305 - type AppBskyEmbedRecordWithMediaAggregated { 306 - media: JSON 307 - record: JSON 308 - count: Int! 309 - } 326 + """Filter by actorHandle""" 327 + actorHandle: AppBskyActorProfileFieldCondition 310 328 311 - type AppBskyEmbedRecordWithMediaConnection { 312 - totalCount: Int! 313 - pageInfo: PageInfo! 314 - edges: [AppBskyEmbedRecordWithMediaEdge!]! 315 - nodes: [AppBskyEmbedRecordWithMedia!]! 316 - } 329 + """Filter by createdAt""" 330 + createdAt: AppBskyActorProfileFieldCondition 317 331 318 - type AppBskyEmbedRecordWithMediaEdge { 319 - node: AppBskyEmbedRecordWithMedia! 320 - cursor: String! 321 - } 332 + """Filter by description""" 333 + description: AppBskyActorProfileFieldCondition 322 334 323 - enum AppBskyEmbedRecordWithMediaGroupByField { 324 - indexedAt 325 - media 326 - record 327 - } 335 + """Filter by displayName""" 336 + displayName: AppBskyActorProfileFieldCondition 328 337 329 - input AppBskyEmbedRecordWithMediaGroupByFieldInput { 330 - field: AppBskyEmbedRecordWithMediaGroupByField! 331 - interval: DateInterval 332 - } 338 + """Filter by labels""" 339 + labels: AppBskyActorProfileFieldCondition 333 340 334 - input AppBskyEmbedRecordWithMediaSortFieldInput { 335 - field: AppBskyEmbedRecordWithMediaGroupByField! 336 - direction: SortDirection 337 - } 341 + """Filter by pronouns""" 342 + pronouns: AppBskyActorProfileFieldCondition 338 343 339 - input AppBskyEmbedRecordWithMediaWhereInput { 340 - indexedAt: DateTimeFilter 341 - uri: StringFilter 342 - cid: StringFilter 343 - did: StringFilter 344 - collection: StringFilter 345 - actorHandle: StringFilter 346 - media: StringFilter 347 - record: StringFilter 348 - } 344 + """Filter by website""" 345 + website: AppBskyActorProfileFieldCondition 349 346 350 - type AppBskyEmbedVideo { 351 - uri: String! 352 - cid: String! 353 - did: String! 354 - indexedAt: String! 355 - actorHandle: String 356 - alt: String 357 - aspectRatio: JSON 358 - captions: JSON 359 - video: Blob 360 - appBskyActorProfile: AppBskyActorProfile 361 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 362 - appBskyFeedPostgatesCount: Int! 363 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 364 - appBskyFeedThreadgatesCount: Int! 365 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 366 - appBskyActorProfilesCount: Int! 367 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 368 - fmTealAlphaFeedPlaysCount: Int! 369 - } 347 + """All conditions must match (AND logic)""" 348 + and: [AppBskyActorProfileWhereInput!] 370 349 371 - type AppBskyEmbedVideoAggregated { 372 - alt: JSON 373 - aspectRatio: JSON 374 - captions: JSON 375 - video: JSON 376 - count: Int! 350 + """Any condition must match (OR logic)""" 351 + or: [AppBskyActorProfileWhereInput!] 377 352 } 378 353 379 - type AppBskyEmbedVideoConnection { 380 - totalCount: Int! 381 - pageInfo: PageInfo! 382 - edges: [AppBskyEmbedVideoEdge!]! 383 - nodes: [AppBskyEmbedVideo!]! 384 - } 354 + """A blob reference with metadata and URL generation""" 355 + type Blob { 356 + """CID reference to the blob""" 357 + ref: String! 385 358 386 - type AppBskyEmbedVideoEdge { 387 - node: AppBskyEmbedVideo! 388 - cursor: String! 389 - } 359 + """MIME type of the blob""" 360 + mimeType: String! 390 361 391 - enum AppBskyEmbedVideoGroupByField { 392 - indexedAt 393 - alt 394 - aspectRatio 395 - captions 396 - video 397 - } 362 + """Size in bytes""" 363 + size: Int! 398 364 399 - input AppBskyEmbedVideoGroupByFieldInput { 400 - field: AppBskyEmbedVideoGroupByField! 401 - interval: DateInterval 365 + """ 366 + Generate CDN URL for the blob with the specified preset (avatar, banner, feed_thumbnail, feed_fullsize) 367 + """ 368 + url( 369 + """Image preset: avatar, banner, feed_thumbnail, feed_fullsize""" 370 + preset: String 371 + ): String! 402 372 } 403 373 404 - input AppBskyEmbedVideoSortFieldInput { 405 - field: AppBskyEmbedVideoGroupByField! 406 - direction: SortDirection 407 - } 374 + """Input type for blob references""" 375 + input BlobInput { 376 + """CID reference to the blob""" 377 + ref: String! 408 378 409 - input AppBskyEmbedVideoWhereInput { 410 - indexedAt: DateTimeFilter 411 - uri: StringFilter 412 - cid: StringFilter 413 - did: StringFilter 414 - collection: StringFilter 415 - actorHandle: StringFilter 416 - alt: StringFilter 417 - aspectRatio: StringFilter 418 - captions: StringFilter 419 - video: StringFilter 420 - } 379 + """MIME type of the blob""" 380 + mimeType: String! 421 381 422 - type AppBskyFeedPostgate { 423 - uri: String! 424 - cid: String! 425 - did: String! 426 - indexedAt: String! 427 - actorHandle: String 428 - createdAt: String! 429 - detachedEmbeddingUris: [String] 430 - embeddingRules: JSON 431 - post: String! 432 - appBskyFeedPostgate: AppBskyFeedPostgate 433 - appBskyFeedThreadgate: AppBskyFeedThreadgate 434 - appBskyActorProfile: AppBskyActorProfile 435 - fmTealAlphaFeedPlay: FmTealAlphaFeedPlay 436 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 437 - appBskyFeedPostgatesCount: Int! 438 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 439 - appBskyFeedThreadgatesCount: Int! 440 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 441 - appBskyActorProfilesCount: Int! 442 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 443 - fmTealAlphaFeedPlaysCount: Int! 382 + """Size in bytes""" 383 + size: Int! 444 384 } 445 385 446 - type AppBskyFeedPostgateAggregated { 447 - createdAt: JSON 448 - detachedEmbeddingUris: JSON 449 - embeddingRules: JSON 450 - post: JSON 451 - count: Int! 452 - } 386 + """Response from uploading a blob""" 387 + type BlobUploadResponse { 388 + """CID reference to the blob""" 389 + ref: String! 453 390 454 - type AppBskyFeedPostgateConnection { 455 - totalCount: Int! 456 - pageInfo: PageInfo! 457 - edges: [AppBskyFeedPostgateEdge!]! 458 - nodes: [AppBskyFeedPostgate!]! 459 - } 391 + """MIME type of the blob""" 392 + mimeType: String! 460 393 461 - type AppBskyFeedPostgateEdge { 462 - node: AppBskyFeedPostgate! 463 - cursor: String! 394 + """Size in bytes""" 395 + size: Int! 464 396 } 465 397 466 - enum AppBskyFeedPostgateGroupByField { 467 - indexedAt 468 - createdAt 469 - detachedEmbeddingUris 470 - embeddingRules 471 - post 472 - } 398 + """Date truncation intervals for aggregation""" 399 + enum DateInterval { 400 + """Truncate to hour""" 401 + HOUR 473 402 474 - input AppBskyFeedPostgateGroupByFieldInput { 475 - field: AppBskyFeedPostgateGroupByField! 476 - interval: DateInterval 477 - } 403 + """Truncate to day""" 404 + DAY 478 405 479 - input AppBskyFeedPostgateSortFieldInput { 480 - field: AppBskyFeedPostgateGroupByField! 481 - direction: SortDirection 482 - } 406 + """Truncate to week""" 407 + WEEK 483 408 484 - input AppBskyFeedPostgateWhereInput { 485 - indexedAt: DateTimeFilter 486 - uri: StringFilter 487 - cid: StringFilter 488 - did: StringFilter 489 - collection: StringFilter 490 - actorHandle: StringFilter 491 - createdAt: StringFilter 492 - detachedEmbeddingUris: StringFilter 493 - embeddingRules: StringFilter 494 - post: StringFilter 409 + """Truncate to month""" 410 + MONTH 495 411 } 496 412 497 - type AppBskyFeedThreadgate { 498 - uri: String! 499 - cid: String! 500 - did: String! 501 - indexedAt: String! 502 - actorHandle: String 503 - allow: JSON 504 - createdAt: String! 505 - hiddenReplies: [String] 506 - post: String! 507 - appBskyFeedPostgate: AppBskyFeedPostgate 508 - appBskyFeedThreadgate: AppBskyFeedThreadgate 509 - appBskyActorProfile: AppBskyActorProfile 510 - fmTealAlphaFeedPlay: FmTealAlphaFeedPlay 511 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 512 - appBskyFeedPostgatesCount: Int! 513 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 514 - appBskyFeedThreadgatesCount: Int! 515 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 516 - appBskyActorProfilesCount: Int! 517 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 518 - fmTealAlphaFeedPlaysCount: Int! 413 + """Result of a delete mutation""" 414 + type DeleteResult { 415 + """URI of deleted record""" 416 + uri: String 519 417 } 520 418 521 - type AppBskyFeedThreadgateAggregated { 522 - allow: JSON 523 - createdAt: JSON 524 - hiddenReplies: JSON 525 - post: JSON 526 - count: Int! 527 - } 419 + """Object type from lexicon definition""" 420 + type FmTealAlphaFeedDefsArtist { 421 + """Field from object definition""" 422 + artistMbId: String 528 423 529 - type AppBskyFeedThreadgateConnection { 530 - totalCount: Int! 531 - pageInfo: PageInfo! 532 - edges: [AppBskyFeedThreadgateEdge!]! 533 - nodes: [AppBskyFeedThreadgate!]! 424 + """Field from object definition""" 425 + artistName: String! 534 426 } 535 427 536 - type AppBskyFeedThreadgateEdge { 537 - node: AppBskyFeedThreadgate! 538 - cursor: String! 539 - } 428 + """Record type: fm.teal.alpha.feed.play""" 429 + type FmTealAlphaFeedPlay { 430 + """Record URI""" 431 + uri: String 540 432 541 - enum AppBskyFeedThreadgateGroupByField { 542 - indexedAt 543 - allow 544 - createdAt 545 - hiddenReplies 546 - post 547 - } 433 + """Record CID""" 434 + cid: String 548 435 549 - input AppBskyFeedThreadgateGroupByFieldInput { 550 - field: AppBskyFeedThreadgateGroupByField! 551 - interval: DateInterval 552 - } 436 + """DID of record author""" 437 + did: String 553 438 554 - input AppBskyFeedThreadgateSortFieldInput { 555 - field: AppBskyFeedThreadgateGroupByField! 556 - direction: SortDirection 557 - } 439 + """Collection name""" 440 + collection: String 558 441 559 - input AppBskyFeedThreadgateWhereInput { 560 - indexedAt: DateTimeFilter 561 - uri: StringFilter 562 - cid: StringFilter 563 - did: StringFilter 564 - collection: StringFilter 565 - actorHandle: StringFilter 566 - allow: StringFilter 567 - createdAt: StringFilter 568 - hiddenReplies: StringFilter 569 - post: StringFilter 570 - } 442 + """When record was indexed""" 443 + indexedAt: String 571 444 572 - type AppBskyRichtextFacet { 573 - uri: String! 574 - cid: String! 575 - did: String! 576 - indexedAt: String! 445 + """Handle of the actor who created this record""" 577 446 actorHandle: String 578 - features: JSON! 579 - index: JSON! 580 - appBskyActorProfile: AppBskyActorProfile 581 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 582 - appBskyFeedPostgatesCount: Int! 583 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 584 - appBskyFeedThreadgatesCount: Int! 585 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 586 - appBskyActorProfilesCount: Int! 587 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 588 - fmTealAlphaFeedPlaysCount: Int! 589 - } 590 447 591 - type AppBskyRichtextFacetAggregated { 592 - features: JSON 593 - index: JSON 594 - count: Int! 595 - } 448 + """Field from lexicon""" 449 + artistMbIds: [String!] 596 450 597 - type AppBskyRichtextFacetConnection { 598 - totalCount: Int! 599 - pageInfo: PageInfo! 600 - edges: [AppBskyRichtextFacetEdge!]! 601 - nodes: [AppBskyRichtextFacet!]! 602 - } 451 + """Field from lexicon""" 452 + artistNames: [String!] 603 453 604 - type AppBskyRichtextFacetEdge { 605 - node: AppBskyRichtextFacet! 606 - cursor: String! 607 - } 454 + """Field from lexicon""" 455 + artists: [FmTealAlphaFeedDefsArtist!] 608 456 609 - enum AppBskyRichtextFacetGroupByField { 610 - indexedAt 611 - features 612 - index 613 - } 457 + """Field from lexicon""" 458 + duration: Int 614 459 615 - input AppBskyRichtextFacetGroupByFieldInput { 616 - field: AppBskyRichtextFacetGroupByField! 617 - interval: DateInterval 618 - } 460 + """Field from lexicon""" 461 + isrc: String 619 462 620 - input AppBskyRichtextFacetSortFieldInput { 621 - field: AppBskyRichtextFacetGroupByField! 622 - direction: SortDirection 623 - } 463 + """Field from lexicon""" 464 + musicServiceBaseDomain: String 624 465 625 - input AppBskyRichtextFacetWhereInput { 626 - indexedAt: DateTimeFilter 627 - uri: StringFilter 628 - cid: StringFilter 629 - did: StringFilter 630 - collection: StringFilter 631 - actorHandle: StringFilter 632 - features: StringFilter 633 - index: StringFilter 634 - } 466 + """Field from lexicon""" 467 + originUrl: String 468 + 469 + """Field from lexicon""" 470 + playedTime: String 471 + 472 + """Field from lexicon""" 473 + recordingMbId: String 635 474 636 - type Blob { 637 - ref: String! 638 - mimeType: String! 639 - size: Int! 475 + """Field from lexicon""" 476 + releaseMbId: String 477 + 478 + """Field from lexicon""" 479 + releaseName: String 480 + 481 + """Field from lexicon""" 482 + submissionClientAgent: String 483 + 484 + """Field from lexicon""" 485 + trackMbId: String 486 + 487 + """Field from lexicon""" 488 + trackName: String 640 489 641 490 """ 642 - Generate CDN URL for the blob with the specified preset (avatar, banner, feed_thumbnail, feed_fullsize) 491 + Reverse join: records in app.bsky.actor.profile that reference this record via joinedViaStarterPack 643 492 """ 644 - url(preset: String): String! 645 - } 493 + appBskyActorProfileViaJoinedViaStarterPack( 494 + """Returns the first n items from the list""" 495 + first: Int 646 496 647 - type ComAtprotoRepoStrongRef { 648 - did: String! 649 - indexedAt: String! 650 - actorHandle: String 651 - cid: String! 652 - uri: String! 653 - appBskyFeedPostgate: AppBskyFeedPostgate 654 - appBskyFeedThreadgate: AppBskyFeedThreadgate 655 - appBskyActorProfile: AppBskyActorProfile 656 - fmTealAlphaFeedPlay: FmTealAlphaFeedPlay 657 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 658 - appBskyFeedPostgatesCount: Int! 659 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 660 - appBskyFeedThreadgatesCount: Int! 661 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 662 - appBskyActorProfilesCount: Int! 663 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 664 - fmTealAlphaFeedPlaysCount: Int! 665 - } 497 + """Returns items after the given cursor""" 498 + after: String 666 499 667 - type ComAtprotoRepoStrongRefAggregated { 668 - cid: JSON 669 - uri: JSON 670 - count: Int! 671 - } 500 + """Returns the last n items from the list""" 501 + last: Int 672 502 673 - type ComAtprotoRepoStrongRefConnection { 674 - totalCount: Int! 675 - pageInfo: PageInfo! 676 - edges: [ComAtprotoRepoStrongRefEdge!]! 677 - nodes: [ComAtprotoRepoStrongRef!]! 678 - } 503 + """Returns items before the given cursor""" 504 + before: String 679 505 680 - type ComAtprotoRepoStrongRefEdge { 681 - node: ComAtprotoRepoStrongRef! 682 - cursor: String! 683 - } 506 + """Sort order for the connection""" 507 + sortBy: [AppBskyActorProfileSortFieldInput!] 684 508 685 - enum ComAtprotoRepoStrongRefGroupByField { 686 - indexedAt 687 - cid 688 - uri 689 - } 509 + """Filter conditions for the query""" 510 + where: AppBskyActorProfileWhereInput 511 + ): AppBskyActorProfileConnection 690 512 691 - input ComAtprotoRepoStrongRefGroupByFieldInput { 692 - field: ComAtprotoRepoStrongRefGroupByField! 693 - interval: DateInterval 694 - } 513 + """ 514 + Reverse join: records in app.bsky.actor.profile that reference this record via pinnedPost 515 + """ 516 + appBskyActorProfileViaPinnedPost( 517 + """Returns the first n items from the list""" 518 + first: Int 695 519 696 - input ComAtprotoRepoStrongRefSortFieldInput { 697 - field: ComAtprotoRepoStrongRefGroupByField! 698 - direction: SortDirection 699 - } 520 + """Returns items after the given cursor""" 521 + after: String 700 522 701 - input ComAtprotoRepoStrongRefWhereInput { 702 - indexedAt: DateTimeFilter 703 - did: StringFilter 704 - collection: StringFilter 705 - actorHandle: StringFilter 706 - cid: StringFilter 707 - uri: StringFilter 523 + """Returns the last n items from the list""" 524 + last: Int 525 + 526 + """Returns items before the given cursor""" 527 + before: String 528 + 529 + """Sort order for the connection""" 530 + sortBy: [AppBskyActorProfileSortFieldInput!] 531 + 532 + """Filter conditions for the query""" 533 + where: AppBskyActorProfileWhereInput 534 + ): AppBskyActorProfileConnection 535 + 536 + """ 537 + DID join: record in app.bsky.actor.profile that shares the same DID as this record 538 + """ 539 + appBskyActorProfileByDid: AppBskyActorProfile 708 540 } 709 541 710 - enum DateInterval { 711 - second 712 - minute 713 - hour 714 - day 715 - week 716 - month 717 - quarter 718 - year 719 - } 542 + """Aggregated results for fm.teal.alpha.feed.play""" 543 + type FmTealAlphaFeedPlayAggregated { 544 + """Grouped field value""" 545 + uri: String 546 + 547 + """Grouped field value""" 548 + cid: String 549 + 550 + """Grouped field value""" 551 + did: String 552 + 553 + """Grouped field value""" 554 + collection: String 555 + 556 + """Grouped field value""" 557 + indexed_at: String 558 + 559 + """Grouped field value""" 560 + artistMbIds: String 561 + 562 + """Grouped field value""" 563 + artistNames: String 564 + 565 + """Grouped field value""" 566 + artists: String 720 567 721 - input DateTimeFilter { 722 - eq: String 723 - gt: String 724 - gte: String 725 - lt: String 726 - lte: String 727 - } 568 + """Grouped field value""" 569 + duration: String 728 570 729 - type FmTealAlphaFeedPlay { 730 - uri: String! 731 - cid: String! 732 - did: String! 733 - indexedAt: String! 734 - actorHandle: String 735 - artistMbIds: [String] 736 - artistNames: [String] 737 - artists: JSON 738 - duration: Int 571 + """Grouped field value""" 739 572 isrc: String 573 + 574 + """Grouped field value""" 740 575 musicServiceBaseDomain: String 576 + 577 + """Grouped field value""" 741 578 originUrl: String 579 + 580 + """Grouped field value""" 742 581 playedTime: String 582 + 583 + """Grouped field value""" 743 584 recordingMbId: String 585 + 586 + """Grouped field value""" 744 587 releaseMbId: String 588 + 589 + """Grouped field value""" 745 590 releaseName: String 591 + 592 + """Grouped field value""" 746 593 submissionClientAgent: String 594 + 595 + """Grouped field value""" 747 596 trackMbId: String 748 - trackName: String! 749 - appBskyActorProfile: AppBskyActorProfile 750 - appBskyFeedPostgates(limit: Int): [AppBskyFeedPostgate!]! 751 - appBskyFeedPostgatesCount: Int! 752 - appBskyFeedThreadgates(limit: Int): [AppBskyFeedThreadgate!]! 753 - appBskyFeedThreadgatesCount: Int! 754 - appBskyActorProfiles(limit: Int): [AppBskyActorProfile!]! 755 - appBskyActorProfilesCount: Int! 756 - fmTealAlphaFeedPlays(limit: Int): [FmTealAlphaFeedPlay!]! 757 - fmTealAlphaFeedPlaysCount: Int! 758 - } 759 597 760 - type FmTealAlphaFeedPlayAggregated { 761 - artistMbIds: JSON 762 - artistNames: JSON 763 - artists: JSON 764 - duration: JSON 765 - isrc: JSON 766 - musicServiceBaseDomain: JSON 767 - originUrl: JSON 768 - playedTime: JSON 769 - recordingMbId: JSON 770 - releaseMbId: JSON 771 - releaseName: JSON 772 - submissionClientAgent: JSON 773 - trackMbId: JSON 774 - trackName: JSON 598 + """Grouped field value""" 599 + trackName: String 600 + 601 + """Count of records in this group""" 775 602 count: Int! 776 603 } 777 604 605 + """A connection to a list of items for FmTealAlphaFeedPlay""" 778 606 type FmTealAlphaFeedPlayConnection { 779 - totalCount: Int! 607 + """A list of edges""" 608 + edges: [FmTealAlphaFeedPlayEdge!]! 609 + 610 + """Information to aid in pagination""" 780 611 pageInfo: PageInfo! 781 - edges: [FmTealAlphaFeedPlayEdge!]! 782 - nodes: [FmTealAlphaFeedPlay!]! 612 + 613 + """Total number of items in the connection""" 614 + totalCount: Int 783 615 } 784 616 617 + """An edge in a connection for FmTealAlphaFeedPlay""" 785 618 type FmTealAlphaFeedPlayEdge { 619 + """The item at the end of the edge""" 786 620 node: FmTealAlphaFeedPlay! 621 + 622 + """A cursor for use in pagination""" 787 623 cursor: String! 788 624 } 789 625 626 + """Filter operators for FmTealAlphaFeedPlay fields""" 627 + input FmTealAlphaFeedPlayFieldCondition { 628 + """Exact match (equals)""" 629 + eq: String 630 + 631 + """Match any value in the list""" 632 + in: [String!] 633 + 634 + """Case-insensitive substring match (string fields only)""" 635 + contains: String 636 + 637 + """Greater than""" 638 + gt: String 639 + 640 + """Greater than or equal to""" 641 + gte: String 642 + 643 + """Less than""" 644 + lt: String 645 + 646 + """Less than or equal to""" 647 + lte: String 648 + } 649 + 650 + """Available groupBy fields for FmTealAlphaFeedPlay""" 790 651 enum FmTealAlphaFeedPlayGroupByField { 652 + """Group by uri""" 653 + uri 654 + 655 + """Group by cid""" 656 + cid 657 + 658 + """Group by did""" 659 + did 660 + 661 + """Group by collection""" 662 + collection 663 + 664 + """Group by indexedAt""" 791 665 indexedAt 666 + 667 + """Group by actorHandle""" 668 + actorHandle 669 + 670 + """Group by artistMbIds""" 792 671 artistMbIds 672 + 673 + """Group by artistNames""" 793 674 artistNames 675 + 676 + """Group by artists""" 794 677 artists 678 + 679 + """Group by duration""" 795 680 duration 681 + 682 + """Group by isrc""" 796 683 isrc 684 + 685 + """Group by musicServiceBaseDomain""" 797 686 musicServiceBaseDomain 687 + 688 + """Group by originUrl""" 798 689 originUrl 690 + 691 + """Group by playedTime""" 799 692 playedTime 693 + 694 + """Group by recordingMbId""" 800 695 recordingMbId 696 + 697 + """Group by releaseMbId""" 801 698 releaseMbId 699 + 700 + """Group by releaseName""" 802 701 releaseName 702 + 703 + """Group by submissionClientAgent""" 803 704 submissionClientAgent 705 + 706 + """Group by trackMbId""" 804 707 trackMbId 708 + 709 + """Group by trackName""" 805 710 trackName 806 711 } 807 712 713 + """Specifies a field to group by with optional date truncation""" 808 714 input FmTealAlphaFeedPlayGroupByFieldInput { 715 + """Field name to group by""" 809 716 field: FmTealAlphaFeedPlayGroupByField! 717 + 718 + """Date truncation interval (for datetime fields)""" 810 719 interval: DateInterval 811 720 } 812 721 722 + """Input type for FmTealAlphaFeedPlayInput""" 723 + input FmTealAlphaFeedPlayInput { 724 + """Input field for artistMbIds""" 725 + artistMbIds: String 726 + 727 + """Input field for artistNames""" 728 + artistNames: String 729 + 730 + """Input field for artists""" 731 + artists: String 732 + 733 + """Input field for duration""" 734 + duration: Int 735 + 736 + """Input field for isrc""" 737 + isrc: String 738 + 739 + """Input field for musicServiceBaseDomain""" 740 + musicServiceBaseDomain: String 741 + 742 + """Input field for originUrl""" 743 + originUrl: String 744 + 745 + """Input field for playedTime""" 746 + playedTime: String 747 + 748 + """Input field for recordingMbId""" 749 + recordingMbId: String 750 + 751 + """Input field for releaseMbId""" 752 + releaseMbId: String 753 + 754 + """Input field for releaseName""" 755 + releaseName: String 756 + 757 + """Input field for submissionClientAgent""" 758 + submissionClientAgent: String 759 + 760 + """Input field for trackMbId""" 761 + trackMbId: String 762 + 763 + """Input field for trackName""" 764 + trackName: String! 765 + } 766 + 767 + """Available sort fields for FmTealAlphaFeedPlay""" 768 + enum FmTealAlphaFeedPlaySortField { 769 + """Sort by uri""" 770 + uri 771 + 772 + """Sort by cid""" 773 + cid 774 + 775 + """Sort by did""" 776 + did 777 + 778 + """Sort by collection""" 779 + collection 780 + 781 + """Sort by indexedAt""" 782 + indexedAt 783 + 784 + """Sort by duration""" 785 + duration 786 + 787 + """Sort by isrc""" 788 + isrc 789 + 790 + """Sort by musicServiceBaseDomain""" 791 + musicServiceBaseDomain 792 + 793 + """Sort by originUrl""" 794 + originUrl 795 + 796 + """Sort by playedTime""" 797 + playedTime 798 + 799 + """Sort by recordingMbId""" 800 + recordingMbId 801 + 802 + """Sort by releaseMbId""" 803 + releaseMbId 804 + 805 + """Sort by releaseName""" 806 + releaseName 807 + 808 + """Sort by submissionClientAgent""" 809 + submissionClientAgent 810 + 811 + """Sort by trackMbId""" 812 + trackMbId 813 + 814 + """Sort by trackName""" 815 + trackName 816 + } 817 + 818 + """Specifies a field to sort by and its direction for FmTealAlphaFeedPlay""" 813 819 input FmTealAlphaFeedPlaySortFieldInput { 814 - field: FmTealAlphaFeedPlayGroupByField! 815 - direction: SortDirection 820 + """Field to sort by""" 821 + field: FmTealAlphaFeedPlaySortField! 822 + 823 + """Sort direction (ASC or DESC)""" 824 + direction: SortDirection! 816 825 } 817 826 827 + """Filter conditions for FmTealAlphaFeedPlay with nested AND/OR support""" 818 828 input FmTealAlphaFeedPlayWhereInput { 819 - indexedAt: DateTimeFilter 820 - uri: StringFilter 821 - cid: StringFilter 822 - did: StringFilter 823 - collection: StringFilter 824 - actorHandle: StringFilter 825 - artistMbIds: StringFilter 826 - artistNames: StringFilter 827 - artists: StringFilter 828 - duration: IntFilter 829 - isrc: StringFilter 830 - musicServiceBaseDomain: StringFilter 831 - originUrl: StringFilter 832 - playedTime: StringFilter 833 - recordingMbId: StringFilter 834 - releaseMbId: StringFilter 835 - releaseName: StringFilter 836 - submissionClientAgent: StringFilter 837 - trackMbId: StringFilter 838 - trackName: StringFilter 829 + """Filter by uri""" 830 + uri: FmTealAlphaFeedPlayFieldCondition 831 + 832 + """Filter by cid""" 833 + cid: FmTealAlphaFeedPlayFieldCondition 834 + 835 + """Filter by did""" 836 + did: FmTealAlphaFeedPlayFieldCondition 837 + 838 + """Filter by collection""" 839 + collection: FmTealAlphaFeedPlayFieldCondition 840 + 841 + """Filter by indexedAt""" 842 + indexedAt: FmTealAlphaFeedPlayFieldCondition 843 + 844 + """Filter by actorHandle""" 845 + actorHandle: FmTealAlphaFeedPlayFieldCondition 846 + 847 + """Filter by duration""" 848 + duration: FmTealAlphaFeedPlayFieldCondition 849 + 850 + """Filter by isrc""" 851 + isrc: FmTealAlphaFeedPlayFieldCondition 852 + 853 + """Filter by musicServiceBaseDomain""" 854 + musicServiceBaseDomain: FmTealAlphaFeedPlayFieldCondition 855 + 856 + """Filter by originUrl""" 857 + originUrl: FmTealAlphaFeedPlayFieldCondition 858 + 859 + """Filter by playedTime""" 860 + playedTime: FmTealAlphaFeedPlayFieldCondition 861 + 862 + """Filter by recordingMbId""" 863 + recordingMbId: FmTealAlphaFeedPlayFieldCondition 864 + 865 + """Filter by releaseMbId""" 866 + releaseMbId: FmTealAlphaFeedPlayFieldCondition 867 + 868 + """Filter by releaseName""" 869 + releaseName: FmTealAlphaFeedPlayFieldCondition 870 + 871 + """Filter by submissionClientAgent""" 872 + submissionClientAgent: FmTealAlphaFeedPlayFieldCondition 873 + 874 + """Filter by trackMbId""" 875 + trackMbId: FmTealAlphaFeedPlayFieldCondition 876 + 877 + """Filter by trackName""" 878 + trackName: FmTealAlphaFeedPlayFieldCondition 879 + 880 + """All conditions must match (AND logic)""" 881 + and: [FmTealAlphaFeedPlayWhereInput!] 882 + 883 + """Any condition must match (OR logic)""" 884 + or: [FmTealAlphaFeedPlayWhereInput!] 839 885 } 840 886 841 - input IntFilter { 842 - eq: Int 843 - in: [Int] 844 - gt: Int 845 - gte: Int 846 - lt: Int 847 - lte: Int 848 - } 887 + """Root mutation type""" 888 + type Mutation { 889 + """Upload a blob to the PDS""" 890 + uploadBlob( 891 + """Base64 encoded blob data""" 892 + data: String! 893 + 894 + """MIME type of the blob""" 895 + mimeType: String! 896 + ): BlobUploadResponse! 897 + 898 + """Create a new app.bsky.actor.profile record""" 899 + createAppBskyActorProfile( 900 + """Record data""" 901 + input: AppBskyActorProfileInput! 902 + 903 + """Optional record key (defaults to TID)""" 904 + rkey: String 905 + ): AppBskyActorProfile 849 906 850 - scalar JSON 907 + """Update an existing app.bsky.actor.profile record""" 908 + updateAppBskyActorProfile( 909 + """Record key to update""" 910 + rkey: String! 851 911 852 - type Mutation { 853 - """Sync user collections for a given DID""" 854 - syncUserCollections(did: String!): SyncResult! 912 + """Updated record data""" 913 + input: AppBskyActorProfileInput! 914 + ): AppBskyActorProfile 915 + 916 + """Delete a app.bsky.actor.profile record""" 917 + deleteAppBskyActorProfile( 918 + """Record key to delete""" 919 + rkey: String! 920 + ): DeleteResult 921 + 922 + """Create a new fm.teal.alpha.feed.play record""" 923 + createFmTealAlphaFeedPlay( 924 + """Record data""" 925 + input: FmTealAlphaFeedPlayInput! 926 + 927 + """Optional record key (defaults to TID)""" 928 + rkey: String 929 + ): FmTealAlphaFeedPlay 930 + 931 + """Update an existing fm.teal.alpha.feed.play record""" 932 + updateFmTealAlphaFeedPlay( 933 + """Record key to update""" 934 + rkey: String! 935 + 936 + """Updated record data""" 937 + input: FmTealAlphaFeedPlayInput! 938 + ): FmTealAlphaFeedPlay 939 + 940 + """Delete a fm.teal.alpha.feed.play record""" 941 + deleteFmTealAlphaFeedPlay( 942 + """Record key to delete""" 943 + rkey: String! 944 + ): DeleteResult 855 945 } 856 946 947 + """Information about pagination in a connection""" 857 948 type PageInfo { 949 + """When paginating forwards, are there more items?""" 858 950 hasNextPage: Boolean! 951 + 952 + """When paginating backwards, are there more items?""" 859 953 hasPreviousPage: Boolean! 954 + 955 + """Cursor corresponding to the first item in the page""" 860 956 startCursor: String 957 + 958 + """Cursor corresponding to the last item in the page""" 861 959 endCursor: String 862 960 } 863 961 962 + """Root query type""" 864 963 type Query { 865 - """Query app.bsky.embed.record records""" 866 - appBskyEmbedRecords(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyEmbedRecordSortFieldInput], where: AppBskyEmbedRecordWhereInput): AppBskyEmbedRecordConnection! 964 + """Query app.bsky.actor.profile with cursor pagination and sorting""" 965 + appBskyActorProfile( 966 + """Returns the first n items from the list""" 967 + first: Int 867 968 868 - """ 869 - Aggregated query for app.bsky.embed.record records with GROUP BY support 870 - """ 871 - appBskyEmbedRecordsAggregated(groupBy: [AppBskyEmbedRecordGroupByFieldInput!], where: AppBskyEmbedRecordWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyEmbedRecordAggregated!]! 969 + """Returns items after the given cursor""" 970 + after: String 872 971 873 - """Query app.bsky.embed.images records""" 874 - appBskyEmbedImageses(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyEmbedImagesSortFieldInput], where: AppBskyEmbedImagesWhereInput): AppBskyEmbedImagesConnection! 972 + """Returns the last n items from the list""" 973 + last: Int 875 974 876 - """ 877 - Aggregated query for app.bsky.embed.images records with GROUP BY support 878 - """ 879 - appBskyEmbedImagesesAggregated(groupBy: [AppBskyEmbedImagesGroupByFieldInput!], where: AppBskyEmbedImagesWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyEmbedImagesAggregated!]! 975 + """Returns items before the given cursor""" 976 + before: String 880 977 881 - """Query app.bsky.embed.video records""" 882 - appBskyEmbedVideos(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyEmbedVideoSortFieldInput], where: AppBskyEmbedVideoWhereInput): AppBskyEmbedVideoConnection! 978 + """Sort order for the connection""" 979 + sortBy: [AppBskyActorProfileSortFieldInput!] 883 980 884 - """ 885 - Aggregated query for app.bsky.embed.video records with GROUP BY support 886 - """ 887 - appBskyEmbedVideosAggregated(groupBy: [AppBskyEmbedVideoGroupByFieldInput!], where: AppBskyEmbedVideoWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyEmbedVideoAggregated!]! 981 + """Filter conditions for the query""" 982 + where: AppBskyActorProfileWhereInput 983 + ): AppBskyActorProfileConnection 888 984 889 - """Query app.bsky.embed.recordWithMedia records""" 890 - appBskyEmbedRecordWithMedias(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyEmbedRecordWithMediaSortFieldInput], where: AppBskyEmbedRecordWithMediaWhereInput): AppBskyEmbedRecordWithMediaConnection! 985 + """Query fm.teal.alpha.feed.play with cursor pagination and sorting""" 986 + fmTealAlphaFeedPlay( 987 + """Returns the first n items from the list""" 988 + first: Int 891 989 892 - """ 893 - Aggregated query for app.bsky.embed.recordWithMedia records with GROUP BY support 894 - """ 895 - appBskyEmbedRecordWithMediasAggregated(groupBy: [AppBskyEmbedRecordWithMediaGroupByFieldInput!], where: AppBskyEmbedRecordWithMediaWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyEmbedRecordWithMediaAggregated!]! 990 + """Returns items after the given cursor""" 991 + after: String 896 992 897 - """Query app.bsky.embed.external records""" 898 - appBskyEmbedExternals(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyEmbedExternalSortFieldInput], where: AppBskyEmbedExternalWhereInput): AppBskyEmbedExternalConnection! 993 + """Returns the last n items from the list""" 994 + last: Int 899 995 900 - """ 901 - Aggregated query for app.bsky.embed.external records with GROUP BY support 902 - """ 903 - appBskyEmbedExternalsAggregated(groupBy: [AppBskyEmbedExternalGroupByFieldInput!], where: AppBskyEmbedExternalWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyEmbedExternalAggregated!]! 996 + """Returns items before the given cursor""" 997 + before: String 904 998 905 - """Query app.bsky.feed.postgate records""" 906 - appBskyFeedPostgates(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyFeedPostgateSortFieldInput], where: AppBskyFeedPostgateWhereInput): AppBskyFeedPostgateConnection! 999 + """Sort order for the connection""" 1000 + sortBy: [FmTealAlphaFeedPlaySortFieldInput!] 907 1001 908 - """ 909 - Aggregated query for app.bsky.feed.postgate records with GROUP BY support 910 - """ 911 - appBskyFeedPostgatesAggregated(groupBy: [AppBskyFeedPostgateGroupByFieldInput!], where: AppBskyFeedPostgateWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyFeedPostgateAggregated!]! 1002 + """Filter conditions for the query""" 1003 + where: FmTealAlphaFeedPlayWhereInput 1004 + ): FmTealAlphaFeedPlayConnection 912 1005 913 - """Query app.bsky.feed.threadgate records""" 914 - appBskyFeedThreadgates(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyFeedThreadgateSortFieldInput], where: AppBskyFeedThreadgateWhereInput): AppBskyFeedThreadgateConnection! 1006 + """Aggregated query for app.bsky.actor.profile""" 1007 + appBskyActorProfileAggregated( 1008 + """Fields to group by (required)""" 1009 + groupBy: [AppBskyActorProfileGroupByFieldInput!] 915 1010 916 - """ 917 - Aggregated query for app.bsky.feed.threadgate records with GROUP BY support 918 - """ 919 - appBskyFeedThreadgatesAggregated(groupBy: [AppBskyFeedThreadgateGroupByFieldInput!], where: AppBskyFeedThreadgateWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyFeedThreadgateAggregated!]! 1011 + """Filter records before aggregation""" 1012 + where: AppBskyActorProfileWhereInput 920 1013 921 - """Query app.bsky.richtext.facet records""" 922 - appBskyRichtextFacets(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyRichtextFacetSortFieldInput], where: AppBskyRichtextFacetWhereInput): AppBskyRichtextFacetConnection! 1014 + """Order by count (default: desc)""" 1015 + orderBy: AggregationOrderBy 923 1016 924 - """ 925 - Aggregated query for app.bsky.richtext.facet records with GROUP BY support 926 - """ 927 - appBskyRichtextFacetsAggregated(groupBy: [AppBskyRichtextFacetGroupByFieldInput!], where: AppBskyRichtextFacetWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyRichtextFacetAggregated!]! 1017 + """Maximum number of results (default 50, max 1000)""" 1018 + limit: Int 1019 + ): [AppBskyActorProfileAggregated!] 928 1020 929 - """Query app.bsky.actor.profile records""" 930 - appBskyActorProfiles(first: Int, after: String, last: Int, before: String, sortBy: [AppBskyActorProfileSortFieldInput], where: AppBskyActorProfileWhereInput): AppBskyActorProfileConnection! 1021 + """Aggregated query for fm.teal.alpha.feed.play""" 1022 + fmTealAlphaFeedPlayAggregated( 1023 + """Fields to group by (required)""" 1024 + groupBy: [FmTealAlphaFeedPlayGroupByFieldInput!] 931 1025 932 - """ 933 - Aggregated query for app.bsky.actor.profile records with GROUP BY support 934 - """ 935 - appBskyActorProfilesAggregated(groupBy: [AppBskyActorProfileGroupByFieldInput!], where: AppBskyActorProfileWhereInput, orderBy: AggregationOrderBy, limit: Int): [AppBskyActorProfileAggregated!]! 1026 + """Filter records before aggregation""" 1027 + where: FmTealAlphaFeedPlayWhereInput 936 1028 937 - """Query com.atproto.repo.strongRef records""" 938 - comAtprotoRepoStrongRefs(first: Int, after: String, last: Int, before: String, sortBy: [ComAtprotoRepoStrongRefSortFieldInput], where: ComAtprotoRepoStrongRefWhereInput): ComAtprotoRepoStrongRefConnection! 1029 + """Order by count (default: desc)""" 1030 + orderBy: AggregationOrderBy 939 1031 940 - """ 941 - Aggregated query for com.atproto.repo.strongRef records with GROUP BY support 942 - """ 943 - comAtprotoRepoStrongRefsAggregated(groupBy: [ComAtprotoRepoStrongRefGroupByFieldInput!], where: ComAtprotoRepoStrongRefWhereInput, orderBy: AggregationOrderBy, limit: Int): [ComAtprotoRepoStrongRefAggregated!]! 1032 + """Maximum number of results (default 50, max 1000)""" 1033 + limit: Int 1034 + ): [FmTealAlphaFeedPlayAggregated!] 1035 + } 944 1036 945 - """Query fm.teal.alpha.feed.play records""" 946 - fmTealAlphaFeedPlays(first: Int, after: String, last: Int, before: String, sortBy: [FmTealAlphaFeedPlaySortFieldInput], where: FmTealAlphaFeedPlayWhereInput): FmTealAlphaFeedPlayConnection! 1037 + union Record = AppBskyActorProfile | FmTealAlphaFeedPlay 947 1038 948 - """ 949 - Aggregated query for fm.teal.alpha.feed.play records with GROUP BY support 950 - """ 951 - fmTealAlphaFeedPlaysAggregated(groupBy: [FmTealAlphaFeedPlayGroupByFieldInput!], where: FmTealAlphaFeedPlayWhereInput, orderBy: AggregationOrderBy, limit: Int): [FmTealAlphaFeedPlayAggregated!]! 952 - } 953 - 1039 + """Sort direction for query results""" 954 1040 enum SortDirection { 955 - asc 956 - desc 957 - } 1041 + """Ascending order""" 1042 + ASC 958 1043 959 - input StringFilter { 960 - eq: String 961 - in: [String] 962 - contains: String 963 - gt: String 964 - gte: String 965 - lt: String 966 - lte: String 1044 + """Descending order""" 1045 + DESC 967 1046 } 968 1047 1048 + """GraphQL subscription root""" 969 1049 type Subscription { 970 - """Subscribe to app.bsky.feed.postgate record creation events""" 971 - appBskyFeedPostgateCreated: AppBskyFeedPostgate! 972 - 973 - """Subscribe to app.bsky.feed.postgate record update events""" 974 - appBskyFeedPostgateUpdated: AppBskyFeedPostgate! 975 - 976 - """ 977 - Subscribe to app.bsky.feed.postgate record deletion events. Returns the URI of deleted records. 978 - """ 979 - appBskyFeedPostgateDeleted: String! 980 - 981 - """Subscribe to app.bsky.feed.threadgate record creation events""" 982 - appBskyFeedThreadgateCreated: AppBskyFeedThreadgate! 983 - 984 - """Subscribe to app.bsky.feed.threadgate record update events""" 985 - appBskyFeedThreadgateUpdated: AppBskyFeedThreadgate! 986 - 987 - """ 988 - Subscribe to app.bsky.feed.threadgate record deletion events. Returns the URI of deleted records. 989 - """ 990 - appBskyFeedThreadgateDeleted: String! 991 - 992 - """Subscribe to app.bsky.actor.profile record creation events""" 1050 + """Emitted when a new app.bsky.actor.profile record is created""" 993 1051 appBskyActorProfileCreated: AppBskyActorProfile! 994 1052 995 - """Subscribe to app.bsky.actor.profile record update events""" 1053 + """Emitted when a app.bsky.actor.profile record is updated""" 996 1054 appBskyActorProfileUpdated: AppBskyActorProfile! 997 1055 998 - """ 999 - Subscribe to app.bsky.actor.profile record deletion events. Returns the URI of deleted records. 1000 - """ 1001 - appBskyActorProfileDeleted: String! 1056 + """Emitted when a app.bsky.actor.profile record is deleted""" 1057 + appBskyActorProfileDeleted: AppBskyActorProfile! 1002 1058 1003 - """Subscribe to fm.teal.alpha.feed.play record creation events""" 1059 + """Emitted when a new fm.teal.alpha.feed.play record is created""" 1004 1060 fmTealAlphaFeedPlayCreated: FmTealAlphaFeedPlay! 1005 1061 1006 - """Subscribe to fm.teal.alpha.feed.play record update events""" 1062 + """Emitted when a fm.teal.alpha.feed.play record is updated""" 1007 1063 fmTealAlphaFeedPlayUpdated: FmTealAlphaFeedPlay! 1008 1064 1009 - """ 1010 - Subscribe to fm.teal.alpha.feed.play record deletion events. Returns the URI of deleted records. 1011 - """ 1012 - fmTealAlphaFeedPlayDeleted: String! 1013 - } 1014 - 1015 - type SyncResult { 1016 - success: Boolean! 1017 - reposProcessed: Int! 1018 - recordsSynced: Int! 1019 - timedOut: Boolean! 1020 - message: String! 1065 + """Emitted when a fm.teal.alpha.feed.play record is deleted""" 1066 + fmTealAlphaFeedPlayDeleted: FmTealAlphaFeedPlay! 1021 1067 } 1022 1068
+82 -54
src/App.tsx
··· 4 4 usePaginationFragment, 5 5 useSubscription, 6 6 } from "react-relay"; 7 - import { useEffect, useRef, useMemo } from "react"; 7 + import { useEffect, useMemo, useRef } from "react"; 8 8 import type { AppQuery } from "./__generated__/AppQuery.graphql"; 9 9 import type { App_plays$key } from "./__generated__/App_plays.graphql"; 10 10 import type { AppSubscription } from "./__generated__/AppSubscription.graphql"; ··· 39 39 ...ScrobbleChart_data 40 40 } 41 41 `, 42 - queryVariables 42 + queryVariables, 43 43 ); 44 44 45 45 const { data, loadNext, hasNext, isLoadingNext } = usePaginationFragment< ··· 53 53 cursor: { type: "String" } 54 54 count: { type: "Int", defaultValue: 20 } 55 55 ) { 56 - fmTealAlphaFeedPlays( 56 + fmTealAlphaFeedPlay( 57 57 first: $count 58 58 after: $cursor 59 - sortBy: [{ field: playedTime, direction: desc }] 60 - ) @connection(key: "App_fmTealAlphaFeedPlays", filters: ["sortBy"]) { 59 + sortBy: [{ field: playedTime, direction: DESC }] 60 + ) @connection(key: "App_fmTealAlphaFeedPlay", filters: ["sortBy"]) { 61 61 totalCount 62 62 edges { 63 63 node { ··· 68 68 } 69 69 } 70 70 `, 71 - queryData 71 + queryData, 72 72 ); 73 73 74 74 const loadMoreRef = useRef<HTMLDivElement>(null); 75 + const loadNextRef = useRef(loadNext); 76 + const isLoadingRef = useRef(false); 77 + loadNextRef.current = loadNext; 75 78 76 79 // Subscribe to new plays 77 - const subscriptionConfig: GraphQLSubscriptionConfig<AppSubscription> = { 78 - subscription: graphql` 80 + const subscriptionConfig: GraphQLSubscriptionConfig<AppSubscription> = 81 + useMemo(() => ({ 82 + subscription: graphql` 79 83 subscription AppSubscription { 80 84 fmTealAlphaFeedPlayCreated { 81 85 uri ··· 84 88 } 85 89 } 86 90 `, 87 - variables: {}, 88 - updater: (store) => { 89 - const newPlay = store.getRootField("fmTealAlphaFeedPlayCreated"); 90 - if (!newPlay) return; 91 + variables: {}, 92 + updater: (store) => { 93 + const newPlay = store.getRootField("fmTealAlphaFeedPlayCreated"); 94 + if (!newPlay) return; 91 95 92 - const root = store.getRoot(); 93 - const connection = ConnectionHandler.getConnection( 94 - root, 95 - "App_fmTealAlphaFeedPlays", 96 - { sortBy: [{ field: "playedTime", direction: "desc" }] } 97 - ); 96 + // Only add plays from the last 24 hours 97 + const playedTime = newPlay.getValue("playedTime") as string | null; 98 + if (!playedTime) return; 98 99 99 - if (!connection) return; 100 + const playDate = new Date(playedTime); 101 + const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000); 100 102 101 - const edge = ConnectionHandler.createEdge( 102 - store, 103 - connection, 104 - newPlay, 105 - "FmTealAlphaFeedPlayEdge" 106 - ); 103 + if (playDate < cutoff) { 104 + // Play is too old, don't add it to the feed 105 + return; 106 + } 107 107 108 - ConnectionHandler.insertEdgeBefore(connection, edge); 108 + const root = store.getRoot(); 109 + const connection = ConnectionHandler.getConnection( 110 + root, 111 + "App_fmTealAlphaFeedPlay", 112 + { sortBy: [{ field: "playedTime", direction: "DESC" }] }, 113 + ); 109 114 110 - // Update totalCount 111 - const totalCountRecord = root.getLinkedRecord("fmTealAlphaFeedPlays", { 112 - sortBy: [{ field: "playedTime", direction: "desc" }], 113 - }); 114 - if (totalCountRecord) { 115 - const currentCount = totalCountRecord.getValue("totalCount") as number; 116 - if (typeof currentCount === "number") { 117 - totalCountRecord.setValue(currentCount + 1, "totalCount"); 115 + if (!connection) return; 116 + 117 + const edge = ConnectionHandler.createEdge( 118 + store, 119 + connection, 120 + newPlay, 121 + "FmTealAlphaFeedPlayEdge", 122 + ); 123 + 124 + ConnectionHandler.insertEdgeBefore(connection, edge); 125 + 126 + // Update totalCount 127 + const totalCountRecord = root.getLinkedRecord("fmTealAlphaFeedPlay", { 128 + sortBy: [{ field: "playedTime", direction: "DESC" }], 129 + }); 130 + if (totalCountRecord) { 131 + const currentCount = totalCountRecord.getValue( 132 + "totalCount", 133 + ) as number; 134 + if (typeof currentCount === "number") { 135 + totalCountRecord.setValue(currentCount + 1, "totalCount"); 136 + } 118 137 } 119 - } 120 - }, 121 - }; 138 + }, 139 + }), []); 122 140 123 141 useSubscription(subscriptionConfig); 124 142 ··· 126 144 window.scrollTo(0, 0); 127 145 }, []); 128 146 129 - const plays = 130 - data?.fmTealAlphaFeedPlays?.edges 131 - ?.map((edge) => edge.node) 132 - .filter((n) => n != null) || []; 147 + const plays = data?.fmTealAlphaFeedPlay?.edges 148 + ?.map((edge) => edge.node) 149 + .filter((n) => n != null) || []; 150 + 151 + // Sync the loading ref with isLoadingNext 152 + useEffect(() => { 153 + isLoadingRef.current = isLoadingNext; 154 + }, [isLoadingNext]); 133 155 134 156 useEffect(() => { 135 157 if (!loadMoreRef.current || !hasNext) return; 136 158 159 + const element = loadMoreRef.current; 137 160 const observer = new IntersectionObserver( 138 161 (entries) => { 139 - if (entries[0].isIntersecting && hasNext && !isLoadingNext) { 140 - loadNext(20); 162 + if (entries[0].isIntersecting && !isLoadingRef.current) { 163 + isLoadingRef.current = true; 164 + loadNextRef.current(20); 141 165 } 142 166 }, 143 - { threshold: 0.1 } 167 + { threshold: 0.1 }, 144 168 ); 145 169 146 - observer.observe(loadMoreRef.current); 170 + observer.observe(element); 147 171 148 172 return () => observer.disconnect(); 149 - }, [hasNext, isLoadingNext, loadNext]); 173 + }, [hasNext]); 150 174 151 175 // Group plays by date 152 176 const groupedPlays: { date: string; plays: typeof plays }[] = []; ··· 174 198 <Layout headerChart={<ScrobbleChart queryRef={queryData} />}> 175 199 <div className="mb-8"> 176 200 <p className="text-xs text-zinc-500 uppercase tracking-wider"> 177 - {data?.fmTealAlphaFeedPlays?.totalCount?.toLocaleString()} scrobbles 201 + {data?.fmTealAlphaFeedPlay?.totalCount?.toLocaleString()} scrobbles 178 202 </p> 179 203 </div> 180 204 ··· 195 219 196 220 {hasNext && ( 197 221 <div ref={loadMoreRef} className="py-12 text-center"> 198 - {isLoadingNext ? ( 199 - <p className="text-xs text-zinc-600 uppercase tracking-wider"> 200 - Loading... 201 - </p> 202 - ) : ( 203 - <p className="text-xs text-zinc-700 uppercase tracking-wider">ยท</p> 204 - )} 222 + {isLoadingNext 223 + ? ( 224 + <p className="text-xs text-zinc-600 uppercase tracking-wider"> 225 + Loading... 226 + </p> 227 + ) 228 + : ( 229 + <p className="text-xs text-zinc-700 uppercase tracking-wider"> 230 + ยท 231 + </p> 232 + )} 205 233 </div> 206 234 )} 207 235 </Layout>
+40 -26
src/Profile.tsx
··· 1 1 import { graphql, useLazyLoadQuery, usePaginationFragment } from "react-relay"; 2 - import { useParams, Link } from "react-router-dom"; 3 - import { useEffect, useRef, useMemo } from "react"; 2 + import { Link, useParams } from "react-router-dom"; 3 + import { useEffect, useMemo, useRef } from "react"; 4 4 import type { ProfileQuery as ProfileQueryType } from "./__generated__/ProfileQuery.graphql"; 5 5 import type { Profile_plays$key } from "./__generated__/Profile_plays.graphql"; 6 6 import TrackItem from "./TrackItem"; ··· 33 33 ...ScrobbleChart_data 34 34 } 35 35 `, 36 - queryVariables 36 + queryVariables, 37 37 ); 38 38 39 39 const { data, loadNext, hasNext, isLoadingNext } = usePaginationFragment< ··· 48 48 count: { type: "Int", defaultValue: 20 } 49 49 where: { type: "FmTealAlphaFeedPlayWhereInput!" } 50 50 ) { 51 - fmTealAlphaFeedPlays( 51 + fmTealAlphaFeedPlay( 52 52 first: $count 53 53 after: $cursor 54 - sortBy: [{ field: playedTime, direction: desc }] 54 + sortBy: [{ field: playedTime, direction: DESC }] 55 55 where: $where 56 56 ) 57 57 @connection( 58 - key: "Profile_fmTealAlphaFeedPlays" 58 + key: "Profile_fmTealAlphaFeedPlay" 59 59 filters: ["where", "sortBy"] 60 60 ) { 61 61 totalCount ··· 63 63 node { 64 64 ...TrackItem_play 65 65 actorHandle 66 - appBskyActorProfile { 66 + appBskyActorProfileByDid { 67 67 displayName 68 68 description 69 69 avatar { ··· 75 75 } 76 76 } 77 77 `, 78 - queryData 78 + queryData, 79 79 ); 80 80 81 81 const loadMoreRef = useRef<HTMLDivElement>(null); 82 82 83 83 const plays = useMemo( 84 - () => data?.fmTealAlphaFeedPlays?.edges?.map((edge) => edge.node).filter((n) => n != null) || [], 85 - [data?.fmTealAlphaFeedPlays?.edges] 84 + () => 85 + data?.fmTealAlphaFeedPlay?.edges?.map((edge) => edge.node).filter((n) => 86 + n != null 87 + ) || [], 88 + [data?.fmTealAlphaFeedPlay?.edges], 86 89 ); 87 - const profile = plays?.[0]?.appBskyActorProfile; 90 + const profile = plays?.[0]?.appBskyActorProfileByDid; 88 91 89 92 useEffect(() => { 90 93 window.scrollTo(0, 0); ··· 99 102 loadNext(20); 100 103 } 101 104 }, 102 - { threshold: 0.1 } 105 + { threshold: 0.1 }, 103 106 ); 104 107 105 108 observer.observe(loadMoreRef.current); ··· 142 145 </div> 143 146 144 147 <div className="mb-8"> 145 - <h2 className="text-sm font-medium uppercase tracking-wider text-zinc-400 mb-2">Recent Tracks</h2> 148 + <h2 className="text-sm font-medium uppercase tracking-wider text-zinc-400 mb-2"> 149 + Recent Tracks 150 + </h2> 146 151 <p className="text-xs text-zinc-500 uppercase tracking-wider"> 147 - {(data?.fmTealAlphaFeedPlays?.totalCount ?? 0).toLocaleString()} scrobbles 152 + {(data?.fmTealAlphaFeedPlay?.totalCount ?? 0).toLocaleString()}{" "} 153 + scrobbles 148 154 </p> 149 155 </div> 150 156 151 157 <div className="space-y-1"> 152 - {plays && plays.length > 0 ? ( 153 - plays.map((play, index) => <TrackItem key={index} play={play} />) 154 - ) : ( 155 - <p className="text-zinc-600 text-center py-8 text-xs uppercase tracking-wider"> 156 - No tracks found for this user 157 - </p> 158 - )} 158 + {plays && plays.length > 0 159 + ? ( 160 + plays.map((play, index) => <TrackItem key={index} play={play} />) 161 + ) 162 + : ( 163 + <p className="text-zinc-600 text-center py-8 text-xs uppercase tracking-wider"> 164 + No tracks found for this user 165 + </p> 166 + )} 159 167 </div> 160 168 161 169 {hasNext && ( 162 170 <div ref={loadMoreRef} className="py-12 text-center"> 163 - {isLoadingNext ? ( 164 - <p className="text-xs text-zinc-600 uppercase tracking-wider">Loading...</p> 165 - ) : ( 166 - <p className="text-xs text-zinc-700 uppercase tracking-wider">ยท</p> 167 - )} 171 + {isLoadingNext 172 + ? ( 173 + <p className="text-xs text-zinc-600 uppercase tracking-wider"> 174 + Loading... 175 + </p> 176 + ) 177 + : ( 178 + <p className="text-xs text-zinc-700 uppercase tracking-wider"> 179 + ยท 180 + </p> 181 + )} 168 182 </div> 169 183 )} 170 184 </div>
+23 -21
src/ScrobbleChart.tsx
··· 10 10 const data = useFragment( 11 11 graphql` 12 12 fragment ScrobbleChart_data on Query { 13 - chartData: fmTealAlphaFeedPlaysAggregated( 14 - groupBy: [{ field: playedTime, interval: day }] 13 + chartData: fmTealAlphaFeedPlayAggregated( 14 + groupBy: [{ field: playedTime, interval: DAY }] 15 15 where: $chartWhere 16 16 limit: 90 17 17 ) { ··· 20 20 } 21 21 } 22 22 `, 23 - queryRef 23 + queryRef, 24 24 ); 25 25 26 26 const chartData = useMemo(() => { ··· 29 29 // Convert aggregated data to chart format 30 30 const aggregated = data.chartData.map((item) => { 31 31 // playedTime comes back as '2025-08-03 00:00:00', extract just the date part 32 - const date = item.playedTime ? item.playedTime.split(' ')[0] : ""; 32 + const date = item.playedTime ? item.playedTime.split(" ")[0] : ""; 33 33 return { 34 34 date, 35 35 count: item.count, ··· 71 71 // Generate points for the line 72 72 const points = chartData.map((d, i) => { 73 73 const x = padding.left + (i / (chartData.length - 1)) * chartWidth; 74 - const y = padding.top + chartHeight - ((d.count - minCount) / range) * chartHeight; 74 + const y = padding.top + chartHeight - 75 + ((d.count - minCount) / range) * chartHeight; 75 76 return `${x},${y}`; 76 77 }).join(" "); 77 78 ··· 80 81 `${padding.left},${padding.top + chartHeight}`, 81 82 ...chartData.map((d, i) => { 82 83 const x = padding.left + (i / (chartData.length - 1)) * chartWidth; 83 - const y = padding.top + chartHeight - ((d.count - minCount) / range) * chartHeight; 84 + const y = padding.top + chartHeight - 85 + ((d.count - minCount) / range) * chartHeight; 84 86 return `${x},${y}`; 85 87 }), 86 88 `${padding.left + chartWidth},${padding.top + chartHeight}`, ··· 92 94 className="w-full h-full" 93 95 preserveAspectRatio="none" 94 96 > 95 - {/* Area fill */} 96 - <polygon 97 - points={areaPoints} 98 - fill="rgb(139 92 246 / 0.1)" 99 - stroke="none" 100 - /> 97 + {/* Area fill */} 98 + <polygon 99 + points={areaPoints} 100 + fill="rgb(139 92 246 / 0.1)" 101 + stroke="none" 102 + /> 101 103 102 - {/* Line */} 103 - <polyline 104 - points={points} 105 - fill="none" 106 - stroke="rgb(139 92 246)" 107 - strokeWidth="1.5" 108 - strokeLinecap="round" 109 - strokeLinejoin="round" 110 - /> 104 + {/* Line */} 105 + <polyline 106 + points={points} 107 + fill="none" 108 + stroke="rgb(139 92 246)" 109 + strokeWidth="1.5" 110 + strokeLinecap="round" 111 + strokeLinejoin="round" 112 + /> 111 113 </svg> 112 114 ); 113 115 }
+4 -4
src/TopAlbums.tsx
··· 12 12 const data = useLazyLoadQuery<TopAlbumsQuery>( 13 13 graphql` 14 14 query TopAlbumsQuery($where: FmTealAlphaFeedPlayWhereInput) { 15 - fmTealAlphaFeedPlaysAggregated( 15 + fmTealAlphaFeedPlayAggregated( 16 16 groupBy: [{ field: releaseMbId }, { field: releaseName }, { field: artists }] 17 - orderBy: { count: desc } 17 + orderBy: { count: DESC } 18 18 limit: 100 19 19 where: $where 20 20 ) { ··· 26 26 } 27 27 `, 28 28 queryVariables, 29 - { fetchKey: period || "all", fetchPolicy: "store-or-network" } 29 + { fetchKey: period || "all", fetchPolicy: "store-or-network" }, 30 30 ); 31 31 32 - const albums = [...(data.fmTealAlphaFeedPlaysAggregated || [])]; 32 + const albums = [...(data.fmTealAlphaFeedPlayAggregated || [])]; 33 33 34 34 // Deduplicate by release name, keeping the one with highest count 35 35 // Prefer entries with artist data
+4 -4
src/TopTracks.tsx
··· 12 12 const data = useLazyLoadQuery<TopTracksQuery>( 13 13 graphql` 14 14 query TopTracksQuery($where: FmTealAlphaFeedPlayWhereInput) { 15 - fmTealAlphaFeedPlaysAggregated( 15 + fmTealAlphaFeedPlayAggregated( 16 16 groupBy: [{ field: trackName }, { field: releaseMbId }, { field: artists }] 17 - orderBy: { count: desc } 17 + orderBy: { count: DESC } 18 18 limit: 50 19 19 where: $where 20 20 ) { ··· 26 26 } 27 27 `, 28 28 queryVariables, 29 - { fetchKey: period || "all", fetchPolicy: "store-or-network" } 29 + { fetchKey: period || "all", fetchPolicy: "store-or-network" }, 30 30 ); 31 31 32 - const tracks = data.fmTealAlphaFeedPlaysAggregated || []; 32 + const tracks = data.fmTealAlphaFeedPlayAggregated || []; 33 33 const maxCount = tracks.length > 0 ? tracks[0].count : 0; 34 34 35 35 return (
+10 -5
src/TrackItem.tsx
··· 13 13 fragment TrackItem_play on FmTealAlphaFeedPlay { 14 14 trackName 15 15 playedTime 16 - artists 16 + artists { 17 + artistName 18 + } 17 19 releaseName 18 20 releaseMbId 19 21 actorHandle 20 22 musicServiceBaseDomain 21 - appBskyActorProfile { 23 + appBskyActorProfileByDid { 22 24 displayName 23 25 } 24 26 } 25 27 `, 26 - play 28 + play, 27 29 ); 28 30 29 31 return ( 30 32 <div className="group py-3 px-4 hover:bg-zinc-900/50 transition-colors"> 31 33 <div className="flex items-center gap-4"> 32 34 <div className="flex-shrink-0"> 33 - <AlbumArt releaseMbId={data.releaseMbId} alt={`${data.trackName} album art`} /> 35 + <AlbumArt 36 + releaseMbId={data.releaseMbId} 37 + alt={`${data.trackName} album art`} 38 + /> 34 39 </div> 35 40 36 41 <div className="flex-1 min-w-0 grid grid-cols-2 gap-4"> ··· 51 56 <p className="text-xs text-zinc-500 truncate"> 52 57 {Array.isArray(data.artists) 53 58 ? data.artists.map((a) => a.artistName).join(", ") 54 - : data.artists} 59 + : "Unknown Artist"} 55 60 </p> 56 61 </div> 57 62
+21 -10
src/__generated__/AppPaginationQuery.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<38f32c1e1448eb48251113a07e781789>> 2 + * @generated SignedSource<<783e2832122c1d8f7bb41d1fe78f9ef1>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 51 51 "name": "sortBy", 52 52 "value": [ 53 53 { 54 - "direction": "desc", 54 + "direction": "DESC", 55 55 "field": "playedTime" 56 56 } 57 57 ] ··· 95 95 "args": (v1/*: any*/), 96 96 "concreteType": "FmTealAlphaFeedPlayConnection", 97 97 "kind": "LinkedField", 98 - "name": "fmTealAlphaFeedPlays", 98 + "name": "fmTealAlphaFeedPlay", 99 99 "plural": false, 100 100 "selections": [ 101 101 { ··· 138 138 { 139 139 "alias": null, 140 140 "args": null, 141 - "kind": "ScalarField", 141 + "concreteType": "FmTealAlphaFeedDefsArtist", 142 + "kind": "LinkedField", 142 143 "name": "artists", 144 + "plural": true, 145 + "selections": [ 146 + { 147 + "alias": null, 148 + "args": null, 149 + "kind": "ScalarField", 150 + "name": "artistName", 151 + "storageKey": null 152 + } 153 + ], 143 154 "storageKey": null 144 155 }, 145 156 { ··· 175 186 "args": null, 176 187 "concreteType": "AppBskyActorProfile", 177 188 "kind": "LinkedField", 178 - "name": "appBskyActorProfile", 189 + "name": "appBskyActorProfileByDid", 179 190 "plural": false, 180 191 "selections": [ 181 192 { ··· 243 254 "sortBy" 244 255 ], 245 256 "handle": "connection", 246 - "key": "App_fmTealAlphaFeedPlays", 257 + "key": "App_fmTealAlphaFeedPlay", 247 258 "kind": "LinkedHandle", 248 - "name": "fmTealAlphaFeedPlays" 259 + "name": "fmTealAlphaFeedPlay" 249 260 } 250 261 ] 251 262 }, 252 263 "params": { 253 - "cacheID": "cb24b99f8b849bdfc642275cfd4df3fe", 264 + "cacheID": "dac482c1a09c5930d955d9805c6dfb8d", 254 265 "id": null, 255 266 "metadata": {}, 256 267 "name": "AppPaginationQuery", 257 268 "operationKind": "query", 258 - "text": "query AppPaginationQuery(\n $count: Int = 20\n $cursor: String\n) {\n ...App_plays_1G22uz\n}\n\nfragment App_plays_1G22uz on Query {\n fmTealAlphaFeedPlays(first: $count, after: $cursor, sortBy: [{field: playedTime, direction: desc}]) {\n totalCount\n edges {\n node {\n playedTime\n ...TrackItem_play\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfile {\n displayName\n }\n}\n" 269 + "text": "query AppPaginationQuery(\n $count: Int = 20\n $cursor: String\n) {\n ...App_plays_1G22uz\n}\n\nfragment App_plays_1G22uz on Query {\n fmTealAlphaFeedPlay(first: $count, after: $cursor, sortBy: [{field: playedTime, direction: DESC}]) {\n totalCount\n edges {\n node {\n playedTime\n ...TrackItem_play\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists {\n artistName\n }\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfileByDid {\n displayName\n }\n}\n" 259 270 } 260 271 }; 261 272 })(); 262 273 263 - (node as any).hash = "1e73fa97ccff20071e5a3fba0f00b48c"; 274 + (node as any).hash = "b793d066128b9e7d52d3209bd3e14afe"; 264 275 265 276 export default node;
+44 -49
src/__generated__/AppQuery.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<bd4d57eff6a192efe2535389231fe37e>> 2 + * @generated SignedSource<<fa406caeea45379cd74ae946fcf13cc3>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 11 11 import { ConcreteRequest } from 'relay-runtime'; 12 12 import { FragmentRefs } from "relay-runtime"; 13 13 export type FmTealAlphaFeedPlayWhereInput = { 14 - actorHandle?: StringFilter | null | undefined; 15 - artistMbIds?: StringFilter | null | undefined; 16 - artistNames?: StringFilter | null | undefined; 17 - artists?: StringFilter | null | undefined; 18 - cid?: StringFilter | null | undefined; 19 - collection?: StringFilter | null | undefined; 20 - did?: StringFilter | null | undefined; 21 - duration?: IntFilter | null | undefined; 22 - indexedAt?: DateTimeFilter | null | undefined; 23 - isrc?: StringFilter | null | undefined; 24 - musicServiceBaseDomain?: StringFilter | null | undefined; 25 - originUrl?: StringFilter | null | undefined; 26 - playedTime?: StringFilter | null | undefined; 27 - recordingMbId?: StringFilter | null | undefined; 28 - releaseMbId?: StringFilter | null | undefined; 29 - releaseName?: StringFilter | null | undefined; 30 - submissionClientAgent?: StringFilter | null | undefined; 31 - trackMbId?: StringFilter | null | undefined; 32 - trackName?: StringFilter | null | undefined; 33 - uri?: StringFilter | null | undefined; 14 + actorHandle?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 15 + and?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 16 + cid?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 17 + collection?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 18 + did?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 19 + duration?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 20 + indexedAt?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 21 + isrc?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 22 + musicServiceBaseDomain?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 23 + or?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 24 + originUrl?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 25 + playedTime?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 26 + recordingMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 27 + releaseMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 28 + releaseName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 29 + submissionClientAgent?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 30 + trackMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 31 + trackName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 32 + uri?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 34 33 }; 35 - export type DateTimeFilter = { 36 - eq?: string | null | undefined; 37 - gt?: string | null | undefined; 38 - gte?: string | null | undefined; 39 - lt?: string | null | undefined; 40 - lte?: string | null | undefined; 41 - }; 42 - export type StringFilter = { 34 + export type FmTealAlphaFeedPlayFieldCondition = { 43 35 contains?: string | null | undefined; 44 36 eq?: string | null | undefined; 45 37 gt?: string | null | undefined; 46 38 gte?: string | null | undefined; 47 - in?: ReadonlyArray<string | null | undefined> | null | undefined; 39 + in?: ReadonlyArray<string> | null | undefined; 48 40 lt?: string | null | undefined; 49 41 lte?: string | null | undefined; 50 42 }; 51 - export type IntFilter = { 52 - eq?: number | null | undefined; 53 - gt?: number | null | undefined; 54 - gte?: number | null | undefined; 55 - in?: ReadonlyArray<number | null | undefined> | null | undefined; 56 - lt?: number | null | undefined; 57 - lte?: number | null | undefined; 58 - }; 59 43 export type AppQuery$variables = { 60 44 chartWhere: FmTealAlphaFeedPlayWhereInput; 61 45 }; ··· 86 70 "name": "sortBy", 87 71 "value": [ 88 72 { 89 - "direction": "desc", 73 + "direction": "DESC", 90 74 "field": "playedTime" 91 75 } 92 76 ] ··· 131 115 "args": (v1/*: any*/), 132 116 "concreteType": "FmTealAlphaFeedPlayConnection", 133 117 "kind": "LinkedField", 134 - "name": "fmTealAlphaFeedPlays", 118 + "name": "fmTealAlphaFeedPlay", 135 119 "plural": false, 136 120 "selections": [ 137 121 { ··· 168 152 { 169 153 "alias": null, 170 154 "args": null, 171 - "kind": "ScalarField", 155 + "concreteType": "FmTealAlphaFeedDefsArtist", 156 + "kind": "LinkedField", 172 157 "name": "artists", 158 + "plural": true, 159 + "selections": [ 160 + { 161 + "alias": null, 162 + "args": null, 163 + "kind": "ScalarField", 164 + "name": "artistName", 165 + "storageKey": null 166 + } 167 + ], 173 168 "storageKey": null 174 169 }, 175 170 { ··· 205 200 "args": null, 206 201 "concreteType": "AppBskyActorProfile", 207 202 "kind": "LinkedField", 208 - "name": "appBskyActorProfile", 203 + "name": "appBskyActorProfileByDid", 209 204 "plural": false, 210 205 "selections": [ 211 206 { ··· 264 259 "storageKey": null 265 260 } 266 261 ], 267 - "storageKey": "fmTealAlphaFeedPlays(first:20,sortBy:[{\"direction\":\"desc\",\"field\":\"playedTime\"}])" 262 + "storageKey": "fmTealAlphaFeedPlay(first:20,sortBy:[{\"direction\":\"DESC\",\"field\":\"playedTime\"}])" 268 263 }, 269 264 { 270 265 "alias": null, ··· 273 268 "sortBy" 274 269 ], 275 270 "handle": "connection", 276 - "key": "App_fmTealAlphaFeedPlays", 271 + "key": "App_fmTealAlphaFeedPlay", 277 272 "kind": "LinkedHandle", 278 - "name": "fmTealAlphaFeedPlays" 273 + "name": "fmTealAlphaFeedPlay" 279 274 }, 280 275 { 281 276 "alias": "chartData", ··· 286 281 "value": [ 287 282 { 288 283 "field": "playedTime", 289 - "interval": "day" 284 + "interval": "DAY" 290 285 } 291 286 ] 292 287 }, ··· 303 298 ], 304 299 "concreteType": "FmTealAlphaFeedPlayAggregated", 305 300 "kind": "LinkedField", 306 - "name": "fmTealAlphaFeedPlaysAggregated", 301 + "name": "fmTealAlphaFeedPlayAggregated", 307 302 "plural": true, 308 303 "selections": [ 309 304 (v2/*: any*/), ··· 320 315 ] 321 316 }, 322 317 "params": { 323 - "cacheID": "038b79e3af13c34df9bfca055c5f7829", 318 + "cacheID": "3793b7efac382baa6447beb922658c23", 324 319 "id": null, 325 320 "metadata": {}, 326 321 "name": "AppQuery", 327 322 "operationKind": "query", 328 - "text": "query AppQuery(\n $chartWhere: FmTealAlphaFeedPlayWhereInput!\n) {\n ...App_plays\n ...ScrobbleChart_data\n}\n\nfragment App_plays on Query {\n fmTealAlphaFeedPlays(first: 20, sortBy: [{field: playedTime, direction: desc}]) {\n totalCount\n edges {\n node {\n playedTime\n ...TrackItem_play\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment ScrobbleChart_data on Query {\n chartData: fmTealAlphaFeedPlaysAggregated(groupBy: [{field: playedTime, interval: day}], where: $chartWhere, limit: 90) {\n playedTime\n count\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfile {\n displayName\n }\n}\n" 323 + "text": "query AppQuery(\n $chartWhere: FmTealAlphaFeedPlayWhereInput!\n) {\n ...App_plays\n ...ScrobbleChart_data\n}\n\nfragment App_plays on Query {\n fmTealAlphaFeedPlay(first: 20, sortBy: [{field: playedTime, direction: DESC}]) {\n totalCount\n edges {\n node {\n playedTime\n ...TrackItem_play\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment ScrobbleChart_data on Query {\n chartData: fmTealAlphaFeedPlayAggregated(groupBy: [{field: playedTime, interval: DAY}], where: $chartWhere, limit: 90) {\n playedTime\n count\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists {\n artistName\n }\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfileByDid {\n displayName\n }\n}\n" 329 324 } 330 325 }; 331 326 })();
+17 -6
src/__generated__/AppSubscription.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<0e4c25e0e4257b2c7042e374f3568241>> 2 + * @generated SignedSource<<896a9c63784bd14529042a1cb0adfd64>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 14 14 export type AppSubscription$data = { 15 15 readonly fmTealAlphaFeedPlayCreated: { 16 16 readonly playedTime: string | null | undefined; 17 - readonly uri: string; 17 + readonly uri: string | null | undefined; 18 18 readonly " $fragmentSpreads": FragmentRefs<"TrackItem_play">; 19 19 }; 20 20 }; ··· 93 93 { 94 94 "alias": null, 95 95 "args": null, 96 - "kind": "ScalarField", 96 + "concreteType": "FmTealAlphaFeedDefsArtist", 97 + "kind": "LinkedField", 97 98 "name": "artists", 99 + "plural": true, 100 + "selections": [ 101 + { 102 + "alias": null, 103 + "args": null, 104 + "kind": "ScalarField", 105 + "name": "artistName", 106 + "storageKey": null 107 + } 108 + ], 98 109 "storageKey": null 99 110 }, 100 111 { ··· 130 141 "args": null, 131 142 "concreteType": "AppBskyActorProfile", 132 143 "kind": "LinkedField", 133 - "name": "appBskyActorProfile", 144 + "name": "appBskyActorProfileByDid", 134 145 "plural": false, 135 146 "selections": [ 136 147 { ··· 149 160 ] 150 161 }, 151 162 "params": { 152 - "cacheID": "d2419c5bef1474c19f75ee5b97062013", 163 + "cacheID": "15e882ff59aeffce82a48611e02dbe63", 153 164 "id": null, 154 165 "metadata": {}, 155 166 "name": "AppSubscription", 156 167 "operationKind": "subscription", 157 - "text": "subscription AppSubscription {\n fmTealAlphaFeedPlayCreated {\n uri\n playedTime\n ...TrackItem_play\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfile {\n displayName\n }\n}\n" 168 + "text": "subscription AppSubscription {\n fmTealAlphaFeedPlayCreated {\n uri\n playedTime\n ...TrackItem_play\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists {\n artistName\n }\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfileByDid {\n displayName\n }\n}\n" 158 169 } 159 170 }; 160 171 })();
+10 -10
src/__generated__/App_plays.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<ba0bacb4e016f0edbea67013c8694b23>> 2 + * @generated SignedSource<<3266d35506946a9879921e682d9a0b8a>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 11 11 import { ReaderFragment } from 'relay-runtime'; 12 12 import { FragmentRefs } from "relay-runtime"; 13 13 export type App_plays$data = { 14 - readonly fmTealAlphaFeedPlays: { 14 + readonly fmTealAlphaFeedPlay: { 15 15 readonly edges: ReadonlyArray<{ 16 16 readonly node: { 17 17 readonly playedTime: string | null | undefined; 18 18 readonly " $fragmentSpreads": FragmentRefs<"TrackItem_play">; 19 19 }; 20 20 }>; 21 - readonly totalCount: number; 22 - }; 21 + readonly totalCount: number | null | undefined; 22 + } | null | undefined; 23 23 readonly " $fragmentType": "App_plays"; 24 24 }; 25 25 export type App_plays$key = { ··· 31 31 32 32 const node: ReaderFragment = (function(){ 33 33 var v0 = [ 34 - "fmTealAlphaFeedPlays" 34 + "fmTealAlphaFeedPlay" 35 35 ]; 36 36 return { 37 37 "argumentDefinitions": [ ··· 72 72 "name": "App_plays", 73 73 "selections": [ 74 74 { 75 - "alias": "fmTealAlphaFeedPlays", 75 + "alias": "fmTealAlphaFeedPlay", 76 76 "args": [ 77 77 { 78 78 "kind": "Literal", 79 79 "name": "sortBy", 80 80 "value": [ 81 81 { 82 - "direction": "desc", 82 + "direction": "DESC", 83 83 "field": "playedTime" 84 84 } 85 85 ] ··· 87 87 ], 88 88 "concreteType": "FmTealAlphaFeedPlayConnection", 89 89 "kind": "LinkedField", 90 - "name": "__App_fmTealAlphaFeedPlays_connection", 90 + "name": "__App_fmTealAlphaFeedPlay_connection", 91 91 "plural": false, 92 92 "selections": [ 93 93 { ··· 171 171 "storageKey": null 172 172 } 173 173 ], 174 - "storageKey": "__App_fmTealAlphaFeedPlays_connection(sortBy:[{\"direction\":\"desc\",\"field\":\"playedTime\"}])" 174 + "storageKey": "__App_fmTealAlphaFeedPlay_connection(sortBy:[{\"direction\":\"DESC\",\"field\":\"playedTime\"}])" 175 175 } 176 176 ], 177 177 "type": "Query", ··· 179 179 }; 180 180 })(); 181 181 182 - (node as any).hash = "1e73fa97ccff20071e5a3fba0f00b48c"; 182 + (node as any).hash = "b793d066128b9e7d52d3209bd3e14afe"; 183 183 184 184 export default node;
+42 -47
src/__generated__/ProfilePaginationQuery.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<05e7a8d8804cbbe062ff7dce37522623>> 2 + * @generated SignedSource<<39639d8abd772effa21efdf069699bf6>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 11 11 import { ConcreteRequest } from 'relay-runtime'; 12 12 import { FragmentRefs } from "relay-runtime"; 13 13 export type FmTealAlphaFeedPlayWhereInput = { 14 - actorHandle?: StringFilter | null | undefined; 15 - artistMbIds?: StringFilter | null | undefined; 16 - artistNames?: StringFilter | null | undefined; 17 - artists?: StringFilter | null | undefined; 18 - cid?: StringFilter | null | undefined; 19 - collection?: StringFilter | null | undefined; 20 - did?: StringFilter | null | undefined; 21 - duration?: IntFilter | null | undefined; 22 - indexedAt?: DateTimeFilter | null | undefined; 23 - isrc?: StringFilter | null | undefined; 24 - musicServiceBaseDomain?: StringFilter | null | undefined; 25 - originUrl?: StringFilter | null | undefined; 26 - playedTime?: StringFilter | null | undefined; 27 - recordingMbId?: StringFilter | null | undefined; 28 - releaseMbId?: StringFilter | null | undefined; 29 - releaseName?: StringFilter | null | undefined; 30 - submissionClientAgent?: StringFilter | null | undefined; 31 - trackMbId?: StringFilter | null | undefined; 32 - trackName?: StringFilter | null | undefined; 33 - uri?: StringFilter | null | undefined; 14 + actorHandle?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 15 + and?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 16 + cid?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 17 + collection?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 18 + did?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 19 + duration?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 20 + indexedAt?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 21 + isrc?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 22 + musicServiceBaseDomain?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 23 + or?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 24 + originUrl?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 25 + playedTime?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 26 + recordingMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 27 + releaseMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 28 + releaseName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 29 + submissionClientAgent?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 30 + trackMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 31 + trackName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 32 + uri?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 34 33 }; 35 - export type DateTimeFilter = { 36 - eq?: string | null | undefined; 37 - gt?: string | null | undefined; 38 - gte?: string | null | undefined; 39 - lt?: string | null | undefined; 40 - lte?: string | null | undefined; 41 - }; 42 - export type StringFilter = { 34 + export type FmTealAlphaFeedPlayFieldCondition = { 43 35 contains?: string | null | undefined; 44 36 eq?: string | null | undefined; 45 37 gt?: string | null | undefined; 46 38 gte?: string | null | undefined; 47 - in?: ReadonlyArray<string | null | undefined> | null | undefined; 39 + in?: ReadonlyArray<string> | null | undefined; 48 40 lt?: string | null | undefined; 49 41 lte?: string | null | undefined; 50 42 }; 51 - export type IntFilter = { 52 - eq?: number | null | undefined; 53 - gt?: number | null | undefined; 54 - gte?: number | null | undefined; 55 - in?: ReadonlyArray<number | null | undefined> | null | undefined; 56 - lt?: number | null | undefined; 57 - lte?: number | null | undefined; 58 - }; 59 43 export type ProfilePaginationQuery$variables = { 60 44 count?: number | null | undefined; 61 45 cursor?: string | null | undefined; ··· 108 92 "name": "sortBy", 109 93 "value": [ 110 94 { 111 - "direction": "desc", 95 + "direction": "DESC", 112 96 "field": "playedTime" 113 97 } 114 98 ] ··· 154 138 "args": (v2/*: any*/), 155 139 "concreteType": "FmTealAlphaFeedPlayConnection", 156 140 "kind": "LinkedField", 157 - "name": "fmTealAlphaFeedPlays", 141 + "name": "fmTealAlphaFeedPlay", 158 142 "plural": false, 159 143 "selections": [ 160 144 { ··· 197 181 { 198 182 "alias": null, 199 183 "args": null, 200 - "kind": "ScalarField", 184 + "concreteType": "FmTealAlphaFeedDefsArtist", 185 + "kind": "LinkedField", 201 186 "name": "artists", 187 + "plural": true, 188 + "selections": [ 189 + { 190 + "alias": null, 191 + "args": null, 192 + "kind": "ScalarField", 193 + "name": "artistName", 194 + "storageKey": null 195 + } 196 + ], 202 197 "storageKey": null 203 198 }, 204 199 { ··· 234 229 "args": null, 235 230 "concreteType": "AppBskyActorProfile", 236 231 "kind": "LinkedField", 237 - "name": "appBskyActorProfile", 232 + "name": "appBskyActorProfileByDid", 238 233 "plural": false, 239 234 "selections": [ 240 235 { ··· 334 329 "sortBy" 335 330 ], 336 331 "handle": "connection", 337 - "key": "Profile_fmTealAlphaFeedPlays", 332 + "key": "Profile_fmTealAlphaFeedPlay", 338 333 "kind": "LinkedHandle", 339 - "name": "fmTealAlphaFeedPlays" 334 + "name": "fmTealAlphaFeedPlay" 340 335 } 341 336 ] 342 337 }, 343 338 "params": { 344 - "cacheID": "72ce84bf8cc8ac016e19ca462a2f7b70", 339 + "cacheID": "4da0ee226512aceadce3210332ed4766", 345 340 "id": null, 346 341 "metadata": {}, 347 342 "name": "ProfilePaginationQuery", 348 343 "operationKind": "query", 349 - "text": "query ProfilePaginationQuery(\n $count: Int = 20\n $cursor: String\n $where: FmTealAlphaFeedPlayWhereInput!\n) {\n ...Profile_plays_mjR8k\n}\n\nfragment Profile_plays_mjR8k on Query {\n fmTealAlphaFeedPlays(first: $count, after: $cursor, sortBy: [{field: playedTime, direction: desc}], where: $where) {\n totalCount\n edges {\n node {\n ...TrackItem_play\n actorHandle\n appBskyActorProfile {\n displayName\n description\n avatar {\n url(preset: \"avatar\")\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfile {\n displayName\n }\n}\n" 344 + "text": "query ProfilePaginationQuery(\n $count: Int = 20\n $cursor: String\n $where: FmTealAlphaFeedPlayWhereInput!\n) {\n ...Profile_plays_mjR8k\n}\n\nfragment Profile_plays_mjR8k on Query {\n fmTealAlphaFeedPlay(first: $count, after: $cursor, sortBy: [{field: playedTime, direction: DESC}], where: $where) {\n totalCount\n edges {\n node {\n ...TrackItem_play\n actorHandle\n appBskyActorProfileByDid {\n displayName\n description\n avatar {\n url(preset: \"avatar\")\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists {\n artistName\n }\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfileByDid {\n displayName\n }\n}\n" 350 345 } 351 346 }; 352 347 })(); 353 348 354 - (node as any).hash = "fb9d67e8cd94c4191b9956225ff78bdf"; 349 + (node as any).hash = "06ba557474df22684f61a32da8aec20a"; 355 350 356 351 export default node;
+43 -48
src/__generated__/ProfileQuery.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<8d62f515b7652094345304e43124aa72>> 2 + * @generated SignedSource<<586d7e40425eb1e823fb98f47d69cefd>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 11 11 import { ConcreteRequest } from 'relay-runtime'; 12 12 import { FragmentRefs } from "relay-runtime"; 13 13 export type FmTealAlphaFeedPlayWhereInput = { 14 - actorHandle?: StringFilter | null | undefined; 15 - artistMbIds?: StringFilter | null | undefined; 16 - artistNames?: StringFilter | null | undefined; 17 - artists?: StringFilter | null | undefined; 18 - cid?: StringFilter | null | undefined; 19 - collection?: StringFilter | null | undefined; 20 - did?: StringFilter | null | undefined; 21 - duration?: IntFilter | null | undefined; 22 - indexedAt?: DateTimeFilter | null | undefined; 23 - isrc?: StringFilter | null | undefined; 24 - musicServiceBaseDomain?: StringFilter | null | undefined; 25 - originUrl?: StringFilter | null | undefined; 26 - playedTime?: StringFilter | null | undefined; 27 - recordingMbId?: StringFilter | null | undefined; 28 - releaseMbId?: StringFilter | null | undefined; 29 - releaseName?: StringFilter | null | undefined; 30 - submissionClientAgent?: StringFilter | null | undefined; 31 - trackMbId?: StringFilter | null | undefined; 32 - trackName?: StringFilter | null | undefined; 33 - uri?: StringFilter | null | undefined; 14 + actorHandle?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 15 + and?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 16 + cid?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 17 + collection?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 18 + did?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 19 + duration?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 20 + indexedAt?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 21 + isrc?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 22 + musicServiceBaseDomain?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 23 + or?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 24 + originUrl?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 25 + playedTime?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 26 + recordingMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 27 + releaseMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 28 + releaseName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 29 + submissionClientAgent?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 30 + trackMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 31 + trackName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 32 + uri?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 34 33 }; 35 - export type DateTimeFilter = { 36 - eq?: string | null | undefined; 37 - gt?: string | null | undefined; 38 - gte?: string | null | undefined; 39 - lt?: string | null | undefined; 40 - lte?: string | null | undefined; 41 - }; 42 - export type StringFilter = { 34 + export type FmTealAlphaFeedPlayFieldCondition = { 43 35 contains?: string | null | undefined; 44 36 eq?: string | null | undefined; 45 37 gt?: string | null | undefined; 46 38 gte?: string | null | undefined; 47 - in?: ReadonlyArray<string | null | undefined> | null | undefined; 39 + in?: ReadonlyArray<string> | null | undefined; 48 40 lt?: string | null | undefined; 49 41 lte?: string | null | undefined; 50 42 }; 51 - export type IntFilter = { 52 - eq?: number | null | undefined; 53 - gt?: number | null | undefined; 54 - gte?: number | null | undefined; 55 - in?: ReadonlyArray<number | null | undefined> | null | undefined; 56 - lt?: number | null | undefined; 57 - lte?: number | null | undefined; 58 - }; 59 43 export type ProfileQuery$variables = { 60 44 chartWhere: FmTealAlphaFeedPlayWhereInput; 61 45 where: FmTealAlphaFeedPlayWhereInput; ··· 95 79 "name": "sortBy", 96 80 "value": [ 97 81 { 98 - "direction": "desc", 82 + "direction": "DESC", 99 83 "field": "playedTime" 100 84 } 101 85 ] ··· 149 133 "args": (v3/*: any*/), 150 134 "concreteType": "FmTealAlphaFeedPlayConnection", 151 135 "kind": "LinkedField", 152 - "name": "fmTealAlphaFeedPlays", 136 + "name": "fmTealAlphaFeedPlay", 153 137 "plural": false, 154 138 "selections": [ 155 139 { ··· 186 170 { 187 171 "alias": null, 188 172 "args": null, 189 - "kind": "ScalarField", 173 + "concreteType": "FmTealAlphaFeedDefsArtist", 174 + "kind": "LinkedField", 190 175 "name": "artists", 176 + "plural": true, 177 + "selections": [ 178 + { 179 + "alias": null, 180 + "args": null, 181 + "kind": "ScalarField", 182 + "name": "artistName", 183 + "storageKey": null 184 + } 185 + ], 191 186 "storageKey": null 192 187 }, 193 188 { ··· 223 218 "args": null, 224 219 "concreteType": "AppBskyActorProfile", 225 220 "kind": "LinkedField", 226 - "name": "appBskyActorProfile", 221 + "name": "appBskyActorProfileByDid", 227 222 "plural": false, 228 223 "selections": [ 229 224 { ··· 323 318 "sortBy" 324 319 ], 325 320 "handle": "connection", 326 - "key": "Profile_fmTealAlphaFeedPlays", 321 + "key": "Profile_fmTealAlphaFeedPlay", 327 322 "kind": "LinkedHandle", 328 - "name": "fmTealAlphaFeedPlays" 323 + "name": "fmTealAlphaFeedPlay" 329 324 }, 330 325 { 331 326 "alias": "chartData", ··· 336 331 "value": [ 337 332 { 338 333 "field": "playedTime", 339 - "interval": "day" 334 + "interval": "DAY" 340 335 } 341 336 ] 342 337 }, ··· 353 348 ], 354 349 "concreteType": "FmTealAlphaFeedPlayAggregated", 355 350 "kind": "LinkedField", 356 - "name": "fmTealAlphaFeedPlaysAggregated", 351 + "name": "fmTealAlphaFeedPlayAggregated", 357 352 "plural": true, 358 353 "selections": [ 359 354 (v4/*: any*/), ··· 370 365 ] 371 366 }, 372 367 "params": { 373 - "cacheID": "083f03714f183a8e68ff0a6d15f0d757", 368 + "cacheID": "06807a18670ad67256b497dd0ef8f208", 374 369 "id": null, 375 370 "metadata": {}, 376 371 "name": "ProfileQuery", 377 372 "operationKind": "query", 378 - "text": "query ProfileQuery(\n $where: FmTealAlphaFeedPlayWhereInput!\n $chartWhere: FmTealAlphaFeedPlayWhereInput!\n) {\n ...Profile_plays_3FC4Qo\n ...ScrobbleChart_data\n}\n\nfragment Profile_plays_3FC4Qo on Query {\n fmTealAlphaFeedPlays(first: 20, sortBy: [{field: playedTime, direction: desc}], where: $where) {\n totalCount\n edges {\n node {\n ...TrackItem_play\n actorHandle\n appBskyActorProfile {\n displayName\n description\n avatar {\n url(preset: \"avatar\")\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment ScrobbleChart_data on Query {\n chartData: fmTealAlphaFeedPlaysAggregated(groupBy: [{field: playedTime, interval: day}], where: $chartWhere, limit: 90) {\n playedTime\n count\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfile {\n displayName\n }\n}\n" 373 + "text": "query ProfileQuery(\n $where: FmTealAlphaFeedPlayWhereInput!\n $chartWhere: FmTealAlphaFeedPlayWhereInput!\n) {\n ...Profile_plays_3FC4Qo\n ...ScrobbleChart_data\n}\n\nfragment Profile_plays_3FC4Qo on Query {\n fmTealAlphaFeedPlay(first: 20, sortBy: [{field: playedTime, direction: DESC}], where: $where) {\n totalCount\n edges {\n node {\n ...TrackItem_play\n actorHandle\n appBskyActorProfileByDid {\n displayName\n description\n avatar {\n url(preset: \"avatar\")\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment ScrobbleChart_data on Query {\n chartData: fmTealAlphaFeedPlayAggregated(groupBy: [{field: playedTime, interval: DAY}], where: $chartWhere, limit: 90) {\n playedTime\n count\n }\n}\n\nfragment TrackItem_play on FmTealAlphaFeedPlay {\n trackName\n playedTime\n artists {\n artistName\n }\n releaseName\n releaseMbId\n actorHandle\n musicServiceBaseDomain\n appBskyActorProfileByDid {\n displayName\n }\n}\n" 379 374 } 380 375 }; 381 376 })();
+11 -11
src/__generated__/Profile_plays.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<9b9347661ace6bcbeb677e53e4b5feec>> 2 + * @generated SignedSource<<debe921c118f11f1685c3407b690bcf8>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 11 11 import { ReaderFragment } from 'relay-runtime'; 12 12 import { FragmentRefs } from "relay-runtime"; 13 13 export type Profile_plays$data = { 14 - readonly fmTealAlphaFeedPlays: { 14 + readonly fmTealAlphaFeedPlay: { 15 15 readonly edges: ReadonlyArray<{ 16 16 readonly node: { 17 17 readonly actorHandle: string | null | undefined; 18 - readonly appBskyActorProfile: { 18 + readonly appBskyActorProfileByDid: { 19 19 readonly avatar: { 20 20 readonly url: string; 21 21 } | null | undefined; ··· 25 25 readonly " $fragmentSpreads": FragmentRefs<"TrackItem_play">; 26 26 }; 27 27 }>; 28 - readonly totalCount: number; 29 - }; 28 + readonly totalCount: number | null | undefined; 29 + } | null | undefined; 30 30 readonly " $fragmentType": "Profile_plays"; 31 31 }; 32 32 export type Profile_plays$key = { ··· 38 38 39 39 const node: ReaderFragment = (function(){ 40 40 var v0 = [ 41 - "fmTealAlphaFeedPlays" 41 + "fmTealAlphaFeedPlay" 42 42 ]; 43 43 return { 44 44 "argumentDefinitions": [ ··· 84 84 "name": "Profile_plays", 85 85 "selections": [ 86 86 { 87 - "alias": "fmTealAlphaFeedPlays", 87 + "alias": "fmTealAlphaFeedPlay", 88 88 "args": [ 89 89 { 90 90 "kind": "Literal", 91 91 "name": "sortBy", 92 92 "value": [ 93 93 { 94 - "direction": "desc", 94 + "direction": "DESC", 95 95 "field": "playedTime" 96 96 } 97 97 ] ··· 104 104 ], 105 105 "concreteType": "FmTealAlphaFeedPlayConnection", 106 106 "kind": "LinkedField", 107 - "name": "__Profile_fmTealAlphaFeedPlays_connection", 107 + "name": "__Profile_fmTealAlphaFeedPlay_connection", 108 108 "plural": false, 109 109 "selections": [ 110 110 { ··· 147 147 "args": null, 148 148 "concreteType": "AppBskyActorProfile", 149 149 "kind": "LinkedField", 150 - "name": "appBskyActorProfile", 150 + "name": "appBskyActorProfileByDid", 151 151 "plural": false, 152 152 "selections": [ 153 153 { ··· 245 245 }; 246 246 })(); 247 247 248 - (node as any).hash = "fb9d67e8cd94c4191b9956225ff78bdf"; 248 + (node as any).hash = "06ba557474df22684f61a32da8aec20a"; 249 249 250 250 export default node;
+6 -6
src/__generated__/ScrobbleChart_data.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<7b446f8950ffde63fb0e7748bb596e66>> 2 + * @generated SignedSource<<7e2392afa490a7b1da46656aa250f70b>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 13 13 export type ScrobbleChart_data$data = { 14 14 readonly chartData: ReadonlyArray<{ 15 15 readonly count: number; 16 - readonly playedTime: any | null | undefined; 17 - }>; 16 + readonly playedTime: string | null | undefined; 17 + }> | null | undefined; 18 18 readonly " $fragmentType": "ScrobbleChart_data"; 19 19 }; 20 20 export type ScrobbleChart_data$key = { ··· 42 42 "value": [ 43 43 { 44 44 "field": "playedTime", 45 - "interval": "day" 45 + "interval": "DAY" 46 46 } 47 47 ] 48 48 }, ··· 59 59 ], 60 60 "concreteType": "FmTealAlphaFeedPlayAggregated", 61 61 "kind": "LinkedField", 62 - "name": "fmTealAlphaFeedPlaysAggregated", 62 + "name": "fmTealAlphaFeedPlayAggregated", 63 63 "plural": true, 64 64 "selections": [ 65 65 { ··· 84 84 "abstractKey": null 85 85 }; 86 86 87 - (node as any).hash = "6d8ebfa533779947a0b3cd703929b5ba"; 87 + (node as any).hash = "acb96f5268c9520f77c672a7ea3a7454"; 88 88 89 89 export default node;
+32 -48
src/__generated__/TopAlbumsQuery.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<ba0a977fd251b8099185f84ffca5fe7f>> 2 + * @generated SignedSource<<8d07fc631e364271a41ea2bd1ab069bb>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 10 10 11 11 import { ConcreteRequest } from 'relay-runtime'; 12 12 export type FmTealAlphaFeedPlayWhereInput = { 13 - actorHandle?: StringFilter | null | undefined; 14 - artistMbIds?: StringFilter | null | undefined; 15 - artistNames?: StringFilter | null | undefined; 16 - artists?: StringFilter | null | undefined; 17 - cid?: StringFilter | null | undefined; 18 - collection?: StringFilter | null | undefined; 19 - did?: StringFilter | null | undefined; 20 - duration?: IntFilter | null | undefined; 21 - indexedAt?: DateTimeFilter | null | undefined; 22 - isrc?: StringFilter | null | undefined; 23 - musicServiceBaseDomain?: StringFilter | null | undefined; 24 - originUrl?: StringFilter | null | undefined; 25 - playedTime?: StringFilter | null | undefined; 26 - recordingMbId?: StringFilter | null | undefined; 27 - releaseMbId?: StringFilter | null | undefined; 28 - releaseName?: StringFilter | null | undefined; 29 - submissionClientAgent?: StringFilter | null | undefined; 30 - trackMbId?: StringFilter | null | undefined; 31 - trackName?: StringFilter | null | undefined; 32 - uri?: StringFilter | null | undefined; 33 - }; 34 - export type DateTimeFilter = { 35 - eq?: string | null | undefined; 36 - gt?: string | null | undefined; 37 - gte?: string | null | undefined; 38 - lt?: string | null | undefined; 39 - lte?: string | null | undefined; 13 + actorHandle?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 14 + and?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 15 + cid?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 16 + collection?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 17 + did?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 18 + duration?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 19 + indexedAt?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 20 + isrc?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 21 + musicServiceBaseDomain?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 22 + or?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 23 + originUrl?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 24 + playedTime?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 25 + recordingMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 26 + releaseMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 27 + releaseName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 28 + submissionClientAgent?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 29 + trackMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 30 + trackName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 31 + uri?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 40 32 }; 41 - export type StringFilter = { 33 + export type FmTealAlphaFeedPlayFieldCondition = { 42 34 contains?: string | null | undefined; 43 35 eq?: string | null | undefined; 44 36 gt?: string | null | undefined; 45 37 gte?: string | null | undefined; 46 - in?: ReadonlyArray<string | null | undefined> | null | undefined; 38 + in?: ReadonlyArray<string> | null | undefined; 47 39 lt?: string | null | undefined; 48 40 lte?: string | null | undefined; 49 - }; 50 - export type IntFilter = { 51 - eq?: number | null | undefined; 52 - gt?: number | null | undefined; 53 - gte?: number | null | undefined; 54 - in?: ReadonlyArray<number | null | undefined> | null | undefined; 55 - lt?: number | null | undefined; 56 - lte?: number | null | undefined; 57 41 }; 58 42 export type TopAlbumsQuery$variables = { 59 43 where?: FmTealAlphaFeedPlayWhereInput | null | undefined; 60 44 }; 61 45 export type TopAlbumsQuery$data = { 62 - readonly fmTealAlphaFeedPlaysAggregated: ReadonlyArray<{ 63 - readonly artists: any | null | undefined; 46 + readonly fmTealAlphaFeedPlayAggregated: ReadonlyArray<{ 47 + readonly artists: string | null | undefined; 64 48 readonly count: number; 65 - readonly releaseMbId: any | null | undefined; 66 - readonly releaseName: any | null | undefined; 67 - }>; 49 + readonly releaseMbId: string | null | undefined; 50 + readonly releaseName: string | null | undefined; 51 + }> | null | undefined; 68 52 }; 69 53 export type TopAlbumsQuery = { 70 54 response: TopAlbumsQuery$data; ··· 107 91 "kind": "Literal", 108 92 "name": "orderBy", 109 93 "value": { 110 - "count": "desc" 94 + "count": "DESC" 111 95 } 112 96 }, 113 97 { ··· 118 102 ], 119 103 "concreteType": "FmTealAlphaFeedPlayAggregated", 120 104 "kind": "LinkedField", 121 - "name": "fmTealAlphaFeedPlaysAggregated", 105 + "name": "fmTealAlphaFeedPlayAggregated", 122 106 "plural": true, 123 107 "selections": [ 124 108 { ··· 171 155 "selections": (v1/*: any*/) 172 156 }, 173 157 "params": { 174 - "cacheID": "4bc742f9cab572a86f4956ae1325e650", 158 + "cacheID": "6b742b6a57c908748af1780da995e31c", 175 159 "id": null, 176 160 "metadata": {}, 177 161 "name": "TopAlbumsQuery", 178 162 "operationKind": "query", 179 - "text": "query TopAlbumsQuery(\n $where: FmTealAlphaFeedPlayWhereInput\n) {\n fmTealAlphaFeedPlaysAggregated(groupBy: [{field: releaseMbId}, {field: releaseName}, {field: artists}], orderBy: {count: desc}, limit: 100, where: $where) {\n releaseMbId\n releaseName\n artists\n count\n }\n}\n" 163 + "text": "query TopAlbumsQuery(\n $where: FmTealAlphaFeedPlayWhereInput\n) {\n fmTealAlphaFeedPlayAggregated(groupBy: [{field: releaseMbId}, {field: releaseName}, {field: artists}], orderBy: {count: DESC}, limit: 100, where: $where) {\n releaseMbId\n releaseName\n artists\n count\n }\n}\n" 180 164 } 181 165 }; 182 166 })(); 183 167 184 - (node as any).hash = "c916cfe287c6837e7b40f0712b123f12"; 168 + (node as any).hash = "13fd8a47c19eeb4f327f0d6d869b73cd"; 185 169 186 170 export default node;
+32 -48
src/__generated__/TopTracksQuery.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<d82ad2bc23a12ef33ba6bce1df9620f3>> 2 + * @generated SignedSource<<3d375bb2f6549eb84b9399717743b845>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 10 10 11 11 import { ConcreteRequest } from 'relay-runtime'; 12 12 export type FmTealAlphaFeedPlayWhereInput = { 13 - actorHandle?: StringFilter | null | undefined; 14 - artistMbIds?: StringFilter | null | undefined; 15 - artistNames?: StringFilter | null | undefined; 16 - artists?: StringFilter | null | undefined; 17 - cid?: StringFilter | null | undefined; 18 - collection?: StringFilter | null | undefined; 19 - did?: StringFilter | null | undefined; 20 - duration?: IntFilter | null | undefined; 21 - indexedAt?: DateTimeFilter | null | undefined; 22 - isrc?: StringFilter | null | undefined; 23 - musicServiceBaseDomain?: StringFilter | null | undefined; 24 - originUrl?: StringFilter | null | undefined; 25 - playedTime?: StringFilter | null | undefined; 26 - recordingMbId?: StringFilter | null | undefined; 27 - releaseMbId?: StringFilter | null | undefined; 28 - releaseName?: StringFilter | null | undefined; 29 - submissionClientAgent?: StringFilter | null | undefined; 30 - trackMbId?: StringFilter | null | undefined; 31 - trackName?: StringFilter | null | undefined; 32 - uri?: StringFilter | null | undefined; 33 - }; 34 - export type DateTimeFilter = { 35 - eq?: string | null | undefined; 36 - gt?: string | null | undefined; 37 - gte?: string | null | undefined; 38 - lt?: string | null | undefined; 39 - lte?: string | null | undefined; 13 + actorHandle?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 14 + and?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 15 + cid?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 16 + collection?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 17 + did?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 18 + duration?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 19 + indexedAt?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 20 + isrc?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 21 + musicServiceBaseDomain?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 22 + or?: ReadonlyArray<FmTealAlphaFeedPlayWhereInput> | null | undefined; 23 + originUrl?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 24 + playedTime?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 25 + recordingMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 26 + releaseMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 27 + releaseName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 28 + submissionClientAgent?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 29 + trackMbId?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 30 + trackName?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 31 + uri?: FmTealAlphaFeedPlayFieldCondition | null | undefined; 40 32 }; 41 - export type StringFilter = { 33 + export type FmTealAlphaFeedPlayFieldCondition = { 42 34 contains?: string | null | undefined; 43 35 eq?: string | null | undefined; 44 36 gt?: string | null | undefined; 45 37 gte?: string | null | undefined; 46 - in?: ReadonlyArray<string | null | undefined> | null | undefined; 38 + in?: ReadonlyArray<string> | null | undefined; 47 39 lt?: string | null | undefined; 48 40 lte?: string | null | undefined; 49 - }; 50 - export type IntFilter = { 51 - eq?: number | null | undefined; 52 - gt?: number | null | undefined; 53 - gte?: number | null | undefined; 54 - in?: ReadonlyArray<number | null | undefined> | null | undefined; 55 - lt?: number | null | undefined; 56 - lte?: number | null | undefined; 57 41 }; 58 42 export type TopTracksQuery$variables = { 59 43 where?: FmTealAlphaFeedPlayWhereInput | null | undefined; 60 44 }; 61 45 export type TopTracksQuery$data = { 62 - readonly fmTealAlphaFeedPlaysAggregated: ReadonlyArray<{ 63 - readonly artists: any | null | undefined; 46 + readonly fmTealAlphaFeedPlayAggregated: ReadonlyArray<{ 47 + readonly artists: string | null | undefined; 64 48 readonly count: number; 65 - readonly releaseMbId: any | null | undefined; 66 - readonly trackName: any | null | undefined; 67 - }>; 49 + readonly releaseMbId: string | null | undefined; 50 + readonly trackName: string | null | undefined; 51 + }> | null | undefined; 68 52 }; 69 53 export type TopTracksQuery = { 70 54 response: TopTracksQuery$data; ··· 107 91 "kind": "Literal", 108 92 "name": "orderBy", 109 93 "value": { 110 - "count": "desc" 94 + "count": "DESC" 111 95 } 112 96 }, 113 97 { ··· 118 102 ], 119 103 "concreteType": "FmTealAlphaFeedPlayAggregated", 120 104 "kind": "LinkedField", 121 - "name": "fmTealAlphaFeedPlaysAggregated", 105 + "name": "fmTealAlphaFeedPlayAggregated", 122 106 "plural": true, 123 107 "selections": [ 124 108 { ··· 171 155 "selections": (v1/*: any*/) 172 156 }, 173 157 "params": { 174 - "cacheID": "d889d685b64fb19d468954bb3fb7ff7c", 158 + "cacheID": "bc9ed2b6c355b3a8fedb84cb713fa8de", 175 159 "id": null, 176 160 "metadata": {}, 177 161 "name": "TopTracksQuery", 178 162 "operationKind": "query", 179 - "text": "query TopTracksQuery(\n $where: FmTealAlphaFeedPlayWhereInput\n) {\n fmTealAlphaFeedPlaysAggregated(groupBy: [{field: trackName}, {field: releaseMbId}, {field: artists}], orderBy: {count: desc}, limit: 50, where: $where) {\n trackName\n releaseMbId\n artists\n count\n }\n}\n" 163 + "text": "query TopTracksQuery(\n $where: FmTealAlphaFeedPlayWhereInput\n) {\n fmTealAlphaFeedPlayAggregated(groupBy: [{field: trackName}, {field: releaseMbId}, {field: artists}], orderBy: {count: DESC}, limit: 50, where: $where) {\n trackName\n releaseMbId\n artists\n count\n }\n}\n" 180 164 } 181 165 }; 182 166 })(); 183 167 184 - (node as any).hash = "4b62eaeaf8a935abc28e77c8cd2907d1"; 168 + (node as any).hash = "d2aadd883f60f6f31f8d466dc9653cd8"; 185 169 186 170 export default node;
+20 -7
src/__generated__/TrackItem_play.graphql.ts
··· 1 1 /** 2 - * @generated SignedSource<<8d4b2dad137cc86578e0230225cde09f>> 2 + * @generated SignedSource<<d110bc257911ffb384b30e7e973211c9>> 3 3 * @lightSyntaxTransform 4 4 * @nogrep 5 5 */ ··· 12 12 import { FragmentRefs } from "relay-runtime"; 13 13 export type TrackItem_play$data = { 14 14 readonly actorHandle: string | null | undefined; 15 - readonly appBskyActorProfile: { 15 + readonly appBskyActorProfileByDid: { 16 16 readonly displayName: string | null | undefined; 17 17 } | null | undefined; 18 - readonly artists: any | null | undefined; 18 + readonly artists: ReadonlyArray<{ 19 + readonly artistName: string; 20 + }> | null | undefined; 19 21 readonly musicServiceBaseDomain: string | null | undefined; 20 22 readonly playedTime: string | null | undefined; 21 23 readonly releaseMbId: string | null | undefined; 22 24 readonly releaseName: string | null | undefined; 23 - readonly trackName: string; 25 + readonly trackName: string | null | undefined; 24 26 readonly " $fragmentType": "TrackItem_play"; 25 27 }; 26 28 export type TrackItem_play$key = { ··· 51 53 { 52 54 "alias": null, 53 55 "args": null, 54 - "kind": "ScalarField", 56 + "concreteType": "FmTealAlphaFeedDefsArtist", 57 + "kind": "LinkedField", 55 58 "name": "artists", 59 + "plural": true, 60 + "selections": [ 61 + { 62 + "alias": null, 63 + "args": null, 64 + "kind": "ScalarField", 65 + "name": "artistName", 66 + "storageKey": null 67 + } 68 + ], 56 69 "storageKey": null 57 70 }, 58 71 { ··· 88 101 "args": null, 89 102 "concreteType": "AppBskyActorProfile", 90 103 "kind": "LinkedField", 91 - "name": "appBskyActorProfile", 104 + "name": "appBskyActorProfileByDid", 92 105 "plural": false, 93 106 "selections": [ 94 107 { ··· 106 119 "abstractKey": null 107 120 }; 108 121 109 - (node as any).hash = "ff1bb5f1d370a2aa9ee45a6db4320f83"; 122 + (node as any).hash = "93f45db972efd335604fbc28995328de"; 110 123 111 124 export default node;
+8 -9
src/main.tsx
··· 1 1 import { StrictMode, Suspense } from "react"; 2 2 import { createRoot } from "react-dom/client"; 3 - import { BrowserRouter, Routes, Route } from "react-router-dom"; 3 + import { BrowserRouter, Route, Routes } from "react-router-dom"; 4 4 import "./index.css"; 5 5 import App from "./App.tsx"; 6 6 import Profile from "./Profile.tsx"; ··· 10 10 import { RelayEnvironmentProvider } from "react-relay"; 11 11 import { 12 12 Environment, 13 + type FetchFunction, 14 + type GraphQLResponse, 13 15 Network, 14 - type FetchFunction, 15 16 Observable, 16 17 type SubscribeFunction, 17 - type GraphQLResponse, 18 18 } from "relay-runtime"; 19 19 import { createClient } from "graphql-ws"; 20 20 21 21 const HTTP_ENDPOINT = 22 - "http://localhost:3000/graphql?slice=at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/network.slices.slice/3m257yljpbg2a"; 22 + "https://quickslice-production-d668.up.railway.app/graphql"; 23 23 24 - const WS_ENDPOINT = 25 - "ws://localhost:3000/graphql/ws?slice=at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/network.slices.slice/3m257yljpbg2a"; 24 + const WS_ENDPOINT = "wss://quickslice-production-d668.up.railway.app/graphql"; 26 25 27 26 const fetchGraphQL: FetchFunction = async (request, variables) => { 28 27 const resp = await fetch(HTTP_ENDPOINT, { ··· 78 77 sink.error(error); 79 78 } else if (error instanceof CloseEvent) { 80 79 sink.error( 81 - new Error(`WebSocket closed: ${error.code} ${error.reason}`) 80 + new Error(`WebSocket closed: ${error.code} ${error.reason}`), 82 81 ); 83 82 } else { 84 83 sink.error(new Error(JSON.stringify(error))); 85 84 } 86 85 }, 87 86 complete: () => sink.complete(), 88 - } 87 + }, 89 88 ); 90 89 }); 91 90 }; ··· 110 109 </Suspense> 111 110 </RelayEnvironmentProvider> 112 111 </BrowserRouter> 113 - </StrictMode> 112 + </StrictMode>, 114 113 );