diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..584a04cc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,35 @@ +{ + "eslint.codeActionsOnSave.mode": "problems", + "eslint.workingDirectories": [ + { "pattern": "./packages/*/" }, + { "pattern": "./apps/*/" } + ], + "[graphql]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + }, + "[typescript]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + }, + "[typescriptreact]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + }, + "eslint.validate": [ + "graphql", + "javascript", + "javascriptreact", + "typescript", + "typescriptreact" + ], + "[graphql][typescript][typescriptreact]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } + }, + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/apps/storybook/next.config.mjs b/apps/storybook/next.config.mjs index c8bca415..ab1be264 100644 --- a/apps/storybook/next.config.mjs +++ b/apps/storybook/next.config.mjs @@ -5,16 +5,16 @@ import withPlugins from "next-compose-plugins"; import remarkGfm from "remark-gfm"; const withBundleAnalyzer = bundleAnalyzerPlugin({ - enabled: process.env.BUNDLE_ANALYZE === "true", + enabled: process.env.BUNDLE_ANALYZE === "true", }); const withMdx = mdxPlugin({ - extension: /\.mdx?$/, - options: { - providerImportSource: "@mdx-js/react", - remarkPlugins: [frontmatter, remarkGfm], - rehypePlugins: [], - }, + extension: /\.mdx?$/, + options: { + providerImportSource: "@mdx-js/react", + remarkPlugins: [frontmatter, remarkGfm], + rehypePlugins: [], + }, }); /** @type {import("next").NextConfig} */ @@ -23,22 +23,19 @@ const config = { externalDir: true, }, i18n: { - locales: ["en-US"], - defaultLocale: "en-US", - }, + locales: ["en-US"], + defaultLocale: "en-US", + }, images: { - deviceSizes: [320, 420, 768, 1024, 1200], - domains: [], - loader: "default", - }, - pageExtensions: ["ts", "tsx", "js", "jsx", "md", "mdx"], + deviceSizes: [320, 420, 768, 1024, 1200], + domains: [], + loader: "default", + }, + pageExtensions: ["ts", "tsx", "js", "jsx", "md", "mdx"], reactStrictMode: true, - env: { - WS_ENDPOINT: process.env.WS_ENDPOINT, - }, + env: { + WS_ENDPOINT: process.env.WS_ENDPOINT, + }, }; -export default withPlugins([ - withBundleAnalyzer, - withMdx, -], config); +export default withPlugins([withBundleAnalyzer, withMdx], config); diff --git a/apps/web/src/components/DocsBreadcrumbs/DocsBreadcrumbs.tsx b/apps/web/src/components/DocsBreadcrumbs/DocsBreadcrumbs.tsx index 8b1479a4..b774ac00 100644 --- a/apps/web/src/components/DocsBreadcrumbs/DocsBreadcrumbs.tsx +++ b/apps/web/src/components/DocsBreadcrumbs/DocsBreadcrumbs.tsx @@ -27,9 +27,7 @@ export const DocsBreadcrumbs = memo((props) => { const getName = useCallback((slugs: string[]): string | null => { const [head, ...tail] = slugs; - const path = [head, ...tail.map((part) => `[${part}]`)].join( - "[children]", - ); + const path = [head, ...tail.map((part) => `[${part}]`)].join("[children]"); return get(routes, `${path}[name]`) ?? null; }, []); @@ -43,11 +41,7 @@ export const DocsBreadcrumbs = memo((props) => { const parts = slugs.slice(0, i + 1); return ( - + {getName(parts)} ); diff --git a/apps/web/src/components/DocsCard/DocsCard.tsx b/apps/web/src/components/DocsCard/DocsCard.tsx index c4a42b0c..2da08462 100644 --- a/apps/web/src/components/DocsCard/DocsCard.tsx +++ b/apps/web/src/components/DocsCard/DocsCard.tsx @@ -8,7 +8,7 @@ const Root = tw(Paper)` items-stretch gap-3 p-4 - rounded-xl + rounded-lg `; const Title = tw.h2` @@ -29,17 +29,13 @@ export interface DocsCardProps { title: string; } -export const DocsCard: FC = ({ - className, - description, - href, - style, - title, -}) => { +export const DocsCard: FC = ({ className, description, href, style, title }) => { return ( - - 📄️ {title} - {!!description && {description}} - + + + 📄️ {title} + {!!description && {description}} + + ); }; diff --git a/apps/web/src/components/DocsSeo/DocsSeo.tsx b/apps/web/src/components/DocsSeo/DocsSeo.tsx index 1919f943..e2a86b05 100644 --- a/apps/web/src/components/DocsSeo/DocsSeo.tsx +++ b/apps/web/src/components/DocsSeo/DocsSeo.tsx @@ -7,11 +7,5 @@ export interface DocsSeoProps { } export const DocsSeo: FC = ({ description, title }) => { - return ( - - ); + return ; }; diff --git a/apps/web/src/components/DocsTreeViewNavigation/DocsTreeViewNavigation.tsx b/apps/web/src/components/DocsTreeViewNavigation/DocsTreeViewNavigation.tsx index 9f170eb6..dc2b17a3 100644 --- a/apps/web/src/components/DocsTreeViewNavigation/DocsTreeViewNavigation.tsx +++ b/apps/web/src/components/DocsTreeViewNavigation/DocsTreeViewNavigation.tsx @@ -12,22 +12,20 @@ export interface DocsTreeViewNavigationProps { style?: CSSProperties; } -export const DocsTreeViewNavigation = memo( - (props) => { - const { className, onClickLink, style } = props; +export const DocsTreeViewNavigation = memo((props) => { + const { className, onClickLink, style } = props; - return ( - - - - ); - }, -); + return ( + + + + ); +}); DocsTreeViewNavigation.displayName = "DocsTreeViewNavigation"; diff --git a/apps/web/src/components/DocsTreeViewNavigation/DocsTreeViewNavigationRoutes.tsx b/apps/web/src/components/DocsTreeViewNavigation/DocsTreeViewNavigationRoutes.tsx index 1fcac45b..6d5bb18f 100644 --- a/apps/web/src/components/DocsTreeViewNavigation/DocsTreeViewNavigationRoutes.tsx +++ b/apps/web/src/components/DocsTreeViewNavigation/DocsTreeViewNavigationRoutes.tsx @@ -11,9 +11,13 @@ export interface DocsTreeViewNavigationRoutesProps { selected?: boolean; } -export const DocsTreeViewNavigationRoutes: FC< - DocsTreeViewNavigationRoutesProps -> = ({ baseRoute = "", level, onClickLink, routes, selected }) => { +export const DocsTreeViewNavigationRoutes: FC = ({ + baseRoute = "", + level, + onClickLink, + routes, + selected, +}) => { const router = useRouter(); const sorted = useMemo(() => { @@ -37,10 +41,7 @@ export const DocsTreeViewNavigationRoutes: FC< .split("/"); }, [baseRoute, router.asPath]); - const routeSlug = useMemo( - () => router.asPath.split("/")[level + 1], - [level, router.asPath], - ); + const routeSlug = useMemo(() => router.asPath.split("/")[level + 1], [level, router.asPath]); const finalSlug = slugs.at(-1); diff --git a/apps/web/src/components/HomeBoxesDemoSection/HomeBoxesDemoSection.tsx b/apps/web/src/components/HomeBoxesDemoSection/HomeBoxesDemoSection.tsx index 996fbc36..970108ec 100644 --- a/apps/web/src/components/HomeBoxesDemoSection/HomeBoxesDemoSection.tsx +++ b/apps/web/src/components/HomeBoxesDemoSection/HomeBoxesDemoSection.tsx @@ -48,16 +48,13 @@ export interface HomeBoxesDemoSectionProps { style?: CSSProperties; } -export const HomeBoxesDemoSection: FC = ({ - className, - style, -}) => { +export const HomeBoxesDemoSection: FC = ({ className, style }) => { return ( Simple-to-use APIs - Configure your server and client to unlock intuitive APIs that - allow you to focus on your end-user experience. + Configure your server and client to unlock intuitive APIs that allow you to focus on your end-user + experience. diff --git a/apps/web/src/components/HomeChessDemo/HomeChessDemo.tsx b/apps/web/src/components/HomeChessDemo/HomeChessDemo.tsx index ad36a97f..c82fff87 100644 --- a/apps/web/src/components/HomeChessDemo/HomeChessDemo.tsx +++ b/apps/web/src/components/HomeChessDemo/HomeChessDemo.tsx @@ -1,20 +1,7 @@ -import { - ChessBoard, - ChessBoardRef, - ChessMoveHistory, - LoadingChessBoard, -} from "@pluv-internal/react-chess"; +import { ChessBoard, ChessBoardRef, ChessMoveHistory, LoadingChessBoard } from "@pluv-internal/react-chess"; import { yjs } from "@pluv/crdt-yjs"; import ms from "ms"; -import { - CSSProperties, - FC, - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; +import { CSSProperties, FC, useCallback, useEffect, useMemo, useRef, useState } from "react"; import tw, { styled } from "twin.macro"; import { useStorage } from "../../pluv-io/cloudflare"; @@ -128,20 +115,11 @@ export const HomeChessDemo: FC = ({ className, style }) => { const [winner, setWinner] = useState(); const chessRef = useRef(); - const moveHistory = useMemo( - () => demo?.chessHistory?.slice() ?? null, - [demo], - ); + const moveHistory = useMemo(() => demo?.chessHistory?.slice() ?? null, [demo]); const onGameOver = useCallback((winner: "b" | "w" | null) => { setGameOver(true); - setWinner( - winner === "b" - ? "Black wins!" - : winner === "w" - ? "White wins!" - : "Draw", - ); + setWinner(winner === "b" ? "Black wins!" : winner === "w" ? "White wins!" : "Draw"); }, []); useEffect(() => { @@ -169,10 +147,7 @@ export const HomeChessDemo: FC = ({ className, style }) => { id="home-chess" onGameOver={onGameOver} onMove={({ game }) => { - sharedType?.set( - "chessHistory", - yjs.array(game.history()), - ); + sharedType?.set("chessHistory", yjs.array(game.history())); }} /> ) : ( diff --git a/apps/web/src/components/HomeChessDemo/useOtherSquares.ts b/apps/web/src/components/HomeChessDemo/useOtherSquares.ts index 972c0c2f..1ed89e23 100644 --- a/apps/web/src/components/HomeChessDemo/useOtherSquares.ts +++ b/apps/web/src/components/HomeChessDemo/useOtherSquares.ts @@ -2,9 +2,7 @@ import { useOthers } from "pluv-io"; import { useMemo } from "react"; export const useOtherSquares = (): Record => { - const otherSquares = useOthers((others) => - others.map((other) => other.presence.demoChessSquare), - ); + const otherSquares = useOthers((others) => others.map((other) => other.presence.demoChessSquare)); return useMemo(() => { return otherSquares.reduce>( diff --git a/apps/web/src/components/HomeCodeDemo/HomeCodeDemoBox.tsx b/apps/web/src/components/HomeCodeDemo/HomeCodeDemoBox.tsx index 7e832f0d..9fd87b92 100644 --- a/apps/web/src/components/HomeCodeDemo/HomeCodeDemoBox.tsx +++ b/apps/web/src/components/HomeCodeDemo/HomeCodeDemoBox.tsx @@ -71,48 +71,46 @@ export interface HomeCodeDemoBoxProps { user?: string | null; } -export const HomeCodeDemoBox = forwardRef( - (props, ref) => { - const { - className, - id, - onSelect, - position: { x, y }, - selected, - style, - user, - } = props; +export const HomeCodeDemoBox = forwardRef((props, ref) => { + const { + className, + id, + onSelect, + position: { x, y }, + selected, + style, + user, + } = props; - const { attributes, isDragging, listeners, setNodeRef } = useDraggable({ - id, - }); + const { attributes, isDragging, listeners, setNodeRef } = useDraggable({ + id, + }); - return ( - - (ref, setNodeRef)} - {...attributes} - {...listeners} - onMouseDown={() => { - onSelect?.(); - }} - role="none" - style={{ - transform: `translate3d(${x}px, ${y}px, 0)`, - }} - data-selected={isDragging} - > - {!!user && ( - - {user} - - - )} - {selected && } - - - ); - }, -); + return ( + + (ref, setNodeRef)} + {...attributes} + {...listeners} + onMouseDown={() => { + onSelect?.(); + }} + role="none" + style={{ + transform: `translate3d(${x}px, ${y}px, 0)`, + }} + data-selected={isDragging} + > + {!!user && ( + + {user} + + + )} + {selected && } + + + ); +}); HomeCodeDemoBox.displayName = "HomeCodeDemoBox"; diff --git a/apps/web/src/components/HomeCodeDemo/HomeCodeDemoBrowser.tsx b/apps/web/src/components/HomeCodeDemo/HomeCodeDemoBrowser.tsx index e57b17d7..29cdea21 100644 --- a/apps/web/src/components/HomeCodeDemo/HomeCodeDemoBrowser.tsx +++ b/apps/web/src/components/HomeCodeDemo/HomeCodeDemoBrowser.tsx @@ -63,10 +63,7 @@ const SecondBox = tw(HomeCodeDemoBox)` text-violet-500 `; -const didClickIn = ( - element: HTMLDivElement | null, - event: MouseEvent, -): boolean => { +const didClickIn = (element: HTMLDivElement | null, event: MouseEvent): boolean => { return !element || element.contains(event.target as Node | null); }; @@ -77,34 +74,16 @@ export interface HomeCodeDemoBrowserProps { user: keyof HomeCodeDemoSelections; } -export const HomeCodeDemoBrowser: FC = ({ - className, - id, - style, - user, -}) => { - const { - boxSize, - codePositions, - initPositions, - selections, - setCodePositions, - setInitPositions, - setSelections, - } = useContext(HomeCodeDemoContext); +export const HomeCodeDemoBrowser: FC = ({ className, id, style, user }) => { + const { boxSize, codePositions, initPositions, selections, setCodePositions, setInitPositions, setSelections } = + useContext(HomeCodeDemoContext); const { [user]: myself, ...others } = selections; const [box1, box1Ref] = useState(null); const [box2, box2Ref] = useState(null); - const otherUser = useMemo( - () => - (Object.keys(others)[0] ?? null) as - | keyof HomeCodeDemoSelections - | null, - [others], - ); + const otherUser = useMemo(() => (Object.keys(others)[0] ?? null) as keyof HomeCodeDemoSelections | null, [others]); const other = useMemo(() => { if (!otherUser) return null; @@ -125,14 +104,8 @@ export const HomeCodeDemoBrowser: FC = ({ const minHeight = rootRect.height / -2 + boxSize / 2; const maxHeight = rootRect.height / 2 - boxSize / 2; - const newXPosition = Math.min( - Math.max(position.x, minWidth), - maxWidth, - ); - const newYPosition = Math.min( - Math.max(position.y, minHeight), - maxHeight, - ); + const newXPosition = Math.min(Math.max(position.x, minWidth), maxWidth); + const newYPosition = Math.min(Math.max(position.y, minHeight), maxHeight); return { x: newXPosition, y: newYPosition }; }, diff --git a/apps/web/src/components/HomeCodeDemo/HomeCodeDemoUserDemo.tsx b/apps/web/src/components/HomeCodeDemo/HomeCodeDemoUserDemo.tsx index ed18c070..c9678503 100644 --- a/apps/web/src/components/HomeCodeDemo/HomeCodeDemoUserDemo.tsx +++ b/apps/web/src/components/HomeCodeDemo/HomeCodeDemoUserDemo.tsx @@ -28,10 +28,7 @@ export interface HomeCodeDemoUserDemoProps { style?: CSSProperties; } -export const HomeCodeDemoUserDemo: FC = ({ - className, - style, -}) => { +export const HomeCodeDemoUserDemo: FC = ({ className, style }) => { return ( diff --git a/apps/web/src/components/HomeFeaturesSection/HomeFeaturesSection.tsx b/apps/web/src/components/HomeFeaturesSection/HomeFeaturesSection.tsx index 5773bb41..d1277f7a 100644 --- a/apps/web/src/components/HomeFeaturesSection/HomeFeaturesSection.tsx +++ b/apps/web/src/components/HomeFeaturesSection/HomeFeaturesSection.tsx @@ -28,10 +28,7 @@ export interface HomeFeaturesSectionProps { style?: CSSProperties; } -export const HomeFeaturesSection: FC = ({ - className, - style, -}) => { +export const HomeFeaturesSection: FC = ({ className, style }) => { return ( @@ -39,22 +36,10 @@ export const HomeFeaturesSection: FC = ({ description="Get auto-completion and in-code errors with end-to-end type-safety." title="Type-safety" /> - - - - + + + + = ({ className, description, style, title }) => { +export const HomeFeaturesSectionFeature: FC = ({ + className, + description, + style, + title, +}) => { return ( {title} diff --git a/apps/web/src/components/HomeHero/HomeHero.tsx b/apps/web/src/components/HomeHero/HomeHero.tsx index 716da321..043e9032 100644 --- a/apps/web/src/components/HomeHero/HomeHero.tsx +++ b/apps/web/src/components/HomeHero/HomeHero.tsx @@ -131,9 +131,7 @@ export const HomeHero = memo(({ className, style }) => { priority src="/static/jpg/rainfall-background.jpg" /> - {showRainfall && ( - - )} + {showRainfall && } @@ -149,8 +147,7 @@ export const HomeHero = memo(({ className, style }) => { - Multiplayer APIs powered-by{" "} - TypeScript inference end-to-end + Multiplayer APIs powered-by TypeScript inference end-to-end diff --git a/apps/web/src/components/HomeHero/HomeHeroRainfall.tsx b/apps/web/src/components/HomeHero/HomeHeroRainfall.tsx index 701640e7..1bb294bc 100644 --- a/apps/web/src/components/HomeHero/HomeHeroRainfall.tsx +++ b/apps/web/src/components/HomeHero/HomeHeroRainfall.tsx @@ -6,31 +6,24 @@ export interface HomeHeroRainfallProps { style?: CSSProperties; } -export const HomeHeroRainfall = memo( - ({ className, style }) => { - const [rainfallElem, rainfallRef] = useState( - null, - ); - const [ready, setReady] = useState(false); - const rainfall = useMemo( - () => new Rainfall({ onReady: () => setReady(true) }), - [], - ); - - useEffect(() => { - if (!ready) return; - if (!rainfallElem) return; - - rainfall.initialize(rainfallElem); - - return () => { - rainfall.uninitialize(); - }; - }, [rainfall, ready, rainfallElem]); - - return
; - }, -); +export const HomeHeroRainfall = memo(({ className, style }) => { + const [rainfallElem, rainfallRef] = useState(null); + const [ready, setReady] = useState(false); + const rainfall = useMemo(() => new Rainfall({ onReady: () => setReady(true) }), []); + + useEffect(() => { + if (!ready) return; + if (!rainfallElem) return; + + rainfall.initialize(rainfallElem); + + return () => { + rainfall.uninitialize(); + }; + }, [rainfall, ready, rainfallElem]); + + return
; +}); HomeHeroRainfall.displayName = "HomeHeroRainfall"; diff --git a/apps/web/src/components/HomeIntroSection/HomeIntroSection.tsx b/apps/web/src/components/HomeIntroSection/HomeIntroSection.tsx index 71b74b88..4425495d 100644 --- a/apps/web/src/components/HomeIntroSection/HomeIntroSection.tsx +++ b/apps/web/src/components/HomeIntroSection/HomeIntroSection.tsx @@ -48,16 +48,12 @@ export interface HomeIntroSectionProps { style?: CSSProperties; } -export const HomeIntroSection: FC = ({ - className, - style, -}) => { +export const HomeIntroSection: FC = ({ className, style }) => { return ( Multiplayer made easy - Pluv provides powerful utilities to make building complex - multiplayer experiences easier. + Pluv provides powerful utilities to make building complex multiplayer experiences easier. diff --git a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemo.tsx b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemo.tsx index 5cc9a830..175a1230 100644 --- a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemo.tsx +++ b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemo.tsx @@ -48,10 +48,7 @@ export interface HomeTypeSafetyDemoProps { style?: CSSProperties; } -export const HomeTypeSafetyDemo: FC = ({ - className, - style, -}) => { +export const HomeTypeSafetyDemo: FC = ({ className, style }) => { const contentRef = useRef(null); const [typistStates] = useOrchestratedTypist(contentRef, { diff --git a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoClient.tsx b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoClient.tsx index 2b8c2190..e65e131d 100644 --- a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoClient.tsx +++ b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoClient.tsx @@ -13,10 +13,9 @@ export interface HomeTypeSafetyDemoClientProps { style?: CSSProperties; } -export const HomeTypeSafetyDemoClient = memo( - ({ className, style }) => { - const template = useMemo( - (): string => codeBlock` +export const HomeTypeSafetyDemoClient = memo(({ className, style }) => { + const template = useMemo( + (): string => codeBlock` // client/Room.tsx import { useBroadcast, useEvent } from "client/pluv"; @@ -42,36 +41,24 @@ export const HomeTypeSafetyDemoClient = memo( // return ... }; `, - [], - ); + [], + ); - const [ - , - , - , - { text: inputParam }, - { text: newMessage }, - { text: sendMessageInput }, - ] = useContext(HomeTypeSafetyDemoContext); + const [, , , { text: inputParam }, { text: newMessage }, { text: sendMessageInput }] = + useContext(HomeTypeSafetyDemoContext); - const code = useMemo(() => { - return template - .replace(INPUT_PARAMETER, inputParam) - .replace(NEW_MESSAGE, newMessage) - .replace(SEND_MESSAGE_INPUT, sendMessageInput); - }, [inputParam, newMessage, sendMessageInput, template]); + const code = useMemo(() => { + return template + .replace(INPUT_PARAMETER, inputParam) + .replace(NEW_MESSAGE, newMessage) + .replace(SEND_MESSAGE_INPUT, sendMessageInput); + }, [inputParam, newMessage, sendMessageInput, template]); - return ( - - {code} - - ); - }, -); + return ( + + {code} + + ); +}); HomeTypeSafetyDemoClient.displayName = "HomeTypeSafetyDemoClient"; diff --git a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoClientToken.tsx b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoClientToken.tsx index 850b339a..9df2ff48 100644 --- a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoClientToken.tsx +++ b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoClientToken.tsx @@ -3,8 +3,8 @@ import { memo, useCallback, useState } from "react"; export type HomeTypeSafetyDemoClientTokenProps = PrismCodeTokenProps; -export const HomeTypeSafetyDemoClientToken = - memo(({ lineNo, tokenProps }) => { +export const HomeTypeSafetyDemoClientToken = memo( + ({ lineNo, tokenProps: { key, ...tokenProps } }) => { const text = tokenProps.children; const [open, setOpen] = useState(false); @@ -22,7 +22,7 @@ export const HomeTypeSafetyDemoClientToken = const padded = text.startsWith(" "); - if (tokenProps.key === 8 && lineNo === 11) { + if (key === 8 && lineNo === 11) { return ( ; - }); + }, +); HomeTypeSafetyDemoClientToken.displayName = "HomeTypeSafetyDemoClientToken"; diff --git a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoServer.tsx b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoServer.tsx index 23bdb78d..f493f496 100644 --- a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoServer.tsx +++ b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoServer.tsx @@ -13,10 +13,9 @@ export interface HomeTypeSafetyDemoServerProps { style?: CSSProperties; } -export const HomeTypeSafetyDemoServer = memo( - ({ className, style }) => { - const template = useMemo( - () => codeBlock` +export const HomeTypeSafetyDemoServer = memo(({ className, style }) => { + const template = useMemo( + () => codeBlock` // server/pluv.ts import { createIO } from "@pluv/io"; @@ -40,36 +39,24 @@ export const HomeTypeSafetyDemoServer = memo( resolver: ({${RESOLVER_PARAMETER}}) => ({${RESOLVER_OUTPUT}}), }); `, - [], - ); - - const [ - { text: inputParam }, - { text: resolverParam }, - { text: resolverOutput }, - ] = useContext(HomeTypeSafetyDemoContext); - - const code = useMemo(() => { - return template - .replace(INPUT_PARAMETER, inputParam) - .replace(RESOLVER_PARAMETER, resolverParam) - .replace( - RESOLVER_OUTPUT, - resolverOutput ? `\n ${resolverOutput}\n ` : "", - ); - }, [inputParam, resolverOutput, resolverParam, template]); - - return ( - - {code} - - ); - }, -); + [], + ); + + const [{ text: inputParam }, { text: resolverParam }, { text: resolverOutput }] = + useContext(HomeTypeSafetyDemoContext); + + const code = useMemo(() => { + return template + .replace(INPUT_PARAMETER, inputParam) + .replace(RESOLVER_PARAMETER, resolverParam) + .replace(RESOLVER_OUTPUT, resolverOutput ? `\n ${resolverOutput}\n ` : ""); + }, [inputParam, resolverOutput, resolverParam, template]); + + return ( + + {code} + + ); +}); HomeTypeSafetyDemoServer.displayName = "HomeTypeSafetyDemoServer"; diff --git a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoServerToken.tsx b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoServerToken.tsx index 644afc2a..71aa2e2e 100644 --- a/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoServerToken.tsx +++ b/apps/web/src/components/HomeTypeSafetyDemo/HomeTypeSafetyDemoServerToken.tsx @@ -3,8 +3,8 @@ import { memo, useCallback, useState } from "react"; export type HomeTypeSafetyDemoServerTokenProps = PrismCodeTokenProps; -export const HomeTypeSafetyDemoServerToken = - memo(({ lineNo, tokenProps }) => { +export const HomeTypeSafetyDemoServerToken = memo( + ({ lineNo, tokenProps: { key, ...tokenProps } }) => { const text = tokenProps.children; const [open, setOpen] = useState(false); @@ -22,7 +22,7 @@ export const HomeTypeSafetyDemoServerToken = const padded = text.startsWith(" "); - if (tokenProps.key === 6 && lineNo === 13) { + if (key === 6 && lineNo === 13) { return ( ; - }); + }, +); HomeTypeSafetyDemoServerToken.displayName = "HomeTypeSafetyDemoServerToken"; diff --git a/apps/web/src/components/HomeTypeSafetyDemo/context.ts b/apps/web/src/components/HomeTypeSafetyDemo/context.ts index 0dbacce8..37b52ef8 100644 --- a/apps/web/src/components/HomeTypeSafetyDemo/context.ts +++ b/apps/web/src/components/HomeTypeSafetyDemo/context.ts @@ -3,5 +3,4 @@ import { createContext } from "react"; export type HomeTypeSafetyDemoContextValue = readonly TypistState[]; -export const HomeTypeSafetyDemoContext = - createContext([]); +export const HomeTypeSafetyDemoContext = createContext([]); diff --git a/apps/web/src/components/HomeTypeSafetyDemoSection/HomeTypeSafetyDemoSection.tsx b/apps/web/src/components/HomeTypeSafetyDemoSection/HomeTypeSafetyDemoSection.tsx index aeecfdbb..669f827e 100644 --- a/apps/web/src/components/HomeTypeSafetyDemoSection/HomeTypeSafetyDemoSection.tsx +++ b/apps/web/src/components/HomeTypeSafetyDemoSection/HomeTypeSafetyDemoSection.tsx @@ -48,17 +48,11 @@ export interface HomeTypeSafetyDemoSectionProps { style?: CSSProperties; } -export const HomeTypeSafetyDemoSection: FC = ({ - className, - style, -}) => { +export const HomeTypeSafetyDemoSection: FC = ({ className, style }) => { return ( End-to-end Type-Safety - - Get intellisense and autocomplete, so you can move fast and - catch errors in development - + Get intellisense and autocomplete, so you can move fast and catch errors in development diff --git a/apps/web/src/components/MobileDocsSideDrawer/MobileDocsSideDrawer.tsx b/apps/web/src/components/MobileDocsSideDrawer/MobileDocsSideDrawer.tsx index 90ae1278..65d5aa84 100644 --- a/apps/web/src/components/MobileDocsSideDrawer/MobileDocsSideDrawer.tsx +++ b/apps/web/src/components/MobileDocsSideDrawer/MobileDocsSideDrawer.tsx @@ -1,9 +1,4 @@ -import { - Button, - LogoIcon, - NextLink, - SideDrawer, -} from "@pluv-internal/react-components"; +import { Button, LogoIcon, NextLink, SideDrawer } from "@pluv-internal/react-components"; import { XIcon } from "@pluv-internal/react-icons"; import { CSSProperties, FC, MouseEvent } from "react"; import tw from "twin.macro"; @@ -52,11 +47,7 @@ export interface MobileDocsSideDrawerProps { style?: CSSProperties; } -export const MobileDocsSideDrawer: FC = ({ - className, - onClickLink, - style, -}) => { +export const MobileDocsSideDrawer: FC = ({ className, onClickLink, style }) => { return ( diff --git a/apps/web/src/components/SiteWideAppBar/SiteWideAppBar.tsx b/apps/web/src/components/SiteWideAppBar/SiteWideAppBar.tsx index 13844b02..6ea3cc1a 100644 --- a/apps/web/src/components/SiteWideAppBar/SiteWideAppBar.tsx +++ b/apps/web/src/components/SiteWideAppBar/SiteWideAppBar.tsx @@ -1,11 +1,4 @@ -import { - Anchor, - AppBar, - Button, - LogoIcon, - NextLink, - SideDrawer, -} from "@pluv-internal/react-components"; +import { Anchor, AnchorButton, AppBar, Button, LogoIcon, NextLink, SideDrawer } from "@pluv-internal/react-components"; import { BarsIcon, GitHubIcon, NpmIcon } from "@pluv-internal/react-icons"; import { useRouter } from "next/router"; import { CSSProperties, memo, useState } from "react"; @@ -122,27 +115,16 @@ export const SiteWideAppBar = memo((props) => { pluv.io - + Docs - + Quickstart - - + diff --git a/apps/web/src/components/SiteWideFooter/SiteWideFooter.tsx b/apps/web/src/components/SiteWideFooter/SiteWideFooter.tsx index 1bd1b07a..4b82890a 100644 --- a/apps/web/src/components/SiteWideFooter/SiteWideFooter.tsx +++ b/apps/web/src/components/SiteWideFooter/SiteWideFooter.tsx @@ -1,9 +1,4 @@ -import { - Button, - Footer, - LogoIcon, - NextLink, -} from "@pluv-internal/react-components"; +import { AnchorButton, Footer, LogoIcon, NextLink } from "@pluv-internal/react-components"; import { GitHubIcon, NpmIcon } from "@pluv-internal/react-icons"; import { CSSProperties, memo } from "react"; import tw, { styled } from "twin.macro"; @@ -92,7 +87,7 @@ export const SiteWideFooter = memo((props) => { pluv.io - - + diff --git a/apps/web/src/components/SiteWideLayout/SiteWideLayout.tsx b/apps/web/src/components/SiteWideLayout/SiteWideLayout.tsx index 6ecd842a..842bd88c 100644 --- a/apps/web/src/components/SiteWideLayout/SiteWideLayout.tsx +++ b/apps/web/src/components/SiteWideLayout/SiteWideLayout.tsx @@ -13,6 +13,7 @@ const PluvIOLink = tw(Anchor)` const Root = tw.div` flex flex-col + min-h-screen `; const StyledBanner = tw(Banner)` @@ -43,11 +44,8 @@ export const SiteWideLayout = memo((props) => { {!!SHOW_BANNER && (
- - pluv.io - {" "} - is in preview! Please wait for a v1.0.0 stable release - before using this in production. + pluv.io is in preview! + Please wait for a v1.0.0 stable release before using this in production.
)} diff --git a/apps/web/src/pages/_document.tsx b/apps/web/src/pages/_document.tsx index 35ce97f4..671ce2e0 100644 --- a/apps/web/src/pages/_document.tsx +++ b/apps/web/src/pages/_document.tsx @@ -1,10 +1,4 @@ -import NextDocument, { - DocumentContext, - Head, - Html, - Main, - NextScript, -} from "next/document"; +import NextDocument, { DocumentContext, Head, Html, Main, NextScript } from "next/document"; import React from "react"; import { ServerStyleSheet } from "styled-components"; @@ -17,8 +11,7 @@ class CustomDocument extends NextDocument { try { ctx.renderPage = () => { return originalRenderPage({ - enhanceApp: (App) => (props) => - sheet.collectStyles(), + enhanceApp: (App) => (props) => sheet.collectStyles(), }); }; @@ -42,39 +35,18 @@ class CustomDocument extends NextDocument { return ( - - - + + + - + - +
diff --git a/apps/web/src/pages/docs/[[...slug]].tsx b/apps/web/src/pages/docs/[[...slug]].tsx index ccc03689..7e65de24 100644 --- a/apps/web/src/pages/docs/[[...slug]].tsx +++ b/apps/web/src/pages/docs/[[...slug]].tsx @@ -1,11 +1,6 @@ import fs from "fs-extra"; import matter from "gray-matter"; -import type { - GetStaticPaths, - GetStaticProps, - InferGetStaticPropsType, - NextPage, -} from "next"; +import type { GetStaticPaths, GetStaticProps, InferGetStaticPropsType, NextPage } from "next"; import path from "path"; import tw from "twin.macro"; import { DocsCard, DocsLayout } from "../../components"; @@ -35,10 +30,7 @@ export interface DocsIndexChild { const routes: DocRoutes = docRoutes; -const Page: NextPage> = ({ - children, - meta, -}) => { +const Page: NextPage> = ({ children, meta }) => { return ( {meta?.title} @@ -57,23 +49,15 @@ const Page: NextPage> = ({ }; const getFolderRoutes = (candidates: DocRoutes): readonly string[] => { - return Object.entries(candidates).reduce( - (acc, [slug, node]) => { - const isFolder = !!Object.keys(node.children).length; - const children = getFolderRoutes(node.children).map( - (nested) => `${slug}/${nested}`, - ); - - return isFolder ? [...acc, slug, ...children] : acc; - }, - [], - ); + return Object.entries(candidates).reduce((acc, [slug, node]) => { + const isFolder = !!Object.keys(node.children).length; + const children = getFolderRoutes(node.children).map((nested) => `${slug}/${nested}`); + + return isFolder ? [...acc, slug, ...children] : acc; + }, []); }; -const getSourcePath = ( - slugs: readonly string[], - candidates: DocRoutes, -): string => { +const getSourcePath = (slugs: readonly string[], candidates: DocRoutes): string => { const [slug, ...rest] = slugs; if (!slug) return ""; @@ -133,10 +117,7 @@ export const getStaticProps: GetStaticProps< .map((filePath) => { const contents = fs.readFileSync(filePath, { encoding: "utf-8" }); const data = (matter(contents).data ?? null) as MetaJson | null; - const name = filePath - .replace(path.extname(filePath), "") - .replace(source, "") - .replace(/^\//, ""); + const name = filePath.replace(path.extname(filePath), "").replace(source, "").replace(/^\//, ""); const slug = name .replace(/\s+/g, "-") .replace(/[^a-zA-Z0-9-\.]/g, "") diff --git a/internal/cloudflare-utils/src/Router.ts b/internal/cloudflare-utils/src/Router.ts index 00b1b17d..1b9e9f74 100644 --- a/internal/cloudflare-utils/src/Router.ts +++ b/internal/cloudflare-utils/src/Router.ts @@ -1,17 +1,14 @@ import type { Id, MaybePromise, Spread } from "@pluv/types"; import { match } from "path-to-regexp"; -type PathParamRecord< - TParamName extends string, - TParamValue extends string | string[] = string, -> = { [key in `${TParamName}`]: TParamValue }; +type PathParamRecord = { + [key in `${TParamName}`]: TParamValue; +}; export type PathParams = T extends string ? T extends `/:${infer IFullParam}` ? IFullParam extends `${infer IParamName}/${infer IRestParam}` - ? Spread< - [PathParamRecord, PathParams<`/${IRestParam}`>] - > + ? Spread<[PathParamRecord, PathParams<`/${IRestParam}`>]> : IFullParam extends `${infer IParamName}${"+" | "*"}` ? PathParamRecord : PathParamRecord @@ -53,11 +50,7 @@ type RouterPathTuple< TMethod extends RouterMethod, TPathName extends string, TPathParams extends PathParams, -> = readonly [ - method: TMethod, - path: TPathName, - handler: RouterPathHandler>, -]; +> = readonly [method: TMethod, path: TPathName, handler: RouterPathHandler>]; type RouterPaths< TContext, @@ -70,17 +63,11 @@ export interface RouterConfigOptions { context: TContext; } -export interface RouterOptions< - TContext, - TPaths extends RouterPaths, -> { +export interface RouterOptions> { paths?: TPaths; } -export class Router< - TContext, - TPaths extends RouterPaths = [], -> { +export class Router = []> { private _config: RouterConfigOptions | null = null; public paths: TPaths; @@ -91,17 +78,13 @@ export class Router< public async match(request: Request): Promise { if (!this._config) { - throw new Error( - 'Must call "setConfig" before matching a new request.', - ); + throw new Error('Must call "setConfig" before matching a new request.'); } const url = new URL(request.url); const matchedPath = this.paths.find(([method, pattern]) => { - const isMethodMatch = - this._compareMethods(request.method, method) || - method === "all"; + const isMethodMatch = this._compareMethods(request.method, method) || method === "all"; return isMethodMatch && !!match(pattern)(url.pathname); }); @@ -145,23 +128,13 @@ export class Router< method: TMethod, pattern: TPath, handler: RouterPathHandler>>, - ): Router< - TContext, - [...TPaths, ...RouterPaths>] - > { - const newPath = [[method, pattern, handler]] as RouterPaths< - TContext, - TMethod, - TPath, - PathParams - >; + ): Router>]> { + const newPath = [[method, pattern, handler]] as RouterPaths>; return Router.merge(this, new Router({ paths: newPath })); } - public setConfig( - options: RouterConfigOptions, - ): Router { + public setConfig(options: RouterConfigOptions): Router { this._config = options; return this; @@ -174,23 +147,20 @@ export class Router< private _getQuery(request: Request): ParsedUrlQuery { const url = new URL(request.url); - return Array.from(url.searchParams.entries()).reduce( - (acc, [key, value]) => { - if (typeof value === "undefined") return acc; - - const previous = acc[key]; - const decoded = decodeURIComponent(value); - - return { - ...acc, - [key]: Array.isArray(previous) - ? [...previous, decoded] - : typeof previous !== "undefined" - ? [previous, decoded] - : decoded, - }; - }, - {} as ParsedUrlQuery, - ); + return Array.from(url.searchParams.entries()).reduce((acc, [key, value]) => { + if (typeof value === "undefined") return acc; + + const previous = acc[key]; + const decoded = decodeURIComponent(value); + + return { + ...acc, + [key]: Array.isArray(previous) + ? [...previous, decoded] + : typeof previous !== "undefined" + ? [previous, decoded] + : decoded, + }; + }, {} as ParsedUrlQuery); } } diff --git a/internal/cloudflare-utils/src/UrlUtils.ts b/internal/cloudflare-utils/src/UrlUtils.ts index 65dcf755..5d0108d8 100644 --- a/internal/cloudflare-utils/src/UrlUtils.ts +++ b/internal/cloudflare-utils/src/UrlUtils.ts @@ -36,23 +36,15 @@ export class UrlUtils { } public static preferHttps(url: string): string { - return /^(https?|wss?):\/\/localhost/.test(url) - ? UrlUtils.ensureHttp(url) - : UrlUtils.ensureHttps(url); + return /^(https?|wss?):\/\/localhost/.test(url) ? UrlUtils.ensureHttp(url) : UrlUtils.ensureHttps(url); } public static preferWss(url: string): string { - return /^(https?|wss?):\/\/localhost/.test(url) - ? UrlUtils.ensureWs(url) - : UrlUtils.ensureWss(url); + return /^(https?|wss?):\/\/localhost/.test(url) ? UrlUtils.ensureWs(url) : UrlUtils.ensureWss(url); } public static relative(req: RelativeRequestLike, path: string): string { - const origin: string = UrlUtils._isLocationLike(req) - ? req.origin - : UrlUtils._isRequestLike(req) - ? req.url - : ""; + const origin: string = UrlUtils._isLocationLike(req) ? req.origin : UrlUtils._isRequestLike(req) ? req.url : ""; if (!origin) { return path; diff --git a/internal/cloudflare-utils/src/index.ts b/internal/cloudflare-utils/src/index.ts index 6ce71ba0..5be61678 100644 --- a/internal/cloudflare-utils/src/index.ts +++ b/internal/cloudflare-utils/src/index.ts @@ -1,12 +1,7 @@ export { createRouter } from "./createRouter"; export { DurableObjectUtils } from "./DurableObjectUtils"; export { RequestUtils } from "./RequestUtils"; -export type { - ParsedUrlQuery, - RouterConfigOptions, - RouterMethod, - RouterOptions, -} from "./Router"; +export type { ParsedUrlQuery, RouterConfigOptions, RouterMethod, RouterOptions } from "./Router"; export { Router } from "./Router"; export { UrlUtils } from "./UrlUtils"; export { WebSocketUtils } from "./WebSocketUtils"; diff --git a/internal/mdx-components/src/MdxBlockQuote.tsx b/internal/mdx-components/src/MdxBlockQuote.tsx index 67c6d9d4..1855c707 100644 --- a/internal/mdx-components/src/MdxBlockQuote.tsx +++ b/internal/mdx-components/src/MdxBlockQuote.tsx @@ -1,10 +1,7 @@ import { InferComponentProps } from "@pluv-internal/typings"; import tw from "twin.macro"; -export type MdxBlockQuoteProps = Omit< - InferComponentProps, - "ref" ->; +export type MdxBlockQuoteProps = Omit, "ref">; export const MdxBlockQuote = tw.blockquote` mb-[1.2em] diff --git a/internal/mdx-components/src/MdxH1.tsx b/internal/mdx-components/src/MdxH1.tsx index 78be7fe6..bce49fc3 100644 --- a/internal/mdx-components/src/MdxH1.tsx +++ b/internal/mdx-components/src/MdxH1.tsx @@ -13,11 +13,7 @@ export interface MdxH1Props { style?: CSSProperties; } -export const MdxH1 = ({ - children, - className, - style, -}: MdxH1Props): ReactElement | null => { +export const MdxH1 = ({ children, className, style }: MdxH1Props): ReactElement | null => { return ( {children} diff --git a/internal/mdx-components/src/MdxH2.tsx b/internal/mdx-components/src/MdxH2.tsx index dbcd1bfb..7946b057 100644 --- a/internal/mdx-components/src/MdxH2.tsx +++ b/internal/mdx-components/src/MdxH2.tsx @@ -13,11 +13,7 @@ export interface MdxH2Props { style?: CSSProperties; } -export const MdxH2 = ({ - children, - className, - style, -}: MdxH2Props): ReactElement | null => { +export const MdxH2 = ({ children, className, style }: MdxH2Props): ReactElement | null => { return ( {children} diff --git a/internal/mdx-components/src/MdxH3.tsx b/internal/mdx-components/src/MdxH3.tsx index 5d6b5d9e..ab6ffb7f 100644 --- a/internal/mdx-components/src/MdxH3.tsx +++ b/internal/mdx-components/src/MdxH3.tsx @@ -13,11 +13,7 @@ export interface MdxH3Props { style?: CSSProperties; } -export const MdxH3 = ({ - children, - className, - style, -}: MdxH3Props): ReactElement | null => { +export const MdxH3 = ({ children, className, style }: MdxH3Props): ReactElement | null => { return ( {children} diff --git a/internal/mdx-components/src/MdxH4.tsx b/internal/mdx-components/src/MdxH4.tsx index 0f0217b3..e7029bc3 100644 --- a/internal/mdx-components/src/MdxH4.tsx +++ b/internal/mdx-components/src/MdxH4.tsx @@ -13,11 +13,7 @@ export interface MdxH4Props { style?: CSSProperties; } -export const MdxH4 = ({ - children, - className, - style, -}: MdxH4Props): ReactElement | null => { +export const MdxH4 = ({ children, className, style }: MdxH4Props): ReactElement | null => { return ( {children} diff --git a/internal/mdx-components/src/MdxH5.tsx b/internal/mdx-components/src/MdxH5.tsx index 65bbab43..2da846c4 100644 --- a/internal/mdx-components/src/MdxH5.tsx +++ b/internal/mdx-components/src/MdxH5.tsx @@ -13,11 +13,7 @@ export interface MdxH5Props { style?: CSSProperties; } -export const MdxH5 = ({ - children, - className, - style, -}: MdxH5Props): ReactElement | null => { +export const MdxH5 = ({ children, className, style }: MdxH5Props): ReactElement | null => { return ( {children} diff --git a/internal/mdx-components/src/MdxH6.tsx b/internal/mdx-components/src/MdxH6.tsx index b2f00680..83e9a049 100644 --- a/internal/mdx-components/src/MdxH6.tsx +++ b/internal/mdx-components/src/MdxH6.tsx @@ -13,11 +13,7 @@ export interface MdxH6Props { style?: CSSProperties; } -export const MdxH6 = ({ - children, - className, - style, -}: MdxH6Props): ReactElement | null => { +export const MdxH6 = ({ children, className, style }: MdxH6Props): ReactElement | null => { return ( {children} diff --git a/internal/mdx-components/src/MdxImg.tsx b/internal/mdx-components/src/MdxImg.tsx index 7bd336bf..956fb65a 100644 --- a/internal/mdx-components/src/MdxImg.tsx +++ b/internal/mdx-components/src/MdxImg.tsx @@ -8,21 +8,8 @@ export interface MdxImgProps { style?: CSSProperties; } -export const MdxImg = ({ - alt, - className, - src, - style, -}: MdxImgProps): ReactElement | null => { +export const MdxImg = ({ alt, className, src, style }: MdxImgProps): ReactElement | null => { if (!src) return null; - return ( - - ); + return ; }; diff --git a/internal/mdx-components/src/MdxPre.tsx b/internal/mdx-components/src/MdxPre.tsx index 4e243e95..ac13b16a 100644 --- a/internal/mdx-components/src/MdxPre.tsx +++ b/internal/mdx-components/src/MdxPre.tsx @@ -1,13 +1,6 @@ import { Language, PrismCode } from "@pluv-internal/react-code"; import { InferComponentProps } from "@pluv-internal/typings"; -import { - PropsWithChildren, - ReactElement, - ReactNode, - isValidElement, - useCallback, - useMemo, -} from "react"; +import { PropsWithChildren, ReactElement, ReactNode, isValidElement, useCallback, useMemo } from "react"; import tw from "twin.macro"; const Root = tw(PrismCode)` @@ -22,12 +15,9 @@ export type MdxPreProps = Omit, "ref">; export const MdxPre = (props: MdxPreProps): ReactElement | null => { const { children, className, style } = props; - const hasChildren = useCallback( - (element: ReactNode): element is ReactElement => { - return isValidElement(element) && !!element.props.children; - }, - [], - ); + const hasChildren = useCallback((element: ReactNode): element is ReactElement => { + return isValidElement(element) && !!element.props.children; + }, []); const contents = useMemo(() => { const getChildrenText = (_children: ReactNode): string => { diff --git a/internal/mdx-components/src/MdxTable.tsx b/internal/mdx-components/src/MdxTable.tsx index 8091cf1b..b6b4af40 100644 --- a/internal/mdx-components/src/MdxTable.tsx +++ b/internal/mdx-components/src/MdxTable.tsx @@ -54,11 +54,7 @@ export interface MdxTableProps { style?: CSSProperties; } -export const MdxTable = ({ - children, - className, - style, -}: MdxTableProps): ReactElement | null => { +export const MdxTable = ({ children, className, style }: MdxTableProps): ReactElement | null => { return ( {children}
diff --git a/internal/react-chess/src/ChessBoard.tsx b/internal/react-chess/src/ChessBoard.tsx index 91226a03..10c8a788 100644 --- a/internal/react-chess/src/ChessBoard.tsx +++ b/internal/react-chess/src/ChessBoard.tsx @@ -30,131 +30,109 @@ export interface ChessBoardProps { style?: CSSProperties; } -export const ChessBoard = forwardRef( - (props, ref) => { - const { - className, - customPiece, - history = [], - id, - onGameOver, - onMove, - onSquareSelect, - style, - } = props; - - const sounds = useChessSounds(); - - const clone = useCallback((game: Chess) => { - return game - .history() - .reduce( - (board, notation) => (board.move(notation), board), - new Chess(), - ); - }, []); - - const game = useMemo((): Chess => { - return history.reduce( - (board, notation) => (board.move(notation), board), - new Chess(), - ); - }, [history]); - - const move = useCallback( - (newMove: ChessMove | string): boolean => { - if (!onMove) return false; - - const copy = clone(game); - - let move: Move | null = null; - - try { - move = copy.move(newMove); - } catch { - return false; - } - - if (!move) return false; - - const lastMove = copy - .history({ verbose: true }) - .slice(-1) - .pop(); - - if (!lastMove) throw new Error("Error while making move"); - - onMove({ game: copy, move: lastMove.san }); - - if (copy.isGameOver()) sounds.gameEnd.play(); - else if (copy.isCheck()) sounds.check.play(); - else if (lastMove.captured) sounds.capture.play(); - else if (lastMove.promotion) sounds.promote.play(); - else if (lastMove.san.startsWith("0-0")) sounds.castle.play(); - else sounds.move.play(); - - if (lastMove.promotion) sounds.promote.play(); - - return true; - }, - [clone, game, onMove, sounds], - ); - - const clear = useCallback(() => game.clear(), [game]); - - useImperativeHandle(ref, () => ({ clear, move }), [clear, move]); - - const onDrop = useCallback( - (from: Square, to: Square): boolean => { - onSquareSelect?.(to); - - // Always promote to queen for simplicity - return move({ from, to, promotion: "q" }); - }, - [move, onSquareSelect], - ); - - const isGameOver = game.isGameOver(); - const winner = isGameOver ? game.turn() : null; - - useEffect(() => { - isGameOver && onGameOver?.(winner); - }, [isGameOver, onGameOver, winner]); - - return ( -
- - !!onMove} - onPieceDragBegin={(_, square) => { - onSquareSelect?.(square); - }} - onSquareClick={onSquareSelect} - onSquareRightClick={onSquareSelect} - onPieceDrop={onDrop} - position={game.fen()} - /> - -
- {sounds.capture.element} - {sounds.castle.element} - {sounds.check.element} - {sounds.gameEnd.element} - {sounds.move.element} - {sounds.promote.element} -
+export const ChessBoard = forwardRef((props, ref) => { + const { className, customPiece, history = [], id, onGameOver, onMove, onSquareSelect, style } = props; + + const sounds = useChessSounds(); + + const clone = useCallback((game: Chess) => { + return game.history().reduce((board, notation) => (board.move(notation), board), new Chess()); + }, []); + + const game = useMemo((): Chess => { + return history.reduce((board, notation) => (board.move(notation), board), new Chess()); + }, [history]); + + const move = useCallback( + (newMove: ChessMove | string): boolean => { + if (!onMove) return false; + + const copy = clone(game); + + let move: Move | null = null; + + try { + move = copy.move(newMove); + } catch { + return false; + } + + if (!move) return false; + + const lastMove = copy.history({ verbose: true }).slice(-1).pop(); + + if (!lastMove) throw new Error("Error while making move"); + + onMove({ game: copy, move: lastMove.san }); + + if (copy.isGameOver()) sounds.gameEnd.play(); + else if (copy.isCheck()) sounds.check.play(); + else if (lastMove.captured) sounds.capture.play(); + else if (lastMove.promotion) sounds.promote.play(); + else if (lastMove.san.startsWith("0-0")) sounds.castle.play(); + else sounds.move.play(); + + if (lastMove.promotion) sounds.promote.play(); + + return true; + }, + [clone, game, onMove, sounds], + ); + + const clear = useCallback(() => game.clear(), [game]); + + useImperativeHandle(ref, () => ({ clear, move }), [clear, move]); + + const onDrop = useCallback( + (from: Square, to: Square): boolean => { + onSquareSelect?.(to); + + // Always promote to queen for simplicity + return move({ from, to, promotion: "q" }); + }, + [move, onSquareSelect], + ); + + const isGameOver = game.isGameOver(); + const winner = isGameOver ? game.turn() : null; + + useEffect(() => { + isGameOver && onGameOver?.(winner); + }, [isGameOver, onGameOver, winner]); + + return ( +
+ + !!onMove} + onPieceDragBegin={(_, square) => { + onSquareSelect?.(square); + }} + onSquareClick={onSquareSelect} + onSquareRightClick={onSquareSelect} + onPieceDrop={onDrop} + position={game.fen()} + /> + +
+ {sounds.capture.element} + {sounds.castle.element} + {sounds.check.element} + {sounds.gameEnd.element} + {sounds.move.element} + {sounds.promote.element}
- ); - }, -); +
+ ); +}); ChessBoard.displayName = "ChessBoard"; diff --git a/internal/react-chess/src/ChessMoveHistory.tsx b/internal/react-chess/src/ChessMoveHistory.tsx index e0448968..dacbad2e 100644 --- a/internal/react-chess/src/ChessMoveHistory.tsx +++ b/internal/react-chess/src/ChessMoveHistory.tsx @@ -55,19 +55,13 @@ export interface ChessMoveHistoryProps { style?: CSSProperties; } -export const ChessMoveHistory: FC = ({ - className, - history, - style, -}) => { +export const ChessMoveHistory: FC = ({ className, history, style }) => { const turns: readonly MoveTurn[] = useMemo(() => { return history.reduce((acc, move, i) => { const lastWhite = acc.slice(-1)?.[0]?.[0] ?? null; const isWhiteTurn = !(i % 2); - return isWhiteTurn - ? [...acc, [move, null]] - : [...acc.slice(0, -1), [lastWhite, move]]; + return isWhiteTurn ? [...acc, [move, null]] : [...acc.slice(0, -1), [lastWhite, move]]; }, []); }, [history]); diff --git a/internal/react-chess/src/KingPiece.tsx b/internal/react-chess/src/KingPiece.tsx index b2ea3394..4b664ff3 100644 --- a/internal/react-chess/src/KingPiece.tsx +++ b/internal/react-chess/src/KingPiece.tsx @@ -34,18 +34,8 @@ export const KingPiece: FC = ({ className, style }) => { strokeDasharray="none" strokeOpacity={1} > - - + + = ({ className, style }) => { stroke="rgb(0, 0, 0)" d="M 12.5,37 C 18,40.5 27,40.5 32.5,37 L 32.5,30 C 32.5,30 41.5,25.5 38.5,19.5 C 34.5,13 25,16 22.5,23.5 L 22.5,27 L 22.5,23.5 C 20,16 10.5,13 6.5,19.5 C 3.5,25.5 12.5,30 12.5,30 L 12.5,37" /> - - - + + + ); diff --git a/internal/react-chess/src/LoadingChessBoard.tsx b/internal/react-chess/src/LoadingChessBoard.tsx index 370581dd..92445de6 100644 --- a/internal/react-chess/src/LoadingChessBoard.tsx +++ b/internal/react-chess/src/LoadingChessBoard.tsx @@ -78,10 +78,7 @@ export interface LoadingChessBoardProps { export const LoadingChessBoard = memo((props) => { const { children = () => , className, style } = props; - const [position, setPosition] = useState<[row: number, col: number]>([ - BOARD_SIZE / 2 - 1, - BOARD_SIZE / 2 - 1, - ]); + const [position, setPosition] = useState<[row: number, col: number]>([BOARD_SIZE / 2 - 1, BOARD_SIZE / 2 - 1]); useEffect(() => { const interval = setInterval(() => { @@ -107,11 +104,7 @@ export const LoadingChessBoard = memo((props) => { {Array.from({ length: BOARD_SIZE }, (_, j) => ( {!j && {BOARD_SIZE - i}} - {i === BOARD_SIZE - 1 && ( - - {String.fromCharCode(65 + j).toLowerCase()} - - )} + {i === BOARD_SIZE - 1 && {String.fromCharCode(65 + j).toLowerCase()}} {row === i && col === j && children({ position })} ))} diff --git a/internal/react-chess/src/defaultPieces.tsx b/internal/react-chess/src/defaultPieces.tsx index 19d424fa..e57242d2 100644 --- a/internal/react-chess/src/defaultPieces.tsx +++ b/internal/react-chess/src/defaultPieces.tsx @@ -8,12 +8,7 @@ import type { ReactNode } from "react"; export const defaultPieces: Record = { wP: ( - + = { ), wR: ( - + = { strokeOpacity: "1", }} > - - + + = { ), wN: ( - + = { ), wB: ( - + = { ), wQ: ( - + = { > - - + + @@ -203,12 +166,7 @@ export const defaultPieces: Record = { ), wK: ( - + = { d="M 12.5,37 C 18,40.5 27,40.5 32.5,37 L 32.5,30 C 32.5,30 41.5,25.5 38.5,19.5 C 34.5,13 25,16 22.5,23.5 L 22.5,27 L 22.5,23.5 C 20,16 10.5,13 6.5,19.5 C 3.5,25.5 12.5,30 12.5,30 L 12.5,37" style={{ fill: "#ffffff", stroke: "#000000" }} /> - - - + + + ), bP: ( - + = { ), bR: ( - + = { strokeOpacity: "1", }} > - - - + + + - + = { ), bN: ( - + = { ), bB: ( - + = { ), bQ: ( - + = { ), bK: ( - + { diff --git a/internal/react-chess/src/useChessSounds.ts b/internal/react-chess/src/useChessSounds.ts index d8be7da6..a62182fe 100644 --- a/internal/react-chess/src/useChessSounds.ts +++ b/internal/react-chess/src/useChessSounds.ts @@ -2,8 +2,7 @@ import { useAudio } from "@pluv-internal/react-hooks"; import type { ReactElement } from "react"; import { useMemo } from "react"; -const ASSET_BASE_PREFIX = - "https://raw.githubusercontent.com/pluv-io/pluv/master/assets/"; +const ASSET_BASE_PREFIX = "https://raw.githubusercontent.com/pluv-io/pluv/master/assets/"; export interface SoundControls { element: ReactElement; diff --git a/internal/react-code/src/CodeTooltipIcon.tsx b/internal/react-code/src/CodeTooltipIcon.tsx index 4ad12475..7d0861b7 100644 --- a/internal/react-code/src/CodeTooltipIcon.tsx +++ b/internal/react-code/src/CodeTooltipIcon.tsx @@ -7,10 +7,7 @@ export type CodeTooltipIconProps = InferComponentProps<"svg"> & { type?: CodeTooltipIconType; }; -export const CodeTooltipIcon: FC = ({ - type = "field", - ...svgProps -}) => { +export const CodeTooltipIcon: FC = ({ type = "field", ...svgProps }) => { switch (type) { case "field": return ( diff --git a/internal/react-code/src/MultiPrismCode.tsx b/internal/react-code/src/MultiPrismCode.tsx index cf4da77e..91b4e56d 100644 --- a/internal/react-code/src/MultiPrismCode.tsx +++ b/internal/react-code/src/MultiPrismCode.tsx @@ -91,9 +91,7 @@ export interface MultiPrismCodeProps { tabs?: readonly MultiPrismCodeTab[]; } -export const MultiPrismCode = ( - props: MultiPrismCodeProps, -): ReactElement => { +export const MultiPrismCode = (props: MultiPrismCodeProps): ReactElement => { const { className, style, tabs = [] } = props; const defaultTab = useMemo((): TTab | undefined => tabs[0]?.name, [tabs]); @@ -109,9 +107,7 @@ export const MultiPrismCode = ( {tabs.map((tab) => ( - - {tab.code} - + {tab.code} ))} diff --git a/internal/react-code/src/PrismCode.tsx b/internal/react-code/src/PrismCode.tsx index 4ec45353..23ca251a 100644 --- a/internal/react-code/src/PrismCode.tsx +++ b/internal/react-code/src/PrismCode.tsx @@ -119,29 +119,15 @@ export const PrismCode = memo( className: _className, language = "tsx", style: _style, - tokenRenderer: Token = ({ tokenProps }) => , + tokenRenderer: Token = ({ tokenProps }) => , } = props; return ( - - {({ - className, - style, - tokens, - getLineProps, - getTokenProps, - }) => ( -
+            
+                {({ className, style, tokens, getLineProps, getTokenProps }) => (
+                    
                         {tokens.map((line, i) => (
-                            
+                            
                                 {i + 1}
                                 
                                     {line.map((token, key) => (
diff --git a/internal/react-code/src/index.ts b/internal/react-code/src/index.ts
index 9ec6d6df..dfee22d8 100644
--- a/internal/react-code/src/index.ts
+++ b/internal/react-code/src/index.ts
@@ -1,16 +1,9 @@
 export type { CodeTooltipProps } from "./CodeTooltip";
 export { CodeTooltip } from "./CodeTooltip";
-export type {
-    CodeTooltipIconProps,
-    CodeTooltipIconType,
-} from "./CodeTooltipIcon";
+export type { CodeTooltipIconProps, CodeTooltipIconType } from "./CodeTooltipIcon";
 export { CodeTooltipIcon } from "./CodeTooltipIcon";
 export { LaserWaveTheme } from "./LaserWaveTheme";
 export type { MultiPrismCodeProps, MultiPrismCodeTab } from "./MultiPrismCode";
 export { MultiPrismCode } from "./MultiPrismCode";
-export type {
-    Language,
-    PrismCodeProps,
-    PrismCodeTokenProps,
-} from "./PrismCode";
+export type { Language, PrismCodeProps, PrismCodeTokenProps } from "./PrismCode";
 export { PrismCode } from "./PrismCode";
diff --git a/internal/react-components/package.json b/internal/react-components/package.json
index b4610989..94f629b6 100644
--- a/internal/react-components/package.json
+++ b/internal/react-components/package.json
@@ -14,13 +14,17 @@
 		"@emotion/is-prop-valid": "^1.2.2",
 		"@pluv-internal/react-hooks": "workspace:^",
 		"@pluv-internal/react-icons": "workspace:^",
+		"@pluv-internal/utils": "workspace:^",
 		"@radix-ui/react-dialog": "^1.0.5",
 		"@radix-ui/react-navigation-menu": "^1.1.4",
 		"@radix-ui/react-visually-hidden": "^1.0.3",
+		"@types/common-tags": "^1.8.4",
 		"@types/ms": "^0.7.34",
 		"@types/react": "^18.3.1",
 		"@types/react-dom": "^18.3.0",
+		"class-variance-authority": "^0.7.0",
 		"clsx": "^2.1.1",
+		"common-tags": "^1.8.2",
 		"framer-motion": "^11.1.7",
 		"ms": "^2.1.3",
 		"next": "^14.2.3",
diff --git a/internal/react-components/src/GlobalStyles.tsx b/internal/react-components/src/GlobalStyles.tsx
index 3dfd0634..e2a0dcaf 100644
--- a/internal/react-components/src/GlobalStyles.tsx
+++ b/internal/react-components/src/GlobalStyles.tsx
@@ -3,8 +3,7 @@ import tw, { globalStyles } from "twin.macro";
 
 const baseStyles = Object.fromEntries(
     Object.entries(globalStyles).filter(
-        ([prop]) =>
-            prop !== "button, [type='button'], [type='reset'], [type='submit']",
+        ([prop]) => prop !== "button, [type='button'], [type='reset'], [type='submit']",
     ),
 ) as any;
 
diff --git a/internal/react-components/src/atoms/Anchor/Anchor.tsx b/internal/react-components/src/atoms/Anchor/Anchor.tsx
index b09425e1..f8fbc15d 100644
--- a/internal/react-components/src/atoms/Anchor/Anchor.tsx
+++ b/internal/react-components/src/atoms/Anchor/Anchor.tsx
@@ -1,14 +1,31 @@
-import { InferComponentProps } from "@pluv-internal/typings";
-import tw from "twin.macro";
+import type { InferComponentProps } from "@pluv-internal/typings";
+import { cn } from "@pluv-internal/utils";
+import { oneLine } from "common-tags";
+import { forwardRef } from "react";
 import { NextLink } from "../NextLink";
 
-export type AnchorProps = InferComponentProps;
+export type AnchorProps = InferComponentProps;
 
-export const Anchor = tw(NextLink)`
-    hover:text-sky-500
-    hover:underline
-    transition-colors
-    duration-75
-    ease-in
-    [&[data-selected="true"]]:text-sky-500
-`;
+export const Anchor = forwardRef((props, ref) => {
+    const { className, ...restProps } = props;
+
+    return (
+        
+    );
+});
+
+Anchor.displayName = "Anchor";
diff --git a/internal/react-components/src/atoms/AnchorButton/AnchorButton.tsx b/internal/react-components/src/atoms/AnchorButton/AnchorButton.tsx
new file mode 100644
index 00000000..b7ae7846
--- /dev/null
+++ b/internal/react-components/src/atoms/AnchorButton/AnchorButton.tsx
@@ -0,0 +1,22 @@
+import type { InferComponentProps } from "@pluv-internal/typings";
+import { cn } from "@pluv-internal/utils";
+import type { VariantProps } from "class-variance-authority";
+import { forwardRef } from "react";
+import { buttonVariants } from "../Button/Button";
+import { NextLink } from "../NextLink";
+
+export type AnchorButtonProps = InferComponentProps & VariantProps;
+
+export const AnchorButton = forwardRef((props, ref) => {
+    const { bounce, className, outlined, size, square, variant, ...restProps } = props;
+
+    return (
+        
+    );
+});
+
+AnchorButton.displayName = "Button";
diff --git a/internal/react-components/src/atoms/AnchorButton/index.ts b/internal/react-components/src/atoms/AnchorButton/index.ts
new file mode 100644
index 00000000..f121e27c
--- /dev/null
+++ b/internal/react-components/src/atoms/AnchorButton/index.ts
@@ -0,0 +1 @@
+export * from "./AnchorButton";
diff --git a/internal/react-components/src/atoms/AnchorPill/AnchorPill.tsx b/internal/react-components/src/atoms/AnchorPill/AnchorPill.tsx
new file mode 100644
index 00000000..82af496b
--- /dev/null
+++ b/internal/react-components/src/atoms/AnchorPill/AnchorPill.tsx
@@ -0,0 +1,39 @@
+import type { InferComponentProps } from "@pluv-internal/typings";
+import { cn } from "@pluv-internal/utils";
+import { oneLine } from "common-tags";
+import { forwardRef } from "react";
+import { NextLink } from "../NextLink";
+
+export type AnchorPillProps = InferComponentProps;
+
+export const AnchorPill = forwardRef((props, ref) => {
+    const { className, ...restProps } = props;
+
+    return (
+        
+    );
+});
+
+AnchorPill.displayName = "AnchorPill";
diff --git a/internal/react-components/src/atoms/AnchorPill/index.ts b/internal/react-components/src/atoms/AnchorPill/index.ts
new file mode 100644
index 00000000..9729d525
--- /dev/null
+++ b/internal/react-components/src/atoms/AnchorPill/index.ts
@@ -0,0 +1 @@
+export * from "./AnchorPill";
diff --git a/internal/react-components/src/atoms/AppBar/AppBar.tsx b/internal/react-components/src/atoms/AppBar/AppBar.tsx
index dfd3f0cd..39191e4f 100644
--- a/internal/react-components/src/atoms/AppBar/AppBar.tsx
+++ b/internal/react-components/src/atoms/AppBar/AppBar.tsx
@@ -1,23 +1,37 @@
 import type { InferComponentProps } from "@pluv-internal/typings";
-import tw, { styled } from "twin.macro";
-import { getZIndex } from "../../z-indices";
+import { cn } from "@pluv-internal/utils";
+import { oneLine } from "common-tags";
+import { forwardRef } from "react";
 
-export type AppBarProps = InferComponentProps;
+export type AppBarProps = InferComponentProps<"div">;
 
-export const AppBar = styled.div`
-    ${tw`
-        sticky
-        top-0
-        w-full
-        min-h-[4rem]
-        py-2
-        px-4
-        border-b
-        border-solid
-        border-indigo-700/60
-        shadow-lg
-        shadow-indigo-800
-        bg-zinc-800
-    `}
-    z-index: ${getZIndex("app-bar")};
-`;
+export const AppBar = forwardRef((props, ref) => {
+    const { className, ...restProps } = props;
+
+    return (
+        
+ ); +}); + +AppBar.displayName = "AppBar"; diff --git a/internal/react-components/src/atoms/Banner/Banner.tsx b/internal/react-components/src/atoms/Banner/Banner.tsx index 5ee3abe5..b1aa5379 100644 --- a/internal/react-components/src/atoms/Banner/Banner.tsx +++ b/internal/react-components/src/atoms/Banner/Banner.tsx @@ -1,21 +1,38 @@ -import { InferComponentProps } from "@pluv-internal/typings"; -import tw from "twin.macro"; +import type { InferComponentProps } from "@pluv-internal/typings"; +import { cn } from "@pluv-internal/utils"; +import { oneLine } from "common-tags"; +import { forwardRef } from "react"; -export type BannerProps = InferComponentProps; +export type BannerProps = InferComponentProps<"div">; -export const Banner = tw.div` - flex - flex-row - items-center - justify-center - w-full - py-2 - px-4 - border-b - border-solid - border-zinc-800 - bg-indigo-700 - text-white - text-center - text-sm -`; +export const Banner = forwardRef((props, ref) => { + const { className, ...restProps } = props; + + return ( +
+ ); +}); + +Banner.displayName = "Banner"; diff --git a/internal/react-components/src/atoms/Button/Button.tsx b/internal/react-components/src/atoms/Button/Button.tsx index 25c569e9..424abb28 100644 --- a/internal/react-components/src/atoms/Button/Button.tsx +++ b/internal/react-components/src/atoms/Button/Button.tsx @@ -1,153 +1,102 @@ -import isPropValid from "@emotion/is-prop-valid"; import type { InferComponentProps } from "@pluv-internal/typings"; -import tw, { styled } from "twin.macro"; +import { cn } from "@pluv-internal/utils"; +import type { VariantProps } from "class-variance-authority"; +import { cva } from "class-variance-authority"; +import { oneLine } from "common-tags"; +import { forwardRef } from "react"; -export type ButtonVariant = - | "alert" - | "error" - | "primary" - | "secondary" - | "success"; +export type ButtonVariant = "alert" | "error" | "primary" | "secondary" | "success"; -export type ButtonProps = InferComponentProps; +export type ButtonProps = InferComponentProps<"button"> & VariantProps; -export const Button = styled.button.withConfig({ - shouldForwardProp(prop) { - return isPropValid(prop); - }, -})<{ - bounce?: boolean; - outlined?: boolean; - size?: "small" | "medium" | "large"; - square?: boolean; - variant?: ButtonVariant; -}>` - ${tw` - relative - flex - items-center - justify-center - border - border-solid - border-transparent - rounded-md - font-semibold - cursor-pointer - transition - duration-150 - ease-in-out - shadow-sm - transform - disabled:shadow-none - disabled:opacity-60 - disabled:cursor-not-allowed - not-disabled:active:shadow-none - not-disabled:hover:shadow-md - not-disabled:hover:opacity-80 - disabled:after:absolute - disabled:after:inset-0 - disabled:after:pointer-events-auto - disabled:after:cursor-not-allowed - `} - - ${({ bounce = true }) => bounce && tw`not-disabled:hover:-translate-y-0.5`} - - ${({ outlined, variant = "primary" }) => { - switch (variant) { - case "alert": - return outlined - ? tw`border-pink-600` - : tw` - bg-pink-600 - text-white - `; - case "error": - return outlined - ? tw`border-rose-600` - : tw` - bg-rose-600 - text-white - `; - case "primary": - return outlined - ? tw`border-sky-500` - : tw` - bg-sky-500 - text-black - `; - case "secondary": - return outlined - ? tw`border-amber-400` - : tw` - bg-amber-400 - text-black - `; - case "success": - return outlined - ? tw`border-emerald-500` - : tw` - bg-emerald-500 - text-black - `; - default: - return null; - } - }} - - ${tw` - border-opacity-40 +export const buttonVariants = cva( + oneLine` + not-disabled:active:shadow-none + not-disabled:hover:shadow-md + not-disabled:hover:opacity-80 not-disabled:hover:border-opacity-100 - `} - - ${({ size = "medium" }) => { - switch (size) { - case "large": - return tw` - text-lg - font-bold - `; - case "small": - return tw` - text-base - rounded - `; - case "medium": - default: - return tw`text-lg`; - } - }} + relative + flex + transform + cursor-pointer + items-center + justify-center + border + border-solid + border-transparent + border-opacity-40 + font-semibold + leading-snug + shadow-sm + transition + duration-150 + ease-in-out + disabled:cursor-not-allowed + disabled:opacity-60 + disabled:shadow-none + disabled:after:pointer-events-auto + disabled:after:absolute + disabled:after:inset-0 + disabled:after:cursor-not-allowed + `, + { + variants: { + bounce: { true: "not-disabled:hover:-translate-y-0.5", false: "" }, + outlined: { true: "", false: "" }, + size: { + small: "rounded text-base", + medium: "rounded-md text-lg", + large: "rounded-md text-lg font-bold", + }, + square: { true: "", false: "" }, + variant: { alert: "", error: "", primary: "", secondary: "", success: "" }, + }, + defaultVariants: { + bounce: true, + }, + compoundVariants: [ + { outlined: true, variant: "alert", className: "border-pink-600" }, + { outlined: false, variant: "alert", className: "bg-pink-600 text-white" }, + { outlined: true, variant: "error", className: "border-rose-600" }, + { outlined: false, variant: "error", className: "bg-rose-600 text-white" }, + { outlined: true, variant: "primary", className: "border-sky-500" }, + { outlined: false, variant: "primary", className: "bg-sky-500 text-black" }, + { outlined: true, variant: "secondary", className: "border-amber-400" }, + { outlined: false, variant: "secondary", className: "bg-amber-400 text-black" }, + { outlined: true, variant: "success", className: "border-emerald-500" }, + { outlined: false, variant: "success", className: "bg-emerald-500 text-black" }, + { size: "small", square: true, className: "p-1" }, + { size: "small", square: false, className: "px-1.5 py-1" }, + { size: "medium", square: true, className: "p-2" }, + { size: "medium", square: false, className: "px-2.5 py-2" }, + { size: "large", square: true, className: "p-3.5" }, + { size: "large", square: false, className: "px-4 py-3.5" }, + ], + }, +); -${({ size = "medium", square }) => { - switch (size) { - case "large": - return square - ? tw`p-3.5` - : tw` - px-4 - py-3.5 - `; - case "small": - return square - ? tw`p-1` - : tw` - px-1.5 - py-1 - `; - case "medium": - default: - return square - ? tw`p-2` - : tw` - px-2.5 - py-2 - `; - } - }} +export const Button = forwardRef((props, ref) => { + const { + bounce, + className, + outlined, + role = "button", + size, + square, + type = "button", + variant, + ...restProps + } = props; - ${tw`leading-snug`} -`; + return ( + + ); }; diff --git a/internal/react-components/src/molecules/TreeView/TreeViewLink.tsx b/internal/react-components/src/molecules/TreeView/TreeViewLink.tsx index c0919513..2d16c4a9 100644 --- a/internal/react-components/src/molecules/TreeView/TreeViewLink.tsx +++ b/internal/react-components/src/molecules/TreeView/TreeViewLink.tsx @@ -1,37 +1,9 @@ +import { cn } from "@pluv-internal/utils"; import * as NavigationMenu from "@radix-ui/react-navigation-menu"; -import { CSSProperties, FC, MouseEvent, ReactNode } from "react"; -import tw from "twin.macro"; +import { oneLine } from "common-tags"; +import type { CSSProperties, FC, MouseEvent, ReactNode } from "react"; import { NextLink } from "../../atoms"; -const Root = tw(NavigationMenu.Item)` - flex - flex-col - items-stretch -`; - -const Item = tw(NextLink)` - flex - flex-row - items-center - h-8 - px-3 - rounded - text-sm - transition-colors - duration-150 - ease-in - cursor-pointer - text-slate-400 - hover:bg-slate-300/10 - hover:text-white - focus:bg-slate-300/20 - focus:text-white - active:bg-slate-300/40 - active:text-white - [&[data-selected="true"]]:text-sky-500 - [&[data-selected="true"]]:bg-slate-300/20 -`; - export interface TreeViewLinkProps { children?: ReactNode; className?: string; @@ -54,9 +26,31 @@ export const TreeViewLink: FC = ({ target, }) => { return ( - + - = ({ data-selected={selected} > {children} - + - + ); }; diff --git a/internal/react-components/src/molecules/TreeView/TreeViewList.tsx b/internal/react-components/src/molecules/TreeView/TreeViewList.tsx index dc056cec..df70d9a9 100644 --- a/internal/react-components/src/molecules/TreeView/TreeViewList.tsx +++ b/internal/react-components/src/molecules/TreeView/TreeViewList.tsx @@ -1,100 +1,11 @@ import { ChevronDownIcon } from "@pluv-internal/react-icons"; +import { cn } from "@pluv-internal/utils"; import * as NavigationMenu from "@radix-ui/react-navigation-menu"; +import { oneLine } from "common-tags"; import { m } from "framer-motion"; import { CSSProperties, FC, ReactNode, useState } from "react"; -import tw, { styled } from "twin.macro"; import { NextLink } from "../../atoms"; -const Root = tw(NavigationMenu.Item)` - flex - flex-col - items-stretch -`; - -const ItemContent = styled.button` - ${tw` - grow - flex - flex-row - items-center - px-3 - font-semibold - cursor-pointer - `} - - &::before { - ${tw` - content-[""] - absolute - inset-0 - rounded - transition-colors - duration-150 - ease-in - cursor-pointer - bg-slate-300/0 - pointer-events-none - `} - } - - ${tw` - hover:before:bg-slate-300/10 - focus:before:bg-slate-300/20 - active:before:bg-slate-300/40 - `} -`; - -const Item = styled.div` - ${tw` - relative - flex - flex-row - items-stretch - h-8 - [&[data-selected="true"]]:text-sky-500 - `} - - &[data-selected="true"] ${ItemContent} { - ${tw`before:bg-slate-300/20`} - } -`; - -const StyledIcon = tw(ChevronDownIcon)` - -rotate-90 - transition - duration-150 - ease-linear -`; - -const ChevronButton = styled.button` - ${tw` - flex - items-center - justify-center - w-8 - rounded - hover:bg-slate-300/10 - focus:bg-slate-300/20 - active:bg-slate-300/40 - `} - - &[aria-expanded="true"] > ${StyledIcon} { - ${tw` - rotate-0 - `} - } -`; - -const Content = tw(m.ul)` - flex - flex-col - items-stretch - gap-0.5 - mt-0.5 - pl-3 - overflow-y-clip -`; - export interface TreeViewListProps { children?: ReactNode; className?: string; @@ -116,36 +27,101 @@ export const TreeViewList: FC = ({ }) => { const [open, setOpen] = useState(defaultOpen); + const childStyle = oneLine` + flex + grow + cursor-pointer + flex-row + items-center + px-3 + font-semibold + before:pointer-events-none + before:absolute + before:inset-0 + before:cursor-pointer + before:rounded + before:bg-slate-300/0 + before:transition-colors + before:duration-150 + before:ease-in + before:content-[""] + hover:before:bg-slate-300/10 + focus:before:bg-slate-300/20 + active:before:bg-slate-300/40 + `; + const child = href ? ( - { e.stopPropagation(); }} > {children} - + ) : ( - {children} + ); return ( - - +
:first-child]:before:bg-slate-300/20 + [&[data-selected="true"]]:text-sky-500 + `} onClick={() => { setOpen((oldOpen) => !oldOpen); }} data-selected={selected} > {child} - - - - - :first-child]:rotate-0 + `} + aria-expanded={open || selected} + > + + +
+ = ({ }} > {content} - -
+ + ); }; diff --git a/internal/react-components/src/molecules/Typist/TypistCursor.tsx b/internal/react-components/src/molecules/Typist/TypistCursor.tsx index 546877dd..7b6166bd 100644 --- a/internal/react-components/src/molecules/Typist/TypistCursor.tsx +++ b/internal/react-components/src/molecules/Typist/TypistCursor.tsx @@ -1,27 +1,30 @@ -import { keyframes } from "styled-components"; -import tw, { styled } from "twin.macro"; +import type { InferComponentProps } from "@pluv-internal/typings"; +import { cn } from "@pluv-internal/utils"; +import { oneLine } from "common-tags"; +import { forwardRef } from "react"; -const blink = keyframes` - 0% { - opacity: 1 - } - 50% { - opacity: 0 - } - to { - opacity: 1 - } -`; +export type TypistCursorProps = InferComponentProps<"span">; -export const TypistCursor = styled.span` - ${tw` - font-medium - `} - font-size: 0.84em; - opacity: 1; - animation: ${blink} 1s linear infinite; -`; +export const TypistCursor = forwardRef((props, ref) => { + const { className, ...restProps } = props; -TypistCursor.defaultProps = { - children: "|", -}; + return ( + + {"|"} + + ); +}); + +TypistCursor.displayName = "TypistCursor"; diff --git a/internal/react-components/src/molecules/index.ts b/internal/react-components/src/molecules/index.ts index fb8114cd..f9b925c9 100644 --- a/internal/react-components/src/molecules/index.ts +++ b/internal/react-components/src/molecules/index.ts @@ -2,11 +2,7 @@ export type { BreadcrumbsItemProps, BreadcrumbsProps } from "./Breadcrumbs"; export { Breadcrumbs } from "./Breadcrumbs"; export type { TableOfContentsProps } from "./TableOfContents"; export { TableOfContents } from "./TableOfContents"; -export type { - TreeViewButtonProps, - TreeViewLinkProps, - TreeViewProps, -} from "./TreeView"; +export type { TreeViewButtonProps, TreeViewLinkProps, TreeViewProps } from "./TreeView"; export { TreeView } from "./TreeView"; export type { TypistProps, TypistState } from "./Typist"; export { Typist } from "./Typist"; diff --git a/internal/react-components/src/utils/filterValidProps.ts b/internal/react-components/src/utils/filterValidProps.ts index 8c9d0e04..4d30cce5 100644 --- a/internal/react-components/src/utils/filterValidProps.ts +++ b/internal/react-components/src/utils/filterValidProps.ts @@ -1,8 +1,6 @@ import isPropValid from "@emotion/is-prop-valid"; -export const filterValidProps = >( - props: TProps, -): TProps => { +export const filterValidProps = >(props: TProps): TProps => { return Object.entries(props).reduce((acc, [key, value]) => { return isPropValid(key) ? { ...acc, [key]: value } : acc; }, {} as TProps); diff --git a/internal/react-components/src/z-indices.ts b/internal/react-components/src/z-indices.ts index 8b5deb58..676ae020 100644 --- a/internal/react-components/src/z-indices.ts +++ b/internal/react-components/src/z-indices.ts @@ -1,11 +1,4 @@ -const zIndices = [ - "default", - "extra", - "footer", - "app-bar", - "backdrop", - "side-drawer", -] as const; +const zIndices = ["default", "extra", "footer", "app-bar", "backdrop", "side-drawer"] as const; export type ZIndexElement = (typeof zIndices)[number]; diff --git a/internal/react-hooks/src/index.ts b/internal/react-hooks/src/index.ts index cfed5f8b..ac2e0112 100644 --- a/internal/react-hooks/src/index.ts +++ b/internal/react-hooks/src/index.ts @@ -5,17 +5,9 @@ export { useMeasure } from "./useMeasure"; export { useMediaQuery } from "./useMediaQuery"; export type { NoSsrFunction } from "./useNoSsr"; export { useNoSsr } from "./useNoSsr"; -export type { - OrchestratedTypistState, - UseOrchestratedTypistParams, -} from "./useOrchestratedTypist"; +export type { OrchestratedTypistState, UseOrchestratedTypistParams } from "./useOrchestratedTypist"; export { useOrchestratedTypist } from "./useOrchestratedTypist"; -export type { - TypistMode, - TypistState, - UseTypistActions, - UseTypistParams, -} from "./useTypist"; +export type { TypistMode, TypistState, UseTypistActions, UseTypistParams } from "./useTypist"; export { useTypist } from "./useTypist"; export { useUpdateEffect } from "./useUpdateEffect"; export { useWindowFocus } from "./useWindowFocus"; diff --git a/internal/react-hooks/src/useNoSsr.ts b/internal/react-hooks/src/useNoSsr.ts index b830670a..dbcd688a 100644 --- a/internal/react-hooks/src/useNoSsr.ts +++ b/internal/react-hooks/src/useNoSsr.ts @@ -9,11 +9,7 @@ export const useNoSsr = (): NoSsrFunction => { const noSsr = useCallback( (value: T | (() => T), fallback?: T): T | null => { - return didMount - ? typeof value !== "function" - ? value - : (value as () => T)() - : fallback ?? null; + return didMount ? (typeof value !== "function" ? value : (value as () => T)()) : fallback ?? null; }, [didMount], ); diff --git a/internal/react-hooks/src/useOrchestratedTypist.ts b/internal/react-hooks/src/useOrchestratedTypist.ts index f9571f48..e83c79fe 100644 --- a/internal/react-hooks/src/useOrchestratedTypist.ts +++ b/internal/react-hooks/src/useOrchestratedTypist.ts @@ -8,14 +8,7 @@ export interface OrchestratedTypistState { export type UseOrchestratedTypistParams = Pick< UseTypistParams, - | "deleteDelay" - | "deleteSpeed" - | "paused" - | "repeat" - | "repeatDelay" - | "sentences" - | "typingDelay" - | "typingSpeed" + "deleteDelay" | "deleteSpeed" | "paused" | "repeat" | "repeatDelay" | "sentences" | "typingDelay" | "typingSpeed" > & { onChange?: (state: OrchestratedTypistState) => void; }; @@ -48,8 +41,7 @@ export const useOrchestratedTypist = ( return sentences.reduce((acc, _, i) => { const prevSentence = sentences[i - 1] ?? ""; const prevDelay = acc[i - 1] ?? 0; - const delay = - prevSentence.length * typingSpeed + prevDelay + typingDelay; + const delay = prevSentence.length * typingSpeed + prevDelay + typingDelay; return [...acc, delay]; }, []); diff --git a/internal/react-hooks/src/useTypist.ts b/internal/react-hooks/src/useTypist.ts index fe0ace82..318ef2c9 100644 --- a/internal/react-hooks/src/useTypist.ts +++ b/internal/react-hooks/src/useTypist.ts @@ -4,12 +4,7 @@ import { RefObject, useRef } from "react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useWindowFocus } from "./useWindowFocus"; -export type TypistMode = - | "starting" - | "typing" - | "deleting" - | "paused" - | "halted"; +export type TypistMode = "starting" | "typing" | "deleting" | "paused" | "halted"; export interface TypistState { completed: boolean; @@ -65,16 +60,12 @@ export const useTypist = ( const hasDisplayedSentence: boolean = !!displayedSentence; const sentencesCount: number = sentences.length; - const timeoutsRef = useRef< - [ - timeout1: number | null, - timeout2: number | null, - timeout3: number | null, - ] - >([null, null, null]); - const intervalsRef = useRef< - [interval1: number | null, interval2: number | null] - >([null, null]); + const timeoutsRef = useRef<[timeout1: number | null, timeout2: number | null, timeout3: number | null]>([ + null, + null, + null, + ]); + const intervalsRef = useRef<[interval1: number | null, interval2: number | null]>([null, null]); const isViewed = focused && isIntersecting; @@ -207,9 +198,7 @@ export const useTypist = ( if (mode !== "deleting") return; if (hasDisplayedSentence) return; - setIndex((oldIndex) => - oldIndex >= sentencesCount - 1 ? 0 : oldIndex + 1, - ); + setIndex((oldIndex) => (oldIndex >= sentencesCount - 1 ? 0 : oldIndex + 1)); setMode("starting"); }, [hasDisplayedSentence, index, mode, paused, sentencesCount]); @@ -231,18 +220,9 @@ export const useTypist = ( return () => { clearTimeout(timeout); }; - }, [ - hasDisplayedSentence, - index, - mode, - paused, - repeat, - repeatDelay, - sentencesCount, - ]); + }, [hasDisplayedSentence, index, mode, paused, repeat, repeatDelay, sentencesCount]); - const completed = - isCompleted && index === sentencesCount - 1 && mode === "paused"; + const completed = isCompleted && index === sentencesCount - 1 && mode === "paused"; const typistState = useMemo( () => ({ completed, mode, text: displayedSentence }), diff --git a/internal/react-hooks/src/useWindowFocus.ts b/internal/react-hooks/src/useWindowFocus.ts index 93435d2f..a754a8f5 100644 --- a/internal/react-hooks/src/useWindowFocus.ts +++ b/internal/react-hooks/src/useWindowFocus.ts @@ -7,9 +7,7 @@ const hasFocus = (): boolean => { * @author David Lee * @date March 26, 2022 */ - return typeof document !== "undefined" - ? document.hasFocus() || document.visibilityState === "visible" - : true; + return typeof document !== "undefined" ? document.hasFocus() || document.visibilityState === "visible" : true; }; export const useWindowFocus = () => { @@ -47,10 +45,7 @@ export const useWindowFocus = () => { return () => { window.removeEventListener("focus", onFocus); window.removeEventListener("blur", onBlur); - document.removeEventListener( - "visibilitychange", - onVisibilityChange, - ); + document.removeEventListener("visibilitychange", onVisibilityChange); }; }, [isBrowser]); diff --git a/internal/react-icons/src/index.tsx b/internal/react-icons/src/index.tsx index f863e39c..1724bcf5 100644 --- a/internal/react-icons/src/index.tsx +++ b/internal/react-icons/src/index.tsx @@ -6,143 +6,77 @@ export type SvgIconComponent = typeof BarsIcon; export type SvgIconComponentProps = InferComponentProps; export const BarsIcon = React.memo( - React.forwardRef( - (props: SVGProps, ref: Ref) => ( - - - - ), - ), + React.forwardRef((props: SVGProps, ref: Ref) => ( + + + + )), ); export const ChevronDownIcon = React.memo( - React.forwardRef( - (props: SVGProps, ref: Ref) => ( - - - - ), - ), + React.forwardRef((props: SVGProps, ref: Ref) => ( + + + + )), ); export const GitHubIcon = React.memo( - React.forwardRef( - (props: SVGProps, ref: Ref) => ( - - {"GitHub"} - - - ), - ), + React.forwardRef((props: SVGProps, ref: Ref) => ( + + {"GitHub"} + + + )), ); export const HomeIcon = React.memo( - React.forwardRef( - (props: SVGProps, ref: Ref) => ( - - - - ), - ), + React.forwardRef((props: SVGProps, ref: Ref) => ( + + + + )), ); export const LinkIcon = React.memo( - React.forwardRef( - (props: SVGProps, ref: Ref) => ( - - - - - ), - ), + React.forwardRef((props: SVGProps, ref: Ref) => ( + + + + + )), ); export const NpmIcon = React.memo( - React.forwardRef( - (props: SVGProps, ref: Ref) => ( - - {"Npm"} - - - ), - ), + React.forwardRef((props: SVGProps, ref: Ref) => ( + + {"Npm"} + + + )), ); export const XIcon = React.memo( - React.forwardRef( - (props: SVGProps, ref: Ref) => ( - - - - ), - ), + React.forwardRef((props: SVGProps, ref: Ref) => ( + + + + )), ); diff --git a/internal/tailwind-config/tailwind.config.js b/internal/tailwind-config/tailwind.config.js index e780caf2..b1dd1cc2 100644 --- a/internal/tailwind-config/tailwind.config.js +++ b/internal/tailwind-config/tailwind.config.js @@ -1,19 +1,39 @@ const defaultTheme = require("tailwindcss/defaultTheme"); +const zIndices = ["default", "extra", "footer", "app-bar", "backdrop", "side-drawer"]; + +/** @type {import("tailwindcss").Config} */ module.exports = { theme: { fontFamily: { sans: ["Inter", ...defaultTheme.fontFamily.sans], mono: ["Inconsolata", ...defaultTheme.fontFamily.mono], }, + fontSize: { + ...defaultTheme.fontSize, + inherit: ["inherit"], + }, keyframes: { ...defaultTheme.keyframes, + backdropShow: { + from: { opacity: 0 }, + to: { opacity: 1 }, + }, blink: { "0%": { opacity: 1 }, "50%": { opacity: 0 }, "100%": { opacity: 1 }, }, + rootShow: { + from: { transform: "translateX(-100%)" }, + to: { transform: "translateX(0)" }, + }, + rootHide: { + from: { transform: "translateX(0)" }, + to: { transform: "translateX(-100%)" }, + }, }, + zIndex: zIndices.reduce((acc, name, i) => ({ ...acc, [name]: i }), defaultTheme.zIndex), }, fontFamily: { ...defaultTheme.fontFamily, diff --git a/internal/utils/package.json b/internal/utils/package.json index 65fbe203..979def9a 100644 --- a/internal/utils/package.json +++ b/internal/utils/package.json @@ -16,6 +16,8 @@ "typescript": "^5.4.5" }, "dependencies": { - "@types/react": "^18.3.1" + "@types/react": "^18.3.1", + "clsx": "^2.1.1", + "tailwind-merge": "^2.3.0" } } diff --git a/internal/utils/src/cn.ts b/internal/utils/src/cn.ts new file mode 100644 index 00000000..25490549 --- /dev/null +++ b/internal/utils/src/cn.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export const cn = (...args: ClassValue[]) => { + return twMerge(clsx(args)); +}; diff --git a/internal/utils/src/get.ts b/internal/utils/src/get.ts index aa3c53a8..7dc35356 100644 --- a/internal/utils/src/get.ts +++ b/internal/utils/src/get.ts @@ -1,16 +1,9 @@ -export const get = ( - obj: Record, - path: string, -): TResult | undefined => { +export const get = (obj: Record, path: string): TResult | undefined => { const travel = (regexp: RegExp) => String.prototype.split .call(path, regexp) .filter(Boolean) - .reduce( - (res, key) => - res !== null && res !== undefined ? res[key] : res, - obj, - ); + .reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj); const result = (travel(/[,[\]]+?/) || travel(/[,[\].]+?/)) as TResult; diff --git a/internal/utils/src/index.ts b/internal/utils/src/index.ts index 3eae7ada..0ac52b63 100644 --- a/internal/utils/src/index.ts +++ b/internal/utils/src/index.ts @@ -1 +1,2 @@ +export { cn } from "./cn"; export { get } from "./get"; diff --git a/packages/addon-indexeddb/src/IndexedDBStorage.ts b/packages/addon-indexeddb/src/IndexedDBStorage.ts index a0bf9560..693684d3 100644 --- a/packages/addon-indexeddb/src/IndexedDBStorage.ts +++ b/packages/addon-indexeddb/src/IndexedDBStorage.ts @@ -70,10 +70,7 @@ export class IndexedDBStorage extends AbstractStorageStore { if (!db) return []; - const updates = await db.getAll( - UPGRADES_KEY, - this._getLowerBound(start), - ); + const updates = await db.getAll(UPGRADES_KEY, this._getLowerBound(start)); const lastKey = await this._getLastKey(); diff --git a/packages/cli/src/commands/build.tsx b/packages/cli/src/commands/build.tsx index f7b3b1a2..94da7231 100644 --- a/packages/cli/src/commands/build.tsx +++ b/packages/cli/src/commands/build.tsx @@ -39,8 +39,7 @@ const Command: FC = ({ args }) => { {" "} )} - Building {input} →{" "} - {outDir} + Building {input}{outDir} {!!error && ( diff --git a/packages/cli/src/utils/getConfig.ts b/packages/cli/src/utils/getConfig.ts index 93971f83..3d804b3b 100644 --- a/packages/cli/src/utils/getConfig.ts +++ b/packages/cli/src/utils/getConfig.ts @@ -10,20 +10,16 @@ export type ParsedPluvConfig = z.output; export const getConfig = (): ParsedPluvConfig => { const filenames = readdirSync(process.cwd()); - const configName = ["pluv.config.js", "pluv.config.json"].find( - (validName) => filenames.some((filename) => filename === validName), + const configName = ["pluv.config.js", "pluv.config.json"].find((validName) => + filenames.some((filename) => filename === validName), ); - const config: PluvConfig = configName - ? require(path.resolve(process.cwd(), `./${configName}`)) - : {}; + const config: PluvConfig = configName ? require(path.resolve(process.cwd(), `./${configName}`)) : {}; const parsed = ZodPluvConfig.parse(config); const input = parsed.input ?? - ["pluv.ts", "pluv.mjs", "pluv.js"].find((validName) => - filenames.some((filename) => filename === validName), - ); + ["pluv.ts", "pluv.mjs", "pluv.js"].find((validName) => filenames.some((filename) => filename === validName)); return { ...parsed, input }; }; diff --git a/packages/crdt-loro/src/array/CrdtLoroArray.ts b/packages/crdt-loro/src/array/CrdtLoroArray.ts index a6b44367..bad587db 100644 --- a/packages/crdt-loro/src/array/CrdtLoroArray.ts +++ b/packages/crdt-loro/src/array/CrdtLoroArray.ts @@ -4,10 +4,7 @@ import type { CrdtLoroDoc } from "../doc/CrdtLoroDoc"; import { cloneType, getLoroContainerType, isWrapper } from "../shared"; import type { InferLoroJson } from "../types"; -export class CrdtLoroArray extends AbstractCrdtType< - LoroList, - InferLoroJson[] -> { +export class CrdtLoroArray extends AbstractCrdtType, InferLoroJson[]> { public readonly initialValue: T[] | readonly T[]; private _doc: CrdtLoroDoc | null = null; @@ -68,10 +65,7 @@ export class CrdtLoroArray extends AbstractCrdtType< } const containerType = getLoroContainerType(item); - const container = this.value.insertContainer( - index + i, - containerType, - ); + const container = this.value.insertContainer(index + i, containerType); cloneType({ source: item, target: container as any }); if (this._doc) item.doc = this._doc; diff --git a/packages/crdt-loro/src/array/array.ts b/packages/crdt-loro/src/array/array.ts index cd958828..214e837e 100644 --- a/packages/crdt-loro/src/array/array.ts +++ b/packages/crdt-loro/src/array/array.ts @@ -1,7 +1,5 @@ import { CrdtLoroArray } from "./CrdtLoroArray"; -export const array = ( - value: T[] | readonly T[] = [], -): CrdtLoroArray => { +export const array = (value: T[] | readonly T[] = []): CrdtLoroArray => { return new CrdtLoroArray(value); }; diff --git a/packages/crdt-loro/src/doc/CrdtLoroDoc.ts b/packages/crdt-loro/src/doc/CrdtLoroDoc.ts index 112a5976..e50a6bf7 100644 --- a/packages/crdt-loro/src/doc/CrdtLoroDoc.ts +++ b/packages/crdt-loro/src/doc/CrdtLoroDoc.ts @@ -56,10 +56,7 @@ export class CrdtLoroDoc< } public applyEncodedState(params: DocApplyEncodedStateParams): this { - const update = - typeof params.update === "string" - ? toUint8Array(params.update) - : params.update; + const update = typeof params.update === "string" ? toUint8Array(params.update) : params.update; if (!update) return this; @@ -68,14 +65,7 @@ export class CrdtLoroDoc< return this; } - public batchApplyEncodedState( - updates: readonly ( - | DocApplyEncodedStateParams - | string - | null - | undefined - )[], - ): this { + public batchApplyEncodedState(updates: readonly (DocApplyEncodedStateParams | string | null | undefined)[]): this { const _updates = updates.reduce((acc, item) => { if (!item) return acc; @@ -86,10 +76,7 @@ export class CrdtLoroDoc< } if (typeof item === "object") { - const update = - typeof item.update === "string" - ? toUint8Array(item.update) - : item.update; + const update = typeof item.update === "string" ? toUint8Array(item.update) : item.update; if (!update) return acc; @@ -138,9 +125,7 @@ export class CrdtLoroDoc< public get(key?: undefined): TStorage; public get(key: TKey): TStorage[TKey]; - public get( - key?: TKey, - ): TStorage | TStorage[TKey] { + public get(key?: TKey): TStorage | TStorage[TKey] { if (typeof key === "undefined") return this._storage; return this._storage[key as TKey]; @@ -171,9 +156,7 @@ export class CrdtLoroDoc< throw new Error("This is not yet supported"); } - public subscribe( - listener: (params: DocSubscribeCallbackParams) => void, - ): () => void { + public subscribe(listener: (params: DocSubscribeCallbackParams) => void): () => void { const fn = (event: LoroEventBatch) => { const update = fromUint8Array(this.value.exportFrom()); @@ -185,29 +168,23 @@ export class CrdtLoroDoc< }); }; - const subscriptionIds = Object.entries(this._storage).reduce( - (map, [key, crdtType]) => { - const container = crdtType.value as Container; - const subscriptionId = container.subscribe(this.value, fn); + const subscriptionIds = Object.entries(this._storage).reduce((map, [key, crdtType]) => { + const container = crdtType.value as Container; + const subscriptionId = container.subscribe(this.value, fn); - return map.set(key, subscriptionId); - }, - new Map(), - ); + return map.set(key, subscriptionId); + }, new Map()); return () => { - Array.from(subscriptionIds.entries()).forEach( - ([key, subscriptionId]) => { - const container = (this._storage[key]?.value ?? - null) as Container | null; - - if (!container) { - throw new Error("Storage could not be found"); - } - - container.unsubscribe(this.value, subscriptionId); - }, - ); + Array.from(subscriptionIds.entries()).forEach(([key, subscriptionId]) => { + const container = (this._storage[key]?.value ?? null) as Container | null; + + if (!container) { + throw new Error("Storage could not be found"); + } + + container.unsubscribe(this.value, subscriptionId); + }); }; } diff --git a/packages/crdt-loro/src/doc/CrdtLoroDocFactory.ts b/packages/crdt-loro/src/doc/CrdtLoroDocFactory.ts index aa03d5d8..cfc715bc 100644 --- a/packages/crdt-loro/src/doc/CrdtLoroDocFactory.ts +++ b/packages/crdt-loro/src/doc/CrdtLoroDocFactory.ts @@ -21,12 +21,8 @@ export class CrdtLoroDocFactory< return new CrdtLoroDoc(); } - public getFactory( - initialStorage?: (() => TStorage) | undefined, - ): CrdtLoroDocFactory { - return new CrdtLoroDocFactory( - initialStorage ?? this._initialStorage, - ); + public getFactory(initialStorage?: (() => TStorage) | undefined): CrdtLoroDocFactory { + return new CrdtLoroDocFactory(initialStorage ?? this._initialStorage); } public getFresh(): CrdtLoroDoc { @@ -55,11 +51,7 @@ export class CrdtLoroDocFactory< ); } - public getInitialized( - initialStorage?: () => TStorage, - ): CrdtLoroDoc { - return new CrdtLoroDoc( - initialStorage?.() ?? this._initialStorage(), - ); + public getInitialized(initialStorage?: () => TStorage): CrdtLoroDoc { + return new CrdtLoroDoc(initialStorage?.() ?? this._initialStorage()); } } diff --git a/packages/crdt-loro/src/doc/doc.ts b/packages/crdt-loro/src/doc/doc.ts index 85a0b474..5a123143 100644 --- a/packages/crdt-loro/src/doc/doc.ts +++ b/packages/crdt-loro/src/doc/doc.ts @@ -1,9 +1,7 @@ import type { AbstractCrdtType } from "@pluv/crdt"; import { CrdtLoroDocFactory } from "./CrdtLoroDocFactory"; -export const doc = < - TStorage extends Record>, ->( +export const doc = >>( value: () => TStorage = () => ({}) as TStorage, ): CrdtLoroDocFactory => { return new CrdtLoroDocFactory(value); diff --git a/packages/crdt-loro/src/map/CrdtLoroMap.ts b/packages/crdt-loro/src/map/CrdtLoroMap.ts index 4cb19f19..1ed52da6 100644 --- a/packages/crdt-loro/src/map/CrdtLoroMap.ts +++ b/packages/crdt-loro/src/map/CrdtLoroMap.ts @@ -18,9 +18,7 @@ export class CrdtLoroMap extends AbstractCrdtType< constructor(value: readonly (readonly [key: string, value: T])[] = []) { super(); - this.initialValue = value.map( - ([k, v]) => [k, v] as [key: string, value: T], - ); + this.initialValue = value.map(([k, v]) => [k, v] as [key: string, value: T]); } public set doc(doc: CrdtLoroDoc) { diff --git a/packages/crdt-loro/src/map/map.ts b/packages/crdt-loro/src/map/map.ts index 66ed550e..ac225219 100644 --- a/packages/crdt-loro/src/map/map.ts +++ b/packages/crdt-loro/src/map/map.ts @@ -1,7 +1,5 @@ import { CrdtLoroMap } from "./CrdtLoroMap"; -export const map = ( - value: readonly (readonly [key: string, value: T])[] = [], -): CrdtLoroMap => { +export const map = (value: readonly (readonly [key: string, value: T])[] = []): CrdtLoroMap => { return new CrdtLoroMap(value); }; diff --git a/packages/crdt-loro/src/object/CrdtLoroObject.ts b/packages/crdt-loro/src/object/CrdtLoroObject.ts index c122cdaf..a2d77af8 100644 --- a/packages/crdt-loro/src/object/CrdtLoroObject.ts +++ b/packages/crdt-loro/src/object/CrdtLoroObject.ts @@ -4,9 +4,7 @@ import type { CrdtLoroDoc } from "../doc/CrdtLoroDoc"; import { cloneType, getLoroContainerType, isWrapper } from "../shared"; import type { InferLoroJson } from "../types"; -export class CrdtLoroObject< - T extends Record, -> extends AbstractCrdtType, InferLoroJson> { +export class CrdtLoroObject> extends AbstractCrdtType, InferLoroJson> { public readonly initialValue: readonly (readonly [key: string, value: T])[]; private _doc: CrdtLoroDoc | null = null; @@ -16,9 +14,7 @@ export class CrdtLoroObject< constructor(value: T) { super(); - this.initialValue = Object.entries(value).map( - ([k, v]) => [k, v] as [key: string, value: T], - ); + this.initialValue = Object.entries(value).map(([k, v]) => [k, v] as [key: string, value: T]); } public set doc(doc: CrdtLoroDoc) { diff --git a/packages/crdt-loro/src/object/object.ts b/packages/crdt-loro/src/object/object.ts index 3c3da384..4ec8821c 100644 --- a/packages/crdt-loro/src/object/object.ts +++ b/packages/crdt-loro/src/object/object.ts @@ -1,7 +1,5 @@ import { CrdtLoroObject } from "./CrdtLoroObject"; -export const object = >( - value: T, -): CrdtLoroObject => { +export const object = >(value: T): CrdtLoroObject => { return new CrdtLoroObject(value); }; diff --git a/packages/crdt-loro/src/shared/cloneType.ts b/packages/crdt-loro/src/shared/cloneType.ts index d59b4c63..aa281cb2 100644 --- a/packages/crdt-loro/src/shared/cloneType.ts +++ b/packages/crdt-loro/src/shared/cloneType.ts @@ -144,9 +144,7 @@ function cloneMap(params: CloneMapParams): void { }); } -function cloneObject>( - params: CloneObjectParams, -): void { +function cloneObject>(params: CloneObjectParams): void { const { source, target } = params; const items = source.initialValue; @@ -205,9 +203,7 @@ function cloneText(params: CloneTextParams): void { source.insert(0, source.initalValue); } -export const cloneType = ( - params: CloneTypeParams, -) => { +export const cloneType = (params: CloneTypeParams) => { const { source, target } = params; if (source instanceof CrdtLoroArray) { diff --git a/packages/crdt-loro/src/shared/isWrapper.ts b/packages/crdt-loro/src/shared/isWrapper.ts index 245aa4c7..ed4b247a 100644 --- a/packages/crdt-loro/src/shared/isWrapper.ts +++ b/packages/crdt-loro/src/shared/isWrapper.ts @@ -5,11 +5,7 @@ import { CrdtLoroText } from "../text/CrdtLoroText"; export const isWrapper = ( item: any, -): item is - | CrdtLoroArray - | CrdtLoroMap - | CrdtLoroObject - | CrdtLoroText => { +): item is CrdtLoroArray | CrdtLoroMap | CrdtLoroObject | CrdtLoroText => { return ( item instanceof CrdtLoroArray || item instanceof CrdtLoroMap || diff --git a/packages/crdt-yjs/src/array/CrdtYjsArray.ts b/packages/crdt-yjs/src/array/CrdtYjsArray.ts index 90f57864..b424eef0 100644 --- a/packages/crdt-yjs/src/array/CrdtYjsArray.ts +++ b/packages/crdt-yjs/src/array/CrdtYjsArray.ts @@ -4,13 +4,8 @@ import { Array as YArray } from "yjs"; import { toYjsValue } from "../shared"; import type { InferYjsJson, InferYjsType } from "../types"; -export class CrdtYjsArray extends AbstractCrdtType< - YArray>, - InferYjsJson[] -> { - public readonly initialValue: - | InferYjsType[] - | readonly InferYjsType[]; +export class CrdtYjsArray extends AbstractCrdtType>, InferYjsJson[]> { + public readonly initialValue: InferYjsType[] | readonly InferYjsType[]; public value: YArray>; constructor(value: T[] | readonly T[] = []) { diff --git a/packages/crdt-yjs/src/array/array.ts b/packages/crdt-yjs/src/array/array.ts index 0f399811..4c463fee 100644 --- a/packages/crdt-yjs/src/array/array.ts +++ b/packages/crdt-yjs/src/array/array.ts @@ -1,7 +1,5 @@ import { CrdtYjsArray } from "./CrdtYjsArray"; -export const array = ( - value: T[] | readonly T[] = [], -): CrdtYjsArray => { +export const array = (value: T[] | readonly T[] = []): CrdtYjsArray => { return new CrdtYjsArray(value); }; diff --git a/packages/crdt-yjs/src/doc/CrdtYjsDoc.ts b/packages/crdt-yjs/src/doc/CrdtYjsDoc.ts index e045a463..5dbf2fad 100644 --- a/packages/crdt-yjs/src/doc/CrdtYjsDoc.ts +++ b/packages/crdt-yjs/src/doc/CrdtYjsDoc.ts @@ -27,9 +27,7 @@ import { CrdtYjsXmlElement } from "../xmlElement/CrdtYjsXmlElement"; import { CrdtYjsXmlFragment } from "../xmlFragment/CrdtYjsXmlFragment"; import { CrdtYjsXmlText } from "../xmlText/CrdtYjsXmlText"; -export class CrdtYjsDoc< - TStorage extends Record>, -> extends AbstractCrdtDoc { +export class CrdtYjsDoc>> extends AbstractCrdtDoc { public value: YDoc = new YDoc(); private _storage: TStorage; @@ -80,10 +78,7 @@ export class CrdtYjsDoc< } if (node instanceof CrdtYjsXmlElement) { - const yXmlElement = this.value.get( - key, - YXmlElement, - ) as YXmlElement; + const yXmlElement = this.value.get(key, YXmlElement) as YXmlElement; yXmlElement.insert(0, node.initialValue.slice(0)); node.value = yXmlElement; @@ -92,10 +87,7 @@ export class CrdtYjsDoc< } if (node instanceof CrdtYjsXmlFragment) { - const yXmlFragment = this.value.get( - key, - YXmlFragment, - ) as YXmlFragment; + const yXmlFragment = this.value.get(key, YXmlFragment) as YXmlFragment; yXmlFragment.insert(0, node.initialValue.slice(0)); node.value = yXmlFragment; @@ -121,47 +113,33 @@ export class CrdtYjsDoc< if (update === null || typeof update === "undefined") return this; - const uint8Update = - typeof update === "string" ? toUint8Array(update) : update; + const uint8Update = typeof update === "string" ? toUint8Array(update) : update; applyUpdate(this.value, uint8Update, origin); return this; } - public batchApplyEncodedState( - updates: readonly ( - | DocApplyEncodedStateParams - | string - | null - | undefined - )[], - ): this { - const params = updates.reduce( - (acc, update) => { - if (!update) return acc; + public batchApplyEncodedState(updates: readonly (DocApplyEncodedStateParams | string | null | undefined)[]): this { + const params = updates.reduce((acc, update) => { + if (!update) return acc; - if (typeof update === "string") { - acc.push({ update }); + if (typeof update === "string") { + acc.push({ update }); - return acc; - } - - if (!!update && typeof update === "object") { - acc.push(update); + return acc; + } - return acc; - } + if (!!update && typeof update === "object") { + acc.push(update); return acc; - }, - [], - ); + } - return params.reduce( - (doc, update) => doc.applyEncodedState(update), - this, - ); + return acc; + }, []); + + return params.reduce((doc, update) => doc.applyEncodedState(update), this); } public canRedo(): boolean { @@ -179,9 +157,7 @@ export class CrdtYjsDoc< public get(key?: undefined): TStorage; public get(key: TKey): TStorage[TKey]; - public get( - key?: TKey, - ): TStorage | TStorage[TKey] { + public get(key?: TKey): TStorage | TStorage[TKey] { if (typeof key === "undefined") return this._storage; return this._storage[key as TKey]; @@ -201,9 +177,7 @@ export class CrdtYjsDoc< return this; } - public subscribe( - listener: (params: DocSubscribeCallbackParams) => void, - ): () => void { + public subscribe(listener: (params: DocSubscribeCallbackParams) => void): () => void { const fn = (update: Uint8Array, origin: any, doc: YDoc) => { listener({ doc: this, @@ -223,9 +197,7 @@ export class CrdtYjsDoc< public track(): this { if (this._undoManager) this._undoManager.destroy(); - const sharedTypes = Object.values(this._storage).reduce< - YAbstractType[] - >((acc, type) => { + const sharedTypes = Object.values(this._storage).reduce[]>((acc, type) => { if ( type instanceof CrdtYjsArray || type instanceof CrdtYjsMap || diff --git a/packages/crdt-yjs/src/doc/CrdtYjsDocFactory.ts b/packages/crdt-yjs/src/doc/CrdtYjsDocFactory.ts index 07d4acba..25c1f53d 100644 --- a/packages/crdt-yjs/src/doc/CrdtYjsDocFactory.ts +++ b/packages/crdt-yjs/src/doc/CrdtYjsDocFactory.ts @@ -24,12 +24,8 @@ export class CrdtYjsDocFactory< return new CrdtYjsDoc(); } - public getFactory( - initialStorage?: (() => TStorage) | undefined, - ): CrdtYjsDocFactory { - return new CrdtYjsDocFactory( - initialStorage ?? this._initialStorage, - ); + public getFactory(initialStorage?: (() => TStorage) | undefined): CrdtYjsDocFactory { + return new CrdtYjsDocFactory(initialStorage ?? this._initialStorage); } public getFresh(): CrdtYjsDoc { @@ -73,11 +69,7 @@ export class CrdtYjsDocFactory< ); } - public getInitialized( - initialStorage?: () => TStorage, - ): CrdtYjsDoc { - return new CrdtYjsDoc( - initialStorage?.() ?? this._initialStorage(), - ); + public getInitialized(initialStorage?: () => TStorage): CrdtYjsDoc { + return new CrdtYjsDoc(initialStorage?.() ?? this._initialStorage()); } } diff --git a/packages/crdt-yjs/src/doc/doc.ts b/packages/crdt-yjs/src/doc/doc.ts index c5815be0..a2a0715a 100644 --- a/packages/crdt-yjs/src/doc/doc.ts +++ b/packages/crdt-yjs/src/doc/doc.ts @@ -1,9 +1,7 @@ import type { AbstractCrdtType } from "@pluv/crdt"; import { CrdtYjsDocFactory } from "./CrdtYjsDocFactory"; -export const doc = < - TStorage extends Record>, ->( +export const doc = >>( value: () => TStorage = () => ({}) as TStorage, ): CrdtYjsDocFactory => { return new CrdtYjsDocFactory(value); diff --git a/packages/crdt-yjs/src/map/CrdtYjsMap.ts b/packages/crdt-yjs/src/map/CrdtYjsMap.ts index 14794081..b6106f10 100644 --- a/packages/crdt-yjs/src/map/CrdtYjsMap.ts +++ b/packages/crdt-yjs/src/map/CrdtYjsMap.ts @@ -8,10 +8,7 @@ export class CrdtYjsMap extends AbstractCrdtType< YMap>, Record> > { - public initialValue: readonly (readonly [ - key: string, - value: InferYjsType, - ])[]; + public initialValue: readonly (readonly [key: string, value: InferYjsType])[]; public value: YMap>; constructor(value: readonly (readonly [key: string, value: T])[] = []) { diff --git a/packages/crdt-yjs/src/map/map.ts b/packages/crdt-yjs/src/map/map.ts index 2ff6ebf0..26dd3626 100644 --- a/packages/crdt-yjs/src/map/map.ts +++ b/packages/crdt-yjs/src/map/map.ts @@ -1,7 +1,5 @@ import { CrdtYjsMap } from "./CrdtYjsMap"; -export const map = ( - value: readonly (readonly [key: string, value: T])[] = [], -): CrdtYjsMap => { +export const map = (value: readonly (readonly [key: string, value: T])[] = []): CrdtYjsMap => { return new CrdtYjsMap(value); }; diff --git a/packages/crdt-yjs/src/object/CrdtYjsObject.ts b/packages/crdt-yjs/src/object/CrdtYjsObject.ts index c9689cd4..96a5e53e 100644 --- a/packages/crdt-yjs/src/object/CrdtYjsObject.ts +++ b/packages/crdt-yjs/src/object/CrdtYjsObject.ts @@ -4,19 +4,17 @@ import { Map as YMap } from "yjs"; import { toYjsValue } from "../shared"; import type { InferYjsJson, InferYjsType } from "../types"; -export class CrdtYjsObject< - T extends Record, -> extends AbstractCrdtType>, InferYjsJson> { +export class CrdtYjsObject> extends AbstractCrdtType< + YMap>, + InferYjsJson +> { public initialValue: readonly (readonly [key: string, value: T[keyof T]])[]; public value: YMap>; constructor(value: T = {} as T) { super(); - this.initialValue = Object.entries(value).map(([k, v]) => [ - k, - toYjsValue(v), - ]); + this.initialValue = Object.entries(value).map(([k, v]) => [k, toYjsValue(v)]); this.value = new YMap(this.initialValue); } diff --git a/packages/crdt-yjs/src/object/object.ts b/packages/crdt-yjs/src/object/object.ts index 273ddbe2..958f653d 100644 --- a/packages/crdt-yjs/src/object/object.ts +++ b/packages/crdt-yjs/src/object/object.ts @@ -1,7 +1,5 @@ import { CrdtYjsObject } from "./CrdtYjsObject"; -export const object = >( - value: T, -): CrdtYjsObject => { +export const object = >(value: T): CrdtYjsObject => { return new CrdtYjsObject(value); }; diff --git a/packages/crdt-yjs/src/shared/isWrapper.ts b/packages/crdt-yjs/src/shared/isWrapper.ts index 049ae126..a5a36d40 100644 --- a/packages/crdt-yjs/src/shared/isWrapper.ts +++ b/packages/crdt-yjs/src/shared/isWrapper.ts @@ -8,11 +8,7 @@ import { CrdtYjsXmlText } from "../xmlText"; export const isWrapper = ( item: any, -): item is - | CrdtYjsArray - | CrdtYjsMap - | CrdtYjsObject - | CrdtYjsText => { +): item is CrdtYjsArray | CrdtYjsMap | CrdtYjsObject | CrdtYjsText => { return ( item instanceof CrdtYjsArray || item instanceof CrdtYjsMap || diff --git a/packages/crdt-yjs/src/xmlElement/CrdtYjsXmlElement.ts b/packages/crdt-yjs/src/xmlElement/CrdtYjsXmlElement.ts index 1d075f39..7a0b9c0c 100644 --- a/packages/crdt-yjs/src/xmlElement/CrdtYjsXmlElement.ts +++ b/packages/crdt-yjs/src/xmlElement/CrdtYjsXmlElement.ts @@ -9,10 +9,7 @@ export class CrdtYjsXmlElement extends AbstractCrdtType { public readonly name: string; public value: YXmlElement; - constructor( - name: string, - children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[], - ) { + constructor(name: string, children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]) { super(); this.initialValue = children.map((item) => item.value); @@ -31,10 +28,7 @@ export class CrdtYjsXmlElement extends AbstractCrdtType { return this; } - public insert( - index: number, - ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[] - ): this { + public insert(index: number, ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]): this { const converted = children.map((child) => toYjsValue(child)); this.value.insert(index, converted); @@ -42,15 +36,11 @@ export class CrdtYjsXmlElement extends AbstractCrdtType { return this; } - public push( - ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[] - ): this { + public push(...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]): this { return this.insert(this.length, ...children); } - public unshift( - ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[] - ): this { + public unshift(...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]): this { return this.insert(0, ...children); } diff --git a/packages/crdt-yjs/src/xmlFragment/CrdtYjsXmlFragment.ts b/packages/crdt-yjs/src/xmlFragment/CrdtYjsXmlFragment.ts index b912a9c4..0b2239ca 100644 --- a/packages/crdt-yjs/src/xmlFragment/CrdtYjsXmlFragment.ts +++ b/packages/crdt-yjs/src/xmlFragment/CrdtYjsXmlFragment.ts @@ -27,10 +27,7 @@ export class CrdtYjsXmlFragment extends AbstractCrdtType { return this; } - public insert( - index: number, - ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[] - ): this { + public insert(index: number, ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]): this { const converted = children.map((child) => toYjsValue(child)); this.value.insert(index, converted); @@ -38,15 +35,11 @@ export class CrdtYjsXmlFragment extends AbstractCrdtType { return this; } - public push( - ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[] - ): this { + public push(...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]): this { return this.insert(this.length, ...children); } - public unshift( - ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[] - ): this { + public unshift(...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]): this { return this.insert(0, ...children); } diff --git a/packages/crdt-yjs/src/xmlFragment/xmlFragment.ts b/packages/crdt-yjs/src/xmlFragment/xmlFragment.ts index 0ef255ed..4f6dba15 100644 --- a/packages/crdt-yjs/src/xmlFragment/xmlFragment.ts +++ b/packages/crdt-yjs/src/xmlFragment/xmlFragment.ts @@ -2,8 +2,6 @@ import type { CrdtYjsXmlElement } from "../xmlElement"; import type { CrdtYjsXmlText } from "../xmlText"; import { CrdtYjsXmlFragment } from "./CrdtYjsXmlFragment"; -export const xmlFragment = ( - children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[], -): CrdtYjsXmlFragment => { +export const xmlFragment = (children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]): CrdtYjsXmlFragment => { return new CrdtYjsXmlFragment(children); }; diff --git a/packages/crdt-yjs/src/xmlText/CrdtYjsXmlText.ts b/packages/crdt-yjs/src/xmlText/CrdtYjsXmlText.ts index 35a5e472..d2a60924 100644 --- a/packages/crdt-yjs/src/xmlText/CrdtYjsXmlText.ts +++ b/packages/crdt-yjs/src/xmlText/CrdtYjsXmlText.ts @@ -22,11 +22,7 @@ export class CrdtYjsXmlText extends AbstractCrdtType { return this; } - public insert( - index: number, - text: string, - attributes?: Record, - ): this { + public insert(index: number, text: string, attributes?: Record): this { this.value.insert(index, text, attributes); return this; diff --git a/packages/crdt/src/AbstractCrdtDoc.ts b/packages/crdt/src/AbstractCrdtDoc.ts index 79fb0f68..5016d027 100644 --- a/packages/crdt/src/AbstractCrdtDoc.ts +++ b/packages/crdt/src/AbstractCrdtDoc.ts @@ -6,26 +6,17 @@ export interface DocApplyEncodedStateParams { update?: string | Uint8Array; } -export interface DocSubscribeCallbackParams< - T extends Record>, -> { +export interface DocSubscribeCallbackParams>> { doc: AbstractCrdtDoc; local: boolean; origin?: string | null; update: string; } -export abstract class AbstractCrdtDoc< - T extends Record>, -> { +export abstract class AbstractCrdtDoc>> { public abstract applyEncodedState(params: DocApplyEncodedStateParams): this; public abstract batchApplyEncodedState( - updates: readonly ( - | DocApplyEncodedStateParams - | string - | null - | undefined - )[], + updates: readonly (DocApplyEncodedStateParams | string | null | undefined)[], ): this; public abstract canRedo(): boolean; public abstract canUndo(): boolean; @@ -35,9 +26,7 @@ export abstract class AbstractCrdtDoc< public abstract getEncodedState(): string; public abstract isEmpty(): boolean; public abstract redo(): this; - public abstract subscribe( - listener: (params: DocSubscribeCallbackParams) => void, - ): () => void; + public abstract subscribe(listener: (params: DocSubscribeCallbackParams) => void): () => void; public abstract toJson(): InferCrdtStorageJson; public abstract track(): this; public abstract transact(fn: () => void, origin?: string): this; diff --git a/packages/crdt/src/AbstractCrdtDocFactory.ts b/packages/crdt/src/AbstractCrdtDocFactory.ts index 11f20d57..d0b38abd 100644 --- a/packages/crdt/src/AbstractCrdtDocFactory.ts +++ b/packages/crdt/src/AbstractCrdtDocFactory.ts @@ -1,15 +1,9 @@ import { AbstractCrdtDoc } from "./AbstractCrdtDoc"; import type { AbstractCrdtType } from "./AbstractCrdtType"; -export abstract class AbstractCrdtDocFactory< - TStorage extends Record>, -> { +export abstract class AbstractCrdtDocFactory>> { public abstract getEmpty(): AbstractCrdtDoc; - public abstract getFactory( - initialStorage?: () => TStorage, - ): AbstractCrdtDocFactory; + public abstract getFactory(initialStorage?: () => TStorage): AbstractCrdtDocFactory; public abstract getFresh(): AbstractCrdtDoc; - public abstract getInitialized( - initialStorage?: () => TStorage, - ): AbstractCrdtDoc; + public abstract getInitialized(initialStorage?: () => TStorage): AbstractCrdtDoc; } diff --git a/packages/crdt/src/AbstractCrdtType.ts b/packages/crdt/src/AbstractCrdtType.ts index f06a5a49..0e328ebb 100644 --- a/packages/crdt/src/AbstractCrdtType.ts +++ b/packages/crdt/src/AbstractCrdtType.ts @@ -1,9 +1,6 @@ import type { InferCrdtStorageJson } from "./types"; -export abstract class AbstractCrdtType< - TValue extends unknown, - TJson extends unknown, -> { +export abstract class AbstractCrdtType { public abstract value: TValue; public abstract toJson(): InferCrdtStorageJson; diff --git a/packages/crdt/src/NoopCrdtDoc.ts b/packages/crdt/src/NoopCrdtDoc.ts index 7ce9e7ff..f6747256 100644 --- a/packages/crdt/src/NoopCrdtDoc.ts +++ b/packages/crdt/src/NoopCrdtDoc.ts @@ -1,7 +1,4 @@ -import type { - DocApplyEncodedStateParams, - DocSubscribeCallbackParams, -} from "./AbstractCrdtDoc"; +import type { DocApplyEncodedStateParams, DocSubscribeCallbackParams } from "./AbstractCrdtDoc"; import { AbstractCrdtDoc } from "./AbstractCrdtDoc"; export class NoopCrdtDoc extends AbstractCrdtDoc { @@ -9,14 +6,7 @@ export class NoopCrdtDoc extends AbstractCrdtDoc { return this; } - public batchApplyEncodedState( - updates: readonly ( - | string - | DocApplyEncodedStateParams - | null - | undefined - )[], - ): this { + public batchApplyEncodedState(updates: readonly (string | DocApplyEncodedStateParams | null | undefined)[]): this { return this; } @@ -50,9 +40,7 @@ export class NoopCrdtDoc extends AbstractCrdtDoc { return this; } - public subscribe( - listener: (params: DocSubscribeCallbackParams<{}>) => void, - ): () => void { + public subscribe(listener: (params: DocSubscribeCallbackParams<{}>) => void): () => void { return () => undefined; } diff --git a/packages/crdt/src/NoopCrdtDocFactory.ts b/packages/crdt/src/NoopCrdtDocFactory.ts index 51d541d1..cc882533 100644 --- a/packages/crdt/src/NoopCrdtDocFactory.ts +++ b/packages/crdt/src/NoopCrdtDocFactory.ts @@ -6,9 +6,7 @@ export class NoopCrdtDocFactory extends AbstractCrdtDocFactory { return new NoopCrdtDoc(); } - public getFactory( - initialStorage?: (() => {}) | undefined, - ): NoopCrdtDocFactory { + public getFactory(initialStorage?: (() => {}) | undefined): NoopCrdtDocFactory { return this; } @@ -16,9 +14,7 @@ export class NoopCrdtDocFactory extends AbstractCrdtDocFactory { return new NoopCrdtDoc(); } - public getInitialized( - initialStorage?: (() => {}) | undefined, - ): NoopCrdtDoc { + public getInitialized(initialStorage?: (() => {}) | undefined): NoopCrdtDoc { return new NoopCrdtDoc(); } } diff --git a/packages/crdt/src/index.ts b/packages/crdt/src/index.ts index df44dfff..e62dd318 100644 --- a/packages/crdt/src/index.ts +++ b/packages/crdt/src/index.ts @@ -1,8 +1,5 @@ export { AbstractCrdtDoc } from "./AbstractCrdtDoc"; -export type { - DocApplyEncodedStateParams, - DocSubscribeCallbackParams, -} from "./AbstractCrdtDoc"; +export type { DocApplyEncodedStateParams, DocSubscribeCallbackParams } from "./AbstractCrdtDoc"; export { AbstractCrdtDocFactory } from "./AbstractCrdtDocFactory"; export { AbstractCrdtType } from "./AbstractCrdtType"; export { NoopCrdtDoc } from "./NoopCrdtDoc"; diff --git a/packages/eslint-config-pluv/index.js b/packages/eslint-config-pluv/index.js index 9b78f180..56332950 100644 --- a/packages/eslint-config-pluv/index.js +++ b/packages/eslint-config-pluv/index.js @@ -1,12 +1,8 @@ +const path = require("path"); + /** @type {import("eslint").Linter.Config} */ module.exports = { - extends: [ - "next", - "turbo", - "plugin:prettier/recommended", - "plugin:tailwindcss/recommended", - "prettier", - ], + extends: ["next", "turbo", "plugin:prettier/recommended", "plugin:tailwindcss/recommended", "prettier"], parserOptions: { babelOptions: { presets: [require.resolve("next/babel")], @@ -15,12 +11,7 @@ module.exports = { plugins: ["prettier", "tailwindcss"], rules: { "@next/next/no-html-link-for-pages": "off", - "prettier/prettier": [ - "warn", - { - tabWidth: 4, - }, - ], + "prettier/prettier": ["warn", { printWidth: 120, tabWidth: 4 }], "react/jsx-key": "off", "react/self-closing-comp": [ "warn", @@ -29,10 +20,18 @@ module.exports = { html: true, }, ], + "tailwindcss/classnames-order": [ + "warn", + { + callees: ["classnames", "clsx", "cva", "cn"], + tags: ["oneLine"], + }, + ], }, settings: { tailwindcss: { - config: "./tailwindcss.config.js", + callees: ["cn"], + config: path.join(__dirname, "./tailwind.config.js"), }, }, }; diff --git a/packages/eslint-config-pluv/package.json b/packages/eslint-config-pluv/package.json index 4880a44a..9941fc50 100644 --- a/packages/eslint-config-pluv/package.json +++ b/packages/eslint-config-pluv/package.json @@ -16,13 +16,13 @@ }, "dependencies": { "eslint": "^8.57.0", - "eslint-config-next": "^14.2.3", + "eslint-config-next": "^14.2.2", "eslint-config-prettier": "^9.1.0", - "eslint-config-turbo": "^1.13.3", + "eslint-config-turbo": "^1.13.2", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.1", + "eslint-plugin-react": "7.34.1", "eslint-plugin-tailwindcss": "^3.15.1", - "next": "^14.2.3", + "next": "^14.2.2", "prettier": "^3.2.5", "prettier-plugin-tailwindcss": "^0.5.14" }, diff --git a/packages/io/src/AbstractPersistance.ts b/packages/io/src/AbstractPersistance.ts index b600cab8..98a87e3e 100644 --- a/packages/io/src/AbstractPersistance.ts +++ b/packages/io/src/AbstractPersistance.ts @@ -1,18 +1,11 @@ import type { JsonObject } from "@pluv/types"; export abstract class AbstractPersistance { - public abstract addUser( - room: string, - connectionId: string, - user: JsonObject | null, - ): Promise; + public abstract addUser(room: string, connectionId: string, user: JsonObject | null): Promise; public abstract deleteStorageState(room: string): Promise; - public abstract deleteUser( - room: string, - connectionId: string, - ): Promise; + public abstract deleteUser(room: string, connectionId: string): Promise; public abstract deleteUsers(room: string): Promise; @@ -20,14 +13,9 @@ export abstract class AbstractPersistance { public abstract getStorageState(room: string): Promise; - public abstract getUser( - room: string, - connectionId: string, - ): Promise; + public abstract getUser(room: string, connectionId: string): Promise; - public abstract getUsers( - room: string, - ): Promise; + public abstract getUsers(room: string): Promise; public abstract setStorageState(room: string, state: string): Promise; } diff --git a/packages/io/src/AbstractPlatform.ts b/packages/io/src/AbstractPlatform.ts index 54d75680..4f62e00c 100644 --- a/packages/io/src/AbstractPlatform.ts +++ b/packages/io/src/AbstractPlatform.ts @@ -1,9 +1,6 @@ import { AbstractPersistance } from "./AbstractPersistance"; import type { AbstractPubSub } from "./AbstractPubSub"; -import type { - AbstractWebSocket, - AbstractWebSocketConfig, -} from "./AbstractWebSocket"; +import type { AbstractWebSocket, AbstractWebSocketConfig } from "./AbstractWebSocket"; import { Persistance } from "./Persistance"; import { PubSub } from "./PubSub"; @@ -11,14 +8,10 @@ export type InferPlatformWebSocketType = TPlatform extends AbstractPlatform ? IWebSocket : never; export type InferPlatformRoomContextType = - TPlatform extends AbstractPlatform - ? IIOContext - : never; + TPlatform extends AbstractPlatform ? IIOContext : never; export type InferPlatformEventContextType = - TPlatform extends AbstractPlatform - ? IRoomContext - : never; + TPlatform extends AbstractPlatform ? IRoomContext : never; export type AbstractPlatformConfig = | { persistance?: undefined; pubSub?: undefined } @@ -47,10 +40,7 @@ export abstract class AbstractPlatform< this.pubSub = pubSub ?? new PubSub(); } - public abstract convertWebSocket( - webSocket: TWebSocket, - config: ConvertWebSocketConfig, - ): AbstractWebSocket; + public abstract convertWebSocket(webSocket: TWebSocket, config: ConvertWebSocketConfig): AbstractWebSocket; public abstract parseData(data: string | ArrayBuffer): Record; diff --git a/packages/io/src/AbstractPubSub.ts b/packages/io/src/AbstractPubSub.ts index 8b204ca7..07b26229 100644 --- a/packages/io/src/AbstractPubSub.ts +++ b/packages/io/src/AbstractPubSub.ts @@ -9,10 +9,7 @@ export type IOPubSubEventMessage< }; export abstract class AbstractPubSub { - public abstract publish( - roomName: string, - payload: IOPubSubEventMessage, - ): Promise; + public abstract publish(roomName: string, payload: IOPubSubEventMessage): Promise; public abstract subscribe( roomName: string, diff --git a/packages/io/src/AbstractWebSocket.ts b/packages/io/src/AbstractWebSocket.ts index 0655069e..fcb90f63 100644 --- a/packages/io/src/AbstractWebSocket.ts +++ b/packages/io/src/AbstractWebSocket.ts @@ -73,15 +73,9 @@ export abstract class AbstractWebSocket { * @author leedavidcs * @date August 28, 2022 */ - public abstract addEventListener( - type: TType, - handler: AbstractListener, - ): void; + public abstract addEventListener(type: TType, handler: AbstractListener): void; - public abstract close( - code?: number | undefined, - reason?: string | undefined, - ): void; + public abstract close(code?: number | undefined, reason?: string | undefined): void; public abstract initialize(): Promise<() => void>; @@ -90,16 +84,9 @@ export abstract class AbstractWebSocket { public abstract terminate(): void; public handleError(params: AbstractWebSocketHandleErrorParams): void { - const { - error, - message = error instanceof Error - ? error.message - : "Unexpected error", - session, - } = params; + const { error, message = error instanceof Error ? error.message : "Unexpected error", session } = params; - const stack: string | null = - error instanceof Error ? error.stack ?? null : null; + const stack: string | null = error instanceof Error ? error.stack ?? null : null; return this.sendMessage({ connectionId: session?.id ?? null, @@ -110,9 +97,7 @@ export abstract class AbstractWebSocket { }); } - public sendMessage< - TMessage extends IOEventMessage = IOEventMessage, - >(data: TMessage): void { + public sendMessage = IOEventMessage>(data: TMessage): void { return this.send(JSON.stringify(data)); } } diff --git a/packages/io/src/IORoom.ts b/packages/io/src/IORoom.ts index 78c87e74..a7cd7350 100644 --- a/packages/io/src/IORoom.ts +++ b/packages/io/src/IORoom.ts @@ -56,11 +56,7 @@ interface IORoomListeners { export type IORoomConfig< TPlatform extends AbstractPlatform = AbstractPlatform, - TAuthorize extends IOAuthorize< - any, - any, - InferPlatformRoomContextType - > = BaseIOAuthorize, + TAuthorize extends IOAuthorize> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord = {}, TOutputBroadcast extends EventRecord = {}, @@ -71,14 +67,7 @@ export type IORoomConfig< context: TContext & InferPlatformRoomContextType; crdt?: { doc: (value: any) => AbstractCrdtDocFactory }; debug: boolean; - events: InferEventConfig< - TPlatform, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - >; + events: InferEventConfig; platform: TPlatform; }; @@ -94,21 +83,15 @@ export type WebsocketRegisterOptions = { export class IORoom< TPlatform extends AbstractPlatform = AbstractPlatform, - TAuthorize extends IOAuthorize< - any, - any, - InferPlatformRoomContextType - > = BaseIOAuthorize, + TAuthorize extends IOAuthorize> = BaseIOAuthorize, TContext extends Record = {}, TInput extends EventRecord = {}, TOutputBroadcast extends EventRecord = {}, TOutputSelf extends EventRecord = {}, TOutputSync extends EventRecord = {}, -> implements - IOLike +> implements IOLike { - private readonly _context: TContext & - InferPlatformRoomContextType; + private readonly _context: TContext & InferPlatformRoomContextType; private readonly _debug: boolean; private readonly _docFactory: AbstractCrdtDocFactory; private readonly _platform: TPlatform; @@ -119,38 +102,15 @@ export class IORoom< private _uninitialize: (() => Promise) | null = null; readonly _authorize: TAuthorize | null = null; - readonly _events: InferEventConfig< - TPlatform, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - >; + readonly _events: InferEventConfig; readonly id: string; constructor( id: string, - config: IORoomConfig< - TPlatform, - TAuthorize, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - >, + config: IORoomConfig, ) { - const { - authorize, - context, - crdt = noop, - debug, - events, - onDestroy, - platform, - } = config; + const { authorize, context, crdt = noop, debug, events, onDestroy, platform } = config; this._context = context; this._debug = debug; @@ -189,9 +149,7 @@ export class IORoom< return Array.from(this._sessions.values()).reduce((count, session) => { if (session.quit) return count; - return currentTime - session.timers.ping > PING_TIMEOUT_MS - ? count - : count + 1; + return currentTime - session.timers.ping > PING_TIMEOUT_MS ? count : count + 1; }, 0); } @@ -200,9 +158,8 @@ export class IORoom< options: WebsocketRegisterOptions, ): Promise { const { token, ..._platformEventContext } = options; - const platformEventContext = - _platformEventContext as InferPlatformRoomContextType & - InferPlatformEventContextType; + const platformEventContext = _platformEventContext as InferPlatformRoomContextType & + InferPlatformEventContextType; if (!this._uninitialize) await this._initialize(); @@ -215,11 +172,7 @@ export class IORoom< userId: user?.id ?? null, }); - this._logDebug( - `${colors.blue( - `Registering connection for room ${this.id}:`, - )} ${sessionId}`, - ); + this._logDebug(`${colors.blue(`Registering connection for room ${this.id}:`)} ${sessionId}`); const uninitializeWs = await pluvWs.initialize(); const ioAuthorize = this._getIOAuthorize(options); @@ -227,17 +180,10 @@ export class IORoom< const isUnauthorized = !!ioAuthorize?.required && !user; // There is an attempt for multiple of the same identities. Probably malicious. const isTokenInUse = - !!user && - Array.from(this._sessions.values()).some( - (session) => session.user?.id === user.id, - ); + !!user && Array.from(this._sessions.values()).some((session) => session.user?.id === user.id); if (isUnauthorized || isTokenInUse) { - this._logDebug( - `${colors.blue( - "Authorization failed for connection:", - )} ${sessionId}`, - ); + this._logDebug(`${colors.blue("Authorization failed for connection:")} ${sessionId}`); pluvWs.handleError({ error: new Error("Not authorized") }); pluvWs.close(3000, "WebSocket unauthorized."); @@ -260,16 +206,10 @@ export class IORoom< this._sessions.set(session.id, session); - await this._platform.persistance.addUser( - this.id, - sessionId, - user ?? {}, - ); + await this._platform.persistance.addUser(this.id, sessionId, user ?? {}); const onClose = this._onClose(session, uninitializeWs).bind(this); - const onMessage = this._onMessage(session, platformEventContext).bind( - this, - ); + const onMessage = this._onMessage(session, platformEventContext).bind(this); pluvWs.addEventListener("close", onClose); pluvWs.addEventListener("error", onClose); @@ -277,11 +217,7 @@ export class IORoom< this._emitRegistered(session); - this._logDebug( - `${colors.blue( - `Registered connection for room ${this.id}:`, - )} ${sessionId}`, - ); + this._logDebug(`${colors.blue(`Registered connection for room ${this.id}:`)} ${sessionId}`); const size = this.getSize(); @@ -295,9 +231,7 @@ export class IORoom< const sender = senderId ? this._sessions.get(senderId) : null; const quitters = Array.from(this._sessions.values()).filter( - (session) => - session.quit || - currentTime - session.timers.ping > PING_TIMEOUT_MS, + (session) => session.quit || currentTime - session.timers.ping > PING_TIMEOUT_MS, ); quitters.forEach((session) => { @@ -370,9 +304,7 @@ export class IORoom< } if (payload.room !== this.id) { - this._logDebug( - colors.blue(`Token is not authorized for room ${this.id}:`), - ); + this._logDebug(colors.blue(`Token is not authorized for room ${this.id}:`)); this._logDebug(colors.blue("Received:"), payload.room); this._logDebug(token); @@ -382,9 +314,7 @@ export class IORoom< try { return ioAuthorize.user.parse(payload.user) ?? null; } catch { - this._logDebug( - `${colors.blue("Token fails validation:")} ${token}`, - ); + this._logDebug(`${colors.blue("Token fails validation:")} ${token}`); return null; } @@ -392,22 +322,11 @@ export class IORoom< private _getEventConfig( message: EventMessage, - ): - | InferEventConfig< - TPlatform, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - >[keyof TInput] - | null { + ): InferEventConfig[keyof TInput] | null { return this._events[message.type as keyof TInput] ?? null; } - private _getEventInputs( - message: EventMessage, - ): TInput[string] { + private _getEventInputs(message: EventMessage): TInput[string] { const eventConfig = this._getEventConfig(message); if (!eventConfig) return message.data; @@ -420,45 +339,26 @@ export class IORoom< * @author leedavidcs * @date September 25, 2022 */ - return eventConfig.input - ? (eventConfig.input.parse(message.data) as TInput[string]) - : message.data; + return eventConfig.input ? (eventConfig.input.parse(message.data) as TInput[string]) : message.data; } private _getEventResolverObject( message: EventMessage, - ): EventResolverObject< - TPlatform, - TContext, - TInput[string], - TOutputBroadcast, - TOutputSelf, - TOutputSync - > { + ): EventResolverObject { const eventConfig = this._getEventConfig(message); if (!eventConfig) return {}; const resolver: | EventResolver< - TContext & - InferPlatformRoomContextType & - InferPlatformEventContextType, + TContext & InferPlatformRoomContextType & InferPlatformEventContextType, TInput[string], TOutputBroadcast > - | EventResolverObject< - TPlatform, - TContext, - TInput[string], - TOutputBroadcast, - TOutputSelf, - TOutputSync - > = eventConfig.resolver; - - return typeof resolver === "function" - ? { broadcast: resolver } - : { ...resolver }; + | EventResolverObject = + eventConfig.resolver; + + return typeof resolver === "function" ? { broadcast: resolver } : { ...resolver }; } private async _initialize(): Promise { @@ -470,17 +370,14 @@ export class IORoom< this._uninitialize = null; } - const pubSubId = await this._platform.pubSub.subscribe( - this.id, - ({ options = {}, ...message }) => { - const session = { - id: message.connectionId, - user: message.user, - }; + const pubSubId = await this._platform.pubSub.subscribe(this.id, ({ options = {}, ...message }) => { + const session = { + id: message.connectionId, + user: message.user, + }; - this._sendMessage(message, session, options); - }, - ); + this._sendMessage(message, session, options); + }); this._uninitialize = async () => { this._platform.pubSub.unsubscribe(pubSubId); @@ -504,50 +401,35 @@ export class IORoom< this._debug && console.log(...data); } - private _onClose( - session: WebSocketSession, - callback?: () => void, - ): () => void { + private _onClose(session: WebSocketSession, callback?: () => void): () => void { return (): void => { if (!this._uninitialize) return; session.quit = true; - this._logDebug( - `${colors.blue( - `(Unregistering connection for room ${this.id}:`, - )} ${session.id}`, - ); + this._logDebug(`${colors.blue(`(Unregistering connection for room ${this.id}:`)} ${session.id}`); this._sessions.delete(session.id); - this._platform.persistance - .deleteUser(this.id, session.id) - .finally(() => { - this._broadcast({ - message: { - type: "$EXIT", - data: { sessionId: session.id }, - }, - senderId: session.id, - }); + this._platform.persistance.deleteUser(this.id, session.id).finally(() => { + this._broadcast({ + message: { + type: "$EXIT", + data: { sessionId: session.id }, + }, + senderId: session.id, + }); - callback?.(); + callback?.(); - const size = this.getSize(); + const size = this.getSize(); - this._logDebug( - `${colors.blue( - `Unregistered connection for room ${this.id}:`, - )} ${session.id}`, - ); - this._logDebug( - `${colors.blue(`Room ${this.id} size:`)} ${size}`, - ); + this._logDebug(`${colors.blue(`Unregistered connection for room ${this.id}:`)} ${session.id}`); + this._logDebug(`${colors.blue(`Room ${this.id} size:`)} ${size}`); - if (size) return; + if (size) return; - this._uninitialize?.(); - }); + this._uninitialize?.(); + }); }; } @@ -593,9 +475,7 @@ export class IORoom< } const extendedContext: EventResolverContext< - TContext & - InferPlatformRoomContextType & - InferPlatformEventContextType + TContext & InferPlatformRoomContextType & InferPlatformEventContextType > = { ...baseContext, context: { ...this._context, ...platformEventContext }, @@ -638,9 +518,7 @@ export class IORoom< }; } - private _parseMessage(message: { - data: string | ArrayBuffer; - }): EventMessage | null { + private _parseMessage(message: { data: string | ArrayBuffer }): EventMessage | null { try { const parsed = this._platform.parseData(message.data); @@ -703,10 +581,7 @@ export class IORoom< }); } - private _sendSelfMessage( - message: EventMessage, - sender: SendMessageSender | null, - ): void { + private _sendSelfMessage(message: EventMessage, sender: SendMessageSender | null): void { const senderId = sender?.id; if (!senderId) return; @@ -723,10 +598,7 @@ export class IORoom< }); } - private _sendSyncMessage( - message: EventMessage, - sender: SendMessageSender | null, - ): void { + private _sendSyncMessage(message: EventMessage, sender: SendMessageSender | null): void { const senderId = sender?.id; if (!senderId) return; diff --git a/packages/io/src/Persistance.ts b/packages/io/src/Persistance.ts index a6e6479a..e9d4d27b 100644 --- a/packages/io/src/Persistance.ts +++ b/packages/io/src/Persistance.ts @@ -5,13 +5,8 @@ export class Persistance extends AbstractPersistance { private _storages = new Map(); private _users = new Map>(); - public addUser( - room: string, - connectionId: string, - user: JsonObject | null, - ): Promise { - const users = - this._users.get(room) ?? new Map(); + public addUser(room: string, connectionId: string, user: JsonObject | null): Promise { + const users = this._users.get(room) ?? new Map(); this._users.set(room, users); users.set(connectionId, user); @@ -56,10 +51,7 @@ export class Persistance extends AbstractPersistance { return Promise.resolve(storage); } - public getUser( - room: string, - connectionId: string, - ): Promise { + public getUser(room: string, connectionId: string): Promise { const user = this._users.get(room)?.get(connectionId); return Promise.resolve(user ?? null); diff --git a/packages/io/src/PluvIO.ts b/packages/io/src/PluvIO.ts index b6bbe396..3826ee14 100644 --- a/packages/io/src/PluvIO.ts +++ b/packages/io/src/PluvIO.ts @@ -17,11 +17,7 @@ import type { Spread, } from "@pluv/types"; import colors from "kleur"; -import type { - AbstractPlatform, - InferPlatformEventContextType, - InferPlatformRoomContextType, -} from "./AbstractPlatform"; +import type { AbstractPlatform, InferPlatformEventContextType, InferPlatformRoomContextType } from "./AbstractPlatform"; import type { IORoomListenerEvent } from "./IORoom"; import { IORoom } from "./IORoom"; import type { JWTEncodeParams } from "./authorize"; @@ -30,14 +26,10 @@ import type { EventConfig, InferEventConfig } from "./types"; import { __PLUV_VERSION } from "./version"; type InferIOContext> = - TIO extends PluvIO - ? IContext - : never; + TIO extends PluvIO ? IContext : never; type InferIOPlatform> = - TIO extends PluvIO - ? IPlatform - : never; + TIO extends PluvIO ? IPlatform : never; export type InferIORoom> = TIO extends PluvIO< @@ -49,15 +41,7 @@ export type InferIORoom> = infer IOutputSelf, infer IOutputSync > - ? IORoom< - IPlatform, - IAuthorize, - IContext, - IInput, - IOutputBroadcast, - IOutputSelf, - IOutputSync - > + ? IORoom : never; type GetInitialStorageEvent = { @@ -75,11 +59,7 @@ export interface PluvIOListeners { export type PluvIOConfig< TPlatform extends AbstractPlatform = AbstractPlatform, - TAuthorize extends IOAuthorize< - any, - any, - InferPlatformRoomContextType - > | null = null, + TAuthorize extends IOAuthorize> | null = null, TContext extends JsonObject = {}, TInput extends EventRecord = {}, TOutputBroadcast extends EventRecord = {}, @@ -90,14 +70,7 @@ export type PluvIOConfig< context?: TContext; crdt?: { doc: (value: any) => AbstractCrdtDocFactory }; debug?: boolean; - events?: InferEventConfig< - TPlatform, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - >; + events?: InferEventConfig; getInitialStorage?: GetInitialStorageFn; platform: TPlatform; }; @@ -108,44 +81,24 @@ export type GetRoomOptions = { export class PluvIO< TPlatform extends AbstractPlatform = AbstractPlatform, - TAuthorize extends IOAuthorize< - any, - any, - InferPlatformRoomContextType - > = BaseIOAuthorize, + TAuthorize extends IOAuthorize> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord = {}, TOutputBroadcast extends EventRecord = {}, TOutputSelf extends EventRecord = {}, TOutputSync extends EventRecord = {}, -> implements - IOLike +> implements IOLike { private _rooms = new Map< string, - IORoom< - TPlatform, - TAuthorize, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - > + IORoom >(); readonly _authorize: TAuthorize | null = null; readonly _context: TContext = {} as TContext; readonly _crdt: { doc: (value: any) => AbstractCrdtDocFactory }; readonly _debug: boolean; - readonly _events: InferEventConfig< - TPlatform, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - > = { + readonly _events: InferEventConfig = { $GET_OTHERS: { resolver: { sync: (data, { room, session, sessions }) => { @@ -190,8 +143,7 @@ export class PluvIO< }; }, self: async ({ update }, { context, doc, room }) => { - const oldState = - await this._platform.persistance.getStorageState(room); + const oldState = await this._platform.persistance.getStorageState(room); const updates: readonly Maybe[] = [ oldState @@ -204,14 +156,9 @@ export class PluvIO< ]; if (updates.some((_update) => !!_update)) { - const encodedState = doc - .batchApplyEncodedState(updates) - .getEncodedState(); + const encodedState = doc.batchApplyEncodedState(updates).getEncodedState(); - await this._platform.persistance.setStorageState( - room, - encodedState, - ); + await this._platform.persistance.setStorageState(room, encodedState); this._listeners.onStorageUpdated({ ...context, @@ -220,10 +167,7 @@ export class PluvIO< }); } - const state = - (await this._platform.persistance.getStorageState( - room, - )) ?? doc.getEncodedState(); + const state = (await this._platform.persistance.getStorageState(room)) ?? doc.getEncodedState(); return { $STORAGE_RECEIVED: { state } }; }, @@ -246,63 +190,39 @@ export class PluvIO< resolver: ({ presence }, { session }) => { if (!session) return {}; - session.presence = Object.assign( - Object.create(null), - session.presence, - presence, - ); + session.presence = Object.assign(Object.create(null), session.presence, presence); return { $PRESENCE_UPDATED: { presence } }; }, }, $UPDATE_STORAGE: { resolver: ({ origin, update }, { context, doc, room }) => { - if ( - origin === "$INITIALIZED" && - Object.keys(doc.toJson()).length - ) { + if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) { return; } const updated = doc.applyEncodedState({ update }); const encodedState = updated.getEncodedState(); - this._platform.persistance - .setStorageState(room, encodedState) - .then(() => { - this._listeners.onStorageUpdated({ - ...context, - encodedState, - room, - }); + this._platform.persistance.setStorageState(room, encodedState).then(() => { + this._listeners.onStorageUpdated({ + ...context, + encodedState, + room, }); + }); return { $STORAGE_UPDATED: { state: encodedState } }; }, }, - } as InferEventConfig< - TPlatform, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - >; + } as InferEventConfig; readonly _getInitialStorage: GetInitialStorageFn | null = null; readonly _listeners: PluvIOListeners; readonly _platform: TPlatform; readonly _version: string = __PLUV_VERSION as any; constructor( - options: PluvIOConfig< - TPlatform, - TAuthorize, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - >, + options: PluvIOConfig, ) { const { authorize, @@ -332,21 +252,14 @@ export class PluvIO< } public async createToken( - params: JWTEncodeParams< - InferIOAuthorizeUser>, - TPlatform - >, + params: JWTEncodeParams>, TPlatform>, ): Promise { if (!this._authorize) { - throw new Error( - "IO does not specify authorize during initialization.", - ); + throw new Error("IO does not specify authorize during initialization."); } const ioAuthorize = - typeof this._authorize === "function" - ? this._authorize(params) - : (this._authorize as { secret: string }); + typeof this._authorize === "function" ? this._authorize(params) : (this._authorize as { secret: string }); const secret = ioAuthorize.secret; @@ -364,14 +277,7 @@ export class PluvIO< TResultSync extends EventRecord = {}, >( event: TEvent, - config: EventConfig< - TPlatform, - TContext, - TData, - TResultBroadcast, - TResultSelf, - TResultSync - >, + config: EventConfig, ): PluvIO< TPlatform, TAuthorize, @@ -391,9 +297,7 @@ export class PluvIO< TPlatform, TContext, EventRecord, - TResultBroadcast extends EventRecord - ? TResultBroadcast - : {}, + TResultBroadcast extends EventRecord ? TResultBroadcast : {}, TResultSelf extends EventRecord ? TResultSelf : {}, TResultSync extends EventRecord ? TResultSync : {} >; @@ -424,15 +328,7 @@ export class PluvIO< public getRoom( room: string, options: GetRoomOptions, - ): IORoom< - TPlatform, - TAuthorize, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - > { + ): IORoom { const { debug, ...platformRoomContext } = options; this._purgeEmptyRooms(); @@ -451,48 +347,36 @@ export class PluvIO< ...platformRoomContext, } as TContext & InferPlatformRoomContextType; - const newRoom = new IORoom< - TPlatform, - TAuthorize, - TContext, - TInput, - TOutputBroadcast, - TOutputSelf, - TOutputSync - >(room, { - authorize: this._authorize ?? undefined, - context: roomContext, - crdt: this._crdt, - debug: debug ?? this._debug, - events: this._events, - onDestroy: ({ encodedState, room }) => { - this._logDebug( - `${colors.blue("Deleting empty room:")} ${room}`, - ); - - const roomContext = { - room, - encodedState, - ...platformRoomContext, - } as IORoomListenerEvent & - InferPlatformRoomContextType; - - this._rooms.delete(room); - this._listeners.onRoomDeleted(roomContext); - - if (this._debug) { - const rooms = Array.from(this._rooms.keys()); - - this._logDebug(`${colors.blue("Deleted room:")} ${room}`); - this._logDebug( - `${colors.blue("Rooms available:")} ${rooms.join( - ", ", - )}`, - ); - } + const newRoom = new IORoom( + room, + { + authorize: this._authorize ?? undefined, + context: roomContext, + crdt: this._crdt, + debug: debug ?? this._debug, + events: this._events, + onDestroy: ({ encodedState, room }) => { + this._logDebug(`${colors.blue("Deleting empty room:")} ${room}`); + + const roomContext = { + room, + encodedState, + ...platformRoomContext, + } as IORoomListenerEvent & InferPlatformRoomContextType; + + this._rooms.delete(room); + this._listeners.onRoomDeleted(roomContext); + + if (this._debug) { + const rooms = Array.from(this._rooms.keys()); + + this._logDebug(`${colors.blue("Deleted room:")} ${room}`); + this._logDebug(`${colors.blue("Rooms available:")} ${rooms.join(", ")}`); + } + }, + platform, }, - platform, - }); + ); this._rooms.set(room, newRoom); @@ -500,9 +384,7 @@ export class PluvIO< const rooms = Array.from(this._rooms.keys()); this._logDebug(`${colors.blue("Created room:")} ${room}`); - this._logDebug( - `${colors.blue("Rooms available:")} ${rooms.join(", ")}`, - ); + this._logDebug(`${colors.blue("Rooms available:")} ${rooms.join(", ")}`); } return newRoom; @@ -520,17 +402,13 @@ export class PluvIO< Spread<[InferIOOutputSelf, InferIOOutputSelf]>, Spread<[InferIOOutputSync, InferIOOutputSync]> > { - const authorize = (first._authorize ?? - undefined) as InferIOAuthorize; + const authorize = (first._authorize ?? undefined) as InferIOAuthorize; const context = first._context as InferIOContext; const crdt = first._crdt; const debug = first._debug; const platform = first._platform as InferIOPlatform; - const getInitialStorage = - first._getInitialStorage as GetInitialStorageFn< - InferIOPlatform - >; + const getInitialStorage = first._getInitialStorage as GetInitialStorageFn>; const events1 = first._events; const events2 = second._events; diff --git a/packages/io/src/PubSub.ts b/packages/io/src/PubSub.ts index c52ffbeb..96e43be2 100644 --- a/packages/io/src/PubSub.ts +++ b/packages/io/src/PubSub.ts @@ -10,15 +10,9 @@ export class PubSub extends AbstractPubSub { // Map of roomName to subscription ids private _subscriptionsRefs = new Map(); // Map of - private _unsubscriptions = new Map< - number, - [roomName: string, unsubscribe: () => void] - >(); - - public async publish( - roomName: string, - payload: IOPubSubEventMessage, - ): Promise { + private _unsubscriptions = new Map void]>(); + + public async publish(roomName: string, payload: IOPubSubEventMessage): Promise { const subject = this._subjects.get(roomName); if (!subject) return; @@ -26,10 +20,7 @@ export class PubSub extends AbstractPubSub { Promise.resolve(subject.next(payload)); } - public subscribe( - roomName: string, - onMessage: (message: IOPubSubEventMessage) => void, - ): Promise { + public subscribe(roomName: string, onMessage: (message: IOPubSubEventMessage) => void): Promise { const id = this._currentSubscriptionId++; const refs = this._subscriptionsRefs.get(roomName) ?? []; @@ -46,8 +37,7 @@ export class PubSub extends AbstractPubSub { } public unsubscribe(subscriptionId: number): void { - const [roomName, unsubscribe] = - this._unsubscriptions.get(subscriptionId) ?? []; + const [roomName, unsubscribe] = this._unsubscriptions.get(subscriptionId) ?? []; if (!roomName || !unsubscribe) return; @@ -67,9 +57,7 @@ export class PubSub extends AbstractPubSub { this._subscriptionsRefs.set( roomName, - index === -1 - ? refs - : [...refs.slice(0, index), ...refs.slice(index + 1)], + index === -1 ? refs : [...refs.slice(0, index), ...refs.slice(index + 1)], ); unsubscribe(); diff --git a/packages/io/src/authorize.ts b/packages/io/src/authorize.ts index 08df9d2a..483bb346 100644 --- a/packages/io/src/authorize.ts +++ b/packages/io/src/authorize.ts @@ -1,21 +1,12 @@ import hkdf from "@panva/hkdf"; import type { BaseUser } from "@pluv/types"; import { EncryptJWT, jwtDecrypt } from "jose"; -import type { - AbstractPlatform, - InferPlatformRoomContextType, -} from "./AbstractPlatform"; +import type { AbstractPlatform, InferPlatformRoomContextType } from "./AbstractPlatform"; const DEFAULT_MAX_AGE_MS = 60_000; export const getEncryptionKey = async (secret: string): Promise => { - return await hkdf( - "sha256", - secret, - "", - "Pluv.io Generated Encryption Key", - 32, - ); + return await hkdf("sha256", secret, "", "Pluv.io Generated Encryption Key", 32); }; export interface JWT { @@ -24,10 +15,7 @@ export interface JWT { user: TUser; } -export type JWTEncodeParams< - TUser extends BaseUser, - TPlatform extends AbstractPlatform, -> = { +export type JWTEncodeParams = { maxAge?: number; room: string; user: TUser; @@ -50,10 +38,7 @@ const now = () => (Date.now() / 1_000) | 0; export const authorize = (params: AuthorizeParams) => { const { platform, secret } = params; - const encode = async < - TUser extends BaseUser, - TPlatform extends AbstractPlatform, - >( + const encode = async ( encodeParams: JWTEncodeParams, ): Promise => { const { maxAge = DEFAULT_MAX_AGE_MS, room, user } = encodeParams; @@ -74,9 +59,7 @@ export const authorize = (params: AuthorizeParams) => { return token.toString(); }; - const decode = async ( - jwt: string, - ): Promise | null> => { + const decode = async (jwt: string): Promise | null> => { const encryptionSecret = await getEncryptionKey(secret); const { payload } = await jwtDecrypt(jwt, encryptionSecret, { diff --git a/packages/io/src/createIO.ts b/packages/io/src/createIO.ts index fe0da5b0..fd9b52f7 100644 --- a/packages/io/src/createIO.ts +++ b/packages/io/src/createIO.ts @@ -1,15 +1,6 @@ import type { AbstractCrdtDocFactory } from "@pluv/crdt"; -import type { - BaseClientEventRecord, - BaseIOEventRecord, - BaseUser, - IOAuthorize, - JsonObject, -} from "@pluv/types"; -import type { - AbstractPlatform, - InferPlatformRoomContextType, -} from "./AbstractPlatform"; +import type { BaseClientEventRecord, BaseIOEventRecord, BaseUser, IOAuthorize, JsonObject } from "@pluv/types"; +import type { AbstractPlatform, InferPlatformRoomContextType } from "./AbstractPlatform"; import type { GetInitialStorageFn, PluvIOListeners } from "./PluvIO"; import { PluvIO } from "./PluvIO"; @@ -19,11 +10,7 @@ export type CreateIOParams< TAuthorizeUser extends BaseUser = BaseUser, TAuthorizeRequired extends boolean = false, > = Partial> & { - authorize?: IOAuthorize< - TAuthorizeUser, - TAuthorizeRequired, - InferPlatformRoomContextType - >; + authorize?: IOAuthorize>; context?: TContext; crdt?: { doc: (value: any) => AbstractCrdtDocFactory }; debug?: boolean; @@ -37,41 +24,19 @@ export const createIO = < TAuthorizeUser extends BaseUser = BaseUser, TAuthorizeRequired extends boolean = false, >( - params: CreateIOParams< - TPlatform, - TContext, - TAuthorizeUser, - TAuthorizeRequired - >, + params: CreateIOParams, ): PluvIO< TPlatform, - IOAuthorize< - TAuthorizeUser, - TAuthorizeRequired, - InferPlatformRoomContextType - >, + IOAuthorize>, TContext, BaseClientEventRecord, BaseIOEventRecord> > => { - const { - authorize, - context, - crdt, - debug, - getInitialStorage, - onRoomDeleted, - onStorageUpdated, - platform, - } = params; + const { authorize, context, crdt, debug, getInitialStorage, onRoomDeleted, onStorageUpdated, platform } = params; return new PluvIO< TPlatform, - IOAuthorize< - TAuthorizeUser, - TAuthorizeRequired, - InferPlatformRoomContextType - >, + IOAuthorize>, TContext, BaseClientEventRecord, BaseIOEventRecord> diff --git a/packages/io/src/index.ts b/packages/io/src/index.ts index 0a193a0e..5db4b2d8 100644 --- a/packages/io/src/index.ts +++ b/packages/io/src/index.ts @@ -1,9 +1,4 @@ -export type { - BaseUser, - EventMessage, - EventRecord, - IOEventMessage, -} from "@pluv/types"; +export type { BaseUser, EventMessage, EventRecord, IOEventMessage } from "@pluv/types"; export { AbstractPersistance } from "./AbstractPersistance"; export { AbstractPlatform } from "./AbstractPlatform"; export type { @@ -29,11 +24,6 @@ export type { export type { IORoom } from "./IORoom"; export { PluvIO } from "./PluvIO"; export type { GetRoomOptions, InferIORoom, PluvIOConfig } from "./PluvIO"; -export type { - AuthorizeModule, - AuthorizeParams, - JWT, - JWTEncodeParams, -} from "./authorize"; +export type { AuthorizeModule, AuthorizeParams, JWT, JWTEncodeParams } from "./authorize"; export { createIO } from "./createIO"; export type { CreateIOParams } from "./createIO"; diff --git a/packages/io/src/types.ts b/packages/io/src/types.ts index c0572442..7918d34a 100644 --- a/packages/io/src/types.ts +++ b/packages/io/src/types.ts @@ -1,16 +1,6 @@ import type { AbstractCrdtDoc } from "@pluv/crdt"; -import type { - EventRecord, - Id, - InputZodLike, - JsonObject, - MaybePromise, -} from "@pluv/types"; -import { - AbstractPlatform, - InferPlatformEventContextType, - InferPlatformRoomContextType, -} from "./AbstractPlatform"; +import type { EventRecord, Id, InputZodLike, JsonObject, MaybePromise } from "@pluv/types"; +import { AbstractPlatform, InferPlatformEventContextType, InferPlatformRoomContextType } from "./AbstractPlatform"; import type { AbstractWebSocket } from "./AbstractWebSocket"; declare global { @@ -30,20 +20,11 @@ export interface EventConfig< input?: InputZodLike; resolver: | EventResolver< - TContext & - InferPlatformRoomContextType & - InferPlatformEventContextType, + TContext & InferPlatformRoomContextType & InferPlatformEventContextType, TData, TResultBroadcast > - | EventResolverObject< - TPlatform, - TContext, - TData, - TResultBroadcast, - TResultSelf, - TResultSync - >; + | EventResolverObject; } export type EventConfigType = "broadcast" | "self" | "sync"; @@ -52,23 +33,15 @@ export type SyncEventResolver< TContext extends Record = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord = {}, -> = ( - data: TData, - context: EventResolverContext, -) => MaybePromise; +> = (data: TData, context: EventResolverContext) => MaybePromise; export type EventResolver< TContext extends Record = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord = {}, -> = ( - data: TData, - context: EventResolverContext, -) => MaybePromise; +> = (data: TData, context: EventResolverContext) => MaybePromise; -export interface EventResolverContext< - TContext extends Record = {}, -> { +export interface EventResolverContext = {}> { context: TContext; doc: AbstractCrdtDoc; room: string; @@ -97,16 +70,12 @@ export type EventResolverObject< TResultSync extends EventRecord = {}, > = { broadcast?: EventResolver< - TContext & - InferPlatformRoomContextType & - InferPlatformEventContextType, + TContext & InferPlatformRoomContextType & InferPlatformEventContextType, TData, TResultBroadcast >; self?: EventResolver< - TContext & - InferPlatformRoomContextType & - InferPlatformEventContextType, + TContext & InferPlatformRoomContextType & InferPlatformEventContextType, TData, TResultSelf >; @@ -122,16 +91,7 @@ export type InferEventConfig< TOutputSync extends EventRecord = {}, > = { [P in keyof TInput]: P extends string - ? Id< - EventConfig< - TPlatform, - TContext, - TInput[P], - TOutputBroadcast, - TOutputSelf, - TOutputSync - > - > + ? Id> : never; }; diff --git a/packages/persistance-redis/src/PersistanceRedis.ts b/packages/persistance-redis/src/PersistanceRedis.ts index 620ecbb6..1325e2cc 100644 --- a/packages/persistance-redis/src/PersistanceRedis.ts +++ b/packages/persistance-redis/src/PersistanceRedis.ts @@ -22,18 +22,11 @@ export class PersistanceRedis extends AbstractPersistance { this._client = client; } - public async addUser( - room: string, - connectionId: string, - user: JsonObject | null, - ): Promise { + public async addUser(room: string, connectionId: string, user: JsonObject | null): Promise { await this._client .multi() .sadd(this._getRoomUsersKey(room), connectionId) - .set( - this._getRoomUsersUserKey(room, connectionId), - JSON.stringify(user), - ) + .set(this._getRoomUsersUserKey(room, connectionId), JSON.stringify(user)) .exec(); } @@ -50,25 +43,19 @@ export class PersistanceRedis extends AbstractPersistance { .del(this._getRoomUsersUserKey(room, connectionId)); if (size === 1) { - multi = multi - .del(this._getRoomStorageKey(room)) - .del(this._getRoomUsersKey(room)); + multi = multi.del(this._getRoomStorageKey(room)).del(this._getRoomUsersKey(room)); } await multi.exec(); } public async deleteUsers(room: string): Promise { - const members = await this._client.smembers( - this._getRoomUsersKey(room), - ); + const members = await this._client.smembers(this._getRoomUsersKey(room)); await members .reduce( (commands, connectionId) => { - return commands.del( - this._getRoomUsersUserKey(room, connectionId), - ); + return commands.del(this._getRoomUsersUserKey(room, connectionId)); }, this._client.multi().del(this._getRoomUsersKey(room)), ) @@ -87,27 +74,16 @@ export class PersistanceRedis extends AbstractPersistance { await this._client.set(this._getRoomStorageKey(room), state); } - public async getUser( - room: string, - connectionId: string, - ): Promise { - const data = await this._client.get( - this._getRoomUsersUserKey(room, connectionId), - ); + public async getUser(room: string, connectionId: string): Promise { + const data = await this._client.get(this._getRoomUsersUserKey(room, connectionId)); return !data ? null : JSON.parse(data); } - public async getUsers( - room: string, - ): Promise { - const members = await this._client.smembers( - this._getRoomUsersKey(room), - ); + public async getUsers(room: string): Promise { + const members = await this._client.smembers(this._getRoomUsersKey(room)); - return await Promise.all( - members.map((connectionId) => this.getUser(room, connectionId)), - ); + return await Promise.all(members.map((connectionId) => this.getUser(room, connectionId))); } private _getClusterKey(key: string): string { @@ -123,8 +99,6 @@ export class PersistanceRedis extends AbstractPersistance { } private _getRoomUsersUserKey(room: string, connectionId: string): string { - return this._getClusterKey( - `${this._getRoomUsersKey(room)}${DELIMITER}${connectionId}`, - ); + return this._getClusterKey(`${this._getRoomUsersKey(room)}${DELIMITER}${connectionId}`); } } diff --git a/packages/platform-cloudflare/src/CloudflarePlatform.ts b/packages/platform-cloudflare/src/CloudflarePlatform.ts index ebd36790..3b89462e 100644 --- a/packages/platform-cloudflare/src/CloudflarePlatform.ts +++ b/packages/platform-cloudflare/src/CloudflarePlatform.ts @@ -2,13 +2,12 @@ import type { ConvertWebSocketConfig } from "@pluv/io"; import { AbstractPlatform } from "@pluv/io"; import { CloudflareWebSocket } from "./CloudflareWebSocket"; -export class CloudflarePlatform< - TEnv extends Record = {}, -> extends AbstractPlatform { - public convertWebSocket( - webSocket: WebSocket, - config: ConvertWebSocketConfig, - ): CloudflareWebSocket { +export class CloudflarePlatform = {}> extends AbstractPlatform< + WebSocket, + { env: TEnv }, + { request: Request } +> { + public convertWebSocket(webSocket: WebSocket, config: ConvertWebSocketConfig): CloudflareWebSocket { return new CloudflareWebSocket(webSocket, config); } diff --git a/packages/platform-cloudflare/src/CloudflareWebSocket.ts b/packages/platform-cloudflare/src/CloudflareWebSocket.ts index a1a61479..ec4b8e22 100644 --- a/packages/platform-cloudflare/src/CloudflareWebSocket.ts +++ b/packages/platform-cloudflare/src/CloudflareWebSocket.ts @@ -1,9 +1,4 @@ -import { - AbstractEventMap, - AbstractListener, - AbstractWebSocket, - AbstractWebSocketConfig, -} from "@pluv/io"; +import { AbstractEventMap, AbstractListener, AbstractWebSocket, AbstractWebSocketConfig } from "@pluv/io"; export interface CloudflareWebSocketEventMap { close: CloseEvent; @@ -29,17 +24,12 @@ export class CloudflareWebSocket extends AbstractWebSocket { this.webSocket = webSocket; } - public addEventListener( - type: TType, - handler: AbstractListener, - ) { + public addEventListener(type: TType, handler: AbstractListener) { this.webSocket.addEventListener(type, handler as any); } public close(code?: number | undefined, reason?: string | undefined): void { - const canClose = [this.CONNECTING, this.OPEN].some( - (readyState) => readyState === this.readyState, - ); + const canClose = [this.CONNECTING, this.OPEN].some((readyState) => readyState === this.readyState); if (!canClose) return; diff --git a/packages/platform-cloudflare/src/createPluvHandler.ts b/packages/platform-cloudflare/src/createPluvHandler.ts index 27c49cf2..40b81a70 100644 --- a/packages/platform-cloudflare/src/createPluvHandler.ts +++ b/packages/platform-cloudflare/src/createPluvHandler.ts @@ -1,12 +1,5 @@ import { IORoom, PluvIO } from "@pluv/io"; -import { - Id, - InferIOAuthorize, - InferIOAuthorizeRequired, - InferIOAuthorizeUser, - Maybe, - MaybePromise, -} from "@pluv/types"; +import { Id, InferIOAuthorize, InferIOAuthorizeRequired, InferIOAuthorizeUser, Maybe, MaybePromise } from "@pluv/types"; import { match } from "path-to-regexp"; import { CloudflarePlatform } from "./CloudflarePlatform"; @@ -18,17 +11,10 @@ export type AuthorizeFunction> = ( ctx: AuthorizeFunctionContext, ) => MaybePromise>>>; -export type CreatePluvHandlerConfig< - TPluv extends PluvIO, - TEnv extends Record, -> = { +export type CreatePluvHandlerConfig, TEnv extends Record> = { binding: string; endpoint?: string; - modify?: ( - request: Request, - response: Response, - env: TEnv, - ) => MaybePromise; + modify?: (request: Request, response: Response, env: TEnv) => MaybePromise; io: TPluv; } & (InferIOAuthorizeRequired> extends true ? { authorize: AuthorizeFunction } @@ -39,9 +25,7 @@ export type PluvHandlerFetch = {}> = ( env: TEnv, ) => Promise; -export interface CreatePluvHandlerResult< - TEnv extends Record = {}, -> { +export interface CreatePluvHandlerResult = {}> { DurableObject: { new (state: DurableObjectState, env: TEnv): DurableObject; }; @@ -49,28 +33,11 @@ export interface CreatePluvHandlerResult< handler: ExportedHandler; } -type InferCloudflarePluvHandlerEnv< - TPluv extends PluvIO, -> = - TPluv extends PluvIO< - CloudflarePlatform, - any, - any, - any, - any, - any, - any - > - ? IEnv - : {}; - -export const createPluvHandler = < - TPluv extends PluvIO, ->( - config: CreatePluvHandlerConfig< - TPluv, - Id> - >, +type InferCloudflarePluvHandlerEnv> = + TPluv extends PluvIO, any, any, any, any, any, any> ? IEnv : {}; + +export const createPluvHandler = >( + config: CreatePluvHandlerConfig>>, ): CreatePluvHandlerResult>> => { const { authorize, binding, endpoint = "/api/pluv", modify, io } = config; @@ -78,31 +45,18 @@ export const createPluvHandler = < private _env: Id>; private _io: IORoom; - constructor( - state: DurableObjectState, - env: Id>, - ) { + constructor(state: DurableObjectState, env: Id>) { this._env = env; this._io = io.getRoom(state.id.toString(), { env }); } - webSocketClose( - ws: WebSocket, - code: number, - reason: string, - wasClean: boolean, - ): void | Promise {} + webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean): void | Promise {} webSocketError(ws: WebSocket, error: unknown): void | Promise {} - webSocketMessage( - ws: WebSocket, - message: string | ArrayBuffer, - ): void | Promise {} + webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): void | Promise {} - async fetch( - request: Request>, - ): Promise { + async fetch(request: Request>): Promise { const isWSRequest = request.headers.get("Upgrade") === "websocket"; if (!isWSRequest) { @@ -123,12 +77,8 @@ export const createPluvHandler = < } }; - const getDurableObjectNamespace = ( - env: Id>, - ): DurableObjectNamespace => { - const namespace = env[ - binding as keyof typeof env - ] as DurableObjectNamespace; + const getDurableObjectNamespace = (env: Id>): DurableObjectNamespace => { + const namespace = env[binding as keyof typeof env] as DurableObjectNamespace; if (!namespace) { throw new Error(`Could not find DurableObject binding: ${binding}`); @@ -137,9 +87,7 @@ export const createPluvHandler = < return namespace; }; - const authHandler: PluvHandlerFetch< - Id> - > = async (request, env) => { + const authHandler: PluvHandlerFetch>> = async (request, env) => { if (!authorize) return null; const { pathname, searchParams } = new URL(request.url); @@ -176,19 +124,14 @@ export const createPluvHandler = < status: 200, }); } catch (err) { - return new Response( - err instanceof Error ? err.message : "Unauthorized", - { - headers: { "Content-Type": "text/plain" }, - status: 403, - }, - ); + return new Response(err instanceof Error ? err.message : "Unauthorized", { + headers: { "Content-Type": "text/plain" }, + status: 403, + }); } }; - const roomHandler: PluvHandlerFetch< - Id> - > = async (request, env) => { + const roomHandler: PluvHandlerFetch>> = async (request, env) => { const { pathname } = new URL(request.url); const matcher = match<{ roomId: string }>(`${endpoint}/room/:roomId`); const matched = matcher(pathname); @@ -211,9 +154,7 @@ export const createPluvHandler = < return room.fetch(request); }; - const fetch: PluvHandlerFetch< - Id> - > = async (request, env) => { + const fetch: PluvHandlerFetch>> = async (request, env) => { return [authHandler, roomHandler].reduce((promise, current) => { return promise.then((value) => value ?? current(request, env)); }, Promise.resolve(null)); diff --git a/packages/platform-cloudflare/src/platformCloudflare.ts b/packages/platform-cloudflare/src/platformCloudflare.ts index bd86b1fa..f31fc063 100644 --- a/packages/platform-cloudflare/src/platformCloudflare.ts +++ b/packages/platform-cloudflare/src/platformCloudflare.ts @@ -1,7 +1,5 @@ import { CloudflarePlatform } from "./CloudflarePlatform"; -export const platformCloudflare = < - TEnv extends Record = {}, ->(): CloudflarePlatform => { +export const platformCloudflare = = {}>(): CloudflarePlatform => { return new CloudflarePlatform(); }; diff --git a/packages/platform-node/src/NodePlatform.ts b/packages/platform-node/src/NodePlatform.ts index 1dd5f15a..d77c48ec 100644 --- a/packages/platform-node/src/NodePlatform.ts +++ b/packages/platform-node/src/NodePlatform.ts @@ -13,20 +13,14 @@ export type NodePlatformOptions = pubSub: AbstractPubSub; }; -export class NodePlatform extends AbstractPlatform< - WebSocket, - { req: IncomingMessage } -> { +export class NodePlatform extends AbstractPlatform { constructor(options: NodePlatformOptions = {}) { const { persistance, pubSub } = options; super(persistance && pubSub ? { persistance, pubSub } : {}); } - public convertWebSocket( - webSocket: WebSocket, - config: ConvertWebSocketConfig, - ): NodeWebSocket { + public convertWebSocket(webSocket: WebSocket, config: ConvertWebSocketConfig): NodeWebSocket { return new NodeWebSocket(webSocket, config); } diff --git a/packages/platform-node/src/NodeWebSocket.ts b/packages/platform-node/src/NodeWebSocket.ts index cfb2a9cf..64078fac 100644 --- a/packages/platform-node/src/NodeWebSocket.ts +++ b/packages/platform-node/src/NodeWebSocket.ts @@ -32,10 +32,7 @@ export class NodeWebSocket extends AbstractWebSocket { this.webSocket = webSocket; } - public addEventListener( - type: TType, - handler: AbstractListener, - ): void { + public addEventListener(type: TType, handler: AbstractListener): void { switch (type) { case "close": this.webSocket.on("close", async (code, reason) => { @@ -74,9 +71,7 @@ export class NodeWebSocket extends AbstractWebSocket { } public close(code?: number | undefined, reason?: string | undefined): void { - const canClose = [this.CONNECTING, this.OPEN].some( - (readyState) => readyState === this.readyState, - ); + const canClose = [this.CONNECTING, this.OPEN].some((readyState) => readyState === this.readyState); if (!canClose) return; diff --git a/packages/platform-node/src/createPluvHandler.ts b/packages/platform-node/src/createPluvHandler.ts index 24530f50..d6f076e1 100644 --- a/packages/platform-node/src/createPluvHandler.ts +++ b/packages/platform-node/src/createPluvHandler.ts @@ -1,11 +1,5 @@ import type { PluvIO } from "@pluv/io"; -import { - InferIOAuthorize, - InferIOAuthorizeRequired, - InferIOAuthorizeUser, - Maybe, - MaybePromise, -} from "@pluv/types"; +import { InferIOAuthorize, InferIOAuthorizeRequired, InferIOAuthorizeUser, Maybe, MaybePromise } from "@pluv/types"; import Http from "http"; import { match } from "path-to-regexp"; import Url from "url"; @@ -47,20 +41,13 @@ const handle = (ws: WS.WebSocket) => ({ }, }); -export type RequestHandler = ( - req: Http.IncomingMessage, - res: Http.ServerResponse, - next?: () => void, -) => void; +export type RequestHandler = (req: Http.IncomingMessage, res: Http.ServerResponse, next?: () => void) => void; export interface WebSocketHandlerResult { matched: boolean; } -export type WebSocketHandler = ( - ws: WS.WebSocket, - req: Http.IncomingMessage, -) => Promise; +export type WebSocketHandler = (ws: WS.WebSocket, req: Http.IncomingMessage) => Promise; export interface CreatePluvHandlerResult { createWsServer: () => WS.Server; @@ -68,19 +55,14 @@ export interface CreatePluvHandlerResult { wsHandler: WebSocketHandler; } -export const createPluvHandler = < - TPluv extends PluvIO, ->( +export const createPluvHandler = >( config: CreatePluvHandlerConfig, ): CreatePluvHandlerResult => { const { authorize, endpoint = "/api/pluv", io, server } = config; const wsServer = new WS.Server({ server }); - const wsHandler = async ( - ws: WS.WebSocket, - req: Http.IncomingMessage, - ): Promise => { + const wsHandler = async (ws: WS.WebSocket, req: Http.IncomingMessage): Promise => { const url = req.url; const onError = handle(ws); diff --git a/packages/platform-node/src/index.ts b/packages/platform-node/src/index.ts index dd818108..19622a12 100644 --- a/packages/platform-node/src/index.ts +++ b/packages/platform-node/src/index.ts @@ -1,8 +1,4 @@ -export type { - AuthorizeFunction, - AuthorizeFunctionContext, - CreatePluvHandlerConfig, -} from "./createPluvHandler"; +export type { AuthorizeFunction, AuthorizeFunctionContext, CreatePluvHandlerConfig } from "./createPluvHandler"; export { createPluvHandler } from "./createPluvHandler"; export type { WebSocket } from "ws"; export type { NodePlatformOptions } from "./NodePlatform"; diff --git a/packages/platform-node/src/platformNode.ts b/packages/platform-node/src/platformNode.ts index 67ca9874..57c09889 100644 --- a/packages/platform-node/src/platformNode.ts +++ b/packages/platform-node/src/platformNode.ts @@ -1,8 +1,6 @@ import type { NodePlatformOptions } from "./NodePlatform"; import { NodePlatform } from "./NodePlatform"; -export const platformNode = ( - options: NodePlatformOptions = {}, -): NodePlatform => { +export const platformNode = (options: NodePlatformOptions = {}): NodePlatform => { return new NodePlatform(options); }; diff --git a/packages/pubsub-redis/src/PubSubRedis.ts b/packages/pubsub-redis/src/PubSubRedis.ts index 05b929bd..f492312e 100644 --- a/packages/pubsub-redis/src/PubSubRedis.ts +++ b/packages/pubsub-redis/src/PubSubRedis.ts @@ -16,10 +16,7 @@ export class PubSubRedis extends AbstractPubSub { private _subscriptionsRefs = new Map(); private _subscriptions = new Map< number, - [ - roomName: string, - onMessage: (message: IOPubSubEventMessage) => void, - ] + [roomName: string, onMessage: (message: IOPubSubEventMessage) => void] >(); constructor(options: PubSubRedisOptions) { @@ -45,17 +42,11 @@ export class PubSubRedis extends AbstractPubSub { return this._subscriber; } - public async publish( - roomName: string, - payload: IOPubSubEventMessage, - ): Promise { + public async publish(roomName: string, payload: IOPubSubEventMessage): Promise { await this._publisher.publish(roomName, JSON.stringify(payload)); } - public subscribe( - roomName: string, - onMessage: (message: IOPubSubEventMessage) => void, - ): Promise { + public subscribe(roomName: string, onMessage: (message: IOPubSubEventMessage) => void): Promise { const id = this._currentSubscriptionId++; const refs = this._subscriptionsRefs.get(roomName) ?? []; @@ -87,9 +78,7 @@ export class PubSubRedis extends AbstractPubSub { this._subscriptionsRefs.set( roomName, - index === -1 - ? refs - : [...refs.slice(0, index), ...refs.slice(index + 1)], + index === -1 ? refs : [...refs.slice(0, index), ...refs.slice(index + 1)], ); this._subscriptions.delete(subscriptionId); @@ -100,8 +89,7 @@ export class PubSubRedis extends AbstractPubSub { if (!subscribers?.length) return; - const parsed: IOPubSubEventMessage = - typeof message === "string" ? JSON.parse(message) : message; + const parsed: IOPubSubEventMessage = typeof message === "string" ? JSON.parse(message) : message; subscribers.forEach((id) => { const subscription = this._subscriptions.get(id); diff --git a/packages/react/src/internal/index.ts b/packages/react/src/internal/index.ts index 70b60259..372ffae9 100644 --- a/packages/react/src/internal/index.ts +++ b/packages/react/src/internal/index.ts @@ -1,6 +1,2 @@ -export { - useRerender, - useSyncExternalStore, - useSyncExternalStoreWithSelector, -} from "./hooks"; +export { useRerender, useSyncExternalStore, useSyncExternalStoreWithSelector } from "./hooks"; export { identity, shallowArrayEqual } from "./utils"; diff --git a/packages/types/src/general.ts b/packages/types/src/general.ts index 3da9e59d..bfd65713 100644 --- a/packages/types/src/general.ts +++ b/packages/types/src/general.ts @@ -12,11 +12,7 @@ export type SpreadProperties = { [P in K]: L[P] | Exclude; }; -export type Id = T extends infer U - ? U extends Constructable - ? U - : { [K in keyof U]: U[K] } - : never; +export type Id = T extends infer U ? (U extends Constructable ? U : { [K in keyof U]: U[K] }) : never; type SpreadTwo = Id< Pick> & @@ -25,12 +21,7 @@ type SpreadTwo = Id< SpreadProperties & keyof L> >; -export type Spread = A extends [ - infer L, - ...infer R, -] - ? SpreadTwo> - : unknown; +export type Spread = A extends [infer L, ...infer R] ? SpreadTwo> : unknown; export type DeepPartial = { [P in keyof T]?: T[P] extends Array @@ -44,28 +35,17 @@ export type DeepWriteable = { -readonly [P in keyof T]: DeepWriteable; }; -export type OptionalProps< - T extends Record, - K extends keyof T = keyof T, -> = Omit & Partial>; +export type OptionalProps, K extends keyof T = keyof T> = Omit & + Partial>; -export type NonNilProps< - T extends Record, - K extends keyof T = keyof T, -> = Omit & { [P in K]-?: NonNullable }; +export type NonNilProps, K extends keyof T = keyof T> = Omit & { + [P in K]-?: NonNullable; +}; export type JsonPrimitive = string | number | boolean | null; -export type Json = - | JsonPrimitive - | Json[] - | readonly Json[] - | { [key: string]: Json }; +export type Json = JsonPrimitive | Json[] | readonly Json[] | { [key: string]: Json }; export type JsonObject = Record; -export type StringLiteral = T extends string - ? string extends T - ? never - : T - : never; +export type StringLiteral = T extends string ? (string extends T ? never : T) : never; diff --git a/packages/types/src/pluv.ts b/packages/types/src/pluv.ts index 96b268b0..ca6977d3 100644 --- a/packages/types/src/pluv.ts +++ b/packages/types/src/pluv.ts @@ -28,9 +28,7 @@ export interface BaseIOAuthorize { user: InputZodLike; } -export interface BaseIOAuthorizeEventRecord< - TAuthorize extends IOAuthorize, -> { +export interface BaseIOAuthorizeEventRecord> { $OTHERS_RECEIVED: { others: { [connectionId: string]: { @@ -72,10 +70,7 @@ export type BaseIOEventRecord> = }; }; -export interface EventMessage< - TEvent extends string, - TData extends JsonObject = {}, -> { +export interface EventMessage { data: TData; type: TEvent; } @@ -84,10 +79,9 @@ export type EventRecord = { [key in `${TEvent}`]: TData; }; -export type GetEventMessage< - T extends EventRecord, - TEvent extends keyof T, -> = TEvent extends string ? EventMessage : never; +export type GetEventMessage, TEvent extends keyof T> = TEvent extends string + ? EventMessage + : never; export type InferEventMessage< TEvents extends EventRecord = EventRecord, @@ -96,41 +90,28 @@ export type InferEventMessage< [P in TEvent]: P extends string ? Id> : never; }[TEvent]; -export type InferIOAuthorize = - TIO extends IOLike ? IAuthorize : never; +export type InferIOAuthorize = TIO extends IOLike ? IAuthorize : never; -export type InferIOAuthorizeRequired< - TAuthorize extends IOAuthorize, -> = TAuthorize extends IOAuthorize ? IRequired : never; +export type InferIOAuthorizeRequired> = + TAuthorize extends IOAuthorize ? IRequired : never; -export type InferIOAuthorizeUser< - TAuthorize extends IOAuthorize, -> = +export type InferIOAuthorizeUser> = TAuthorize extends IOAuthorize ? IRequired extends true ? IUser : IUser | null : never; -export type InferIOInput = - TIO extends IOLike ? IInput : never; +export type InferIOInput = TIO extends IOLike ? IInput : never; export type InferIOOutput = - TIO extends IOLike< - any, - any, - infer IOutputBroadcast, - infer IOutputSelf, - infer IOutputSync - > + TIO extends IOLike ? Spread<[IOutputBroadcast, IOutputSelf, IOutputSync]> : never; -export type InferIOOutputBroadcast = - TIO extends IOLike ? IOutput : never; +export type InferIOOutputBroadcast = TIO extends IOLike ? IOutput : never; -export type InferIOOutputSelf = - TIO extends IOLike ? IOutput : never; +export type InferIOOutputSelf = TIO extends IOLike ? IOutput : never; export type InferIOOutputSync = TIO extends IOLike ? IOutput : never; @@ -171,10 +152,7 @@ export type IOAuthorizeRequiredEventMessage = NonNilProps< "connectionId" | "user" >; -export type IOEventMessage< - TIO extends IOLike, - TEvent extends keyof InferIOOutput = keyof InferIOOutput, -> = Id< +export type IOEventMessage = keyof InferIOOutput> = Id< { room: string } & InferEventMessage, TEvent> & (InferEventMessage, TEvent>["type"] extends "$ERROR" ? IOAuthorizeOptionalEventMessage @@ -193,23 +171,11 @@ export interface IOLike< [P in keyof TInput]: P extends string ? { resolver: - | (( - data: TInput[P], - ...args: any[] - ) => MaybePromise) + | ((data: TInput[P], ...args: any[]) => MaybePromise) | { - broadcast?: ( - data: TInput[P], - ...args: any[] - ) => MaybePromise; - self?: ( - data: TInput[P], - ...args: any[] - ) => MaybePromise; - sync?: ( - data: TInput[P], - ...args: any[] - ) => MaybePromise; + broadcast?: (data: TInput[P], ...args: any[]) => MaybePromise; + self?: (data: TInput[P], ...args: any[]) => MaybePromise; + sync?: (data: TInput[P], ...args: any[]) => MaybePromise; }; } : never; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b5ccb39..bbc0f02f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -688,6 +688,9 @@ importers: '@pluv-internal/react-icons': specifier: workspace:^ version: link:../react-icons + '@pluv-internal/utils': + specifier: workspace:^ + version: link:../utils '@radix-ui/react-dialog': specifier: ^1.0.5 version: 1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) @@ -697,6 +700,9 @@ importers: '@radix-ui/react-visually-hidden': specifier: ^1.0.3 version: 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@types/common-tags': + specifier: ^1.8.4 + version: 1.8.4 '@types/ms': specifier: ^0.7.34 version: 0.7.34 @@ -706,9 +712,15 @@ importers: '@types/react-dom': specifier: ^18.3.0 version: 18.3.0 + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 clsx: specifier: ^2.1.1 version: 2.1.1 + common-tags: + specifier: ^1.8.2 + version: 1.8.2 framer-motion: specifier: ^11.1.7 version: 11.1.7(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1)(react@18.3.1) @@ -936,6 +948,12 @@ importers: '@types/react': specifier: ^18.3.1 version: 18.3.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + tailwind-merge: + specifier: ^2.3.0 + version: 2.3.0 devDependencies: '@pluv/tsconfig': specifier: workspace:^ @@ -1175,25 +1193,25 @@ importers: specifier: ^8.57.0 version: 8.57.0 eslint-config-next: - specifier: ^14.2.3 + specifier: ^14.2.2 version: 14.2.3(eslint@8.57.0)(typescript@5.4.5) eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@8.57.0) eslint-config-turbo: - specifier: ^1.13.3 + specifier: ^1.13.2 version: 1.13.3(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) eslint-plugin-react: - specifier: ^7.34.1 + specifier: 7.34.1 version: 7.34.1(eslint@8.57.0) eslint-plugin-tailwindcss: specifier: ^3.15.1 version: 3.15.1(tailwindcss@3.4.3) next: - specifier: ^14.2.3 + specifier: ^14.2.2 version: 14.2.3(@playwright/test@1.43.1)(react-dom@18.3.1)(react@18.3.1) prettier: specifier: ^3.2.5 @@ -2932,18 +2950,14 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 - - /@babel/runtime@7.22.6: - resolution: {integrity: sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.11 + dev: false /@babel/runtime@7.23.1: resolution: {integrity: sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 + dev: false /@babel/runtime@7.23.5: resolution: {integrity: sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==} @@ -4254,7 +4268,7 @@ packages: /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: - '@babel/runtime': 7.23.5 + '@babel/runtime': 7.24.5 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 @@ -4583,7 +4597,7 @@ packages: /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} @@ -4619,7 +4633,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) @@ -4638,7 +4652,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 @@ -4651,7 +4665,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 @@ -4698,7 +4712,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 @@ -4740,7 +4754,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) @@ -4761,7 +4775,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 @@ -4801,7 +4815,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.1)(react@18.3.1) @@ -4820,7 +4834,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 react: 18.3.1 @@ -4923,7 +4937,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.3.1 '@types/react-dom': 18.3.0 @@ -4944,7 +4958,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 @@ -4966,7 +4980,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 '@radix-ui/react-slot': 1.0.2(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 '@types/react-dom': 18.3.0 @@ -4986,7 +5000,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) @@ -5072,7 +5086,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 react: 18.3.1 @@ -5191,7 +5205,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 @@ -5204,7 +5218,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 react: 18.3.1 @@ -5218,7 +5232,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 react: 18.3.1 @@ -5232,7 +5246,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 @@ -5245,7 +5259,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.1 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 @@ -5292,7 +5306,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.24.5 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.3.1 '@types/react-dom': 18.3.0 @@ -8426,6 +8440,12 @@ packages: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} dev: true + /class-variance-authority@0.7.0: + resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + dependencies: + clsx: 2.0.0 + dev: false + /clean-css@5.3.3: resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} @@ -8522,6 +8542,11 @@ packages: engines: {node: '>=0.8'} dev: true + /clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + engines: {node: '>=6'} + dev: false + /clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -9678,26 +9703,6 @@ packages: stop-iteration-iterator: 1.0.0 dev: true - /es-iterator-helpers@1.0.18: - resolution: {integrity: sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - globalthis: 1.0.4 - has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - iterator.prototype: 1.1.2 - safe-array-concat: 1.1.2 - dev: false - /es-iterator-helpers@1.0.19: resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} engines: {node: '>= 0.4'} @@ -10099,7 +10104,7 @@ packages: array.prototype.toreversed: 1.1.2 array.prototype.tosorted: 1.1.3 doctrine: 2.1.0 - es-iterator-helpers: 1.0.18 + es-iterator-helpers: 1.0.19 eslint: 8.57.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 @@ -15065,7 +15070,7 @@ packages: /regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.24.5 dev: true /regex-parser@2.3.0: @@ -16223,6 +16228,12 @@ packages: tslib: 2.6.2 dev: false + /tailwind-merge@2.3.0: + resolution: {integrity: sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==} + dependencies: + '@babel/runtime': 7.24.5 + dev: false + /tailwindcss@3.4.3(ts-node@10.9.2): resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} engines: {node: '>=14.0.0'}