mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-10 04:39:19 +02:00
convert to typescript
This commit is contained in:
parent
27260a9f9b
commit
40352f77c7
@ -8,6 +8,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="src/index.jsx"></script>
|
||||
<script type="module" src="src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
16
package.json
16
package.json
@ -5,14 +5,9 @@
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "vite serve",
|
||||
"build": "vite build",
|
||||
"build": "tsc && vite build",
|
||||
"format": "prettier --ignore-path .gitignore -w ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.8.1",
|
||||
"vite": "^4.0.2",
|
||||
"vite-plugin-pwa": "^0.14.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chakra-ui/icons": "^2.0.14",
|
||||
"@chakra-ui/react": "^2.4.4",
|
||||
@ -29,5 +24,14 @@
|
||||
"react-router-dom": "^6.5.0",
|
||||
"react-use": "^17.4.0",
|
||||
"rxjs": "^7.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@vitejs/plugin-react": "^3.0.0",
|
||||
"prettier": "^2.8.1",
|
||||
"typescript": "^4.9.4",
|
||||
"vite": "^4.0.2",
|
||||
"vite-plugin-pwa": "^0.14.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
@ -10,7 +11,6 @@ import {
|
||||
Table,
|
||||
Thead,
|
||||
Tbody,
|
||||
Tfoot,
|
||||
Tr,
|
||||
Th,
|
||||
Td,
|
||||
@ -19,11 +19,11 @@ import {
|
||||
useDisclosure,
|
||||
Badge,
|
||||
} from "@chakra-ui/react";
|
||||
import React, { useState } from "react";
|
||||
import { useInterval } from "react-use";
|
||||
import { Relay } from "../services/relays";
|
||||
import relayPool from "../services/relays/relay-pool";
|
||||
|
||||
const getRelayStatusText = (relay) => {
|
||||
const getRelayStatusText = (relay: Relay) => {
|
||||
if (relay.connecting) return "Connecting...";
|
||||
if (relay.connected) return "Connected";
|
||||
if (relay.closing) return "Disconnecting...";
|
||||
@ -32,7 +32,7 @@ const getRelayStatusText = (relay) => {
|
||||
|
||||
export const ConnectedRelays = () => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [relays, setRelays] = useState([]);
|
||||
const [relays, setRelays] = useState<Relay[]>([]);
|
||||
|
||||
useInterval(() => {
|
||||
setRelays(relayPool.getRelays());
|
@ -1,5 +1,8 @@
|
||||
import React from "react";
|
||||
import { ErrorBoundary as ErrorBoundaryHelper } from "react-error-boundary";
|
||||
import {
|
||||
ErrorBoundary as ErrorBoundaryHelper,
|
||||
FallbackProps,
|
||||
} from "react-error-boundary";
|
||||
import {
|
||||
Alert,
|
||||
AlertIcon,
|
||||
@ -7,7 +10,7 @@ import {
|
||||
AlertDescription,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
export function ErrorFallback({ error, resetErrorBoundary }) {
|
||||
export function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
return (
|
||||
<Alert status="error">
|
||||
<AlertIcon />
|
||||
@ -17,7 +20,12 @@ export function ErrorFallback({ error, resetErrorBoundary }) {
|
||||
);
|
||||
}
|
||||
|
||||
export const ErrorBoundary = ({ children, ...props }) => (
|
||||
export const ErrorBoundary = ({
|
||||
children,
|
||||
...props
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<ErrorBoundaryHelper FallbackComponent={ErrorFallback} {...props}>
|
||||
{children}
|
||||
</ErrorBoundaryHelper>
|
@ -14,7 +14,7 @@ import {
|
||||
import { useAsync } from "react-use";
|
||||
import { getRelaysEventWasSeen } from "../services/events-seen";
|
||||
|
||||
export const EventSeenOn = ({ id }) => {
|
||||
export const EventSeenOn = ({ id }: { id: string }) => {
|
||||
const { value } = useAsync(() => getRelaysEventWasSeen(id), [id]);
|
||||
|
||||
if (!value) return null;
|
@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom";
|
||||
import { ErrorBoundary } from "./error-boundary";
|
||||
import { ConnectedRelays } from "./connected-relays";
|
||||
|
||||
export const Page = ({ children }) => {
|
||||
export const Page = ({ children }: {children: React.ReactNode}) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
@ -10,8 +10,15 @@ import {
|
||||
ModalOverlay,
|
||||
} from "@chakra-ui/react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { NostrEvent } from "../types/nostr-event";
|
||||
|
||||
export const PostModal = ({ event, onClose, isOpen }) => (
|
||||
export type PostModalProps = {
|
||||
event: NostrEvent;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export const PostModal = ({ event, onClose, isOpen }: PostModalProps) => (
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="6xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
@ -8,6 +8,7 @@ import {
|
||||
CardHeader,
|
||||
Flex,
|
||||
Heading,
|
||||
HStack,
|
||||
Text,
|
||||
useDisclosure,
|
||||
VStack,
|
||||
@ -16,9 +17,12 @@ import ReactMarkdown from "react-markdown";
|
||||
import { Link } from "react-router-dom";
|
||||
import moment from "moment";
|
||||
import { PostModal } from "./post-modal";
|
||||
import { EventSeenOn } from "./event-seen-on";
|
||||
import { NostrEvent } from "../types/nostr-event";
|
||||
|
||||
export const Post = ({ event }) => {
|
||||
export type PostProps = {
|
||||
event: NostrEvent;
|
||||
};
|
||||
export const Post = ({ event }: PostProps) => {
|
||||
const { isOpen, onClose, onOpen } = useDisclosure();
|
||||
|
||||
const isLong = event.content.length > 800;
|
||||
@ -26,7 +30,7 @@ export const Post = ({ event }) => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Flex spacing="4">
|
||||
<HStack spacing="4">
|
||||
<Flex flex="1" gap="4" alignItems="center" flexWrap="wrap">
|
||||
<Avatar name="Segun Adebayo" src="https://bit.ly/sage-adebayo" />
|
||||
|
||||
@ -37,7 +41,7 @@ export const Post = ({ event }) => {
|
||||
<Text>{moment(event.created_at * 1000).fromNow()}</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</HStack>
|
||||
</CardHeader>
|
||||
<CardBody pt={0}>
|
||||
<VStack alignItems="flex-start" justifyContent="stretch">
|
@ -1,9 +1,14 @@
|
||||
import { useRef } from "react";
|
||||
import { useDeepCompareEffect, useMount, useUnmount } from "react-use";
|
||||
import { Subscription } from "../services/subscriptions";
|
||||
import { NostrQuery } from "../types/nostr-query";
|
||||
|
||||
export function useSubscription(urls, query, name) {
|
||||
const sub = useRef(null);
|
||||
export function useSubscription(
|
||||
urls: string[],
|
||||
query: NostrQuery,
|
||||
name?: string
|
||||
) {
|
||||
const sub = useRef<Subscription | null>(null);
|
||||
sub.current = sub.current || new Subscription(urls, query, name);
|
||||
|
||||
useMount(() => {
|
||||
@ -16,5 +21,5 @@ export function useSubscription(urls, query, name) {
|
||||
if (sub.current) sub.current.close();
|
||||
});
|
||||
|
||||
return sub.current;
|
||||
return sub.current as Subscription;
|
||||
}
|
@ -4,7 +4,9 @@ import { App } from "./app";
|
||||
import { Providers } from "./providers";
|
||||
import "./services/events-seen";
|
||||
|
||||
const root = createRoot(document.getElementById("root"));
|
||||
const element = document.getElementById("root");
|
||||
if (!element) throw new Error("missing mount point");
|
||||
const root = createRoot(element);
|
||||
root.render(
|
||||
<Providers>
|
||||
<App />
|
@ -4,7 +4,7 @@ import { RelaysProvider } from "./relay-provider";
|
||||
import { HashRouter } from "react-router-dom";
|
||||
import theme from "../theme";
|
||||
|
||||
export const Providers = ({ children }) => (
|
||||
export const Providers = ({ children }: { children: React.ReactNode }) => (
|
||||
<ChakraProvider theme={theme}>
|
||||
<HashRouter>
|
||||
<RelaysProvider>{children}</RelaysProvider>
|
@ -8,17 +8,17 @@ import React, {
|
||||
import settingsService from "../services/settings";
|
||||
|
||||
const relaysContext = createContext({
|
||||
relays: [],
|
||||
relays: [] as string[],
|
||||
loading: true,
|
||||
overwriteRelays: () => {},
|
||||
overwriteRelays: (urls: string[]) => {},
|
||||
});
|
||||
|
||||
export function useRelays() {
|
||||
return useContext(relaysContext);
|
||||
}
|
||||
|
||||
export const RelaysProvider = ({ children }) => {
|
||||
const [relays, setRelays] = useState([]);
|
||||
export const RelaysProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [relays, setRelays] = useState<string[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const update = useCallback(async () => {
|
||||
@ -27,7 +27,7 @@ export const RelaysProvider = ({ children }) => {
|
||||
}, [setRelays]);
|
||||
|
||||
const overwriteRelays = useCallback(
|
||||
async (urls) => {
|
||||
async (urls: string[]) => {
|
||||
if (urls) await settingsService.setRelays(urls);
|
||||
await update();
|
||||
},
|
@ -1,9 +0,0 @@
|
||||
import { openDB } from "idb";
|
||||
import { upgrade } from "./migrations";
|
||||
|
||||
const version = 1;
|
||||
const db = await openDB("storage", version, {
|
||||
upgrade,
|
||||
});
|
||||
|
||||
export default db;
|
50
src/services/db/index.ts
Normal file
50
src/services/db/index.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { openDB } from "idb";
|
||||
|
||||
import { IDBPDatabase, IDBPTransaction, StoreNames } from "idb";
|
||||
import { CustomSchema } from "./schema";
|
||||
|
||||
type MigrationFunction = (
|
||||
database: IDBPDatabase<CustomSchema>,
|
||||
transaction: IDBPTransaction<
|
||||
CustomSchema,
|
||||
StoreNames<CustomSchema>[],
|
||||
"versionchange"
|
||||
>,
|
||||
event: IDBVersionChangeEvent
|
||||
) => void;
|
||||
|
||||
const MIGRATIONS: MigrationFunction[] = [
|
||||
// 0 -> 1
|
||||
function (db, transaction, event) {
|
||||
db.createObjectStore("user-metadata", {
|
||||
keyPath: "pubkey",
|
||||
});
|
||||
|
||||
const eventsSeen = db.createObjectStore("events-seen", { keyPath: "id" });
|
||||
eventsSeen.createIndex("lastSeen", "lastSeen");
|
||||
|
||||
// db.createObjectStore("contacts", {
|
||||
// keyPath: "pubkey",
|
||||
// });
|
||||
|
||||
// setup data
|
||||
const settings = db.createObjectStore("settings");
|
||||
settings.put(["wss://nostr.rdfriedl.com"], "relays");
|
||||
},
|
||||
];
|
||||
|
||||
const version = 1;
|
||||
const db = await openDB<CustomSchema>("storage", version, {
|
||||
upgrade(db, oldVersion, newVersion, transaction, event) {
|
||||
// TODO: why is newVersion sometimes null?
|
||||
// @ts-ignore
|
||||
for (let i = oldVersion; i <= newVersion; i++) {
|
||||
if (MIGRATIONS[i]) {
|
||||
console.log(`Running database migration ${i}`);
|
||||
MIGRATIONS[i](db, transaction, event);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default db;
|
@ -1,29 +0,0 @@
|
||||
const MIGRATIONS = [
|
||||
// 0 -> 1
|
||||
function (db, transaction, event) {
|
||||
const userMetadata = db.createObjectStore("user-metadata", {
|
||||
keyPath: "pubkey",
|
||||
});
|
||||
userMetadata.createIndex("id", "id", { unique: true });
|
||||
|
||||
const eventsSeen = db.createObjectStore("events-seen", { keyPath: "id" });
|
||||
eventsSeen.createIndex("lastSeen", "lastSeen");
|
||||
|
||||
db.createObjectStore("contacts", {
|
||||
keyPath: "pubkey",
|
||||
});
|
||||
|
||||
// setup data
|
||||
const settings = db.createObjectStore("settings");
|
||||
settings.put(["wss://nostr.rdfriedl.com"], "relays");
|
||||
},
|
||||
];
|
||||
|
||||
export function upgrade(db, oldVersion, newVersion, transaction, event) {
|
||||
for (let i = oldVersion; i <= newVersion; i++) {
|
||||
if (MIGRATIONS[i]) {
|
||||
console.log(`Running database migration ${i}`);
|
||||
MIGRATIONS[i](db, transaction, event);
|
||||
}
|
||||
}
|
||||
}
|
21
src/services/db/schema.ts
Normal file
21
src/services/db/schema.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { DBSchema } from "idb";
|
||||
|
||||
export interface CustomSchema extends DBSchema {
|
||||
"user-metadata": {
|
||||
key: string;
|
||||
value: any;
|
||||
};
|
||||
"events-seen": {
|
||||
key: string;
|
||||
value: {
|
||||
id: string;
|
||||
relays: string[];
|
||||
lastSeen: Date;
|
||||
};
|
||||
indexes: { lastSeen: Date };
|
||||
};
|
||||
settings: {
|
||||
key: string;
|
||||
value: any;
|
||||
};
|
||||
}
|
@ -22,6 +22,6 @@ relayPool.onRelayCreated.subscribe((relay) => {
|
||||
});
|
||||
});
|
||||
|
||||
export async function getRelaysEventWasSeen(id) {
|
||||
export async function getRelaysEventWasSeen(id: string) {
|
||||
return await db.get("events-seen", id);
|
||||
}
|
@ -3,28 +3,28 @@ import { Relay } from "./relay";
|
||||
import settingsService from "../settings";
|
||||
|
||||
export class RelayPool {
|
||||
relays = new Map();
|
||||
relayClaims = new Map();
|
||||
onRelayCreated = new Subject();
|
||||
relays = new Map<string, Relay>();
|
||||
relayClaims = new Map<string, Set<any>>();
|
||||
onRelayCreated = new Subject<Relay>();
|
||||
|
||||
getRelays() {
|
||||
return Array.from(this.relays.values());
|
||||
}
|
||||
getRelayClaims(url) {
|
||||
getRelayClaims(url: string) {
|
||||
if (!this.relayClaims.has(url)) {
|
||||
this.relayClaims.set(url, new Set());
|
||||
}
|
||||
return this.relayClaims.get(url);
|
||||
return this.relayClaims.get(url) as Set<any>;
|
||||
}
|
||||
|
||||
requestRelay(url, connect = true) {
|
||||
requestRelay(url: string, connect = true) {
|
||||
if (!this.relays.has(url)) {
|
||||
const newRelay = new Relay(url);
|
||||
this.relays.set(url, newRelay);
|
||||
this.onRelayCreated.next(newRelay);
|
||||
}
|
||||
|
||||
const relay = this.relays.get(url);
|
||||
const relay = this.relays.get(url) as Relay;
|
||||
if (connect && !relay.okay) {
|
||||
relay.open();
|
||||
}
|
||||
@ -49,10 +49,10 @@ export class RelayPool {
|
||||
}
|
||||
|
||||
// id can be anything
|
||||
addClaim(url, id) {
|
||||
addClaim(url: string, id: any) {
|
||||
this.getRelayClaims(url).add(id);
|
||||
}
|
||||
removeClaim(url, id) {
|
||||
removeClaim(url: string, id: any) {
|
||||
this.getRelayClaims(url).delete(id);
|
||||
}
|
||||
|
||||
@ -68,6 +68,7 @@ export class RelayPool {
|
||||
const relayPool = new RelayPool();
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
// @ts-ignore
|
||||
window.relayPool = relayPool;
|
||||
}
|
||||
|
@ -1,7 +1,26 @@
|
||||
import { Subject } from "rxjs";
|
||||
import { IncomingNostrEvent, NostrEvent } from "../../types/nostr-event";
|
||||
import { NostrOutgoingMessage } from "../../types/nostr-query";
|
||||
|
||||
export type IncomingEvent = {
|
||||
type: "EVENT";
|
||||
subId: string;
|
||||
body: NostrEvent;
|
||||
};
|
||||
export type IncomingNotice = {
|
||||
type: "NOTICE";
|
||||
message: string;
|
||||
};
|
||||
|
||||
export class Relay {
|
||||
constructor(url) {
|
||||
url: string;
|
||||
onOpen: Subject<Relay>;
|
||||
onClose: Subject<Relay>;
|
||||
onEvent: Subject<IncomingEvent>;
|
||||
onNotice: Subject<IncomingNotice>;
|
||||
ws?: WebSocket;
|
||||
|
||||
constructor(url: string) {
|
||||
this.url = url;
|
||||
|
||||
this.onOpen = new Subject();
|
||||
@ -30,9 +49,9 @@ export class Relay {
|
||||
};
|
||||
this.ws.onmessage = this.handleMessage.bind(this);
|
||||
}
|
||||
send(json) {
|
||||
send(json: NostrOutgoingMessage) {
|
||||
if (this.connected) {
|
||||
this.ws.send(JSON.stringify(json));
|
||||
this.ws?.send(JSON.stringify(json));
|
||||
}
|
||||
}
|
||||
close() {
|
||||
@ -58,20 +77,20 @@ export class Relay {
|
||||
return this.ws?.readyState;
|
||||
}
|
||||
|
||||
handleMessage(event) {
|
||||
handleMessage(event: MessageEvent<string>) {
|
||||
// skip empty events
|
||||
if (!event.data) return;
|
||||
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
const data: IncomingNostrEvent = JSON.parse(event.data);
|
||||
const type = data[0];
|
||||
|
||||
switch (type) {
|
||||
case "EVENT":
|
||||
this.onEvent.next({ type, subId: data[1], body: data[2] }, this);
|
||||
this.onEvent.next({ type, subId: data[1], body: data[2] });
|
||||
break;
|
||||
case "NOTICE":
|
||||
this.onNotice.next({ type, message: data[1] }, this);
|
||||
this.onNotice.next({ type, message: data[1] });
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
@ -1,10 +1,10 @@
|
||||
import db from "./db";
|
||||
|
||||
export async function getRelays() {
|
||||
export async function getRelays(): Promise<string[]> {
|
||||
return await db.get("settings", "relays");
|
||||
}
|
||||
export async function setRelays(relays = []) {
|
||||
return await db.put("settings", relays, "relays");
|
||||
export async function setRelays(relays: string[] = []) {
|
||||
await db.put("settings", relays, "relays");
|
||||
}
|
||||
|
||||
const settingsService = {
|
||||
@ -13,6 +13,7 @@ const settingsService = {
|
||||
};
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
// @ts-ignore
|
||||
window.settingsService = settingsService;
|
||||
}
|
||||
|
@ -1,16 +1,24 @@
|
||||
import { Subject } from "rxjs";
|
||||
import { Subject, SubscriptionLike } from "rxjs";
|
||||
import { NostrEvent } from "../types/nostr-event";
|
||||
import { NostrOutgoingMessage, NostrQuery } from "../types/nostr-query";
|
||||
import { Relay } from "./relays";
|
||||
import { IncomingEvent } from "./relays/relay";
|
||||
import relayPool from "./relays/relay-pool";
|
||||
import settingsService from "./settings";
|
||||
|
||||
export class Subscription {
|
||||
static OPEN = "open";
|
||||
static CLOSED = "closed";
|
||||
|
||||
id: string;
|
||||
name?: string;
|
||||
query?: NostrQuery;
|
||||
relayUrls: string[];
|
||||
relays: Relay[];
|
||||
state = Subscription.CLOSED;
|
||||
onEvent = new Subject();
|
||||
cleanup = [];
|
||||
onEvent = new Subject<NostrEvent>();
|
||||
cleanup: SubscriptionLike[] = [];
|
||||
|
||||
constructor(relayUrls, query, name) {
|
||||
constructor(relayUrls: string[], query?: NostrQuery, name?: string) {
|
||||
this.id = String(Math.floor(Math.random() * 1000000));
|
||||
this.query = query;
|
||||
this.name = name;
|
||||
@ -18,22 +26,23 @@ export class Subscription {
|
||||
|
||||
this.relays = relayUrls.map((url) => relayPool.requestRelay(url));
|
||||
}
|
||||
handleOpen(relay) {
|
||||
handleOpen(relay: Relay) {
|
||||
if (!this.query) return;
|
||||
// when the relay connects send the req event
|
||||
relay.send(["REQ", this.id, this.query]);
|
||||
}
|
||||
handleEvent(event) {
|
||||
handleEvent(event: IncomingEvent) {
|
||||
if (event.subId === this.id) {
|
||||
this.onEvent.next(event.body);
|
||||
}
|
||||
}
|
||||
send(message) {
|
||||
send(message: NostrOutgoingMessage) {
|
||||
for (const relay of this.relays) {
|
||||
relay.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
setQuery(query) {
|
||||
setQuery(query: NostrQuery) {
|
||||
this.query = query;
|
||||
|
||||
// if open, than update remote subscription
|
||||
@ -75,8 +84,3 @@ export class Subscription {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function createSubscription(query) {
|
||||
const urls = await settingsService.getRelays();
|
||||
return new Subscription(urls, query);
|
||||
}
|
@ -1,22 +1,14 @@
|
||||
import { BehaviorSubject, Subject } from "rxjs";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { NostrEvent } from "../types/nostr-event";
|
||||
import settingsService from "./settings";
|
||||
import { Subscription } from "./subscriptions";
|
||||
|
||||
function waitOnSignal(signal) {
|
||||
return new Promise((res) => {
|
||||
const listener = (event) => {
|
||||
signal.removeListener(listener);
|
||||
res(event);
|
||||
};
|
||||
signal.addListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
class UserMetadata {
|
||||
requests = new Map();
|
||||
requests = new Map<string, BehaviorSubject<NostrEvent | null>>();
|
||||
subscription: Subscription;
|
||||
|
||||
constructor(relayUrls = []) {
|
||||
this.subscription = new Subscription(relayUrls, null, "user-metadata");
|
||||
constructor(relayUrls: string[] = []) {
|
||||
this.subscription = new Subscription(relayUrls, undefined, "user-metadata");
|
||||
|
||||
this.subscription.onEvent.subscribe((event) => {
|
||||
try {
|
||||
@ -30,9 +22,9 @@ class UserMetadata {
|
||||
}, 1000 * 10);
|
||||
}
|
||||
|
||||
requestUserMetadata(pubkey) {
|
||||
requestUserMetadata(pubkey: string) {
|
||||
if (!this.requests.has(pubkey)) {
|
||||
this.requests.set(pubkey, new BehaviorSubject(null));
|
||||
this.requests.set(pubkey, new BehaviorSubject<NostrEvent | null>(null));
|
||||
this.updateSubscription();
|
||||
}
|
||||
return this.requests.get(pubkey);
|
||||
@ -69,6 +61,7 @@ class UserMetadata {
|
||||
const userMetadata = new UserMetadata(await settingsService.getRelays());
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
// @ts-ignore
|
||||
window.userMetadata = userMetadata;
|
||||
}
|
||||
|
13
src/types/nostr-event.ts
Normal file
13
src/types/nostr-event.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export type NostrEvent = {
|
||||
id: string;
|
||||
pubkey: string;
|
||||
created_at: number;
|
||||
kind: number;
|
||||
tags: any[];
|
||||
content: string;
|
||||
sig: string;
|
||||
};
|
||||
|
||||
export type IncomingNostrEvent =
|
||||
| ["EVENT", string, NostrEvent]
|
||||
| ["NOTICE", string];
|
21
src/types/nostr-query.ts
Normal file
21
src/types/nostr-query.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { NostrEvent } from "./nostr-event";
|
||||
|
||||
export type NostrOutgoingEvent = ["EVENT", NostrEvent];
|
||||
export type NostrOutgoingRequest = ["REQ", string, NostrQuery];
|
||||
export type NostrOutgoingClose = ["CLOSE", string];
|
||||
|
||||
export type NostrOutgoingMessage =
|
||||
| NostrOutgoingEvent
|
||||
| NostrOutgoingRequest
|
||||
| NostrOutgoingClose;
|
||||
|
||||
export type NostrQuery = {
|
||||
ids?: string[];
|
||||
authors?: string[];
|
||||
kinds?: number[];
|
||||
// "#e": <a list of event ids that are referenced in an "e" tag>,
|
||||
// "#p": <a list of pubkeys that are referenced in a "p" tag>,
|
||||
since?: number;
|
||||
until?: number;
|
||||
limit?: number;
|
||||
};
|
@ -4,10 +4,11 @@ import { useSubscription } from "../../hooks/use-subscription";
|
||||
import { useRelays } from "../../providers/relay-provider";
|
||||
import { Post } from "../../components/post";
|
||||
import moment from "moment/moment";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
|
||||
export const GlobalView = () => {
|
||||
const { relays } = useRelays();
|
||||
const [events, setEvents] = useState({});
|
||||
const [events, setEvents] = useState<Record<string, NostrEvent>>({});
|
||||
|
||||
const sub = useSubscription(
|
||||
relays,
|
@ -6,14 +6,14 @@ import {
|
||||
Stack,
|
||||
Textarea,
|
||||
} from "@chakra-ui/react";
|
||||
import React, { useState } from "react";
|
||||
import React, { SyntheticEvent, useState } from "react";
|
||||
import { useRelays } from "../providers/relay-provider";
|
||||
|
||||
export const SettingsView = () => {
|
||||
const { relays, overwriteRelays } = useRelays();
|
||||
const [relayUrls, setRelayUrls] = useState(relays.join("\n"));
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
const handleSubmit = async (event: SyntheticEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
const newRelays = relayUrls
|
||||
.split("\n")
|
@ -13,22 +13,23 @@ import { useObservable } from "react-use";
|
||||
import userMetadata from "../../services/user-metadata";
|
||||
|
||||
export const UserView = () => {
|
||||
const params = useParams();
|
||||
|
||||
if (!params.pubkey) {
|
||||
const { pubkey } = useParams();
|
||||
if (!pubkey) {
|
||||
// TODO: better 404
|
||||
throw new Error("No pubkey");
|
||||
}
|
||||
|
||||
const observable = useMemo(
|
||||
() => userMetadata.requestUserMetadata(params.pubkey),
|
||||
[params.pubkey]
|
||||
() => userMetadata.requestUserMetadata(pubkey),
|
||||
[pubkey]
|
||||
);
|
||||
// @ts-ignore
|
||||
const metadata = useObservable(observable);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading>{metadata?.name ?? params.pubkey}</Heading>
|
||||
{/* @ts-ignore */}
|
||||
<Heading>{metadata?.name ?? pubkey}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>Posts</Tab>
|
||||
@ -38,7 +39,7 @@ export const UserView = () => {
|
||||
|
||||
<TabPanels>
|
||||
<TabPanel>
|
||||
<UserPostsTab pubkey={params.pubkey} />
|
||||
<UserPostsTab pubkey={pubkey} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<p>two!</p>
|
@ -3,11 +3,12 @@ import { SkeletonText } from "@chakra-ui/react";
|
||||
import settingsService from "../../services/settings";
|
||||
import { useSubscription } from "../../hooks/use-subscription";
|
||||
import { Post } from "../../components/post";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
|
||||
const relayUrls = await settingsService.getRelays();
|
||||
|
||||
export const UserPostsTab = ({ pubkey }) => {
|
||||
const [events, setEvents] = useState({});
|
||||
export const UserPostsTab = ({ pubkey }: { pubkey: string }) => {
|
||||
const [events, setEvents] = useState<Record<string, NostrEvent>>({});
|
||||
|
||||
const sub = useSubscription(
|
||||
relayUrls,
|
||||
@ -36,5 +37,11 @@ export const UserPostsTab = ({ pubkey }) => {
|
||||
return <SkeletonText />;
|
||||
}
|
||||
|
||||
return timeline.map((event) => <Post key={event.id} event={event} />);
|
||||
return (
|
||||
<>
|
||||
{timeline.map((event) => (
|
||||
<Post key={event.id} event={event} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,41 +0,0 @@
|
||||
// import React, { useEffect, useState } from "react";
|
||||
// import { Card, CardBody, SkeletonText } from "@chakra-ui/react";
|
||||
// import ReactMarkdown from "react-markdown";
|
||||
// import { onEvent, subscribeToAuthor } from "../../services/relays";
|
||||
// import { useSignal } from "../../hooks/use-signal";
|
||||
|
||||
// export const UserRelaysTab = ({ pubkey }) => {
|
||||
// const [events, setEvents] = useState({});
|
||||
|
||||
// useEffect(() => {
|
||||
// if (pubkey) {
|
||||
// subscribeToAuthor(pubkey);
|
||||
// }
|
||||
// }, [pubkey]);
|
||||
|
||||
// useSignal(
|
||||
// onEvent,
|
||||
// (event) => {
|
||||
// if (event.body.kind === 1) {
|
||||
// setEvents((dir) => ({ [event.body.id]: event.body, ...dir }));
|
||||
// }
|
||||
// },
|
||||
// [setEvents]
|
||||
// );
|
||||
|
||||
// const timeline = Object.values(events).sort(
|
||||
// (a, b) => a.created_at - b.created_at
|
||||
// );
|
||||
|
||||
// if (timeline.length === 0) {
|
||||
// return <SkeletonText />;
|
||||
// }
|
||||
|
||||
// return timeline.map((event) => (
|
||||
// <Card key={event.id}>
|
||||
// <CardBody>
|
||||
// <ReactMarkdown>{event.content}</ReactMarkdown>
|
||||
// </CardBody>
|
||||
// </Card>
|
||||
// ));
|
||||
// };
|
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
9
tsconfig.node.json
Normal file
9
tsconfig.node.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
target: ["chrome89", "edge89", "firefox89", "safari15"],
|
||||
},
|
||||
// plugins: [
|
||||
// VitePWA({
|
||||
// registerType: "autoUpdate",
|
||||
// devOptions: {
|
||||
// enabled: true,
|
||||
// },
|
||||
// }),
|
||||
// ],
|
||||
});
|
10
vite.config.ts
Normal file
10
vite.config.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
build: {
|
||||
target: ["chrome89", "edge89", "firefox89", "safari15"],
|
||||
},
|
||||
plugins: [react()],
|
||||
});
|
175
yarn.lock
175
yarn.lock
@ -26,7 +26,7 @@
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.18.6"
|
||||
|
||||
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.0", "@babel/compat-data@^7.20.1":
|
||||
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.0", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.5.tgz#86f172690b093373a933223b4745deeb6049e733"
|
||||
integrity sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==
|
||||
@ -52,6 +52,27 @@
|
||||
json5 "^2.2.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/core@^7.20.5":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.7.tgz#37072f951bd4d28315445f66e0ec9f6ae0c8c35f"
|
||||
integrity sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.1.0"
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/generator" "^7.20.7"
|
||||
"@babel/helper-compilation-targets" "^7.20.7"
|
||||
"@babel/helper-module-transforms" "^7.20.7"
|
||||
"@babel/helpers" "^7.20.7"
|
||||
"@babel/parser" "^7.20.7"
|
||||
"@babel/template" "^7.20.7"
|
||||
"@babel/traverse" "^7.20.7"
|
||||
"@babel/types" "^7.20.7"
|
||||
convert-source-map "^1.7.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
json5 "^2.2.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/generator@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.5.tgz#cb25abee3178adf58d6814b68517c62bdbfdda95"
|
||||
@ -61,6 +82,15 @@
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/generator@^7.20.7":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.7.tgz#f8ef57c8242665c5929fe2e8d82ba75460187b4a"
|
||||
integrity sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.20.7"
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
|
||||
@ -86,6 +116,17 @@
|
||||
browserslist "^4.21.3"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.20.7":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz#a6cd33e93629f5eb473b021aac05df62c4cd09bb"
|
||||
integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.20.5"
|
||||
"@babel/helper-validator-option" "^7.18.6"
|
||||
browserslist "^4.21.3"
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz#327154eedfb12e977baa4ecc72e5806720a85a06"
|
||||
@ -174,6 +215,20 @@
|
||||
"@babel/traverse" "^7.20.1"
|
||||
"@babel/types" "^7.20.2"
|
||||
|
||||
"@babel/helper-module-transforms@^7.20.7":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.7.tgz#7a6c9a1155bef55e914af574153069c9d9470c43"
|
||||
integrity sha512-FNdu7r67fqMUSVuQpFQGE6BPdhJIhitoxhGzDbAXNcA07uoVG37fOiMk3OSV8rEICuyG6t8LGkd9EE64qIEoIA==
|
||||
dependencies:
|
||||
"@babel/helper-environment-visitor" "^7.18.9"
|
||||
"@babel/helper-module-imports" "^7.18.6"
|
||||
"@babel/helper-simple-access" "^7.20.2"
|
||||
"@babel/helper-split-export-declaration" "^7.18.6"
|
||||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
"@babel/template" "^7.20.7"
|
||||
"@babel/traverse" "^7.20.7"
|
||||
"@babel/types" "^7.20.7"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe"
|
||||
@ -262,6 +317,15 @@
|
||||
"@babel/traverse" "^7.20.5"
|
||||
"@babel/types" "^7.20.5"
|
||||
|
||||
"@babel/helpers@^7.20.7":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.7.tgz#04502ff0feecc9f20ecfaad120a18f011a8e6dce"
|
||||
integrity sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==
|
||||
dependencies:
|
||||
"@babel/template" "^7.20.7"
|
||||
"@babel/traverse" "^7.20.7"
|
||||
"@babel/types" "^7.20.7"
|
||||
|
||||
"@babel/highlight@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
|
||||
@ -276,6 +340,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8"
|
||||
integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
|
||||
|
||||
"@babel/parser@^7.20.7":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.7.tgz#66fe23b3c8569220817d5feb8b9dcdc95bb4f71b"
|
||||
integrity sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==
|
||||
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
|
||||
@ -717,6 +786,20 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz#3849401bab7ae8ffa1e3e5687c94a753fc75bda7"
|
||||
integrity sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source@^7.19.6":
|
||||
version "7.19.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz#88578ae8331e5887e8ce28e4c9dc83fb29da0b86"
|
||||
integrity sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.19.0"
|
||||
|
||||
"@babel/plugin-transform-regenerator@^7.18.6":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d"
|
||||
@ -891,6 +974,15 @@
|
||||
"@babel/parser" "^7.18.10"
|
||||
"@babel/types" "^7.18.10"
|
||||
|
||||
"@babel/template@^7.20.7":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8"
|
||||
integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/parser" "^7.20.7"
|
||||
"@babel/types" "^7.20.7"
|
||||
|
||||
"@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.5.tgz#78eb244bea8270fdda1ef9af22a5d5e5b7e57133"
|
||||
@ -907,6 +999,22 @@
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/traverse@^7.20.7":
|
||||
version "7.20.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.8.tgz#e3a23eb04af24f8bbe8a8ba3eef6155b77df0b08"
|
||||
integrity sha512-/RNkaYDeCy4MjyV70+QkSHhxbvj2JO/5Ft2Pa880qJOG8tWrqcT/wXUuCCv43yogfqPzHL77Xu101KQPf4clnQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/generator" "^7.20.7"
|
||||
"@babel/helper-environment-visitor" "^7.18.9"
|
||||
"@babel/helper-function-name" "^7.19.0"
|
||||
"@babel/helper-hoist-variables" "^7.18.6"
|
||||
"@babel/helper-split-export-declaration" "^7.18.6"
|
||||
"@babel/parser" "^7.20.7"
|
||||
"@babel/types" "^7.20.7"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.4.4":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
|
||||
@ -916,6 +1024,15 @@
|
||||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.20.7":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f"
|
||||
integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.19.4"
|
||||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@chakra-ui/accordion@2.1.4":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@chakra-ui/accordion/-/accordion-2.1.4.tgz#a3eca38f8e52d5a5f4b9528fb9d269dcdcb035ac"
|
||||
@ -2158,11 +2275,27 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
|
||||
|
||||
"@types/prop-types@^15.0.0":
|
||||
"@types/prop-types@*", "@types/prop-types@^15.0.0":
|
||||
version "15.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
|
||||
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
|
||||
|
||||
"@types/react-dom@^18.0.9":
|
||||
version "18.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.9.tgz#ffee5e4bfc2a2f8774b15496474f8e7fe8d0b504"
|
||||
integrity sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^18.0.26":
|
||||
version "18.0.26"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.26.tgz#8ad59fc01fef8eaf5c74f4ea392621749f0b7917"
|
||||
integrity sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/resolve@1.17.1":
|
||||
version "1.17.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
|
||||
@ -2170,6 +2303,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
|
||||
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
|
||||
|
||||
"@types/trusted-types@^2.0.2":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756"
|
||||
@ -2180,6 +2318,17 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
|
||||
integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==
|
||||
|
||||
"@vitejs/plugin-react@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-3.0.0.tgz#f36ee1b2ce958dd11ac63fdf746a3b27b0d258ed"
|
||||
integrity sha512-1mvyPc0xYW5G8CHQvJIJXLoMjl5Ct3q2g5Y2s6Ccfgwm45y48LBvsla7az+GkkAtYikWQ4Lxqcsq5RHLcZgtNQ==
|
||||
dependencies:
|
||||
"@babel/core" "^7.20.5"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.18.6"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.19.6"
|
||||
magic-string "^0.27.0"
|
||||
react-refresh "^0.14.0"
|
||||
|
||||
"@xobotyi/scrollbar-width@^1.9.5":
|
||||
version "1.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d"
|
||||
@ -3222,6 +3371,13 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
lru-cache@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||
integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
|
||||
dependencies:
|
||||
yallist "^3.0.2"
|
||||
|
||||
magic-string@^0.25.0, magic-string@^0.25.7:
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
|
||||
@ -3758,6 +3914,11 @@ react-markdown@^8.0.4:
|
||||
unist-util-visit "^4.0.0"
|
||||
vfile "^5.0.0"
|
||||
|
||||
react-refresh@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
||||
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
|
||||
|
||||
react-remove-scroll-bar@^2.3.3:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9"
|
||||
@ -4282,6 +4443,11 @@ type-fest@^0.16.0:
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860"
|
||||
integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==
|
||||
|
||||
typescript@^4.9.4:
|
||||
version "4.9.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
|
||||
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
|
||||
|
||||
unbox-primitive@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
|
||||
@ -4664,6 +4830,11 @@ wrappy@1:
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
|
||||
|
||||
yallist@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
||||
yaml@^1.10.0:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||
|
Loading…
x
Reference in New Issue
Block a user