diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56c3114..3888f7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,6 @@ concurrency: env: NODE_VERSION: "20" - PNPM_VERSION: "9" jobs: ci: @@ -33,9 +32,9 @@ jobs: steps: - uses: actions/checkout@v7 - - uses: pnpm/action-setup@v3 - with: - version: ${{ env.PNPM_VERSION }} + # pnpm version comes from "packageManager" in package.json (SSOT); + # pnpm/action-setup@v6 errors if both are specified. + - uses: pnpm/action-setup@v6 - uses: actions/setup-node@v7 with: diff --git a/apps/web/app/(dashboard)/documents/page.tsx b/apps/web/app/(dashboard)/documents/page.tsx index 4c835cd..bd57edc 100644 --- a/apps/web/app/(dashboard)/documents/page.tsx +++ b/apps/web/app/(dashboard)/documents/page.tsx @@ -61,11 +61,7 @@ export default async function DocumentsPage({ searchParams }: PageProps) { const dateTo = params.dateTo; const page = parseInt(params.page || "1", 10); const sort = (params.sort || "issueDate") as - | "number" - | "issueDate" - | "dueDate" - | "total" - | "createdAt"; + "number" | "issueDate" | "dueDate" | "total" | "createdAt"; const order = (params.order || "desc") as "asc" | "desc"; const result = await listDocuments(db, session.user.companyId, { diff --git a/apps/web/app/actions/bulk-import.ts b/apps/web/app/actions/bulk-import.ts index 9719013..5c14e5f 100644 --- a/apps/web/app/actions/bulk-import.ts +++ b/apps/web/app/actions/bulk-import.ts @@ -175,20 +175,18 @@ export async function bulkImportAction( const customersToImport = customersParsed.data .slice(0, batchSize) .filter((row: Record) => row["Nummer"] && row["Firma / Kundenname"]) - .map( - (row: Record): Record => ({ - contactNumber: row["Nummer"], - name: row["Firma / Kundenname"], - email: row["E-Mail"] || null, - phone: row["Telefon"] || null, - type: "customer", - street: row["Straße"] || null, - city: row["Stadt"] || null, - postalCode: row["PLZ"] || null, - country: row["Land"] || DEFAULT_COUNTRY, - vatNumber: row["USt-IdNr."] || null, - }), - ); + .map((row: Record): Record => ({ + contactNumber: row["Nummer"], + name: row["Firma / Kundenname"], + email: row["E-Mail"] || null, + phone: row["Telefon"] || null, + type: "customer", + street: row["Straße"] || null, + city: row["Stadt"] || null, + postalCode: row["PLZ"] || null, + country: row["Land"] || DEFAULT_COUNTRY, + vatNumber: row["USt-IdNr."] || null, + })); const customerResults = await bulkInsertContacts(db, companyId, customersToImport); result.customersInserted = customerResults.inserted; @@ -206,20 +204,18 @@ export async function bulkImportAction( const vendorsToImport = vendorsParsed.data .slice(0, batchSize) .filter((row: Record) => row["Nummer"] && row["Firma / Lieferantenname"]) - .map( - (row: Record): Record => ({ - contactNumber: row["Nummer"], - name: row["Firma / Lieferantenname"], - email: row["E-Mail"] || null, - phone: row["Telefon"] || null, - type: "vendor", - street: row["Straße"] || null, - city: row["Stadt"] || null, - postalCode: row["PLZ"] || null, - country: row["Land"] || DEFAULT_COUNTRY, - vatNumber: row["USt-IdNr."] || null, - }), - ); + .map((row: Record): Record => ({ + contactNumber: row["Nummer"], + name: row["Firma / Lieferantenname"], + email: row["E-Mail"] || null, + phone: row["Telefon"] || null, + type: "vendor", + street: row["Straße"] || null, + city: row["Stadt"] || null, + postalCode: row["PLZ"] || null, + country: row["Land"] || DEFAULT_COUNTRY, + vatNumber: row["USt-IdNr."] || null, + })); const vendorResults = await bulkInsertContacts(db, companyId, vendorsToImport); result.vendorsInserted = vendorResults.inserted; @@ -310,19 +306,17 @@ export async function bulkImportAction( const glRows = glParsed.data .filter((row) => row["Buchungsdatum"] && (row["Soll"] || row["Haben"])) - .map( - (row): Record => ({ - date: row["Buchungsdatum"] || null, - reference: row["Buchungsnummer"] || null, - description: row["Beschreibung"] || null, - notes: row["Bemerkungen"] || null, - debitAmount: parseAmount(row["Soll"]), - debitAccount: row["Sollkonto"] || null, - creditAmount: parseAmount(row["Haben"]), - creditAccount: row["Habenkonto"] || null, - voucher: row["Beleg"] || null, - }), - ); + .map((row): Record => ({ + date: row["Buchungsdatum"] || null, + reference: row["Buchungsnummer"] || null, + description: row["Beschreibung"] || null, + notes: row["Bemerkungen"] || null, + debitAmount: parseAmount(row["Soll"]), + debitAccount: row["Sollkonto"] || null, + creditAmount: parseAmount(row["Haben"]), + creditAccount: row["Habenkonto"] || null, + voucher: row["Beleg"] || null, + })); const accountCodeMap = await buildAccountCodeMap(db, companyId); const glResults = await bulkInsertJournalEntries(db, companyId, glRows, accountCodeMap); @@ -346,15 +340,13 @@ export async function bulkImportAction( const stockRows = stockParsed.data .filter((row) => row["Artikelnummer"] && row["Menge"]) - .map( - (row): Record => ({ - articleNumber: row["Artikelnummer"] || null, - quantity: parseAmount(row["Menge"]), - warehouse: row["Lager"] || null, - location: row["Lagerplatz"] || null, - productName: row["Artikelbeschreibung"] || null, - }), - ); + .map((row): Record => ({ + articleNumber: row["Artikelnummer"] || null, + quantity: parseAmount(row["Menge"]), + warehouse: row["Lager"] || null, + location: row["Lagerplatz"] || null, + productName: row["Artikelbeschreibung"] || null, + })); const { warehouses } = await import("@kivvi/database"); const [defaultWarehouse] = await db diff --git a/apps/web/app/api/chat/route.ts b/apps/web/app/api/chat/route.ts index 8dc14eb..525a424 100644 --- a/apps/web/app/api/chat/route.ts +++ b/apps/web/app/api/chat/route.ts @@ -255,8 +255,7 @@ export async function POST(request: NextRequest) { // Determine provider and model — user selection > company settings > env fallback const selectedProvider = (providerId || settings.aiProvider || process.env.AI_PROVIDER) as - | ProviderType - | undefined; + ProviderType | undefined; const selectedModel = (modelId || settings.aiModel) as string | undefined; // Build execution context diff --git a/apps/web/components/inventory/movement-form/index.tsx b/apps/web/components/inventory/movement-form/index.tsx index ef23d50..2d82a76 100644 --- a/apps/web/components/inventory/movement-form/index.tsx +++ b/apps/web/components/inventory/movement-form/index.tsx @@ -29,8 +29,7 @@ interface Warehouse { export type MovementFormProps = { products: Product[]; } & ( - | { warehouseId: string; warehouses?: never } - | { warehouseId?: never; warehouses: Warehouse[] } + { warehouseId: string; warehouses?: never } | { warehouseId?: never; warehouses: Warehouse[] } ); export function MovementForm(props: MovementFormProps) { diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index 045f81c..869b263 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -113,9 +113,7 @@ export default auth((req) => { if (mod) { // Justified: next-auth middleware types don't include custom fields const enabledModules = (req.auth as any)?.user?.enabledModules as - | string[] - | null - | undefined; + string[] | null | undefined; if (!isModuleEnabled(enabledModules ?? undefined, mod)) { return NextResponse.redirect(new URL("/dashboard", req.url)); } diff --git a/package.json b/package.json index 45e292f..70c2038 100644 --- a/package.json +++ b/package.json @@ -45,10 +45,10 @@ "format:check": "prettier --check ." }, "devDependencies": { - "@types/node": "^20.11.0", + "@types/node": "^26.4.0", "husky": "^9.1.7", "lint-staged": "^16.3.3", - "prettier": "3.8.0", + "prettier": "3.9.6", "tsx": "^4.21.0", "turbo": "^2.0.0", "typescript": "^5.3.3" diff --git a/packages/ai/src/types.ts b/packages/ai/src/types.ts index 8a5e1c4..d43425d 100644 --- a/packages/ai/src/types.ts +++ b/packages/ai/src/types.ts @@ -117,13 +117,7 @@ export interface ExecutionContext { } export type VerticalType = - | "general" - | "financial-advisory" - | "legal" - | "medical" - | "nonprofit" - | "retail" - | "manufacturing"; + "general" | "financial-advisory" | "legal" | "medical" | "nonprofit" | "retail" | "manufacturing"; export type Permission = | "invoice:read" diff --git a/packages/core/src/domain/dashboard-alerts.ts b/packages/core/src/domain/dashboard-alerts.ts index cb04c30..0cd5084 100644 --- a/packages/core/src/domain/dashboard-alerts.ts +++ b/packages/core/src/domain/dashboard-alerts.ts @@ -31,8 +31,7 @@ export interface AlertLowStockProduct { } export type DashboardAlertMetadata = - | { breakdown: AlertDraftBreakdown[] } - | { products: AlertLowStockProduct[] }; + { breakdown: AlertDraftBreakdown[] } | { products: AlertLowStockProduct[] }; export interface DashboardAlert { id: string; diff --git a/packages/core/src/domain/ricardo.ts b/packages/core/src/domain/ricardo.ts index 08d4cc1..9354325 100644 --- a/packages/core/src/domain/ricardo.ts +++ b/packages/core/src/domain/ricardo.ts @@ -33,11 +33,7 @@ export interface RicardoListingPayload { } export type RicardoCondition = - | "new" - | "used_like_new" - | "used_good" - | "used_acceptable" - | "for_parts"; + "new" | "used_like_new" | "used_good" | "used_acceptable" | "for_parts"; export interface RicardoListingResult { listingId: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9613b4d..90b4bff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,8 +22,8 @@ importers: version: 4.2.1(pdfkit@0.17.2)(typescript@5.9.3) devDependencies: '@types/node': - specifier: ^20.11.0 - version: 20.19.30 + specifier: ^26.4.0 + version: 26.4.0 husky: specifier: ^9.1.7 version: 9.1.7 @@ -31,8 +31,8 @@ importers: specifier: ^16.3.3 version: 16.3.3 prettier: - specifier: 3.8.0 - version: 3.8.0 + specifier: 3.9.6 + version: 3.9.6 tsx: specifier: ^4.21.0 version: 4.21.0 @@ -2297,6 +2297,9 @@ packages: '@types/node@20.19.30': resolution: {integrity: sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==} + '@types/node@26.4.0': + resolution: {integrity: sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==} + '@types/nodemailer@7.0.9': resolution: {integrity: sha512-vI8oF1M+8JvQhsId0Pc38BdUP2evenIIys7c7p+9OZXSPOH5c1dyINP1jT8xQ2xPuBUXmIC87s+91IZMDjH8Ow==} @@ -4746,8 +4749,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.0: - resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} engines: {node: '>=14'} hasBin: true @@ -5436,6 +5439,9 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + unicode-properties@1.4.1: resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} @@ -7580,6 +7586,10 @@ snapshots: dependencies: undici-types: 6.21.0 + '@types/node@26.4.0': + dependencies: + undici-types: 8.3.0 + '@types/nodemailer@7.0.9': dependencies: '@types/node': 20.19.30 @@ -7590,7 +7600,7 @@ snapshots: '@types/pdfkit@0.17.4': dependencies: - '@types/node': 20.19.30 + '@types/node': 26.4.0 '@types/pg-pool@2.0.6': dependencies: @@ -10328,7 +10338,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.8.0: {} + prettier@3.9.6: {} progress@2.0.3: {} @@ -11114,6 +11124,8 @@ snapshots: undici-types@6.21.0: {} + undici-types@8.3.0: {} + unicode-properties@1.4.1: dependencies: base64-js: 1.5.1