tangled
alpha
login
or
join now
whey.party
/
red-dwarf
82
fork
atom
an independent Bluesky client using Constellation, PDS Queries, and other services
reddwarf.app
frontend
spa
bluesky
reddwarf
microcosm
client
app
82
fork
atom
overview
issues
25
pulls
pipelines
attampt at fixing av via fast bypasses
whey.party
2 weeks ago
2b165edc
8562ff73
+253
-57
6 changed files
expand all
collapse all
unified
split
src
providers
PollMutationQueueProvider.tsx
routes
about.tsx
profile.$did
post.$rkey.tsx
settings.tsx
utils
followState.ts
useQuery.ts
+10
-6
src/providers/PollMutationQueueProvider.tsx
···
295
return context;
296
}
297
298
-
function usePollSelfVotes(pollUri: string) {
299
const { agent } = useAuth();
300
const agentDid = agent?.did;
301
302
const { uris: userVotesA } = useGetOneToOneState(
303
-
agentDid
304
? {
305
target: pollUri,
306
user: agentDid,
307
collection: "app.reddwarf.poll.vote.a",
308
path: ".subject.uri",
0
309
}
310
: undefined,
311
);
312
const { uris: userVotesB } = useGetOneToOneState(
313
-
agentDid
314
? {
315
target: pollUri,
316
user: agentDid,
317
collection: "app.reddwarf.poll.vote.b",
318
path: ".subject.uri",
0
319
}
320
: undefined,
321
);
322
const { uris: userVotesC } = useGetOneToOneState(
323
-
agentDid
324
? {
325
target: pollUri,
326
user: agentDid,
327
collection: "app.reddwarf.poll.vote.c",
328
path: ".subject.uri",
0
329
}
330
: undefined,
331
);
332
const { uris: userVotesD } = useGetOneToOneState(
333
-
agentDid
334
? {
335
target: pollUri,
336
user: agentDid,
337
collection: "app.reddwarf.poll.vote.d",
338
path: ".subject.uri",
0
339
}
340
: undefined,
341
);
···
361
const myDid = agent?.did;
362
363
const { castVoteRaw, getLocalVotes } = usePollMutationQueue();
364
-
const serverUserVotes = usePollSelfVotes(pollUri); // Our own votes from server
365
const localVotes = getLocalVotes(pollUri); // Pending local actions
366
367
// 1. FETCHING - Move the logic here
···
295
return context;
296
}
297
298
+
function usePollSelfVotes(pollUri: string, enabled?: boolean) {
299
const { agent } = useAuth();
300
const agentDid = agent?.did;
301
302
const { uris: userVotesA } = useGetOneToOneState(
303
+
agentDid && enabled
304
? {
305
target: pollUri,
306
user: agentDid,
307
collection: "app.reddwarf.poll.vote.a",
308
path: ".subject.uri",
309
+
enabled: enabled
310
}
311
: undefined,
312
);
313
const { uris: userVotesB } = useGetOneToOneState(
314
+
agentDid && enabled
315
? {
316
target: pollUri,
317
user: agentDid,
318
collection: "app.reddwarf.poll.vote.b",
319
path: ".subject.uri",
320
+
enabled: enabled
321
}
322
: undefined,
323
);
324
const { uris: userVotesC } = useGetOneToOneState(
325
+
agentDid && enabled
326
? {
327
target: pollUri,
328
user: agentDid,
329
collection: "app.reddwarf.poll.vote.c",
330
path: ".subject.uri",
331
+
enabled: enabled
332
}
333
: undefined,
334
);
335
const { uris: userVotesD } = useGetOneToOneState(
336
+
agentDid && enabled
337
? {
338
target: pollUri,
339
user: agentDid,
340
collection: "app.reddwarf.poll.vote.d",
341
path: ".subject.uri",
342
+
enabled: enabled
343
}
344
: undefined,
345
);
···
365
const myDid = agent?.did;
366
367
const { castVoteRaw, getLocalVotes } = usePollMutationQueue();
368
+
const serverUserVotes = usePollSelfVotes(pollUri, enabled); // Our own votes from server
369
const localVotes = getLocalVotes(pollUri); // Pending local actions
370
371
// 1. FETCHING - Move the logic here
+88
-27
src/routes/about.tsx
···
1
import { createFileRoute } from '@tanstack/react-router'
0
2
3
import { FORCED_LABELER_DIDS, HOST_ABOUT_MARKDOWN, HOST_ADMIN, HOST_DESCRIPTION, HOST_HERO, HOST_LABELMERGE, HOST_SIGNUP_PDS } from '~/../policy';
4
import { Header } from '~/components/Header';
···
173
// endorsed feeds (should be shown in the explore tab too in lieu of feed discovery)
174
// - [ ] HOST_UNAUTHED_DEFAULT_FEEDS
175
// endorsed PDS
176
-
// - [ ] HOST_SIGNUP_PDS
177
// todo move the other default services into policy.ts
178
// todo re- sort policy.ts according to this component
179
// also the default services used like microcosm stuff and lycan and maybe the reliance of an appview for search or some other hting
···
181
// default general host moderation policies
182
// todo: layerd moderataion later pls thanks
183
// show the labelmerge insstance responsible
184
-
// - [ ] HOST_LABELMERGE
185
// show both the whitelisted source and labeler dids in the same spot.
186
// like on hover / click it opens a dialog / popover to show what authority the labeler has
187
// - [x] FORCED_LABELER_DIDS
···
197
return (
198
<>
199
{/* settings heading or about heading? */}
0
0
0
0
0
0
0
0
0
0
0
0
0
200
<Heading3 title="Instance Defaults" />
201
-
<div className="grid grid-cols-2 gap-x-2 gap-y-2 text-sm text-gray-700 dark:text-gray-300 mr-auto ml-2">
202
-
<span className="font-medium">PDS (User Account Storage):</span>
203
-
<span className={HOST_SIGNUP_PDS ? "" : "italic"}>{HOST_SIGNUP_PDS || "not set"}</span>
204
-
205
-
<span className="font-medium">Labelmerge (Label Cache):</span>
206
-
<span>{HOST_LABELMERGE || "not set"}</span>
207
-
208
-
<span className="font-medium">Constellation (Backlink Index):</span>
209
-
<span>{defaultconstellationURL || "not set"}</span>
210
-
211
-
<span className="font-medium">Slingshot (Record Cache):</span>
212
-
<span>{defaultslingshotURL || "not set"}</span>
213
-
214
-
<span className="font-medium">Image Provider (CDN):</span>
215
-
<span>{defaultImgCDN || "not set"}</span>
216
-
217
-
<span className="font-medium">Video Provider (CDN):</span>
218
-
<span>{defaultVideoCDN || "not set"}</span>
219
-
220
-
<span className="font-medium">Lycan (Personal Search):</span>
221
-
<span className={defaultLycanURL ? "" : "italic"}>{defaultLycanURL || "not set"}</span>
222
-
223
-
<span className="font-medium">AppView (Bluesky Index):</span>
224
-
<span className={defaultAppviewURL? "" : "italic"}>{defaultAppviewURL || "not set"}</span>
225
-
</div>
0
0
0
0
226
{/* {hostmandate && (<Heading2 title="Host-Mandated Labelers" />)} */}
227
<Heading3 title="General Moderation" />
228
{hostmandate && (<Heading4 title="Host-Mandated Labelers" />)}
···
240
<div className='h-[300px] w-auto' />
241
242
</>
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
243
)
244
}
···
1
import { createFileRoute } from '@tanstack/react-router'
2
+
import React from 'react';
3
4
import { FORCED_LABELER_DIDS, HOST_ABOUT_MARKDOWN, HOST_ADMIN, HOST_DESCRIPTION, HOST_HERO, HOST_LABELMERGE, HOST_SIGNUP_PDS } from '~/../policy';
5
import { Header } from '~/components/Header';
···
174
// endorsed feeds (should be shown in the explore tab too in lieu of feed discovery)
175
// - [ ] HOST_UNAUTHED_DEFAULT_FEEDS
176
// endorsed PDS
177
+
// - [x] HOST_SIGNUP_PDS
178
// todo move the other default services into policy.ts
179
// todo re- sort policy.ts according to this component
180
// also the default services used like microcosm stuff and lycan and maybe the reliance of an appview for search or some other hting
···
182
// default general host moderation policies
183
// todo: layerd moderataion later pls thanks
184
// show the labelmerge insstance responsible
185
+
// - [x] HOST_LABELMERGE
186
// show both the whitelisted source and labeler dids in the same spot.
187
// like on hover / click it opens a dialog / popover to show what authority the labeler has
188
// - [x] FORCED_LABELER_DIDS
···
198
return (
199
<>
200
{/* settings heading or about heading? */}
201
+
<Heading3 title="Instance Configuration" />
202
+
<KeyValueGrid
203
+
items={[
204
+
{
205
+
label: "PDS Signups (Account Storage):",
206
+
value: HOST_SIGNUP_PDS || "",
207
+
},
208
+
{
209
+
label: "Labelmerge (Label Cache):",
210
+
value: HOST_LABELMERGE,
211
+
},
212
+
]}
213
+
/>
214
<Heading3 title="Instance Defaults" />
215
+
<KeyValueGrid
216
+
items={[
217
+
{
218
+
label: "Constellation (Backlink Index):",
219
+
value: defaultconstellationURL,
220
+
//italicIfEmpty: true,
221
+
},
222
+
{
223
+
label: "Slingshot (Record Cache):",
224
+
value: defaultslingshotURL,
225
+
},
226
+
{
227
+
label: "Image Provider (CDN):",
228
+
value: defaultImgCDN,
229
+
},
230
+
{
231
+
label: "Video Provider (CDN):",
232
+
value: defaultVideoCDN,
233
+
},
234
+
{
235
+
label: "Lycan (Personal Search):",
236
+
value: defaultLycanURL,
237
+
},
238
+
{
239
+
label: "AppView (Bluesky Index):",
240
+
value: defaultAppviewURL,
241
+
},
242
+
]}
243
+
/>
244
{/* {hostmandate && (<Heading2 title="Host-Mandated Labelers" />)} */}
245
<Heading3 title="General Moderation" />
246
{hostmandate && (<Heading4 title="Host-Mandated Labelers" />)}
···
258
<div className='h-[300px] w-auto' />
259
260
</>
261
+
)
262
+
}
263
+
264
+
type KeyValueItem = {
265
+
label: string
266
+
value?: string | null
267
+
//italicIfEmpty?: boolean
268
+
}
269
+
270
+
interface KeyValueGridProps {
271
+
items: KeyValueItem[]
272
+
className?: string
273
+
}
274
+
275
+
export function KeyValueGrid({ items, className = "" }: KeyValueGridProps) {
276
+
return (
277
+
<div
278
+
className={`grid grid-cols-2 gap-x-2 gap-y-2 text-sm mr-auto ml-2 ${className}`}
279
+
>
280
+
{items.map((item, i) => {
281
+
const isEmpty = !item.value
282
+
283
+
return (
284
+
<React.Fragment key={i}>
285
+
{/* Label */}
286
+
<span className="font-medium text-gray-500 dark:text-gray-400">
287
+
{item.label}
288
+
</span>
289
+
290
+
{/* Value */}
291
+
<span
292
+
className={
293
+
isEmpty
294
+
? "text-gray-400 dark:text-gray-500 italic"
295
+
: "text-gray-600 dark:text-gray-300"
296
+
}
297
+
>
298
+
{item.value || "not set"}
299
+
</span>
300
+
</React.Fragment>
301
+
)
302
+
})}
303
+
</div>
304
)
305
}
+77
-20
src/routes/profile.$did/post.$rkey.tsx
···
1
import { AtUri } from "@atproto/api";
2
-
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
3
import { createFileRoute, Outlet, useMatchRoute } from "@tanstack/react-router";
4
-
import { useAtom } from "jotai";
0
5
import React, { useLayoutEffect } from "react";
6
7
import { Header } from "~/components/Header";
8
import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer";
9
-
import { constellationURLAtom, slingshotURLAtom } from "~/utils/atoms";
10
//import { usePersistentStore } from '~/providers/PersistentStoreProvider';
11
import {
12
constructPostQuery,
0
13
type linksAllResponse,
14
type linksRecordsResponse,
15
useQueryConstellation,
16
-
useQueryIdentity,
0
17
useQueryPost,
18
yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks,
19
} from "~/utils/useQuery";
···
189
// };
190
// }, [atUri]);
191
0
0
192
const {
193
data: identity,
194
isLoading: isIdentityLoading,
195
error: identityError,
196
-
} = useQueryIdentity(showMainPostRoute ? did : undefined);
197
198
const resolvedDid = did.startsWith("did:") ? did : identity?.did;
199
···
207
208
const { data: mainPost } = useQueryPost(showMainPostRoute ? atUri : undefined);
209
210
-
console.log("atUri",atUri)
211
-
212
const opdid = React.useMemo(
213
() =>
214
atUri
···
218
);
219
220
// @ts-expect-error i hate overloads
221
-
const { data: links } = useQueryConstellation(atUri&&showMainPostRoute?{
222
method: "/links/all",
223
target: atUri,
224
} : {
225
method: "undefined",
226
target: ""
227
-
})as { data: linksAllResponse | undefined };
228
229
//const [likes, setLikes] = React.useState<number | null>(null);
230
//const [reposts, setReposts] = React.useState<number | null>(null);
···
245
setReplyCount(
246
links
247
? links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"]
248
-
?.records || 0
249
: null
250
);
251
}, [links]);
···
388
389
hasPerformedInitialLayout.current = true;
390
}
391
-
392
// todo idk what to do with this
393
// eslint-disable-next-line react-hooks/set-state-in-effect
394
setLayoutReady(true);
···
396
}, [parents, layoutReady, showMainPostRoute]);
397
398
399
-
const [slingshoturl] = useAtom(slingshotURLAtom)
400
-
0
0
0
0
0
0
401
React.useEffect(() => {
402
if (parentsLoading || !showMainPostRoute) {
403
setLayoutReady(false);
···
412
const directparent = mainPost?.value.reply?.parent.uri;
413
414
React.useEffect(() => {
0
0
0
0
0
415
if (!mainPost?.value?.reply?.parent?.uri) {
416
setParents([]);
417
return;
···
420
let ignore = false;
421
const fetchParents = async () => {
422
setParentsLoading(true);
423
-
const parentChain: ({uri: string;cid: string;value: any;} | undefined)[] = [];
424
let currentParentUri = mainPost?.value.reply?.parent.uri;
425
const MAX_PARENTS = 25;
426
let safetyCounter = 0;
427
428
while (currentParentUri && safetyCounter < MAX_PARENTS) {
429
try {
430
-
const parentPost = await queryClient.fetchQuery(
431
-
constructPostQuery(currentParentUri, slingshoturl)
432
-
);
433
if (!parentPost) break;
434
parentChain.push(parentPost);
435
currentParentUri = parentPost.value?.reply?.parent?.uri;
436
} catch (error) {
437
console.error("Failed to fetch a parent post:", error);
438
// its okay to always add one invalid parent then stop
439
-
if (currentParentUri){
440
parentChain.push({
441
uri: currentParentUri,
442
cid: "sorry",
···
458
return () => {
459
ignore = true;
460
};
461
-
}, [mainPost, queryClient, slingshoturl]);
462
463
if ((!did || !rkey) && showMainPostRoute) return <div>Invalid post URI</div>;
464
if (isIdentityLoading && showMainPostRoute) return <div>Resolving handle...</div>;
···
545
/>
546
);
547
})}
548
-
{hasNextPage && (
549
<button
550
onClick={() => fetchNextPage()}
551
disabled={isFetchingNextPage}
···
560
</>
561
);
562
}
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
import { AtUri } from "@atproto/api";
2
+
import { QueryClient, useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
3
import { createFileRoute, Outlet, useMatchRoute } from "@tanstack/react-router";
4
+
import { useAtom, useAtomValue } from "jotai";
5
+
import { loadable } from "jotai/utils";
6
import React, { useLayoutEffect } from "react";
7
8
import { Header } from "~/components/Header";
9
import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer";
10
+
import { appviewUrlAtom, constellationURLAtom, enableAppViewAtom, slingshotURLAtom } from "~/utils/atoms";
11
//import { usePersistentStore } from '~/providers/PersistentStoreProvider';
12
import {
13
constructPostQuery,
14
+
constructSingularAVPostQuery,
15
type linksAllResponse,
16
type linksRecordsResponse,
17
useQueryConstellation,
18
+
useQueryFastAVIdentity,
19
+
//useQueryIdentity,
20
useQueryPost,
21
yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks,
22
} from "~/utils/useQuery";
···
192
// };
193
// }, [atUri]);
194
195
+
const [slingshoturl] = useAtom(slingshotURLAtom);
196
+
197
const {
198
data: identity,
199
isLoading: isIdentityLoading,
200
error: identityError,
201
+
} = useQueryFastAVIdentity(showMainPostRoute ? did : undefined, slingshoturl, queryClient, true);
202
203
const resolvedDid = did.startsWith("did:") ? did : identity?.did;
204
···
212
213
const { data: mainPost } = useQueryPost(showMainPostRoute ? atUri : undefined);
214
215
+
console.log("atUri", atUri)
216
+
217
const opdid = React.useMemo(
218
() =>
219
atUri
···
223
);
224
225
// @ts-expect-error i hate overloads
226
+
const { data: links } = useQueryConstellation(atUri && showMainPostRoute ? {
227
method: "/links/all",
228
target: atUri,
229
} : {
230
method: "undefined",
231
target: ""
232
+
}) as { data: linksAllResponse | undefined };
233
234
//const [likes, setLikes] = React.useState<number | null>(null);
235
//const [reposts, setReposts] = React.useState<number | null>(null);
···
250
setReplyCount(
251
links
252
? links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"]
253
+
?.records || 0
254
: null
255
);
256
}, [links]);
···
393
394
hasPerformedInitialLayout.current = true;
395
}
396
+
397
// todo idk what to do with this
398
// eslint-disable-next-line react-hooks/set-state-in-effect
399
setLayoutReady(true);
···
401
}, [parents, layoutReady, showMainPostRoute]);
402
403
404
+
const [isAppviewEnabled] = useAtom(enableAppViewAtom);
405
+
const loadablePrefs = useAtomValue(loadable(enableAppViewAtom))
406
+
React.useEffect(() => {
407
+
console.log("why is this fucked isAppviewEnabled?:", isAppviewEnabled);
408
+
},[isAppviewEnabled])
409
+
const [appviewUrl] = useAtom(appviewUrlAtom);
410
+
//const [slingshoturl] = useAtom(slingshotURLAtom)
411
+
412
React.useEffect(() => {
413
if (parentsLoading || !showMainPostRoute) {
414
setLayoutReady(false);
···
423
const directparent = mainPost?.value.reply?.parent.uri;
424
425
React.useEffect(() => {
426
+
console.log("parent fetching useeffect called!")
427
+
// if (loadablePrefs.state !== "hasData") {
428
+
// setParentsLoading(true);
429
+
// return;
430
+
// }
431
if (!mainPost?.value?.reply?.parent?.uri) {
432
setParents([]);
433
return;
···
436
let ignore = false;
437
const fetchParents = async () => {
438
setParentsLoading(true);
439
+
const parentChain: ({ uri: string; cid: string; value: any; } | undefined)[] = [];
440
let currentParentUri = mainPost?.value.reply?.parent.uri;
441
const MAX_PARENTS = 25;
442
let safetyCounter = 0;
443
444
while (currentParentUri && safetyCounter < MAX_PARENTS) {
445
try {
446
+
const parentPost = await getProfilePostTryFail({isAppviewEnabled, appviewUrl, queryClient, currentParentUri, slingshoturl})
0
0
447
if (!parentPost) break;
448
parentChain.push(parentPost);
449
currentParentUri = parentPost.value?.reply?.parent?.uri;
450
} catch (error) {
451
console.error("Failed to fetch a parent post:", error);
452
// its okay to always add one invalid parent then stop
453
+
if (currentParentUri) {
454
parentChain.push({
455
uri: currentParentUri,
456
cid: "sorry",
···
472
return () => {
473
ignore = true;
474
};
475
+
}, [appviewUrl, isAppviewEnabled, loadablePrefs.state, mainPost, queryClient, slingshoturl]);
476
477
if ((!did || !rkey) && showMainPostRoute) return <div>Invalid post URI</div>;
478
if (isIdentityLoading && showMainPostRoute) return <div>Resolving handle...</div>;
···
559
/>
560
);
561
})}
562
+
{hasNextPage && (
563
<button
564
onClick={() => fetchNextPage()}
565
disabled={isFetchingNextPage}
···
574
</>
575
);
576
}
577
+
578
+
579
+
async function getProfilePostTryFail({
580
+
isAppviewEnabled,
581
+
appviewUrl,
582
+
queryClient,
583
+
currentParentUri,
584
+
slingshoturl,
585
+
}: {
586
+
isAppviewEnabled?: boolean,
587
+
appviewUrl?: string,
588
+
queryClient: QueryClient,
589
+
currentParentUri: string,
590
+
slingshoturl: string,
591
+
}): Promise<{
592
+
uri: string,
593
+
cid: string,
594
+
value: any
595
+
} | undefined> {
596
+
try {
597
+
if (isAppviewEnabled && appviewUrl) {
598
+
console.log("why is this called? isAppviewEnabled:",isAppviewEnabled," appviewUrl:",appviewUrl)
599
+
const result = await queryClient.fetchQuery(
600
+
constructSingularAVPostQuery({ aturi: currentParentUri, avurl: appviewUrl, instantBypass: true })
601
+
)
602
+
if (result?.uri && result?.cid && result?.record) {
603
+
return {
604
+
uri: result?.uri,
605
+
cid: result?.cid,
606
+
value: result?.record as any
607
+
}
608
+
} else {
609
+
throw "whatever";
610
+
}
611
+
} else {
612
+
throw "sure";
613
+
}
614
+
} catch {
615
+
console.log("whatever why is this called? isAppviewEnabled:",isAppviewEnabled," appviewUrl:",appviewUrl)
616
+
return await queryClient.fetchQuery(
617
+
constructPostQuery(currentParentUri, slingshoturl))
618
+
}
619
+
}
+1
-1
src/routes/settings.tsx
···
205
<SwitchSetting
206
atom={enableAppViewAtom}
207
title={"AppView-First"}
208
-
description={"Prioritize using an AppView to hydrate posts & profiles before using microcosm"}
209
//init={false}
210
/>
211
<div className={`${isAppViewEnabled ? "" : "opacity-50 pointer-events-none"}`}>
···
205
<SwitchSetting
206
atom={enableAppViewAtom}
207
title={"AppView-First"}
208
+
description={"Prioritize using an AppView to fetch posts before using microcosm"}
209
//init={false}
210
/>
211
<div className={`${isAppViewEnabled ? "" : "opacity-50 pointer-events-none"}`}>
+3
-1
src/utils/followState.ts
···
134
user: string;
135
collection: string;
136
path: string;
0
137
}): {
138
uris: string[],
139
isLoading: boolean;
···
152
customkey: params.collection.includes("reddwarf.poll.vote")
153
? "constellation-polls"
154
: undefined,
0
155
}
156
-
: { method: "undefined", target: "whatever" },
157
// overloading sucks so much
158
) as UseQueryResult<linksRecordsResponse | undefined, Error>;
159
if (!params || !params.user) return {
···
134
user: string;
135
collection: string;
136
path: string;
137
+
enabled?: boolean;
138
}): {
139
uris: string[],
140
isLoading: boolean;
···
153
customkey: params.collection.includes("reddwarf.poll.vote")
154
? "constellation-polls"
155
: undefined,
156
+
enabled: params.enabled || false,
157
}
158
+
: { method: "undefined", target: "whatever", enabled: false },
159
// overloading sucks so much
160
) as UseQueryResult<linksRecordsResponse | undefined, Error>;
161
if (!params || !params.user) return {
+74
-2
src/utils/useQuery.ts
···
7
useInfiniteQuery,
8
useQueries,
9
useQuery,
0
10
type UseQueryResult,
11
} from "@tanstack/react-query";
12
import { create, windowScheduler } from "@yornaath/batshit";
···
73
export function useQueryIdentity(didorhandle?: string) {
74
const [slingshoturl] = useAtom(slingshotURLAtom);
75
return useQuery(constructIdentityQuery(didorhandle, slingshoturl));
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
76
}
77
78
export function constructPostQuery(uri?: string, slingshoturl?: string) {
···
1398
type SingularAVPostQuery = {
1399
aturi: string,
1400
avurl: string,
0
1401
}
1402
type SingularAVPostResult = ATPAPI.AppBskyFeedDefs.PostView
1403
···
1533
);
1534
1535
export function constructSingularAVPostQuery(options: SingularAVPostQuery) {
1536
-
const { aturi, avurl } = options;
0
1537
1538
return queryOptions({
1539
-
queryKey: ["__volatile","savpq", aturi],
1540
1541
enabled: !!aturi && !!avurl,
1542
···
1546
// throw result.error
1547
// }
1548
// return result;
0
0
0
0
0
0
0
0
0
0
0
0
0
1549
const result = (await postquerymerge
1550
.fetch(options))as SingularAVPostResult;
1551
// .catch(
···
7
useInfiniteQuery,
8
useQueries,
9
useQuery,
10
+
//useQueryClient,
11
type UseQueryResult,
12
} from "@tanstack/react-query";
13
import { create, windowScheduler } from "@yornaath/batshit";
···
74
export function useQueryIdentity(didorhandle?: string) {
75
const [slingshoturl] = useAtom(slingshotURLAtom);
76
return useQuery(constructIdentityQuery(didorhandle, slingshoturl));
77
+
}
78
+
79
+
export function constructFastAVIdentityQuery(
80
+
didorhandle?: string,
81
+
slingshoturl?: string,
82
+
queryClient?: QueryClient,
83
+
enabled?: boolean
84
+
) {
85
+
return queryOptions({
86
+
queryKey: ["identity", didorhandle],
87
+
queryFn: async () => {
88
+
try {
89
+
console.log("whathuh trying", ["savpq", didorhandle])
90
+
if (!queryClient) throw "whatever"
91
+
const datas = queryClient.getQueriesData<SingularAVPostResult | undefined>({
92
+
queryKey: ["savpq", didorhandle],
93
+
})
94
+
console.log("whathuh checking", datas)
95
+
const data = datas[0][1];
96
+
if (!data) {
97
+
throw "whatever"
98
+
}
99
+
//const parsedaturi = new ATPAPI.AtUri(data.uri)
100
+
console.log("whathuh success")
101
+
return {
102
+
did: data.author.did,
103
+
handle: data.author.handle
104
+
}
105
+
} catch {
106
+
console.log("whathuh failure")
107
+
if (!didorhandle) return undefined as undefined;
108
+
const res = await fetch(
109
+
`https://${slingshoturl}/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${encodeURIComponent(didorhandle)}`,
110
+
);
111
+
if (!res.ok) throw new Error("Failed to fetch post");
112
+
try {
113
+
return (await res.json()) as {
114
+
did: string;
115
+
handle: string;
116
+
pds: string;
117
+
signing_key: string;
118
+
};
119
+
} catch (_e) {
120
+
return undefined;
121
+
}
122
+
}
123
+
},
124
+
enabled,
125
+
staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes
126
+
gcTime: /*0//*/ 5 * 60 * 1000,
127
+
});
128
+
}
129
+
130
+
131
+
export function useQueryFastAVIdentity(didorhandle?: string, slingshoturl?: string, queryClient?: QueryClient, enabled: boolean = true) {
132
+
return useQuery(constructFastAVIdentityQuery(didorhandle, slingshoturl, queryClient, enabled));
133
}
134
135
export function constructPostQuery(uri?: string, slingshoturl?: string) {
···
1455
type SingularAVPostQuery = {
1456
aturi: string,
1457
avurl: string,
1458
+
instantBypass?: boolean,
1459
}
1460
type SingularAVPostResult = ATPAPI.AppBskyFeedDefs.PostView
1461
···
1591
);
1592
1593
export function constructSingularAVPostQuery(options: SingularAVPostQuery) {
1594
+
const { aturi, avurl, instantBypass } = options;
1595
+
const parsedaturi = new ATPAPI.AtUri(aturi)
1596
1597
return queryOptions({
1598
+
queryKey: ["savpq", parsedaturi.host, /*"__volatile", */aturi],
1599
1600
enabled: !!aturi && !!avurl,
1601
···
1605
// throw result.error
1606
// }
1607
// return result;
1608
+
if (instantBypass) {
1609
+
const params = new URLSearchParams();
1610
+
params.append("uris", aturi)
1611
+
const url = `${avurl}/xrpc/app.bsky.feed.getPosts?${params.toString()}`;
1612
+
1613
+
const res = await fetch(url);
1614
+
if (!res.ok) {
1615
+
throw new Error(`Labelmerge fetch failed: ${res.status} ${res.statusText}`);
1616
+
}
1617
+
1618
+
const result = (await res.json()) as ATPAPI.AppBskyFeedGetPosts.OutputSchema;
1619
+
return result.posts[0]
1620
+
}
1621
const result = (await postquerymerge
1622
.fetch(options))as SingularAVPostResult;
1623
// .catch(