Support audio files in gallery and viewer, include Musik .txt in ZIP, exclude .txt from website

This commit is contained in:
Jannik committed 2026-10-03 12:36:01 +02:00
1 parent 77e8876a07
commit 25e5f3d0a6
12 files changed
+230 -25

No files matched your search

+3 -3
View File
@@ -59,8 +59,8 @@ export async function generateMetadata({
where: { relativePath: mediaPath },
});
// Don't leak metadata for unpublished items
if (!item?.published) {
// Don't leak metadata for unpublished items or text files
if (!item?.published || item.filename.toLowerCase().endsWith('.txt') || item.mediaType === 'OTHER') {
return { title: 'Nele & Till - Hochzeit' };
}
@@ -93,7 +93,7 @@ export default async function MediaDirectRoute({
where: { relativePath: mediaPath },
});
if (!item) {
if (!item || item.filename.toLowerCase().endsWith('.txt') || item.mediaType === 'OTHER') {
notFound();
}
+4 -1
View File
@@ -47,7 +47,10 @@ export default function AdminLayoutEditor() {
const res = await fetch('/api/media?admin=true&limit=1000');
if (res.ok) {
const data = await res.json();
setItems(data.items);
const sortedItems = (data.items || []).slice().sort((a: MediaItem, b: MediaItem) =>
a.relativePath.localeCompare(b.relativePath, undefined, { numeric: true, sensitivity: 'base' })
);
setItems(sortedItems);
}
} catch (err) {
console.error('Error fetching admin data:', err);
+33 -6
View File
@@ -54,11 +54,12 @@ export default function AdminDashboard() {
const res = await fetch('/api/media?admin=true&limit=5000');
if (res.ok) {
const data = await res.json();
setItems(data.items);
const mediaOnly = data.items.filter((i: MediaItem) => !i.filename.toLowerCase().endsWith('.txt') && i.mediaType !== 'OTHER');
setItems(mediaOnly);
setStats({
total: data.items.length,
published: data.items.filter((i: MediaItem) => i.published).length,
unpublished: data.items.filter((i: MediaItem) => !i.published).length,
total: mediaOnly.length,
published: mediaOnly.filter((i: MediaItem) => i.published).length,
unpublished: mediaOnly.filter((i: MediaItem) => !i.published).length,
});
}
} catch (err) {
@@ -186,7 +187,22 @@ export default function AdminDashboard() {
if (!authChecked) return <div style={{ padding: '20px' }}>Prüfe Berechtigung...</div>;
const displayedItems = selectedFolder ? items.filter(i => i.directory === selectedFolder) : items;
const displayedItems = (selectedFolder ? items.filter(i => i.directory === selectedFolder) : items)
.slice()
.sort((a, b) => {
if (!selectedFolder && a.directory !== b.directory) {
const indexA = orderedFolders.indexOf(a.directory);
const indexB = orderedFolders.indexOf(b.directory);
if (indexA !== -1 && indexB !== -1) return indexA - indexB;
if (indexA !== -1) return -1;
if (indexB !== -1) return 1;
const dirCompare = (a.directory || '').localeCompare(b.directory || '', undefined, { numeric: true, sensitivity: 'base' });
if (dirCompare !== 0) return dirCompare;
}
const fileCompare = a.filename.localeCompare(b.filename, undefined, { numeric: true, sensitivity: 'base' });
if (fileCompare !== 0) return fileCompare;
return a.relativePath.localeCompare(b.relativePath, undefined, { numeric: true, sensitivity: 'base' });
});
return (
<div className="admin-content" style={{ padding: '20px', maxWidth: '1200px', margin: '0 auto' }}>
@@ -318,13 +334,24 @@ export default function AdminDashboard() {
}}
>
<div style={{ position: 'relative', aspectRatio: '1/1', background: '#eee' }}>
{/* eslint-disable-next-line @next/next/no-img-element */}
{item.mediaType === 'AUDIO' ? (
<div style={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', background: '#f8f4ee', color: 'var(--color-primary)' }}>
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 18V5l12-2v13"></path>
<circle cx="6" cy="18" r="3"></circle>
<circle cx="18" cy="16" r="3"></circle>
</svg>
<span style={{ fontSize: '0.75rem', marginTop: '6px', fontWeight: 600 }}>Audio (MP3)</span>
</div>
) : (
/* eslint-disable-next-line @next/next/no-img-element */
<img
src={`/api/media/${item.relativePath}?type=thumb`}
alt={item.filename}
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
loading="lazy"
/>
)}
{item.mediaType === 'VIDEO' && (
<div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.3)' }}>
<svg width="24" height="24" viewBox="0 0 24 24" fill="white" stroke="none"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
+11 -4
View File
@@ -9,12 +9,19 @@ export async function GET(request: NextRequest) {
try {
const items = await prisma.mediaItem.findMany({
orderBy: [
{ featured: 'desc' },
{ placementMode: 'asc' },
{ sortOrder: 'asc' },
{ createdAt: 'desc' }
{ directory: 'asc' },
{ filename: 'asc' },
{ id: 'asc' }
]
});
items.sort((a, b) => {
if (a.directory !== b.directory) {
return (a.directory || '').localeCompare(b.directory || '', undefined, { numeric: true, sensitivity: 'base' });
}
const fileCompare = a.filename.localeCompare(b.filename, undefined, { numeric: true, sensitivity: 'base' });
if (fileCompare !== 0) return fileCompare;
return a.relativePath.localeCompare(b.relativePath, undefined, { numeric: true, sensitivity: 'base' });
});
return NextResponse.json({ items });
} catch (error) {
console.error('Error fetching layout items:', error);
+14 -3
View File
@@ -26,6 +26,8 @@ export async function GET(request: NextRequest) {
const where: Record<string, unknown> = {};
if (!isAdminRequest) {
where.published = true;
where.mediaType = { not: 'OTHER' };
where.NOT = { filename: { endsWith: '.txt' } };
}
if (directoryParam) {
const dirs = directoryParam.split(',');
@@ -52,9 +54,9 @@ export async function GET(request: NextRequest) {
take: limit + 1,
...(cursor ? { skip: 1, cursor: { id: cursor } } : {}),
orderBy: [
{ featured: 'desc' },
{ sortOrder: 'asc' },
{ createdAt: 'desc' },
{ directory: 'asc' },
{ filename: 'asc' },
{ id: 'asc' },
],
include: { _count: { select: { likes: true } } },
});
@@ -63,6 +65,15 @@ export async function GET(request: NextRequest) {
const nextItem = items.pop();
nextCursor = nextItem!.id;
}
items.sort((a, b) => {
if (a.directory !== b.directory) {
return (a.directory || '').localeCompare(b.directory || '', undefined, { numeric: true, sensitivity: 'base' });
}
const fileCompare = a.filename.localeCompare(b.filename, undefined, { numeric: true, sensitivity: 'base' });
if (fileCompare !== 0) return fileCompare;
return a.relativePath.localeCompare(b.relativePath, undefined, { numeric: true, sensitivity: 'base' });
});
} else {
// Custom pagination with randomized chunk sorting
let seed = Math.floor(Math.random() * 1000000);
+10 -2
View File
@@ -9,7 +9,11 @@ async function getInitialMedia() {
try {
// 1. Fetch metadata for all published items to sort them properly
const allMetadata = await prisma.mediaItem.findMany({
where: { published: true },
where: {
published: true,
mediaType: { not: 'OTHER' },
NOT: { filename: { endsWith: '.txt' } },
},
select: {
id: true,
featured: true,
@@ -48,7 +52,11 @@ async function getInitialMedia() {
// Fetch available directories for filtering
const dirs = await prisma.mediaItem.findMany({
where: { published: true },
where: {
published: true,
mediaType: { not: 'OTHER' },
NOT: { filename: { endsWith: '.txt' } },
},
select: { directory: true },
distinct: ['directory'],
orderBy: { directory: 'asc' }
+53
View File
@@ -30,6 +30,7 @@ export default function FullscreenViewer({
votingOpen,
}: ViewerProps) {
const isVideo = item.mediaType === 'VIDEO';
const isAudio = item.mediaType === 'AUDIO';
const touchStartX = useRef<number | null>(null);
// Update URL to reflect current media
@@ -118,6 +119,58 @@ export default function FullscreenViewer({
playsInline
onClick={(e) => e.stopPropagation()}
/>
) : isAudio ? (
<div
className="viewer-content"
onClick={(e) => e.stopPropagation()}
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
background: 'rgba(30, 36, 28, 0.95)',
border: '1px solid rgba(124, 154, 110, 0.4)',
borderRadius: '16px',
padding: '40px 30px',
maxWidth: '460px',
width: '90%',
boxShadow: '0 20px 50px rgba(0,0,0,0.6)',
color: '#fff',
textAlign: 'center',
}}
>
<div
style={{
width: '100px',
height: '100px',
borderRadius: '50%',
background: 'linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-dark) 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginBottom: '20px',
boxShadow: '0 8px 24px rgba(0,0,0,0.3)',
}}
>
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 18V5l12-2v13"></path>
<circle cx="6" cy="18" r="3"></circle>
<circle cx="18" cy="16" r="3"></circle>
</svg>
</div>
<h2 style={{ fontFamily: 'var(--font-display)', fontSize: '1.5rem', marginBottom: '8px', color: '#fff' }}>
{item.filename.replace(/\.[^/.]+$/, '')}
</h2>
<p style={{ color: 'rgba(255,255,255,0.7)', fontSize: '0.9rem', marginBottom: '24px' }}>
Nele & Till • Hochzeit
</p>
<audio
src={`/api/media/${item.relativePath}`}
controls
autoPlay
style={{ width: '100%', outline: 'none', borderRadius: '8px' }}
/>
</div>
) : (
// eslint-disable-next-line @next/next/no-img-element
<img
+62 -2
View File
@@ -59,7 +59,9 @@ export default function MediaTile({ item, index, onClick, votingOpen }: MediaTil
};
const isVideo = item.mediaType === 'VIDEO';
const isAudio = item.mediaType === 'AUDIO';
const likesCount = item._count?.likes ?? 0;
const songTitle = item.filename.replace(/\.[^/.]+$/, '');
return (
<div
@@ -77,7 +79,64 @@ export default function MediaTile({ item, index, onClick, votingOpen }: MediaTil
<div style={{ display: 'block', paddingTop: `${(1 / displayRatio) * 100}%` }} />
{isVisible && (
<>
{/* eslint-disable-next-line @next/next/no-img-element */}
{isAudio ? (
<div
style={{
position: 'absolute',
inset: 0,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
background: 'linear-gradient(135deg, #4A5D40 0%, #2F3E28 100%)',
color: '#fff',
padding: '16px',
textAlign: 'center',
}}
ref={(el) => {
if (el) el.parentElement?.classList.remove('loading-skeleton');
}}
>
<div style={{
width: '56px',
height: '56px',
borderRadius: '50%',
background: 'rgba(255, 255, 255, 0.15)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginBottom: '10px',
backdropFilter: 'blur(4px)',
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
}}>
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 18V5l12-2v13"></path>
<circle cx="6" cy="18" r="3"></circle>
<circle cx="18" cy="16" r="3"></circle>
</svg>
</div>
<div style={{
fontFamily: 'var(--font-display)',
fontSize: '1.1rem',
fontWeight: 600,
letterSpacing: '0.02em',
marginBottom: '4px',
lineHeight: 1.2,
textShadow: '0 2px 4px rgba(0,0,0,0.3)',
}}>
{songTitle}
</div>
<span style={{
fontSize: '0.75rem',
textTransform: 'uppercase',
letterSpacing: '0.1em',
opacity: 0.8,
}}>
Hochzeitslied
</span>
</div>
) : (
/* eslint-disable-next-line @next/next/no-img-element */
<img
src={isVideo ? `/api/media/${item.relativePath}?type=poster` : `/api/media/${item.relativePath}?type=thumb`}
alt={item.filename}
@@ -87,7 +146,8 @@ export default function MediaTile({ item, index, onClick, votingOpen }: MediaTil
target.parentElement?.classList.remove('loading-skeleton');
}}
/>
{isVideo && (
)}
{(isVideo || isAudio) && (
<div className="play-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="none">
<polygon points="5 3 19 12 5 21 5 3"></polygon>
+1
View File
@@ -69,6 +69,7 @@ const EXCLUDED_SUFFIXES = [
'.partial',
'.crdownload',
'.part',
'.txt',
];
const EXCLUDED_DIRECTORIES = new Set([
+34
View File
@@ -61,19 +61,53 @@ export async function buildZip(): Promise<boolean> {
// 5. Add each published file
let addedCount = 0;
const addedPaths = new Set<string>();
for (const item of publishedItems) {
if (item.relativePath.toLowerCase().endsWith('.txt')) {
continue;
}
const absolutePath = path.join(MEDIA_ROOT, item.relativePath);
// Verify file still exists
try {
await fs.promises.access(absolutePath, fs.constants.R_OK);
archive.file(absolutePath, { name: item.relativePath });
addedPaths.add(item.relativePath);
addedCount++;
} catch {
console.warn(`[ZIP] File missing, skipping: ${item.relativePath}`);
}
}
// Always include .txt files from the Musik directory (e.g. song lyrics)
try {
if (fs.existsSync(MEDIA_ROOT)) {
const rootEntries = await fs.promises.readdir(MEDIA_ROOT, { withFileTypes: true });
const musicDirs = rootEntries.filter(
(e) => e.isDirectory() && e.name.toLowerCase() === 'musik'
);
for (const mDir of musicDirs) {
const musicDirPath = path.join(MEDIA_ROOT, mDir.name);
const musicFiles = await fs.promises.readdir(musicDirPath, { withFileTypes: true });
for (const file of musicFiles) {
if (file.isFile() && file.name.toLowerCase().endsWith('.txt')) {
const relPath = path.posix.join(mDir.name, file.name);
const absPath = path.join(musicDirPath, file.name);
if (!addedPaths.has(relPath)) {
archive.file(absPath, { name: relPath });
addedPaths.add(relPath);
addedCount++;
console.log(`[ZIP] Included text file in zip: ${relPath}`);
}
}
}
}
}
} catch (err) {
console.warn('[ZIP] Error reading Musik directory for .txt files:', err);
}
// 6. Finalize archive
await archive.finalize();
+4 -3
View File
@@ -1,4 +1,4 @@
/**
/**
* Filesystem scanner — recursively scans media directory,
* detects new/changed/removed files, and syncs with the database.
*/
@@ -61,8 +61,9 @@ export async function runFullScan(): Promise<{
} else {
unchanged++;
dbPaths.delete(relPath);
if (existing.thumbnailReady === false) {
enqueueProcessing(relPath, getMediaType(file.ext)).catch(console.error);
const mediaType = getMediaType(file.ext);
if (existing.thumbnailReady === false && (mediaType === 'IMAGE' || mediaType === 'VIDEO')) {
enqueueProcessing(relPath, mediaType).catch(console.error);
console.log('Re-queued missing thumbnail:', relPath);
}
}
+1 -1
View File
@@ -1 +1 @@
{"program":{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.string.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.object.d.ts","./node_modules/typescript/lib/lib.esnext.regexp.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/prop-types/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/shared/lib/amp.d.ts","./node_modules/next/amp.d.ts","./node_modules/@types/node/ts5.6/globals.typedarray.d.ts","./node_modules/@types/node/ts5.6/buffer.buffer.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/buffer/index.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/uLine truncated
{"program":{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.string.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.object.d.ts","./node_modules/typescript/lib/lib.esnext.regexp.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/prop-types/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/shared/lib/amp.d.ts","./node_modules/next/amp.d.ts","./node_modules/@types/node/ts5.6/globals.typedarray.d.ts","./node_modules/@types/node/ts5.6/buffer.buffer.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/buffer/index.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/uLine truncated