bump deps

This commit is contained in:
sk1982 2024-04-12 05:17:41 -04:00
parent c00c429ede
commit e1ec5f275f
23 changed files with 200 additions and 1418 deletions

1
empty.cjs Normal file
View File

@ -0,0 +1 @@
module.exports = {};

View File

@ -56,12 +56,19 @@ module.exports = bundleAnalyzer({ enabled: !!process.env.ANALYZE })({
additionalData: `$asset-url: "${baseAssetUrl}";`
},
experimental: {
instrumentationHook: true
instrumentationHook: true,
serverComponentsExternalPackages: ['kysely', 'mysql2', 'bcrypt']
},
productionBrowserSourceMaps: true,
webpack: config => {
config.externals = [...config.externals, 'bcrypt', 'mysql2'];
webpack: (config, { nextRuntime }) => {
config.resolve.alias['resize-observer-polyfill'] = path.resolve(__dirname, 'resize-observer.cjs');
if (nextRuntime === 'edge') {
config.resolve.alias['mysql2'] = path.resolve(__dirname, 'empty.cjs');
config.resolve.alias['kysely'] = path.resolve(__dirname, 'empty.cjs');
config.resolve.alias['bcrypt'] = path.resolve(__dirname, 'empty.cjs');
config.resolve.alias['crypto'] = path.resolve(__dirname, 'empty.cjs');
config.resolve.alias['node:crypto'] = path.resolve(__dirname, 'empty.cjs');
}
return config;
}
});

1483
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -17,21 +17,21 @@
},
"dependencies": {
"@heroicons/react": "^2.1.3",
"@next/bundle-analyzer": "^14.1.4",
"@next/bundle-analyzer": "^14.2.0",
"@nextui-org/react": "^2.2.10",
"@tanstack/react-virtual": "^3.2.0",
"@tanstack/react-virtual": "^3.2.1",
"bcrypt": "^5.1.1",
"clsx": "^2.1.0",
"db-migrate": "^0.11.14",
"db-migrate-mysql": "^2.3.2",
"deep-is": "^0.1.4",
"framer-motion": "^10.18.0",
"framer-motion": "^11.0.28",
"jsonwebtoken": "^9.0.2",
"kysely": "^0.27.3",
"mysql2": "^3.9.2",
"next": "14.1.4",
"mysql2": "^3.9.4",
"next": "14.2.0",
"next-auth": "^5.0.0-beta.15",
"next-client-cookies": "^1.1.0",
"next-client-cookies": "^1.1.1",
"next-themes": "^0.3.0",
"react": "^18",
"react-day-picker": "^8.10.0",
@ -40,13 +40,13 @@
"react-icons": "^5.0.1",
"react-resizable": "^3.0.5",
"react-swipeable": "^7.0.1",
"sass": "^1.72.0",
"sass": "^1.75.0",
"tailwind-merge": "^2.2.2",
"tailwindcss-text-fill-stroke": "^2.0.0-beta.1",
"usehooks-ts": "^3.0.2"
"usehooks-ts": "^3.1.0"
},
"devDependencies": {
"@dotenvx/dotenvx": "^0.26.0",
"@dotenvx/dotenvx": "^0.32.0",
"@types/bcrypt": "^5.0.2",
"@types/jsonwebtoken": "^9.0.6",
"@types/node": "^20",
@ -54,15 +54,14 @@
"@types/react-dom": "^18",
"@types/react-grid-layout": "^1.3.5",
"@types/react-resizable": "^3.0.7",
"@types/react-virtualized": "^9.21.29",
"autoprefixer": "^10.4.19",
"eslint": "^8",
"eslint-config-next": "14.1.4",
"kysely-codegen": "^0.14.1",
"eslint-config-next": "14.2.0",
"kysely-codegen": "^0.14.2",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"tailwindcss": "^3.4.3",
"ts-node": "^10.9.2",
"type-fest": "^4.14.0",
"type-fest": "^4.15.0",
"typescript": "^5"
}
}

View File

@ -44,13 +44,15 @@ type LoginOptions = {
export const login = async (options?: LoginOptions) => {
if (!options)
return signIn();
return { redirect: await signIn(undefined, { redirect: false }) as string };
try {
return await signIn('credentials', {
const res = await signIn('credentials', {
...options,
redirectTo: options?.redirectTo ?? '/'
redirectTo: options.redirectTo ?? '/',
redirect: false,
});
return { redirect: res };
} catch (e) {
if (e instanceof AuthError) {
if (e.type === 'CredentialsSignin')
@ -63,8 +65,11 @@ export const login = async (options?: LoginOptions) => {
}
};
export const logout = async (options: { redirectTo?: string, redirect?: boolean }) => {
return signOut(options);
export const logout = async (options: { redirectTo?: string }) => {
return await signOut({
...options,
redirect: false
});
};
export const register = async (formData: FormData) => {

View File

@ -124,7 +124,7 @@ export async function getPlaylog(opts: GetPlaylogOptions) {
.select(({ fn }) => fn.countAll().as('total'))
.executeTakeFirstOrThrow()).total);
return { data: playlog, total };
return { data: structuredClone(playlog), total };
}
export type ChuniPlaylog = Awaited<ReturnType<typeof getPlaylog>>;

View File

@ -3,17 +3,15 @@
import { GeneratedDB, db } from '@/db';
import { getUser, requireUser } from './auth';
import { notFound } from 'next/navigation';
import { CompiledQuery, Transaction, sql } from 'kysely';
import { Transaction, sql } from 'kysely';
import { syncUserFriends, withChuniRivalCount } from '@/data/friend';
import { SqlBool } from 'kysely';
import { Exact } from 'type-fest';
import { revalidatePath } from 'next/cache';
export const getFriendRequests = async () => {
const user = await getUser();
if (!user) return [];
return db.selectFrom('actaeon_friend_requests as req')
return structuredClone(await db.selectFrom('actaeon_friend_requests as req')
.where('user', '=', user.id)
.innerJoin('aime_user as u', 'u.id', 'req.friend')
.innerJoin('actaeon_user_ext as ext', 'ext.userId', 'u.id')
@ -23,7 +21,7 @@ export const getFriendRequests = async () => {
'ext.uuid as userUuid'
])
.orderBy('req.createdDate desc')
.execute();
.execute());
};
export type FriendRequest = Awaited<ReturnType<typeof getFriendRequests>>[number];

View File

@ -157,5 +157,5 @@ export const createMachine = async ({ arcade, update }: { arcade: number, update
revalidatePath('/arcade', 'page');
revalidatePath('/arcade/[arcadeId]', 'page');
return { error: false, message: '', data: await getArcadeCabs({ arcade, user, permissions: arcadePermissions }) };
return { error: false, message: '', data: structuredClone(await getArcadeCabs({ arcade, user, permissions: arcadePermissions })) };
}

View File

@ -40,7 +40,8 @@ export const LoginCard = ({ initialError, referer, callback }: LoginCardProps) =
})
.then(res => {
if (res?.error)
setError(res.message)
return setError(res.message)
setTimeout(() => location.href = res.redirect, 10);
})
.finally(() => setLoading(false));
};

View File

@ -18,8 +18,8 @@ export default async function ArcadeDetailPage({ params }: { params: { arcadeId:
const [users, cabs, links] = await Promise.all([
getArcadeUsers({ arcade: arcade.id, permissions: arcade.permissions, user }),
getArcadeCabs({ arcade: arcade.id, permissions: arcade.permissions, user }),
getArcadeInviteLinks({ arcade: arcade.id, permissions: arcade.permissions, user })
getArcadeCabs({ arcade: arcade.id, permissions: arcade.permissions, user }).then(d => structuredClone(d)),
getArcadeInviteLinks({ arcade: arcade.id, permissions: arcade.permissions, user }).then(d => structuredClone(d))
]);
return (<ArcadeDetail users={users} arcade={arcade} cabs={cabs} links={links} />)

View File

@ -17,9 +17,9 @@ export default async function ChuniDashboard() {
return (<ChuniNoProfile />);
const [profile, rating, playlog] = await Promise.all([
getUserData(user),
getUserRating(user),
getPlaylog({ limit: 72 })
getUserData(user).then(d => structuredClone(d)),
getUserRating(user).then(d => structuredClone(d)),
getPlaylog({ limit: 72 }).then(d => structuredClone(d))
]);
return (<div className="flex h-full flex-col md:flex-row">

View File

@ -10,7 +10,7 @@ export default async function ChuniMusicDetailPage({ params }: { params: { music
return notFound();
const [music, playlog] = await Promise.all([
getMusic(musicId),
getMusic(musicId).then(d => structuredClone(d)),
getPlaylog({ musicId, limit: 500 })
]);

View File

@ -6,6 +6,6 @@ export default async function ChuniMusicPage() {
const music = await getMusic();
return (
<ChuniMusicList music={music} />
<ChuniMusicList music={structuredClone(music)} />
);
}

View File

@ -19,8 +19,8 @@ export default async function ChuniUserboxPage() {
if (!user?.chuni)
return (<ChuniNoProfile />);
const profile = await getUserData(user);
const userboxItems = await getUserboxItems(user, profile);
const profile = structuredClone(await getUserData(user));
const userboxItems = structuredClone(await getUserboxItems(user, profile));
return (<ChuniUserbox profile={profile} userboxItems={userboxItems} />);
}

View File

@ -9,13 +9,13 @@ export const dynamic = 'force-dynamic';
export default async function DashboardPage() {
const [user, status] = await Promise.all([
getUser(),
getServerStatus()
getServerStatus().then(d => structuredClone(d))
]);
if (!user) return (<Dashboard serverStatus={status} />)
const [chuniProfile, dashboard] = await Promise.all([
getUserData(user),
getUserData(user).then(d => structuredClone(d)),
getDashboard(user)
]);

View File

@ -6,7 +6,7 @@ export const dynamic = 'force-dynamic';
export default async function FriendsPage() {
const user = await requireUser();
const friends = await getFriends(user.id);
const friends = structuredClone(await getFriends(user.id));
return (<Friends friends={friends} />);
};

View File

@ -305,7 +305,8 @@ export const HeaderSidebar = ({ children }: HeaderSidebarProps) => {
</div>
</DropdownItem>
<DropdownItem className="p-0" color="danger" variant="flat">
<div className="w-full h-full block px-2 py-1.5 text-danger" onClick={() => logout({ redirectTo: '/' })}>
<div className="w-full h-full block px-2 py-1.5 text-danger" onClick={() => logout({ redirectTo: '/' })
.then(r => setTimeout(() => location.href = r.redirect, 10))}>
Logout
</div>
</DropdownItem>
@ -314,7 +315,8 @@ export const HeaderSidebar = ({ children }: HeaderSidebarProps) => {
</> :
<>
<ThemeSwitcherDropdown />
<Button size="sm" className="ml-2" color="primary" onClick={() => login()}>
<Button size="sm" className="ml-2" color="primary" onClick={() => login()
.then(r => setTimeout(() => location.href = r.redirect, 10))}>
Login
</Button>
</>
@ -397,7 +399,8 @@ export const HeaderSidebar = ({ children }: HeaderSidebarProps) => {
</Button>
</Link>}
</div>
<Button color="primary" className="w-full flex-shrink-0" onClick={() => user ? logout({ redirectTo: '/' }) : login()}>
<Button color="primary" className="w-full flex-shrink-0" onClick={() => (user ? logout({ redirectTo: '/' }) : login())
.then(r => setTimeout(() => location.href = r.redirect!, 10))}>
{user ? 'Logout' : 'Login'}
</Button>
</div>
@ -457,7 +460,8 @@ export const HeaderSidebar = ({ children }: HeaderSidebarProps) => {
</div>
</section>
<Button className="mt-auto mx-3 flex-shrink-0" color="danger" onPress={() => logout({ redirectTo: '/' })}>
<Button className="mt-auto mx-3 flex-shrink-0" color="danger" onPress={() => logout({ redirectTo: '/' })
.then(r => setTimeout(() => location.href = r.redirect, 10))}>
Logout
</Button>
</div>

View File

@ -7,7 +7,7 @@ import { getGlobalConfig } from '@/config';
export default async function SettingsPage() {
const user = await requireUser();
const cards = await getCards(user.id);
const cards = structuredClone(await getCards(user.id));
return (<div className="w-full flex items-center justify-center">
<div className="w-full max-w-full sm:max-w-5xl flex flex-col gap-2 2xl:max-w-screen-4xl 2xl:grid grid-cols-12">

View File

@ -15,7 +15,7 @@ export default async function TeamDetailPage({ params }: { params: { teamId: str
const [users, links] = await Promise.all([
getTeamUsers({ user, team }),
getTeamInviteLinks({ user, team })
getTeamInviteLinks({ user, team }).then(d => structuredClone(d))
]);
if (!team.visible)

View File

@ -9,7 +9,7 @@ export const dynamic = 'force-dynamic';
export default async function UserProfilePage({ params }: { params: { userId: string; }; }) {
const viewingUser = await getUser();
const user = await withUsersVisibleTo(viewingUser)
const user = structuredClone(await withUsersVisibleTo(viewingUser)
.selectFrom('aime_user as u')
.innerJoin('actaeon_user_ext as ext', 'ext.userId', 'u.id')
.where('ext.uuid', '=', params.userId)
@ -22,7 +22,7 @@ export default async function UserProfilePage({ params }: { params: { userId: st
'last_login_date',
userIsVisible('u.id').as('visible')
])
.executeTakeFirst();
.executeTakeFirst());
if (!user)
return notFound();
@ -32,18 +32,18 @@ export default async function UserProfilePage({ params }: { params: { userId: st
.where('user1', '=', user.id)
.where('user2', '=', viewingUser?.id!)
.select('chuniRival')
.executeTakeFirst(),
.executeTakeFirst().then(d => structuredClone(d)),
db.selectFrom('actaeon_friend_requests')
.where('user', '=', user.id)
.where('friend', '=', viewingUser?.id!)
.select('user')
.executeTakeFirst()
.executeTakeFirst().then(d => structuredClone(d))
]);
if (!user.visible)
return (<UserProfile friend={friend} pendingFriend={!!pendingFriend} user={user as UserProfile<false>}/>);
const chuniProfile = await getChuniUserData(user);
const chuniProfile = structuredClone(await getChuniUserData(user));
return (<UserProfile friend={friend} pendingFriend={!!pendingFriend} user={user as UserProfile<true>} chuniProfile={chuniProfile} />);
}

View File

@ -3,7 +3,7 @@ import CredentialsProvider from 'next-auth/providers/credentials';
import { db, GeneratedDB } from '@/db';
import { DBUserPayload } from '@/types/user';
import { cache } from 'react';
import { SelectQueryBuilder, sql } from 'kysely';
import { SelectQueryBuilder } from 'kysely';
import { AimeUser } from '@/types/db';
import crypto from 'crypto';
import { createActaeonTeamsFromExistingTeams } from './data/team';
@ -40,7 +40,7 @@ else if (['1', 'true', 'yes'].includes(process.env.COOKIE_SECURE?.toLowerCase()!
const nextAuth = NextAuth({
pages: {
signIn: `${basePath}/auth/login`
signIn: `${basePath}/auth/login/`
},
...config,
basePath: `${basePath}/api/auth/`,

View File

@ -11,7 +11,8 @@ export const PrivateVisibilityError = () => {
<LockClosedIcon className="w-48 mb-10" />
<header className="text-2xl font-semibold">This page is private.</header>
{!user ? <span>You may be able to access it by&nbsp;
<span className="underline hover:text-secondary transition cursor-pointer" onClick={() => login()}>logging in.</span>
<span className="underline hover:text-secondary transition cursor-pointer" onClick={() => login()
.then(r => setTimeout(() => location.href = r.redirect!, 10))}>logging in.</span>
</span> : <span>You do not have permission to view this page.</span>}
</main>);
}

View File

@ -81,8 +81,5 @@ export async function register() {
createActaeonTeamsFromExistingTeams().catch(console.error),
createActaeonFriendsFromExistingFriends().catch(console.error)
]);
} else if (process.env.NEXT_RUNTIME === 'edge') {
(globalThis as any).bcrypt = {};
(globalThis as any).mysql2 = {};
}
}