A decentralized music tracking and discovery platform built on AT Protocol 🎵

Add follows graph, DB table and endpoints

+4328 -10
+12
apps/api/drizzle/0002_robust_wong.sql
··· 1 + CREATE TABLE "follows" ( 2 + "xata_id" text PRIMARY KEY DEFAULT xata_id() NOT NULL, 3 + "uri" text NOT NULL, 4 + "follower_did" text NOT NULL, 5 + "subject_did" text NOT NULL, 6 + "xata_version" integer, 7 + "xata_createdat" timestamp DEFAULT now() NOT NULL, 8 + "xata_updatedat" timestamp DEFAULT now() NOT NULL, 9 + CONSTRAINT "follows_uri_unique" UNIQUE("uri") 10 + ); 11 + --> statement-breakpoint 12 + CREATE UNIQUE INDEX "follows_follower_subject_unique" ON "follows" USING btree ("follower_did","subject_did");
+3424
apps/api/drizzle/meta/0002_snapshot.json
··· 1 + { 2 + "id": "ba060d7c-5d31-44b1-abd4-8de1cd5357a7", 3 + "prevId": "6d2ede58-9041-48a4-92fc-e8995d6bc049", 4 + "version": "7", 5 + "dialect": "postgresql", 6 + "tables": { 7 + "public.album_tracks": { 8 + "name": "album_tracks", 9 + "schema": "", 10 + "columns": { 11 + "xata_id": { 12 + "name": "xata_id", 13 + "type": "text", 14 + "primaryKey": true, 15 + "notNull": true, 16 + "default": "xata_id()" 17 + }, 18 + "album_id": { 19 + "name": "album_id", 20 + "type": "text", 21 + "primaryKey": false, 22 + "notNull": true 23 + }, 24 + "track_id": { 25 + "name": "track_id", 26 + "type": "text", 27 + "primaryKey": false, 28 + "notNull": true 29 + }, 30 + "xata_createdat": { 31 + "name": "xata_createdat", 32 + "type": "timestamp", 33 + "primaryKey": false, 34 + "notNull": true, 35 + "default": "now()" 36 + }, 37 + "xata_updatedat": { 38 + "name": "xata_updatedat", 39 + "type": "timestamp", 40 + "primaryKey": false, 41 + "notNull": true, 42 + "default": "now()" 43 + }, 44 + "xata_version": { 45 + "name": "xata_version", 46 + "type": "integer", 47 + "primaryKey": false, 48 + "notNull": false 49 + } 50 + }, 51 + "indexes": {}, 52 + "foreignKeys": { 53 + "album_tracks_album_id_albums_xata_id_fk": { 54 + "name": "album_tracks_album_id_albums_xata_id_fk", 55 + "tableFrom": "album_tracks", 56 + "tableTo": "albums", 57 + "columnsFrom": [ 58 + "album_id" 59 + ], 60 + "columnsTo": [ 61 + "xata_id" 62 + ], 63 + "onDelete": "no action", 64 + "onUpdate": "no action" 65 + }, 66 + "album_tracks_track_id_tracks_xata_id_fk": { 67 + "name": "album_tracks_track_id_tracks_xata_id_fk", 68 + "tableFrom": "album_tracks", 69 + "tableTo": "tracks", 70 + "columnsFrom": [ 71 + "track_id" 72 + ], 73 + "columnsTo": [ 74 + "xata_id" 75 + ], 76 + "onDelete": "no action", 77 + "onUpdate": "no action" 78 + } 79 + }, 80 + "compositePrimaryKeys": {}, 81 + "uniqueConstraints": {}, 82 + "policies": {}, 83 + "checkConstraints": {}, 84 + "isRLSEnabled": false 85 + }, 86 + "public.albums": { 87 + "name": "albums", 88 + "schema": "", 89 + "columns": { 90 + "xata_id": { 91 + "name": "xata_id", 92 + "type": "text", 93 + "primaryKey": true, 94 + "notNull": true, 95 + "default": "xata_id()" 96 + }, 97 + "title": { 98 + "name": "title", 99 + "type": "text", 100 + "primaryKey": false, 101 + "notNull": true 102 + }, 103 + "artist": { 104 + "name": "artist", 105 + "type": "text", 106 + "primaryKey": false, 107 + "notNull": true 108 + }, 109 + "release_date": { 110 + "name": "release_date", 111 + "type": "text", 112 + "primaryKey": false, 113 + "notNull": false 114 + }, 115 + "year": { 116 + "name": "year", 117 + "type": "integer", 118 + "primaryKey": false, 119 + "notNull": false 120 + }, 121 + "album_art": { 122 + "name": "album_art", 123 + "type": "text", 124 + "primaryKey": false, 125 + "notNull": false 126 + }, 127 + "uri": { 128 + "name": "uri", 129 + "type": "text", 130 + "primaryKey": false, 131 + "notNull": false 132 + }, 133 + "artist_uri": { 134 + "name": "artist_uri", 135 + "type": "text", 136 + "primaryKey": false, 137 + "notNull": false 138 + }, 139 + "apple_music_link": { 140 + "name": "apple_music_link", 141 + "type": "text", 142 + "primaryKey": false, 143 + "notNull": false 144 + }, 145 + "spotify_link": { 146 + "name": "spotify_link", 147 + "type": "text", 148 + "primaryKey": false, 149 + "notNull": false 150 + }, 151 + "tidal_link": { 152 + "name": "tidal_link", 153 + "type": "text", 154 + "primaryKey": false, 155 + "notNull": false 156 + }, 157 + "youtube_link": { 158 + "name": "youtube_link", 159 + "type": "text", 160 + "primaryKey": false, 161 + "notNull": false 162 + }, 163 + "sha256": { 164 + "name": "sha256", 165 + "type": "text", 166 + "primaryKey": false, 167 + "notNull": true 168 + }, 169 + "xata_createdat": { 170 + "name": "xata_createdat", 171 + "type": "timestamp", 172 + "primaryKey": false, 173 + "notNull": true, 174 + "default": "now()" 175 + }, 176 + "xata_updatedat": { 177 + "name": "xata_updatedat", 178 + "type": "timestamp", 179 + "primaryKey": false, 180 + "notNull": true, 181 + "default": "now()" 182 + }, 183 + "xata_version": { 184 + "name": "xata_version", 185 + "type": "integer", 186 + "primaryKey": false, 187 + "notNull": false 188 + } 189 + }, 190 + "indexes": {}, 191 + "foreignKeys": {}, 192 + "compositePrimaryKeys": {}, 193 + "uniqueConstraints": { 194 + "albums_uri_unique": { 195 + "name": "albums_uri_unique", 196 + "nullsNotDistinct": false, 197 + "columns": [ 198 + "uri" 199 + ] 200 + }, 201 + "albums_apple_music_link_unique": { 202 + "name": "albums_apple_music_link_unique", 203 + "nullsNotDistinct": false, 204 + "columns": [ 205 + "apple_music_link" 206 + ] 207 + }, 208 + "albums_spotify_link_unique": { 209 + "name": "albums_spotify_link_unique", 210 + "nullsNotDistinct": false, 211 + "columns": [ 212 + "spotify_link" 213 + ] 214 + }, 215 + "albums_tidal_link_unique": { 216 + "name": "albums_tidal_link_unique", 217 + "nullsNotDistinct": false, 218 + "columns": [ 219 + "tidal_link" 220 + ] 221 + }, 222 + "albums_youtube_link_unique": { 223 + "name": "albums_youtube_link_unique", 224 + "nullsNotDistinct": false, 225 + "columns": [ 226 + "youtube_link" 227 + ] 228 + }, 229 + "albums_sha256_unique": { 230 + "name": "albums_sha256_unique", 231 + "nullsNotDistinct": false, 232 + "columns": [ 233 + "sha256" 234 + ] 235 + } 236 + }, 237 + "policies": {}, 238 + "checkConstraints": {}, 239 + "isRLSEnabled": false 240 + }, 241 + "public.api_keys": { 242 + "name": "api_keys", 243 + "schema": "", 244 + "columns": { 245 + "xata_id": { 246 + "name": "xata_id", 247 + "type": "text", 248 + "primaryKey": true, 249 + "notNull": true, 250 + "default": "xata_id()" 251 + }, 252 + "name": { 253 + "name": "name", 254 + "type": "text", 255 + "primaryKey": false, 256 + "notNull": true 257 + }, 258 + "api_key": { 259 + "name": "api_key", 260 + "type": "text", 261 + "primaryKey": false, 262 + "notNull": true 263 + }, 264 + "shared_secret": { 265 + "name": "shared_secret", 266 + "type": "text", 267 + "primaryKey": false, 268 + "notNull": true 269 + }, 270 + "description": { 271 + "name": "description", 272 + "type": "text", 273 + "primaryKey": false, 274 + "notNull": false 275 + }, 276 + "enabled": { 277 + "name": "enabled", 278 + "type": "boolean", 279 + "primaryKey": false, 280 + "notNull": true, 281 + "default": true 282 + }, 283 + "user_id": { 284 + "name": "user_id", 285 + "type": "text", 286 + "primaryKey": false, 287 + "notNull": true 288 + }, 289 + "xata_createdat": { 290 + "name": "xata_createdat", 291 + "type": "timestamp", 292 + "primaryKey": false, 293 + "notNull": true, 294 + "default": "now()" 295 + }, 296 + "xata_updatedat": { 297 + "name": "xata_updatedat", 298 + "type": "timestamp", 299 + "primaryKey": false, 300 + "notNull": true, 301 + "default": "now()" 302 + } 303 + }, 304 + "indexes": {}, 305 + "foreignKeys": { 306 + "api_keys_user_id_users_xata_id_fk": { 307 + "name": "api_keys_user_id_users_xata_id_fk", 308 + "tableFrom": "api_keys", 309 + "tableTo": "users", 310 + "columnsFrom": [ 311 + "user_id" 312 + ], 313 + "columnsTo": [ 314 + "xata_id" 315 + ], 316 + "onDelete": "no action", 317 + "onUpdate": "no action" 318 + } 319 + }, 320 + "compositePrimaryKeys": {}, 321 + "uniqueConstraints": {}, 322 + "policies": {}, 323 + "checkConstraints": {}, 324 + "isRLSEnabled": false 325 + }, 326 + "public.artist_albums": { 327 + "name": "artist_albums", 328 + "schema": "", 329 + "columns": { 330 + "xata_id": { 331 + "name": "xata_id", 332 + "type": "text", 333 + "primaryKey": true, 334 + "notNull": true, 335 + "default": "xata_id()" 336 + }, 337 + "artist_id": { 338 + "name": "artist_id", 339 + "type": "text", 340 + "primaryKey": false, 341 + "notNull": true 342 + }, 343 + "album_id": { 344 + "name": "album_id", 345 + "type": "text", 346 + "primaryKey": false, 347 + "notNull": true 348 + }, 349 + "xata_createdat": { 350 + "name": "xata_createdat", 351 + "type": "timestamp", 352 + "primaryKey": false, 353 + "notNull": true, 354 + "default": "now()" 355 + }, 356 + "xata_updatedat": { 357 + "name": "xata_updatedat", 358 + "type": "timestamp", 359 + "primaryKey": false, 360 + "notNull": true, 361 + "default": "now()" 362 + }, 363 + "xata_version": { 364 + "name": "xata_version", 365 + "type": "integer", 366 + "primaryKey": false, 367 + "notNull": false 368 + } 369 + }, 370 + "indexes": {}, 371 + "foreignKeys": { 372 + "artist_albums_artist_id_artists_xata_id_fk": { 373 + "name": "artist_albums_artist_id_artists_xata_id_fk", 374 + "tableFrom": "artist_albums", 375 + "tableTo": "artists", 376 + "columnsFrom": [ 377 + "artist_id" 378 + ], 379 + "columnsTo": [ 380 + "xata_id" 381 + ], 382 + "onDelete": "no action", 383 + "onUpdate": "no action" 384 + }, 385 + "artist_albums_album_id_albums_xata_id_fk": { 386 + "name": "artist_albums_album_id_albums_xata_id_fk", 387 + "tableFrom": "artist_albums", 388 + "tableTo": "albums", 389 + "columnsFrom": [ 390 + "album_id" 391 + ], 392 + "columnsTo": [ 393 + "xata_id" 394 + ], 395 + "onDelete": "no action", 396 + "onUpdate": "no action" 397 + } 398 + }, 399 + "compositePrimaryKeys": {}, 400 + "uniqueConstraints": {}, 401 + "policies": {}, 402 + "checkConstraints": {}, 403 + "isRLSEnabled": false 404 + }, 405 + "public.artist_tracks": { 406 + "name": "artist_tracks", 407 + "schema": "", 408 + "columns": { 409 + "xata_id": { 410 + "name": "xata_id", 411 + "type": "text", 412 + "primaryKey": true, 413 + "notNull": true, 414 + "default": "xata_id()" 415 + }, 416 + "artist_id": { 417 + "name": "artist_id", 418 + "type": "text", 419 + "primaryKey": false, 420 + "notNull": true 421 + }, 422 + "track_id": { 423 + "name": "track_id", 424 + "type": "text", 425 + "primaryKey": false, 426 + "notNull": true 427 + }, 428 + "xata_createdat": { 429 + "name": "xata_createdat", 430 + "type": "timestamp", 431 + "primaryKey": false, 432 + "notNull": true, 433 + "default": "now()" 434 + }, 435 + "xata_updatedat": { 436 + "name": "xata_updatedat", 437 + "type": "timestamp", 438 + "primaryKey": false, 439 + "notNull": true, 440 + "default": "now()" 441 + }, 442 + "xata_version": { 443 + "name": "xata_version", 444 + "type": "integer", 445 + "primaryKey": false, 446 + "notNull": false 447 + } 448 + }, 449 + "indexes": {}, 450 + "foreignKeys": { 451 + "artist_tracks_artist_id_artists_xata_id_fk": { 452 + "name": "artist_tracks_artist_id_artists_xata_id_fk", 453 + "tableFrom": "artist_tracks", 454 + "tableTo": "artists", 455 + "columnsFrom": [ 456 + "artist_id" 457 + ], 458 + "columnsTo": [ 459 + "xata_id" 460 + ], 461 + "onDelete": "no action", 462 + "onUpdate": "no action" 463 + }, 464 + "artist_tracks_track_id_tracks_xata_id_fk": { 465 + "name": "artist_tracks_track_id_tracks_xata_id_fk", 466 + "tableFrom": "artist_tracks", 467 + "tableTo": "tracks", 468 + "columnsFrom": [ 469 + "track_id" 470 + ], 471 + "columnsTo": [ 472 + "xata_id" 473 + ], 474 + "onDelete": "no action", 475 + "onUpdate": "no action" 476 + } 477 + }, 478 + "compositePrimaryKeys": {}, 479 + "uniqueConstraints": {}, 480 + "policies": {}, 481 + "checkConstraints": {}, 482 + "isRLSEnabled": false 483 + }, 484 + "public.artists": { 485 + "name": "artists", 486 + "schema": "", 487 + "columns": { 488 + "xata_id": { 489 + "name": "xata_id", 490 + "type": "text", 491 + "primaryKey": true, 492 + "notNull": true, 493 + "default": "xata_id()" 494 + }, 495 + "name": { 496 + "name": "name", 497 + "type": "text", 498 + "primaryKey": false, 499 + "notNull": true 500 + }, 501 + "biography": { 502 + "name": "biography", 503 + "type": "text", 504 + "primaryKey": false, 505 + "notNull": false 506 + }, 507 + "born": { 508 + "name": "born", 509 + "type": "timestamp", 510 + "primaryKey": false, 511 + "notNull": false 512 + }, 513 + "born_in": { 514 + "name": "born_in", 515 + "type": "text", 516 + "primaryKey": false, 517 + "notNull": false 518 + }, 519 + "died": { 520 + "name": "died", 521 + "type": "timestamp", 522 + "primaryKey": false, 523 + "notNull": false 524 + }, 525 + "picture": { 526 + "name": "picture", 527 + "type": "text", 528 + "primaryKey": false, 529 + "notNull": false 530 + }, 531 + "sha256": { 532 + "name": "sha256", 533 + "type": "text", 534 + "primaryKey": false, 535 + "notNull": true 536 + }, 537 + "uri": { 538 + "name": "uri", 539 + "type": "text", 540 + "primaryKey": false, 541 + "notNull": false 542 + }, 543 + "apple_music_link": { 544 + "name": "apple_music_link", 545 + "type": "text", 546 + "primaryKey": false, 547 + "notNull": false 548 + }, 549 + "spotify_link": { 550 + "name": "spotify_link", 551 + "type": "text", 552 + "primaryKey": false, 553 + "notNull": false 554 + }, 555 + "tidal_link": { 556 + "name": "tidal_link", 557 + "type": "text", 558 + "primaryKey": false, 559 + "notNull": false 560 + }, 561 + "youtube_link": { 562 + "name": "youtube_link", 563 + "type": "text", 564 + "primaryKey": false, 565 + "notNull": false 566 + }, 567 + "genres": { 568 + "name": "genres", 569 + "type": "text[]", 570 + "primaryKey": false, 571 + "notNull": false 572 + }, 573 + "xata_createdat": { 574 + "name": "xata_createdat", 575 + "type": "timestamp", 576 + "primaryKey": false, 577 + "notNull": true, 578 + "default": "now()" 579 + }, 580 + "xata_updatedat": { 581 + "name": "xata_updatedat", 582 + "type": "timestamp", 583 + "primaryKey": false, 584 + "notNull": true, 585 + "default": "now()" 586 + }, 587 + "xata_version": { 588 + "name": "xata_version", 589 + "type": "integer", 590 + "primaryKey": false, 591 + "notNull": false 592 + } 593 + }, 594 + "indexes": {}, 595 + "foreignKeys": {}, 596 + "compositePrimaryKeys": {}, 597 + "uniqueConstraints": { 598 + "artists_sha256_unique": { 599 + "name": "artists_sha256_unique", 600 + "nullsNotDistinct": false, 601 + "columns": [ 602 + "sha256" 603 + ] 604 + }, 605 + "artists_uri_unique": { 606 + "name": "artists_uri_unique", 607 + "nullsNotDistinct": false, 608 + "columns": [ 609 + "uri" 610 + ] 611 + } 612 + }, 613 + "policies": {}, 614 + "checkConstraints": {}, 615 + "isRLSEnabled": false 616 + }, 617 + "public.dropbox_accounts": { 618 + "name": "dropbox_accounts", 619 + "schema": "", 620 + "columns": { 621 + "xata_id": { 622 + "name": "xata_id", 623 + "type": "text", 624 + "primaryKey": true, 625 + "notNull": true, 626 + "default": "xata_id()" 627 + }, 628 + "email": { 629 + "name": "email", 630 + "type": "text", 631 + "primaryKey": false, 632 + "notNull": true 633 + }, 634 + "is_beta_user": { 635 + "name": "is_beta_user", 636 + "type": "boolean", 637 + "primaryKey": false, 638 + "notNull": true, 639 + "default": false 640 + }, 641 + "user_id": { 642 + "name": "user_id", 643 + "type": "text", 644 + "primaryKey": false, 645 + "notNull": true 646 + }, 647 + "xata_version": { 648 + "name": "xata_version", 649 + "type": "text", 650 + "primaryKey": false, 651 + "notNull": false 652 + }, 653 + "xata_createdat": { 654 + "name": "xata_createdat", 655 + "type": "timestamp", 656 + "primaryKey": false, 657 + "notNull": true, 658 + "default": "now()" 659 + }, 660 + "xata_updatedat": { 661 + "name": "xata_updatedat", 662 + "type": "timestamp", 663 + "primaryKey": false, 664 + "notNull": true, 665 + "default": "now()" 666 + } 667 + }, 668 + "indexes": {}, 669 + "foreignKeys": { 670 + "dropbox_accounts_user_id_users_xata_id_fk": { 671 + "name": "dropbox_accounts_user_id_users_xata_id_fk", 672 + "tableFrom": "dropbox_accounts", 673 + "tableTo": "users", 674 + "columnsFrom": [ 675 + "user_id" 676 + ], 677 + "columnsTo": [ 678 + "xata_id" 679 + ], 680 + "onDelete": "no action", 681 + "onUpdate": "no action" 682 + } 683 + }, 684 + "compositePrimaryKeys": {}, 685 + "uniqueConstraints": { 686 + "dropbox_accounts_email_unique": { 687 + "name": "dropbox_accounts_email_unique", 688 + "nullsNotDistinct": false, 689 + "columns": [ 690 + "email" 691 + ] 692 + } 693 + }, 694 + "policies": {}, 695 + "checkConstraints": {}, 696 + "isRLSEnabled": false 697 + }, 698 + "public.dropbox_directories": { 699 + "name": "dropbox_directories", 700 + "schema": "", 701 + "columns": { 702 + "xata_id": { 703 + "name": "xata_id", 704 + "type": "text", 705 + "primaryKey": true, 706 + "notNull": true, 707 + "default": "xata_id()" 708 + }, 709 + "name": { 710 + "name": "name", 711 + "type": "text", 712 + "primaryKey": false, 713 + "notNull": true 714 + }, 715 + "path": { 716 + "name": "path", 717 + "type": "text", 718 + "primaryKey": false, 719 + "notNull": true 720 + }, 721 + "parent_id": { 722 + "name": "parent_id", 723 + "type": "text", 724 + "primaryKey": false, 725 + "notNull": false 726 + }, 727 + "dropbox_id": { 728 + "name": "dropbox_id", 729 + "type": "text", 730 + "primaryKey": false, 731 + "notNull": true 732 + }, 733 + "file_id": { 734 + "name": "file_id", 735 + "type": "text", 736 + "primaryKey": false, 737 + "notNull": true 738 + }, 739 + "xata_version": { 740 + "name": "xata_version", 741 + "type": "text", 742 + "primaryKey": false, 743 + "notNull": false 744 + }, 745 + "xata_createdat": { 746 + "name": "xata_createdat", 747 + "type": "timestamp", 748 + "primaryKey": false, 749 + "notNull": true, 750 + "default": "now()" 751 + }, 752 + "xata_updatedat": { 753 + "name": "xata_updatedat", 754 + "type": "timestamp", 755 + "primaryKey": false, 756 + "notNull": true, 757 + "default": "now()" 758 + } 759 + }, 760 + "indexes": {}, 761 + "foreignKeys": { 762 + "dropbox_directories_parent_id_dropbox_directories_xata_id_fk": { 763 + "name": "dropbox_directories_parent_id_dropbox_directories_xata_id_fk", 764 + "tableFrom": "dropbox_directories", 765 + "tableTo": "dropbox_directories", 766 + "columnsFrom": [ 767 + "parent_id" 768 + ], 769 + "columnsTo": [ 770 + "xata_id" 771 + ], 772 + "onDelete": "no action", 773 + "onUpdate": "no action" 774 + } 775 + }, 776 + "compositePrimaryKeys": {}, 777 + "uniqueConstraints": { 778 + "dropbox_directories_file_id_unique": { 779 + "name": "dropbox_directories_file_id_unique", 780 + "nullsNotDistinct": false, 781 + "columns": [ 782 + "file_id" 783 + ] 784 + } 785 + }, 786 + "policies": {}, 787 + "checkConstraints": {}, 788 + "isRLSEnabled": false 789 + }, 790 + "public.dropbox_paths": { 791 + "name": "dropbox_paths", 792 + "schema": "", 793 + "columns": { 794 + "xata_id": { 795 + "name": "xata_id", 796 + "type": "text", 797 + "primaryKey": true, 798 + "notNull": true, 799 + "default": "xata_id()" 800 + }, 801 + "path": { 802 + "name": "path", 803 + "type": "text", 804 + "primaryKey": false, 805 + "notNull": true 806 + }, 807 + "name": { 808 + "name": "name", 809 + "type": "text", 810 + "primaryKey": false, 811 + "notNull": true 812 + }, 813 + "dropbox_id": { 814 + "name": "dropbox_id", 815 + "type": "text", 816 + "primaryKey": false, 817 + "notNull": true 818 + }, 819 + "track_id": { 820 + "name": "track_id", 821 + "type": "text", 822 + "primaryKey": false, 823 + "notNull": true 824 + }, 825 + "directory_id": { 826 + "name": "directory_id", 827 + "type": "text", 828 + "primaryKey": false, 829 + "notNull": false 830 + }, 831 + "file_id": { 832 + "name": "file_id", 833 + "type": "text", 834 + "primaryKey": false, 835 + "notNull": true 836 + }, 837 + "xata_version": { 838 + "name": "xata_version", 839 + "type": "text", 840 + "primaryKey": false, 841 + "notNull": false 842 + }, 843 + "xata_createdat": { 844 + "name": "xata_createdat", 845 + "type": "timestamp", 846 + "primaryKey": false, 847 + "notNull": true, 848 + "default": "now()" 849 + }, 850 + "xata_updatedat": { 851 + "name": "xata_updatedat", 852 + "type": "timestamp", 853 + "primaryKey": false, 854 + "notNull": true, 855 + "default": "now()" 856 + } 857 + }, 858 + "indexes": {}, 859 + "foreignKeys": { 860 + "dropbox_paths_directory_id_dropbox_directories_xata_id_fk": { 861 + "name": "dropbox_paths_directory_id_dropbox_directories_xata_id_fk", 862 + "tableFrom": "dropbox_paths", 863 + "tableTo": "dropbox_directories", 864 + "columnsFrom": [ 865 + "directory_id" 866 + ], 867 + "columnsTo": [ 868 + "xata_id" 869 + ], 870 + "onDelete": "no action", 871 + "onUpdate": "no action" 872 + } 873 + }, 874 + "compositePrimaryKeys": {}, 875 + "uniqueConstraints": { 876 + "dropbox_paths_file_id_unique": { 877 + "name": "dropbox_paths_file_id_unique", 878 + "nullsNotDistinct": false, 879 + "columns": [ 880 + "file_id" 881 + ] 882 + } 883 + }, 884 + "policies": {}, 885 + "checkConstraints": {}, 886 + "isRLSEnabled": false 887 + }, 888 + "public.dropbox_tokens": { 889 + "name": "dropbox_tokens", 890 + "schema": "", 891 + "columns": { 892 + "xata_id": { 893 + "name": "xata_id", 894 + "type": "text", 895 + "primaryKey": true, 896 + "notNull": true, 897 + "default": "xata_id()" 898 + }, 899 + "refresh_token": { 900 + "name": "refresh_token", 901 + "type": "text", 902 + "primaryKey": false, 903 + "notNull": true 904 + }, 905 + "xata_createdat": { 906 + "name": "xata_createdat", 907 + "type": "timestamp", 908 + "primaryKey": false, 909 + "notNull": true, 910 + "default": "now()" 911 + }, 912 + "xata_updatedat": { 913 + "name": "xata_updatedat", 914 + "type": "timestamp", 915 + "primaryKey": false, 916 + "notNull": true, 917 + "default": "now()" 918 + } 919 + }, 920 + "indexes": {}, 921 + "foreignKeys": {}, 922 + "compositePrimaryKeys": {}, 923 + "uniqueConstraints": {}, 924 + "policies": {}, 925 + "checkConstraints": {}, 926 + "isRLSEnabled": false 927 + }, 928 + "public.dropbox": { 929 + "name": "dropbox", 930 + "schema": "", 931 + "columns": { 932 + "xata_id": { 933 + "name": "xata_id", 934 + "type": "text", 935 + "primaryKey": true, 936 + "notNull": true, 937 + "default": "xata_id()" 938 + }, 939 + "user_id": { 940 + "name": "user_id", 941 + "type": "text", 942 + "primaryKey": false, 943 + "notNull": true 944 + }, 945 + "dropbox_token_id": { 946 + "name": "dropbox_token_id", 947 + "type": "text", 948 + "primaryKey": false, 949 + "notNull": true 950 + }, 951 + "xata_version": { 952 + "name": "xata_version", 953 + "type": "text", 954 + "primaryKey": false, 955 + "notNull": false 956 + }, 957 + "xata_createdat": { 958 + "name": "xata_createdat", 959 + "type": "timestamp", 960 + "primaryKey": false, 961 + "notNull": true, 962 + "default": "now()" 963 + }, 964 + "xata_updatedat": { 965 + "name": "xata_updatedat", 966 + "type": "timestamp", 967 + "primaryKey": false, 968 + "notNull": true, 969 + "default": "now()" 970 + } 971 + }, 972 + "indexes": {}, 973 + "foreignKeys": { 974 + "dropbox_user_id_users_xata_id_fk": { 975 + "name": "dropbox_user_id_users_xata_id_fk", 976 + "tableFrom": "dropbox", 977 + "tableTo": "users", 978 + "columnsFrom": [ 979 + "user_id" 980 + ], 981 + "columnsTo": [ 982 + "xata_id" 983 + ], 984 + "onDelete": "no action", 985 + "onUpdate": "no action" 986 + }, 987 + "dropbox_dropbox_token_id_dropbox_tokens_xata_id_fk": { 988 + "name": "dropbox_dropbox_token_id_dropbox_tokens_xata_id_fk", 989 + "tableFrom": "dropbox", 990 + "tableTo": "dropbox_tokens", 991 + "columnsFrom": [ 992 + "dropbox_token_id" 993 + ], 994 + "columnsTo": [ 995 + "xata_id" 996 + ], 997 + "onDelete": "no action", 998 + "onUpdate": "no action" 999 + } 1000 + }, 1001 + "compositePrimaryKeys": {}, 1002 + "uniqueConstraints": {}, 1003 + "policies": {}, 1004 + "checkConstraints": {}, 1005 + "isRLSEnabled": false 1006 + }, 1007 + "public.feeds": { 1008 + "name": "feeds", 1009 + "schema": "", 1010 + "columns": { 1011 + "xata_id": { 1012 + "name": "xata_id", 1013 + "type": "text", 1014 + "primaryKey": true, 1015 + "notNull": true, 1016 + "default": "xata_id()" 1017 + }, 1018 + "display_name": { 1019 + "name": "display_name", 1020 + "type": "text", 1021 + "primaryKey": false, 1022 + "notNull": true 1023 + }, 1024 + "description": { 1025 + "name": "description", 1026 + "type": "text", 1027 + "primaryKey": false, 1028 + "notNull": false 1029 + }, 1030 + "did": { 1031 + "name": "did", 1032 + "type": "text", 1033 + "primaryKey": false, 1034 + "notNull": true 1035 + }, 1036 + "uri": { 1037 + "name": "uri", 1038 + "type": "text", 1039 + "primaryKey": false, 1040 + "notNull": true 1041 + }, 1042 + "avatar": { 1043 + "name": "avatar", 1044 + "type": "text", 1045 + "primaryKey": false, 1046 + "notNull": false 1047 + }, 1048 + "user_id": { 1049 + "name": "user_id", 1050 + "type": "text", 1051 + "primaryKey": false, 1052 + "notNull": true 1053 + }, 1054 + "xata_version": { 1055 + "name": "xata_version", 1056 + "type": "integer", 1057 + "primaryKey": false, 1058 + "notNull": false 1059 + }, 1060 + "xata_createdat": { 1061 + "name": "xata_createdat", 1062 + "type": "timestamp", 1063 + "primaryKey": false, 1064 + "notNull": true, 1065 + "default": "now()" 1066 + }, 1067 + "xata_updatedat": { 1068 + "name": "xata_updatedat", 1069 + "type": "timestamp", 1070 + "primaryKey": false, 1071 + "notNull": true, 1072 + "default": "now()" 1073 + } 1074 + }, 1075 + "indexes": {}, 1076 + "foreignKeys": { 1077 + "feeds_user_id_users_xata_id_fk": { 1078 + "name": "feeds_user_id_users_xata_id_fk", 1079 + "tableFrom": "feeds", 1080 + "tableTo": "users", 1081 + "columnsFrom": [ 1082 + "user_id" 1083 + ], 1084 + "columnsTo": [ 1085 + "xata_id" 1086 + ], 1087 + "onDelete": "no action", 1088 + "onUpdate": "no action" 1089 + } 1090 + }, 1091 + "compositePrimaryKeys": {}, 1092 + "uniqueConstraints": { 1093 + "feeds_uri_unique": { 1094 + "name": "feeds_uri_unique", 1095 + "nullsNotDistinct": false, 1096 + "columns": [ 1097 + "uri" 1098 + ] 1099 + } 1100 + }, 1101 + "policies": {}, 1102 + "checkConstraints": {}, 1103 + "isRLSEnabled": false 1104 + }, 1105 + "public.follows": { 1106 + "name": "follows", 1107 + "schema": "", 1108 + "columns": { 1109 + "xata_id": { 1110 + "name": "xata_id", 1111 + "type": "text", 1112 + "primaryKey": true, 1113 + "notNull": true, 1114 + "default": "xata_id()" 1115 + }, 1116 + "uri": { 1117 + "name": "uri", 1118 + "type": "text", 1119 + "primaryKey": false, 1120 + "notNull": true 1121 + }, 1122 + "follower_did": { 1123 + "name": "follower_did", 1124 + "type": "text", 1125 + "primaryKey": false, 1126 + "notNull": true 1127 + }, 1128 + "subject_did": { 1129 + "name": "subject_did", 1130 + "type": "text", 1131 + "primaryKey": false, 1132 + "notNull": true 1133 + }, 1134 + "xata_version": { 1135 + "name": "xata_version", 1136 + "type": "integer", 1137 + "primaryKey": false, 1138 + "notNull": false 1139 + }, 1140 + "xata_createdat": { 1141 + "name": "xata_createdat", 1142 + "type": "timestamp", 1143 + "primaryKey": false, 1144 + "notNull": true, 1145 + "default": "now()" 1146 + }, 1147 + "xata_updatedat": { 1148 + "name": "xata_updatedat", 1149 + "type": "timestamp", 1150 + "primaryKey": false, 1151 + "notNull": true, 1152 + "default": "now()" 1153 + } 1154 + }, 1155 + "indexes": { 1156 + "follows_follower_subject_unique": { 1157 + "name": "follows_follower_subject_unique", 1158 + "columns": [ 1159 + { 1160 + "expression": "follower_did", 1161 + "isExpression": false, 1162 + "asc": true, 1163 + "nulls": "last" 1164 + }, 1165 + { 1166 + "expression": "subject_did", 1167 + "isExpression": false, 1168 + "asc": true, 1169 + "nulls": "last" 1170 + } 1171 + ], 1172 + "isUnique": true, 1173 + "concurrently": false, 1174 + "method": "btree", 1175 + "with": {} 1176 + } 1177 + }, 1178 + "foreignKeys": {}, 1179 + "compositePrimaryKeys": {}, 1180 + "uniqueConstraints": { 1181 + "follows_uri_unique": { 1182 + "name": "follows_uri_unique", 1183 + "nullsNotDistinct": false, 1184 + "columns": [ 1185 + "uri" 1186 + ] 1187 + } 1188 + }, 1189 + "policies": {}, 1190 + "checkConstraints": {}, 1191 + "isRLSEnabled": false 1192 + }, 1193 + "public.google_drive_accounts": { 1194 + "name": "google_drive_accounts", 1195 + "schema": "", 1196 + "columns": { 1197 + "xata_id": { 1198 + "name": "xata_id", 1199 + "type": "text", 1200 + "primaryKey": true, 1201 + "notNull": true, 1202 + "default": "xata_id()" 1203 + }, 1204 + "email": { 1205 + "name": "email", 1206 + "type": "text", 1207 + "primaryKey": false, 1208 + "notNull": true 1209 + }, 1210 + "is_beta_user": { 1211 + "name": "is_beta_user", 1212 + "type": "boolean", 1213 + "primaryKey": false, 1214 + "notNull": true, 1215 + "default": false 1216 + }, 1217 + "user_id": { 1218 + "name": "user_id", 1219 + "type": "text", 1220 + "primaryKey": false, 1221 + "notNull": true 1222 + }, 1223 + "xata_version": { 1224 + "name": "xata_version", 1225 + "type": "text", 1226 + "primaryKey": false, 1227 + "notNull": false 1228 + }, 1229 + "xata_createdat": { 1230 + "name": "xata_createdat", 1231 + "type": "timestamp", 1232 + "primaryKey": false, 1233 + "notNull": true, 1234 + "default": "now()" 1235 + }, 1236 + "xata_updatedat": { 1237 + "name": "xata_updatedat", 1238 + "type": "timestamp", 1239 + "primaryKey": false, 1240 + "notNull": true, 1241 + "default": "now()" 1242 + } 1243 + }, 1244 + "indexes": {}, 1245 + "foreignKeys": { 1246 + "google_drive_accounts_user_id_users_xata_id_fk": { 1247 + "name": "google_drive_accounts_user_id_users_xata_id_fk", 1248 + "tableFrom": "google_drive_accounts", 1249 + "tableTo": "users", 1250 + "columnsFrom": [ 1251 + "user_id" 1252 + ], 1253 + "columnsTo": [ 1254 + "xata_id" 1255 + ], 1256 + "onDelete": "no action", 1257 + "onUpdate": "no action" 1258 + } 1259 + }, 1260 + "compositePrimaryKeys": {}, 1261 + "uniqueConstraints": { 1262 + "google_drive_accounts_email_unique": { 1263 + "name": "google_drive_accounts_email_unique", 1264 + "nullsNotDistinct": false, 1265 + "columns": [ 1266 + "email" 1267 + ] 1268 + } 1269 + }, 1270 + "policies": {}, 1271 + "checkConstraints": {}, 1272 + "isRLSEnabled": false 1273 + }, 1274 + "public.google_drive_directories": { 1275 + "name": "google_drive_directories", 1276 + "schema": "", 1277 + "columns": { 1278 + "xata_id": { 1279 + "name": "xata_id", 1280 + "type": "text", 1281 + "primaryKey": true, 1282 + "notNull": true, 1283 + "default": "xata_id()" 1284 + }, 1285 + "name": { 1286 + "name": "name", 1287 + "type": "text", 1288 + "primaryKey": false, 1289 + "notNull": true 1290 + }, 1291 + "path": { 1292 + "name": "path", 1293 + "type": "text", 1294 + "primaryKey": false, 1295 + "notNull": true 1296 + }, 1297 + "parent_id": { 1298 + "name": "parent_id", 1299 + "type": "text", 1300 + "primaryKey": false, 1301 + "notNull": false 1302 + }, 1303 + "google_drive_id": { 1304 + "name": "google_drive_id", 1305 + "type": "text", 1306 + "primaryKey": false, 1307 + "notNull": true 1308 + }, 1309 + "file_id": { 1310 + "name": "file_id", 1311 + "type": "text", 1312 + "primaryKey": false, 1313 + "notNull": true 1314 + }, 1315 + "xata_version": { 1316 + "name": "xata_version", 1317 + "type": "text", 1318 + "primaryKey": false, 1319 + "notNull": false 1320 + }, 1321 + "xata_createdat": { 1322 + "name": "xata_createdat", 1323 + "type": "timestamp", 1324 + "primaryKey": false, 1325 + "notNull": true, 1326 + "default": "now()" 1327 + }, 1328 + "xata_updatedat": { 1329 + "name": "xata_updatedat", 1330 + "type": "timestamp", 1331 + "primaryKey": false, 1332 + "notNull": true, 1333 + "default": "now()" 1334 + } 1335 + }, 1336 + "indexes": {}, 1337 + "foreignKeys": { 1338 + "google_drive_directories_parent_id_google_drive_directories_xata_id_fk": { 1339 + "name": "google_drive_directories_parent_id_google_drive_directories_xata_id_fk", 1340 + "tableFrom": "google_drive_directories", 1341 + "tableTo": "google_drive_directories", 1342 + "columnsFrom": [ 1343 + "parent_id" 1344 + ], 1345 + "columnsTo": [ 1346 + "xata_id" 1347 + ], 1348 + "onDelete": "no action", 1349 + "onUpdate": "no action" 1350 + } 1351 + }, 1352 + "compositePrimaryKeys": {}, 1353 + "uniqueConstraints": { 1354 + "google_drive_directories_file_id_unique": { 1355 + "name": "google_drive_directories_file_id_unique", 1356 + "nullsNotDistinct": false, 1357 + "columns": [ 1358 + "file_id" 1359 + ] 1360 + } 1361 + }, 1362 + "policies": {}, 1363 + "checkConstraints": {}, 1364 + "isRLSEnabled": false 1365 + }, 1366 + "public.google_drive_paths": { 1367 + "name": "google_drive_paths", 1368 + "schema": "", 1369 + "columns": { 1370 + "xata_id": { 1371 + "name": "xata_id", 1372 + "type": "text", 1373 + "primaryKey": true, 1374 + "notNull": true, 1375 + "default": "xata_id()" 1376 + }, 1377 + "google_drive_id": { 1378 + "name": "google_drive_id", 1379 + "type": "text", 1380 + "primaryKey": false, 1381 + "notNull": true 1382 + }, 1383 + "track_id": { 1384 + "name": "track_id", 1385 + "type": "text", 1386 + "primaryKey": false, 1387 + "notNull": true 1388 + }, 1389 + "name": { 1390 + "name": "name", 1391 + "type": "text", 1392 + "primaryKey": false, 1393 + "notNull": true 1394 + }, 1395 + "directory_id": { 1396 + "name": "directory_id", 1397 + "type": "text", 1398 + "primaryKey": false, 1399 + "notNull": false 1400 + }, 1401 + "file_id": { 1402 + "name": "file_id", 1403 + "type": "text", 1404 + "primaryKey": false, 1405 + "notNull": true 1406 + }, 1407 + "xata_version": { 1408 + "name": "xata_version", 1409 + "type": "text", 1410 + "primaryKey": false, 1411 + "notNull": false 1412 + }, 1413 + "xata_createdat": { 1414 + "name": "xata_createdat", 1415 + "type": "timestamp", 1416 + "primaryKey": false, 1417 + "notNull": true, 1418 + "default": "now()" 1419 + }, 1420 + "xata_updatedat": { 1421 + "name": "xata_updatedat", 1422 + "type": "timestamp", 1423 + "primaryKey": false, 1424 + "notNull": true, 1425 + "default": "now()" 1426 + } 1427 + }, 1428 + "indexes": {}, 1429 + "foreignKeys": { 1430 + "google_drive_paths_directory_id_google_drive_directories_xata_id_fk": { 1431 + "name": "google_drive_paths_directory_id_google_drive_directories_xata_id_fk", 1432 + "tableFrom": "google_drive_paths", 1433 + "tableTo": "google_drive_directories", 1434 + "columnsFrom": [ 1435 + "directory_id" 1436 + ], 1437 + "columnsTo": [ 1438 + "xata_id" 1439 + ], 1440 + "onDelete": "no action", 1441 + "onUpdate": "no action" 1442 + } 1443 + }, 1444 + "compositePrimaryKeys": {}, 1445 + "uniqueConstraints": { 1446 + "google_drive_paths_file_id_unique": { 1447 + "name": "google_drive_paths_file_id_unique", 1448 + "nullsNotDistinct": false, 1449 + "columns": [ 1450 + "file_id" 1451 + ] 1452 + } 1453 + }, 1454 + "policies": {}, 1455 + "checkConstraints": {}, 1456 + "isRLSEnabled": false 1457 + }, 1458 + "public.google_drive_tokens": { 1459 + "name": "google_drive_tokens", 1460 + "schema": "", 1461 + "columns": { 1462 + "xata_id": { 1463 + "name": "xata_id", 1464 + "type": "text", 1465 + "primaryKey": true, 1466 + "notNull": true, 1467 + "default": "xata_id()" 1468 + }, 1469 + "refresh_token": { 1470 + "name": "refresh_token", 1471 + "type": "text", 1472 + "primaryKey": false, 1473 + "notNull": true 1474 + }, 1475 + "xata_createdat": { 1476 + "name": "xata_createdat", 1477 + "type": "timestamp", 1478 + "primaryKey": false, 1479 + "notNull": true, 1480 + "default": "now()" 1481 + }, 1482 + "xata_updatedat": { 1483 + "name": "xata_updatedat", 1484 + "type": "timestamp", 1485 + "primaryKey": false, 1486 + "notNull": true, 1487 + "default": "now()" 1488 + } 1489 + }, 1490 + "indexes": {}, 1491 + "foreignKeys": {}, 1492 + "compositePrimaryKeys": {}, 1493 + "uniqueConstraints": {}, 1494 + "policies": {}, 1495 + "checkConstraints": {}, 1496 + "isRLSEnabled": false 1497 + }, 1498 + "public.google_drive": { 1499 + "name": "google_drive", 1500 + "schema": "", 1501 + "columns": { 1502 + "xata_id": { 1503 + "name": "xata_id", 1504 + "type": "text", 1505 + "primaryKey": true, 1506 + "notNull": true, 1507 + "default": "xata_id()" 1508 + }, 1509 + "google_drive_token_id": { 1510 + "name": "google_drive_token_id", 1511 + "type": "text", 1512 + "primaryKey": false, 1513 + "notNull": true 1514 + }, 1515 + "user_id": { 1516 + "name": "user_id", 1517 + "type": "text", 1518 + "primaryKey": false, 1519 + "notNull": true 1520 + }, 1521 + "xata_version": { 1522 + "name": "xata_version", 1523 + "type": "text", 1524 + "primaryKey": false, 1525 + "notNull": false 1526 + }, 1527 + "xata_createdat": { 1528 + "name": "xata_createdat", 1529 + "type": "timestamp", 1530 + "primaryKey": false, 1531 + "notNull": true, 1532 + "default": "now()" 1533 + }, 1534 + "xata_updatedat": { 1535 + "name": "xata_updatedat", 1536 + "type": "timestamp", 1537 + "primaryKey": false, 1538 + "notNull": true, 1539 + "default": "now()" 1540 + } 1541 + }, 1542 + "indexes": {}, 1543 + "foreignKeys": { 1544 + "google_drive_google_drive_token_id_google_drive_tokens_xata_id_fk": { 1545 + "name": "google_drive_google_drive_token_id_google_drive_tokens_xata_id_fk", 1546 + "tableFrom": "google_drive", 1547 + "tableTo": "google_drive_tokens", 1548 + "columnsFrom": [ 1549 + "google_drive_token_id" 1550 + ], 1551 + "columnsTo": [ 1552 + "xata_id" 1553 + ], 1554 + "onDelete": "no action", 1555 + "onUpdate": "no action" 1556 + }, 1557 + "google_drive_user_id_users_xata_id_fk": { 1558 + "name": "google_drive_user_id_users_xata_id_fk", 1559 + "tableFrom": "google_drive", 1560 + "tableTo": "users", 1561 + "columnsFrom": [ 1562 + "user_id" 1563 + ], 1564 + "columnsTo": [ 1565 + "xata_id" 1566 + ], 1567 + "onDelete": "no action", 1568 + "onUpdate": "no action" 1569 + } 1570 + }, 1571 + "compositePrimaryKeys": {}, 1572 + "uniqueConstraints": {}, 1573 + "policies": {}, 1574 + "checkConstraints": {}, 1575 + "isRLSEnabled": false 1576 + }, 1577 + "public.loved_tracks": { 1578 + "name": "loved_tracks", 1579 + "schema": "", 1580 + "columns": { 1581 + "xata_id": { 1582 + "name": "xata_id", 1583 + "type": "text", 1584 + "primaryKey": true, 1585 + "notNull": true, 1586 + "default": "xata_id()" 1587 + }, 1588 + "user_id": { 1589 + "name": "user_id", 1590 + "type": "text", 1591 + "primaryKey": false, 1592 + "notNull": true 1593 + }, 1594 + "track_id": { 1595 + "name": "track_id", 1596 + "type": "text", 1597 + "primaryKey": false, 1598 + "notNull": true 1599 + }, 1600 + "uri": { 1601 + "name": "uri", 1602 + "type": "text", 1603 + "primaryKey": false, 1604 + "notNull": false 1605 + }, 1606 + "xata_createdat": { 1607 + "name": "xata_createdat", 1608 + "type": "timestamp", 1609 + "primaryKey": false, 1610 + "notNull": true, 1611 + "default": "now()" 1612 + } 1613 + }, 1614 + "indexes": {}, 1615 + "foreignKeys": { 1616 + "loved_tracks_user_id_users_xata_id_fk": { 1617 + "name": "loved_tracks_user_id_users_xata_id_fk", 1618 + "tableFrom": "loved_tracks", 1619 + "tableTo": "users", 1620 + "columnsFrom": [ 1621 + "user_id" 1622 + ], 1623 + "columnsTo": [ 1624 + "xata_id" 1625 + ], 1626 + "onDelete": "no action", 1627 + "onUpdate": "no action" 1628 + }, 1629 + "loved_tracks_track_id_tracks_xata_id_fk": { 1630 + "name": "loved_tracks_track_id_tracks_xata_id_fk", 1631 + "tableFrom": "loved_tracks", 1632 + "tableTo": "tracks", 1633 + "columnsFrom": [ 1634 + "track_id" 1635 + ], 1636 + "columnsTo": [ 1637 + "xata_id" 1638 + ], 1639 + "onDelete": "no action", 1640 + "onUpdate": "no action" 1641 + } 1642 + }, 1643 + "compositePrimaryKeys": {}, 1644 + "uniqueConstraints": { 1645 + "loved_tracks_uri_unique": { 1646 + "name": "loved_tracks_uri_unique", 1647 + "nullsNotDistinct": false, 1648 + "columns": [ 1649 + "uri" 1650 + ] 1651 + } 1652 + }, 1653 + "policies": {}, 1654 + "checkConstraints": {}, 1655 + "isRLSEnabled": false 1656 + }, 1657 + "public.playlist_tracks": { 1658 + "name": "playlist_tracks", 1659 + "schema": "", 1660 + "columns": { 1661 + "xata_id": { 1662 + "name": "xata_id", 1663 + "type": "text", 1664 + "primaryKey": true, 1665 + "notNull": true, 1666 + "default": "xata_id()" 1667 + }, 1668 + "playlist_id": { 1669 + "name": "playlist_id", 1670 + "type": "text", 1671 + "primaryKey": false, 1672 + "notNull": true 1673 + }, 1674 + "track_id": { 1675 + "name": "track_id", 1676 + "type": "text", 1677 + "primaryKey": false, 1678 + "notNull": true 1679 + }, 1680 + "xata_createdat": { 1681 + "name": "xata_createdat", 1682 + "type": "timestamp", 1683 + "primaryKey": false, 1684 + "notNull": true, 1685 + "default": "now()" 1686 + } 1687 + }, 1688 + "indexes": {}, 1689 + "foreignKeys": { 1690 + "playlist_tracks_playlist_id_playlists_xata_id_fk": { 1691 + "name": "playlist_tracks_playlist_id_playlists_xata_id_fk", 1692 + "tableFrom": "playlist_tracks", 1693 + "tableTo": "playlists", 1694 + "columnsFrom": [ 1695 + "playlist_id" 1696 + ], 1697 + "columnsTo": [ 1698 + "xata_id" 1699 + ], 1700 + "onDelete": "no action", 1701 + "onUpdate": "no action" 1702 + }, 1703 + "playlist_tracks_track_id_tracks_xata_id_fk": { 1704 + "name": "playlist_tracks_track_id_tracks_xata_id_fk", 1705 + "tableFrom": "playlist_tracks", 1706 + "tableTo": "tracks", 1707 + "columnsFrom": [ 1708 + "track_id" 1709 + ], 1710 + "columnsTo": [ 1711 + "xata_id" 1712 + ], 1713 + "onDelete": "no action", 1714 + "onUpdate": "no action" 1715 + } 1716 + }, 1717 + "compositePrimaryKeys": {}, 1718 + "uniqueConstraints": {}, 1719 + "policies": {}, 1720 + "checkConstraints": {}, 1721 + "isRLSEnabled": false 1722 + }, 1723 + "public.playlists": { 1724 + "name": "playlists", 1725 + "schema": "", 1726 + "columns": { 1727 + "xata_id": { 1728 + "name": "xata_id", 1729 + "type": "text", 1730 + "primaryKey": true, 1731 + "notNull": true, 1732 + "default": "xata_id()" 1733 + }, 1734 + "name": { 1735 + "name": "name", 1736 + "type": "text", 1737 + "primaryKey": false, 1738 + "notNull": true 1739 + }, 1740 + "picture": { 1741 + "name": "picture", 1742 + "type": "text", 1743 + "primaryKey": false, 1744 + "notNull": false 1745 + }, 1746 + "description": { 1747 + "name": "description", 1748 + "type": "text", 1749 + "primaryKey": false, 1750 + "notNull": false 1751 + }, 1752 + "uri": { 1753 + "name": "uri", 1754 + "type": "text", 1755 + "primaryKey": false, 1756 + "notNull": false 1757 + }, 1758 + "spotify_link": { 1759 + "name": "spotify_link", 1760 + "type": "text", 1761 + "primaryKey": false, 1762 + "notNull": false 1763 + }, 1764 + "tidal_link": { 1765 + "name": "tidal_link", 1766 + "type": "text", 1767 + "primaryKey": false, 1768 + "notNull": false 1769 + }, 1770 + "apple_music_link": { 1771 + "name": "apple_music_link", 1772 + "type": "text", 1773 + "primaryKey": false, 1774 + "notNull": false 1775 + }, 1776 + "created_by": { 1777 + "name": "created_by", 1778 + "type": "text", 1779 + "primaryKey": false, 1780 + "notNull": true 1781 + }, 1782 + "xata_createdat": { 1783 + "name": "xata_createdat", 1784 + "type": "timestamp", 1785 + "primaryKey": false, 1786 + "notNull": true, 1787 + "default": "now()" 1788 + }, 1789 + "xata_updatedat": { 1790 + "name": "xata_updatedat", 1791 + "type": "timestamp", 1792 + "primaryKey": false, 1793 + "notNull": true, 1794 + "default": "now()" 1795 + } 1796 + }, 1797 + "indexes": {}, 1798 + "foreignKeys": { 1799 + "playlists_created_by_users_xata_id_fk": { 1800 + "name": "playlists_created_by_users_xata_id_fk", 1801 + "tableFrom": "playlists", 1802 + "tableTo": "users", 1803 + "columnsFrom": [ 1804 + "created_by" 1805 + ], 1806 + "columnsTo": [ 1807 + "xata_id" 1808 + ], 1809 + "onDelete": "no action", 1810 + "onUpdate": "no action" 1811 + } 1812 + }, 1813 + "compositePrimaryKeys": {}, 1814 + "uniqueConstraints": { 1815 + "playlists_uri_unique": { 1816 + "name": "playlists_uri_unique", 1817 + "nullsNotDistinct": false, 1818 + "columns": [ 1819 + "uri" 1820 + ] 1821 + } 1822 + }, 1823 + "policies": {}, 1824 + "checkConstraints": {}, 1825 + "isRLSEnabled": false 1826 + }, 1827 + "public.profile_shouts": { 1828 + "name": "profile_shouts", 1829 + "schema": "", 1830 + "columns": { 1831 + "xata_id": { 1832 + "name": "xata_id", 1833 + "type": "text", 1834 + "primaryKey": true, 1835 + "notNull": true, 1836 + "default": "xata_id()" 1837 + }, 1838 + "user_id": { 1839 + "name": "user_id", 1840 + "type": "text", 1841 + "primaryKey": false, 1842 + "notNull": true 1843 + }, 1844 + "shout_id": { 1845 + "name": "shout_id", 1846 + "type": "text", 1847 + "primaryKey": false, 1848 + "notNull": true 1849 + }, 1850 + "xata_createdat": { 1851 + "name": "xata_createdat", 1852 + "type": "timestamp", 1853 + "primaryKey": false, 1854 + "notNull": true, 1855 + "default": "now()" 1856 + } 1857 + }, 1858 + "indexes": {}, 1859 + "foreignKeys": { 1860 + "profile_shouts_user_id_users_xata_id_fk": { 1861 + "name": "profile_shouts_user_id_users_xata_id_fk", 1862 + "tableFrom": "profile_shouts", 1863 + "tableTo": "users", 1864 + "columnsFrom": [ 1865 + "user_id" 1866 + ], 1867 + "columnsTo": [ 1868 + "xata_id" 1869 + ], 1870 + "onDelete": "no action", 1871 + "onUpdate": "no action" 1872 + }, 1873 + "profile_shouts_shout_id_shouts_xata_id_fk": { 1874 + "name": "profile_shouts_shout_id_shouts_xata_id_fk", 1875 + "tableFrom": "profile_shouts", 1876 + "tableTo": "shouts", 1877 + "columnsFrom": [ 1878 + "shout_id" 1879 + ], 1880 + "columnsTo": [ 1881 + "xata_id" 1882 + ], 1883 + "onDelete": "no action", 1884 + "onUpdate": "no action" 1885 + } 1886 + }, 1887 + "compositePrimaryKeys": {}, 1888 + "uniqueConstraints": {}, 1889 + "policies": {}, 1890 + "checkConstraints": {}, 1891 + "isRLSEnabled": false 1892 + }, 1893 + "public.queue_tracks": { 1894 + "name": "queue_tracks", 1895 + "schema": "", 1896 + "columns": { 1897 + "xata_id": { 1898 + "name": "xata_id", 1899 + "type": "text", 1900 + "primaryKey": true, 1901 + "notNull": true, 1902 + "default": "xata_id()" 1903 + }, 1904 + "user_id": { 1905 + "name": "user_id", 1906 + "type": "text", 1907 + "primaryKey": false, 1908 + "notNull": true 1909 + }, 1910 + "track_id": { 1911 + "name": "track_id", 1912 + "type": "text", 1913 + "primaryKey": false, 1914 + "notNull": true 1915 + }, 1916 + "position": { 1917 + "name": "position", 1918 + "type": "integer", 1919 + "primaryKey": false, 1920 + "notNull": true 1921 + }, 1922 + "file_uri": { 1923 + "name": "file_uri", 1924 + "type": "text", 1925 + "primaryKey": false, 1926 + "notNull": true 1927 + }, 1928 + "xata_version": { 1929 + "name": "xata_version", 1930 + "type": "integer", 1931 + "primaryKey": false, 1932 + "notNull": true, 1933 + "default": 0 1934 + }, 1935 + "xata_createdat": { 1936 + "name": "xata_createdat", 1937 + "type": "timestamp", 1938 + "primaryKey": false, 1939 + "notNull": true, 1940 + "default": "now()" 1941 + }, 1942 + "xata_updatedat": { 1943 + "name": "xata_updatedat", 1944 + "type": "timestamp", 1945 + "primaryKey": false, 1946 + "notNull": true, 1947 + "default": "now()" 1948 + } 1949 + }, 1950 + "indexes": {}, 1951 + "foreignKeys": { 1952 + "queue_tracks_user_id_users_xata_id_fk": { 1953 + "name": "queue_tracks_user_id_users_xata_id_fk", 1954 + "tableFrom": "queue_tracks", 1955 + "tableTo": "users", 1956 + "columnsFrom": [ 1957 + "user_id" 1958 + ], 1959 + "columnsTo": [ 1960 + "xata_id" 1961 + ], 1962 + "onDelete": "no action", 1963 + "onUpdate": "no action" 1964 + }, 1965 + "queue_tracks_track_id_tracks_xata_id_fk": { 1966 + "name": "queue_tracks_track_id_tracks_xata_id_fk", 1967 + "tableFrom": "queue_tracks", 1968 + "tableTo": "tracks", 1969 + "columnsFrom": [ 1970 + "track_id" 1971 + ], 1972 + "columnsTo": [ 1973 + "xata_id" 1974 + ], 1975 + "onDelete": "no action", 1976 + "onUpdate": "no action" 1977 + } 1978 + }, 1979 + "compositePrimaryKeys": {}, 1980 + "uniqueConstraints": {}, 1981 + "policies": {}, 1982 + "checkConstraints": {}, 1983 + "isRLSEnabled": false 1984 + }, 1985 + "public.scrobbles": { 1986 + "name": "scrobbles", 1987 + "schema": "", 1988 + "columns": { 1989 + "xata_id": { 1990 + "name": "xata_id", 1991 + "type": "text", 1992 + "primaryKey": true, 1993 + "notNull": true, 1994 + "default": "xata_id()" 1995 + }, 1996 + "user_id": { 1997 + "name": "user_id", 1998 + "type": "text", 1999 + "primaryKey": false, 2000 + "notNull": false 2001 + }, 2002 + "track_id": { 2003 + "name": "track_id", 2004 + "type": "text", 2005 + "primaryKey": false, 2006 + "notNull": false 2007 + }, 2008 + "album_id": { 2009 + "name": "album_id", 2010 + "type": "text", 2011 + "primaryKey": false, 2012 + "notNull": false 2013 + }, 2014 + "artist_id": { 2015 + "name": "artist_id", 2016 + "type": "text", 2017 + "primaryKey": false, 2018 + "notNull": false 2019 + }, 2020 + "uri": { 2021 + "name": "uri", 2022 + "type": "text", 2023 + "primaryKey": false, 2024 + "notNull": false 2025 + }, 2026 + "xata_createdat": { 2027 + "name": "xata_createdat", 2028 + "type": "timestamp", 2029 + "primaryKey": false, 2030 + "notNull": true, 2031 + "default": "now()" 2032 + }, 2033 + "xata_updatedat": { 2034 + "name": "xata_updatedat", 2035 + "type": "timestamp", 2036 + "primaryKey": false, 2037 + "notNull": true, 2038 + "default": "now()" 2039 + }, 2040 + "xata_version": { 2041 + "name": "xata_version", 2042 + "type": "integer", 2043 + "primaryKey": false, 2044 + "notNull": false 2045 + }, 2046 + "timestamp": { 2047 + "name": "timestamp", 2048 + "type": "timestamp", 2049 + "primaryKey": false, 2050 + "notNull": true, 2051 + "default": "now()" 2052 + } 2053 + }, 2054 + "indexes": {}, 2055 + "foreignKeys": { 2056 + "scrobbles_user_id_users_xata_id_fk": { 2057 + "name": "scrobbles_user_id_users_xata_id_fk", 2058 + "tableFrom": "scrobbles", 2059 + "tableTo": "users", 2060 + "columnsFrom": [ 2061 + "user_id" 2062 + ], 2063 + "columnsTo": [ 2064 + "xata_id" 2065 + ], 2066 + "onDelete": "no action", 2067 + "onUpdate": "no action" 2068 + }, 2069 + "scrobbles_track_id_tracks_xata_id_fk": { 2070 + "name": "scrobbles_track_id_tracks_xata_id_fk", 2071 + "tableFrom": "scrobbles", 2072 + "tableTo": "tracks", 2073 + "columnsFrom": [ 2074 + "track_id" 2075 + ], 2076 + "columnsTo": [ 2077 + "xata_id" 2078 + ], 2079 + "onDelete": "no action", 2080 + "onUpdate": "no action" 2081 + }, 2082 + "scrobbles_album_id_albums_xata_id_fk": { 2083 + "name": "scrobbles_album_id_albums_xata_id_fk", 2084 + "tableFrom": "scrobbles", 2085 + "tableTo": "albums", 2086 + "columnsFrom": [ 2087 + "album_id" 2088 + ], 2089 + "columnsTo": [ 2090 + "xata_id" 2091 + ], 2092 + "onDelete": "no action", 2093 + "onUpdate": "no action" 2094 + }, 2095 + "scrobbles_artist_id_artists_xata_id_fk": { 2096 + "name": "scrobbles_artist_id_artists_xata_id_fk", 2097 + "tableFrom": "scrobbles", 2098 + "tableTo": "artists", 2099 + "columnsFrom": [ 2100 + "artist_id" 2101 + ], 2102 + "columnsTo": [ 2103 + "xata_id" 2104 + ], 2105 + "onDelete": "no action", 2106 + "onUpdate": "no action" 2107 + } 2108 + }, 2109 + "compositePrimaryKeys": {}, 2110 + "uniqueConstraints": { 2111 + "scrobbles_uri_unique": { 2112 + "name": "scrobbles_uri_unique", 2113 + "nullsNotDistinct": false, 2114 + "columns": [ 2115 + "uri" 2116 + ] 2117 + } 2118 + }, 2119 + "policies": {}, 2120 + "checkConstraints": {}, 2121 + "isRLSEnabled": false 2122 + }, 2123 + "public.shout_likes": { 2124 + "name": "shout_likes", 2125 + "schema": "", 2126 + "columns": { 2127 + "xata_id": { 2128 + "name": "xata_id", 2129 + "type": "text", 2130 + "primaryKey": true, 2131 + "notNull": true, 2132 + "default": "xata_id()" 2133 + }, 2134 + "user_id": { 2135 + "name": "user_id", 2136 + "type": "text", 2137 + "primaryKey": false, 2138 + "notNull": true 2139 + }, 2140 + "shout_id": { 2141 + "name": "shout_id", 2142 + "type": "text", 2143 + "primaryKey": false, 2144 + "notNull": true 2145 + }, 2146 + "xata_createdat": { 2147 + "name": "xata_createdat", 2148 + "type": "timestamp", 2149 + "primaryKey": false, 2150 + "notNull": true, 2151 + "default": "now()" 2152 + }, 2153 + "uri": { 2154 + "name": "uri", 2155 + "type": "text", 2156 + "primaryKey": false, 2157 + "notNull": true 2158 + } 2159 + }, 2160 + "indexes": {}, 2161 + "foreignKeys": { 2162 + "shout_likes_user_id_users_xata_id_fk": { 2163 + "name": "shout_likes_user_id_users_xata_id_fk", 2164 + "tableFrom": "shout_likes", 2165 + "tableTo": "users", 2166 + "columnsFrom": [ 2167 + "user_id" 2168 + ], 2169 + "columnsTo": [ 2170 + "xata_id" 2171 + ], 2172 + "onDelete": "no action", 2173 + "onUpdate": "no action" 2174 + }, 2175 + "shout_likes_shout_id_shouts_xata_id_fk": { 2176 + "name": "shout_likes_shout_id_shouts_xata_id_fk", 2177 + "tableFrom": "shout_likes", 2178 + "tableTo": "shouts", 2179 + "columnsFrom": [ 2180 + "shout_id" 2181 + ], 2182 + "columnsTo": [ 2183 + "xata_id" 2184 + ], 2185 + "onDelete": "no action", 2186 + "onUpdate": "no action" 2187 + } 2188 + }, 2189 + "compositePrimaryKeys": {}, 2190 + "uniqueConstraints": { 2191 + "shout_likes_uri_unique": { 2192 + "name": "shout_likes_uri_unique", 2193 + "nullsNotDistinct": false, 2194 + "columns": [ 2195 + "uri" 2196 + ] 2197 + } 2198 + }, 2199 + "policies": {}, 2200 + "checkConstraints": {}, 2201 + "isRLSEnabled": false 2202 + }, 2203 + "public.shout_reports": { 2204 + "name": "shout_reports", 2205 + "schema": "", 2206 + "columns": { 2207 + "xata_id": { 2208 + "name": "xata_id", 2209 + "type": "text", 2210 + "primaryKey": true, 2211 + "notNull": true, 2212 + "default": "xata_id()" 2213 + }, 2214 + "user_id": { 2215 + "name": "user_id", 2216 + "type": "text", 2217 + "primaryKey": false, 2218 + "notNull": true 2219 + }, 2220 + "shout_id": { 2221 + "name": "shout_id", 2222 + "type": "text", 2223 + "primaryKey": false, 2224 + "notNull": true 2225 + }, 2226 + "xata_createdat": { 2227 + "name": "xata_createdat", 2228 + "type": "timestamp", 2229 + "primaryKey": false, 2230 + "notNull": true, 2231 + "default": "now()" 2232 + } 2233 + }, 2234 + "indexes": {}, 2235 + "foreignKeys": { 2236 + "shout_reports_user_id_users_xata_id_fk": { 2237 + "name": "shout_reports_user_id_users_xata_id_fk", 2238 + "tableFrom": "shout_reports", 2239 + "tableTo": "users", 2240 + "columnsFrom": [ 2241 + "user_id" 2242 + ], 2243 + "columnsTo": [ 2244 + "xata_id" 2245 + ], 2246 + "onDelete": "no action", 2247 + "onUpdate": "no action" 2248 + }, 2249 + "shout_reports_shout_id_shouts_xata_id_fk": { 2250 + "name": "shout_reports_shout_id_shouts_xata_id_fk", 2251 + "tableFrom": "shout_reports", 2252 + "tableTo": "shouts", 2253 + "columnsFrom": [ 2254 + "shout_id" 2255 + ], 2256 + "columnsTo": [ 2257 + "xata_id" 2258 + ], 2259 + "onDelete": "no action", 2260 + "onUpdate": "no action" 2261 + } 2262 + }, 2263 + "compositePrimaryKeys": {}, 2264 + "uniqueConstraints": {}, 2265 + "policies": {}, 2266 + "checkConstraints": {}, 2267 + "isRLSEnabled": false 2268 + }, 2269 + "public.shouts": { 2270 + "name": "shouts", 2271 + "schema": "", 2272 + "columns": { 2273 + "xata_id": { 2274 + "name": "xata_id", 2275 + "type": "text", 2276 + "primaryKey": true, 2277 + "notNull": true, 2278 + "default": "xata_id()" 2279 + }, 2280 + "content": { 2281 + "name": "content", 2282 + "type": "text", 2283 + "primaryKey": false, 2284 + "notNull": true 2285 + }, 2286 + "track_id": { 2287 + "name": "track_id", 2288 + "type": "text", 2289 + "primaryKey": false, 2290 + "notNull": false 2291 + }, 2292 + "artist_id": { 2293 + "name": "artist_id", 2294 + "type": "text", 2295 + "primaryKey": false, 2296 + "notNull": false 2297 + }, 2298 + "album_id": { 2299 + "name": "album_id", 2300 + "type": "text", 2301 + "primaryKey": false, 2302 + "notNull": false 2303 + }, 2304 + "scrobble_id": { 2305 + "name": "scrobble_id", 2306 + "type": "text", 2307 + "primaryKey": false, 2308 + "notNull": false 2309 + }, 2310 + "uri": { 2311 + "name": "uri", 2312 + "type": "text", 2313 + "primaryKey": false, 2314 + "notNull": true 2315 + }, 2316 + "author_id": { 2317 + "name": "author_id", 2318 + "type": "text", 2319 + "primaryKey": false, 2320 + "notNull": true 2321 + }, 2322 + "parent_id": { 2323 + "name": "parent_id", 2324 + "type": "text", 2325 + "primaryKey": false, 2326 + "notNull": false 2327 + }, 2328 + "xata_createdat": { 2329 + "name": "xata_createdat", 2330 + "type": "timestamp", 2331 + "primaryKey": false, 2332 + "notNull": true, 2333 + "default": "now()" 2334 + }, 2335 + "xata_updatedat": { 2336 + "name": "xata_updatedat", 2337 + "type": "timestamp", 2338 + "primaryKey": false, 2339 + "notNull": true, 2340 + "default": "now()" 2341 + } 2342 + }, 2343 + "indexes": {}, 2344 + "foreignKeys": { 2345 + "shouts_track_id_tracks_xata_id_fk": { 2346 + "name": "shouts_track_id_tracks_xata_id_fk", 2347 + "tableFrom": "shouts", 2348 + "tableTo": "tracks", 2349 + "columnsFrom": [ 2350 + "track_id" 2351 + ], 2352 + "columnsTo": [ 2353 + "xata_id" 2354 + ], 2355 + "onDelete": "no action", 2356 + "onUpdate": "no action" 2357 + }, 2358 + "shouts_artist_id_users_xata_id_fk": { 2359 + "name": "shouts_artist_id_users_xata_id_fk", 2360 + "tableFrom": "shouts", 2361 + "tableTo": "users", 2362 + "columnsFrom": [ 2363 + "artist_id" 2364 + ], 2365 + "columnsTo": [ 2366 + "xata_id" 2367 + ], 2368 + "onDelete": "no action", 2369 + "onUpdate": "no action" 2370 + }, 2371 + "shouts_album_id_albums_xata_id_fk": { 2372 + "name": "shouts_album_id_albums_xata_id_fk", 2373 + "tableFrom": "shouts", 2374 + "tableTo": "albums", 2375 + "columnsFrom": [ 2376 + "album_id" 2377 + ], 2378 + "columnsTo": [ 2379 + "xata_id" 2380 + ], 2381 + "onDelete": "no action", 2382 + "onUpdate": "no action" 2383 + }, 2384 + "shouts_scrobble_id_scrobbles_xata_id_fk": { 2385 + "name": "shouts_scrobble_id_scrobbles_xata_id_fk", 2386 + "tableFrom": "shouts", 2387 + "tableTo": "scrobbles", 2388 + "columnsFrom": [ 2389 + "scrobble_id" 2390 + ], 2391 + "columnsTo": [ 2392 + "xata_id" 2393 + ], 2394 + "onDelete": "no action", 2395 + "onUpdate": "no action" 2396 + }, 2397 + "shouts_author_id_users_xata_id_fk": { 2398 + "name": "shouts_author_id_users_xata_id_fk", 2399 + "tableFrom": "shouts", 2400 + "tableTo": "users", 2401 + "columnsFrom": [ 2402 + "author_id" 2403 + ], 2404 + "columnsTo": [ 2405 + "xata_id" 2406 + ], 2407 + "onDelete": "no action", 2408 + "onUpdate": "no action" 2409 + }, 2410 + "shouts_parent_id_shouts_xata_id_fk": { 2411 + "name": "shouts_parent_id_shouts_xata_id_fk", 2412 + "tableFrom": "shouts", 2413 + "tableTo": "shouts", 2414 + "columnsFrom": [ 2415 + "parent_id" 2416 + ], 2417 + "columnsTo": [ 2418 + "xata_id" 2419 + ], 2420 + "onDelete": "no action", 2421 + "onUpdate": "no action" 2422 + } 2423 + }, 2424 + "compositePrimaryKeys": {}, 2425 + "uniqueConstraints": { 2426 + "shouts_uri_unique": { 2427 + "name": "shouts_uri_unique", 2428 + "nullsNotDistinct": false, 2429 + "columns": [ 2430 + "uri" 2431 + ] 2432 + } 2433 + }, 2434 + "policies": {}, 2435 + "checkConstraints": {}, 2436 + "isRLSEnabled": false 2437 + }, 2438 + "public.spotify_accounts": { 2439 + "name": "spotify_accounts", 2440 + "schema": "", 2441 + "columns": { 2442 + "xata_id": { 2443 + "name": "xata_id", 2444 + "type": "text", 2445 + "primaryKey": true, 2446 + "notNull": true, 2447 + "default": "xata_id()" 2448 + }, 2449 + "xata_version": { 2450 + "name": "xata_version", 2451 + "type": "integer", 2452 + "primaryKey": false, 2453 + "notNull": false 2454 + }, 2455 + "email": { 2456 + "name": "email", 2457 + "type": "text", 2458 + "primaryKey": false, 2459 + "notNull": true 2460 + }, 2461 + "user_id": { 2462 + "name": "user_id", 2463 + "type": "text", 2464 + "primaryKey": false, 2465 + "notNull": true 2466 + }, 2467 + "is_beta_user": { 2468 + "name": "is_beta_user", 2469 + "type": "boolean", 2470 + "primaryKey": false, 2471 + "notNull": true, 2472 + "default": false 2473 + }, 2474 + "spotify_app_id": { 2475 + "name": "spotify_app_id", 2476 + "type": "text", 2477 + "primaryKey": false, 2478 + "notNull": false 2479 + }, 2480 + "xata_createdat": { 2481 + "name": "xata_createdat", 2482 + "type": "timestamp", 2483 + "primaryKey": false, 2484 + "notNull": true, 2485 + "default": "now()" 2486 + }, 2487 + "xata_updatedat": { 2488 + "name": "xata_updatedat", 2489 + "type": "timestamp", 2490 + "primaryKey": false, 2491 + "notNull": true, 2492 + "default": "now()" 2493 + } 2494 + }, 2495 + "indexes": {}, 2496 + "foreignKeys": { 2497 + "spotify_accounts_user_id_users_xata_id_fk": { 2498 + "name": "spotify_accounts_user_id_users_xata_id_fk", 2499 + "tableFrom": "spotify_accounts", 2500 + "tableTo": "users", 2501 + "columnsFrom": [ 2502 + "user_id" 2503 + ], 2504 + "columnsTo": [ 2505 + "xata_id" 2506 + ], 2507 + "onDelete": "no action", 2508 + "onUpdate": "no action" 2509 + } 2510 + }, 2511 + "compositePrimaryKeys": {}, 2512 + "uniqueConstraints": {}, 2513 + "policies": {}, 2514 + "checkConstraints": {}, 2515 + "isRLSEnabled": false 2516 + }, 2517 + "public.spotify_apps": { 2518 + "name": "spotify_apps", 2519 + "schema": "", 2520 + "columns": { 2521 + "xata_id": { 2522 + "name": "xata_id", 2523 + "type": "text", 2524 + "primaryKey": true, 2525 + "notNull": true, 2526 + "default": "xata_id()" 2527 + }, 2528 + "xata_version": { 2529 + "name": "xata_version", 2530 + "type": "integer", 2531 + "primaryKey": false, 2532 + "notNull": false 2533 + }, 2534 + "spotify_app_id": { 2535 + "name": "spotify_app_id", 2536 + "type": "text", 2537 + "primaryKey": false, 2538 + "notNull": true 2539 + }, 2540 + "spotify_secret": { 2541 + "name": "spotify_secret", 2542 + "type": "text", 2543 + "primaryKey": false, 2544 + "notNull": true 2545 + }, 2546 + "xata_createdat": { 2547 + "name": "xata_createdat", 2548 + "type": "timestamp", 2549 + "primaryKey": false, 2550 + "notNull": true, 2551 + "default": "now()" 2552 + }, 2553 + "xata_updatedat": { 2554 + "name": "xata_updatedat", 2555 + "type": "timestamp", 2556 + "primaryKey": false, 2557 + "notNull": true, 2558 + "default": "now()" 2559 + } 2560 + }, 2561 + "indexes": {}, 2562 + "foreignKeys": {}, 2563 + "compositePrimaryKeys": {}, 2564 + "uniqueConstraints": { 2565 + "spotify_apps_spotify_app_id_unique": { 2566 + "name": "spotify_apps_spotify_app_id_unique", 2567 + "nullsNotDistinct": false, 2568 + "columns": [ 2569 + "spotify_app_id" 2570 + ] 2571 + } 2572 + }, 2573 + "policies": {}, 2574 + "checkConstraints": {}, 2575 + "isRLSEnabled": false 2576 + }, 2577 + "public.spotify_tokens": { 2578 + "name": "spotify_tokens", 2579 + "schema": "", 2580 + "columns": { 2581 + "xata_id": { 2582 + "name": "xata_id", 2583 + "type": "text", 2584 + "primaryKey": true, 2585 + "notNull": true, 2586 + "default": "xata_id()" 2587 + }, 2588 + "xata_version": { 2589 + "name": "xata_version", 2590 + "type": "integer", 2591 + "primaryKey": false, 2592 + "notNull": false 2593 + }, 2594 + "access_token": { 2595 + "name": "access_token", 2596 + "type": "text", 2597 + "primaryKey": false, 2598 + "notNull": true 2599 + }, 2600 + "refresh_token": { 2601 + "name": "refresh_token", 2602 + "type": "text", 2603 + "primaryKey": false, 2604 + "notNull": true 2605 + }, 2606 + "user_id": { 2607 + "name": "user_id", 2608 + "type": "text", 2609 + "primaryKey": false, 2610 + "notNull": true 2611 + }, 2612 + "spotify_app_id": { 2613 + "name": "spotify_app_id", 2614 + "type": "text", 2615 + "primaryKey": false, 2616 + "notNull": true 2617 + }, 2618 + "xata_createdat": { 2619 + "name": "xata_createdat", 2620 + "type": "timestamp", 2621 + "primaryKey": false, 2622 + "notNull": true, 2623 + "default": "now()" 2624 + }, 2625 + "xata_updatedat": { 2626 + "name": "xata_updatedat", 2627 + "type": "timestamp", 2628 + "primaryKey": false, 2629 + "notNull": true, 2630 + "default": "now()" 2631 + } 2632 + }, 2633 + "indexes": {}, 2634 + "foreignKeys": { 2635 + "spotify_tokens_user_id_users_xata_id_fk": { 2636 + "name": "spotify_tokens_user_id_users_xata_id_fk", 2637 + "tableFrom": "spotify_tokens", 2638 + "tableTo": "users", 2639 + "columnsFrom": [ 2640 + "user_id" 2641 + ], 2642 + "columnsTo": [ 2643 + "xata_id" 2644 + ], 2645 + "onDelete": "no action", 2646 + "onUpdate": "no action" 2647 + } 2648 + }, 2649 + "compositePrimaryKeys": {}, 2650 + "uniqueConstraints": {}, 2651 + "policies": {}, 2652 + "checkConstraints": {}, 2653 + "isRLSEnabled": false 2654 + }, 2655 + "public.tracks": { 2656 + "name": "tracks", 2657 + "schema": "", 2658 + "columns": { 2659 + "xata_id": { 2660 + "name": "xata_id", 2661 + "type": "text", 2662 + "primaryKey": true, 2663 + "notNull": true, 2664 + "default": "xata_id()" 2665 + }, 2666 + "title": { 2667 + "name": "title", 2668 + "type": "text", 2669 + "primaryKey": false, 2670 + "notNull": true 2671 + }, 2672 + "artist": { 2673 + "name": "artist", 2674 + "type": "text", 2675 + "primaryKey": false, 2676 + "notNull": true 2677 + }, 2678 + "album_artist": { 2679 + "name": "album_artist", 2680 + "type": "text", 2681 + "primaryKey": false, 2682 + "notNull": true 2683 + }, 2684 + "album_art": { 2685 + "name": "album_art", 2686 + "type": "text", 2687 + "primaryKey": false, 2688 + "notNull": false 2689 + }, 2690 + "album": { 2691 + "name": "album", 2692 + "type": "text", 2693 + "primaryKey": false, 2694 + "notNull": true 2695 + }, 2696 + "track_number": { 2697 + "name": "track_number", 2698 + "type": "integer", 2699 + "primaryKey": false, 2700 + "notNull": false 2701 + }, 2702 + "duration": { 2703 + "name": "duration", 2704 + "type": "integer", 2705 + "primaryKey": false, 2706 + "notNull": true 2707 + }, 2708 + "mb_id": { 2709 + "name": "mb_id", 2710 + "type": "text", 2711 + "primaryKey": false, 2712 + "notNull": false 2713 + }, 2714 + "youtube_link": { 2715 + "name": "youtube_link", 2716 + "type": "text", 2717 + "primaryKey": false, 2718 + "notNull": false 2719 + }, 2720 + "spotify_link": { 2721 + "name": "spotify_link", 2722 + "type": "text", 2723 + "primaryKey": false, 2724 + "notNull": false 2725 + }, 2726 + "apple_music_link": { 2727 + "name": "apple_music_link", 2728 + "type": "text", 2729 + "primaryKey": false, 2730 + "notNull": false 2731 + }, 2732 + "tidal_link": { 2733 + "name": "tidal_link", 2734 + "type": "text", 2735 + "primaryKey": false, 2736 + "notNull": false 2737 + }, 2738 + "sha256": { 2739 + "name": "sha256", 2740 + "type": "text", 2741 + "primaryKey": false, 2742 + "notNull": true 2743 + }, 2744 + "disc_number": { 2745 + "name": "disc_number", 2746 + "type": "integer", 2747 + "primaryKey": false, 2748 + "notNull": false 2749 + }, 2750 + "lyrics": { 2751 + "name": "lyrics", 2752 + "type": "text", 2753 + "primaryKey": false, 2754 + "notNull": false 2755 + }, 2756 + "composer": { 2757 + "name": "composer", 2758 + "type": "text", 2759 + "primaryKey": false, 2760 + "notNull": false 2761 + }, 2762 + "genre": { 2763 + "name": "genre", 2764 + "type": "text", 2765 + "primaryKey": false, 2766 + "notNull": false 2767 + }, 2768 + "label": { 2769 + "name": "label", 2770 + "type": "text", 2771 + "primaryKey": false, 2772 + "notNull": false 2773 + }, 2774 + "copyright_message": { 2775 + "name": "copyright_message", 2776 + "type": "text", 2777 + "primaryKey": false, 2778 + "notNull": false 2779 + }, 2780 + "uri": { 2781 + "name": "uri", 2782 + "type": "text", 2783 + "primaryKey": false, 2784 + "notNull": false 2785 + }, 2786 + "album_uri": { 2787 + "name": "album_uri", 2788 + "type": "text", 2789 + "primaryKey": false, 2790 + "notNull": false 2791 + }, 2792 + "artist_uri": { 2793 + "name": "artist_uri", 2794 + "type": "text", 2795 + "primaryKey": false, 2796 + "notNull": false 2797 + }, 2798 + "xata_createdat": { 2799 + "name": "xata_createdat", 2800 + "type": "timestamp", 2801 + "primaryKey": false, 2802 + "notNull": true, 2803 + "default": "now()" 2804 + }, 2805 + "xata_updatedat": { 2806 + "name": "xata_updatedat", 2807 + "type": "timestamp", 2808 + "primaryKey": false, 2809 + "notNull": true, 2810 + "default": "now()" 2811 + }, 2812 + "xata_version": { 2813 + "name": "xata_version", 2814 + "type": "integer", 2815 + "primaryKey": false, 2816 + "notNull": false 2817 + } 2818 + }, 2819 + "indexes": {}, 2820 + "foreignKeys": {}, 2821 + "compositePrimaryKeys": {}, 2822 + "uniqueConstraints": { 2823 + "tracks_mb_id_unique": { 2824 + "name": "tracks_mb_id_unique", 2825 + "nullsNotDistinct": false, 2826 + "columns": [ 2827 + "mb_id" 2828 + ] 2829 + }, 2830 + "tracks_youtube_link_unique": { 2831 + "name": "tracks_youtube_link_unique", 2832 + "nullsNotDistinct": false, 2833 + "columns": [ 2834 + "youtube_link" 2835 + ] 2836 + }, 2837 + "tracks_spotify_link_unique": { 2838 + "name": "tracks_spotify_link_unique", 2839 + "nullsNotDistinct": false, 2840 + "columns": [ 2841 + "spotify_link" 2842 + ] 2843 + }, 2844 + "tracks_apple_music_link_unique": { 2845 + "name": "tracks_apple_music_link_unique", 2846 + "nullsNotDistinct": false, 2847 + "columns": [ 2848 + "apple_music_link" 2849 + ] 2850 + }, 2851 + "tracks_tidal_link_unique": { 2852 + "name": "tracks_tidal_link_unique", 2853 + "nullsNotDistinct": false, 2854 + "columns": [ 2855 + "tidal_link" 2856 + ] 2857 + }, 2858 + "tracks_sha256_unique": { 2859 + "name": "tracks_sha256_unique", 2860 + "nullsNotDistinct": false, 2861 + "columns": [ 2862 + "sha256" 2863 + ] 2864 + }, 2865 + "tracks_uri_unique": { 2866 + "name": "tracks_uri_unique", 2867 + "nullsNotDistinct": false, 2868 + "columns": [ 2869 + "uri" 2870 + ] 2871 + } 2872 + }, 2873 + "policies": {}, 2874 + "checkConstraints": {}, 2875 + "isRLSEnabled": false 2876 + }, 2877 + "public.user_albums": { 2878 + "name": "user_albums", 2879 + "schema": "", 2880 + "columns": { 2881 + "xata_id": { 2882 + "name": "xata_id", 2883 + "type": "text", 2884 + "primaryKey": true, 2885 + "notNull": true, 2886 + "default": "xata_id()" 2887 + }, 2888 + "user_id": { 2889 + "name": "user_id", 2890 + "type": "text", 2891 + "primaryKey": false, 2892 + "notNull": true 2893 + }, 2894 + "album_id": { 2895 + "name": "album_id", 2896 + "type": "text", 2897 + "primaryKey": false, 2898 + "notNull": true 2899 + }, 2900 + "xata_createdat": { 2901 + "name": "xata_createdat", 2902 + "type": "timestamp", 2903 + "primaryKey": false, 2904 + "notNull": true, 2905 + "default": "now()" 2906 + }, 2907 + "xata_updatedat": { 2908 + "name": "xata_updatedat", 2909 + "type": "timestamp", 2910 + "primaryKey": false, 2911 + "notNull": true, 2912 + "default": "now()" 2913 + }, 2914 + "xata_version": { 2915 + "name": "xata_version", 2916 + "type": "integer", 2917 + "primaryKey": false, 2918 + "notNull": false 2919 + }, 2920 + "scrobbles": { 2921 + "name": "scrobbles", 2922 + "type": "integer", 2923 + "primaryKey": false, 2924 + "notNull": false 2925 + }, 2926 + "uri": { 2927 + "name": "uri", 2928 + "type": "text", 2929 + "primaryKey": false, 2930 + "notNull": true 2931 + } 2932 + }, 2933 + "indexes": {}, 2934 + "foreignKeys": { 2935 + "user_albums_user_id_users_xata_id_fk": { 2936 + "name": "user_albums_user_id_users_xata_id_fk", 2937 + "tableFrom": "user_albums", 2938 + "tableTo": "users", 2939 + "columnsFrom": [ 2940 + "user_id" 2941 + ], 2942 + "columnsTo": [ 2943 + "xata_id" 2944 + ], 2945 + "onDelete": "no action", 2946 + "onUpdate": "no action" 2947 + }, 2948 + "user_albums_album_id_albums_xata_id_fk": { 2949 + "name": "user_albums_album_id_albums_xata_id_fk", 2950 + "tableFrom": "user_albums", 2951 + "tableTo": "albums", 2952 + "columnsFrom": [ 2953 + "album_id" 2954 + ], 2955 + "columnsTo": [ 2956 + "xata_id" 2957 + ], 2958 + "onDelete": "no action", 2959 + "onUpdate": "no action" 2960 + } 2961 + }, 2962 + "compositePrimaryKeys": {}, 2963 + "uniqueConstraints": { 2964 + "user_albums_uri_unique": { 2965 + "name": "user_albums_uri_unique", 2966 + "nullsNotDistinct": false, 2967 + "columns": [ 2968 + "uri" 2969 + ] 2970 + } 2971 + }, 2972 + "policies": {}, 2973 + "checkConstraints": {}, 2974 + "isRLSEnabled": false 2975 + }, 2976 + "public.user_artists": { 2977 + "name": "user_artists", 2978 + "schema": "", 2979 + "columns": { 2980 + "xata_id": { 2981 + "name": "xata_id", 2982 + "type": "text", 2983 + "primaryKey": true, 2984 + "notNull": true, 2985 + "default": "xata_id()" 2986 + }, 2987 + "user_id": { 2988 + "name": "user_id", 2989 + "type": "text", 2990 + "primaryKey": false, 2991 + "notNull": true 2992 + }, 2993 + "artist_id": { 2994 + "name": "artist_id", 2995 + "type": "text", 2996 + "primaryKey": false, 2997 + "notNull": true 2998 + }, 2999 + "xata_createdat": { 3000 + "name": "xata_createdat", 3001 + "type": "timestamp", 3002 + "primaryKey": false, 3003 + "notNull": true, 3004 + "default": "now()" 3005 + }, 3006 + "xata_updatedat": { 3007 + "name": "xata_updatedat", 3008 + "type": "timestamp", 3009 + "primaryKey": false, 3010 + "notNull": true, 3011 + "default": "now()" 3012 + }, 3013 + "xata_version": { 3014 + "name": "xata_version", 3015 + "type": "integer", 3016 + "primaryKey": false, 3017 + "notNull": false 3018 + }, 3019 + "scrobbles": { 3020 + "name": "scrobbles", 3021 + "type": "integer", 3022 + "primaryKey": false, 3023 + "notNull": false 3024 + }, 3025 + "uri": { 3026 + "name": "uri", 3027 + "type": "text", 3028 + "primaryKey": false, 3029 + "notNull": true 3030 + } 3031 + }, 3032 + "indexes": {}, 3033 + "foreignKeys": { 3034 + "user_artists_user_id_users_xata_id_fk": { 3035 + "name": "user_artists_user_id_users_xata_id_fk", 3036 + "tableFrom": "user_artists", 3037 + "tableTo": "users", 3038 + "columnsFrom": [ 3039 + "user_id" 3040 + ], 3041 + "columnsTo": [ 3042 + "xata_id" 3043 + ], 3044 + "onDelete": "no action", 3045 + "onUpdate": "no action" 3046 + }, 3047 + "user_artists_artist_id_artists_xata_id_fk": { 3048 + "name": "user_artists_artist_id_artists_xata_id_fk", 3049 + "tableFrom": "user_artists", 3050 + "tableTo": "artists", 3051 + "columnsFrom": [ 3052 + "artist_id" 3053 + ], 3054 + "columnsTo": [ 3055 + "xata_id" 3056 + ], 3057 + "onDelete": "no action", 3058 + "onUpdate": "no action" 3059 + } 3060 + }, 3061 + "compositePrimaryKeys": {}, 3062 + "uniqueConstraints": { 3063 + "user_artists_uri_unique": { 3064 + "name": "user_artists_uri_unique", 3065 + "nullsNotDistinct": false, 3066 + "columns": [ 3067 + "uri" 3068 + ] 3069 + } 3070 + }, 3071 + "policies": {}, 3072 + "checkConstraints": {}, 3073 + "isRLSEnabled": false 3074 + }, 3075 + "public.user_playlists": { 3076 + "name": "user_playlists", 3077 + "schema": "", 3078 + "columns": { 3079 + "xata_id": { 3080 + "name": "xata_id", 3081 + "type": "text", 3082 + "primaryKey": true, 3083 + "notNull": true, 3084 + "default": "xata_id()" 3085 + }, 3086 + "user_id": { 3087 + "name": "user_id", 3088 + "type": "text", 3089 + "primaryKey": false, 3090 + "notNull": true 3091 + }, 3092 + "playlist_id": { 3093 + "name": "playlist_id", 3094 + "type": "text", 3095 + "primaryKey": false, 3096 + "notNull": true 3097 + }, 3098 + "xata_createdat": { 3099 + "name": "xata_createdat", 3100 + "type": "timestamp", 3101 + "primaryKey": false, 3102 + "notNull": true, 3103 + "default": "now()" 3104 + }, 3105 + "uri": { 3106 + "name": "uri", 3107 + "type": "text", 3108 + "primaryKey": false, 3109 + "notNull": false 3110 + } 3111 + }, 3112 + "indexes": {}, 3113 + "foreignKeys": { 3114 + "user_playlists_user_id_users_xata_id_fk": { 3115 + "name": "user_playlists_user_id_users_xata_id_fk", 3116 + "tableFrom": "user_playlists", 3117 + "tableTo": "users", 3118 + "columnsFrom": [ 3119 + "user_id" 3120 + ], 3121 + "columnsTo": [ 3122 + "xata_id" 3123 + ], 3124 + "onDelete": "no action", 3125 + "onUpdate": "no action" 3126 + }, 3127 + "user_playlists_playlist_id_playlists_xata_id_fk": { 3128 + "name": "user_playlists_playlist_id_playlists_xata_id_fk", 3129 + "tableFrom": "user_playlists", 3130 + "tableTo": "playlists", 3131 + "columnsFrom": [ 3132 + "playlist_id" 3133 + ], 3134 + "columnsTo": [ 3135 + "xata_id" 3136 + ], 3137 + "onDelete": "no action", 3138 + "onUpdate": "no action" 3139 + } 3140 + }, 3141 + "compositePrimaryKeys": {}, 3142 + "uniqueConstraints": { 3143 + "user_playlists_uri_unique": { 3144 + "name": "user_playlists_uri_unique", 3145 + "nullsNotDistinct": false, 3146 + "columns": [ 3147 + "uri" 3148 + ] 3149 + } 3150 + }, 3151 + "policies": {}, 3152 + "checkConstraints": {}, 3153 + "isRLSEnabled": false 3154 + }, 3155 + "public.user_tracks": { 3156 + "name": "user_tracks", 3157 + "schema": "", 3158 + "columns": { 3159 + "xata_id": { 3160 + "name": "xata_id", 3161 + "type": "text", 3162 + "primaryKey": true, 3163 + "notNull": true, 3164 + "default": "xata_id()" 3165 + }, 3166 + "user_id": { 3167 + "name": "user_id", 3168 + "type": "text", 3169 + "primaryKey": false, 3170 + "notNull": true 3171 + }, 3172 + "track_id": { 3173 + "name": "track_id", 3174 + "type": "text", 3175 + "primaryKey": false, 3176 + "notNull": true 3177 + }, 3178 + "xata_createdat": { 3179 + "name": "xata_createdat", 3180 + "type": "timestamp", 3181 + "primaryKey": false, 3182 + "notNull": true, 3183 + "default": "now()" 3184 + }, 3185 + "xata_updatedat": { 3186 + "name": "xata_updatedat", 3187 + "type": "timestamp", 3188 + "primaryKey": false, 3189 + "notNull": true, 3190 + "default": "now()" 3191 + }, 3192 + "xata_version": { 3193 + "name": "xata_version", 3194 + "type": "integer", 3195 + "primaryKey": false, 3196 + "notNull": false 3197 + }, 3198 + "uri": { 3199 + "name": "uri", 3200 + "type": "text", 3201 + "primaryKey": false, 3202 + "notNull": true 3203 + }, 3204 + "scrobbles": { 3205 + "name": "scrobbles", 3206 + "type": "integer", 3207 + "primaryKey": false, 3208 + "notNull": false 3209 + } 3210 + }, 3211 + "indexes": {}, 3212 + "foreignKeys": { 3213 + "user_tracks_user_id_users_xata_id_fk": { 3214 + "name": "user_tracks_user_id_users_xata_id_fk", 3215 + "tableFrom": "user_tracks", 3216 + "tableTo": "users", 3217 + "columnsFrom": [ 3218 + "user_id" 3219 + ], 3220 + "columnsTo": [ 3221 + "xata_id" 3222 + ], 3223 + "onDelete": "no action", 3224 + "onUpdate": "no action" 3225 + }, 3226 + "user_tracks_track_id_tracks_xata_id_fk": { 3227 + "name": "user_tracks_track_id_tracks_xata_id_fk", 3228 + "tableFrom": "user_tracks", 3229 + "tableTo": "tracks", 3230 + "columnsFrom": [ 3231 + "track_id" 3232 + ], 3233 + "columnsTo": [ 3234 + "xata_id" 3235 + ], 3236 + "onDelete": "no action", 3237 + "onUpdate": "no action" 3238 + } 3239 + }, 3240 + "compositePrimaryKeys": {}, 3241 + "uniqueConstraints": { 3242 + "user_tracks_uri_unique": { 3243 + "name": "user_tracks_uri_unique", 3244 + "nullsNotDistinct": false, 3245 + "columns": [ 3246 + "uri" 3247 + ] 3248 + } 3249 + }, 3250 + "policies": {}, 3251 + "checkConstraints": {}, 3252 + "isRLSEnabled": false 3253 + }, 3254 + "public.users": { 3255 + "name": "users", 3256 + "schema": "", 3257 + "columns": { 3258 + "xata_id": { 3259 + "name": "xata_id", 3260 + "type": "text", 3261 + "primaryKey": true, 3262 + "notNull": true, 3263 + "default": "xata_id()" 3264 + }, 3265 + "did": { 3266 + "name": "did", 3267 + "type": "text", 3268 + "primaryKey": false, 3269 + "notNull": true 3270 + }, 3271 + "display_name": { 3272 + "name": "display_name", 3273 + "type": "text", 3274 + "primaryKey": false, 3275 + "notNull": false 3276 + }, 3277 + "handle": { 3278 + "name": "handle", 3279 + "type": "text", 3280 + "primaryKey": false, 3281 + "notNull": true 3282 + }, 3283 + "avatar": { 3284 + "name": "avatar", 3285 + "type": "text", 3286 + "primaryKey": false, 3287 + "notNull": true 3288 + }, 3289 + "xata_createdat": { 3290 + "name": "xata_createdat", 3291 + "type": "timestamp", 3292 + "primaryKey": false, 3293 + "notNull": true, 3294 + "default": "now()" 3295 + }, 3296 + "xata_updatedat": { 3297 + "name": "xata_updatedat", 3298 + "type": "timestamp", 3299 + "primaryKey": false, 3300 + "notNull": true, 3301 + "default": "now()" 3302 + }, 3303 + "xata_version": { 3304 + "name": "xata_version", 3305 + "type": "integer", 3306 + "primaryKey": false, 3307 + "notNull": false 3308 + } 3309 + }, 3310 + "indexes": {}, 3311 + "foreignKeys": {}, 3312 + "compositePrimaryKeys": {}, 3313 + "uniqueConstraints": { 3314 + "users_did_unique": { 3315 + "name": "users_did_unique", 3316 + "nullsNotDistinct": false, 3317 + "columns": [ 3318 + "did" 3319 + ] 3320 + }, 3321 + "users_handle_unique": { 3322 + "name": "users_handle_unique", 3323 + "nullsNotDistinct": false, 3324 + "columns": [ 3325 + "handle" 3326 + ] 3327 + } 3328 + }, 3329 + "policies": {}, 3330 + "checkConstraints": {}, 3331 + "isRLSEnabled": false 3332 + }, 3333 + "public.webscrobblers": { 3334 + "name": "webscrobblers", 3335 + "schema": "", 3336 + "columns": { 3337 + "xata_id": { 3338 + "name": "xata_id", 3339 + "type": "text", 3340 + "primaryKey": true, 3341 + "notNull": true, 3342 + "default": "xata_id()" 3343 + }, 3344 + "name": { 3345 + "name": "name", 3346 + "type": "text", 3347 + "primaryKey": false, 3348 + "notNull": true 3349 + }, 3350 + "uuid": { 3351 + "name": "uuid", 3352 + "type": "text", 3353 + "primaryKey": false, 3354 + "notNull": true 3355 + }, 3356 + "description": { 3357 + "name": "description", 3358 + "type": "text", 3359 + "primaryKey": false, 3360 + "notNull": false 3361 + }, 3362 + "enabled": { 3363 + "name": "enabled", 3364 + "type": "boolean", 3365 + "primaryKey": false, 3366 + "notNull": true, 3367 + "default": true 3368 + }, 3369 + "user_id": { 3370 + "name": "user_id", 3371 + "type": "text", 3372 + "primaryKey": false, 3373 + "notNull": true 3374 + }, 3375 + "xata_createdat": { 3376 + "name": "xata_createdat", 3377 + "type": "timestamp", 3378 + "primaryKey": false, 3379 + "notNull": true, 3380 + "default": "now()" 3381 + }, 3382 + "xata_updatedat": { 3383 + "name": "xata_updatedat", 3384 + "type": "timestamp", 3385 + "primaryKey": false, 3386 + "notNull": true, 3387 + "default": "now()" 3388 + } 3389 + }, 3390 + "indexes": {}, 3391 + "foreignKeys": { 3392 + "webscrobblers_user_id_users_xata_id_fk": { 3393 + "name": "webscrobblers_user_id_users_xata_id_fk", 3394 + "tableFrom": "webscrobblers", 3395 + "tableTo": "users", 3396 + "columnsFrom": [ 3397 + "user_id" 3398 + ], 3399 + "columnsTo": [ 3400 + "xata_id" 3401 + ], 3402 + "onDelete": "no action", 3403 + "onUpdate": "no action" 3404 + } 3405 + }, 3406 + "compositePrimaryKeys": {}, 3407 + "uniqueConstraints": {}, 3408 + "policies": {}, 3409 + "checkConstraints": {}, 3410 + "isRLSEnabled": false 3411 + } 3412 + }, 3413 + "enums": {}, 3414 + "schemas": {}, 3415 + "sequences": {}, 3416 + "roles": {}, 3417 + "policies": {}, 3418 + "views": {}, 3419 + "_meta": { 3420 + "columns": {}, 3421 + "schemas": {}, 3422 + "tables": {} 3423 + } 3424 + }
+7
apps/api/drizzle/meta/_journal.json
··· 15 15 "when": 1766863536746, 16 16 "tag": "0001_parched_random", 17 17 "breakpoints": true 18 + }, 19 + { 20 + "idx": 2, 21 + "version": "7", 22 + "when": 1767252686993, 23 + "tag": "0002_robust_wong", 24 + "breakpoints": true 18 25 } 19 26 ] 20 27 }
+4
apps/api/lexicons/graph/follow.json
··· 18 18 "format": "datetime" 19 19 }, 20 20 "subject": { 21 + "type": "string", 22 + "format": "did" 23 + }, 24 + "via": { 21 25 "type": "ref", 22 26 "ref": "com.atproto.repo.strongRef" 23 27 }
+49
apps/api/lexicons/graph/followAccount.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "app.rocksky.graph.followAccount", 4 + "defs": { 5 + "main": { 6 + "type": "procedure", 7 + "description": "Creates a 'follow' relationship from the authenticated account to a specified account.", 8 + "parameters": { 9 + "type": "params", 10 + "required": [ 11 + "account" 12 + ], 13 + "properties": { 14 + "account": { 15 + "type": "string", 16 + "format": "at-identifier" 17 + } 18 + } 19 + }, 20 + "output": { 21 + "encoding": "application/json", 22 + "schema": { 23 + "type": "object", 24 + "required": [ 25 + "subject", 26 + "followers" 27 + ], 28 + "properties": { 29 + "subject": { 30 + "type": "ref", 31 + "ref": "app.rocksky.actor.defs#profileViewBasic" 32 + }, 33 + "followers": { 34 + "type": "array", 35 + "items": { 36 + "type": "ref", 37 + "ref": "app.rocksky.actor.defs#profileViewBasic" 38 + } 39 + }, 40 + "cursor": { 41 + "type": "string", 42 + "description": "A cursor value to pass to subsequent calls to get the next page of results." 43 + } 44 + } 45 + } 46 + } 47 + } 48 + } 49 + }
+49
apps/api/lexicons/graph/unfollowAccount.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "app.rocksky.graph.unfollowAccount", 4 + "defs": { 5 + "main": { 6 + "type": "procedure", 7 + "description": "Removes a 'follow' relationship from the authenticated account to a specified account.", 8 + "parameters": { 9 + "type": "params", 10 + "required": [ 11 + "account" 12 + ], 13 + "properties": { 14 + "account": { 15 + "type": "string", 16 + "format": "at-identifier" 17 + } 18 + } 19 + }, 20 + "output": { 21 + "encoding": "application/json", 22 + "schema": { 23 + "type": "object", 24 + "required": [ 25 + "subject", 26 + "followers" 27 + ], 28 + "properties": { 29 + "subject": { 30 + "type": "ref", 31 + "ref": "app.rocksky.actor.defs#profileViewBasic" 32 + }, 33 + "followers": { 34 + "type": "array", 35 + "items": { 36 + "type": "ref", 37 + "ref": "app.rocksky.actor.defs#profileViewBasic" 38 + } 39 + }, 40 + "cursor": { 41 + "type": "string", 42 + "description": "A cursor value to pass to subsequent calls to get the next page of results." 43 + } 44 + } 45 + } 46 + } 47 + } 48 + } 49 + }
+6 -1
apps/api/pkl/defs/graph/follow.pkl
··· 16 16 format = "datetime" 17 17 } 18 18 19 - ["subject"] = new Ref { 19 + ["subject"] = new StringType { 20 + type = "string" 21 + format = "did" 22 + } 23 + 24 + ["via"] = new Ref { 20 25 type = "ref" 21 26 ref = "com.atproto.repo.strongRef" 22 27 }
+46
apps/api/pkl/defs/graph/followAccount.pkl
··· 1 + amends "../../schema/lexicon.pkl" 2 + 3 + lexicon = 1 4 + id = "app.rocksky.graph.followAccount" 5 + defs = new Mapping<String, Procedure> { 6 + ["main"] { 7 + type = "procedure" 8 + description = 9 + "Creates a 'follow' relationship from the authenticated account to a specified account." 10 + parameters = new Params { 11 + required = List("account") 12 + properties { 13 + ["account"] = new StringType { 14 + type = "string" 15 + format = "at-identifier" 16 + } 17 + } 18 + } 19 + 20 + output { 21 + encoding = "application/json" 22 + schema = new ObjectType { 23 + type = "object" 24 + required = List("subject", "followers") 25 + properties { 26 + ["subject"] = new Ref { 27 + type = "ref" 28 + ref = "app.rocksky.actor.defs#profileViewBasic" 29 + } 30 + ["followers"] = new Array { 31 + type = "array" 32 + items = new Ref { 33 + type = "ref" 34 + ref = "app.rocksky.actor.defs#profileViewBasic" 35 + } 36 + } 37 + ["cursor"] = new StringType { 38 + type = "string" 39 + description = 40 + "A cursor value to pass to subsequent calls to get the next page of results." 41 + } 42 + } 43 + } 44 + } 45 + } 46 + }
+46
apps/api/pkl/defs/graph/unfollowAccount.pkl
··· 1 + amends "../../schema/lexicon.pkl" 2 + 3 + lexicon = 1 4 + id = "app.rocksky.graph.unfollowAccount" 5 + defs = new Mapping<String, Procedure> { 6 + ["main"] { 7 + type = "procedure" 8 + description = 9 + "Removes a 'follow' relationship from the authenticated account to a specified account." 10 + parameters = new Params { 11 + required = List("account") 12 + properties { 13 + ["account"] = new StringType { 14 + type = "string" 15 + format = "at-identifier" 16 + } 17 + } 18 + } 19 + 20 + output { 21 + encoding = "application/json" 22 + schema = new ObjectType { 23 + type = "object" 24 + required = List("subject", "followers") 25 + properties { 26 + ["subject"] = new Ref { 27 + type = "ref" 28 + ref = "app.rocksky.actor.defs#profileViewBasic" 29 + } 30 + ["followers"] = new Array { 31 + type = "array" 32 + items = new Ref { 33 + type = "ref" 34 + ref = "app.rocksky.actor.defs#profileViewBasic" 35 + } 36 + } 37 + ["cursor"] = new StringType { 38 + type = "string" 39 + description = 40 + "A cursor value to pass to subsequent calls to get the next page of results." 41 + } 42 + } 43 + } 44 + } 45 + } 46 + }
+24
apps/api/src/lexicon/index.ts
··· 48 48 import type * as AppRockskyGoogledriveDownloadFile from "./types/app/rocksky/googledrive/downloadFile"; 49 49 import type * as AppRockskyGoogledriveGetFile from "./types/app/rocksky/googledrive/getFile"; 50 50 import type * as AppRockskyGoogledriveGetFiles from "./types/app/rocksky/googledrive/getFiles"; 51 + import type * as AppRockskyGraphFollowAccount from "./types/app/rocksky/graph/followAccount"; 51 52 import type * as AppRockskyGraphGetFollowers from "./types/app/rocksky/graph/getFollowers"; 52 53 import type * as AppRockskyGraphGetFollows from "./types/app/rocksky/graph/getFollows"; 53 54 import type * as AppRockskyGraphGetKnownFollowers from "./types/app/rocksky/graph/getKnownFollowers"; 55 + import type * as AppRockskyGraphUnfollowAccount from "./types/app/rocksky/graph/unfollowAccount"; 54 56 import type * as AppRockskyLikeDislikeShout from "./types/app/rocksky/like/dislikeShout"; 55 57 import type * as AppRockskyLikeDislikeSong from "./types/app/rocksky/like/dislikeSong"; 56 58 import type * as AppRockskyLikeLikeShout from "./types/app/rocksky/like/likeShout"; ··· 717 719 this._server = server; 718 720 } 719 721 722 + followAccount<AV extends AuthVerifier>( 723 + cfg: ConfigOf< 724 + AV, 725 + AppRockskyGraphFollowAccount.Handler<ExtractAuth<AV>>, 726 + AppRockskyGraphFollowAccount.HandlerReqCtx<ExtractAuth<AV>> 727 + >, 728 + ) { 729 + const nsid = "app.rocksky.graph.followAccount"; // @ts-ignore 730 + return this._server.xrpc.method(nsid, cfg); 731 + } 732 + 720 733 getFollowers<AV extends AuthVerifier>( 721 734 cfg: ConfigOf< 722 735 AV, ··· 747 760 >, 748 761 ) { 749 762 const nsid = "app.rocksky.graph.getKnownFollowers"; // @ts-ignore 763 + return this._server.xrpc.method(nsid, cfg); 764 + } 765 + 766 + unfollowAccount<AV extends AuthVerifier>( 767 + cfg: ConfigOf< 768 + AV, 769 + AppRockskyGraphUnfollowAccount.Handler<ExtractAuth<AV>>, 770 + AppRockskyGraphUnfollowAccount.HandlerReqCtx<ExtractAuth<AV>> 771 + >, 772 + ) { 773 + const nsid = "app.rocksky.graph.unfollowAccount"; // @ts-ignore 750 774 return this._server.xrpc.method(nsid, cfg); 751 775 } 752 776 }
+98
apps/api/src/lexicon/lexicons.ts
··· 2799 2799 format: "datetime", 2800 2800 }, 2801 2801 subject: { 2802 + type: "string", 2803 + format: "did", 2804 + }, 2805 + via: { 2802 2806 type: "ref", 2803 2807 ref: "lex:com.atproto.repo.strongRef", 2808 + }, 2809 + }, 2810 + }, 2811 + }, 2812 + }, 2813 + }, 2814 + AppRockskyGraphFollowAccount: { 2815 + lexicon: 1, 2816 + id: "app.rocksky.graph.followAccount", 2817 + defs: { 2818 + main: { 2819 + type: "procedure", 2820 + description: 2821 + "Creates a 'follow' relationship from the authenticated account to a specified account.", 2822 + parameters: { 2823 + type: "params", 2824 + required: ["account"], 2825 + properties: { 2826 + account: { 2827 + type: "string", 2828 + format: "at-identifier", 2829 + }, 2830 + }, 2831 + }, 2832 + output: { 2833 + encoding: "application/json", 2834 + schema: { 2835 + type: "object", 2836 + required: ["subject", "followers"], 2837 + properties: { 2838 + subject: { 2839 + type: "ref", 2840 + ref: "lex:app.rocksky.actor.defs#profileViewBasic", 2841 + }, 2842 + followers: { 2843 + type: "array", 2844 + items: { 2845 + type: "ref", 2846 + ref: "lex:app.rocksky.actor.defs#profileViewBasic", 2847 + }, 2848 + }, 2849 + cursor: { 2850 + type: "string", 2851 + description: 2852 + "A cursor value to pass to subsequent calls to get the next page of results.", 2853 + }, 2804 2854 }, 2805 2855 }, 2806 2856 }, ··· 2941 2991 }, 2942 2992 cursor: { 2943 2993 type: "string", 2994 + }, 2995 + }, 2996 + }, 2997 + output: { 2998 + encoding: "application/json", 2999 + schema: { 3000 + type: "object", 3001 + required: ["subject", "followers"], 3002 + properties: { 3003 + subject: { 3004 + type: "ref", 3005 + ref: "lex:app.rocksky.actor.defs#profileViewBasic", 3006 + }, 3007 + followers: { 3008 + type: "array", 3009 + items: { 3010 + type: "ref", 3011 + ref: "lex:app.rocksky.actor.defs#profileViewBasic", 3012 + }, 3013 + }, 3014 + cursor: { 3015 + type: "string", 3016 + description: 3017 + "A cursor value to pass to subsequent calls to get the next page of results.", 3018 + }, 3019 + }, 3020 + }, 3021 + }, 3022 + }, 3023 + }, 3024 + }, 3025 + AppRockskyGraphUnfollowAccount: { 3026 + lexicon: 1, 3027 + id: "app.rocksky.graph.unfollowAccount", 3028 + defs: { 3029 + main: { 3030 + type: "procedure", 3031 + description: 3032 + "Removes a 'follow' relationship from the authenticated account to a specified account.", 3033 + parameters: { 3034 + type: "params", 3035 + required: ["account"], 3036 + properties: { 3037 + account: { 3038 + type: "string", 3039 + format: "at-identifier", 2944 3040 }, 2945 3041 }, 2946 3042 }, ··· 5634 5730 AppRockskyGoogledriveGetFiles: "app.rocksky.googledrive.getFiles", 5635 5731 AppRockskyGraphDefs: "app.rocksky.graph.defs", 5636 5732 AppRockskyGraphFollow: "app.rocksky.graph.follow", 5733 + AppRockskyGraphFollowAccount: "app.rocksky.graph.followAccount", 5637 5734 AppRockskyGraphGetFollowers: "app.rocksky.graph.getFollowers", 5638 5735 AppRockskyGraphGetFollows: "app.rocksky.graph.getFollows", 5639 5736 AppRockskyGraphGetKnownFollowers: "app.rocksky.graph.getKnownFollowers", 5737 + AppRockskyGraphUnfollowAccount: "app.rocksky.graph.unfollowAccount", 5640 5738 AppRockskyLikeDislikeShout: "app.rocksky.like.dislikeShout", 5641 5739 AppRockskyLikeDislikeSong: "app.rocksky.like.dislikeSong", 5642 5740 AppRockskyLike: "app.rocksky.like",
+2 -1
apps/api/src/lexicon/types/app/rocksky/graph/follow.ts
··· 9 9 10 10 export interface Record { 11 11 createdAt: string; 12 - subject: ComAtprotoRepoStrongRef.Main; 12 + subject: string; 13 + via?: ComAtprotoRepoStrongRef.Main; 13 14 [k: string]: unknown; 14 15 } 15 16
+50
apps/api/src/lexicon/types/app/rocksky/graph/followAccount.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import type express from "express"; 5 + import { ValidationResult, BlobRef } from "@atproto/lexicon"; 6 + import { lexicons } from "../../../../lexicons"; 7 + import { isObj, hasProp } from "../../../../util"; 8 + import { CID } from "multiformats/cid"; 9 + import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; 10 + import type * as AppRockskyActorDefs from "../actor/defs"; 11 + 12 + export interface QueryParams { 13 + account: string; 14 + } 15 + 16 + export type InputSchema = undefined; 17 + 18 + export interface OutputSchema { 19 + subject: AppRockskyActorDefs.ProfileViewBasic; 20 + followers: AppRockskyActorDefs.ProfileViewBasic[]; 21 + /** A cursor value to pass to subsequent calls to get the next page of results. */ 22 + cursor?: string; 23 + [k: string]: unknown; 24 + } 25 + 26 + export type HandlerInput = undefined; 27 + 28 + export interface HandlerSuccess { 29 + encoding: "application/json"; 30 + body: OutputSchema; 31 + headers?: { [key: string]: string }; 32 + } 33 + 34 + export interface HandlerError { 35 + status: number; 36 + message?: string; 37 + } 38 + 39 + export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough; 40 + export type HandlerReqCtx<HA extends HandlerAuth = never> = { 41 + auth: HA; 42 + params: QueryParams; 43 + input: HandlerInput; 44 + req: express.Request; 45 + res: express.Response; 46 + resetRouteRateLimits: () => Promise<void>; 47 + }; 48 + export type Handler<HA extends HandlerAuth = never> = ( 49 + ctx: HandlerReqCtx<HA>, 50 + ) => Promise<HandlerOutput> | HandlerOutput;
+50
apps/api/src/lexicon/types/app/rocksky/graph/unfollowAccount.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import type express from "express"; 5 + import { ValidationResult, BlobRef } from "@atproto/lexicon"; 6 + import { lexicons } from "../../../../lexicons"; 7 + import { isObj, hasProp } from "../../../../util"; 8 + import { CID } from "multiformats/cid"; 9 + import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; 10 + import type * as AppRockskyActorDefs from "../actor/defs"; 11 + 12 + export interface QueryParams { 13 + account: string; 14 + } 15 + 16 + export type InputSchema = undefined; 17 + 18 + export interface OutputSchema { 19 + subject: AppRockskyActorDefs.ProfileViewBasic; 20 + followers: AppRockskyActorDefs.ProfileViewBasic[]; 21 + /** A cursor value to pass to subsequent calls to get the next page of results. */ 22 + cursor?: string; 23 + [k: string]: unknown; 24 + } 25 + 26 + export type HandlerInput = undefined; 27 + 28 + export interface HandlerSuccess { 29 + encoding: "application/json"; 30 + body: OutputSchema; 31 + headers?: { [key: string]: string }; 32 + } 33 + 34 + export interface HandlerError { 35 + status: number; 36 + message?: string; 37 + } 38 + 39 + export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough; 40 + export type HandlerReqCtx<HA extends HandlerAuth = never> = { 41 + auth: HA; 42 + params: QueryParams; 43 + input: HandlerInput; 44 + req: express.Request; 45 + res: express.Response; 46 + resetRouteRateLimits: () => Promise<void>; 47 + }; 48 + export type Handler<HA extends HandlerAuth = never> = ( 49 + ctx: HandlerReqCtx<HA>, 50 + ) => Promise<HandlerOutput> | HandlerOutput;
+33
apps/api/src/schema/follows.ts
··· 1 + import type { InferInsertModel, InferSelectModel } from "drizzle-orm"; 2 + import { sql } from "drizzle-orm"; 3 + import { 4 + integer, 5 + pgTable, 6 + text, 7 + timestamp, 8 + uniqueIndex, 9 + } from "drizzle-orm/pg-core"; 10 + 11 + const follows = pgTable( 12 + "follows", 13 + { 14 + id: text("xata_id").primaryKey().default(sql`xata_id()`), 15 + uri: text("uri").notNull().unique(), 16 + follower_did: text("follower_did").notNull(), 17 + subject_did: text("subject_did").notNull(), 18 + xataVersion: integer("xata_version"), 19 + createdAt: timestamp("xata_createdat").defaultNow().notNull(), 20 + updatedAt: timestamp("xata_updatedat").defaultNow().notNull(), 21 + }, 22 + (t) => [ 23 + uniqueIndex("follows_follower_subject_unique").on( 24 + t.follower_did, 25 + t.subject_did, 26 + ), 27 + ], 28 + ); 29 + 30 + export type SelectFollows = InferSelectModel<typeof follows>; 31 + export type InsertFollows = InferInsertModel<typeof follows>; 32 + 33 + export default follows;
+2
apps/api/src/schema/index.ts
··· 10 10 import dropboxPaths from "./dropbox-paths"; 11 11 import dropboxTokens from "./dropbox-tokens"; 12 12 import feeds from "./feeds"; 13 + import follows from "./follows"; 13 14 import googleDriveAccounts from "./google-drive-accounts"; 14 15 import googleDriveDirectories from "./google-drive-directories"; 15 16 import googleDrivePaths from "./google-drive-paths"; ··· 70 71 googleDrive, 71 72 queueTracks, 72 73 feeds, 74 + follows, 73 75 };
+1 -4
apps/api/src/scripts/avatar.ts
··· 55 55 }; 56 56 57 57 console.log(userPayload); 58 - await ctx.nc.publish( 59 - "rocksky.user", 60 - Buffer.from(JSON.stringify(userPayload)), 61 - ); 58 + ctx.nc.publish("rocksky.user", Buffer.from(JSON.stringify(userPayload))); 62 59 } 63 60 64 61 if (args.length > 0) {
+69
apps/api/src/xrpc/app/rocksky/graph/followAccount.ts
··· 1 + import type { HandlerAuth } from "@atproto/xrpc-server"; 2 + import type { Context } from "context"; 3 + import { eq } from "drizzle-orm"; 4 + import { Effect, pipe } from "effect"; 5 + import type { Server } from "lexicon"; 6 + import { ProfileViewBasic } from "lexicon/types/app/rocksky/actor/defs"; 7 + import type { QueryParams } from "lexicon/types/app/rocksky/graph/followAccount"; 8 + import tables from "schema"; 9 + 10 + export default function (server: Server, ctx: Context) { 11 + const followAccount = (params: QueryParams, auth: HandlerAuth) => 12 + pipe( 13 + { params, ctx, did: auth.credentials?.did }, 14 + handleFollow, 15 + Effect.flatMap(presentation), 16 + Effect.retry({ times: 3 }), 17 + Effect.timeout("10 seconds"), 18 + Effect.catchAll((err) => { 19 + console.error(err); 20 + return Effect.succeed({ 21 + subject: {} satisfies ProfileViewBasic, 22 + followers: [], 23 + }); 24 + }), 25 + ); 26 + server.app.rocksky.graph.followAccount({ 27 + auth: ctx.authVerifier, 28 + handler: async ({ params, auth }) => { 29 + const result = await Effect.runPromise(followAccount(params, auth)); 30 + return { 31 + encoding: "application/json", 32 + body: result, 33 + }; 34 + }, 35 + }); 36 + } 37 + 38 + const handleFollow = ({ 39 + params, 40 + ctx, 41 + did, 42 + }: { 43 + params: QueryParams; 44 + ctx: Context; 45 + did?: string; 46 + }): Effect.Effect<any[], Error> => { 47 + return Effect.tryPromise({ 48 + try: async () => { 49 + if (!did) { 50 + throw new Error("User is not authenticated"); 51 + } 52 + return []; 53 + }, 54 + catch: (error) => new Error(`Failed to retrieve follow: ${error}`), 55 + }); 56 + }; 57 + 58 + const presentation = ( 59 + followers: any[], 60 + ): Effect.Effect< 61 + { subject: ProfileViewBasic; followers: ProfileViewBasic[] }, 62 + never 63 + > => { 64 + // Logic to format the response for play action 65 + return Effect.sync(() => ({ 66 + subject: {} satisfies ProfileViewBasic, 67 + followers: [], 68 + })); 69 + };
+79
apps/api/src/xrpc/app/rocksky/graph/getFollowers.ts
··· 1 + import type { Context } from "context"; 2 + import { eq, or, sql } from "drizzle-orm"; 3 + import { Effect, pipe } from "effect"; 4 + import type { Server } from "lexicon"; 5 + import type { QueryParams } from "lexicon/types/app/rocksky/graph/getFollowers"; 6 + import type { ProfileViewBasic } from "lexicon/types/app/rocksky/actor/defs"; 7 + import tables from "schema"; 8 + 9 + export default function (server: Server, ctx: Context) { 10 + const getFollowers = (params: QueryParams) => 11 + pipe( 12 + { params, ctx }, 13 + retrieve, 14 + Effect.flatMap(presentation), 15 + Effect.retry({ times: 3 }), 16 + Effect.timeout("120 seconds"), 17 + Effect.catchAll((err) => { 18 + console.error(err); 19 + return Effect.succeed({ 20 + subject: {} satisfies ProfileViewBasic, 21 + followers: [] as ProfileViewBasic[], 22 + }); 23 + }), 24 + ); 25 + server.app.rocksky.graph.getFollowers({ 26 + handler: async ({ params }) => { 27 + const result = await Effect.runPromise(getFollowers(params)); 28 + return { 29 + encoding: "application/json", 30 + body: result, 31 + }; 32 + }, 33 + }); 34 + } 35 + 36 + const retrieve = ({ 37 + params, 38 + ctx, 39 + }: { 40 + params: QueryParams; 41 + ctx: Context; 42 + }): Effect.Effect<any[], Error> => { 43 + return Effect.tryPromise({ 44 + try: () => 45 + ctx.db 46 + .select() 47 + .from(tables.follows) 48 + .where(eq(tables.follows.subject_did, params.actor)) 49 + .leftJoin( 50 + tables.users, 51 + eq(tables.users.did, tables.follows.follower_did), 52 + ) 53 + .execute() 54 + .then((rows) => 55 + rows.map(({ users }) => ({ 56 + id: users.id, 57 + did: users.did, 58 + handle: users.handle, 59 + displayName: users.displayName, 60 + avatar: users.avatar, 61 + createdAt: users.createdAt.toISOString(), 62 + updatedAt: users.updatedAt.toISOString(), 63 + })), 64 + ), 65 + catch: (error) => new Error(`Failed to retrieve user followers: ${error}`), 66 + }); 67 + }; 68 + 69 + const presentation = ( 70 + followers: any[], 71 + ): Effect.Effect< 72 + { subject: ProfileViewBasic; followers: ProfileViewBasic[] }, 73 + never 74 + > => { 75 + return Effect.sync(() => ({ 76 + subject: {} satisfies ProfileViewBasic, 77 + followers: [], 78 + })); 79 + };
+79
apps/api/src/xrpc/app/rocksky/graph/getFollows.ts
··· 1 + import type { Context } from "context"; 2 + import { eq, or, sql } from "drizzle-orm"; 3 + import { Effect, pipe } from "effect"; 4 + import type { Server } from "lexicon"; 5 + import type { QueryParams } from "lexicon/types/app/rocksky/graph/getFollowers"; 6 + import type { ProfileViewBasic } from "lexicon/types/app/rocksky/actor/defs"; 7 + import tables from "schema"; 8 + 9 + export default function (server: Server, ctx: Context) { 10 + const getFollows = (params) => 11 + pipe( 12 + { params, ctx }, 13 + retrieve, 14 + Effect.flatMap(presentation), 15 + Effect.retry({ times: 3 }), 16 + Effect.timeout("120 seconds"), 17 + Effect.catchAll((err) => { 18 + console.error(err); 19 + return Effect.succeed({ 20 + subject: {} satisfies ProfileViewBasic, 21 + follows: [], 22 + }); 23 + }), 24 + ); 25 + server.app.rocksky.graph.getFollows({ 26 + handler: async ({ params }) => { 27 + const result = await Effect.runPromise(getFollows(params)); 28 + return { 29 + encoding: "application/json", 30 + body: result, 31 + }; 32 + }, 33 + }); 34 + } 35 + 36 + const retrieve = ({ 37 + params, 38 + ctx, 39 + }: { 40 + params: QueryParams; 41 + ctx: Context; 42 + }): Effect.Effect<any[], Error> => { 43 + return Effect.tryPromise({ 44 + try: () => 45 + ctx.db 46 + .select() 47 + .from(tables.follows) 48 + .where(eq(tables.follows.follower_did, params.actor)) 49 + .leftJoin( 50 + tables.users, 51 + eq(tables.users.did, tables.follows.follower_did), 52 + ) 53 + .execute() 54 + .then((rows) => 55 + rows.map(({ users }) => ({ 56 + id: users.id, 57 + did: users.did, 58 + handle: users.handle, 59 + displayName: users.displayName, 60 + avatar: users.avatar, 61 + createdAt: users.createdAt.toISOString(), 62 + updatedAt: users.updatedAt.toISOString(), 63 + })), 64 + ), 65 + catch: (error) => new Error(`Failed to retrieve user follows: ${error}`), 66 + }); 67 + }; 68 + 69 + const presentation = ( 70 + followers: any[], 71 + ): Effect.Effect< 72 + { subject: ProfileViewBasic; follows: ProfileViewBasic[] }, 73 + never 74 + > => { 75 + return Effect.sync(() => ({ 76 + subject: {} satisfies ProfileViewBasic, 77 + follows: [], 78 + })); 79 + };
+63
apps/api/src/xrpc/app/rocksky/graph/getKnownFollowers.ts
··· 1 + import type { Context } from "context"; 2 + import { eq, or, sql } from "drizzle-orm"; 3 + import { Effect, pipe } from "effect"; 4 + import type { Server } from "lexicon"; 5 + import type { QueryParams } from "lexicon/types/app/rocksky/graph/getKnownFollowers"; 6 + import type { ProfileViewBasic } from "lexicon/types/app/rocksky/actor/defs"; 7 + import tables from "schema"; 8 + 9 + export default function (server: Server, ctx: Context) { 10 + const getKnownFollowers = (params) => 11 + pipe( 12 + { params, ctx }, 13 + retrieve, 14 + Effect.flatMap(presentation), 15 + Effect.retry({ times: 3 }), 16 + Effect.timeout("120 seconds"), 17 + Effect.catchAll((err) => { 18 + console.error(err); 19 + return Effect.succeed({ 20 + subject: {} satisfies ProfileViewBasic, 21 + followers: [] as ProfileViewBasic[], 22 + }); 23 + }), 24 + ); 25 + server.app.rocksky.graph.getKnownFollowers({ 26 + handler: async ({ params }) => { 27 + const result = await Effect.runPromise(getKnownFollowers(params)); 28 + return { 29 + encoding: "application/json", 30 + body: { 31 + ...result, 32 + subject: {} satisfies ProfileViewBasic, 33 + }, 34 + }; 35 + }, 36 + }); 37 + } 38 + 39 + const retrieve = ({ 40 + params, 41 + ctx, 42 + }: { 43 + params: QueryParams; 44 + ctx: Context; 45 + }): Effect.Effect<any[], Error> => { 46 + return Effect.tryPromise({ 47 + try: async () => [], 48 + catch: (error) => 49 + new Error(`Failed to retrieve user known followers: ${error}`), 50 + }); 51 + }; 52 + 53 + const presentation = ( 54 + followers: any[], 55 + ): Effect.Effect< 56 + { subject: ProfileViewBasic; followers: ProfileViewBasic[] }, 57 + never 58 + > => { 59 + return Effect.sync(() => ({ 60 + subject: {} satisfies ProfileViewBasic, 61 + followers: [], 62 + })); 63 + };
+64
apps/api/src/xrpc/app/rocksky/graph/unfollowAccount.ts
··· 1 + import type { HandlerAuth } from "@atproto/xrpc-server"; 2 + import type { Context } from "context"; 3 + import { eq } from "drizzle-orm"; 4 + import { Effect, pipe } from "effect"; 5 + import type { Server } from "lexicon"; 6 + import { ProfileViewBasic } from "lexicon/types/app/rocksky/actor/defs"; 7 + import type { QueryParams } from "lexicon/types/app/rocksky/graph/unfollowAccount"; 8 + import tables from "schema"; 9 + 10 + export default function (server: Server, ctx: Context) { 11 + const unfollowAccount = (params: QueryParams, auth: HandlerAuth) => 12 + pipe( 13 + { params, ctx, did: auth.credentials?.did }, 14 + handleFollow, 15 + Effect.flatMap(presentation), 16 + Effect.retry({ times: 3 }), 17 + Effect.timeout("10 seconds"), 18 + Effect.catchAll((err) => { 19 + console.error(err); 20 + return Effect.succeed({ 21 + subject: {} satisfies ProfileViewBasic, 22 + followers: [], 23 + }); 24 + }), 25 + ); 26 + server.app.rocksky.graph.followAccount({ 27 + auth: ctx.authVerifier, 28 + handler: async ({ params, auth }) => { 29 + const result = await Effect.runPromise(unfollowAccount(params, auth)); 30 + return { 31 + encoding: "application/json", 32 + body: result, 33 + }; 34 + }, 35 + }); 36 + } 37 + 38 + const handleFollow = ({ 39 + params, 40 + ctx, 41 + did, 42 + }: { 43 + params: QueryParams; 44 + ctx: Context; 45 + did?: string; 46 + }): Effect.Effect<any[], Error> => { 47 + return Effect.tryPromise({ 48 + try: async () => [], 49 + catch: (error) => new Error(`Failed to unfollow: ${error}`), 50 + }); 51 + }; 52 + 53 + const presentation = ( 54 + followers: any[], 55 + ): Effect.Effect< 56 + { subject: ProfileViewBasic; followers: ProfileViewBasic[] }, 57 + never 58 + > => { 59 + // Logic to format the response for play action 60 + return Effect.sync(() => ({ 61 + subject: {} satisfies ProfileViewBasic, 62 + followers: [], 63 + })); 64 + };
+1 -1
apps/web/src/components/SongCover/InteractionBar/InteractionBar.tsx
··· 23 23 {liked && <HeartFilled color="#fff" />} 24 24 </span> 25 25 {likesCount > 0 && ( 26 - <span className="ml-[5px] mt-[-4px] text-sm text-white"> 26 + <span className="ml-[5px] mt-[-4px] text-sm !text-[#ffffff]"> 27 27 {likesCount} 28 28 </span> 29 29 )}
+49 -3
crates/jetstream/src/repo.rs
··· 8 8 9 9 use crate::{ 10 10 profile::did_to_profile, 11 - subscriber::{ALBUM_NSID, ARTIST_NSID, FEED_GENERATOR_NSID, SCROBBLE_NSID, SONG_NSID}, 12 - types::{AlbumRecord, ArtistRecord, Commit, FeedGeneratorRecord, ScrobbleRecord, SongRecord}, 11 + subscriber::{ 12 + ALBUM_NSID, ARTIST_NSID, FEED_GENERATOR_NSID, FOLLOW_NSID, SCROBBLE_NSID, SONG_NSID, 13 + }, 14 + types::{ 15 + AlbumRecord, ArtistRecord, Commit, FeedGeneratorRecord, FollowRecord, ScrobbleRecord, 16 + SongRecord, 17 + }, 13 18 webhook::discord::{ 14 19 self, 15 20 model::{ScrobbleData, WebhookEnvelope}, ··· 35 40 ALBUM_NSID, 36 41 SONG_NSID, 37 42 FEED_GENERATOR_NSID, 43 + FOLLOW_NSID, 38 44 ] 39 45 .contains(&commit.collection.as_str()) 40 46 { ··· 186 192 let uri = format!("at://{}/app.rocksky.feed.generator/{}", did, commit.rkey); 187 193 188 194 let feed_generator_record: FeedGeneratorRecord = 189 - serde_json::from_value(commit.record)?; 195 + serde_json::from_value(commit.record.clone())?; 190 196 save_feed_generator(&mut tx, &user_id, feed_generator_record, &uri).await?; 197 + 198 + tx.commit().await?; 199 + } 200 + 201 + if commit.collection == FOLLOW_NSID { 202 + let mut tx = pool.begin().await?; 203 + 204 + save_user(&mut tx, did).await?; 205 + let uri = format!("at://{}/app.rocksky.graph.follow/{}", did, commit.rkey); 206 + 207 + let follow_record: FollowRecord = serde_json::from_value(commit.record)?; 208 + save_user(&mut tx, &follow_record.subject).await?; 209 + save_follow(&mut tx, did, follow_record, &uri).await?; 191 210 192 211 tx.commit().await?; 193 212 } ··· 1076 1095 .await?; 1077 1096 Ok(()) 1078 1097 } 1098 + 1099 + pub async fn save_follow( 1100 + tx: &mut sqlx::Transaction<'_, Postgres>, 1101 + did: &str, 1102 + record: FollowRecord, 1103 + uri: &str, 1104 + ) -> Result<(), Error> { 1105 + tracing::info!(did = %did, uri = %uri, "Saving follow"); 1106 + 1107 + sqlx::query( 1108 + r#" 1109 + INSERT INTO follows ( 1110 + follower_did, 1111 + subject_did, 1112 + uri 1113 + ) VALUES ( 1114 + $1, $2, $3 1115 + ) 1116 + "#, 1117 + ) 1118 + .bind(did) 1119 + .bind(record.subject) 1120 + .bind(uri) 1121 + .execute(&mut **tx) 1122 + .await?; 1123 + Ok(()) 1124 + }
+1
crates/jetstream/src/subscriber.rs
··· 17 17 pub const LIKE_NSID: &str = "app.rocksky.like"; 18 18 pub const SHOUT_NSID: &str = "app.rocksky.shout"; 19 19 pub const FEED_GENERATOR_NSID: &str = "app.rocksky.feed.generator"; 20 + pub const FOLLOW_NSID: &str = "app.rocksky.graph.follow"; 20 21 21 22 pub struct ScrobbleSubscriber { 22 23 pub service_url: String,
+7
crates/jetstream/src/types.rs
··· 244 244 pub did: String, 245 245 pub created_at: String, 246 246 } 247 + 248 + #[derive(Debug, Deserialize, Clone)] 249 + #[serde(rename_all = "camelCase")] 250 + pub struct FollowRecord { 251 + pub subject: String, 252 + pub created_at: String, 253 + }
+12
crates/jetstream/src/xata/follow.rs
··· 1 + use chrono::{DateTime, Utc}; 2 + use serde::Deserialize; 3 + 4 + #[derive(Debug, sqlx::FromRow, Deserialize, Clone)] 5 + pub struct Follow { 6 + pub xata_id: String, 7 + pub uri: String, 8 + pub follower_did: String, 9 + pub subject_did: String, 10 + #[serde(with = "chrono::serde::ts_seconds")] 11 + pub xata_createdat: DateTime<Utc>, 12 + }
+1
crates/jetstream/src/xata/mod.rs
··· 4 4 pub mod artist_album; 5 5 pub mod artist_track; 6 6 pub mod feed; 7 + pub mod follow; 7 8 pub mod loved_track; 8 9 pub mod scrobble; 9 10 pub mod track;