Shows how to get repo export and walk it in TypeScript walktherepo.wisp.place

Compare changes

Choose any two refs to compare.

.tangled/images/apiWalk.jpg

This is a binary file and will not be displayed.

.tangled/images/carWalk.jpg

This is a binary file and will not be displayed.

+13 -2
README.md
··· 1 - # WIP 1 + # Walk The Repo 2 + 3 + demo: [https://walktherepo.wisp.place](https://walktherepo.wisp.place/) 4 + 5 + A demo showing how to use [@atcute](https://github.com/mary-ext/atcute) to download a user's repo and "walk" it to access all the records inside of it faster than you would via multiple api calls. 6 + If you're just wanting to see that code directly it's [here](https://tangled.org/baileytownsend.dev/repo-walk-example/blob/main/src/lib/RepoStats.svelte#L56). 7 + 8 + Comparisons using my repo as an example. 9 + 10 + Repo Export 11 + ![](./.tangled/images/carWalk.jpg) 2 12 3 - Will show how to get a users repo and walk it so you don't do 10 billion list records calls 13 + API Calls 14 + ![](./.tangled/images/apiWalk.jpg)
+6 -4
index.html
··· 1 1 <!doctype html> 2 2 <html lang="en"> 3 - <head> 3 + <head data-theme="forest"> 4 4 <meta charset="UTF-8" /> 5 - <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 5 + <link rel="icon" type="image/svg+xml" href="/dude.png" /> 6 6 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 7 <title>Repo Walking</title> 8 - <meta name="description" content="Walk the repo, count the steps."> 9 - <meta name="og:description" content="Walk the repo, count the steps."> 8 + <meta name="og:title" content="Repo Walking"> 9 + <meta name="description" content="Walk the repo, count the records."> 10 + <meta name="og:description" content="Walk the repo, count the records."> 11 + 10 12 </head> 11 13 <body> 12 14 <div id="app"></div>
+3
package.json
··· 14 14 "@sveltejs/vite-plugin-svelte": "^6.2.1", 15 15 "@tsconfig/svelte": "^5.0.6", 16 16 "@types/node": "^24.10.1", 17 + "daisyui": "^5.5.14", 17 18 "svelte": "^5.43.8", 18 19 "svelte-check": "^4.3.4", 19 20 "typescript": "~5.9.3", ··· 28 29 "@atcute/repo": "^0.1.1", 29 30 "@eslint/compat": "^2.0.0", 30 31 "@eslint/js": "^9.39.2", 32 + "@tailwindcss/vite": "^4.1.18", 31 33 "eslint": "^9.39.2", 32 34 "eslint-plugin-svelte": "^3.14.0", 33 35 "globals": "^17.0.0", 36 + "tailwindcss": "^4.1.18", 34 37 "typescript-eslint": "^8.52.0" 35 38 } 36 39 }
+375 -49
pnpm-lock.yaml
··· 11 11 '@atcute/atproto': 12 12 specifier: ^3.1.10 13 13 version: 3.1.10 14 - '@atcute/car': 15 - specifier: ^5.0.0 16 - version: 5.0.0 17 - '@atcute/cbor': 18 - specifier: ^2.2.8 19 - version: 2.2.8 20 14 '@atcute/client': 21 15 specifier: ^4.2.1 22 16 version: 4.2.1 ··· 34 28 version: 0.1.1 35 29 '@eslint/compat': 36 30 specifier: ^2.0.0 37 - version: 2.0.0(eslint@9.39.2) 31 + version: 2.0.0(eslint@9.39.2(jiti@2.6.1)) 38 32 '@eslint/js': 39 33 specifier: ^9.39.2 40 34 version: 9.39.2 35 + '@tailwindcss/vite': 36 + specifier: ^4.1.18 37 + version: 4.1.18(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)) 41 38 eslint: 42 39 specifier: ^9.39.2 43 - version: 9.39.2 40 + version: 9.39.2(jiti@2.6.1) 44 41 eslint-plugin-svelte: 45 42 specifier: ^3.14.0 46 - version: 3.14.0(eslint@9.39.2)(svelte@5.46.1) 43 + version: 3.14.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.46.1) 47 44 globals: 48 45 specifier: ^17.0.0 49 46 version: 17.0.0 47 + tailwindcss: 48 + specifier: ^4.1.18 49 + version: 4.1.18 50 50 typescript-eslint: 51 51 specifier: ^8.52.0 52 - version: 8.52.0(eslint@9.39.2)(typescript@5.9.3) 52 + version: 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 53 53 devDependencies: 54 54 '@sveltejs/vite-plugin-svelte': 55 55 specifier: ^6.2.1 56 - version: 6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)) 56 + version: 6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)) 57 57 '@tsconfig/svelte': 58 58 specifier: ^5.0.6 59 59 version: 5.0.6 60 60 '@types/node': 61 61 specifier: ^24.10.1 62 62 version: 24.10.4 63 + daisyui: 64 + specifier: ^5.5.14 65 + version: 5.5.14 63 66 svelte: 64 67 specifier: ^5.43.8 65 68 version: 5.46.1 ··· 71 74 version: 5.9.3 72 75 vite: 73 76 specifier: ^7.2.4 74 - version: 7.3.1(@types/node@24.10.4) 77 + version: 7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2) 75 78 76 79 packages: 77 80 ··· 519 522 svelte: ^5.0.0 520 523 vite: ^6.3.0 || ^7.0.0 521 524 525 + '@tailwindcss/node@4.1.18': 526 + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} 527 + 528 + '@tailwindcss/oxide-android-arm64@4.1.18': 529 + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} 530 + engines: {node: '>= 10'} 531 + cpu: [arm64] 532 + os: [android] 533 + 534 + '@tailwindcss/oxide-darwin-arm64@4.1.18': 535 + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} 536 + engines: {node: '>= 10'} 537 + cpu: [arm64] 538 + os: [darwin] 539 + 540 + '@tailwindcss/oxide-darwin-x64@4.1.18': 541 + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} 542 + engines: {node: '>= 10'} 543 + cpu: [x64] 544 + os: [darwin] 545 + 546 + '@tailwindcss/oxide-freebsd-x64@4.1.18': 547 + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} 548 + engines: {node: '>= 10'} 549 + cpu: [x64] 550 + os: [freebsd] 551 + 552 + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': 553 + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} 554 + engines: {node: '>= 10'} 555 + cpu: [arm] 556 + os: [linux] 557 + 558 + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': 559 + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} 560 + engines: {node: '>= 10'} 561 + cpu: [arm64] 562 + os: [linux] 563 + 564 + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': 565 + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} 566 + engines: {node: '>= 10'} 567 + cpu: [arm64] 568 + os: [linux] 569 + 570 + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': 571 + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} 572 + engines: {node: '>= 10'} 573 + cpu: [x64] 574 + os: [linux] 575 + 576 + '@tailwindcss/oxide-linux-x64-musl@4.1.18': 577 + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} 578 + engines: {node: '>= 10'} 579 + cpu: [x64] 580 + os: [linux] 581 + 582 + '@tailwindcss/oxide-wasm32-wasi@4.1.18': 583 + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} 584 + engines: {node: '>=14.0.0'} 585 + cpu: [wasm32] 586 + bundledDependencies: 587 + - '@napi-rs/wasm-runtime' 588 + - '@emnapi/core' 589 + - '@emnapi/runtime' 590 + - '@tybys/wasm-util' 591 + - '@emnapi/wasi-threads' 592 + - tslib 593 + 594 + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': 595 + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} 596 + engines: {node: '>= 10'} 597 + cpu: [arm64] 598 + os: [win32] 599 + 600 + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': 601 + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} 602 + engines: {node: '>= 10'} 603 + cpu: [x64] 604 + os: [win32] 605 + 606 + '@tailwindcss/oxide@4.1.18': 607 + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} 608 + engines: {node: '>= 10'} 609 + 610 + '@tailwindcss/vite@4.1.18': 611 + resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} 612 + peerDependencies: 613 + vite: ^5.2.0 || ^6 || ^7 614 + 522 615 '@tsconfig/svelte@5.0.6': 523 616 resolution: {integrity: sha512-yGxYL0I9eETH1/DR9qVJey4DAsCdeau4a9wYPKuXfEhm8lFO8wg+LLYJjIpAm6Fw7HSlhepPhYPDop75485yWQ==} 524 617 ··· 661 754 resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 662 755 engines: {node: '>=4'} 663 756 hasBin: true 757 + 758 + daisyui@5.5.14: 759 + resolution: {integrity: sha512-L47rvw7I7hK68TA97VB8Ee0woHew+/ohR6Lx6Ah/krfISOqcG4My7poNpX5Mo5/ytMxiR40fEaz6njzDi7cuSg==} 664 760 665 761 debug@4.4.3: 666 762 resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} ··· 678 774 resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 679 775 engines: {node: '>=0.10.0'} 680 776 777 + detect-libc@2.1.2: 778 + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} 779 + engines: {node: '>=8'} 780 + 681 781 devalue@5.6.1: 682 782 resolution: {integrity: sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A==} 783 + 784 + enhanced-resolve@5.18.4: 785 + resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} 786 + engines: {node: '>=10.13.0'} 683 787 684 788 esbuild@0.27.2: 685 789 resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} ··· 802 906 resolution: {integrity: sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==} 803 907 engines: {node: '>=18'} 804 908 909 + graceful-fs@4.2.11: 910 + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 911 + 805 912 has-flag@4.0.0: 806 913 resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 807 914 engines: {node: '>=8'} ··· 836 943 isexe@2.0.0: 837 944 resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 838 945 946 + jiti@2.6.1: 947 + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} 948 + hasBin: true 949 + 839 950 js-yaml@4.1.1: 840 951 resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} 841 952 hasBin: true ··· 859 970 resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 860 971 engines: {node: '>= 0.8.0'} 861 972 973 + lightningcss-android-arm64@1.30.2: 974 + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} 975 + engines: {node: '>= 12.0.0'} 976 + cpu: [arm64] 977 + os: [android] 978 + 979 + lightningcss-darwin-arm64@1.30.2: 980 + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} 981 + engines: {node: '>= 12.0.0'} 982 + cpu: [arm64] 983 + os: [darwin] 984 + 985 + lightningcss-darwin-x64@1.30.2: 986 + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} 987 + engines: {node: '>= 12.0.0'} 988 + cpu: [x64] 989 + os: [darwin] 990 + 991 + lightningcss-freebsd-x64@1.30.2: 992 + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} 993 + engines: {node: '>= 12.0.0'} 994 + cpu: [x64] 995 + os: [freebsd] 996 + 997 + lightningcss-linux-arm-gnueabihf@1.30.2: 998 + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} 999 + engines: {node: '>= 12.0.0'} 1000 + cpu: [arm] 1001 + os: [linux] 1002 + 1003 + lightningcss-linux-arm64-gnu@1.30.2: 1004 + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} 1005 + engines: {node: '>= 12.0.0'} 1006 + cpu: [arm64] 1007 + os: [linux] 1008 + 1009 + lightningcss-linux-arm64-musl@1.30.2: 1010 + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} 1011 + engines: {node: '>= 12.0.0'} 1012 + cpu: [arm64] 1013 + os: [linux] 1014 + 1015 + lightningcss-linux-x64-gnu@1.30.2: 1016 + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} 1017 + engines: {node: '>= 12.0.0'} 1018 + cpu: [x64] 1019 + os: [linux] 1020 + 1021 + lightningcss-linux-x64-musl@1.30.2: 1022 + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} 1023 + engines: {node: '>= 12.0.0'} 1024 + cpu: [x64] 1025 + os: [linux] 1026 + 1027 + lightningcss-win32-arm64-msvc@1.30.2: 1028 + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} 1029 + engines: {node: '>= 12.0.0'} 1030 + cpu: [arm64] 1031 + os: [win32] 1032 + 1033 + lightningcss-win32-x64-msvc@1.30.2: 1034 + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} 1035 + engines: {node: '>= 12.0.0'} 1036 + cpu: [x64] 1037 + os: [win32] 1038 + 1039 + lightningcss@1.30.2: 1040 + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} 1041 + engines: {node: '>= 12.0.0'} 1042 + 862 1043 lilconfig@2.1.0: 863 1044 resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} 864 1045 engines: {node: '>=10'} ··· 1034 1215 svelte@5.46.1: 1035 1216 resolution: {integrity: sha512-ynjfCHD3nP2el70kN5Pmg37sSi0EjOm9FgHYQdC4giWG/hzO3AatzXXJJgP305uIhGQxSufJLuYWtkY8uK/8RA==} 1036 1217 engines: {node: '>=18'} 1218 + 1219 + tailwindcss@4.1.18: 1220 + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} 1221 + 1222 + tapable@2.3.0: 1223 + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} 1224 + engines: {node: '>=6'} 1037 1225 1038 1226 tinyglobby@0.2.15: 1039 1227 resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} ··· 1307 1495 '@esbuild/win32-x64@0.27.2': 1308 1496 optional: true 1309 1497 1310 - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2)': 1498 + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': 1311 1499 dependencies: 1312 - eslint: 9.39.2 1500 + eslint: 9.39.2(jiti@2.6.1) 1313 1501 eslint-visitor-keys: 3.4.3 1314 1502 1315 1503 '@eslint-community/regexpp@4.12.2': {} 1316 1504 1317 - '@eslint/compat@2.0.0(eslint@9.39.2)': 1505 + '@eslint/compat@2.0.0(eslint@9.39.2(jiti@2.6.1))': 1318 1506 dependencies: 1319 1507 '@eslint/core': 1.0.0 1320 1508 optionalDependencies: 1321 - eslint: 9.39.2 1509 + eslint: 9.39.2(jiti@2.6.1) 1322 1510 1323 1511 '@eslint/config-array@0.21.1': 1324 1512 dependencies: ··· 1476 1664 dependencies: 1477 1665 acorn: 8.15.0 1478 1666 1479 - '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)))(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4))': 1667 + '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2))': 1480 1668 dependencies: 1481 - '@sveltejs/vite-plugin-svelte': 6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)) 1669 + '@sveltejs/vite-plugin-svelte': 6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)) 1482 1670 obug: 2.1.1 1483 1671 svelte: 5.46.1 1484 - vite: 7.3.1(@types/node@24.10.4) 1672 + vite: 7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2) 1485 1673 1486 - '@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4))': 1674 + '@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2))': 1487 1675 dependencies: 1488 - '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)))(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)) 1676 + '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)) 1489 1677 deepmerge: 4.3.1 1490 1678 magic-string: 0.30.21 1491 1679 obug: 2.1.1 1492 1680 svelte: 5.46.1 1493 - vite: 7.3.1(@types/node@24.10.4) 1494 - vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.4)) 1681 + vite: 7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2) 1682 + vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)) 1683 + 1684 + '@tailwindcss/node@4.1.18': 1685 + dependencies: 1686 + '@jridgewell/remapping': 2.3.5 1687 + enhanced-resolve: 5.18.4 1688 + jiti: 2.6.1 1689 + lightningcss: 1.30.2 1690 + magic-string: 0.30.21 1691 + source-map-js: 1.2.1 1692 + tailwindcss: 4.1.18 1693 + 1694 + '@tailwindcss/oxide-android-arm64@4.1.18': 1695 + optional: true 1696 + 1697 + '@tailwindcss/oxide-darwin-arm64@4.1.18': 1698 + optional: true 1699 + 1700 + '@tailwindcss/oxide-darwin-x64@4.1.18': 1701 + optional: true 1702 + 1703 + '@tailwindcss/oxide-freebsd-x64@4.1.18': 1704 + optional: true 1705 + 1706 + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': 1707 + optional: true 1708 + 1709 + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': 1710 + optional: true 1711 + 1712 + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': 1713 + optional: true 1714 + 1715 + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': 1716 + optional: true 1717 + 1718 + '@tailwindcss/oxide-linux-x64-musl@4.1.18': 1719 + optional: true 1720 + 1721 + '@tailwindcss/oxide-wasm32-wasi@4.1.18': 1722 + optional: true 1723 + 1724 + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': 1725 + optional: true 1726 + 1727 + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': 1728 + optional: true 1729 + 1730 + '@tailwindcss/oxide@4.1.18': 1731 + optionalDependencies: 1732 + '@tailwindcss/oxide-android-arm64': 4.1.18 1733 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 1734 + '@tailwindcss/oxide-darwin-x64': 4.1.18 1735 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 1736 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 1737 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 1738 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 1739 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 1740 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 1741 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 1742 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 1743 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 1744 + 1745 + '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2))': 1746 + dependencies: 1747 + '@tailwindcss/node': 4.1.18 1748 + '@tailwindcss/oxide': 4.1.18 1749 + tailwindcss: 4.1.18 1750 + vite: 7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2) 1495 1751 1496 1752 '@tsconfig/svelte@5.0.6': {} 1497 1753 ··· 1503 1759 dependencies: 1504 1760 undici-types: 7.16.0 1505 1761 1506 - '@typescript-eslint/eslint-plugin@8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': 1762 + '@typescript-eslint/eslint-plugin@8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 1507 1763 dependencies: 1508 1764 '@eslint-community/regexpp': 4.12.2 1509 - '@typescript-eslint/parser': 8.52.0(eslint@9.39.2)(typescript@5.9.3) 1765 + '@typescript-eslint/parser': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 1510 1766 '@typescript-eslint/scope-manager': 8.52.0 1511 - '@typescript-eslint/type-utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3) 1512 - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3) 1767 + '@typescript-eslint/type-utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 1768 + '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 1513 1769 '@typescript-eslint/visitor-keys': 8.52.0 1514 - eslint: 9.39.2 1770 + eslint: 9.39.2(jiti@2.6.1) 1515 1771 ignore: 7.0.5 1516 1772 natural-compare: 1.4.0 1517 1773 ts-api-utils: 2.4.0(typescript@5.9.3) ··· 1519 1775 transitivePeerDependencies: 1520 1776 - supports-color 1521 1777 1522 - '@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3)': 1778 + '@typescript-eslint/parser@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 1523 1779 dependencies: 1524 1780 '@typescript-eslint/scope-manager': 8.52.0 1525 1781 '@typescript-eslint/types': 8.52.0 1526 1782 '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) 1527 1783 '@typescript-eslint/visitor-keys': 8.52.0 1528 1784 debug: 4.4.3 1529 - eslint: 9.39.2 1785 + eslint: 9.39.2(jiti@2.6.1) 1530 1786 typescript: 5.9.3 1531 1787 transitivePeerDependencies: 1532 1788 - supports-color ··· 1549 1805 dependencies: 1550 1806 typescript: 5.9.3 1551 1807 1552 - '@typescript-eslint/type-utils@8.52.0(eslint@9.39.2)(typescript@5.9.3)': 1808 + '@typescript-eslint/type-utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 1553 1809 dependencies: 1554 1810 '@typescript-eslint/types': 8.52.0 1555 1811 '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) 1556 - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3) 1812 + '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 1557 1813 debug: 4.4.3 1558 - eslint: 9.39.2 1814 + eslint: 9.39.2(jiti@2.6.1) 1559 1815 ts-api-utils: 2.4.0(typescript@5.9.3) 1560 1816 typescript: 5.9.3 1561 1817 transitivePeerDependencies: ··· 1578 1834 transitivePeerDependencies: 1579 1835 - supports-color 1580 1836 1581 - '@typescript-eslint/utils@8.52.0(eslint@9.39.2)(typescript@5.9.3)': 1837 + '@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 1582 1838 dependencies: 1583 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) 1839 + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) 1584 1840 '@typescript-eslint/scope-manager': 8.52.0 1585 1841 '@typescript-eslint/types': 8.52.0 1586 1842 '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) 1587 - eslint: 9.39.2 1843 + eslint: 9.39.2(jiti@2.6.1) 1588 1844 typescript: 5.9.3 1589 1845 transitivePeerDependencies: 1590 1846 - supports-color ··· 1657 1913 1658 1914 cssesc@3.0.0: {} 1659 1915 1916 + daisyui@5.5.14: {} 1917 + 1660 1918 debug@4.4.3: 1661 1919 dependencies: 1662 1920 ms: 2.1.3 ··· 1664 1922 deep-is@0.1.4: {} 1665 1923 1666 1924 deepmerge@4.3.1: {} 1925 + 1926 + detect-libc@2.1.2: {} 1667 1927 1668 1928 devalue@5.6.1: {} 1669 1929 1930 + enhanced-resolve@5.18.4: 1931 + dependencies: 1932 + graceful-fs: 4.2.11 1933 + tapable: 2.3.0 1934 + 1670 1935 esbuild@0.27.2: 1671 1936 optionalDependencies: 1672 1937 '@esbuild/aix-ppc64': 0.27.2 ··· 1698 1963 1699 1964 escape-string-regexp@4.0.0: {} 1700 1965 1701 - eslint-plugin-svelte@3.14.0(eslint@9.39.2)(svelte@5.46.1): 1966 + eslint-plugin-svelte@3.14.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.46.1): 1702 1967 dependencies: 1703 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) 1968 + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) 1704 1969 '@jridgewell/sourcemap-codec': 1.5.5 1705 - eslint: 9.39.2 1970 + eslint: 9.39.2(jiti@2.6.1) 1706 1971 esutils: 2.0.3 1707 1972 globals: 16.5.0 1708 1973 known-css-properties: 0.37.0 ··· 1725 1990 1726 1991 eslint-visitor-keys@4.2.1: {} 1727 1992 1728 - eslint@9.39.2: 1993 + eslint@9.39.2(jiti@2.6.1): 1729 1994 dependencies: 1730 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) 1995 + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) 1731 1996 '@eslint-community/regexpp': 4.12.2 1732 1997 '@eslint/config-array': 0.21.1 1733 1998 '@eslint/config-helpers': 0.4.2 ··· 1761 2026 minimatch: 3.1.2 1762 2027 natural-compare: 1.4.0 1763 2028 optionator: 0.9.4 2029 + optionalDependencies: 2030 + jiti: 2.6.1 1764 2031 transitivePeerDependencies: 1765 2032 - supports-color 1766 2033 ··· 1827 2094 1828 2095 globals@17.0.0: {} 1829 2096 2097 + graceful-fs@4.2.11: {} 2098 + 1830 2099 has-flag@4.0.0: {} 1831 2100 1832 2101 ignore@5.3.2: {} ··· 1852 2121 1853 2122 isexe@2.0.0: {} 1854 2123 2124 + jiti@2.6.1: {} 2125 + 1855 2126 js-yaml@4.1.1: 1856 2127 dependencies: 1857 2128 argparse: 2.0.1 ··· 1873 2144 prelude-ls: 1.2.1 1874 2145 type-check: 0.4.0 1875 2146 2147 + lightningcss-android-arm64@1.30.2: 2148 + optional: true 2149 + 2150 + lightningcss-darwin-arm64@1.30.2: 2151 + optional: true 2152 + 2153 + lightningcss-darwin-x64@1.30.2: 2154 + optional: true 2155 + 2156 + lightningcss-freebsd-x64@1.30.2: 2157 + optional: true 2158 + 2159 + lightningcss-linux-arm-gnueabihf@1.30.2: 2160 + optional: true 2161 + 2162 + lightningcss-linux-arm64-gnu@1.30.2: 2163 + optional: true 2164 + 2165 + lightningcss-linux-arm64-musl@1.30.2: 2166 + optional: true 2167 + 2168 + lightningcss-linux-x64-gnu@1.30.2: 2169 + optional: true 2170 + 2171 + lightningcss-linux-x64-musl@1.30.2: 2172 + optional: true 2173 + 2174 + lightningcss-win32-arm64-msvc@1.30.2: 2175 + optional: true 2176 + 2177 + lightningcss-win32-x64-msvc@1.30.2: 2178 + optional: true 2179 + 2180 + lightningcss@1.30.2: 2181 + dependencies: 2182 + detect-libc: 2.1.2 2183 + optionalDependencies: 2184 + lightningcss-android-arm64: 1.30.2 2185 + lightningcss-darwin-arm64: 1.30.2 2186 + lightningcss-darwin-x64: 1.30.2 2187 + lightningcss-freebsd-x64: 1.30.2 2188 + lightningcss-linux-arm-gnueabihf: 1.30.2 2189 + lightningcss-linux-arm64-gnu: 1.30.2 2190 + lightningcss-linux-arm64-musl: 1.30.2 2191 + lightningcss-linux-x64-gnu: 1.30.2 2192 + lightningcss-linux-x64-musl: 1.30.2 2193 + lightningcss-win32-arm64-msvc: 1.30.2 2194 + lightningcss-win32-x64-msvc: 1.30.2 2195 + 1876 2196 lilconfig@2.1.0: {} 1877 2197 1878 2198 locate-character@3.0.0: {} ··· 2060 2380 magic-string: 0.30.21 2061 2381 zimmerframe: 1.1.4 2062 2382 2383 + tailwindcss@4.1.18: {} 2384 + 2385 + tapable@2.3.0: {} 2386 + 2063 2387 tinyglobby@0.2.15: 2064 2388 dependencies: 2065 2389 fdir: 6.5.0(picomatch@4.0.3) ··· 2073 2397 dependencies: 2074 2398 prelude-ls: 1.2.1 2075 2399 2076 - typescript-eslint@8.52.0(eslint@9.39.2)(typescript@5.9.3): 2400 + typescript-eslint@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): 2077 2401 dependencies: 2078 - '@typescript-eslint/eslint-plugin': 8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) 2079 - '@typescript-eslint/parser': 8.52.0(eslint@9.39.2)(typescript@5.9.3) 2402 + '@typescript-eslint/eslint-plugin': 8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 2403 + '@typescript-eslint/parser': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 2080 2404 '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) 2081 - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3) 2082 - eslint: 9.39.2 2405 + '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 2406 + eslint: 9.39.2(jiti@2.6.1) 2083 2407 typescript: 5.9.3 2084 2408 transitivePeerDependencies: 2085 2409 - supports-color ··· 2096 2420 2097 2421 util-deprecate@1.0.2: {} 2098 2422 2099 - vite@7.3.1(@types/node@24.10.4): 2423 + vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2): 2100 2424 dependencies: 2101 2425 esbuild: 0.27.2 2102 2426 fdir: 6.5.0(picomatch@4.0.3) ··· 2107 2431 optionalDependencies: 2108 2432 '@types/node': 24.10.4 2109 2433 fsevents: 2.3.3 2434 + jiti: 2.6.1 2435 + lightningcss: 1.30.2 2110 2436 2111 - vitefu@1.1.1(vite@7.3.1(@types/node@24.10.4)): 2437 + vitefu@1.1.1(vite@7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)): 2112 2438 optionalDependencies: 2113 - vite: 7.3.1(@types/node@24.10.4) 2439 + vite: 7.3.1(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2) 2114 2440 2115 2441 which@2.0.2: 2116 2442 dependencies:
public/dude.png

This is a binary file and will not be displayed.

public/slowPoke.png

This is a binary file and will not be displayed.

-1
public/vite.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
+31 -28
src/App.svelte
··· 4 4 import RepoStats from './lib/RepoStats.svelte'; 5 5 6 6 let showRepoStats = $state(false); 7 - let did = $state(''); 8 - let pdsUrl = $state(''); 9 - let slowPoke = $state(false); 7 + let searchResults = $state({ 8 + did: '', 9 + handle: '', 10 + pdsUrl: '', 11 + slowPoke: false 12 + }); 10 13 11 - const resolvedResult = (didResult: string, pdsUrlResult: string, slowPokeResult: boolean) => { 12 - did = didResult; 13 - pdsUrl = pdsUrlResult; 14 - slowPoke = slowPokeResult; 14 + const resolvedResult = (didResult: string, handle: string, pdsUrlResult: string, slowPokeResult: boolean) => { 15 + searchResults = { did: didResult, handle: handle, pdsUrl: pdsUrlResult, slowPoke: slowPokeResult }; 15 16 showRepoStats = true; 16 17 }; 17 18 18 - 19 19 </script> 20 20 21 - <main> 22 - {#if showRepoStats} 23 - {#if slowPoke} 24 - <h2>Walking the repo via api calls</h2> 25 - {:else} 26 - <h2>Walking the repo via repo export</h2> 27 - {/if} 28 - {:else} 29 - <h1>Repo Walk Example</h1> 30 - <br> 31 - <p>Demo showing why you may rather export the users whole repo instead of walking it via api calls</p> 21 + <a href="https://tangled.org/baileytownsend.dev/repo-walk-example" target="_blank" rel="noopener noreferrer" class="fixed top-4 right-4 z-50 btn btn-ghost btn-sm gap-2 hover:scale-110 transition-transform shadow-lg"> 22 + <svg version="1.1" class="size-6" width="25" height="25" viewBox="0 0 25 25" xmlns="http://www.w3.org/2000/svg"> 23 + <g transform="translate(-0.42924038,-0.87777209)"> 24 + <path fill="currentColor" style="stroke-width:0.111183;" d="m 16.775491,24.987061 c -0.78517,-0.0064 -1.384202,-0.234614 -2.033994,-0.631295 -0.931792,-0.490188 -1.643475,-1.31368 -2.152014,-2.221647 C 11.781409,23.136647 10.701392,23.744942 9.4922931,24.0886 8.9774725,24.238111 8.0757679,24.389777 6.5811304,23.84827 4.4270703,23.124679 2.8580086,20.883331 3.0363279,18.599583 3.0037061,17.652919 3.3488675,16.723769 3.8381157,15.925061 2.5329485,15.224503 1.4686756,14.048584 1.0611184,12.606459 0.81344502,11.816973 0.82385989,10.966486 0.91519098,10.154906 1.2422711,8.2387903 2.6795811,6.5725716 4.5299585,5.9732484 5.2685364,4.290122 6.8802592,3.0349975 8.706276,2.7794663 c 1.2124148,-0.1688264 2.46744,0.084987 3.52811,0.7011837 1.545426,-1.7139736 4.237779,-2.2205077 6.293579,-1.1676231 1.568222,0.7488935 2.689625,2.3113526 2.961888,4.0151464 1.492195,0.5977882 2.749007,1.8168898 3.242225,3.3644951 0.329805,0.9581836 0.340709,2.0135956 0.127128,2.9974286 -0.381606,1.535184 -1.465322,2.842146 -2.868035,3.556463 0.0034,0.273204 0.901506,2.243045 0.751284,3.729647 -0.03281,1.858525 -1.211631,3.619894 -2.846433,4.475452 -0.953967,0.556812 -2.084452,0.546309 -3.120531,0.535398 z m -4.470079,-5.349839 c 1.322246,-0.147248 2.189053,-1.300106 2.862307,-2.338363 0.318287,-0.472954 0.561404,-1.002348 0.803,-1.505815 0.313265,0.287151 0.578698,0.828085 1.074141,0.956909 0.521892,0.162542 1.133743,0.03052 1.45325,-0.443554 0.611414,-1.140449 0.31004,-2.516537 -0.04602,-3.698347 C 18.232844,11.92927 17.945151,11.232927 17.397785,10.751793 17.514522,9.9283111 17.026575,9.0919791 16.332883,8.6609491 15.741721,9.1323278 14.842258,9.1294949 14.271975,8.6252369 13.178927,9.7400102 12.177239,9.7029996 11.209704,8.8195135 10.992255,8.6209543 10.577326,10.031484 9.1211947,9.2324497 8.2846288,9.9333947 7.6359672,10.607693 7.0611981,11.578553 6.5026891,12.62523 5.9177873,13.554793 5.867393,14.69141 c -0.024234,0.66432 0.4948601,1.360337 1.1982269,1.306329 0.702996,0.06277 1.1815208,-0.629091 1.7138087,-0.916491 0.079382,0.927141 0.1688108,1.923227 0.4821259,2.828358 0.3596254,1.171275 1.6262605,1.915695 2.8251855,1.745211 0.08481,-0.0066 0.218672,-0.01769 0.218672,-0.0176 z m 0.686342,-3.497495 c -0.643126,-0.394168 -0.33365,-1.249599 -0.359402,-1.870938 0.064,-0.749774 0.115321,-1.538054 0.452402,-2.221125 0.356724,-0.487008 1.226721,-0.299139 1.265134,0.325689 -0.02558,0.628509 -0.314101,1.25416 -0.279646,1.9057 -0.07482,0.544043 0.05418,1.155133 -0.186476,1.652391 -0.197455,0.275121 -0.599638,0.355105 -0.892012,0.208283 z m -2.808766,-0.358124 c -0.605767,-0.328664 -0.4133176,-1.155655 -0.5083256,-1.73063 0.078762,-0.66567 0.013203,-1.510085 0.5705316,-1.976886 0.545037,-0.380109 1.286917,0.270803 1.029164,0.868384 -0.274913,0.755214 -0.09475,1.580345 -0.08893,2.34609 -0.104009,0.451702 -0.587146,0.691508 -1.002445,0.493042 z"></path> 25 + </g> 26 + </svg> 27 + <span class="hidden sm:inline">View on Tangled</span> 28 + </a> 32 29 33 - <sub>Also shows how many records you have and how many of each kind if you're into that kind of thing...</sub> 34 - {/if} 35 - <div class="card"> 30 + <main class="container mx-auto px-4 py-8 max-w-4xl"> 31 + <div class="text-center mb-8"> 36 32 {#if showRepoStats} 37 - <RepoStats did={did} pdsUrl={pdsUrl} slowPokeMode={slowPoke}/> 33 + <h2 class="text-2xl font-bold text-primary">Walking <a class="link link-info" href="https://pdsls.dev/at://{searchResults.did}" target="_blank">{searchResults.handle}</a>'s repo {searchResults.slowPoke ? 'via api calls' : 'via export'}</h2> 38 34 {:else} 39 - <SearchForm resolvedResult={resolvedResult}/> 35 + <h1 class="text-5xl font-bold mb-4">Walk The Repo</h1> 36 + <p class="text-lg mb-2">Demo showing why you may rather export the users whole repo instead of walking it via api calls if you want to access all the user's records.</p> 37 + <p class="text-sm opacity-70">Also shows how many records you have and how many of each kind if you're into that kind of thing...</p> 40 38 {/if} 41 39 </div> 42 40 41 + <div class="card bg-base-200 shadow-xl"> 42 + <div class="card-body"> 43 + {#if showRepoStats} 44 + <RepoStats did={searchResults.did} pdsUrl={searchResults.pdsUrl} slowPokeMode={searchResults.slowPoke} handle={searchResults.handle}/> 45 + {:else} 46 + <SearchForm resolvedResult={resolvedResult}/> 47 + {/if} 48 + </div> 49 + </div> 43 50 </main> 44 - 45 - <style> 46 - 47 - </style>
+3 -78
src/app.css
··· 1 - :root { 2 - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; 3 - line-height: 1.5; 4 - font-weight: 400; 5 - 6 - color-scheme: light dark; 7 - color: rgba(255, 255, 255, 0.87); 8 - background-color: #242424; 9 - 10 - font-synthesis: none; 11 - text-rendering: optimizeLegibility; 12 - -webkit-font-smoothing: antialiased; 13 - -moz-osx-font-smoothing: grayscale; 14 - } 15 - 16 - a { 17 - font-weight: 500; 18 - color: #646cff; 19 - text-decoration: inherit; 20 - } 21 - a:hover { 22 - color: #535bf2; 23 - } 24 - 25 - body { 26 - margin: 0; 27 - display: flex; 28 - place-items: start; 29 - min-width: 320px; 30 - min-height: 100vh; 31 - } 32 - 33 - h1 { 34 - font-size: 3.2em; 35 - line-height: 1.1; 36 - } 37 - 38 - .card { 39 - padding: 2em; 40 - } 41 - 42 - #app { 43 - max-width: 1280px; 44 - margin: 0 auto; 45 - padding: 2rem; 46 - text-align: center; 47 - } 48 - 49 - button { 50 - border-radius: 8px; 51 - border: 1px solid transparent; 52 - padding: 0.6em 1.2em; 53 - font-size: 1em; 54 - font-weight: 500; 55 - font-family: inherit; 56 - background-color: #1a1a1a; 57 - cursor: pointer; 58 - transition: border-color 0.25s; 59 - } 60 - button:hover { 61 - border-color: #646cff; 62 - } 63 - button:focus, 64 - button:focus-visible { 65 - outline: 4px auto -webkit-focus-ring-color; 66 - } 67 - 68 - @media (prefers-color-scheme: light) { 69 - :root { 70 - color: #213547; 71 - background-color: #ffffff; 72 - } 73 - a:hover { 74 - color: #747bff; 75 - } 76 - button { 77 - background-color: #f9f9f9; 78 - } 1 + @import "tailwindcss"; 2 + @plugin "daisyui" { 3 + themes: forest --default; 79 4 }
-1
src/assets/svelte.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="26.6" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 308"><path fill="#FF3E00" d="M239.682 40.707C211.113-.182 154.69-12.301 113.895 13.69L42.247 59.356a82.198 82.198 0 0 0-37.135 55.056a86.566 86.566 0 0 0 8.536 55.576a82.425 82.425 0 0 0-12.296 30.719a87.596 87.596 0 0 0 14.964 66.244c28.574 40.893 84.997 53.007 125.787 27.016l71.648-45.664a82.182 82.182 0 0 0 37.135-55.057a86.601 86.601 0 0 0-8.53-55.577a82.409 82.409 0 0 0 12.29-30.718a87.573 87.573 0 0 0-14.963-66.244"></path><path fill="#FFF" d="M106.889 270.841c-23.102 6.007-47.497-3.036-61.103-22.648a52.685 52.685 0 0 1-9.003-39.85a49.978 49.978 0 0 1 1.713-6.693l1.35-4.115l3.671 2.697a92.447 92.447 0 0 0 28.036 14.007l2.663.808l-.245 2.659a16.067 16.067 0 0 0 2.89 10.656a17.143 17.143 0 0 0 18.397 6.828a15.786 15.786 0 0 0 4.403-1.935l71.67-45.672a14.922 14.922 0 0 0 6.734-9.977a15.923 15.923 0 0 0-2.713-12.011a17.156 17.156 0 0 0-18.404-6.832a15.78 15.78 0 0 0-4.396 1.933l-27.35 17.434a52.298 52.298 0 0 1-14.553 6.391c-23.101 6.007-47.497-3.036-61.101-22.649a52.681 52.681 0 0 1-9.004-39.849a49.428 49.428 0 0 1 22.34-33.114l71.664-45.677a52.218 52.218 0 0 1 14.563-6.398c23.101-6.007 47.497 3.036 61.101 22.648a52.685 52.685 0 0 1 9.004 39.85a50.559 50.559 0 0 1-1.713 6.692l-1.35 4.116l-3.67-2.693a92.373 92.373 0 0 0-28.037-14.013l-2.664-.809l.246-2.658a16.099 16.099 0 0 0-2.89-10.656a17.143 17.143 0 0 0-18.398-6.828a15.786 15.786 0 0 0-4.402 1.935l-71.67 45.674a14.898 14.898 0 0 0-6.73 9.975a15.9 15.9 0 0 0 2.709 12.012a17.156 17.156 0 0 0 18.404 6.832a15.841 15.841 0 0 0 4.402-1.935l27.345-17.427a52.147 52.147 0 0 1 14.552-6.397c23.101-6.006 47.497 3.037 61.102 22.65a52.681 52.681 0 0 1 9.003 39.848a49.453 49.453 0 0 1-22.34 33.12l-71.664 45.673a52.218 52.218 0 0 1-14.563 6.398"></path></svg>
+103 -38
src/lib/RepoStats.svelte
··· 1 1 <script lang="ts"> 2 - import { fromStream } from '@atcute/repo'; 3 2 import { onMount } from 'svelte'; 4 3 import { Client, simpleFetchHandler } from '@atcute/client'; 5 4 import type {} from '@atcute/atproto'; 5 + import { fromStream } from '@atcute/repo'; 6 6 7 - const { did, pdsUrl, slowPokeMode } = $props(); 7 + const { did, handle, pdsUrl, slowPokeMode } = $props(); 8 8 9 9 interface CountedCollection { 10 10 collection: string; ··· 14 14 //Shared State 15 15 let loading = $state(true); 16 16 let error: string | null = $state(null); 17 - //Downloaded stuff 17 + //Download info stuff 18 18 let downloadedBytes = $state(0); 19 19 let downloadedMB = $derived((downloadedBytes / (1024 * 1024)).toFixed(2)); 20 20 //Ui counts for collections ··· 52 52 calculateElapsedTime(); 53 53 }; 54 54 55 - // Calls the getRepo endpoint to get a .car export to walk the repo 55 + // Calls the getRepo endpoint to get a .car export to walk the repo. allows you to stream and access records as they are downloaded 56 56 const getRepoStatsViaExport = async () => { 57 57 const rpc = new Client({ handler: simpleFetchHandler({ service: pdsUrl }) }); 58 58 startTimer(); ··· 65 65 if (!result.ok) { 66 66 throw new Error(`HTTP error! status: ${result.status}`); 67 67 } 68 - 69 - let stream = result.data; 70 - const car = fromStream(stream); 68 + const repo = fromStream(result.data); 71 69 72 70 try { 73 - for await (const entry of car) { 74 - 71 + //This reads the repo as it is downloaded. which was very cool and I didn't know it would do that 72 + for await (const entry of repo) { 73 + // record here is the content of the atproto record 74 + // console.log(entry.record); 75 75 let checkForCollection = collections.find(c => c.collection === entry.collection); 76 76 if (!checkForCollection) { 77 77 collections.push({ collection: entry.collection, count: 1 }); ··· 83 83 } 84 84 } finally { 85 85 stopTimer(); 86 - await car.dispose(); 87 86 } 88 - 89 87 loading = false; 90 88 } catch (err) { 91 89 stopTimer(); 90 + console.log(err); 92 91 console.error('Error fetching repo stats:', err); 93 92 if (err instanceof Error) { 94 93 error = err.message; ··· 105 104 try { 106 105 const rpc = new Client({ handler: simpleFetchHandler({ service: pdsUrl }) }); 107 106 startTimer(); 107 + //We can make a call to get a list of collections in the repo 108 108 let describeRepo = await rpc.get('com.atproto.repo.describeRepo', { 109 109 params: { 110 110 repo: did ··· 114 114 throw new Error(`HTTP error! status: ${describeRepo.status}`); 115 115 } 116 116 webCalls++; 117 + //We go through each collection and get a list of records in it 117 118 for (const collection of describeRepo.data.collections) { 118 119 let totalRecordsInCollection = 0; 119 120 currentCollection = collection; 121 + //Do the first call to get a cursor 120 122 const firstCollectionList = await rpc.get('com.atproto.repo.listRecords', { 121 123 params: { 122 124 collection, 123 - repo: did 125 + repo: did, 126 + limit: 100, 124 127 } 125 128 }); 126 129 webCalls++; ··· 132 135 totalRecordsInCollection += firstCollectionList.data.records.length; 133 136 134 137 let cursor = firstCollectionList.data.cursor; 138 + //Walk the collection till the cursor is undefined meaning no more records 135 139 do { 136 140 const nextCollectionList = await rpc.get('com.atproto.repo.listRecords', { 137 141 params: { 138 142 collection, 139 143 repo: did, 144 + limit: 100, 140 145 cursor 141 146 } 142 147 }); ··· 178 183 179 184 </script> 180 185 181 - <div> 182 - {#if slowPokeMode} 183 - <img alt="A Shellder biting a Slowpoke's tail, as seen in the Pokรฉmon anime " 184 - src="https://upload.wikimedia.org/wikipedia/en/a/a2/Slowpoke_and_Shellder.jpg"> 185 - <br> 186 - {/if} 186 + <div class="flex flex-col items-center gap-4"> 187 + <div class="w-full flex justify-center"> 188 + {#if slowPokeMode} 189 + <img 190 + alt="A Shellder biting a Slowpoke's tail, as seen in the Pokรฉmon anime" 191 + src="/slowPoke.png" 192 + class="max-w-sm rounded-lg shadow-lg" 193 + > 194 + {:else} 195 + <img 196 + alt="text in a speech bubble that says 'Dude, wheres my car'" 197 + src="/dude.png" 198 + class="max-w-sm rounded-lg shadow-lg" 199 + > 200 + {/if} 201 + </div> 187 202 188 203 {#if error} 189 - <p style="color: red">{error}</p> 204 + <div class="alert alert-error w-full"> 205 + <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"> 206 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /> 207 + </svg> 208 + <span>{error}</span> 209 + </div> 190 210 {/if} 211 + 191 212 {#if loading && !slowPokeMode} 192 - Loading... ({downloadedMB} MB downloaded, {elapsedTime}s) 213 + <div class="flex items-center gap-3"> 214 + <span class="loading loading-spinner loading-lg text-primary"></span> 215 + <div class="text-lg"> 216 + <div class="font-semibold">Loading...</div> 217 + <div class="text-sm opacity-70"> 218 + <span class="badge badge-info">{downloadedMB} MB</span> downloaded in 219 + <span class="badge badge-ghost">{elapsedTime}s</span> 220 + </div> 221 + </div> 222 + </div> 193 223 {:else if loading && slowPokeMode} 194 - Loading... ({webCalls.toLocaleString()} web calls made, {elapsedTime}s) 224 + <div class="flex items-center gap-3"> 225 + <span class="loading loading-spinner loading-lg text-primary"></span> 226 + <div class="text-lg"> 227 + <div class="font-semibold">Loading...</div> 228 + <div class="text-sm opacity-70"> 229 + <span class="badge badge-info">{webCalls.toLocaleString()} web calls</span> made in 230 + <span class="badge badge-ghost">{elapsedTime}s</span> 231 + </div> 232 + </div> 233 + </div> 195 234 {:else} 196 - {#if !slowPokeMode} 197 - <span>Repo size {downloadedMB} MB (fetched in {elapsedTime}s)</span> 198 - {:else} 199 - <span>Web calls made: {webCalls.toLocaleString()} (fetched in {elapsedTime}s)</span> 200 - {/if} 235 + <div class="stats shadow bg-base-300"> 236 + <div class="stat"> 237 + <div class="stat-title">{slowPokeMode ? 'Web Calls Made' : 'Repo Size'}</div> 238 + <div class="stat-value text-primary"> 239 + {#if !slowPokeMode} 240 + {downloadedMB} MB 241 + {:else} 242 + {webCalls.toLocaleString()} 243 + {/if} 244 + </div> 245 + <div class="stat-desc">Fetched in {elapsedTime}s</div> 246 + </div> 247 + </div> 201 248 {/if} 249 + 202 250 {#if loading && currentCollection !== null} 203 - <br> 204 - <span>Currently walking collection: {currentCollection}</span> 251 + <div class="alert alert-info"> 252 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-current shrink-0 w-6 h-6"> 253 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path> 254 + </svg> 255 + <span>Currently walking collection: <strong>{currentCollection}</strong></span> 256 + </div> 205 257 {/if} 206 258 207 259 {#if collectionsOrdered.length > 0} 260 + <div class="stats stats-vertical lg:stats-horizontal shadow bg-base-300 w-full"> 261 + <div class="stat"> 262 + <div class="stat-title">Total Records</div> 263 + <div class="stat-value text-secondary">{totalRecords.toLocaleString()}</div> 264 + </div> 265 + <div class="stat"> 266 + <div class="stat-title">Different Collections</div> 267 + <div class="stat-value text-accent">{collectionsOrdered.length}</div> 268 + </div> 269 + </div> 208 270 209 - <br> 210 - <span>Total Records: {totalRecords.toLocaleString()}</span> 211 - <br> 212 - <span>Different Collections: {collectionsOrdered.length}</span> 213 - <br> 214 - <ol style="text-align: left;"> 215 - {#each collectionsOrdered as collection (collection.collection)} 216 - <li>{collection.collection} ({collection.count.toLocaleString()} records)</li> 217 - {/each} 218 - </ol> 271 + <div class="card bg-base-300 shadow-xl w-full"> 272 + <div class="card-body"> 273 + <h3 class="card-title">{handle}'s Collections Breakdown</h3> 274 + <ol class="list-decimal list-inside space-y-2"> 275 + {#each collectionsOrdered as collection (collection.collection)} 276 + <li class="text-sm"> 277 + <a class="link font-mono text-primary" href="https://pdsls.dev/at://{did}/{collection.collection}" target="_blank">{collection.collection}</a> 278 + <span class="badge badge-sm ml-2">{collection.count.toLocaleString()} records</span> 279 + </li> 280 + {/each} 281 + </ol> 282 + </div> 283 + </div> 219 284 {/if} 220 285 </div>
+36 -15
src/lib/SearchForm.svelte
··· 37 37 event.preventDefault(); 38 38 error = null; 39 39 try { 40 - if (!isHandle(handleToLookUp)) { 40 + let handle = handleToLookUp.replace(/^@/, '').toLowerCase(); 41 + if (!isHandle(handle)) { 41 42 error = 'Not a valid handle'; 42 43 return; 43 44 } 44 - 45 - let did = await handleResolver.resolve(handleToLookUp); 45 + let did = await handleResolver.resolve(handle); 46 46 47 47 const didDoc = await didResolver.resolve(did); 48 48 const pdsUrl = getPdsEndpoint(didDoc); 49 - 50 - resolvedResult(did, pdsUrl, slowpoke); 49 + 50 + resolvedResult(did, handle, pdsUrl, slowpoke); 51 51 }catch(e){ 52 52 if (e instanceof Error) { 53 53 error = e.message; ··· 58 58 59 59 </script> 60 60 61 - <form onsubmit={searchForUser}> 62 - <label for="search">ATProto Handle</label> 63 - <input bind:value={handleToLookUp} id="search" type="text" placeholder="alice.bsky.social"/> 64 - <button>Lookup</button> 65 - <br> 66 - <label> 67 - <input bind:checked={slowpoke} type="checkbox"/> 68 - slowpoke (uses web calls to walk the repository to show you the speed difference) 61 + <form onsubmit={searchForUser} class="space-y-4"> 62 + <fieldset class="fieldset w-full"> 63 + <label class="label" for="search">ATProto Handle</label> 64 + <input 65 + bind:value={handleToLookUp} 66 + id="search" 67 + type="text" 68 + placeholder="alice.bsky.social" 69 + class="input input-bordered w-full" 70 + /> 71 + </fieldset> 72 + 73 + <fieldset class="fieldset bg-base-100 border-base-300 rounded-box w-64 border p-4"> 74 + <legend class="fieldset-legend">Slow Poke</legend> 75 + <label class="label"> 76 + <input type="checkbox" bind:checked={slowpoke} class="toggle" /> 77 + uses web calls to walk the repo to show you the speed difference 78 + </label> 79 + </fieldset> 69 80 70 - </label> 71 81 {#if error} 72 - <p style="color: red;">Error: {error}</p> 82 + <div class="alert alert-error"> 83 + <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"> 84 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /> 85 + </svg> 86 + <span>Error: {error}</span> 87 + </div> 73 88 {/if} 89 + 90 + <div class="form-control mt-6"> 91 + <button class="btn btn-primary"> 92 + Walk by {slowpoke ? 'API Calls' : 'Repo Export'} 93 + </button> 94 + </div> 74 95 </form>
+5 -1
vite.config.ts
··· 1 1 import { defineConfig } from 'vite'; 2 2 import { svelte } from '@sveltejs/vite-plugin-svelte'; 3 + import tailwindcss from '@tailwindcss/vite' 3 4 4 5 // https://vite.dev/config/ 5 6 export default defineConfig({ 6 - plugins: [svelte()], 7 + plugins: [ 8 + svelte(), 9 + tailwindcss(), 10 + ], 7 11 });