+4
-2
package.json
+4
-2
package.json
···
27
27
"wrangler": "^4.22.0"
28
28
},
29
29
"dependencies": {
30
-
"@atcute/bluesky": "^2.1.1",
30
+
"@atcute/atproto": "^3.1.0",
31
+
"@atcute/bluesky": "^3.1.4",
31
32
"@atcute/bluesky-richtext-parser": "^1.0.7",
32
33
"@atcute/bluesky-richtext-segmenter": "^2.0.3",
33
-
"@atcute/client": "^3.1.0",
34
+
"@atcute/client": "^4.0.3",
35
+
"@atcute/lexicons": "^1.1.0",
34
36
"@badrap/valita": "^0.4.5",
35
37
"@mary/array-fns": "jsr:^0.1.4",
36
38
"@mary/date-fns": "jsr:^0.1.3",
+24
-16
pnpm-lock.yaml
+24
-16
pnpm-lock.yaml
···
8
8
9
9
.:
10
10
dependencies:
11
+
'@atcute/atproto':
12
+
specifier: ^3.1.0
13
+
version: 3.1.0
11
14
'@atcute/bluesky':
12
-
specifier: ^2.1.1
13
-
version: 2.1.1(@atcute/client@3.1.0)
15
+
specifier: ^3.1.4
16
+
version: 3.1.4
14
17
'@atcute/bluesky-richtext-parser':
15
18
specifier: ^1.0.7
16
19
version: 1.0.7
···
18
21
specifier: ^2.0.3
19
22
version: 2.0.3
20
23
'@atcute/client':
21
-
specifier: ^3.1.0
22
-
version: 3.1.0
24
+
specifier: ^4.0.3
25
+
version: 4.0.3
26
+
'@atcute/lexicons':
27
+
specifier: ^1.1.0
28
+
version: 1.1.0
23
29
'@badrap/valita':
24
30
specifier: ^0.4.5
25
31
version: 0.4.5
···
85
91
'@atcute/bluesky-richtext-segmenter@2.0.3':
86
92
resolution: {integrity: sha512-8Jy2EHdqx0mKI0k8l4h2cnaBN1pGgSzSazO0Gp85ttIQmgynZsQX6l4OWgaQx0aNZFmqZRXJ7N0rj/b2dlO1eQ==}
87
93
88
-
'@atcute/bluesky@2.1.1':
89
-
resolution: {integrity: sha512-wEZfFW58J6yC1SqHcVJOn4qbHENTTzjeCEWthRT5HvKovADLqk54HSMSAuXDMBUbintSTBr0khQNZQ3ZdgzDdQ==}
90
-
peerDependencies:
91
-
'@atcute/client': ^3.0.0
92
-
93
94
'@atcute/bluesky@3.1.4':
94
95
resolution: {integrity: sha512-iSdZGk/UktgKpT/lI0/YxRjM3E5dkd6/vIa2mgH82lgRjI0jH5LJAfLXPyr2mPeZ/qku1gf2/KrkqJ9dfiNxVw==}
95
96
96
-
'@atcute/client@3.1.0':
97
-
resolution: {integrity: sha512-+rQPsHXSf0DUm8XoHoaH7Y2E8tIpbsW84djyPj7dqAyrFIjvGuJ1X1DvMufwbTIcmLerdy+dzl34iZcz/h3Vhg==}
97
+
'@atcute/client@4.0.3':
98
+
resolution: {integrity: sha512-RIOZWFVLca/HiPAAUDqQPOdOreCxTbL5cb+WUf5yqQOKIu5yEAP3eksinmlLmgIrlr5qVOE7brazUUzaskFCfw==}
99
+
100
+
'@atcute/identity@1.0.3':
101
+
resolution: {integrity: sha512-mNMxbKHFGys03A8JXKk0KfMBzdd0vrYMzZZWjpw1nYTs0+ea6bo5S1hwqVUZxHdo1gFHSe/t63jxQIF4yL9aKw==}
98
102
99
103
'@atcute/lexicons@1.1.0':
100
104
resolution: {integrity: sha512-LFqwnria78xLYb62Ri/+WwQpUTgZp2DuyolNGIIOV1dpiKhFFFh//nscHMA6IExFLQRqWDs3tTjy7zv0h3sf1Q==}
···
1164
1168
'@atcute/bluesky': 3.1.4
1165
1169
'@atcute/lexicons': 1.1.0
1166
1170
1167
-
'@atcute/bluesky@2.1.1(@atcute/client@3.1.0)':
1168
-
dependencies:
1169
-
'@atcute/client': 3.1.0
1170
-
1171
1171
'@atcute/bluesky@3.1.4':
1172
1172
dependencies:
1173
1173
'@atcute/atproto': 3.1.0
1174
1174
'@atcute/lexicons': 1.1.0
1175
1175
1176
-
'@atcute/client@3.1.0': {}
1176
+
'@atcute/client@4.0.3':
1177
+
dependencies:
1178
+
'@atcute/identity': 1.0.3
1179
+
'@atcute/lexicons': 1.1.0
1180
+
1181
+
'@atcute/identity@1.0.3':
1182
+
dependencies:
1183
+
'@atcute/lexicons': 1.1.0
1184
+
'@badrap/valita': 0.4.5
1177
1185
1178
1186
'@atcute/lexicons@1.1.0':
1179
1187
dependencies:
+4
-4
src/hooks.server.ts
+4
-4
src/hooks.server.ts
···
1
-
import { XRPCError } from '@atcute/client';
1
+
import { ClientResponseError } from '@atcute/client';
2
2
import type { HandleServerError } from '@sveltejs/kit';
3
3
4
4
export const handleError: HandleServerError = async ({ error, event, status, message }) => {
5
5
console.error(error);
6
6
7
-
if (error instanceof XRPCError) {
7
+
if (error instanceof ClientResponseError) {
8
8
if (error.status === 403) {
9
9
return {
10
10
message: `Upstream server is forbidding access to this resource`,
11
11
};
12
12
}
13
13
14
-
if (error.kind === 'AuthRequired' || error.kind === 'auth required') {
14
+
if (error.error === 'AuthRequired' || error.error === 'auth required') {
15
15
return {
16
16
message: `Upstream server is requiring authentication to access this resource`,
17
17
};
18
18
}
19
19
20
-
if (error.kind === 'InternalServerError' || error.description === 'Internal Server Error') {
20
+
if (error.error === 'InternalServerError' || error.description === 'Internal Server Error') {
21
21
return {
22
22
message: `Upstream server returned an internal error`,
23
23
};
+1
-1
src/lib/components/avatar.svelte
+1
-1
src/lib/components/avatar.svelte
+16
-19
src/lib/components/embeds/embeds.svelte
+16
-19
src/lib/components/embeds/embeds.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs } from '@atcute/client/lexicons';
2
+
import { unwrapEmbed, type AppBskyFeedDefs, type MediaEmbed, type RecordEmbed } from '@atcute/bluesky';
3
3
4
4
import { findLabel, FlagsBlurMedia } from '$lib/moderation';
5
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
-
import { unwrapEmbedView, type MediaEmbed, type RecordEmbed } from '$lib/utils/bluesky/embeds';
5
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
6
import { collectionToLabel } from '$lib/utils/bluesky/records';
8
7
9
8
import ContentHider from '../content-hider.svelte';
···
27
26
28
27
const { embed, large = false, post }: Props = $props();
29
28
30
-
const { media, record } = $derived(unwrapEmbedView(embed));
29
+
const { media, record } = $derived(unwrapEmbed(embed));
31
30
</script>
32
31
33
32
<div class="embeds">
···
56
55
{/snippet}
57
56
58
57
{#snippet Record(embed: RecordEmbed)}
59
-
{@const record = embed.record}
60
-
61
-
{#if record.$type === 'app.bsky.embed.record#viewRecord'}
62
-
<QuoteEmbed embed={record} {large} />
63
-
{:else if record.$type === 'app.bsky.feed.defs#generatorView'}
64
-
<FeedEmbed embed={record} />
65
-
{:else if record.$type === 'app.bsky.graph.defs#listView'}
66
-
<ListEmbed embed={record} />
67
-
{:else if record.$type === 'app.bsky.graph.defs#starterPackViewBasic'}
68
-
<StarterpackEmbed embed={record} {large} />
58
+
{#if embed.$type === 'app.bsky.embed.record#viewRecord'}
59
+
<QuoteEmbed {embed} {large} />
60
+
{:else if embed.$type === 'app.bsky.feed.defs#generatorView'}
61
+
<FeedEmbed {embed} />
62
+
{:else if embed.$type === 'app.bsky.graph.defs#listView'}
63
+
<ListEmbed {embed} />
64
+
{:else if embed.$type === 'app.bsky.graph.defs#starterPackViewBasic'}
65
+
<StarterpackEmbed {embed} {large} />
69
66
{:else}
70
-
{@const uri = parseAddressedAtUri(record.uri)}
67
+
{@const uri = assertCanonicalResourceUri(embed.uri)}
71
68
72
-
{#if uri.collection === 'app.bsky.feed.post' && (record.$type === 'app.bsky.embed.record#viewBlocked' || record.$type === 'app.bsky.embed.record#viewDetached')}
73
-
<QuoteBlockedEmbed embed={record} {uri} />
69
+
{#if uri.collection === 'app.bsky.feed.post' && (embed.$type === 'app.bsky.embed.record#viewBlocked' || embed.$type === 'app.bsky.embed.record#viewDetached')}
70
+
<QuoteBlockedEmbed {embed} {uri} />
74
71
{:else}
75
72
{@const resource = collectionToLabel(uri.collection)}
76
73
{@const isUnavailable =
77
74
resource &&
78
-
(record.$type === 'app.bsky.embed.record#viewNotFound' ||
79
-
record.$type === 'app.bsky.embed.record#viewBlocked')}
75
+
(embed.$type === 'app.bsky.embed.record#viewNotFound' ||
76
+
embed.$type === 'app.bsky.embed.record#viewBlocked')}
80
77
81
78
{@render Message(isUnavailable ? `This ${resource} is unavailable` : `Unsupported record embed`)}
82
79
{/if}
+1
-1
src/lib/components/embeds/external-embed.svelte
+1
-1
src/lib/components/embeds/external-embed.svelte
+3
-3
src/lib/components/embeds/feed-embed.svelte
+3
-3
src/lib/components/embeds/feed-embed.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
6
import { findLabel, FlagsBlurMedia } from '$lib/moderation';
7
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
7
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
8
8
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
9
9
import { trimRichText } from '$lib/utils/bluesky/richtext';
10
10
import { truncateRight } from '$lib/utils/strings';
···
22
22
const blurAvi = $derived(!!findLabel(feed.labels, creator.did, FlagsBlurMedia));
23
23
</script>
24
24
25
-
<a href="{base}/{creator.did}/feeds/{parseAddressedAtUri(feed.uri).rkey}" class="feed-embed">
25
+
<a href="{base}/{creator.did}/feeds/{assertCanonicalResourceUri(feed.uri).rkey}" class="feed-embed">
26
26
<div class="main">
27
27
<Avatar type="generator" src={feed.avatar} blur={blurAvi} />
28
28
+1
-1
src/lib/components/embeds/image-embed.svelte
+1
-1
src/lib/components/embeds/image-embed.svelte
+3
-3
src/lib/components/embeds/list-embed.svelte
+3
-3
src/lib/components/embeds/list-embed.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyGraphDefs } from '@atcute/client/lexicons';
2
+
import type { AppBskyGraphDefs } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
6
import { findLabel, FlagsBlurMedia } from '$lib/moderation';
7
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
7
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
8
8
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
9
9
import { purposeToLabel } from '$lib/utils/bluesky/lists';
10
10
import { trimRichText } from '$lib/utils/bluesky/richtext';
···
23
23
const blurAvi = $derived(!!findLabel(list.labels, creator.did, FlagsBlurMedia));
24
24
</script>
25
25
26
-
<a href="{base}/{creator.did}/lists/{parseAddressedAtUri(list.uri).rkey}" class="list-embed">
26
+
<a href="{base}/{creator.did}/lists/{assertCanonicalResourceUri(list.uri).rkey}" class="list-embed">
27
27
<div class="main">
28
28
<Avatar type="list" src={list.avatar} blur={blurAvi} />
29
29
+4
-5
src/lib/components/embeds/quote-blocked-embed.svelte
+4
-5
src/lib/components/embeds/quote-blocked-embed.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyEmbedRecord, Brand } from '@atcute/client/lexicons';
2
+
import type { AppBskyEmbedRecord } from '@atcute/bluesky';
3
+
import type { $type, ParsedCanonicalResourceUri } from '@atcute/lexicons';
3
4
4
5
import { base } from '$app/paths';
5
-
6
-
import type { AddressedAtUri } from '$lib/types/at-uri';
7
6
8
7
import CircleBanSignOutlined from '$lib/components/central-icons/circle-ban-sign-outlined.svelte';
9
8
10
9
interface Props {
11
-
embed: Brand.Union<AppBskyEmbedRecord.ViewBlocked | AppBskyEmbedRecord.ViewDetached>;
12
-
uri: AddressedAtUri;
10
+
embed: $type.enforce<AppBskyEmbedRecord.ViewBlocked | AppBskyEmbedRecord.ViewDetached>;
11
+
uri: ParsedCanonicalResourceUri;
13
12
}
14
13
15
14
const { embed, uri }: Props = $props();
+5
-6
src/lib/components/embeds/quote-embed.svelte
+5
-6
src/lib/components/embeds/quote-embed.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyEmbedRecord, AppBskyFeedPost } from '@atcute/client/lexicons';
2
+
import { unwrapMediaEmbed, type AppBskyEmbedRecord, type AppBskyFeedPost } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
6
import { findLabel, FlagsBlurContent, FlagsBlurMedia } from '$lib/moderation';
7
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
7
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
8
8
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
9
-
import { unwrapMediaEmbedView } from '$lib/utils/bluesky/embeds';
10
9
import { trimRichText } from '$lib/utils/bluesky/richtext';
11
10
12
11
import Avatar from '$lib/components/avatar.svelte';
···
24
23
25
24
const { embed: quote, large = false }: Props = $props();
26
25
27
-
const record = $derived(quote.value as AppBskyFeedPost.Record);
26
+
const record = $derived(quote.value as AppBskyFeedPost.Main);
28
27
const text = $derived(trimRichText(record.text));
29
28
30
29
const author = $derived(quote.author);
31
30
const authorName = $derived(normalizeDisplayName(author.displayName ?? ''));
32
31
33
32
const embed = $derived(quote.embeds?.[0]);
34
-
const media = $derived(unwrapMediaEmbedView(embed));
33
+
const media = $derived(unwrapMediaEmbed(embed));
35
34
36
35
const blurAvi = $derived(!!findLabel(author.labels, author.did, FlagsBlurMedia));
37
36
const blurContent = $derived(findLabel(quote.labels, author.did, FlagsBlurContent));
···
39
38
</script>
40
39
41
40
<ContentHider blur={blurContent}>
42
-
<a href="{base}/{author.did}/{parseAddressedAtUri(quote.uri).rkey}#main" class="quote-embed">
41
+
<a href="{base}/{author.did}/{assertCanonicalResourceUri(quote.uri).rkey}#main" class="quote-embed">
43
42
<div class="meta">
44
43
<Avatar profile={author} src={author.avatar} size="xs" blur={blurAvi} />
45
44
+4
-4
src/lib/components/embeds/starterpack-embed.svelte
+4
-4
src/lib/components/embeds/starterpack-embed.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyGraphDefs, AppBskyGraphStarterpack } from '@atcute/client/lexicons';
2
+
import type { AppBskyGraphDefs, AppBskyGraphStarterpack } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
8
8
import { trimRichText } from '$lib/utils/bluesky/richtext';
9
9
import { truncateRight } from '$lib/utils/strings';
···
17
17
18
18
const { embed: pack, large = false }: Props = $props();
19
19
20
-
const record = pack.record as AppBskyGraphStarterpack.Record;
20
+
const record = pack.record as AppBskyGraphStarterpack.Main;
21
21
22
22
const creator = $derived(pack.creator);
23
23
24
-
const rkey = $derived(parseAddressedAtUri(pack.uri).rkey);
24
+
const rkey = $derived(assertCanonicalResourceUri(pack.uri).rkey);
25
25
</script>
26
26
27
27
<a href="{base}/{creator.did}/packs/{rkey}" class="starterpack-embed">
+1
-1
src/lib/components/embeds/video-standalone-embed.svelte
+1
-1
src/lib/components/embeds/video-standalone-embed.svelte
+1
-1
src/lib/components/embeds/video-thumbnail-embed.svelte
+1
-1
src/lib/components/embeds/video-thumbnail-embed.svelte
···
1
1
<script lang="ts">
2
2
// This is meant to be used inside quote embeds, so it's non-standalone.
3
3
4
-
import type { AppBskyEmbedVideo } from '@atcute/client/lexicons';
4
+
import type { AppBskyEmbedVideo } from '@atcute/bluesky';
5
5
6
6
import { replaceVideoCdnUrl } from '$lib/utils/bluesky/videos';
7
7
+3
-3
src/lib/components/feeds/feed-item.svelte
+3
-3
src/lib/components/feeds/feed-item.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
8
8
import { trimRichText } from '$lib/utils/bluesky/richtext';
9
9
import { formatLongNumber } from '$lib/utils/intl/number';
···
19
19
20
20
const creator = $derived(feed.creator);
21
21
22
-
const href = $derived(`${base}/${creator.did}/feeds/${parseAddressedAtUri(feed.uri).rkey}`);
22
+
const href = $derived(`${base}/${creator.did}/feeds/${assertCanonicalResourceUri(feed.uri).rkey}`);
23
23
</script>
24
24
25
25
<div class="feed-item">
+3
-3
src/lib/components/lists/list-item.svelte
+3
-3
src/lib/components/lists/list-item.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyGraphDefs } from '@atcute/client/lexicons';
2
+
import type { AppBskyGraphDefs } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
8
8
import { purposeToLabel } from '$lib/utils/bluesky/lists';
9
9
import { trimRichText } from '$lib/utils/bluesky/richtext';
···
19
19
20
20
const creator = $derived(list.creator);
21
21
22
-
const href = $derived(`${base}/${creator.did}/lists/${parseAddressedAtUri(list.uri).rkey}`);
22
+
const href = $derived(`${base}/${creator.did}/lists/${assertCanonicalResourceUri(list.uri).rkey}`);
23
23
</script>
24
24
25
25
<div class="list-item">
+1
-1
src/lib/components/profiles/profile-item.svelte
+1
-1
src/lib/components/profiles/profile-item.svelte
+4
-4
src/lib/components/starterpacks/starterpack-item.svelte
+4
-4
src/lib/components/starterpacks/starterpack-item.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyGraphDefs, AppBskyGraphStarterpack } from '@atcute/client/lexicons';
2
+
import type { AppBskyGraphDefs, AppBskyGraphStarterpack } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
8
8
import { trimRichText } from '$lib/utils/bluesky/richtext';
9
9
import { truncateMiddle } from '$lib/utils/strings';
···
18
18
19
19
const creator = $derived(pack.creator);
20
20
21
-
const record = $derived(pack.record as AppBskyGraphStarterpack.Record);
22
-
const href = $derived(`${base}/${creator.did}/packs/${parseAddressedAtUri(pack.uri).rkey}`);
21
+
const record = $derived(pack.record as AppBskyGraphStarterpack.Main);
22
+
const href = $derived(`${base}/${creator.did}/packs/${assertCanonicalResourceUri(pack.uri).rkey}`);
23
23
</script>
24
24
25
25
<div class="starterpack-item">
+4
-4
src/lib/components/timeline/post-feed-item.svelte
+4
-4
src/lib/components/timeline/post-feed-item.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedPost } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedPost } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
6
import type { UiTimelineItem } from '$lib/models/timeline';
7
7
import { findLabel, FlagsBlurContent, FlagsBlurMedia } from '$lib/moderation';
8
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
8
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
9
9
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
10
10
11
11
import ArrowsRepeatRightLeftOutlined from '$lib/components/central-icons/arrows-repeat-right-left-outlined.svelte';
···
29
29
const author = $derived(post.author);
30
30
const authorUrl = $derived(`${base}/${author.did}`);
31
31
32
-
const record = $derived(post.record as AppBskyFeedPost.Record);
33
-
const postUrl = $derived(`${base}/${author.did}/${parseAddressedAtUri(post.uri).rkey}#main`);
32
+
const record = $derived(post.record as AppBskyFeedPost.Main);
33
+
const postUrl = $derived(`${base}/${author.did}/${assertCanonicalResourceUri(post.uri).rkey}#main`);
34
34
35
35
const isAviBlurred = $derived(!!findLabel(author.labels, author.did, FlagsBlurMedia));
36
36
const blur = $derived(findLabel(post.labels, author.did, FlagsBlurContent));
+2
-2
src/lib/components/timeline/post-meta.svelte
+2
-2
src/lib/components/timeline/post-meta.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs, AppBskyFeedPost } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs, AppBskyFeedPost } from '@atcute/bluesky';
3
3
4
4
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
5
5
···
17
17
const author = $derived(post.author);
18
18
const authorName = $derived(normalizeDisplayName(author.displayName ?? ''));
19
19
20
-
const createdAt = $derived((post.record as AppBskyFeedPost.Record).createdAt);
20
+
const createdAt = $derived((post.record as AppBskyFeedPost.Main).createdAt);
21
21
</script>
22
22
23
23
<div class={['post-meta', gutterBottom && 'has-bottom-gutter']}>
+1
-1
src/lib/components/timeline/post-metrics.svelte
+1
-1
src/lib/components/timeline/post-metrics.svelte
+2
-2
src/lib/constants.ts
+2
-2
src/lib/constants.ts
···
1
-
import type { At } from '@atcute/client/lexicons';
1
+
import type { CanonicalResourceUri } from '@atcute/lexicons';
2
2
3
3
// Popular feeds that requires authentication to view
4
-
export const AUTHENTICATED_FEEDS: At.CanonicalResourceUri[] = [
4
+
export const AUTHENTICATED_FEEDS: CanonicalResourceUri[] = [
5
5
// "Popular With Friends" by @bsky.app
6
6
`at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/with-friends`,
7
7
// "Mutuals" by @skyfeed.xyz
+1
-1
src/lib/models/timeline.ts
+1
-1
src/lib/models/timeline.ts
+3
-2
src/lib/moderation.ts
+3
-2
src/lib/moderation.ts
···
1
-
import type { At, ComAtprotoLabelDefs } from '@atcute/client/lexicons';
1
+
import type { ComAtprotoLabelDefs } from '@atcute/atproto';
2
+
import type { Did } from '@atcute/lexicons';
2
3
3
4
export const FlagsNone = 0;
4
5
···
123
124
124
125
export const findLabel = (
125
126
labels: Label[] | undefined,
126
-
authorDid: At.Did,
127
+
authorDid: Did,
127
128
mask: number,
128
129
): LabelDefinition | undefined => {
129
130
if (labels?.length) {
+2
-2
src/lib/queries/constellation.ts
+2
-2
src/lib/queries/constellation.ts
···
1
1
import { error } from '@sveltejs/kit';
2
2
3
-
import type { Records } from '@atcute/client/lexicons';
3
+
import type { Did } from '@atcute/lexicons';
4
+
import type { Records } from '@atcute/lexicons/ambient';
4
5
5
6
import * as v from '@badrap/valita';
6
7
7
8
import { PUBLIC_APP_USER_AGENT, PUBLIC_CONSTELLATION_URL } from '$env/static/public';
8
9
9
-
import type { Did } from '$lib/types/identity';
10
10
import { didString, integer, nsidString, recordKeyString } from '$lib/types/valita';
11
11
12
12
const linkResponse = v.object({
+9
-10
src/lib/queries/handle.ts
+9
-10
src/lib/queries/handle.ts
···
1
-
import type { XRPC } from '@atcute/client';
2
-
import type { At } from '@atcute/client/lexicons';
1
+
import { ok, type Client } from '@atcute/client';
2
+
import type { Did, Handle } from '@atcute/lexicons';
3
3
4
-
import type { Did } from '$lib/types/identity';
4
+
export const resolveHandle = async ({ client, handle }: { client: Client; handle: Handle }): Promise<Did> => {
5
+
const data = await ok(
6
+
client.get('com.atproto.identity.resolveHandle', {
7
+
params: { handle },
8
+
}),
9
+
);
5
10
6
-
export const resolveHandle = async ({ rpc, handle }: { rpc: XRPC; handle: At.Handle }): Promise<Did> => {
7
-
const { data } = await rpc.get('com.atproto.identity.resolveHandle', {
8
-
params: { handle },
9
-
});
10
-
11
-
// because my types are stricter than atcute's
12
-
return data.did as Did;
11
+
return data.did;
13
12
};
+23
-11
src/lib/queries/post.ts
+23
-11
src/lib/queries/post.ts
···
1
-
import { XRPC, XRPCError } from '@atcute/client';
2
-
import type { AppBskyFeedDefs, At } from '@atcute/client/lexicons';
1
+
import type { AppBskyFeedDefs } from '@atcute/bluesky';
2
+
import { type Client, ClientResponseError, ok } from '@atcute/client';
3
+
import type { ResourceUri } from '@atcute/lexicons';
3
4
4
5
export interface GetPostReturn {
5
6
post: AppBskyFeedDefs.PostView;
6
7
threadgate?: AppBskyFeedDefs.ThreadgateView;
7
8
}
8
9
9
-
export const getPost = async ({ rpc, uri }: { rpc: XRPC; uri: At.ResourceUri }): Promise<GetPostReturn> => {
10
-
const { data } = await rpc.get('app.bsky.feed.getPostThread', {
11
-
params: {
12
-
uri: uri,
13
-
depth: 0,
14
-
parentHeight: 0,
15
-
},
16
-
});
10
+
export const getPost = async ({
11
+
client,
12
+
uri,
13
+
}: {
14
+
client: Client;
15
+
uri: ResourceUri;
16
+
}): Promise<GetPostReturn> => {
17
+
const data = await ok(
18
+
client.get('app.bsky.feed.getPostThread', {
19
+
params: {
20
+
uri: uri,
21
+
depth: 0,
22
+
parentHeight: 0,
23
+
},
24
+
}),
25
+
);
17
26
18
27
const { thread, threadgate } = data;
19
28
switch (thread.$type) {
20
29
case 'app.bsky.feed.defs#notFoundPost':
21
30
case 'app.bsky.feed.defs#blockedPost': {
22
-
throw new XRPCError(400, { kind: 'NotFound', description: 'Post not found' });
31
+
throw new ClientResponseError({
32
+
status: 400,
33
+
data: { error: 'NotFound', message: `Post not found` },
34
+
});
23
35
}
24
36
}
25
37
+42
-36
src/lib/queries/timeline.ts
+42
-36
src/lib/queries/timeline.ts
···
1
-
import type { XRPC } from '@atcute/client';
2
-
import type { AppBskyActorDefs, AppBskyFeedDefs, AppBskyFeedGetTimeline, At } from '@atcute/client/lexicons';
1
+
import type { AppBskyActorDefs, AppBskyFeedDefs, AppBskyFeedGetTimeline } from '@atcute/bluesky';
2
+
import { type Client, ok } from '@atcute/client';
3
3
4
4
import {
5
5
buildTimelineSlices,
···
10
10
type TimelineSlice,
11
11
type UiTimelineItem,
12
12
} from '$lib/models/timeline';
13
-
import type { Did } from '$lib/types/identity';
14
13
import { assertNever } from '$lib/utils/invariant';
14
+
import type { Did, ResourceUri } from '@atcute/lexicons';
15
15
16
16
export const enum TimelineType {
17
17
PROFILE,
···
35
35
36
36
export interface CustomFeedTimelineParams {
37
37
type: TimelineType.CUSTOM_FEED;
38
-
feed: At.ResourceUri;
38
+
feed: ResourceUri;
39
39
cursor?: string;
40
40
}
41
41
42
42
export interface UserListTimelineParams {
43
43
type: TimelineType.USER_LIST;
44
-
list: At.ResourceUri;
44
+
list: ResourceUri;
45
45
cursor?: string;
46
46
}
47
47
···
55
55
const PAGE_LIMIT = 50;
56
56
57
57
export const fetchTimeline = async ({
58
-
rpc,
58
+
client,
59
59
params,
60
60
}: {
61
-
rpc: XRPC;
61
+
client: Client;
62
62
params: TimelineParams;
63
63
}): Promise<TimelinePage> => {
64
64
let sliceFilter: SliceFilter | undefined;
65
65
let postFilter: PostFilter | undefined;
66
66
67
-
let timeline: AppBskyFeedGetTimeline.Output;
67
+
let timeline: AppBskyFeedGetTimeline.$output;
68
68
69
69
switch (params.type) {
70
70
case TimelineType.PROFILE: {
71
-
const { data } = await rpc.get('app.bsky.feed.getAuthorFeed', {
72
-
params: {
73
-
actor: params.actor,
74
-
cursor: params.cursor,
75
-
limit: PAGE_LIMIT,
76
-
includePins: params.pinned ?? params.filter !== ProfileFilter.MEDIA,
77
-
filter:
78
-
params.filter === ProfileFilter.MEDIA
79
-
? 'posts_with_media'
80
-
: params.filter === ProfileFilter.POSTS_WITH_REPLIES
81
-
? 'posts_with_replies'
82
-
: 'posts_and_author_threads',
83
-
},
84
-
});
71
+
const data = await ok(
72
+
client.get('app.bsky.feed.getAuthorFeed', {
73
+
params: {
74
+
actor: params.actor,
75
+
cursor: params.cursor,
76
+
limit: PAGE_LIMIT,
77
+
includePins: params.pinned ?? params.filter !== ProfileFilter.MEDIA,
78
+
filter:
79
+
params.filter === ProfileFilter.MEDIA
80
+
? 'posts_with_media'
81
+
: params.filter === ProfileFilter.POSTS_WITH_REPLIES
82
+
? 'posts_with_replies'
83
+
: 'posts_and_author_threads',
84
+
},
85
+
}),
86
+
);
85
87
86
88
timeline = data;
87
89
···
92
94
break;
93
95
}
94
96
case TimelineType.CUSTOM_FEED: {
95
-
const { data } = await rpc.get('app.bsky.feed.getFeed', {
96
-
params: {
97
-
feed: params.feed,
98
-
cursor: params.cursor,
99
-
limit: PAGE_LIMIT,
100
-
},
101
-
});
97
+
const data = await ok(
98
+
client.get('app.bsky.feed.getFeed', {
99
+
params: {
100
+
feed: params.feed,
101
+
cursor: params.cursor,
102
+
limit: PAGE_LIMIT,
103
+
},
104
+
}),
105
+
);
102
106
103
107
timeline = {
104
108
// Discover feed, wooo.
···
110
114
break;
111
115
}
112
116
case TimelineType.USER_LIST: {
113
-
const { data } = await rpc.get('app.bsky.feed.getListFeed', {
114
-
params: {
115
-
list: params.list,
116
-
cursor: params.cursor,
117
-
limit: PAGE_LIMIT,
118
-
},
119
-
});
117
+
const data = await ok(
118
+
client.get('app.bsky.feed.getListFeed', {
119
+
params: {
120
+
list: params.list,
121
+
cursor: params.cursor,
122
+
limit: PAGE_LIMIT,
123
+
},
124
+
}),
125
+
);
120
126
121
127
timeline = data;
122
128
break;
+6
-7
src/lib/redirector.ts
+6
-7
src/lib/redirector.ts
···
1
1
import { base } from '$app/paths';
2
-
import { type PartialAtUri, parsePartialAtUri } from './types/at-uri';
2
+
3
+
import { isDid, isHandle, isRecordKey, isTid, parseResourceUri } from '@atcute/lexicons/syntax';
3
4
4
-
import { isDid, isHandle } from './types/identity';
5
-
import { isRecordKey, isTid } from './types/rkey';
6
5
import {
7
6
BSKY_FEED_LINK_RE,
8
7
BSKY_GO_SHORTLINK_RE,
···
206
205
};
207
206
208
207
export const redirectAtUri = (raw: string): RedirectResult => {
209
-
let uri: PartialAtUri;
210
-
try {
211
-
uri = parsePartialAtUri(raw);
212
-
} catch (e) {
208
+
const result = parseResourceUri(raw);
209
+
if (!result.ok) {
213
210
return;
214
211
}
212
+
213
+
const uri = result.value;
215
214
216
215
if (uri.rkey) {
217
216
switch (uri.collection) {
+16
-9
src/lib/rss.ts
+16
-9
src/lib/rss.ts
···
1
+
import {
2
+
unwrapEmbed,
3
+
type AppBskyFeedDefs,
4
+
type AppBskyFeedPost,
5
+
type AppBskyRichtextFacet,
6
+
} from '@atcute/bluesky';
1
7
import { segmentize } from '@atcute/bluesky-richtext-segmenter';
2
-
import type { AppBskyFeedDefs, AppBskyFeedPost, AppBskyRichtextFacet } from '@atcute/client/lexicons';
3
8
4
9
import { PUBLIC_APP_URL } from '$env/static/public';
5
10
6
11
import { findLabel, FlagsBlurMedia } from './moderation';
7
-
import { parseAddressedAtUri } from './types/at-uri';
8
-
import { getQuoteEmbedView, unwrapEmbedView } from './utils/bluesky/embeds';
12
+
import { assertCanonicalResourceUri } from './types/at-uri';
13
+
import { getQuoteEmbed } from './utils/bluesky/embeds';
9
14
import { assertNever } from './utils/invariant';
10
15
import type { UnwrapArray } from './utils/types';
11
16
···
181
186
const post = item.post;
182
187
const author = post.author;
183
188
184
-
const record = post.record as AppBskyFeedPost.Record;
189
+
const record = post.record as AppBskyFeedPost.Main;
185
190
186
-
const { media, record: recordEmbed } = unwrapEmbedView(post.embed);
187
-
const quote = getQuoteEmbedView(recordEmbed);
191
+
const { media, record: recordEmbed } = unwrapEmbed(post.embed);
192
+
const quote = getQuoteEmbed(recordEmbed);
188
193
189
194
const shouldBlurMedia = !!findLabel(post.labels, author.did, FlagsBlurMedia);
190
195
···
195
200
switch (quote.$type) {
196
201
case 'app.bsky.embed.record#viewRecord': {
197
202
const author = quote.author;
198
-
const record = quote.value as AppBskyFeedPost.Record;
203
+
const record = quote.value as AppBskyFeedPost.Main;
199
204
200
-
const postUrl = `${PUBLIC_APP_URL}/${author.did}/${parseAddressedAtUri(quote.uri).rkey}`;
205
+
const uri = assertCanonicalResourceUri(quote.uri);
206
+
207
+
const postUrl = `${PUBLIC_APP_URL}/${author.did}/${uri.rkey}`;
201
208
202
209
html += `<blockquote>`;
203
210
html += `<b><a href="${escapeAttribute(postUrl)}">`;
···
225
232
226
233
return {
227
234
id: `${post.uri}|${post.cid}`,
228
-
url: `${PUBLIC_APP_URL}/${author.did}/${parseAddressedAtUri(post.uri).rkey}`,
235
+
url: `${PUBLIC_APP_URL}/${author.did}/${assertCanonicalResourceUri(post.uri).rkey}`,
229
236
date: new Date(post.indexedAt),
230
237
description: { html },
231
238
images:
+19
-55
src/lib/types/at-uri.ts
+19
-55
src/lib/types/at-uri.ts
···
1
-
import type { At, Records } from '@atcute/client/lexicons';
1
+
import {
2
+
parseCanonicalResourceUri,
3
+
type Did,
4
+
type Handle,
5
+
type Nsid,
6
+
type ParsedCanonicalResourceUri,
7
+
type ResourceUri,
8
+
} from '@atcute/lexicons';
9
+
import type { Records } from '@atcute/lexicons/ambient';
2
10
3
11
import { assert } from '$lib/utils/invariant';
4
12
5
-
import { isDid, isHandle, type Did, type Handle } from './identity';
6
-
import { isNsid, type Nsid } from './nsid';
7
-
import { isRecordKey, type RecordKey } from './rkey';
8
-
9
-
const ATURI_RE =
10
-
/^at:\/\/([a-zA-Z0-9._:%-]+)(?:\/([a-zA-Z0-9-.]+)(?:\/([a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(?:#(\/[a-zA-Z0-9._~:@!$&%')(*+,;=\-[\]/\\]*))?$/;
11
-
12
-
export type AddressedAtUri = {
13
-
repo: Did;
14
-
collection: Nsid;
15
-
rkey: RecordKey;
16
-
fragment: string | undefined;
17
-
};
18
-
19
-
export const parseAddressedAtUri = (str: string): AddressedAtUri => {
20
-
const match = ATURI_RE.exec(str);
21
-
assert(match !== null, `invalid addressed-at-uri: ${str}`);
22
-
23
-
const [, r, c, k, f] = match;
24
-
assert(isDid(r), `invalid repo in addressed-at-uri: ${r}`);
25
-
assert(isNsid(c), `invalid collection in addressed-at-uri: ${c}`);
26
-
assert(isRecordKey(k), `invalid rkey in addressed-at-uri: ${k}`);
27
-
28
-
return {
29
-
repo: r,
30
-
collection: c,
31
-
rkey: k,
32
-
fragment: f,
33
-
};
34
-
};
35
-
36
-
export type PartialAtUri =
37
-
| { repo: Did | Handle; collection: undefined; rkey: undefined; fragment: string | undefined }
38
-
| { repo: Did | Handle; collection: Nsid; rkey: undefined; fragment: string | undefined }
39
-
| { repo: Did | Handle; collection: Nsid; rkey: RecordKey; fragment: string | undefined };
40
-
41
-
export const parsePartialAtUri = (str: string): PartialAtUri => {
42
-
const match = ATURI_RE.exec(str);
43
-
assert(match !== null, `invalid partial-at-uri: ${str}`);
44
-
45
-
const [, r, c, k, f] = match;
46
-
assert(isDid(r) || isHandle(r), `invalid repo in partial-at-uri: ${r}`);
47
-
assert(c === undefined || isNsid(c), `invalid collection in partial-at-uri: ${c}`);
48
-
assert(k === undefined || isRecordKey(k), `invalid rkey in partial-at-uri: ${k}`);
49
-
50
-
return {
51
-
repo: r,
52
-
collection: c,
53
-
rkey: k,
54
-
fragment: f,
55
-
};
56
-
};
57
-
58
13
export const makeAtUri = (
59
14
repo: Did | Handle,
60
15
collection: keyof Records | (Nsid & {}),
61
16
rkey: string,
62
-
): At.ResourceUri => {
17
+
): ResourceUri => {
63
18
return `at://${repo}/${collection as Nsid}/${rkey}`;
64
19
};
20
+
21
+
export const assertCanonicalResourceUri = (input: string): ParsedCanonicalResourceUri => {
22
+
const result = parseCanonicalResourceUri(input);
23
+
if (!result.ok) {
24
+
assert(false, result.error);
25
+
}
26
+
27
+
return result.value;
28
+
};
-34
src/lib/types/identity.ts
-34
src/lib/types/identity.ts
···
1
-
export type Handle = `${string}.${string}`;
2
-
3
-
const HANDLE_RE =
4
-
/^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+([a-zA-Z][a-zA-Z0-9-]{0,61}[a-zA-Z])$/;
5
-
6
-
export const isHandle = (input: unknown): input is Handle => {
7
-
return typeof input === 'string' && input.length >= 3 && input.length <= 253 && HANDLE_RE.test(input);
8
-
};
9
-
10
-
export type Did<TMethod extends string = string> = `did:${TMethod}:${string}`;
11
-
export type AtprotoDid = Did<'plc' | 'web'>;
12
-
13
-
const DID_RE = /^did:([a-z]+):([a-zA-Z0-9._:%\-]*[a-zA-Z0-9._\-])$/;
14
-
15
-
export const isDid = (input: unknown): input is Did => {
16
-
return typeof input === 'string' && input.length >= 7 && input.length <= 2048 && DID_RE.test(input);
17
-
};
18
-
19
-
const ATPROTO_WEB_DID_RE =
20
-
/^did:web:([a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(?:\.[a-zA-Z]{2,})|localhost(?:%3[aA]\d+)?)$/;
21
-
22
-
export const isAtprotoWebDid = (input: unknown): input is Did<'web'> => {
23
-
return typeof input === 'string' && input.length >= 12 && ATPROTO_WEB_DID_RE.test(input);
24
-
};
25
-
26
-
const PLC_DID_RE = /^did:plc:([a-z2-7]{24})$/;
27
-
28
-
export const isPlcDid = (input: unknown): input is Did<'plc'> => {
29
-
return typeof input === 'string' && input.length === 32 && PLC_DID_RE.test(input);
30
-
};
31
-
32
-
export const isAtprotoDid = (input: unknown): input is AtprotoDid => {
33
-
return isPlcDid(input) || isAtprotoWebDid(input);
34
-
};
-8
src/lib/types/nsid.ts
-8
src/lib/types/nsid.ts
···
1
-
export type Nsid = `${string}.${string}.${string}`;
2
-
3
-
const NSID_RE =
4
-
/^[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?:\.[a-zA-Z](?:[a-zA-Z0-9]{0,62})?)$/;
5
-
6
-
export const isNsid = (input: unknown): input is Nsid => {
7
-
return typeof input === 'string' && input.length >= 5 && input.length <= 317 && NSID_RE.test(input);
8
-
};
-13
src/lib/types/rkey.ts
-13
src/lib/types/rkey.ts
···
1
-
const RECORD_KEY_RE = /^(?!\.{1,2}$)[a-zA-Z0-9_~.:-]{1,512}$/;
2
-
3
-
export type RecordKey = string;
4
-
5
-
export const isRecordKey = (input: unknown): input is RecordKey => {
6
-
return typeof input === 'string' && input.length >= 1 && input.length <= 512 && RECORD_KEY_RE.test(input);
7
-
};
8
-
9
-
const TID_RE = /^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/;
10
-
11
-
export const isTid = (input: string) => {
12
-
return input.length === 13 && TID_RE.test(input);
13
-
};
+2
-4
src/lib/types/valita.ts
+2
-4
src/lib/types/valita.ts
···
1
-
import * as v from '@badrap/valita';
1
+
import { isDid, isNsid, isRecordKey } from '@atcute/lexicons/syntax';
2
2
3
-
import { isDid } from './identity';
4
-
import { isNsid } from './nsid';
5
-
import { isRecordKey } from './rkey';
3
+
import * as v from '@badrap/valita';
6
4
7
5
export const didString = v.string().assert(isDid);
8
6
+11
-45
src/lib/utils/bluesky/embeds.ts
+11
-45
src/lib/utils/bluesky/embeds.ts
···
1
-
import type { AppBskyEmbedRecordWithMedia, AppBskyFeedDefs } from '@atcute/client/lexicons';
2
-
3
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
4
-
5
-
export interface Embed {
6
-
media?: AppBskyEmbedRecordWithMedia.View['media'];
7
-
record?: AppBskyEmbedRecordWithMedia.View['record'];
8
-
}
9
-
10
-
export type MediaEmbed = NonNullable<Embed['media']>;
11
-
export type RecordEmbed = NonNullable<Embed['record']>;
12
-
13
-
export const unwrapMediaEmbedView = (embed: AppBskyFeedDefs.PostView['embed']): Embed['media'] => {
14
-
switch (embed?.$type) {
15
-
case 'app.bsky.embed.recordWithMedia#view':
16
-
return embed.media;
17
-
case 'app.bsky.embed.record#view':
18
-
return;
19
-
}
20
-
21
-
return embed;
22
-
};
1
+
import type { RecordEmbed } from '@atcute/bluesky';
2
+
import { parseCanonicalResourceUri } from '@atcute/lexicons';
23
3
24
-
export const unwrapRecordEmbedView = (embed: AppBskyFeedDefs.PostView['embed']): Embed['record'] => {
4
+
export const getQuoteEmbed = (embed: RecordEmbed | undefined) => {
25
5
switch (embed?.$type) {
26
-
case 'app.bsky.embed.recordWithMedia#view':
27
-
return embed.record;
28
-
29
-
case 'app.bsky.embed.record#view':
30
-
return embed;
31
-
}
32
-
};
33
-
34
-
export const unwrapEmbedView = (embed: AppBskyFeedDefs.PostView['embed']): Embed => {
35
-
return {
36
-
media: unwrapMediaEmbedView(embed),
37
-
record: unwrapRecordEmbedView(embed),
38
-
};
39
-
};
40
-
41
-
export const getQuoteEmbedView = (embed: RecordEmbed | undefined) => {
42
-
const record = embed?.record;
43
-
44
-
switch (record?.$type) {
45
6
case 'app.bsky.embed.record#viewRecord': {
46
-
return record;
7
+
return embed;
47
8
}
48
9
49
10
case 'app.bsky.embed.record#viewNotFound':
50
11
case 'app.bsky.embed.record#viewDetached':
51
12
case 'app.bsky.embed.record#viewBlocked': {
52
-
const uri = parseAddressedAtUri(record.uri);
13
+
const result = parseCanonicalResourceUri(embed.uri);
14
+
if (!result.ok) {
15
+
return;
16
+
}
17
+
18
+
const uri = result.value;
53
19
if (uri.collection === 'app.bsky.feed.post') {
54
-
return record;
20
+
return embed;
55
21
}
56
22
}
57
23
}
+1
-1
src/lib/utils/bluesky/lists.ts
+1
-1
src/lib/utils/bluesky/lists.ts
+1
-1
src/params/did.ts
+1
-1
src/params/did.ts
+2
-4
src/params/didOrHandle.ts
+2
-4
src/params/didOrHandle.ts
···
1
1
import type { ParamMatcher } from '@sveltejs/kit';
2
2
3
-
import { isDid, isHandle, type Did, type Handle } from '$lib/types/identity';
3
+
import { isActorIdentifier } from '@atcute/lexicons/syntax';
4
4
5
-
export const match = ((param: string): param is Did | Handle => {
6
-
return isDid(param) || isHandle(param);
7
-
}) satisfies ParamMatcher;
5
+
export const match = isActorIdentifier satisfies ParamMatcher;
+1
-1
src/params/handle.ts
+1
-1
src/params/handle.ts
+1
-1
src/params/rkey.ts
+1
-1
src/params/rkey.ts
+1
-1
src/params/tid.ts
+1
-1
src/params/tid.ts
+4
-4
src/routes/(app)/(profile)/[actor=didOrHandle]/(timeline)/+page.ts
+4
-4
src/routes/(app)/(profile)/[actor=didOrHandle]/(timeline)/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, simpleFetchHandler } from '@atcute/client';
2
+
import { isDid, type Did } from '@atcute/lexicons/syntax';
2
3
3
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
5
import type { PageLoad } from './$types';
5
6
6
7
import { fetchTimeline, ProfileFilter, TimelineType } from '$lib/queries/timeline';
7
-
import { isDid, type Did } from '$lib/types/identity';
8
8
9
9
export const load: PageLoad = async ({ url, params, fetch, parent }) => {
10
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
11
12
12
let did: Did;
13
13
if (isDid(params.actor)) {
···
18
18
}
19
19
20
20
const timeline = await fetchTimeline({
21
-
rpc,
21
+
client,
22
22
params: {
23
23
type: TimelineType.PROFILE,
24
24
actor: did,
+6
-6
src/routes/(app)/(profile)/[actor=didOrHandle]/(timeline)/media/+page.ts
+6
-6
src/routes/(app)/(profile)/[actor=didOrHandle]/(timeline)/media/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, simpleFetchHandler } from '@atcute/client';
2
+
import { isDid, type Did } from '@atcute/lexicons/syntax';
2
3
3
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
-
import { fetchTimeline, ProfileFilter, TimelineType } from '$lib/queries/timeline';
5
-
import { isDid, type Did } from '$lib/types/identity';
6
-
7
5
import type { PageLoad } from './$types';
8
6
7
+
import { fetchTimeline, ProfileFilter, TimelineType } from '$lib/queries/timeline';
8
+
9
9
export const load: PageLoad = async ({ url, params, fetch, parent }) => {
10
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
11
12
12
let did: Did;
13
13
if (isDid(params.actor)) {
···
18
18
}
19
19
20
20
const timeline = await fetchTimeline({
21
-
rpc,
21
+
client,
22
22
params: {
23
23
type: TimelineType.PROFILE,
24
24
actor: did,
+20
-16
src/routes/(app)/(profile)/[actor=didOrHandle]/(timeline)/rss/+server.ts
+20
-16
src/routes/(app)/(profile)/[actor=didOrHandle]/(timeline)/rss/+server.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
2
-
import type { AppBskyActorDefs } from '@atcute/client/lexicons';
1
+
import type { AppBskyActorDefs } from '@atcute/bluesky';
2
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
3
3
4
4
import { PUBLIC_APP_URL, PUBLIC_APPVIEW_URL } from '$env/static/public';
5
5
import type { RequestHandler } from './$types';
···
9
9
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
10
10
11
11
export const GET: RequestHandler = async ({ params, fetch }) => {
12
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
12
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
13
13
14
14
const [profile, timeline] = await Promise.all([
15
15
(async () => {
16
-
const { data } = await rpc.get('app.bsky.actor.getProfile', {
17
-
params: {
18
-
actor: params.actor,
19
-
},
20
-
});
16
+
const data = await ok(
17
+
client.get('app.bsky.actor.getProfile', {
18
+
params: {
19
+
actor: params.actor,
20
+
},
21
+
}),
22
+
);
21
23
22
24
return data;
23
25
})(),
24
26
25
27
(async () => {
26
-
const { data } = await rpc.get('app.bsky.feed.getAuthorFeed', {
27
-
params: {
28
-
actor: params.actor,
29
-
limit: 100,
30
-
filter: 'posts_and_author_threads',
31
-
includePins: false,
32
-
},
33
-
});
28
+
const data = await ok(
29
+
client.get('app.bsky.feed.getAuthorFeed', {
30
+
params: {
31
+
actor: params.actor,
32
+
limit: 100,
33
+
filter: 'posts_and_author_threads',
34
+
includePins: false,
35
+
},
36
+
}),
37
+
);
34
38
35
39
// Build into slices so we can filter out non-self threads
36
40
const slices = buildTimelineSlices(
+6
-6
src/routes/(app)/(profile)/[actor=didOrHandle]/(timeline)/with_replies/+page.ts
+6
-6
src/routes/(app)/(profile)/[actor=didOrHandle]/(timeline)/with_replies/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, simpleFetchHandler } from '@atcute/client';
2
+
import { isDid, type Did } from '@atcute/lexicons/syntax';
2
3
3
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
-
import { fetchTimeline, ProfileFilter, TimelineType } from '$lib/queries/timeline';
5
-
import { isDid, type Did } from '$lib/types/identity';
6
-
7
5
import type { PageLoad } from './$types';
8
6
7
+
import { fetchTimeline, ProfileFilter, TimelineType } from '$lib/queries/timeline';
8
+
9
9
export const load: PageLoad = async ({ url, params, fetch, parent }) => {
10
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
11
12
12
let did: Did;
13
13
if (isDid(params.actor)) {
···
18
18
}
19
19
20
20
const timeline = await fetchTimeline({
21
-
rpc,
21
+
client,
22
22
params: {
23
23
type: TimelineType.PROFILE,
24
24
actor: did,
+21
-24
src/routes/(app)/(profile)/[actor=didOrHandle]/+layout.ts
+21
-24
src/routes/(app)/(profile)/[actor=didOrHandle]/+layout.ts
···
1
-
import { XRPC, XRPCError, simpleFetchHandler } from '@atcute/client';
1
+
import { Client, ClientResponseError, simpleFetchHandler } from '@atcute/client';
2
2
import { error } from '@sveltejs/kit';
3
3
4
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
···
6
6
import type { LayoutLoad } from './$types';
7
7
8
8
export const load: LayoutLoad = async ({ params, fetch }) => {
9
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
9
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
10
11
-
try {
12
-
const { data } = await rpc.get('app.bsky.actor.getProfile', {
13
-
params: {
14
-
actor: params.actor,
15
-
},
16
-
});
11
+
const response = await client.get('app.bsky.actor.getProfile', {
12
+
params: {
13
+
actor: params.actor,
14
+
},
15
+
});
17
16
18
-
return {
19
-
profile: data,
20
-
};
21
-
} catch (err) {
22
-
if (err instanceof XRPCError) {
23
-
switch (err.kind) {
24
-
case 'InvalidRequest': {
25
-
error(404, `Account doesn't exist`);
26
-
}
27
-
case 'AccountTakedown': {
28
-
error(404, `Account is taken down`);
29
-
}
30
-
case 'AccountDeactivated': {
31
-
error(404, `Account is deactivated`);
32
-
}
17
+
if (!response.ok) {
18
+
const err = response.data;
19
+
switch (err.error) {
20
+
case 'InvalidRequest': {
21
+
error(404, `Account doesn't exist`);
22
+
}
23
+
case 'AccountTakedown': {
24
+
error(404, `Account is taken down`);
25
+
}
26
+
case 'AccountDeactivated': {
27
+
error(404, `Account is deactivated`);
33
28
}
34
29
}
35
30
36
-
throw err;
31
+
throw new ClientResponseError(response);
37
32
}
33
+
34
+
return { profile: response.data };
38
35
};
+1
-1
src/routes/(app)/(profile)/[actor=didOrHandle]/components/profile-aside.svelte
+1
-1
src/routes/(app)/(profile)/[actor=didOrHandle]/components/profile-aside.svelte
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/feeds/+page.ts
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/feeds/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
5
5
6
6
export const load: PageLoad = async ({ url, params, fetch }) => {
7
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
7
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
8
8
9
-
const { data } = await rpc.get('app.bsky.feed.getActorFeeds', {
10
-
params: {
11
-
actor: params.actor,
12
-
limit: 50,
13
-
cursor: url.searchParams.get('cursor') || undefined,
14
-
},
15
-
});
9
+
const data = await ok(
10
+
client.get('app.bsky.feed.getActorFeeds', {
11
+
params: {
12
+
actor: params.actor,
13
+
limit: 50,
14
+
cursor: url.searchParams.get('cursor') || undefined,
15
+
},
16
+
}),
17
+
);
16
18
17
19
return { feeds: { cursor: data.cursor, items: data.feeds } };
18
20
};
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/followers/+page.ts
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/followers/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
5
5
6
6
export const load: PageLoad = async ({ url, params, fetch }) => {
7
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
7
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
8
8
9
-
const { data } = await rpc.get('app.bsky.graph.getFollowers', {
10
-
params: {
11
-
actor: params.actor,
12
-
limit: 50,
13
-
cursor: url.searchParams.get('cursor') || undefined,
14
-
},
15
-
});
9
+
const data = await ok(
10
+
client.get('app.bsky.graph.getFollowers', {
11
+
params: {
12
+
actor: params.actor,
13
+
limit: 50,
14
+
cursor: url.searchParams.get('cursor') || undefined,
15
+
},
16
+
}),
17
+
);
16
18
17
19
return { followers: { cursor: data.cursor, items: data.followers } };
18
20
};
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/following/+page.ts
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/following/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
5
5
6
6
export const load: PageLoad = async ({ url, params, fetch }) => {
7
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
7
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
8
8
9
-
const { data } = await rpc.get('app.bsky.graph.getFollows', {
10
-
params: {
11
-
actor: params.actor,
12
-
limit: 50,
13
-
cursor: url.searchParams.get('cursor') || undefined,
14
-
},
15
-
});
9
+
const data = await ok(
10
+
client.get('app.bsky.graph.getFollows', {
11
+
params: {
12
+
actor: params.actor,
13
+
limit: 50,
14
+
cursor: url.searchParams.get('cursor') || undefined,
15
+
},
16
+
}),
17
+
);
16
18
17
19
return { following: { cursor: data.cursor, items: data.follows } };
18
20
};
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/lists/+page.ts
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/lists/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
5
5
6
6
export const load: PageLoad = async ({ url, params, fetch }) => {
7
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
7
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
8
8
9
-
const { data } = await rpc.get('app.bsky.graph.getLists', {
10
-
params: {
11
-
actor: params.actor,
12
-
limit: 50,
13
-
cursor: url.searchParams.get('cursor') || undefined,
14
-
},
15
-
});
9
+
const data = await ok(
10
+
client.get('app.bsky.graph.getLists', {
11
+
params: {
12
+
actor: params.actor,
13
+
limit: 50,
14
+
cursor: url.searchParams.get('cursor') || undefined,
15
+
},
16
+
}),
17
+
);
16
18
17
19
return { lists: { cursor: data.cursor, items: data.lists } };
18
20
};
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/packs/+page.ts
+11
-9
src/routes/(app)/(profile)/[actor=didOrHandle]/packs/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
5
5
6
6
export const load: PageLoad = async ({ url, params, fetch }) => {
7
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
7
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
8
8
9
-
const { data } = await rpc.get('app.bsky.graph.getActorStarterPacks', {
10
-
params: {
11
-
actor: params.actor,
12
-
limit: 50,
13
-
cursor: url.searchParams.get('cursor') || undefined,
14
-
},
15
-
});
9
+
const data = await ok(
10
+
client.get('app.bsky.graph.getActorStarterPacks', {
11
+
params: {
12
+
actor: params.actor,
13
+
limit: 50,
14
+
cursor: url.searchParams.get('cursor') || undefined,
15
+
},
16
+
}),
17
+
);
16
18
17
19
return { packs: { cursor: data.cursor, items: data.starterPacks } };
18
20
};
+7
-7
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/+page.svelte
+7
-7
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/+page.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedPost } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedPost } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
import { PUBLIC_APP_NAME } from '$env/static/public';
6
6
import type { PageProps } from './$types';
7
7
8
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
8
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
9
9
import { truncateMiddle, truncateRight } from '$lib/utils/strings';
10
10
11
11
import BlockedAscendantItem from './components/blocked-ascendant-item.svelte';
···
22
22
const { data }: PageProps = $props();
23
23
24
24
const main = $derived(data.thread.post);
25
-
const uri = $derived(parseAddressedAtUri(main.uri));
25
+
const uri = $derived(assertCanonicalResourceUri(main.uri));
26
26
27
27
const title = $derived.by(() => {
28
28
const author = `@${truncateMiddle(main.author.handle, 29)}`;
29
-
const content = truncateRight((main.record as AppBskyFeedPost.Record).text.trim(), 70);
29
+
const content = truncateRight((main.record as AppBskyFeedPost.Main).text.trim(), 70);
30
30
31
31
return `${author}: "${content}" — ${PUBLIC_APP_NAME}`;
32
32
});
···
52
52
{#if item.type === 'post'}
53
53
<PostAscendantItem {item} />
54
54
{:else if item.type === 'overflow'}
55
-
{@const uri = parseAddressedAtUri(item.uri)}
55
+
{@const uri = assertCanonicalResourceUri(item.uri)}
56
56
57
57
<OverflowAscendantItem postUrl="{base}/{uri.repo}/{uri.rkey}#main" />
58
58
{:else if item.type === 'blocked'}
59
-
{@const uri = parseAddressedAtUri(item.uri)}
59
+
{@const uri = assertCanonicalResourceUri(item.uri)}
60
60
61
61
<BlockedAscendantItem postUrl="{base}/{uri.repo}/{uri.rkey}#main" />
62
62
{:else if item.type === 'nonexistent'}
63
-
{@const uri = parseAddressedAtUri(item.uri)}
63
+
{@const uri = assertCanonicalResourceUri(item.uri)}
64
64
65
65
<NonexistentAscendantPost postUrl="{base}/{uri.repo}/{uri.rkey}#main" />
66
66
{/if}
+20
-19
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/+page.ts
+20
-19
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/+page.ts
···
1
-
import { simpleFetchHandler, XRPC, XRPCError } from '@atcute/client';
2
-
import type { AppBskyFeedGetPostThread } from '@atcute/client/lexicons';
1
+
import type { AppBskyFeedGetPostThread } from '@atcute/bluesky';
2
+
import { Client, ClientResponseError, ok, simpleFetchHandler } from '@atcute/client';
3
+
import { isDid, type Did } from '@atcute/lexicons/syntax';
4
+
3
5
import { error } from '@sveltejs/kit';
4
6
5
7
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
···
7
9
8
10
import { resolveHandle } from '$lib/queries/handle';
9
11
import { makeAtUri } from '$lib/types/at-uri';
10
-
import { isDid, type Did } from '$lib/types/identity';
11
12
12
13
export const load: PageLoad = async ({ params }) => {
13
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
14
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
14
15
15
16
let did: Did;
16
17
if (!isDid(params.actor)) {
17
18
try {
18
-
did = await resolveHandle({ rpc, handle: params.actor });
19
+
did = await resolveHandle({ client: client, handle: params.actor });
19
20
} catch (err) {
20
-
if (err instanceof XRPCError) {
21
-
switch (err.kind) {
21
+
if (err instanceof ClientResponseError) {
22
+
switch (err.error) {
22
23
case 'InvalidRequest': {
23
24
error(404, `Account doesn't exist`);
24
25
}
···
33
34
34
35
const uri = makeAtUri(did, 'app.bsky.feed.post', params.rkey);
35
36
36
-
let data: AppBskyFeedGetPostThread.Output;
37
+
let data: AppBskyFeedGetPostThread.$output;
37
38
38
39
try {
39
-
const response = await rpc.get('app.bsky.feed.getPostThread', {
40
-
params: {
41
-
uri: uri,
42
-
depth: 4,
43
-
parentHeight: 10,
44
-
},
45
-
});
46
-
47
-
data = response.data;
40
+
data = await ok(
41
+
client.get('app.bsky.feed.getPostThread', {
42
+
params: {
43
+
uri: uri,
44
+
depth: 4,
45
+
parentHeight: 10,
46
+
},
47
+
}),
48
+
);
48
49
} catch (err) {
49
-
if (err instanceof XRPCError) {
50
-
switch (err.kind) {
50
+
if (err instanceof ClientResponseError) {
51
+
switch (err.error) {
51
52
case 'NotFound': {
52
53
error(404, `Post not found`);
53
54
}
+6
-4
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/descendants.svelte
+6
-4
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/descendants.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs, AppBskyFeedThreadgate } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs, AppBskyFeedThreadgate } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
8
8
import { createReplyCollator } from '../utils';
9
9
···
17
17
18
18
const { thread: root, threadgate }: Props = $props();
19
19
20
-
const gate = $derived(threadgate?.record as AppBskyFeedThreadgate.Record | undefined);
20
+
const gate = $derived(threadgate?.record as AppBskyFeedThreadgate.Main | undefined);
21
21
const sort = $derived(createReplyCollator(threadgate));
22
22
</script>
23
23
···
59
59
</div>
60
60
{/if}
61
61
62
-
<OverflowDescendantItem postUrl="{base}/{post.author.did}/{parseAddressedAtUri(post.uri).rkey}#main" />
62
+
<OverflowDescendantItem
63
+
postUrl="{base}/{post.author.did}/{assertCanonicalResourceUri(post.uri).rkey}#main"
64
+
/>
63
65
{/if}
64
66
{/each}
65
67
{/snippet}
+5
-5
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/interaction-state.svelte
+5
-5
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/interaction-state.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs, AppBskyFeedThreadgate } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs, AppBskyFeedThreadgate } from '@atcute/bluesky';
3
3
4
4
import type { UnwrapArray } from '$lib/utils/types';
5
5
···
7
7
import Group_2Outlined from '$lib/components/central-icons/group-2-outlined.svelte';
8
8
import CircleBanSignOutlined from '$lib/components/central-icons/circle-ban-sign-outlined.svelte';
9
9
import { base } from '$app/paths';
10
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
10
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
11
11
12
12
interface Props {
13
13
threadgate: AppBskyFeedDefs.ThreadgateView | undefined;
14
14
}
15
15
16
-
type GateRecord = AppBskyFeedThreadgate.Record;
16
+
type GateRecord = AppBskyFeedThreadgate.Main;
17
17
type Allow = UnwrapArray<GateRecord['allow']>;
18
18
19
19
const { threadgate }: Props = $props();
20
20
21
21
const id = $props.id();
22
22
23
-
const record = $derived(threadgate?.record as AppBskyFeedThreadgate.Record | undefined);
23
+
const record = $derived(threadgate?.record as AppBskyFeedThreadgate.Main | undefined);
24
24
25
25
const allow = $derived.by(() => {
26
26
const order: Record<Allow['$type'], number> = {
···
99
99
{@const hydrated = threadgate!.lists?.find((list) => list.uri === rule.list)}
100
100
101
101
{#if hydrated}
102
-
{@const uri = parseAddressedAtUri(rule.list)}
102
+
{@const uri = assertCanonicalResourceUri(rule.list)}
103
103
104
104
<li>
105
105
Users in <a class="link" href="{base}/{uri.repo}/lists/{uri.rkey}">{hydrated.name}</a> list
+3
-3
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/main-post-metrics.svelte
+3
-3
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/main-post-metrics.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
import { formatCompactNumber } from '$lib/utils/intl/number';
8
8
9
9
interface Props {
···
12
12
13
13
const { post }: Props = $props();
14
14
15
-
const baseUrl = $derived(`${base}/${post.author.did}/${parseAddressedAtUri(post.uri).rkey}`);
15
+
const baseUrl = $derived(`${base}/${post.author.did}/${assertCanonicalResourceUri(post.uri).rkey}`);
16
16
</script>
17
17
18
18
{#snippet Stat(count: number | undefined, one: string, many: string, href: string)}
+4
-4
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/main-post.svelte
+4
-4
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/main-post.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs, AppBskyFeedPost } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs, AppBskyFeedPost } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
6
import { findLabel, FlagsBlurContent, FlagsBlurMedia } from '$lib/moderation';
7
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
7
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
8
8
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
9
9
10
10
import Avatar from '$lib/components/avatar.svelte';
···
27
27
28
28
const { post, threadgate, prev = false }: Props = $props();
29
29
30
-
const uri = $derived(parseAddressedAtUri(post.uri));
30
+
const uri = $derived(assertCanonicalResourceUri(post.uri));
31
31
32
32
const author = $derived(post.author);
33
33
const authorName = $derived(normalizeDisplayName(author.displayName ?? ''));
34
34
35
-
const record = $derived(post.record as AppBskyFeedPost.Record);
35
+
const record = $derived(post.record as AppBskyFeedPost.Main);
36
36
37
37
const authorUrl = $derived(`${base}/${author.did}`);
38
38
const postUrl = $derived(`${base}/${author.did}/${uri.rkey}#main`);
+5
-3
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/missing-descendant-item.svelte
+5
-3
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/missing-descendant-item.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
8
8
interface Props {
9
9
count: number;
···
15
15
16
16
<div class="missing-descendant-item">
17
17
<span class="label">{count === 1 ? `${count} missing reply` : `${count} missing replies`}</span>
18
-
<a href="{base}/{post.author.did}/{parseAddressedAtUri(post.uri).rkey}/all-replies" class="link">View</a>
18
+
<a href="{base}/{post.author.did}/{assertCanonicalResourceUri(post.uri).rkey}/all-replies" class="link"
19
+
>View</a
20
+
>
19
21
</div>
20
22
21
23
<style>
+4
-4
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/post-ascendant-item.svelte
+4
-4
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/post-ascendant-item.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedPost } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedPost } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
6
import { findLabel, FlagsBlurContent, FlagsBlurMedia } from '$lib/moderation';
7
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
7
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
8
8
9
9
import Avatar from '$lib/components/avatar.svelte';
10
10
import RichtextRenderer from '$lib/components/richtext-renderer.svelte';
···
27
27
const author = $derived(post.author);
28
28
const authorUrl = $derived(`${base}/${author.did}`);
29
29
30
-
const record = $derived(post.record as AppBskyFeedPost.Record);
31
-
const postUrl = $derived(`${base}/${author.did}/${parseAddressedAtUri(post.uri).rkey}#main`);
30
+
const record = $derived(post.record as AppBskyFeedPost.Main);
31
+
const postUrl = $derived(`${base}/${author.did}/${assertCanonicalResourceUri(post.uri).rkey}#main`);
32
32
33
33
const isAviBlurred = $derived(!!findLabel(author.labels, author.did, FlagsBlurMedia));
34
34
const blur = $derived(findLabel(post.labels, author.did, FlagsBlurContent));
+4
-4
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/post-descendant-item.svelte
+4
-4
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/components/post-descendant-item.svelte
···
1
1
<script lang="ts">
2
2
import type { Snippet } from 'svelte';
3
3
4
-
import type { AppBskyFeedDefs, AppBskyFeedPost } from '@atcute/client/lexicons';
4
+
import type { AppBskyFeedDefs, AppBskyFeedPost } from '@atcute/bluesky';
5
5
6
6
import { base } from '$app/paths';
7
7
8
8
import { findLabel, FlagsBlurContent, FlagsBlurMedia } from '$lib/moderation';
9
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
9
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
10
10
11
11
import Avatar from '$lib/components/avatar.svelte';
12
12
import ContentHider from '$lib/components/content-hider.svelte';
···
28
28
const author = $derived(post.author);
29
29
const authorUrl = $derived(`${base}/${author.did}`);
30
30
31
-
const record = $derived(post.record as AppBskyFeedPost.Record);
32
-
const postUrl = $derived(`${base}/${author.did}/${parseAddressedAtUri(post.uri).rkey}#main`);
31
+
const record = $derived(post.record as AppBskyFeedPost.Main);
32
+
const postUrl = $derived(`${base}/${author.did}/${assertCanonicalResourceUri(post.uri).rkey}#main`);
33
33
34
34
const isAviBlurred = $derived(!!findLabel(author.labels, author.did, FlagsBlurMedia));
35
35
const blur = $derived(findLabel(post.labels, author.did, FlagsBlurContent));
+3
-3
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/utils.ts
+3
-3
src/routes/(app)/[actor=didOrHandle]/[rkey=tid]/utils.ts
···
1
-
import type { AppBskyFeedDefs, AppBskyFeedPost, AppBskyFeedThreadgate } from '@atcute/client/lexicons';
1
+
import type { AppBskyFeedDefs, AppBskyFeedPost, AppBskyFeedThreadgate } from '@atcute/bluesky';
2
2
3
3
import type { UnwrapArray } from '$lib/utils/types';
4
4
···
45
45
return likeOrder / timePenalty;
46
46
};
47
47
48
-
const gate = threadgateView?.record as AppBskyFeedThreadgate.Record | undefined;
48
+
const gate = threadgateView?.record as AppBskyFeedThreadgate.Main | undefined;
49
49
50
50
return (parent: AppBskyFeedDefs.PostView, a: ReplyItem, b: ReplyItem) => {
51
51
if (a.$type !== 'app.bsky.feed.defs#threadViewPost') {
···
132
132
133
133
if (last && last.type === 'post') {
134
134
const post = last.post;
135
-
const reply = (post.record as AppBskyFeedPost.Record).reply;
135
+
const reply = (post.record as AppBskyFeedPost.Main).reply;
136
136
137
137
if (reply) {
138
138
const uri = reply.parent.uri;
+11
-9
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/+layout.ts
+11
-9
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/+layout.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
+
import { isDid, type Did } from '@atcute/lexicons/syntax';
2
3
3
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
5
import type { LayoutLoad } from './$types';
5
6
6
7
import { resolveHandle } from '$lib/queries/handle';
7
8
import { makeAtUri } from '$lib/types/at-uri';
8
-
import { isDid, type Did } from '$lib/types/identity';
9
9
10
10
export const load: LayoutLoad = async ({ params, fetch }) => {
11
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
12
12
13
13
let did: Did;
14
14
if (isDid(params.actor)) {
15
15
did = params.actor;
16
16
} else {
17
-
did = await resolveHandle({ rpc, handle: params.actor });
17
+
did = await resolveHandle({ client: client, handle: params.actor });
18
18
}
19
19
20
-
const { data } = await rpc.get('app.bsky.feed.getFeedGenerator', {
21
-
params: {
22
-
feed: makeAtUri(did, 'app.bsky.feed.generator', params.rkey),
23
-
},
24
-
});
20
+
const data = await ok(
21
+
client.get('app.bsky.feed.getFeedGenerator', {
22
+
params: {
23
+
feed: makeAtUri(did, 'app.bsky.feed.generator', params.rkey),
24
+
},
25
+
}),
26
+
);
25
27
26
28
const view = data.view;
27
29
+2
-2
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/+page.svelte
+2
-2
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/+page.svelte
···
4
4
import { PUBLIC_APP_NAME } from '$env/static/public';
5
5
import type { PageProps } from './$types';
6
6
7
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
7
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
8
8
import { paginate } from '$lib/utils/pagination';
9
9
10
10
import PageListing from '$lib/components/page/page-listing.svelte';
···
14
14
15
15
const { data }: PageProps = $props();
16
16
17
-
const rkey = $derived(parseAddressedAtUri(data.feed.uri).rkey);
17
+
const rkey = $derived(assertCanonicalResourceUri(data.feed.uri).rkey);
18
18
19
19
const { rootUrl, nextUrl } = $derived(
20
20
paginate(page.url, data.timeline.cursor, `${base}/${data.feed.creator.did}/feeds/${rkey}`),
+4
-4
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/+page.ts
+4
-4
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, simpleFetchHandler } from '@atcute/client';
2
+
import { isDid, type Did } from '@atcute/lexicons/syntax';
2
3
3
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
5
import type { PageLoad } from './$types';
5
6
6
7
import { fetchTimeline, TimelineType } from '$lib/queries/timeline';
7
8
import { makeAtUri } from '$lib/types/at-uri';
8
-
import { isDid, type Did } from '$lib/types/identity';
9
9
10
10
export const load: PageLoad = async ({ url, params, fetch, parent }) => {
11
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
12
12
13
13
let did: Did;
14
14
if (isDid(params.actor)) {
···
19
19
}
20
20
21
21
const timeline = await fetchTimeline({
22
-
rpc,
22
+
client: client,
23
23
params: {
24
24
type: TimelineType.CUSTOM_FEED,
25
25
feed: makeAtUri(did, 'app.bsky.feed.generator', params.rkey),
+3
-3
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/components/feed-aside.svelte
+3
-3
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/components/feed-aside.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedDefs } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedDefs } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
8
8
import { trimRichText } from '$lib/utils/bluesky/richtext';
9
9
import { formatLongNumber } from '$lib/utils/intl/number';
···
20
20
21
21
const { feed }: Props = $props();
22
22
23
-
const uri = $derived(parseAddressedAtUri(feed.uri));
23
+
const uri = $derived(assertCanonicalResourceUri(feed.uri));
24
24
25
25
const creatorUrl = $derived(`${base}/${feed.creator.did}`);
26
26
const feedUrl = $derived(`${creatorUrl}/feeds/${uri.rkey}`);
+12
-10
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/likes/+page.ts
+12
-10
src/routes/(app)/[actor=didOrHandle]/feeds/[rkey=rkey]/likes/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
+
import { isDid, type Did } from '@atcute/lexicons/syntax';
2
3
3
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
5
import type { PageLoad } from './$types';
5
6
6
7
import { makeAtUri } from '$lib/types/at-uri';
7
-
import { isDid, type Did } from '$lib/types/identity';
8
8
9
9
export const load: PageLoad = async ({ url, params, fetch, parent }) => {
10
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
11
12
12
let did: Did;
13
13
if (isDid(params.actor)) {
···
17
17
did = parentData.feed.creator.did as Did;
18
18
}
19
19
20
-
const { data } = await rpc.get('app.bsky.feed.getLikes', {
21
-
params: {
22
-
uri: makeAtUri(did, 'app.bsky.feed.generator', params.rkey),
23
-
limit: 50,
24
-
cursor: url.searchParams.get('cursor') || undefined,
25
-
},
26
-
});
20
+
const data = await ok(
21
+
client.get('app.bsky.feed.getLikes', {
22
+
params: {
23
+
uri: makeAtUri(did, 'app.bsky.feed.generator', params.rkey),
24
+
limit: 50,
25
+
cursor: url.searchParams.get('cursor') || undefined,
26
+
},
27
+
}),
28
+
);
27
29
28
30
return { likes: { cursor: data.cursor, items: data.likes.map((like) => like.actor) } };
29
31
};
+2
-2
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/+layout.svelte
+2
-2
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/+layout.svelte
···
5
5
import { page } from '$app/state';
6
6
import type { LayoutProps } from './$types';
7
7
8
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
8
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
9
9
10
10
import ListAside from './components/list-aside.svelte';
11
11
import ListMetaTags from './components/list-meta-tags.svelte';
···
14
14
15
15
const currentRouteId = $derived(page.route.id);
16
16
17
-
const uri = $derived(parseAddressedAtUri(data.list.uri));
17
+
const uri = $derived(assertCanonicalResourceUri(data.list.uri));
18
18
const listUrl = $derived.by(() => {
19
19
return `${base}/${uri.repo}/lists/${uri.rkey}`;
20
20
});
+15
-11
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/+layout.ts
+15
-11
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/+layout.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
+
import type { Did } from '@atcute/lexicons';
3
+
import { isDid } from '@atcute/lexicons/syntax';
2
4
3
5
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
6
import type { LayoutLoad } from './$types';
5
7
6
8
import { resolveHandle } from '$lib/queries/handle';
7
9
import { makeAtUri } from '$lib/types/at-uri';
8
-
import { isDid, type Did } from '$lib/types/identity';
9
10
10
11
export const load: LayoutLoad = async ({ url, route, params, fetch }) => {
11
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
12
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
12
13
13
14
let did: Did;
14
15
if (isDid(params.actor)) {
15
16
did = params.actor;
16
17
} else {
17
-
did = await resolveHandle({ rpc, handle: params.actor });
18
+
did = await resolveHandle({ client: client, handle: params.actor });
18
19
}
19
20
20
21
const isListing = route.id === '/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/members';
21
22
const cursor = url.searchParams.get('cursor') || undefined;
22
-
const { data } = await rpc.get('app.bsky.graph.getList', {
23
-
params: {
24
-
list: makeAtUri(did, 'app.bsky.graph.list', params.rkey),
25
-
limit: isListing ? 50 : 1,
26
-
cursor: isListing ? cursor : undefined,
27
-
},
28
-
});
23
+
24
+
const data = await ok(
25
+
client.get('app.bsky.graph.getList', {
26
+
params: {
27
+
list: makeAtUri(did, 'app.bsky.graph.list', params.rkey),
28
+
limit: isListing ? 50 : 1,
29
+
cursor: isListing ? cursor : undefined,
30
+
},
31
+
}),
32
+
);
29
33
30
34
const view = data.list;
31
35
+3
-3
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/components/list-aside.svelte
+3
-3
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/components/list-aside.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyGraphDefs } from '@atcute/client/lexicons';
2
+
import type { AppBskyGraphDefs } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
8
8
import { trimRichText } from '$lib/utils/bluesky/richtext';
9
9
import { formatLongNumber } from '$lib/utils/intl/number';
···
20
20
21
21
const { list }: Props = $props();
22
22
23
-
const uri = $derived(parseAddressedAtUri(list.uri));
23
+
const uri = $derived(assertCanonicalResourceUri(list.uri));
24
24
25
25
const creatorUrl = $derived(`${base}/${list.creator.did}`);
26
26
</script>
+2
-2
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/posts/+page.svelte
+2
-2
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/posts/+page.svelte
···
8
8
9
9
import PageListing from '$lib/components/page/page-listing.svelte';
10
10
import PostFeedItem from '$lib/components/timeline/post-feed-item.svelte';
11
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
11
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
12
12
13
13
const { data }: PageProps = $props();
14
14
15
-
const uri = $derived(parseAddressedAtUri(data.list.uri));
15
+
const uri = $derived(assertCanonicalResourceUri(data.list.uri));
16
16
17
17
const { rootUrl, nextUrl } = $derived(
18
18
paginate(page.url, data.timeline.cursor, `${base}/${uri.repo}/lists/${uri.rkey}/posts`),
+5
-5
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/posts/+page.ts
+5
-5
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/posts/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, simpleFetchHandler } from '@atcute/client';
2
+
import { isDid, type Did } from '@atcute/lexicons/syntax';
2
3
3
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
5
import type { PageLoad } from './$types';
5
6
6
-
import { isDid, type Did } from '$lib/types/identity';
7
-
import { makeAtUri } from '$lib/types/at-uri';
8
7
import { fetchTimeline, TimelineType } from '$lib/queries/timeline';
8
+
import { makeAtUri } from '$lib/types/at-uri';
9
9
10
10
export const load: PageLoad = async ({ url, params, fetch, parent }) => {
11
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
12
12
13
13
let did: Did;
14
14
if (isDid(params.actor)) {
···
19
19
}
20
20
21
21
const timeline = await fetchTimeline({
22
-
rpc,
22
+
client: client,
23
23
params: {
24
24
type: TimelineType.USER_LIST,
25
25
list: makeAtUri(did, 'app.bsky.graph.list', params.rkey),
+22
-16
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/posts/rss/+server.ts
+22
-16
src/routes/(app)/[actor=didOrHandle]/lists/[rkey=rkey]/posts/rss/+server.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
+
3
+
import type { Did } from '@atcute/lexicons';
4
+
import { isDid } from '@atcute/lexicons/syntax';
2
5
3
6
import { PUBLIC_APP_URL, PUBLIC_APPVIEW_URL } from '$env/static/public';
4
7
import type { RequestHandler } from './$types';
···
7
10
import { resolveHandle } from '$lib/queries/handle';
8
11
import { createRssFeed, feedPostToFeedItem } from '$lib/rss';
9
12
import { makeAtUri } from '$lib/types/at-uri';
10
-
import { isDid, type Did } from '$lib/types/identity';
11
13
12
14
export const GET: RequestHandler = async ({ params, fetch }) => {
13
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
15
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
14
16
15
17
let did: Did;
16
18
if (isDid(params.actor)) {
17
19
did = params.actor;
18
20
} else {
19
-
did = await resolveHandle({ rpc, handle: params.actor });
21
+
did = await resolveHandle({ client: client, handle: params.actor });
20
22
}
21
23
22
24
const uri = makeAtUri(did, 'app.bsky.graph.list', params.rkey);
23
25
24
26
const [list, timeline] = await Promise.all([
25
27
(async () => {
26
-
const { data } = await rpc.get('app.bsky.graph.getList', {
27
-
params: {
28
-
list: uri,
29
-
limit: 1,
30
-
},
31
-
});
28
+
const data = await ok(
29
+
client.get('app.bsky.graph.getList', {
30
+
params: {
31
+
list: uri,
32
+
limit: 1,
33
+
},
34
+
}),
35
+
);
32
36
33
37
return data.list;
34
38
})(),
35
39
36
40
(async () => {
37
-
const { data } = await rpc.get('app.bsky.feed.getListFeed', {
38
-
params: {
39
-
list: uri,
40
-
limit: 100,
41
-
},
42
-
});
41
+
const data = await ok(
42
+
client.get('app.bsky.feed.getListFeed', {
43
+
params: {
44
+
list: uri,
45
+
limit: 100,
46
+
},
47
+
}),
48
+
);
43
49
44
50
const slices = buildTimelineSlices(data.feed);
45
51
+4
-4
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/+layout.svelte
+4
-4
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/+layout.svelte
···
1
1
<script lang="ts">
2
2
import type { ClassValue } from 'svelte/elements';
3
3
4
-
import type { AppBskyGraphStarterpack } from '@atcute/client/lexicons';
4
+
import type { AppBskyGraphStarterpack } from '@atcute/bluesky';
5
5
6
6
import { base } from '$app/paths';
7
7
import { page } from '$app/state';
8
8
import { PUBLIC_APP_NAME } from '$env/static/public';
9
9
import type { LayoutProps } from './$types';
10
10
11
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
11
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
12
12
13
13
import PackAside from './components/pack-aside.svelte';
14
14
import PackMetaTags from './components/pack-meta-tags.svelte';
···
17
17
18
18
const currentRouteId = $derived(page.route.id);
19
19
20
-
const record = $derived(data.pack.record as AppBskyGraphStarterpack.Record);
21
-
const uri = $derived(parseAddressedAtUri(data.pack.uri));
20
+
const record = $derived(data.pack.record as AppBskyGraphStarterpack.Main);
21
+
const uri = $derived(assertCanonicalResourceUri(data.pack.uri));
22
22
23
23
const listUrl = $derived.by(() => {
24
24
return `${base}/${uri.repo}/packs/${uri.rkey}`;
+9
-7
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/+layout.ts
+9
-7
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/+layout.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { LayoutLoad } from './$types';
···
6
6
import { makeAtUri } from '$lib/types/at-uri';
7
7
8
8
export const load: LayoutLoad = async ({ params, fetch }) => {
9
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
9
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
10
11
-
const { data } = await rpc.get('app.bsky.graph.getStarterPack', {
12
-
params: {
13
-
starterPack: makeAtUri(params.actor, 'app.bsky.graph.starterpack', params.rkey),
14
-
},
15
-
});
11
+
const data = await ok(
12
+
client.get('app.bsky.graph.getStarterPack', {
13
+
params: {
14
+
starterPack: makeAtUri(params.actor, 'app.bsky.graph.starterpack', params.rkey),
15
+
},
16
+
}),
17
+
);
16
18
17
19
const view = data.starterPack;
18
20
+11
-9
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/+page.ts
+11
-9
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
5
5
6
6
export const load: PageLoad = async ({ url, fetch, parent }) => {
7
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
7
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
8
8
9
9
const { pack } = await parent();
10
10
···
19
19
}
20
20
}
21
21
22
-
const { data } = await rpc.get('app.bsky.graph.getList', {
23
-
params: {
24
-
list: pack.list.uri,
25
-
limit: 50,
26
-
cursor: url.searchParams.get('cursor') || undefined,
27
-
},
28
-
});
22
+
const data = await ok(
23
+
client.get('app.bsky.graph.getList', {
24
+
params: {
25
+
list: pack.list.uri,
26
+
limit: 50,
27
+
cursor: url.searchParams.get('cursor') || undefined,
28
+
},
29
+
}),
30
+
);
29
31
30
32
return { members: { cursor: data.cursor, items: data.items } };
31
33
};
+4
-4
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/components/pack-aside.svelte
+4
-4
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/components/pack-aside.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyGraphDefs, AppBskyGraphStarterpack } from '@atcute/client/lexicons';
2
+
import type { AppBskyGraphDefs, AppBskyGraphStarterpack } from '@atcute/bluesky';
3
3
4
4
import { base } from '$app/paths';
5
5
6
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
6
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
7
7
import { normalizeDisplayName } from '$lib/utils/bluesky/display';
8
8
import { trimRichText } from '$lib/utils/bluesky/richtext';
9
9
···
19
19
20
20
const { pack }: Props = $props();
21
21
22
-
const uri = $derived(parseAddressedAtUri(pack.uri));
23
-
const record = $derived(pack.record as AppBskyGraphStarterpack.Record);
22
+
const uri = $derived(assertCanonicalResourceUri(pack.uri));
23
+
const record = $derived(pack.record as AppBskyGraphStarterpack.Main);
24
24
25
25
const creatorUrl = $derived(`${base}/${pack.creator.did}`);
26
26
</script>
+2
-2
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/posts/+page.svelte
+2
-2
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/posts/+page.svelte
···
7
7
8
8
import PageListing from '$lib/components/page/page-listing.svelte';
9
9
import PostFeedItem from '$lib/components/timeline/post-feed-item.svelte';
10
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
10
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
11
11
12
12
const { data }: PageProps = $props();
13
13
14
-
const uri = $derived(parseAddressedAtUri(data.pack.uri));
14
+
const uri = $derived(assertCanonicalResourceUri(data.pack.uri));
15
15
16
16
const { rootUrl, nextUrl } = $derived(
17
17
paginate(page.url, data.timeline.cursor, `${base}/${uri.repo}/packs/${uri.rkey}/posts`),
+3
-3
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/posts/+page.ts
+3
-3
src/routes/(app)/[actor=didOrHandle]/packs/[rkey=rkey]/posts/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { simpleFetchHandler, Client } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
···
6
6
import { fetchTimeline, TimelineType } from '$lib/queries/timeline';
7
7
8
8
export const load: PageLoad = async ({ url, fetch, parent }) => {
9
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
9
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
10
11
11
const { pack } = await parent();
12
12
···
15
15
}
16
16
17
17
const timeline = await fetchTimeline({
18
-
rpc,
18
+
client: client,
19
19
params: {
20
20
type: TimelineType.USER_LIST,
21
21
list: pack.list.uri,
+9
-7
src/routes/(app)/[actor=did]/[rkey=tid]/all-quotes/+page.ts
+9
-7
src/routes/(app)/[actor=did]/[rkey=tid]/all-quotes/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
···
7
7
import { makeAtUri } from '$lib/types/at-uri';
8
8
9
9
export const load: PageLoad = async ({ url, params, fetch }) => {
10
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
11
12
12
const parentUri = makeAtUri(params.actor, 'app.bsky.feed.post', params.rkey);
13
13
···
20
20
});
21
21
22
22
const items = await (async () => {
23
-
const { data } = await rpc.get('app.bsky.feed.getPosts', {
24
-
params: {
25
-
uris: linking_records.map((link) => makeAtUri(link.did, 'app.bsky.feed.post', link.rkey)),
26
-
},
27
-
});
23
+
const data = await ok(
24
+
client.get('app.bsky.feed.getPosts', {
25
+
params: {
26
+
uris: linking_records.map((link) => makeAtUri(link.did, 'app.bsky.feed.post', link.rkey)),
27
+
},
28
+
}),
29
+
);
28
30
29
31
return data.posts;
30
32
})();
+17
-22
src/routes/(app)/[actor=did]/[rkey=tid]/all-replies/+page.ts
+17
-22
src/routes/(app)/[actor=did]/[rkey=tid]/all-replies/+page.ts
···
1
-
import { simpleFetchHandler, XRPC, XRPCError } from '@atcute/client';
2
-
import type { AppBskyFeedDefs, AppBskyFeedGetPostThread } from '@atcute/client/lexicons';
1
+
import type { AppBskyFeedDefs } from '@atcute/bluesky';
2
+
import { Client, ClientResponseError, simpleFetchHandler } from '@atcute/client';
3
3
import { definite } from '@mary/array-fns';
4
4
5
5
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
···
10
10
import { makeAtUri } from '$lib/types/at-uri';
11
11
12
12
export const load: PageLoad = async ({ url, params, fetch }) => {
13
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
13
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
14
14
15
15
const parentUri = makeAtUri(params.actor, 'app.bsky.feed.post', params.rkey);
16
16
17
17
// Fetch the parent post, but don't block.
18
-
const postPromise = getPost({ rpc, uri: parentUri });
18
+
const postPromise = getPost({ client, uri: parentUri });
19
19
void postPromise.catch(() => {});
20
20
21
21
// Get links from Constellation
···
29
29
// Hydrate the links
30
30
const resolvedReplies = await Promise.all(
31
31
linking_records.map(async (link) => {
32
-
let data: AppBskyFeedGetPostThread.Output;
33
-
try {
34
-
const response = await rpc.get('app.bsky.feed.getPostThread', {
35
-
params: {
36
-
uri: makeAtUri(link.did, 'app.bsky.feed.post', link.rkey),
37
-
depth: 3,
38
-
parentHeight: 0,
39
-
},
40
-
});
32
+
const response = await client.get('app.bsky.feed.getPostThread', {
33
+
params: {
34
+
uri: makeAtUri(link.did, 'app.bsky.feed.post', link.rkey),
35
+
depth: 3,
36
+
parentHeight: 0,
37
+
},
38
+
});
41
39
42
-
data = response.data;
43
-
} catch (err) {
44
-
if (err instanceof XRPCError) {
45
-
// ignore if AppView says it's not found
46
-
if (err.kind === 'NotFound') {
47
-
return null;
48
-
}
40
+
if (!response.ok) {
41
+
// AppView says not found, carry on
42
+
if (response.data.error === 'NotFound') {
43
+
return null;
49
44
}
50
45
51
-
throw err;
46
+
throw new ClientResponseError(response);
52
47
}
53
48
54
-
const thread = data.thread;
49
+
const thread = response.data.thread;
55
50
switch (thread.$type) {
56
51
// same goes for this union
57
52
case 'app.bsky.feed.defs#notFoundPost':
+11
-9
src/routes/(app)/[actor=did]/[rkey=tid]/likes/+page.ts
+11
-9
src/routes/(app)/[actor=did]/[rkey=tid]/likes/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
···
6
6
import { makeAtUri } from '$lib/types/at-uri';
7
7
8
8
export const load: PageLoad = async ({ url, params, fetch }) => {
9
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
9
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
10
11
11
const uri = makeAtUri(params.actor, 'app.bsky.feed.post', params.rkey);
12
12
13
-
const { data } = await rpc.get('app.bsky.feed.getLikes', {
14
-
params: {
15
-
uri,
16
-
limit: 50,
17
-
cursor: url.searchParams.get('cursor') || undefined,
18
-
},
19
-
});
13
+
const data = await ok(
14
+
client.get('app.bsky.feed.getLikes', {
15
+
params: {
16
+
uri,
17
+
limit: 50,
18
+
cursor: url.searchParams.get('cursor') || undefined,
19
+
},
20
+
}),
21
+
);
20
22
21
23
return { likes: { cursor: data.cursor, items: data.likes.map((like) => like.actor) } };
22
24
};
+11
-9
src/routes/(app)/[actor=did]/[rkey=tid]/quotes/+page.ts
+11
-9
src/routes/(app)/[actor=did]/[rkey=tid]/quotes/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
···
6
6
import { makeAtUri } from '$lib/types/at-uri';
7
7
8
8
export const load: PageLoad = async ({ url, params, fetch }) => {
9
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
9
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
10
11
11
const uri = makeAtUri(params.actor, 'app.bsky.feed.post', params.rkey);
12
12
13
-
const { data } = await rpc.get('app.bsky.feed.getQuotes', {
14
-
params: {
15
-
uri,
16
-
limit: 50,
17
-
cursor: url.searchParams.get('cursor') || undefined,
18
-
},
19
-
});
13
+
const data = await ok(
14
+
client.get('app.bsky.feed.getQuotes', {
15
+
params: {
16
+
uri,
17
+
limit: 50,
18
+
cursor: url.searchParams.get('cursor') || undefined,
19
+
},
20
+
}),
21
+
);
20
22
21
23
return { quotes: { cursor: data.cursor, items: data.posts } };
22
24
};
+11
-9
src/routes/(app)/[actor=did]/[rkey=tid]/reposts/+page.ts
+11
-9
src/routes/(app)/[actor=did]/[rkey=tid]/reposts/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
4
4
import type { PageLoad } from './$types';
···
6
6
import { makeAtUri } from '$lib/types/at-uri';
7
7
8
8
export const load: PageLoad = async ({ url, params, fetch }) => {
9
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
9
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
10
11
11
const uri = makeAtUri(params.actor, 'app.bsky.feed.post', params.rkey);
12
12
13
-
const { data } = await rpc.get('app.bsky.feed.getRepostedBy', {
14
-
params: {
15
-
uri,
16
-
limit: 50,
17
-
cursor: url.searchParams.get('cursor') || undefined,
18
-
},
19
-
});
13
+
const data = await ok(
14
+
client.get('app.bsky.feed.getRepostedBy', {
15
+
params: {
16
+
uri,
17
+
limit: 50,
18
+
cursor: url.searchParams.get('cursor') || undefined,
19
+
},
20
+
}),
21
+
);
20
22
21
23
return { reposts: { cursor: data.cursor, items: data.repostedBy } };
22
24
};
+5
-5
src/routes/(app)/[actor=did]/[rkey=tid]/unroll/+page.svelte
+5
-5
src/routes/(app)/[actor=did]/[rkey=tid]/unroll/+page.svelte
···
1
1
<script lang="ts">
2
-
import type { AppBskyFeedPost } from '@atcute/client/lexicons';
2
+
import type { AppBskyFeedPost } from '@atcute/bluesky';
3
3
import { cluster } from '@mary/array-fns';
4
4
5
5
import { base } from '$app/paths';
···
7
7
import type { PageProps } from './$types';
8
8
9
9
import { findLabel, FlagsBlurMedia } from '$lib/moderation';
10
-
import { parseAddressedAtUri } from '$lib/types/at-uri';
10
+
import { assertCanonicalResourceUri } from '$lib/types/at-uri';
11
11
import { truncateMiddle, truncateRight } from '$lib/utils/strings';
12
12
13
13
import Avatar from '$lib/components/avatar.svelte';
···
25
25
const author = $derived(main.author);
26
26
const authorName = $derived(author.displayName?.trim());
27
27
28
-
const uri = $derived(parseAddressedAtUri(main.uri));
28
+
const uri = $derived(assertCanonicalResourceUri(main.uri));
29
29
const postUrl = $derived(`${base}/${uri.repo}/${uri.rkey}#main`);
30
30
const authorUrl = $derived(`${base}/${uri.repo}`);
31
31
···
33
33
34
34
const title = $derived.by(() => {
35
35
const author = `@${truncateMiddle(main.author.handle, 29)}`;
36
-
const content = truncateRight((main.record as AppBskyFeedPost.Record).text.trim(), 70);
36
+
const content = truncateRight((main.record as AppBskyFeedPost.Main).text.trim(), 70);
37
37
38
38
return `${author}: "${content}" — ${PUBLIC_APP_NAME}`;
39
39
});
···
104
104
</p>
105
105
106
106
{#each cluster as post}
107
-
{@const record = post.record as AppBskyFeedPost.Record}
107
+
{@const record = post.record as AppBskyFeedPost.Main}
108
108
109
109
<div class="subitem">
110
110
<RichtextRenderer text={record.text} facets={record.facets} />
+15
-12
src/routes/(app)/[actor=did]/[rkey=tid]/unroll/+page.ts
+15
-12
src/routes/(app)/[actor=did]/[rkey=tid]/unroll/+page.ts
···
1
1
import { error } from '@sveltejs/kit';
2
2
3
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
4
-
import type { AppBskyFeedDefs, Brand } from '@atcute/client/lexicons';
3
+
import type { AppBskyFeedDefs } from '@atcute/bluesky';
4
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
5
+
import type { $type } from '@atcute/lexicons';
5
6
6
7
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
7
8
import type { PageLoad } from './$types';
···
9
10
import { makeAtUri } from '$lib/types/at-uri';
10
11
11
12
export const load: PageLoad = async ({ params }) => {
12
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
13
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
13
14
14
15
let currentUri = makeAtUri(params.actor, 'app.bsky.feed.post', params.rkey);
15
16
const items: AppBskyFeedDefs.ThreadViewPost[] = [];
16
17
17
18
while (true) {
18
-
const { data } = await rpc.get('app.bsky.feed.getPostThread', {
19
-
params: {
20
-
uri: currentUri,
21
-
// The max is 1000, but the AppView only returns 10.
22
-
depth: 1000,
23
-
parentHeight: 0,
24
-
},
25
-
});
19
+
const data = await ok(
20
+
client.get('app.bsky.feed.getPostThread', {
21
+
params: {
22
+
uri: currentUri,
23
+
// The max is 1000, but the AppView only returns 10.
24
+
depth: 1000,
25
+
parentHeight: 0,
26
+
},
27
+
}),
28
+
);
26
29
27
30
switch (data.thread.$type) {
28
31
case 'app.bsky.feed.defs#notFoundPost': {
···
48
51
break;
49
52
}
50
53
51
-
const replies = tail.replies.filter((reply): reply is Brand.Union<AppBskyFeedDefs.ThreadViewPost> => {
54
+
const replies = tail.replies.filter((reply): reply is $type.enforce<AppBskyFeedDefs.ThreadViewPost> => {
52
55
if (reply.$type !== 'app.bsky.feed.defs#threadViewPost') {
53
56
return false;
54
57
}
+2
-2
src/routes/(app)/search/+server.ts
+2
-2
src/routes/(app)/search/+server.ts
···
1
1
import { redirect, type RequestHandler } from '@sveltejs/kit';
2
2
3
-
import { isDid, isHandle } from '$lib/types/identity';
4
-
import { isRecordKey, isTid } from '$lib/types/rkey';
3
+
import { isDid, isHandle, isRecordKey, isTid } from '@atcute/lexicons/syntax';
4
+
5
5
import {
6
6
BSKY_FEED_LINK_RE,
7
7
BSKY_LIST_LINK_RE,
+13
-11
src/routes/(app)/search/feeds/+page.ts
+13
-11
src/routes/(app)/search/feeds/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
2
-
import type { At } from '@atcute/client/lexicons';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
3
2
4
3
import { AUTHENTICATED_FEEDS } from '$lib/constants';
5
4
import { asString, useSearchParams } from '$lib/utils/search-params';
6
5
7
6
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
7
+
import type { CanonicalResourceUri } from '@atcute/lexicons';
8
8
import type { PageLoad } from './$types';
9
9
10
10
export const load: PageLoad = async ({ url }) => {
···
13
13
cursor: asString,
14
14
});
15
15
16
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
16
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
17
17
18
18
const query = q.trim();
19
-
const { data } = await rpc.get('app.bsky.unspecced.getPopularFeedGenerators', {
20
-
params: {
21
-
query: query,
22
-
limit: 50,
23
-
cursor: cursor || undefined,
24
-
},
25
-
});
19
+
const data = await ok(
20
+
client.get('app.bsky.unspecced.getPopularFeedGenerators', {
21
+
params: {
22
+
query: query,
23
+
limit: 50,
24
+
cursor: cursor || undefined,
25
+
},
26
+
}),
27
+
);
26
28
27
29
let feeds = data.feeds;
28
30
if (query.length === 0) {
29
-
feeds = feeds.filter((feed) => !AUTHENTICATED_FEEDS.includes(feed.uri as At.CanonicalResourceUri));
31
+
feeds = feeds.filter((feed) => !AUTHENTICATED_FEEDS.includes(feed.uri as CanonicalResourceUri));
30
32
}
31
33
32
34
return {
+16
-39
src/routes/(app)/search/posts/+page.ts
+16
-39
src/routes/(app)/search/posts/+page.ts
···
1
-
import { simpleFetchHandler, XRPC, XRPCError } from '@atcute/client';
1
+
import { Client, ClientResponseError, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { asString, asStringUnion, useSearchParams } from '$lib/utils/search-params';
4
4
···
12
12
cursor: asString,
13
13
});
14
14
15
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
15
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
16
16
17
17
const query = q.trim();
18
18
if (query.length === 0) {
19
19
return { query, posts: { cursor: undefined, items: [] } };
20
20
}
21
21
22
-
try {
23
-
const { data } = await rpc.get(randomCase('app.bsky.feed.searchPosts', !!cursor), {
24
-
params: {
25
-
q: query,
26
-
limit: 50,
27
-
sort: sort,
28
-
cursor: cursor || undefined,
29
-
},
30
-
});
22
+
const response = await client.get('app.bsky.feed.searchPosts', {
23
+
params: {
24
+
q: query,
25
+
limit: 50,
26
+
sort: sort,
27
+
cursor: cursor || undefined,
28
+
},
29
+
});
31
30
32
-
return {
33
-
query,
34
-
posts: {
35
-
cursor: data.cursor,
36
-
items: data.posts,
37
-
},
38
-
};
39
-
} catch (err) {
40
-
if (err instanceof XRPCError) {
41
-
if (err.status === 403) {
42
-
return { query, posts: { cursor: undefined, items: [] } };
43
-
}
31
+
if (!response.ok) {
32
+
if (response.status === 403) {
33
+
return { query, posts: { cursor: undefined, items: [] } };
44
34
}
45
35
46
-
throw err;
36
+
throw new ClientResponseError(response);
47
37
}
48
-
};
49
38
50
-
const randomCase = <T extends string>(str: T, enabled: boolean): T => {
51
-
if (!enabled) {
52
-
return str;
53
-
}
39
+
const data = response.data;
54
40
55
-
let result: string;
56
-
57
-
do {
58
-
result = str
59
-
.split('')
60
-
.map((char) => (Math.random() < 0.5 ? char.toLowerCase() : char.toUpperCase()))
61
-
.join('');
62
-
} while (result === str);
63
-
64
-
return result as T;
41
+
return { query, posts: { cursor: data.cursor, items: data.posts } };
65
42
};
+11
-9
src/routes/(app)/search/users/+page.ts
+11
-9
src/routes/(app)/search/users/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
3
3
import { asString, useSearchParams } from '$lib/utils/search-params';
4
4
···
11
11
cursor: asString,
12
12
});
13
13
14
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
14
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
15
15
16
16
const query = q.trim();
17
17
if (query.length === 0) {
18
18
return { query, profiles: { cursor: undefined, items: [] } };
19
19
}
20
20
21
-
const { data } = await rpc.get('app.bsky.actor.searchActors', {
22
-
params: {
23
-
q: query,
24
-
limit: 50,
25
-
cursor: cursor || undefined,
26
-
},
27
-
});
21
+
const data = await ok(
22
+
client.get('app.bsky.actor.searchActors', {
23
+
params: {
24
+
q: query,
25
+
limit: 50,
26
+
cursor: cursor || undefined,
27
+
},
28
+
}),
29
+
);
28
30
29
31
return {
30
32
query,
+9
-7
src/routes/(app)/trending/+page.ts
+9
-7
src/routes/(app)/trending/+page.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, ok, simpleFetchHandler } from '@atcute/client';
2
2
import { mapDefined } from '@mary/array-fns';
3
3
4
4
import { PUBLIC_APPVIEW_URL } from '$env/static/public';
···
7
7
import { mapTopic } from './utils';
8
8
9
9
export const load: PageLoad = async ({ fetch }) => {
10
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
10
+
const client = new Client({ handler: simpleFetchHandler({ service: PUBLIC_APPVIEW_URL }) });
11
11
12
-
const { data } = await rpc.get('app.bsky.unspecced.getTrendingTopics', {
13
-
params: {
14
-
limit: 14,
15
-
},
16
-
});
12
+
const data = await ok(
13
+
client.get('app.bsky.unspecced.getTrendingTopics', {
14
+
params: {
15
+
limit: 14,
16
+
},
17
+
}),
18
+
);
17
19
18
20
return {
19
21
suggested: mapDefined(data.suggested, mapTopic),
+2
-4
src/routes/(app)/trending/utils.ts
+2
-4
src/routes/(app)/trending/utils.ts
···
1
-
import type { AppBskyUnspeccedDefs } from '@atcute/client/lexicons';
2
-
3
-
import { isDid, isHandle } from '$lib/types/identity';
4
-
import { isRecordKey } from '$lib/types/rkey';
1
+
import type { AppBskyUnspeccedDefs } from '@atcute/bluesky';
2
+
import { isDid, isHandle, isRecordKey } from '@atcute/lexicons/syntax';
5
3
6
4
// /profile/jaz.bsky.social/feed/cv:cat
7
5
// /profile/bossett.social/feed/for-science
+1
tsconfig.json
+1
tsconfig.json