updaded typescript to 7 and fixed few bugs
This commit is contained in:
@@ -40,3 +40,6 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# ai agent settings
|
||||
.claude
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package-lock.json
|
||||
@@ -9,7 +9,8 @@ backend service, polls until parsing finishes, and displays the result in a
|
||||
grid.
|
||||
|
||||
- **Next.js 16** (App Router, Turbopack) with **React 19**
|
||||
- **TypeScript 6**, **ESLint 9** (flat config), **Prettier 3**
|
||||
- **TypeScript 6 and 7** side by side (see "Things that will bite you"),
|
||||
**ESLint 9** (flat config), **Prettier 3**
|
||||
- **ag-grid** for the data grid, **Bootstrap 5** for styling
|
||||
|
||||
Source files live in `src/`:
|
||||
@@ -21,6 +22,50 @@ Source files live in `src/`:
|
||||
- `config/` for app config
|
||||
- `types/` for .d.ts type declaration files
|
||||
|
||||
## Architecture
|
||||
|
||||
The parsing backend is a **separate service in its own repository**, not part
|
||||
of this project. Start it manually before running the frontend; it is expected
|
||||
at `http://127.0.0.1:5226`.
|
||||
|
||||
The browser never calls that backend directly. Requests go through a Next route
|
||||
handler that forwards them:
|
||||
|
||||
```
|
||||
SaveParserBackendService -> /api/proxy/saveParserBackend/* -> backend
|
||||
(client, fetch) (server, route handler)
|
||||
```
|
||||
|
||||
- [src/services/SaveParserBackendService.ts](src/services/SaveParserBackendService.ts)
|
||||
is the only place that talks to the backend. It exposes `uploadSave`,
|
||||
`getSaveStatus` and `getParsedSave` — upload, poll until parsing finishes,
|
||||
then fetch the result.
|
||||
- [src/app/api/proxy/saveParserBackend/[[...path]]/route.ts](src/app/api/proxy/saveParserBackend/[[...path]]/route.ts)
|
||||
forwards every method to the configured backend URL. It exists only to keep
|
||||
requests same-origin, and is meant to be deleted once the backend handles
|
||||
CORS itself.
|
||||
- Route paths live in [src/app/api/proxy/paths.ts](src/app/api/proxy/paths.ts)
|
||||
rather than as string literals, so both sides of the proxy stay in sync.
|
||||
|
||||
Configuration comes from [src/config/AppConfig.ts](src/config/AppConfig.ts)
|
||||
(defaults) merged with `runtimeConfig.json` at the repo root, which holds the
|
||||
backend URL. That file is gitignored, so a fresh clone starts without one and
|
||||
falls back to the defaults.
|
||||
|
||||
### Current status
|
||||
|
||||
Much of the app is still scaffold. Do not assume a feature works because the UI
|
||||
for it exists:
|
||||
|
||||
- **The grid is not wired up.** [src/app/browse/page.tsx](src/app/browse/page.tsx)
|
||||
renders two hardcoded rows and never calls the backend. Nothing connects the
|
||||
upload flow to it yet.
|
||||
- **Auth does not work.** `AuthService` posts to `/api/auth/login` and
|
||||
`/api/auth/register`, which do not exist as routes. The service is slated for
|
||||
removal in favour of Discord OAuth.
|
||||
- **`hashPassword` is a no-op** that returns the password unchanged. Treat any
|
||||
current auth code as a placeholder, not as something to build on.
|
||||
|
||||
## Terminal
|
||||
|
||||
**On Windows, prefer `bash.exe`** — but only a real MSYS2, Cygwin, or
|
||||
@@ -43,7 +88,7 @@ problem rather than a missing install: MSYS2 defaults `MSYS2_PATH_TYPE` to
|
||||
npm run dev # dev server
|
||||
npm run build # production build
|
||||
npm run lint # eslint
|
||||
npm run format # prettier, rewrites files in src/
|
||||
npm run format # prettier, rewrites everything except .gitignore/.prettierignore
|
||||
npx tsc --noEmit # typecheck
|
||||
```
|
||||
|
||||
@@ -108,9 +153,58 @@ Avoid `any`; `no-explicit-any` is enforced. Prefer `unknown` plus narrowing.
|
||||
|
||||
## Things that will bite you
|
||||
|
||||
**TypeScript is pinned to 6 on purpose.** Do not upgrade it to 7. The Next.js
|
||||
ESLint config depends on typescript-eslint, which refuses to run under
|
||||
TypeScript 7, and that would break `npm run lint` entirely.
|
||||
**Both TypeScript 6 and 7 are installed on purpose, under swapped names.**
|
||||
TypeScript 7 is the native Go compiler and type-checks much faster, but
|
||||
typescript-eslint refuses to run under it, which would break `npm run lint`
|
||||
entirely. So each tool gets the version it can use:
|
||||
|
||||
| package.json entry | resolves to | used by |
|
||||
| -------------------- | ------------------------------------------------ | ----------------- |
|
||||
| `typescript` | `@typescript/typescript6` (TS 6 API, bin `tsc6`) | typescript-eslint |
|
||||
| `@typescript/native` | `typescript@7` (Go compiler) | `next build` |
|
||||
|
||||
The alias is deliberately reversed: typescript-eslint looks the compiler up by
|
||||
the package _name_ `typescript`, so that name must stay on TS 6. Do not "fix"
|
||||
this by renaming the entries.
|
||||
|
||||
`next.config.ts` sets `experimental.useTypeScriptCli`, which makes Next spawn a
|
||||
`tsc` binary instead of using the compiler API. Next resolves that binary from
|
||||
the package named `typescript` too, so it would also get TS 6. The `prebuild`
|
||||
script [scripts/replace-tsc6-with-tsc7.mjs](scripts/replace-tsc6-with-tsc7.mjs)
|
||||
works around this by rewriting `node_modules/typescript/bin/tsc6` into a
|
||||
one-line stub that imports TS 7's `lib/tsc.js`.
|
||||
|
||||
Consequences to keep in mind:
|
||||
|
||||
- The patch lives in `node_modules`, so `npm install` undoes it. `prebuild`
|
||||
reapplies it, so `npm run build` is always correct; nothing else needs doing.
|
||||
- `npx tsc --noEmit` is unaffected either way. `node_modules/.bin/tsc` links
|
||||
straight to `@typescript/native`, so the standalone typecheck is always TS 7.
|
||||
- Do not drop the `prebuild` script while leaving `useTypeScriptCli` enabled.
|
||||
Nothing breaks visibly — the build just silently goes back to type-checking
|
||||
with TS 6.
|
||||
|
||||
**All of this is temporary.** The only reason TS 6 is still here is that
|
||||
TypeScript 7.0 ships no stable programmatic JS API, so typescript-eslint cannot
|
||||
run on it. That API arrives in **TypeScript 7.1, planned for 2026-11-24**. Once
|
||||
it is out and typescript-eslint supports it, tear the whole arrangement down:
|
||||
drop `@typescript/native` and the `@typescript/typescript6` alias for a plain
|
||||
`"typescript": "^7.1"`, delete `scripts/replace-tsc6-with-tsc7.mjs` and the
|
||||
`prebuild` script, and re-check whether `useTypeScriptCli` is still worth
|
||||
keeping.
|
||||
|
||||
**Env vars in npm scripts must go through `cross-env`.** The `dev` and `build`
|
||||
scripts set `NEXT_TELEMETRY_DISABLED=1`, which stops Next from collecting
|
||||
anonymous usage data and saves the ~0.5s the telemetry flush adds to every
|
||||
build. The `FOO=1 cmd` prefix is POSIX shell syntax, and on Windows npm runs
|
||||
scripts through `cmd`, where it is a syntax error — so the prefix is written as
|
||||
`cross-env NEXT_TELEMETRY_DISABLED=1 next ...` instead. Keep `cross-env` on any
|
||||
new script that needs an env var.
|
||||
|
||||
Setting the variable from `prebuild` would not work: `prebuild` and `build` are
|
||||
sibling processes, so an env var exported by one is not visible to the other.
|
||||
Each script that needs it sets it itself. `prebuild` has no `cross-env` prefix
|
||||
because it only rewrites the tsc bin and never talks to telemetry.
|
||||
|
||||
**`instrumentation.ts` is compiled for the edge runtime too and it can't be disabled.**
|
||||
Anything using `fs`, `path`, or other Node APIs must be imported behind the
|
||||
|
||||
+6
-4
@@ -1,7 +1,9 @@
|
||||
import type { NextConfig } from "next";
|
||||
import type { NextConfig } from 'next'
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
experimental: {
|
||||
useTypeScriptCli: true,
|
||||
},
|
||||
}
|
||||
|
||||
export default nextConfig;
|
||||
export default nextConfig
|
||||
|
||||
Generated
+873
-469
File diff suppressed because it is too large
Load Diff
+8
-4
@@ -3,13 +3,15 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build",
|
||||
"dev": "cross-env NEXT_TELEMETRY_DISABLED=1 next dev --turbopack",
|
||||
"prebuild": "node scripts/replace-tsc6-with-tsc7.mjs",
|
||||
"build": "cross-env NEXT_TELEMETRY_DISABLED=1 next build",
|
||||
"start": "next start",
|
||||
"lint": "eslint",
|
||||
"format": "npx prettier src --write"
|
||||
"format": "npx prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"ag-grid-community": "^36",
|
||||
"ag-grid-react": "^36",
|
||||
"bootstrap": "^5",
|
||||
"next": "^16",
|
||||
@@ -20,10 +22,12 @@
|
||||
"@types/node": "^26",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@typescript/native": "npm:typescript@^7.0",
|
||||
"cross-env": "^10.1.0",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "^16",
|
||||
"prettier": "^3",
|
||||
"typescript": "^6"
|
||||
"typescript": "npm:@typescript/typescript6@^6.0"
|
||||
},
|
||||
"allowScripts": {
|
||||
"unrs-resolver": false
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
Replaces tsc6 script which is called by next.js to run tsc 7,
|
||||
which is a native executable written in go and works faster.
|
||||
The problem is typescript 7 is supported with nextjs,
|
||||
but is not supported by eslint which we use for static code analysis.
|
||||
This script solves the problem.
|
||||
*/
|
||||
|
||||
import { createRequire } from 'node:module'
|
||||
import { writeFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
const tsc6 = path.join(
|
||||
path.dirname(require.resolve('typescript/package.json')),
|
||||
'bin',
|
||||
'tsc6'
|
||||
)
|
||||
const nativeTsc = path.join(
|
||||
path.dirname(require.resolve('@typescript/native/package.json')),
|
||||
'lib',
|
||||
'tsc.js'
|
||||
)
|
||||
const specifier = path
|
||||
.relative(path.dirname(tsc6), nativeTsc)
|
||||
.split(path.sep)
|
||||
.join('/')
|
||||
|
||||
writeFileSync(tsc6, `#!/usr/bin/env node\nimport('${specifier}')\n`)
|
||||
|
||||
console.log(`patched ${tsc6} -> ${nativeTsc}`)
|
||||
@@ -4,6 +4,10 @@ import { redirectRequest, respondToOPTIONS } from '@/app/api/proxy/functions'
|
||||
import { PROXY_PATHS } from '@/app/api/proxy/paths'
|
||||
import { appConfig } from '@/lib/configLoader'
|
||||
|
||||
//TODO: remove this proxy once the backend handles CORS itself. It only exists
|
||||
// so the browser can make same-origin requests; with CORS on the backend the
|
||||
// client can call it directly and this extra hop disappears.
|
||||
|
||||
// Forwards the incoming request to the save parser backend.
|
||||
async function redirect(req: NextRequest): Promise<NextResponse> {
|
||||
return await redirectRequest(
|
||||
|
||||
@@ -14,6 +14,7 @@ const DARK_SCHEME_QUERY = '(prefers-color-scheme: dark)'
|
||||
const BASE_THEME = themeQuartz.withParams({
|
||||
columnBorder: true,
|
||||
headerColumnBorder: true,
|
||||
headerCellBackgroundTransitionDuration: 0,
|
||||
})
|
||||
// Built once, so the grid keeps seeing the same theme object between renders.
|
||||
const LIGHT_THEME = BASE_THEME
|
||||
@@ -53,6 +54,9 @@ export default function BrowseSaveDataPage() {
|
||||
<AgGridReact
|
||||
theme={agTheme}
|
||||
modules={[AllCommunityModule]}
|
||||
// ddisable all animations
|
||||
animateRows={false}
|
||||
suppressColumnMoveAnimation={true}
|
||||
rowData={[
|
||||
{ id: 1, col1: 'Hello', col2: 'AG Grid' },
|
||||
{ id: 2, col1: 'Dark Mode', col2: 'Support' },
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
font-family: var(--font-ibm-plex-sans), monospace;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
+2
-4
@@ -1,8 +1,8 @@
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
import './globals.css'
|
||||
import type { Metadata } from 'next'
|
||||
import { ModuleRegistry, AllCommunityModule } from 'ag-grid-community'
|
||||
import Navbar from '@/components/Navbar'
|
||||
import { font_IbmPlexSans } from '@/lib/myFonts'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Home',
|
||||
@@ -12,14 +12,12 @@ export const metadata: Metadata = {
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{ children: React.ReactNode }>) {
|
||||
// Register the ag-grid community features
|
||||
ModuleRegistry.registerModules([AllCommunityModule])
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>paradox-save-parser-frontend</title>
|
||||
</head>
|
||||
<body>
|
||||
<body className={font_IbmPlexSans.className}>
|
||||
<Navbar />
|
||||
{children}
|
||||
</body>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { font_Hack } from '@/lib/myFonts'
|
||||
|
||||
// Top navigation bar with a home link and login/register buttons.
|
||||
export default function Navbar() {
|
||||
return (
|
||||
<nav
|
||||
className={`navbar navbar-expand-lg navbar-dark bg-dark px-3 ${font_Hack.className}`}
|
||||
>
|
||||
<nav className={`navbar navbar-expand-lg navbar-dark bg-dark px-3`}>
|
||||
<div className="container-fluid">
|
||||
{/* Left: Home Link */}
|
||||
<Link href="/" className="navbar-brand">
|
||||
|
||||
@@ -3,6 +3,7 @@ import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { AppConfig, defaultConfig } from '@/config/AppConfig'
|
||||
|
||||
// TODO: get rid of this file and read about configs for next.js. Maybe use .env file where variables NEXT_PUBLIC_* are avaliable from client.
|
||||
const configFilePath = path.join(process.cwd(), 'runtimeConfig.json')
|
||||
|
||||
// Reads runtimeConfig.json (merging it over the defaults) and creates new config file if missing
|
||||
@@ -18,7 +19,7 @@ function loadConfig(): AppConfig {
|
||||
console.log(`creating default config file '${configFilePath}'`)
|
||||
fs.mkdirSync(path.dirname(configFilePath), { recursive: true })
|
||||
}
|
||||
fs.writeFileSync(configFilePath, JSON.stringify(defaultConfig, null, 4))
|
||||
fs.writeFileSync(configFilePath, JSON.stringify(config, null, 4))
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
//TODO: replace this whole service with Discord OAuth. The target audience
|
||||
// already uses Discord, so email/password login is not worth building. The
|
||||
// /api/auth/login and /api/auth/register routes below are never implemented —
|
||||
// delete them along with this service.
|
||||
//TODO: controllable rate limits
|
||||
|
||||
class AuthService {
|
||||
|
||||
Reference in New Issue
Block a user