mirror of
https://github.com/aljazceru/rabbit.git
synced 2025-12-17 05:54:19 +01:00
chore: update libraries
This commit is contained in:
5602
package-lock.json
generated
5602
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
62
package.json
62
package.json
@@ -26,51 +26,51 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
||||
"@typescript-eslint/parser": "^6.7.4",
|
||||
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
||||
"@typescript-eslint/parser": "^6.15.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"eslint": "^8.51.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-airbnb-typescript": "^17.1.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-no-relative-import-paths": "^1.5.2",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||
"eslint-plugin-no-relative-import-paths": "^1.5.3",
|
||||
"eslint-plugin-solid": "^0.13.0",
|
||||
"eslint-plugin-tailwindcss": "^3.13.0",
|
||||
"husky": "^8.0.3",
|
||||
"jsdom": "^23.0.0",
|
||||
"jsdom": "^23.0.1",
|
||||
"license-checker": "^25.0.1",
|
||||
"lint-staged": "^14.0.1",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^3.0.3",
|
||||
"typescript": "^5.2.2",
|
||||
"lint-staged": "^15.2.0",
|
||||
"postcss": "^8.4.32",
|
||||
"prettier": "^3.1.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^4.4.11",
|
||||
"vite-plugin-solid": "^2.7.0",
|
||||
"vite-plugin-solid-svg": "^0.6.4",
|
||||
"vitest": "^0.34.6"
|
||||
"vite-plugin-solid": "^2.8.0",
|
||||
"vite-plugin-solid-svg": "^0.7.0",
|
||||
"vitest": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@solidjs/meta": "^0.28.6",
|
||||
"@solidjs/router": "^0.8.3",
|
||||
"@tailwindcss/forms": "^0.5.6",
|
||||
"@tanstack/query-async-storage-persister": "^4.36.1",
|
||||
"@tanstack/query-persist-client-core": "^4.36.1",
|
||||
"@tanstack/solid-query": "^4.36.1",
|
||||
"@tanstack/solid-virtual": "^3.0.0-beta.6",
|
||||
"@textcomplete/core": "^0.1.12",
|
||||
"@textcomplete/textarea": "^0.1.12",
|
||||
"@thisbeyond/solid-dnd": "^0.7.4",
|
||||
"@types/lodash": "^4.14.199",
|
||||
"@solidjs/meta": "^0.29.3",
|
||||
"@solidjs/router": "^0.10.5",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tanstack/query-async-storage-persister": "^5.14.2",
|
||||
"@tanstack/query-persist-client-core": "^5.14.2",
|
||||
"@tanstack/solid-query": "^5.14.2",
|
||||
"@tanstack/solid-virtual": "^3.0.1",
|
||||
"@textcomplete/core": "^0.1.13",
|
||||
"@textcomplete/textarea": "^0.1.13",
|
||||
"@thisbeyond/solid-dnd": "^0.7.5",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"emoji-mart": "^5.5.2",
|
||||
"heroicons": "^2.0.18",
|
||||
"i18next": "^23.5.1",
|
||||
"i18next-browser-languagedetector": "^7.1.0",
|
||||
"heroicons": "^2.1.1",
|
||||
"i18next": "^23.7.11",
|
||||
"i18next-browser-languagedetector": "^7.2.0",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"lodash": "^4.17.21",
|
||||
"nostr-tools": "^1.16.0",
|
||||
"solid-js": "^1.7.12",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"solid-js": "^1.8.7",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
||||
14
src/App.tsx
14
src/App.tsx
@@ -1,6 +1,6 @@
|
||||
import { createEffect, onCleanup, lazy, type Component } from 'solid-js';
|
||||
|
||||
import { Routes, Route } from '@solidjs/router';
|
||||
import { HashRouter, Route } from '@solidjs/router';
|
||||
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';
|
||||
import { persistQueryClient } from '@tanstack/query-persist-client-core';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/solid-query';
|
||||
@@ -50,12 +50,12 @@ const App: Component = () => {
|
||||
return (
|
||||
<I18NextProvider i18next={i18next}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Routes>
|
||||
<Route path="/hello" element={<Hello />} />
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/:id" element={<Permalink />} />
|
||||
<Route path="/*" element={<NotFound />} />
|
||||
</Routes>
|
||||
<HashRouter>
|
||||
<Route path="/hello" component={() => <Hello />} />
|
||||
<Route path="/" component={() => <Home />} />
|
||||
<Route path="/:id" component={() => <Permalink />} />
|
||||
<Route path="/*" component={() => <NotFound />} />
|
||||
</HashRouter>
|
||||
</QueryClientProvider>
|
||||
</I18NextProvider>
|
||||
);
|
||||
|
||||
@@ -117,13 +117,13 @@ const ReactionAction = (props: { event: NostrEvent }) => {
|
||||
'text-zinc-400': !isReactedByMe() || isReactedByMeWithEmoji(),
|
||||
'hover:text-rose-400': !isReactedByMe() || isReactedByMeWithEmoji(),
|
||||
'text-rose-400':
|
||||
(isReactedByMe() && !isReactedByMeWithEmoji()) || publishReactionMutation.isLoading,
|
||||
(isReactedByMe() && !isReactedByMeWithEmoji()) || publishReactionMutation.isPending,
|
||||
}}
|
||||
>
|
||||
<button
|
||||
class="h-4 w-4"
|
||||
onClick={handleReaction}
|
||||
disabled={publishReactionMutation.isLoading}
|
||||
disabled={publishReactionMutation.isPending}
|
||||
>
|
||||
<Show when={isReactedByMe() && !isReactedByMeWithEmoji()} fallback={<HeartOutlined />}>
|
||||
<HeartSolid />
|
||||
@@ -140,7 +140,7 @@ const ReactionAction = (props: { event: NostrEvent }) => {
|
||||
'text-zinc-400': !isReactedByMe() || !isReactedByMeWithEmoji(),
|
||||
'hover:text-rose-400': !isReactedByMe() || !isReactedByMeWithEmoji(),
|
||||
'text-rose-400':
|
||||
(isReactedByMe() && isReactedByMeWithEmoji()) || publishReactionMutation.isLoading,
|
||||
(isReactedByMe() && isReactedByMeWithEmoji()) || publishReactionMutation.isPending,
|
||||
}}
|
||||
>
|
||||
<EmojiPicker onEmojiSelect={handleEmojiSelect}>
|
||||
@@ -199,10 +199,10 @@ const RepostAction = (props: { event: NostrEvent }) => {
|
||||
classList={{
|
||||
'text-zinc-400': !isRepostedByMe(),
|
||||
'hover:text-green-400': !isRepostedByMe(),
|
||||
'text-green-400': isRepostedByMe() || publishRepostMutation.isLoading,
|
||||
'text-green-400': isRepostedByMe() || publishRepostMutation.isPending,
|
||||
}}
|
||||
>
|
||||
<button class="h-4 w-4" onClick={handleRepost} disabled={publishRepostMutation.isLoading}>
|
||||
<button class="h-4 w-4" onClick={handleRepost} disabled={publishRepostMutation.isPending}>
|
||||
<ArrowPathRoundedSquare />
|
||||
</button>
|
||||
<Show when={!config().hideCount && reposts().length > 0}>
|
||||
@@ -327,7 +327,7 @@ const Actions: Component<ActionProps> = (props) => {
|
||||
|
||||
const closeModal = () => setModal(null);
|
||||
|
||||
const deleteMutation = createMutation({
|
||||
const deleteMutation = createMutation(() => ({
|
||||
mutationKey: ['deleteEvent', props.event.id],
|
||||
mutationFn: (...params: Parameters<typeof commands.deleteEvent>) =>
|
||||
commands
|
||||
@@ -348,7 +348,7 @@ const Actions: Component<ActionProps> = (props) => {
|
||||
onError: (err) => {
|
||||
console.error('failed to delete', err);
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
const menu: MenuItem[] = [
|
||||
{
|
||||
|
||||
@@ -122,8 +122,8 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
|
||||
const replyTo = () => props.replyTo && textNote(props.replyTo);
|
||||
const mode = () => props.mode ?? 'normal';
|
||||
|
||||
const publishTextNoteMutation = createMutation({
|
||||
mutationKey: ['publishTextNote'],
|
||||
const publishTextNoteMutation = createMutation(() => ({
|
||||
mutationKey: ['publishTextNote'] as const,
|
||||
mutationFn: commands.publishTextNote.bind(commands),
|
||||
onSuccess: () => {
|
||||
console.log('succeeded to post');
|
||||
@@ -133,7 +133,7 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
|
||||
onError: (err) => {
|
||||
console.error('error', err);
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
const resizeTextArea = () => {
|
||||
if (textAreaRef == null) return;
|
||||
@@ -141,8 +141,8 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
|
||||
textAreaRef.style.height = `${textAreaRef.scrollHeight}px`;
|
||||
};
|
||||
|
||||
const uploadFilesMutation = createMutation({
|
||||
mutationKey: ['uploadFiles'],
|
||||
const uploadFilesMutation = createMutation(() => ({
|
||||
mutationKey: ['uploadFiles'] as const,
|
||||
mutationFn: async (files: File[]) => {
|
||||
const uploadResults = await uploadFiles(uploadNostrBuild)(files);
|
||||
const failed: File[] = [];
|
||||
@@ -161,7 +161,7 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
|
||||
window.alert(i18n()('posting.failedToUploadFile', { filenames }));
|
||||
}
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
const taggedPubkeysWithoutMe = createMemo(() => {
|
||||
const p = getPubkey();
|
||||
@@ -197,7 +197,7 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
|
||||
|
||||
const submit = () => {
|
||||
if (text().length === 0) return;
|
||||
if (publishTextNoteMutation.isLoading) return;
|
||||
if (publishTextNoteMutation.isPending) return;
|
||||
|
||||
if (/nsec1[0-9a-zA-Z]+/.test(text())) {
|
||||
window.alert(i18n()('posting.forbiddenToIncludeNsec'));
|
||||
@@ -290,7 +290,7 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
|
||||
*/
|
||||
const handleChangeFile: JSX.EventHandler<HTMLInputElement, Event> = (ev) => {
|
||||
ev.preventDefault();
|
||||
if (uploadFilesMutation.isLoading) return;
|
||||
if (uploadFilesMutation.isPending) return;
|
||||
// if (!ensureUploaderAgreement()) return;
|
||||
|
||||
const files = [...(ev.currentTarget.files ?? [])];
|
||||
@@ -301,14 +301,14 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
|
||||
|
||||
const handleDrop: JSX.EventHandler<HTMLTextAreaElement, DragEvent> = (ev) => {
|
||||
ev.preventDefault();
|
||||
if (uploadFilesMutation.isLoading) return;
|
||||
if (uploadFilesMutation.isPending) return;
|
||||
// if (!ensureUploaderAgreement()) return;
|
||||
const files = [...(ev?.dataTransfer?.files ?? [])];
|
||||
uploadFilesMutation.mutate(files);
|
||||
};
|
||||
|
||||
const handlePaste: JSX.EventHandler<HTMLTextAreaElement, ClipboardEvent> = (ev) => {
|
||||
if (uploadFilesMutation.isLoading) return;
|
||||
if (uploadFilesMutation.isPending) return;
|
||||
|
||||
const items = [...(ev?.clipboardData?.items ?? [])];
|
||||
|
||||
@@ -333,10 +333,10 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
|
||||
|
||||
const submitDisabled = () =>
|
||||
text().trim().length === 0 ||
|
||||
publishTextNoteMutation.isLoading ||
|
||||
uploadFilesMutation.isLoading;
|
||||
publishTextNoteMutation.isPending ||
|
||||
uploadFilesMutation.isPending;
|
||||
|
||||
const fileUploadDisabled = () => uploadFilesMutation.isLoading;
|
||||
const fileUploadDisabled = () => uploadFilesMutation.isPending;
|
||||
|
||||
onMount(() => {
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -112,7 +112,7 @@ const ProfileDisplay: Component<ProfileDisplayProps> = (props) => {
|
||||
return p != null && userFollowingPubkeys().includes(p);
|
||||
};
|
||||
|
||||
const updateContactsMutation = createMutation({
|
||||
const updateContactsMutation = createMutation(() => ({
|
||||
mutationKey: ['updateContacts'],
|
||||
mutationFn: (...params: Parameters<typeof commands.updateContacts>) =>
|
||||
commands
|
||||
@@ -139,7 +139,7 @@ const ProfileDisplay: Component<ProfileDisplayProps> = (props) => {
|
||||
.then(() => myFollowingQuery.refetch())
|
||||
.catch((err) => console.error('failed to refetch contacts', err));
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
const updateContacts = async (op: 'follow' | 'unfollow', pubkey: string) => {
|
||||
try {
|
||||
@@ -312,12 +312,12 @@ const ProfileDisplay: Component<ProfileDisplayProps> = (props) => {
|
||||
{i18n()('profile.editProfile')}
|
||||
</button>
|
||||
</Match>
|
||||
<Match when={updateContactsMutation.isLoading || updatingContacts()}>
|
||||
<Match when={updateContactsMutation.isPending || updatingContacts()}>
|
||||
<span class="rounded-full border border-primary px-4 py-2 text-primary sm:text-base">
|
||||
{i18n()('general.updating')}
|
||||
</span>
|
||||
</Match>
|
||||
<Match when={myFollowingQuery.isLoading || myFollowingQuery.isFetching}>
|
||||
<Match when={myFollowingQuery.isPending || myFollowingQuery.isFetching}>
|
||||
<span class="rounded-full border border-primary px-4 py-2 text-primary sm:text-base">
|
||||
{i18n()('general.loading')}
|
||||
</span>
|
||||
@@ -329,7 +329,7 @@ const ProfileDisplay: Component<ProfileDisplayProps> = (props) => {
|
||||
onMouseEnter={() => setHoverFollowButton(true)}
|
||||
onMouseLeave={() => setHoverFollowButton(false)}
|
||||
onClick={() => unfollow()}
|
||||
disabled={updateContactsMutation.isLoading}
|
||||
disabled={updateContactsMutation.isPending}
|
||||
>
|
||||
<Show when={!hoverFollowButton()} fallback={i18n()('profile.unfollow')}>
|
||||
{i18n()('profile.followingCurrently')}
|
||||
@@ -341,7 +341,7 @@ const ProfileDisplay: Component<ProfileDisplayProps> = (props) => {
|
||||
class="w-28 rounded-full border border-primary px-4 py-2 text-primary
|
||||
hover:border-rose-400 hover:text-rose-400"
|
||||
onClick={() => follow()}
|
||||
disabled={updateContactsMutation.isLoading}
|
||||
disabled={updateContactsMutation.isPending}
|
||||
>
|
||||
{i18n()('profile.follow')}
|
||||
</button>
|
||||
@@ -357,7 +357,7 @@ const ProfileDisplay: Component<ProfileDisplayProps> = (props) => {
|
||||
</ContextMenu>
|
||||
</div>
|
||||
<Switch>
|
||||
<Match when={userFollowingQuery.isLoading}>
|
||||
<Match when={userFollowingQuery.isPending}>
|
||||
<div class="shrink-0 text-xs">{i18n()('general.loading')}</div>
|
||||
</Match>
|
||||
<Match when={followed()}>
|
||||
@@ -369,7 +369,7 @@ const ProfileDisplay: Component<ProfileDisplayProps> = (props) => {
|
||||
</div>
|
||||
<div class="flex items-start px-4 pt-2">
|
||||
<div class="h-16 shrink overflow-hidden">
|
||||
<Show when={profileQuery.isLoading}>{i18n()('general.loading')}</Show>
|
||||
<Show when={profileQuery.isPending}>{i18n()('general.loading')}</Show>
|
||||
<Show when={(profile()?.display_name?.length ?? 0) > 0}>
|
||||
<div class="truncate text-xl font-bold">{profile()?.display_name}</div>
|
||||
</Show>
|
||||
@@ -387,7 +387,7 @@ const ProfileDisplay: Component<ProfileDisplayProps> = (props) => {
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Match when={verificationQuery.isLoading}>
|
||||
<Match when={verificationQuery.isPending}>
|
||||
<span class="inline-block h-3 w-3">
|
||||
<ArrowPath />
|
||||
</span>
|
||||
|
||||
@@ -50,7 +50,7 @@ const ProfileEdit: Component<ProfileEditProps> = (props) => {
|
||||
);
|
||||
const { updateProfile } = useCommands();
|
||||
|
||||
const mutation = createMutation({
|
||||
const mutation = createMutation(() => ({
|
||||
mutationKey: ['updateProfile'],
|
||||
mutationFn: (...params: Parameters<typeof updateProfile>) =>
|
||||
updateProfile(...params).then((promeses) => Promise.allSettled(promeses.map(timeout(10000)))),
|
||||
@@ -73,12 +73,12 @@ const ProfileEdit: Component<ProfileEditProps> = (props) => {
|
||||
onError: (err) => {
|
||||
console.error('failed to delete', err);
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
const loading = () => query.isLoading || mutation.isLoading;
|
||||
const loading = () => query.isPending || mutation.isPending;
|
||||
const disabled = () => loading();
|
||||
|
||||
setInterval(() => console.log(query.isLoading, mutation.isLoading), 1000);
|
||||
setInterval(() => console.log(query.isPending, mutation.isPending), 1000);
|
||||
|
||||
const otherProperties = () =>
|
||||
omit(profile(), [
|
||||
@@ -313,7 +313,7 @@ const ProfileEdit: Component<ProfileEditProps> = (props) => {
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded bg-rose-300 p-2 font-bold text-white hover:bg-rose-400"
|
||||
disabled={mutation.isLoading}
|
||||
disabled={mutation.isPending}
|
||||
>
|
||||
{i18n()('profile.edit.save')}
|
||||
</button>
|
||||
@@ -325,7 +325,7 @@ const ProfileEdit: Component<ProfileEditProps> = (props) => {
|
||||
{i18n()('profile.edit.cancel')}
|
||||
</button>
|
||||
</div>
|
||||
<Show when={mutation.isLoading}>{i18n()('profile.edit.updating')}</Show>
|
||||
<Show when={mutation.isPending}>{i18n()('profile.edit.updating')}</Show>
|
||||
</form>
|
||||
</div>
|
||||
</BasicModal>
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
/* @refresh reload */
|
||||
import { Router, hashIntegration } from '@solidjs/router';
|
||||
import { render } from 'solid-js/web';
|
||||
|
||||
import '@/index.css';
|
||||
import App from '@/App';
|
||||
|
||||
render(
|
||||
() => (
|
||||
<Router source={hashIntegration()}>
|
||||
<App />
|
||||
</Router>
|
||||
),
|
||||
document.getElementById('root') as HTMLElement,
|
||||
);
|
||||
render(() => <App />, document.getElementById('root') as HTMLElement);
|
||||
|
||||
@@ -16,7 +16,7 @@ const useReactionMutation = (propsProvider: () => UseReactionMutationProps) => {
|
||||
|
||||
const commands = useCommands();
|
||||
|
||||
const mutation = createMutation({
|
||||
const mutation = createMutation(() => ({
|
||||
mutationKey: ['useReactionMutation', props().eventId] as const,
|
||||
mutationFn: (...params: Parameters<typeof commands.publishReaction>) =>
|
||||
commands
|
||||
@@ -43,7 +43,7 @@ const useReactionMutation = (propsProvider: () => UseReactionMutationProps) => {
|
||||
.then(() => queryClient.invalidateQueries({ queryKey }))
|
||||
.catch((err) => console.error('failed to refetch reactions', err));
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
return mutation;
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ const useRepostMutation = (propsProvider: () => UseRepostMutationProps) => {
|
||||
|
||||
const commands = useCommands();
|
||||
|
||||
const mutation = createMutation({
|
||||
const mutation = createMutation(() => ({
|
||||
mutationKey: ['useRepostMutation', props().eventId] as const,
|
||||
mutationFn: (...params: Parameters<typeof commands.publishRepost>) =>
|
||||
commands
|
||||
@@ -43,7 +43,7 @@ const useRepostMutation = (propsProvider: () => UseRepostMutationProps) => {
|
||||
.then(() => queryClient.invalidateQueries({ queryKey }))
|
||||
.catch((err) => console.error('failed to refetch repost', err));
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
return mutation;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,6 @@ export const latestEventQuery =
|
||||
queryClient: QueryClient;
|
||||
}) =>
|
||||
({ queryKey, signal }: { queryKey: K; signal?: AbortSignal }): Promise<NostrEvent | null> => {
|
||||
const prev = queryClient.getQueryData(queryKey, { stale: true }) as NostrEvent;
|
||||
const task = taskProvider(queryKey);
|
||||
if (task == null) return Promise.resolve(null);
|
||||
const promise = task.firstEventPromise().catch(() => {
|
||||
@@ -23,9 +22,12 @@ export const latestEventQuery =
|
||||
});
|
||||
task.onUpdate((events) => {
|
||||
const latest = pickLatestEvent(events);
|
||||
if (prev == null || (latest != null && compareEvents(latest, prev) >= 0)) {
|
||||
queryClient.setQueryData(queryKey, latest);
|
||||
}
|
||||
queryClient.setQueriesData<NostrEvent>({ queryKey, stale: true }, (prev) => {
|
||||
if (latest != null && (prev == null || compareEvents(latest, prev) >= 0)) {
|
||||
return latest;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
registerTask({ task, signal });
|
||||
return timeout(15000, `${JSON.stringify(queryKey)}`)(promise);
|
||||
@@ -40,13 +42,12 @@ export const eventsQuery =
|
||||
queryClient: QueryClient;
|
||||
}) =>
|
||||
({ queryKey, signal }: { queryKey: K; signal?: AbortSignal }): Promise<NostrEvent[]> => {
|
||||
const prev = queryClient.getQueryData(queryKey, { stale: true }) as NostrEvent[];
|
||||
const task = taskProvider(queryKey);
|
||||
if (task == null) return Promise.resolve([]);
|
||||
const promise = task.toUpdatePromise().catch(() => []);
|
||||
task.onUpdate((events) => {
|
||||
// TODO consider kind:5 deletion
|
||||
queryClient.setQueryData(queryKey, () => {
|
||||
queryClient.setQueriesData<NostrEvent[]>({ queryKey, stale: true }, (prev) => {
|
||||
if (prev == null) return events;
|
||||
const deduped = uniqBy([...prev, ...events], (e) => e.id);
|
||||
return sortEvents(deduped);
|
||||
|
||||
@@ -18,9 +18,9 @@ export type UseEvent = {
|
||||
const useEvent = (propsProvider: () => UseEventProps | null): UseEvent => {
|
||||
const props = createMemo(propsProvider);
|
||||
|
||||
const query = createQuery(
|
||||
() => ['useEvent', props()] as const,
|
||||
({ queryKey, signal }) => {
|
||||
const query = createQuery(() => ({
|
||||
queryKey: ['useEvent', props()] as const,
|
||||
queryFn: ({ queryKey, signal }) => {
|
||||
const [, currentProps] = queryKey;
|
||||
if (currentProps == null) return null;
|
||||
const { eventId } = currentProps;
|
||||
@@ -31,15 +31,13 @@ const useEvent = (propsProvider: () => UseEventProps | null): UseEvent => {
|
||||
registerTask({ task, signal });
|
||||
return timeout(15000, `useEvent: ${eventId}`)(promise);
|
||||
},
|
||||
{
|
||||
// Text notes never change, so they can be stored for a long time.
|
||||
// However, events tend to be unreferenced as time passes.
|
||||
staleTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
},
|
||||
);
|
||||
// Text notes never change, so they can be stored for a long time.
|
||||
// However, events tend to be unreferenced as time passes.
|
||||
staleTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
}));
|
||||
|
||||
const event = () => query.data ?? null;
|
||||
|
||||
|
||||
@@ -68,9 +68,9 @@ const useFollowings = (propsProvider: () => UseFollowingsProps | null): UseFollo
|
||||
const props = createMemo(propsProvider);
|
||||
const genQueryKey = () => ['useFollowings', props()] as const;
|
||||
|
||||
const query = createQuery(
|
||||
genQueryKey,
|
||||
latestEventQuery({
|
||||
const query = createQuery(() => ({
|
||||
queryKey: genQueryKey(),
|
||||
queryFn: latestEventQuery<ReturnType<typeof genQueryKey>>({
|
||||
taskProvider: ([, currentProps]) => {
|
||||
if (currentProps == null) return null;
|
||||
const { pubkey } = currentProps;
|
||||
@@ -78,17 +78,16 @@ const useFollowings = (propsProvider: () => UseFollowingsProps | null): UseFollo
|
||||
},
|
||||
queryClient,
|
||||
}),
|
||||
{
|
||||
staleTime: 5 * 60 * 1000, // 5 min
|
||||
cacheTime: 3 * 24 * 60 * 60 * 1000, // 3 days
|
||||
refetchOnMount: true,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchInterval: 0,
|
||||
},
|
||||
);
|
||||
staleTime: 5 * 60 * 1000, // 5 min
|
||||
cacheTime: 3 * 24 * 60 * 60 * 1000, // 3 days
|
||||
refetchOnMount: true,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchInterval: 0,
|
||||
}));
|
||||
|
||||
const invalidateFollowings = (): Promise<void> => queryClient.invalidateQueries(genQueryKey());
|
||||
const invalidateFollowings = (): Promise<void> =>
|
||||
queryClient.invalidateQueries({ queryKey: genQueryKey() });
|
||||
|
||||
return { ...buildMethods(() => query.data), invalidateFollowings, query };
|
||||
};
|
||||
|
||||
@@ -30,9 +30,9 @@ const useParameterizedReplaceableEvent = (
|
||||
const props = createMemo(propsProvider);
|
||||
const genQueryKey = () => ['useFollowings', props()] as const;
|
||||
|
||||
const query = createQuery(
|
||||
genQueryKey,
|
||||
({ queryKey, signal }) => {
|
||||
const query = createQuery(() => ({
|
||||
queryKey: genQueryKey(),
|
||||
queryFn: ({ queryKey, signal }) => {
|
||||
console.debug('useFollowings');
|
||||
const [, currentProps] = queryKey;
|
||||
if (currentProps == null) return Promise.resolve(null);
|
||||
@@ -59,11 +59,9 @@ const useParameterizedReplaceableEvent = (
|
||||
`useParameterizedReplaceableEvent: ${kind}:${author}:${identifier}`,
|
||||
)(promise);
|
||||
},
|
||||
{
|
||||
staleTime: 5 * 60 * 1000, // 5 min
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
},
|
||||
);
|
||||
staleTime: 5 * 60 * 1000, // 5 min
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
}));
|
||||
|
||||
const event = () => query.data ?? null;
|
||||
|
||||
|
||||
@@ -27,16 +27,14 @@ export type UseProfiles = {
|
||||
queries: CreateQueryResult<NostrEvent | null>[];
|
||||
};
|
||||
|
||||
type UseProfileQueryKey = readonly ['useProfile', UseProfileProps | null];
|
||||
|
||||
const useProfile = (propsProvider: () => UseProfileProps | null): UseProfile => {
|
||||
const queryClient = useQueryClient();
|
||||
const props = createMemo(propsProvider);
|
||||
const genQueryKey = createMemo((): UseProfileQueryKey => ['useProfile', props()] as const);
|
||||
const genQueryKey = createMemo(() => ['useProfile', props()] as const);
|
||||
|
||||
const query = createQuery(
|
||||
genQueryKey,
|
||||
latestEventQuery({
|
||||
const query = createQuery(() => ({
|
||||
queryKey: genQueryKey(),
|
||||
queryFn: latestEventQuery<ReturnType<typeof genQueryKey>>({
|
||||
taskProvider: ([, currentProps]) => {
|
||||
if (currentProps == null) return null;
|
||||
const { pubkey } = currentProps;
|
||||
@@ -44,15 +42,13 @@ const useProfile = (propsProvider: () => UseProfileProps | null): UseProfile =>
|
||||
},
|
||||
queryClient,
|
||||
}),
|
||||
{
|
||||
// Profiles are updated occasionally, so a short staleTime is used here.
|
||||
// cacheTime is long so that the user see profiles instantly.
|
||||
staleTime: 5 * 60 * 1000, // 5 min
|
||||
cacheTime: 3 * 24 * 60 * 60 * 1000, // 3 days
|
||||
refetchInterval: 5 * 60 * 1000, // 5 min
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
);
|
||||
// Profiles are updated occasionally, so a short staleTime is used here.
|
||||
// cacheTime is long so that the user see profiles instantly.
|
||||
staleTime: 5 * 60 * 1000, // 5 min
|
||||
cacheTime: 3 * 24 * 60 * 60 * 1000, // 3 days
|
||||
refetchInterval: 5 * 60 * 1000, // 5 min
|
||||
refetchOnWindowFocus: false,
|
||||
}));
|
||||
|
||||
const event = () => query.data;
|
||||
|
||||
@@ -62,7 +58,8 @@ const useProfile = (propsProvider: () => UseProfileProps | null): UseProfile =>
|
||||
return safeParseProfile(content);
|
||||
});
|
||||
|
||||
const invalidateProfile = (): Promise<void> => queryClient.invalidateQueries(genQueryKey());
|
||||
const invalidateProfile = (): Promise<void> =>
|
||||
queryClient.invalidateQueries({ queryKey: genQueryKey() });
|
||||
|
||||
return { profile, event, invalidateProfile, query };
|
||||
};
|
||||
|
||||
@@ -30,9 +30,9 @@ const useReactions = (propsProvider: () => UseReactionsProps | null): UseReactio
|
||||
const queryClient = useQueryClient();
|
||||
const genQueryKey = createMemo(() => queryKeyUseReactions(propsProvider()));
|
||||
|
||||
const query = createQuery(
|
||||
genQueryKey,
|
||||
eventsQuery({
|
||||
const query = createQuery(() => ({
|
||||
queryKey: genQueryKey(),
|
||||
queryFn: eventsQuery<ReturnType<typeof queryKeyUseReactions>>({
|
||||
taskProvider: ([, currentProps]) => {
|
||||
if (currentProps == null) return null;
|
||||
const { eventId: mentionedEventId } = currentProps;
|
||||
@@ -40,12 +40,10 @@ const useReactions = (propsProvider: () => UseReactionsProps | null): UseReactio
|
||||
},
|
||||
queryClient,
|
||||
}),
|
||||
{
|
||||
staleTime: 1 * 60 * 1000, // 1 min
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchInterval: 1 * 60 * 1000, // 1 min
|
||||
},
|
||||
);
|
||||
staleTime: 1 * 60 * 1000, // 1 min
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchInterval: 1 * 60 * 1000, // 1 min
|
||||
}));
|
||||
|
||||
const reactions = () => {
|
||||
const data = query.data ?? [];
|
||||
|
||||
@@ -25,9 +25,9 @@ const useReposts = (propsProvider: () => UseRepostsProps): UseReposts => {
|
||||
const props = createMemo(propsProvider);
|
||||
const genQueryKey = createMemo(() => queryKeyUseReposts(props()));
|
||||
|
||||
const query = createQuery(
|
||||
genQueryKey,
|
||||
eventsQuery({
|
||||
const query = createQuery(() => ({
|
||||
queryKey: genQueryKey(),
|
||||
queryFn: eventsQuery<ReturnType<typeof genQueryKey>>({
|
||||
taskProvider: ([, currentProps]) => {
|
||||
if (currentProps == null) return null;
|
||||
const { eventId: mentionedEventId } = currentProps;
|
||||
@@ -35,12 +35,10 @@ const useReposts = (propsProvider: () => UseRepostsProps): UseReposts => {
|
||||
},
|
||||
queryClient,
|
||||
}),
|
||||
{
|
||||
staleTime: 1 * 60 * 1000, // 1 min
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchInterval: 1 * 60 * 1000, // 1 min
|
||||
},
|
||||
);
|
||||
staleTime: 1 * 60 * 1000, // 1 min
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchInterval: 1 * 60 * 1000, // 1 min
|
||||
}));
|
||||
|
||||
const reposts = () => {
|
||||
const data = query.data ?? [];
|
||||
|
||||
@@ -14,19 +14,19 @@ export type UseVerification = {
|
||||
|
||||
const useVerification = (propsProvider: () => UseVerificationProps | null): UseVerification => {
|
||||
const props = createMemo(propsProvider);
|
||||
const query = createQuery(
|
||||
() => ['useVerification', props()] as const,
|
||||
({ queryKey }) => {
|
||||
const genQueryKey = () => ['useVerification', props()] as const;
|
||||
|
||||
const query = createQuery(() => ({
|
||||
queryKey: genQueryKey(),
|
||||
queryFn: ({ queryKey }) => {
|
||||
const [, currentProps] = queryKey;
|
||||
if (currentProps == null) return Promise.resolve(null);
|
||||
const { nip05: nip05string } = currentProps;
|
||||
return nip05.queryProfile(nip05string);
|
||||
},
|
||||
{
|
||||
staleTime: 30 * 60 * 1000, // 30 min
|
||||
cacheTime: 24 * 60 * 60 * 1000, // 24 hour
|
||||
},
|
||||
);
|
||||
staleTime: 30 * 60 * 1000, // 30 min
|
||||
cacheTime: 24 * 60 * 60 * 1000, // 24 hour
|
||||
}));
|
||||
|
||||
const verification = () => query?.data ?? null;
|
||||
|
||||
|
||||
@@ -56,12 +56,15 @@ export type UseOgpProps = {
|
||||
|
||||
export const useOgp = (propsProvider: () => UseOgpProps) => {
|
||||
const genQueryKey = () => ['useOgp', propsProvider().url] as const;
|
||||
const query = createQuery(genQueryKey, ({ queryKey: [, url] }) => fetchOgpContent(url), {
|
||||
|
||||
const query = createQuery(() => ({
|
||||
queryKey: genQueryKey(),
|
||||
queryFn: ({ queryKey: [, url] }) => fetchOgpContent(url),
|
||||
staleTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
});
|
||||
}));
|
||||
|
||||
const ogp = () => query.data;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user