大修改

This commit is contained in:
Yeomai committed 2026-09-30 03:38:10 +08:00
1 parent a1cbc9404a
commit e81481623c
47 files changed
+1453 -285

No files matched your search

+213 -28
View File
@@ -1,11 +1,15 @@
'use client';
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import Link from 'next/link';
import { usePathname, useRouter } from 'next/navigation';
import { api } from '@/lib/api';
import { clearToken, isLoggedIn } from '@/lib/auth';
import { ENV_LABEL, getViewEnv, setViewEnv, type DataSourceEnv } from '@/lib/env';
import { RESOURCE_CONFIGS } from '@/lib/resources';
type DataSource = DataSourceEnv;
const FIXED_NAV = [
{ href: '/', label: '数据看板' },
{ href: '/users', label: '用户' },
@@ -13,10 +17,41 @@ const FIXED_NAV = [
{ href: '/settings', label: '系统配置' },
];
/**
* 底部「数据源」区域预留的高度(px)。
*
* 这个区块用 position:fixed 钉在视口左下角,脱离文档流,
* 所以要在这里留出等高的空白,免得它盖住最后几个菜单项。
* 数值按内容量给足余量,字体缩放时也不至于被遮住。
*/
const FOOTER_RESERVE_PX = 290;
export default function AdminLayout({ children }: { children: React.ReactNode }) {
const router = useRouter();
const pathname = usePathname();
const [ready, setReady] = useState(false);
/** 管理端「查看哪个库」——只影响自己 */
const [viewEnv, setView] = useState<DataSource>('production');
/** 线上小程序实际读的库 */
const [miniEnv, setMiniEnv] = useState<DataSource>('production');
const [developAvailable, setDevelopAvailable] = useState(false);
const [confirmOpen, setConfirmOpen] = useState(false);
const [switching, setSwitching] = useState(false);
const [error, setError] = useState('');
const loadState = useCallback(() => {
setView(getViewEnv());
api
.stats()
.then((s) => {
setMiniEnv(s.miniProgramEnv === 'develop' ? 'develop' : 'production');
setDevelopAvailable(s.developAvailable);
})
.catch(() => {
/* 取不到时按生产库显示,不阻塞页面 */
});
}, []);
useEffect(() => {
if (!isLoggedIn()) {
@@ -24,44 +59,194 @@ export default function AdminLayout({ children }: { children: React.ReactNode })
return;
}
setReady(true);
}, [router]);
loadState();
}, [router, loadState]);
/** 只切自己的查看视角,不动线上数据来源。 */
const changeViewEnv = (next: DataSource) => {
if (next === viewEnv) return;
setViewEnv(next);
setView(next);
window.location.reload();
};
/** 真正切换线上小程序的数据源,必须二次确认。 */
const applyMiniProgramEnv = () => {
const next: DataSource = miniEnv === 'production' ? 'develop' : 'production';
setSwitching(true);
setError('');
api
.switchMiniProgramDataSource(next)
.then(() => {
setMiniEnv(next);
setConfirmOpen(false);
window.location.reload();
})
.catch((err: { message: string }) => {
setError(err.message || '切换失败');
setSwitching(false);
});
};
if (!ready) {
return <div className="flex min-h-screen items-center justify-center text-sm text-gray-400">加载中…</div>;
}
const nextMiniEnv: DataSource = miniEnv === 'production' ? 'develop' : 'production';
return (
<div className="flex min-h-screen">
<aside className="w-56 shrink-0 border-r border-gray-200 bg-white">
<div className="border-b border-gray-200 px-4 py-4">
<div className="text-sm font-semibold text-gray-900">叶雷讲数学</div>
<div className="text-xs text-gray-400">管理后台</div>
</div>
<nav className="p-2">
{FIXED_NAV.map((item) => (
<NavItem key={item.href} href={item.href} label={item.label} active={pathname === item.href} />
))}
<div className="min-h-screen">
{/*
侧边栏:固定定位、高度恒等于视口。导航区自己滚动。
注意它只承载「导航」,底部数据源区不在它里面——见下面那个独立 fixed 区块。
*/}
<aside className="fixed left-0 top-0 z-30 h-screen w-60 border-r border-gray-200 bg-white">
<div className="flex h-full flex-col">
<div className="shrink-0 border-b border-gray-200 px-4 py-4">
<div className="text-sm font-semibold text-gray-900">叶雷讲数学</div>
<div className="text-xs text-gray-400">管理后台</div>
</div>
<div className="px-3 pt-4 pb-1 text-xs text-gray-400">内容管理</div>
{RESOURCE_CONFIGS.map((r) => (
<NavItem key={r.key} href={`/${r.key}`} label={r.title} active={pathname === `/${r.key}`} />
))}
</nav>
<nav className="min-h-0 flex-1 overflow-y-auto p-2">
{FIXED_NAV.map((item) => (
<NavItem key={item.href} href={item.href} label={item.label} active={pathname === item.href} />
))}
<div className="px-3 pt-4 pb-1 text-xs text-gray-400">内容管理</div>
{RESOURCE_CONFIGS.map((r) => (
<NavItem key={r.key} href={`/${r.key}`} label={r.title} active={pathname === `/${r.key}`} />
))}
</nav>
<div className="border-t border-gray-200 p-2">
<button
onClick={() => {
clearToken();
router.replace('/login');
}}
className="w-full rounded-md px-3 py-2 text-left text-sm text-gray-600 hover:bg-gray-100"
>
退出登录
</button>
{/* 给下面那个 fixed 区块让位,避免遮住最后几个菜单 */}
<div className="shrink-0" style={{ height: FOOTER_RESERVE_PX }} aria-hidden="true" />
</div>
</aside>
<main className="flex-1 p-6">{children}</main>
{/*
数据源区:独立的 fixed 元素,钉在视口左下角。
它不在侧边栏里,也不参与任何 flex 布局,因此页面长短、导航多少、窗口高低都影响不到它。
*/}
<div className="fixed bottom-0 left-0 z-40 w-60 border-t border-gray-200 bg-white p-2">
<div className="px-3 pb-1 text-xs text-gray-400">查看的数据源</div>
<div className="flex gap-1 px-2">
{(['production', 'develop'] as DataSource[]).map((key) => {
const disabled = key === 'develop' && !developAvailable;
return (
<button
key={key}
onClick={() => changeViewEnv(key)}
disabled={disabled}
title={disabled ? '服务端未配置开发库' : '只影响你自己的查看与编辑'}
className={`flex-1 rounded-md border px-2 py-1.5 text-xs transition ${
viewEnv === key
? key === 'develop'
? 'border-orange-400 bg-orange-50 font-medium text-orange-700'
: 'border-blue-400 bg-blue-50 font-medium text-blue-700'
: 'border-gray-200 text-gray-500 hover:bg-gray-50'
} ${disabled ? 'cursor-not-allowed opacity-40' : ''}`}
>
{ENV_LABEL[key]}
</button>
);
})}
</div>
<p className="px-3 pt-1 pb-2 text-[11px] leading-tight text-gray-400">
只影响你自己的查看与编辑,不影响小程序
</p>
<div className="border-t border-gray-100 px-3 pt-3 pb-1 text-xs text-gray-400">
线上小程序数据源
</div>
<div className="px-2 pb-2">
<div className="mb-1.5 flex items-center gap-1.5 px-1 text-sm">
<span
className={`inline-block h-2 w-2 rounded-full ${
miniEnv === 'develop' ? 'bg-orange-500' : 'bg-green-500'
}`}
/>
<span className={miniEnv === 'develop' ? 'font-medium text-orange-700' : 'text-gray-700'}>
{ENV_LABEL[miniEnv]}
</span>
</div>
<button
onClick={() => setConfirmOpen(true)}
disabled={!developAvailable || switching}
title={developAvailable ? undefined : '服务端未配置开发库'}
className="w-full rounded-md border border-gray-300 bg-white px-2 py-1.5 text-xs text-gray-700 transition hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
>
切换到{ENV_LABEL[nextMiniEnv]}
</button>
</div>
<button
onClick={() => {
clearToken();
router.replace('/login');
}}
className="w-full rounded-md px-3 py-2 text-left text-sm text-gray-600 hover:bg-gray-100"
>
退出登录
</button>
</div>
<main className="ml-60">
{miniEnv === 'develop' && (
<div className="border-b border-orange-300 bg-orange-100 px-6 py-2 text-sm font-medium text-orange-800">
⚠ 线上小程序当前读的是<span className="font-bold">开发库</span>
——所有用户打开小程序看到的都是开发库数据,测完请及时切回生产库。
</div>
)}
{miniEnv !== 'develop' && viewEnv === 'develop' && (
<div className="border-b border-blue-200 bg-blue-50 px-6 py-2 text-sm text-blue-800">
你正在查看<span className="font-bold">开发库</span>的数据(仅影响你自己,小程序仍在读生产库)
</div>
)}
<div className="p-6">{children}</div>
</main>
{confirmOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
<div className="w-full max-w-md rounded-lg bg-white p-5 shadow-xl">
<h3 className="mb-3 text-base font-semibold text-gray-900">确认切换线上小程序数据源?</h3>
<div className="space-y-2 text-sm text-gray-600">
<p>
即将把线上小程序从
<span className="mx-1 font-medium">{ENV_LABEL[miniEnv]}</span>
切换到
<span className="mx-1 font-medium text-orange-700">{ENV_LABEL[nextMiniEnv]}</span>。
</p>
{nextMiniEnv === 'develop' ? (
<p className="rounded-md bg-orange-50 px-3 py-2 text-orange-800">
切换后,<span className="font-medium">所有用户</span>在微信里打开小程序看到的都是开发库数据
(旧开发库:132 个用户、3 门课程,首页两个栏目为空)。
他们会以为课程丢失,请务必在测试结束后切回生产库。
</p>
) : (
<p className="rounded-md bg-green-50 px-3 py-2 text-green-800">
将恢复为生产库,用户看到的即真实数据。
</p>
)}
{error && <p className="rounded-md bg-red-50 px-3 py-2 text-red-700">{error}</p>}
</div>
<div className="mt-5 flex justify-end gap-2">
<button
onClick={() => setConfirmOpen(false)}
disabled={switching}
className="rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-50"
>
取消
</button>
<button
onClick={applyMiniProgramEnv}
disabled={switching}
className="rounded-md bg-orange-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-orange-700 disabled:opacity-50"
>
{switching ? '切换中…' : '确认切换'}
</button>
</div>
</div>
</div>
)}
</div>
);
}
+24 -1
View File
@@ -1,8 +1,16 @@
'use client';
import { clearToken, getToken } from './auth';
import { getViewEnv } from './env';
const BASE = (process.env.NEXT_PUBLIC_API_BASE_URL ?? 'http://127.0.0.1:3000').replace(/\/+$/, '');
/**
* 服务端地址。`NEXT_PUBLIC_*` 是**构建时写死**的,所以这个兜底值必须指向真实部署地址——
* 之前兜底写了 127.0.0.1:3000,改成「本机构建、上传产物」之后,
* 构建时读不到环境变量就落到这个兜底值,结果线上后台在拿访问者的电脑当服务器,全部请求失败。
*
* 需要指向别的环境时,构建前设置 NEXT_PUBLIC_API_BASE_URL 覆盖即可。
*/
const BASE = (process.env.NEXT_PUBLIC_API_BASE_URL || 'https://yelaymaths-api.yeomai.site').replace(/\/+$/, '');
export interface ApiFailure {
code: number;
@@ -20,6 +28,8 @@ async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
const token = getToken();
const headers: Record<string, string> = {
'content-type': 'application/json',
// 管理端「查看哪个库」,只影响自己看到的和编辑的数据
'x-yelay-env': getViewEnv(),
...((init.headers as Record<string, string>) ?? {}),
};
if (token) headers.Authorization = `Bearer ${token}`;
@@ -94,8 +104,21 @@ export const api = {
payEnabled: boolean;
/** 0 现网 / 1 沙箱 */
payEnv: number;
/** 当前数据源 */
dataEnv: string;
/** 服务端是否配置了开发库 */
developAvailable: boolean;
/** 线上小程序当前读的库 */
miniProgramEnv: string;
}>('/admin/v1/stats'),
/** 切换**线上小程序**的数据源。影响所有用户,前端必须二次确认。 */
switchMiniProgramDataSource: (env: 'production' | 'develop') =>
request<{ miniProgramEnv: string }>('/admin/v1/data-source', {
method: 'PUT',
body: JSON.stringify({ env }),
}),
listUsers: (page: number, pageSize: number, keyword: string) =>
request<Paged<Record<string, unknown>>>(`/admin/v1/users${qs({ page, pageSize, keyword })}`),
+26
View File
@@ -0,0 +1,26 @@
'use client';
export type DataSourceEnv = 'production' | 'develop';
const VIEW_ENV_KEY = 'yelay_admin_view_env';
/**
* 管理端「查看哪个库」。
*
* 只存在浏览器本地,只影响你自己的查看与编辑视角,
* 不会改变线上小程序的数据来源——那是另一个开关的事。
*/
export function getViewEnv(): DataSourceEnv {
if (typeof window === 'undefined') return 'production';
return window.localStorage.getItem(VIEW_ENV_KEY) === 'develop' ? 'develop' : 'production';
}
export function setViewEnv(env: DataSourceEnv): void {
window.localStorage.setItem(VIEW_ENV_KEY, env);
}
export const ENV_LABEL: Record<DataSourceEnv, string> = {
production: '生产库',
develop: '开发库',
};
+1 -1
View File
@@ -1 +1 @@
{"fileNames":["./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.object.d.ts",".Line truncated
{"fileNames":["./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.object.d.ts",".Line truncated