chore(portal,operator): upgrade to Nuxt 4

Upgrade both Nuxt apps to Nuxt 4.4.6 (vue-tsc 3, TypeScript 5.6, undici 7) and add a root tsconfig.json to each app. Fix the strict-null / noUncheckedIndexedAccess errors surfaced by Nuxt 4's stricter generated tsconfig and vue-tsc 3. Drop the nuxt-oidc-auth pnpm patch (Nuxt 4 fixes the prepare:types crash natively).
This commit is contained in:
Ronni Baslund
2026-05-30 08:02:43 +02:00
parent 0bd4e5498e
commit 17ffd95a70
25 changed files with 888 additions and 706 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ const initials = computed(() =>
.split(' ')
.filter(Boolean)
.slice(0, 2)
.map((p) => p[0].toUpperCase())
.map((p) => p.charAt(0).toUpperCase())
.join(''),
)
+4 -1
View File
@@ -10,7 +10,10 @@ const route = useRoute()
const open = ref(false)
const displayName = computed(() => user.value?.userInfo?.name || user.value?.userName || 'operator')
const displayName = computed<string>(() => {
const name = (user.value?.userInfo as { name?: string } | undefined)?.name
return name || (user.value?.userName as string | undefined) || 'operator'
})
const email = computed(() => (user.value?.userInfo as { email?: string } | undefined)?.email ?? '')
function toggle() {
+5 -3
View File
@@ -2,7 +2,7 @@
"name": "@dezky/operator",
"version": "0.0.1",
"private": true,
"description": "Dezky operator portal — internal admin app (Nuxt 3)",
"description": "Dezky operator portal — internal admin app (Nuxt 4)",
"scripts": {
"dev": "nuxt dev --host 0.0.0.0 --port 3000",
"build": "nuxt build",
@@ -11,14 +11,16 @@
"lint": "eslint ."
},
"dependencies": {
"nuxt": "^3.13.0",
"nuxt": "^4.4.6",
"nuxt-oidc-auth": "1.0.0-beta.11",
"undici": "^7.2.1",
"vue": "^3.5.0",
"vue-router": "^4.4.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.5.0"
"typescript": "^5.6.0",
"vue-tsc": "^3.2.6"
},
"packageManager": "pnpm@9.12.0"
}
+1 -1
View File
@@ -391,7 +391,7 @@ function fmtRelative(iso: string | null | undefined): string {
<div class="cap">
{{
archives?.length
? `archived through seq ${archives[0].endSeq} · ${archives.length} batch${archives.length === 1 ? '' : 'es'}`
? `archived through seq ${archives[0]!.endSeq} · ${archives.length} batch${archives.length === 1 ? '' : 'es'}`
: 'no archives yet · 90-day hot retention'
}}
</div>
+1 -1
View File
@@ -209,7 +209,7 @@ const sortedPrices = computed<PriceRow[]>(() =>
<td v-for="c in CURRENCIES" :key="c" class="cell-amount">
<template v-if="drafts[row._id]">
<input
v-model="drafts[row._id][c]"
v-model="drafts[row._id]![c]"
type="text"
inputmode="decimal"
class="amount-input"
+407 -331
View File
File diff suppressed because it is too large Load Diff
@@ -9,7 +9,7 @@ import { getUserSession } from 'nuxt-oidc-auth/runtime/server/utils/session.js'
function decodeJwtClaims(token: string): Record<string, unknown> {
const parts = token.split('.')
if (parts.length < 2) throw new Error('Not a JWT')
const payload = parts[1].replace(/-/g, '+').replace(/_/g, '/')
const payload = parts[1]!.replace(/-/g, '+').replace(/_/g, '/')
const padded = payload + '='.repeat((4 - (payload.length % 4)) % 4)
return JSON.parse(Buffer.from(padded, 'base64').toString('utf8'))
}
+5 -1
View File
@@ -26,7 +26,11 @@ function originatingIp(event: H3Event): string | undefined {
export async function platformApi<T = unknown>(
event: H3Event,
path: string,
init: { method?: string; body?: unknown; query?: Record<string, string | number | undefined> } = {},
init: {
method?: string
body?: BodyInit | Record<string, unknown> | null
query?: Record<string, string | number | undefined>
} = {},
): Promise<T> {
const session = await getUserSession(event).catch(() => null)
const accessToken = (session as { accessToken?: string } | null)?.accessToken
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "./.nuxt/tsconfig.json"
}