A decentralized music tracking and discovery platform built on AT Protocol 🎵 rocksky.app
spotify atproto lastfm musicbrainz scrobbling listenbrainz
98
fork

Configure Feed

Select the types of activity you want to include in your feed.

Use CAR parsing for repo sync and increase batch size

Replace paginated listRecords calls with getRepo and parse CAR blocks
using @ipld/car and @ipld/dag-cbor. Add related dependencies (and
multiformats) and update bun.lock (apps/cli version 0.2.0 → 0.3.0).

+181 -76
+4
apps/cli/package.json
··· 32 32 "@atproto/jwk-jose": "0.1.5", 33 33 "@atproto/lex-cli": "^0.5.6", 34 34 "@atproto/lexicon": "^0.4.5", 35 + "@atproto/repo": "^0.6.2", 35 36 "@atproto/sync": "^0.1.11", 36 37 "@atproto/syntax": "^0.3.1", 38 + "@ipld/car": "^3.2.4", 39 + "@ipld/dag-cbor": "^9.2.2", 37 40 "@hono/node-server": "^1.13.8", 38 41 "@logtape/logtape": "^1.3.6", 39 42 "@modelcontextprotocol/sdk": "^1.10.2", ··· 56 59 "kysely": "^0.27.5", 57 60 "lodash": "^4.17.21", 58 61 "md5": "^2.3.0", 62 + "multiformats": "^9.9.0", 59 63 "open": "^10.1.0", 60 64 "table": "^6.9.0", 61 65 "unstorage": "^1.14.4",
+149 -70
apps/cli/src/cmd/sync.ts
··· 21 21 import { getDidAndHandle } from "lib/getDidAndHandle"; 22 22 import { cleanUpJetstreamLockOnExit } from "lib/cleanUpJetstreamLock"; 23 23 import { cleanUpSyncLockOnExit } from "lib/cleanUpSyncLock"; 24 - 25 - const PAGE_SIZE = 100; 24 + import { CarReader } from "@ipld/car"; 25 + import * as cbor from "@ipld/dag-cbor"; 26 26 27 27 type Artists = { value: Artist.Record; uri: string; cid: string }[]; 28 28 type Albums = { value: Album.Record; uri: string; cid: string }[]; ··· 133 133 name: tag, 134 134 })); 135 135 136 - const BATCH_SIZE = 500; 136 + const BATCH_SIZE = 1000; 137 137 for (let i = 0; i < uniqueTags.length; i += BATCH_SIZE) { 138 138 const batch = uniqueTags.slice(i, i + BATCH_SIZE); 139 139 await ctx.db ··· 241 241 .filter(({ artist }) => artist); 242 242 243 243 // Process albums in batches 244 - const BATCH_SIZE = 500; 244 + const BATCH_SIZE = 1000; 245 245 let totalAlbumsImported = 0; 246 246 247 247 for (let i = 0; i < validAlbumData.length; i += BATCH_SIZE) { ··· 332 332 .filter(({ artist, album }) => artist && album); 333 333 334 334 // Process in batches to avoid stack overflow with large datasets 335 - const BATCH_SIZE = 500; 335 + const BATCH_SIZE = 1000; 336 336 let totalTracksImported = 0; 337 337 338 338 for (let i = 0; i < validSongData.length; i += BATCH_SIZE) { ··· 481 481 .filter(({ track, album, artist }) => track && album && artist); 482 482 483 483 // Process in batches to avoid stack overflow with large datasets 484 - const BATCH_SIZE = 500; 484 + const BATCH_SIZE = 1000; 485 485 let totalScrobblesImported = 0; 486 486 487 487 for (let i = 0; i < validScrobbleData.length; i += BATCH_SIZE) { ··· 687 687 }; 688 688 689 689 const getRockskyUserSongs = async (agent: Agent): Promise<Songs> => { 690 - let results: { 690 + const results: { 691 691 value: Song.Record; 692 692 uri: string; 693 693 cid: string; 694 694 }[] = []; 695 - let cursor: string | undefined; 696 - do { 697 - const res = await agent.com.atproto.repo.listRecords({ 698 - repo: agent.assertDid, 699 - collection: "app.rocksky.song", 700 - limit: PAGE_SIZE, 701 - cursor, 695 + 696 + try { 697 + logger.info(`Fetching repository CAR file for songs...`); 698 + 699 + const repoRes = await agent.com.atproto.sync.getRepo({ 700 + did: agent.assertDid, 702 701 }); 703 - const records = res.data.records as Array<{ 704 - uri: string; 705 - cid: string; 706 - value: Song.Record; 707 - }>; 708 - results = results.concat(records); 709 - cursor = res.data.cursor; 702 + 703 + const carReader = await CarReader.fromBytes(new Uint8Array(repoRes.data)); 704 + const collection = "app.rocksky.song"; 705 + 706 + for await (const { cid, bytes } of carReader.blocks()) { 707 + try { 708 + const decoded = cbor.decode(bytes); 709 + 710 + // Check if this is a record with $type matching our collection 711 + if (decoded && typeof decoded === "object" && "$type" in decoded) { 712 + if (decoded.$type === collection) { 713 + const value = decoded as unknown as Song.Record; 714 + // Extract rkey from uri if present in the block, otherwise use cid 715 + const uri = `at://${agent.assertDid}/${collection}/${cid.toString()}`; 716 + 717 + results.push({ 718 + value, 719 + uri, 720 + cid: cid.toString(), 721 + }); 722 + } 723 + } 724 + } catch (e) { 725 + logger.warn` Skipping block with CID ${cid.toString()} due to decode error: ${e}`; 726 + continue; 727 + } 728 + } 729 + 710 730 logger.info( 711 731 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} songs`, 712 732 ); 713 - } while (cursor); 733 + } catch (error) { 734 + logger.error(`Error fetching songs from CAR: ${error}`); 735 + throw error; 736 + } 714 737 715 738 return results; 716 739 }; 717 740 718 741 const getRockskyUserAlbums = async (agent: Agent): Promise<Albums> => { 719 - let results: { 742 + const results: { 720 743 value: Album.Record; 721 744 uri: string; 722 745 cid: string; 723 746 }[] = []; 724 - let cursor: string | undefined; 725 - do { 726 - const res = await agent.com.atproto.repo.listRecords({ 727 - repo: agent.assertDid, 728 - collection: "app.rocksky.album", 729 - limit: PAGE_SIZE, 730 - cursor, 747 + 748 + try { 749 + logger.info(`Fetching repository CAR file for albums...`); 750 + 751 + // Use getRepo to fetch the entire repository as a CAR file 752 + const repoRes = await agent.com.atproto.sync.getRepo({ 753 + did: agent.assertDid, 731 754 }); 732 755 733 - const records = res.data.records as Array<{ 734 - uri: string; 735 - cid: string; 736 - value: Album.Record; 737 - }>; 756 + // Parse the CAR file 757 + const carReader = await CarReader.fromBytes(new Uint8Array(repoRes.data)); 758 + const collection = "app.rocksky.album"; 759 + 760 + for await (const { cid, bytes } of carReader.blocks()) { 761 + try { 762 + const decoded = cbor.decode(bytes); 763 + 764 + if (decoded && typeof decoded === "object" && "$type" in decoded) { 765 + if (decoded.$type === collection) { 766 + const value = decoded as unknown as Album.Record; 767 + const uri = `at://${agent.assertDid}/${collection}/${cid.toString()}`; 738 768 739 - results = results.concat(records); 769 + results.push({ 770 + value, 771 + uri, 772 + cid: cid.toString(), 773 + }); 774 + } 775 + } 776 + } catch (e) { 777 + logger.warn` Skipping block with CID ${cid.toString()} due to decode error: ${e}`; 778 + continue; 779 + } 780 + } 740 781 741 - cursor = res.data.cursor; 742 782 logger.info( 743 783 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} albums`, 744 784 ); 745 - } while (cursor); 785 + } catch (error) { 786 + logger.error(`Error fetching albums from CAR: ${error}`); 787 + throw error; 788 + } 746 789 747 790 return results; 748 791 }; 749 792 750 793 const getRockskyUserArtists = async (agent: Agent): Promise<Artists> => { 751 - let results: { 794 + const results: { 752 795 value: Artist.Record; 753 796 uri: string; 754 797 cid: string; 755 798 }[] = []; 756 - let cursor: string | undefined; 757 - do { 758 - const res = await agent.com.atproto.repo.listRecords({ 759 - repo: agent.assertDid, 760 - collection: "app.rocksky.artist", 761 - limit: PAGE_SIZE, 762 - cursor, 799 + 800 + try { 801 + logger.info(`Fetching repository CAR file for artists...`); 802 + 803 + const repoRes = await agent.com.atproto.sync.getRepo({ 804 + did: agent.assertDid, 763 805 }); 764 806 765 - const records = res.data.records as Array<{ 766 - uri: string; 767 - cid: string; 768 - value: Artist.Record; 769 - }>; 807 + const carReader = await CarReader.fromBytes(new Uint8Array(repoRes.data)); 808 + const collection = "app.rocksky.artist"; 809 + 810 + for await (const { cid, bytes } of carReader.blocks()) { 811 + try { 812 + const decoded = cbor.decode(bytes); 770 813 771 - results = results.concat(records); 814 + if (decoded && typeof decoded === "object" && "$type" in decoded) { 815 + if (decoded.$type === collection) { 816 + const value = decoded as unknown as Artist.Record; 817 + const uri = `at://${agent.assertDid}/${collection}/${cid.toString()}`; 818 + 819 + results.push({ 820 + value, 821 + uri, 822 + cid: cid.toString(), 823 + }); 824 + } 825 + } 826 + } catch (e) { 827 + // Skip blocks that can't be decoded 828 + continue; 829 + } 830 + } 772 831 773 - cursor = res.data.cursor; 774 832 logger.info( 775 833 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} artists`, 776 834 ); 777 - } while (cursor); 835 + } catch (error) { 836 + logger.error(`Error fetching artists from CAR: ${error}`); 837 + throw error; 838 + } 778 839 779 840 return results; 780 841 }; 781 842 782 843 const getRockskyUserScrobbles = async (agent: Agent): Promise<Scrobbles> => { 783 - let results: { 844 + const results: { 784 845 value: Scrobble.Record; 785 846 uri: string; 786 847 cid: string; 787 848 }[] = []; 788 - let cursor: string | undefined; 789 - do { 790 - const res = await agent.com.atproto.repo.listRecords({ 791 - repo: agent.assertDid, 792 - collection: "app.rocksky.scrobble", 793 - limit: PAGE_SIZE, 794 - cursor, 849 + 850 + try { 851 + logger.info(`Fetching repository CAR file for scrobbles...`); 852 + 853 + const repoRes = await agent.com.atproto.sync.getRepo({ 854 + did: agent.assertDid, 795 855 }); 796 856 797 - const records = res.data.records as Array<{ 798 - uri: string; 799 - cid: string; 800 - value: Scrobble.Record; 801 - }>; 857 + const carReader = await CarReader.fromBytes(new Uint8Array(repoRes.data)); 858 + const collection = "app.rocksky.scrobble"; 802 859 803 - results = results.concat(records); 860 + for await (const { cid, bytes } of carReader.blocks()) { 861 + try { 862 + const decoded = cbor.decode(bytes); 804 863 805 - cursor = res.data.cursor; 864 + if (decoded && typeof decoded === "object" && "$type" in decoded) { 865 + if (decoded.$type === collection) { 866 + const value = decoded as unknown as Scrobble.Record; 867 + const uri = `at://${agent.assertDid}/${collection}/${cid.toString()}`; 868 + 869 + results.push({ 870 + value, 871 + uri, 872 + cid: cid.toString(), 873 + }); 874 + } 875 + } 876 + } catch (e) { 877 + logger.warn` Skipping block with CID ${cid.toString()} due to decode error: ${e}`; 878 + continue; 879 + } 880 + } 881 + 806 882 logger.info( 807 883 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} scrobbles`, 808 884 ); 809 - } while (cursor); 885 + } catch (error) { 886 + logger.error(`Error fetching scrobbles from CAR: ${error}`); 887 + throw error; 888 + } 810 889 811 890 return results; 812 891 };
+28 -6
bun.lock
··· 103 103 }, 104 104 "apps/cli": { 105 105 "name": "@rocksky/cli", 106 - "version": "0.2.0", 106 + "version": "0.3.0", 107 107 "bin": { 108 108 "rocksky": "./dist/index.js", 109 109 }, ··· 114 114 "@atproto/jwk-jose": "0.1.5", 115 115 "@atproto/lex-cli": "^0.5.6", 116 116 "@atproto/lexicon": "^0.4.5", 117 + "@atproto/repo": "^0.6.2", 117 118 "@atproto/sync": "^0.1.11", 118 119 "@atproto/syntax": "^0.3.1", 119 120 "@hono/node-server": "^1.13.8", 121 + "@ipld/car": "^3.2.4", 122 + "@ipld/dag-cbor": "^9.2.2", 120 123 "@logtape/logtape": "^1.3.6", 121 124 "@modelcontextprotocol/sdk": "^1.10.2", 122 125 "@paralleldrive/cuid2": "^3.0.6", ··· 138 141 "kysely": "^0.27.5", 139 142 "lodash": "^4.17.21", 140 143 "md5": "^2.3.0", 144 + "multiformats": "^9.9.0", 141 145 "open": "^10.1.0", 142 146 "table": "^6.9.0", 143 147 "unstorage": "^1.14.4", ··· 413 417 414 418 "@atproto/oauth-types": ["@atproto/oauth-types@0.2.4", "", { "dependencies": { "@atproto/jwk": "0.1.4", "zod": "^3.23.8" } }, "sha512-V2LnlXi1CSmBQWTQgDm8l4oN7xYxlftVwM7hrvYNP+Jxo3Ozfe0QLK1Wy/CH6/ZqzrBBhYvcbf4DJYTUwPA+hw=="], 415 419 416 - "@atproto/repo": ["@atproto/repo@0.8.10", "", { "dependencies": { "@atproto/common": "^0.4.12", "@atproto/common-web": "^0.4.3", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.5.1", "@ipld/dag-cbor": "^7.0.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "varint": "^6.0.0", "zod": "^3.23.8" } }, "sha512-REs6TZGyxNaYsjqLf447u+gSdyzhvMkVbxMBiKt1ouEVRkiho1CY32+omn62UkpCuGK2y6SCf6x3sVMctgmX4g=="], 420 + "@atproto/repo": ["@atproto/repo@0.6.5", "", { "dependencies": { "@atproto/common": "^0.4.8", "@atproto/common-web": "^0.4.0", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.4.7", "@ipld/car": "^3.2.3", "@ipld/dag-cbor": "^7.0.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, "sha512-Sa95LaEMDtwL9M0kp3vuVQIcgEJI+6EssDLIiuPnJAi9SbEPESdUfEiIR5t2oFCkMwrS7OJQCLdCa7CMy+plUg=="], 417 421 418 422 "@atproto/sync": ["@atproto/sync@0.1.35", "", { "dependencies": { "@atproto/common": "^0.4.12", "@atproto/identity": "^0.4.9", "@atproto/lexicon": "^0.5.1", "@atproto/repo": "^0.8.10", "@atproto/syntax": "^0.4.1", "@atproto/xrpc-server": "^0.9.5", "multiformats": "^9.9.0", "p-queue": "^6.6.2", "ws": "^8.12.0" } }, "sha512-MPvmTjJYCilZEQF1ds7itzF9tNEZtw4Ez0HeMO5E5GaPtTAccBU3AsTxwWST87EX5qsVxMlBTq2go6G6+Swd7Q=="], 419 423 ··· 713 717 714 718 "@ioredis/commands": ["@ioredis/commands@1.4.0", "", {}, "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ=="], 715 719 716 - "@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="], 720 + "@ipld/car": ["@ipld/car@3.2.4", "", { "dependencies": { "@ipld/dag-cbor": "^7.0.0", "multiformats": "^9.5.4", "varint": "^6.0.0" } }, "sha512-rezKd+jk8AsTGOoJKqzfjLJ3WVft7NZNH95f0pfPbicROvzTyvHCNy567HzSUd6gRXZ9im29z5ZEv9Hw49jSYw=="], 721 + 722 + "@ipld/dag-cbor": ["@ipld/dag-cbor@9.2.5", "", { "dependencies": { "cborg": "^4.0.0", "multiformats": "^13.1.0" } }, "sha512-84wSr4jv30biui7endhobYhXBQzQE4c/wdoWlFrKcfiwH+ofaPg8fwsM8okX9cOzkkrsAsNdDyH3ou+kiLquwQ=="], 717 723 718 724 "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], 719 725 ··· 1529 1535 1530 1536 "cbor-x": ["cbor-x@1.6.0", "", { "optionalDependencies": { "cbor-extract": "^2.2.0" } }, "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg=="], 1531 1537 1532 - "cborg": ["cborg@1.10.2", "", { "bin": { "cborg": "cli.js" } }, "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug=="], 1538 + "cborg": ["cborg@4.3.2", "", { "bin": { "cborg": "lib/bin.js" } }, "sha512-l+QzebEAG0vb09YKkaOrMi2zmm80UNjmbvocMIeW5hO7JOXWdrQ/H49yOKfYX0MBgrj/KWgatBnEgRXyNyKD+A=="], 1533 1539 1534 1540 "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], 1535 1541 ··· 2939 2945 2940 2946 "@atproto-labs/identity-resolver/@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="], 2941 2947 2948 + "@atproto/common/@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="], 2949 + 2942 2950 "@atproto/crypto/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], 2943 2951 2944 2952 "@atproto/jwk-jose/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], ··· 2949 2957 2950 2958 "@atproto/lexicon/@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="], 2951 2959 2952 - "@atproto/repo/@atproto/lexicon": ["@atproto/lexicon@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A=="], 2960 + "@atproto/repo/@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="], 2953 2961 2954 2962 "@atproto/sync/@atproto/lexicon": ["@atproto/lexicon@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A=="], 2963 + 2964 + "@atproto/sync/@atproto/repo": ["@atproto/repo@0.8.10", "", { "dependencies": { "@atproto/common": "^0.4.12", "@atproto/common-web": "^0.4.3", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.5.1", "@ipld/dag-cbor": "^7.0.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "varint": "^6.0.0", "zod": "^3.23.8" } }, "sha512-REs6TZGyxNaYsjqLf447u+gSdyzhvMkVbxMBiKt1ouEVRkiho1CY32+omn62UkpCuGK2y6SCf6x3sVMctgmX4g=="], 2955 2965 2956 2966 "@atproto/sync/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw=="], 2957 2967 ··· 2988 2998 "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], 2989 2999 2990 3000 "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], 3001 + 3002 + "@ipld/car/@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="], 3003 + 3004 + "@ipld/dag-cbor/multiformats": ["multiformats@13.4.2", "", {}, "sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ=="], 2991 3005 2992 3006 "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], 2993 3007 ··· 3336 3350 "yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], 3337 3351 3338 3352 "youch/cookie": ["cookie@0.5.0", "", {}, "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="], 3353 + 3354 + "@atproto/common/@ipld/dag-cbor/cborg": ["cborg@1.10.2", "", { "bin": { "cborg": "cli.js" } }, "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug=="], 3339 3355 3340 3356 "@atproto/lex-cli/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 3341 3357 3342 - "@atproto/repo/@atproto/lexicon/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw=="], 3358 + "@atproto/repo/@ipld/dag-cbor/cborg": ["cborg@1.10.2", "", { "bin": { "cborg": "cli.js" } }, "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug=="], 3359 + 3360 + "@atproto/sync/@atproto/repo/@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="], 3343 3361 3344 3362 "@atproto/sync/@atproto/xrpc-server/@atproto/xrpc": ["@atproto/xrpc@0.7.5", "", { "dependencies": { "@atproto/lexicon": "^0.5.1", "zod": "^3.23.8" } }, "sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA=="], 3345 3363 ··· 3472 3490 "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], 3473 3491 3474 3492 "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], 3493 + 3494 + "@ipld/car/@ipld/dag-cbor/cborg": ["cborg@1.10.2", "", { "bin": { "cborg": "cli.js" } }, "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug=="], 3475 3495 3476 3496 "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], 3477 3497 ··· 3704 3724 "wrangler/miniflare/youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="], 3705 3725 3706 3726 "wrangler/miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], 3727 + 3728 + "@atproto/sync/@atproto/repo/@ipld/dag-cbor/cborg": ["cborg@1.10.2", "", { "bin": { "cborg": "cli.js" } }, "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug=="], 3707 3729 3708 3730 "@atproto/sync/@atproto/xrpc-server/express/accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], 3709 3731