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

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 "@atproto/jwk-jose": "0.1.5", 33 "@atproto/lex-cli": "^0.5.6", 34 "@atproto/lexicon": "^0.4.5", 35 "@atproto/sync": "^0.1.11", 36 "@atproto/syntax": "^0.3.1", 37 "@hono/node-server": "^1.13.8", 38 "@logtape/logtape": "^1.3.6", 39 "@modelcontextprotocol/sdk": "^1.10.2", ··· 56 "kysely": "^0.27.5", 57 "lodash": "^4.17.21", 58 "md5": "^2.3.0", 59 "open": "^10.1.0", 60 "table": "^6.9.0", 61 "unstorage": "^1.14.4",
··· 32 "@atproto/jwk-jose": "0.1.5", 33 "@atproto/lex-cli": "^0.5.6", 34 "@atproto/lexicon": "^0.4.5", 35 + "@atproto/repo": "^0.6.2", 36 "@atproto/sync": "^0.1.11", 37 "@atproto/syntax": "^0.3.1", 38 + "@ipld/car": "^3.2.4", 39 + "@ipld/dag-cbor": "^9.2.2", 40 "@hono/node-server": "^1.13.8", 41 "@logtape/logtape": "^1.3.6", 42 "@modelcontextprotocol/sdk": "^1.10.2", ··· 59 "kysely": "^0.27.5", 60 "lodash": "^4.17.21", 61 "md5": "^2.3.0", 62 + "multiformats": "^9.9.0", 63 "open": "^10.1.0", 64 "table": "^6.9.0", 65 "unstorage": "^1.14.4",
+149 -70
apps/cli/src/cmd/sync.ts
··· 21 import { getDidAndHandle } from "lib/getDidAndHandle"; 22 import { cleanUpJetstreamLockOnExit } from "lib/cleanUpJetstreamLock"; 23 import { cleanUpSyncLockOnExit } from "lib/cleanUpSyncLock"; 24 - 25 - const PAGE_SIZE = 100; 26 27 type Artists = { value: Artist.Record; uri: string; cid: string }[]; 28 type Albums = { value: Album.Record; uri: string; cid: string }[]; ··· 133 name: tag, 134 })); 135 136 - const BATCH_SIZE = 500; 137 for (let i = 0; i < uniqueTags.length; i += BATCH_SIZE) { 138 const batch = uniqueTags.slice(i, i + BATCH_SIZE); 139 await ctx.db ··· 241 .filter(({ artist }) => artist); 242 243 // Process albums in batches 244 - const BATCH_SIZE = 500; 245 let totalAlbumsImported = 0; 246 247 for (let i = 0; i < validAlbumData.length; i += BATCH_SIZE) { ··· 332 .filter(({ artist, album }) => artist && album); 333 334 // Process in batches to avoid stack overflow with large datasets 335 - const BATCH_SIZE = 500; 336 let totalTracksImported = 0; 337 338 for (let i = 0; i < validSongData.length; i += BATCH_SIZE) { ··· 481 .filter(({ track, album, artist }) => track && album && artist); 482 483 // Process in batches to avoid stack overflow with large datasets 484 - const BATCH_SIZE = 500; 485 let totalScrobblesImported = 0; 486 487 for (let i = 0; i < validScrobbleData.length; i += BATCH_SIZE) { ··· 687 }; 688 689 const getRockskyUserSongs = async (agent: Agent): Promise<Songs> => { 690 - let results: { 691 value: Song.Record; 692 uri: string; 693 cid: string; 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, 702 }); 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; 710 logger.info( 711 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} songs`, 712 ); 713 - } while (cursor); 714 715 return results; 716 }; 717 718 const getRockskyUserAlbums = async (agent: Agent): Promise<Albums> => { 719 - let results: { 720 value: Album.Record; 721 uri: string; 722 cid: string; 723 }[] = []; 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, 731 }); 732 733 - const records = res.data.records as Array<{ 734 - uri: string; 735 - cid: string; 736 - value: Album.Record; 737 - }>; 738 739 - results = results.concat(records); 740 741 - cursor = res.data.cursor; 742 logger.info( 743 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} albums`, 744 ); 745 - } while (cursor); 746 747 return results; 748 }; 749 750 const getRockskyUserArtists = async (agent: Agent): Promise<Artists> => { 751 - let results: { 752 value: Artist.Record; 753 uri: string; 754 cid: string; 755 }[] = []; 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, 763 }); 764 765 - const records = res.data.records as Array<{ 766 - uri: string; 767 - cid: string; 768 - value: Artist.Record; 769 - }>; 770 771 - results = results.concat(records); 772 773 - cursor = res.data.cursor; 774 logger.info( 775 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} artists`, 776 ); 777 - } while (cursor); 778 779 return results; 780 }; 781 782 const getRockskyUserScrobbles = async (agent: Agent): Promise<Scrobbles> => { 783 - let results: { 784 value: Scrobble.Record; 785 uri: string; 786 cid: string; 787 }[] = []; 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, 795 }); 796 797 - const records = res.data.records as Array<{ 798 - uri: string; 799 - cid: string; 800 - value: Scrobble.Record; 801 - }>; 802 803 - results = results.concat(records); 804 805 - cursor = res.data.cursor; 806 logger.info( 807 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} scrobbles`, 808 ); 809 - } while (cursor); 810 811 return results; 812 };
··· 21 import { getDidAndHandle } from "lib/getDidAndHandle"; 22 import { cleanUpJetstreamLockOnExit } from "lib/cleanUpJetstreamLock"; 23 import { cleanUpSyncLockOnExit } from "lib/cleanUpSyncLock"; 24 + import { CarReader } from "@ipld/car"; 25 + import * as cbor from "@ipld/dag-cbor"; 26 27 type Artists = { value: Artist.Record; uri: string; cid: string }[]; 28 type Albums = { value: Album.Record; uri: string; cid: string }[]; ··· 133 name: tag, 134 })); 135 136 + const BATCH_SIZE = 1000; 137 for (let i = 0; i < uniqueTags.length; i += BATCH_SIZE) { 138 const batch = uniqueTags.slice(i, i + BATCH_SIZE); 139 await ctx.db ··· 241 .filter(({ artist }) => artist); 242 243 // Process albums in batches 244 + const BATCH_SIZE = 1000; 245 let totalAlbumsImported = 0; 246 247 for (let i = 0; i < validAlbumData.length; i += BATCH_SIZE) { ··· 332 .filter(({ artist, album }) => artist && album); 333 334 // Process in batches to avoid stack overflow with large datasets 335 + const BATCH_SIZE = 1000; 336 let totalTracksImported = 0; 337 338 for (let i = 0; i < validSongData.length; i += BATCH_SIZE) { ··· 481 .filter(({ track, album, artist }) => track && album && artist); 482 483 // Process in batches to avoid stack overflow with large datasets 484 + const BATCH_SIZE = 1000; 485 let totalScrobblesImported = 0; 486 487 for (let i = 0; i < validScrobbleData.length; i += BATCH_SIZE) { ··· 687 }; 688 689 const getRockskyUserSongs = async (agent: Agent): Promise<Songs> => { 690 + const results: { 691 value: Song.Record; 692 uri: string; 693 cid: string; 694 }[] = []; 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, 701 }); 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 + 730 logger.info( 731 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} songs`, 732 ); 733 + } catch (error) { 734 + logger.error(`Error fetching songs from CAR: ${error}`); 735 + throw error; 736 + } 737 738 return results; 739 }; 740 741 const getRockskyUserAlbums = async (agent: Agent): Promise<Albums> => { 742 + const results: { 743 value: Album.Record; 744 uri: string; 745 cid: string; 746 }[] = []; 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, 754 }); 755 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()}`; 768 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 + } 781 782 logger.info( 783 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} albums`, 784 ); 785 + } catch (error) { 786 + logger.error(`Error fetching albums from CAR: ${error}`); 787 + throw error; 788 + } 789 790 return results; 791 }; 792 793 const getRockskyUserArtists = async (agent: Agent): Promise<Artists> => { 794 + const results: { 795 value: Artist.Record; 796 uri: string; 797 cid: string; 798 }[] = []; 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, 805 }); 806 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); 813 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 + } 831 832 logger.info( 833 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} artists`, 834 ); 835 + } catch (error) { 836 + logger.error(`Error fetching artists from CAR: ${error}`); 837 + throw error; 838 + } 839 840 return results; 841 }; 842 843 const getRockskyUserScrobbles = async (agent: Agent): Promise<Scrobbles> => { 844 + const results: { 845 value: Scrobble.Record; 846 uri: string; 847 cid: string; 848 }[] = []; 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, 855 }); 856 857 + const carReader = await CarReader.fromBytes(new Uint8Array(repoRes.data)); 858 + const collection = "app.rocksky.scrobble"; 859 860 + for await (const { cid, bytes } of carReader.blocks()) { 861 + try { 862 + const decoded = cbor.decode(bytes); 863 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 + 882 logger.info( 883 `${chalk.cyanBright(agent.assertDid)} ${chalk.greenBright(results.length)} scrobbles`, 884 ); 885 + } catch (error) { 886 + logger.error(`Error fetching scrobbles from CAR: ${error}`); 887 + throw error; 888 + } 889 890 return results; 891 };
+28 -6
bun.lock
··· 103 }, 104 "apps/cli": { 105 "name": "@rocksky/cli", 106 - "version": "0.2.0", 107 "bin": { 108 "rocksky": "./dist/index.js", 109 }, ··· 114 "@atproto/jwk-jose": "0.1.5", 115 "@atproto/lex-cli": "^0.5.6", 116 "@atproto/lexicon": "^0.4.5", 117 "@atproto/sync": "^0.1.11", 118 "@atproto/syntax": "^0.3.1", 119 "@hono/node-server": "^1.13.8", 120 "@logtape/logtape": "^1.3.6", 121 "@modelcontextprotocol/sdk": "^1.10.2", 122 "@paralleldrive/cuid2": "^3.0.6", ··· 138 "kysely": "^0.27.5", 139 "lodash": "^4.17.21", 140 "md5": "^2.3.0", 141 "open": "^10.1.0", 142 "table": "^6.9.0", 143 "unstorage": "^1.14.4", ··· 413 414 "@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 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=="], 417 418 "@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 ··· 713 714 "@ioredis/commands": ["@ioredis/commands@1.4.0", "", {}, "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ=="], 715 716 - "@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="], 717 718 "@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 ··· 1529 1530 "cbor-x": ["cbor-x@1.6.0", "", { "optionalDependencies": { "cbor-extract": "^2.2.0" } }, "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg=="], 1531 1532 - "cborg": ["cborg@1.10.2", "", { "bin": { "cborg": "cli.js" } }, "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug=="], 1533 1534 "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 ··· 2939 2940 "@atproto-labs/identity-resolver/@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="], 2941 2942 "@atproto/crypto/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], 2943 2944 "@atproto/jwk-jose/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], ··· 2949 2950 "@atproto/lexicon/@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="], 2951 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=="], 2953 2954 "@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=="], 2955 2956 "@atproto/sync/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw=="], 2957 ··· 2988 "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], 2989 2990 "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], 2991 2992 "@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 ··· 3336 "yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], 3337 3338 "youch/cookie": ["cookie@0.5.0", "", {}, "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="], 3339 3340 "@atproto/lex-cli/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 3341 3342 - "@atproto/repo/@atproto/lexicon/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw=="], 3343 3344 "@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 ··· 3472 "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], 3473 3474 "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], 3475 3476 "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], 3477 ··· 3704 "wrangler/miniflare/youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="], 3705 3706 "wrangler/miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], 3707 3708 "@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
··· 103 }, 104 "apps/cli": { 105 "name": "@rocksky/cli", 106 + "version": "0.3.0", 107 "bin": { 108 "rocksky": "./dist/index.js", 109 }, ··· 114 "@atproto/jwk-jose": "0.1.5", 115 "@atproto/lex-cli": "^0.5.6", 116 "@atproto/lexicon": "^0.4.5", 117 + "@atproto/repo": "^0.6.2", 118 "@atproto/sync": "^0.1.11", 119 "@atproto/syntax": "^0.3.1", 120 "@hono/node-server": "^1.13.8", 121 + "@ipld/car": "^3.2.4", 122 + "@ipld/dag-cbor": "^9.2.2", 123 "@logtape/logtape": "^1.3.6", 124 "@modelcontextprotocol/sdk": "^1.10.2", 125 "@paralleldrive/cuid2": "^3.0.6", ··· 141 "kysely": "^0.27.5", 142 "lodash": "^4.17.21", 143 "md5": "^2.3.0", 144 + "multiformats": "^9.9.0", 145 "open": "^10.1.0", 146 "table": "^6.9.0", 147 "unstorage": "^1.14.4", ··· 417 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=="], 419 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=="], 421 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=="], 423 ··· 717 718 "@ioredis/commands": ["@ioredis/commands@1.4.0", "", {}, "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ=="], 719 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=="], 723 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=="], 725 ··· 1535 1536 "cbor-x": ["cbor-x@1.6.0", "", { "optionalDependencies": { "cbor-extract": "^2.2.0" } }, "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg=="], 1537 1538 + "cborg": ["cborg@4.3.2", "", { "bin": { "cborg": "lib/bin.js" } }, "sha512-l+QzebEAG0vb09YKkaOrMi2zmm80UNjmbvocMIeW5hO7JOXWdrQ/H49yOKfYX0MBgrj/KWgatBnEgRXyNyKD+A=="], 1539 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=="], 1541 ··· 2945 2946 "@atproto-labs/identity-resolver/@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="], 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 + 2950 "@atproto/crypto/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], 2951 2952 "@atproto/jwk-jose/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], ··· 2957 2958 "@atproto/lexicon/@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="], 2959 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=="], 2961 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=="], 2965 2966 "@atproto/sync/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw=="], 2967 ··· 2998 "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], 2999 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=="], 3005 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=="], 3007 ··· 3350 "yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], 3351 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=="], 3355 3356 "@atproto/lex-cli/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 3357 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=="], 3361 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=="], 3363 ··· 3490 "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], 3491 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=="], 3495 3496 "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], 3497 ··· 3724 "wrangler/miniflare/youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="], 3725 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=="], 3729 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=="], 3731