-12
lexicons.json
-12
lexicons.json
···
1
-
{
2
-
"version": 1,
3
-
"lexicons": [
4
-
"com.atproto.sync.getRepo"
5
-
],
6
-
"resolutions": {
7
-
"com.atproto.sync.getRepo": {
8
-
"uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.sync.getRepo",
9
-
"cid": "bafyreieyt5x6wf4pgcn56tb2724uplmwcqjivkubmi25km3xrvroz6dw5q"
10
-
}
11
-
}
12
-
}
+2
-1
package.json
+2
-1
package.json
+50
-3
pnpm-lock.yaml
+50
-3
pnpm-lock.yaml
···
8
8
9
9
.:
10
10
dependencies:
11
-
'@atproto-labs/did-resolver':
12
-
specifier: ^0.2.5
13
-
version: 0.2.5
11
+
'@atcute/car':
12
+
specifier: ^5.0.0
13
+
version: 5.0.0
14
+
'@atcute/cbor':
15
+
specifier: ^2.2.8
16
+
version: 2.2.8
14
17
'@atproto-labs/handle-resolver':
15
18
specifier: ^0.3.5
16
19
version: 0.3.5
···
44
47
version: 7.3.1(@types/node@24.10.4)
45
48
46
49
packages:
50
+
51
+
'@atcute/car@5.0.0':
52
+
resolution: {integrity: sha512-OIY2xTXv8lSpZsDSn/UYQtJSMvDw5Hi4Q+uyvmiqSM+fht08QRAEq/nxa5YFciPZ3nfDFnZ3//EgJw7QhkSXLQ==}
53
+
54
+
'@atcute/cbor@2.2.8':
55
+
resolution: {integrity: sha512-UzOAN9BuN6JCXgn0ryV8qZuRJUDrNqrbLd6EFM8jc6RYssjRyGRxNy6RZ1NU/07Hd8Tq/0pz8+nQiMu5Zai5uw==}
56
+
57
+
'@atcute/cid@2.3.0':
58
+
resolution: {integrity: sha512-1SRdkTuMs/l5arQ+7Ag0F7JAueZqtzYE0d2gmbkuzi8EPweNU1kYlQs0CE4dSd81YF8PMDTOQty0K2ATq9CW9g==}
59
+
60
+
'@atcute/multibase@1.1.6':
61
+
resolution: {integrity: sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg==}
62
+
63
+
'@atcute/uint8array@1.0.6':
64
+
resolution: {integrity: sha512-ucfRBQc7BFT8n9eCyGOzDHEMKF/nZwhS2pPao4Xtab1ML3HdFYcX2DM1tadCzas85QTGxHe5urnUAAcNKGRi9A==}
65
+
66
+
'@atcute/varint@1.0.3':
67
+
resolution: {integrity: sha512-fdvMPyBB+McDT+Ai5e9RwEbwYV4yjZ60S2Dn5PTjGqUyxvoCH1z42viuheDZRUDkmfQehXJTZ5az7dSozVNtog==}
47
68
48
69
'@atproto-labs/did-resolver@0.2.5':
49
70
resolution: {integrity: sha512-he7EC6OMSifNs01a4RT9mta/yYitoKDzlK9ty2TFV5Uj/+HpB4vYMRdIDFrRW0Hcsehy90E2t/dw0t7361MEKQ==}
···
840
861
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
841
862
842
863
snapshots:
864
+
865
+
'@atcute/car@5.0.0':
866
+
dependencies:
867
+
'@atcute/cbor': 2.2.8
868
+
'@atcute/cid': 2.3.0
869
+
'@atcute/uint8array': 1.0.6
870
+
'@atcute/varint': 1.0.3
871
+
872
+
'@atcute/cbor@2.2.8':
873
+
dependencies:
874
+
'@atcute/cid': 2.3.0
875
+
'@atcute/multibase': 1.1.6
876
+
'@atcute/uint8array': 1.0.6
877
+
878
+
'@atcute/cid@2.3.0':
879
+
dependencies:
880
+
'@atcute/multibase': 1.1.6
881
+
'@atcute/uint8array': 1.0.6
882
+
883
+
'@atcute/multibase@1.1.6':
884
+
dependencies:
885
+
'@atcute/uint8array': 1.0.6
886
+
887
+
'@atcute/uint8array@1.0.6': {}
888
+
889
+
'@atcute/varint@1.0.3': {}
843
890
844
891
'@atproto-labs/did-resolver@0.2.5':
845
892
dependencies:
-5
src/lexicons/com.ts
-5
src/lexicons/com.ts
-5
src/lexicons/com/atproto.ts
-5
src/lexicons/com/atproto.ts
-5
src/lexicons/com/atproto/sync.ts
-5
src/lexicons/com/atproto/sync.ts
-29
src/lexicons/com/atproto/sync/getRepo.defs.ts
-29
src/lexicons/com/atproto/sync/getRepo.defs.ts
···
1
-
/*
2
-
* THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT.
3
-
*/
4
-
5
-
import { l } from '@atproto/lex'
6
-
7
-
const $nsid = 'com.atproto.sync.getRepo'
8
-
9
-
export { $nsid }
10
-
11
-
/** Download a repository export as CAR file. Optionally only a 'diff' since a previous revision. Does not require auth; implemented by PDS. */
12
-
const main = l.query(
13
-
$nsid,
14
-
l.params({
15
-
did: l.string({ format: 'did' }),
16
-
since: l.optional(l.string({ format: 'tid' })),
17
-
}),
18
-
l.payload('application/vnd.ipld.car'),
19
-
['RepoNotFound', 'RepoTakendown', 'RepoSuspended', 'RepoDeactivated'],
20
-
)
21
-
export { main }
22
-
23
-
export type Params = l.InferMethodParams<typeof main>
24
-
export type Output = l.InferMethodOutput<typeof main>
25
-
export type OutputBody = l.InferMethodOutputBody<typeof main>
26
-
27
-
export const $lxm = main.nsid,
28
-
$params = main.parameters,
29
-
$output = main.output
-6
src/lexicons/com/atproto/sync/getRepo.ts
-6
src/lexicons/com/atproto/sync/getRepo.ts
+48
-12
src/lib/RepoStats.svelte
+48
-12
src/lib/RepoStats.svelte
···
1
1
<script lang="ts">
2
+
import {fromStream, fromUint8Array} from '@atcute/car';
3
+
import * as CBOR from '@atcute/cbor';
4
+
5
+
interface CountedCollection {
6
+
collection: string;
7
+
count: number;
8
+
}
9
+
10
+
2
11
const { did, pdsUrl } = $props();
3
12
let loading = $state(true)
4
13
let downloadedBytes = $state(0)
5
14
let downloadedMB = $derived((downloadedBytes / (1024 * 1024)).toFixed(2))
6
15
let error: string | null = $state(null)
7
-
16
+
let collections = $state(new Array<CountedCollection>());
17
+
let collectionsOrdered: Array<CountedCollection> = $derived([...collections].sort((a, b) => b.count - a.count))
18
+
let totalRecords = $state(0)
8
19
9
20
const getRepoStats = async () => {
10
21
const endPoint = `${pdsUrl}/xrpc/com.atproto.sync.getRepo?did=${did}`
···
13
24
const response = await fetch(endPoint)
14
25
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`)
15
26
16
-
const reader = response.body?.getReader()
17
-
if (!reader) throw new Error('ReadableStream not supported')
27
+
const car = fromStream(response.body);
28
+
29
+
try {
30
+
for await (const entry of car) {
31
+
const data = CBOR.decode(entry.bytes);
32
+
if (!data.$type) {
33
+
continue;
34
+
}
18
35
19
-
while (true) {
20
-
const { done, value } = await reader.read()
21
-
if (done) break
22
-
downloadedBytes += value.length
36
+
let checkForCollection = collections.find(c => c.collection === data.$type);
37
+
if (!checkForCollection) {
38
+
collections.push({collection: data.$type, count: 1});
39
+
}else{
40
+
checkForCollection.count++;
41
+
}
42
+
downloadedBytes = entry.entryEnd;
43
+
totalRecords++;
23
44
}
24
-
loading = false
45
+
}finally{
46
+
await car.dispose()
47
+
}
48
+
49
+
loading = false;
25
50
} catch (err) {
26
-
console.error('Error fetching repo stats:', error)
51
+
console.error('Error fetching repo stats:', err)
27
52
error = err.message
28
53
loading = false
29
54
}
···
41
66
{/if}
42
67
{#if loading}
43
68
Loading... ({downloadedMB} MB downloaded)
44
-
{:else }
45
-
<ol>
46
-
<li>Total downloaded: {downloadedMB} MB</li>
69
+
{:else}
70
+
<span>Repo size {downloadedMB} MB</span>
71
+
{/if}
72
+
{#if collectionsOrdered.length > 0}
73
+
74
+
<br>
75
+
<span>Total Records: {totalRecords.toLocaleString()}</span>
76
+
<br>
77
+
<span>Different Collections: {collectionsOrdered.length}</span>
78
+
<br>
79
+
<ol style="text-align: left;">
80
+
{#each collectionsOrdered as collection (collection.collection)}
81
+
<li>{collection.collection} ({collection.count.toLocaleString()} records)</li>
82
+
{/each}
47
83
</ol>
48
84
{/if}
49
85
</div>