diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 8e608153e..000000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,13 +0,0 @@ -/** @type {import("eslint").Linter.Config} */ -module.exports = { - root: true, - extends: ["eslint-config-custom"], - parserOptions: { - tsconfigRootDir: __dirname, - project: [ - "./tsconfig.json", - "./apps/*/tsconfig.json", - "./packages/*/tsconfig.json", - ], - }, -}; diff --git a/.github/actions/ref_from_sha/action.yml b/.github/actions/ref_from_sha/action.yml index a589b58af..06e9edcc4 100644 --- a/.github/actions/ref_from_sha/action.yml +++ b/.github/actions/ref_from_sha/action.yml @@ -13,4 +13,4 @@ outputs: description: "The number of the PR if one is found" runs: using: "node20" - main: "index.js" + main: "index.cjs" diff --git a/.github/actions/ref_from_sha/branch_from_sha.js b/.github/actions/ref_from_sha/branch_from_sha.cjs similarity index 100% rename from .github/actions/ref_from_sha/branch_from_sha.js rename to .github/actions/ref_from_sha/branch_from_sha.cjs diff --git a/.github/actions/ref_from_sha/index.js b/.github/actions/ref_from_sha/index.cjs similarity index 95% rename from .github/actions/ref_from_sha/index.js rename to .github/actions/ref_from_sha/index.cjs index 9356f47e3..393ca3ef3 100644 --- a/.github/actions/ref_from_sha/index.js +++ b/.github/actions/ref_from_sha/index.cjs @@ -8,8 +8,8 @@ const core = require("@actions/core"); const github = require("@actions/github"); -const prFromSha = require("./pr_from_sha"); -const branchFromSha = require("./branch_from_sha"); +const prFromSha = require("./pr_from_sha.cjs"); +const branchFromSha = require("./branch_from_sha.cjs"); async function run() { try { diff --git a/.github/actions/ref_from_sha/pr_from_sha.js b/.github/actions/ref_from_sha/pr_from_sha.cjs similarity index 100% rename from .github/actions/ref_from_sha/pr_from_sha.js rename to .github/actions/ref_from_sha/pr_from_sha.cjs diff --git a/.github/actions/ref_from_sha/test/e2e.js b/.github/actions/ref_from_sha/test/e2e.cjs similarity index 90% rename from .github/actions/ref_from_sha/test/e2e.js rename to .github/actions/ref_from_sha/test/e2e.cjs index 66d036752..475e3933a 100644 --- a/.github/actions/ref_from_sha/test/e2e.js +++ b/.github/actions/ref_from_sha/test/e2e.cjs @@ -1,7 +1,7 @@ const github = require("@actions/github"); -const prFromSha = require("../pr_from_sha"); -const branchFromSha = require("../branch_from_sha"); +const prFromSha = require("../pr_from_sha.cjs"); +const branchFromSha = require("../branch_from_sha.cjs"); const githubToken = process.env.GITHUB_TOKEN; diff --git a/apps/nextjs/.eslintrc.cjs b/apps/nextjs/.eslintrc.cjs deleted file mode 100644 index 9b9cbd01b..000000000 --- a/apps/nextjs/.eslintrc.cjs +++ /dev/null @@ -1,24 +0,0 @@ -/** @type {import("eslint").Linter.Config} */ -module.exports = { - extends: ["../../.eslintrc.cjs", "next", "plugin:storybook/recommended"], - rules: { - "react/prefer-read-only-props": "error", - "react/jsx-no-useless-fragment": "warn", - "no-restricted-imports": [ - "error", - { - paths: [ - { - name: "posthog-js/react", - importNames: ["usePostHog"], - message: - "usePostHog doesn't support multiple PostHog instances, use useAnalytics instead", - }, - ], - }, - ], - }, - parserOptions: { - project: __dirname + "/tsconfig.json", - }, -}; diff --git a/apps/nextjs/jest.config.js b/apps/nextjs/jest.config.mjs similarity index 72% rename from apps/nextjs/jest.config.js rename to apps/nextjs/jest.config.mjs index cd0dc24f9..7898f8abb 100644 --- a/apps/nextjs/jest.config.js +++ b/apps/nextjs/jest.config.mjs @@ -1,5 +1,9 @@ -const { pathsToModuleNameMapper } = require("ts-jest"); -const { compilerOptions } = require("./tsconfig.test.json"); +import { readFile } from "fs/promises"; +import { pathsToModuleNameMapper } from "ts-jest"; + +const tsconfig = JSON.parse( + await readFile(new URL("./tsconfig.test.json", import.meta.url)), +); /** @type {import('ts-jest').JestConfigWithTsJest} */ const config = { @@ -12,12 +16,12 @@ const config = { isolatedModules: true, }, ], - "^.+\\.svg$": "/jest.svgTransform.js", + "^.+\\.svg$": "/jest.svgTransform.mjs", "^.+\\.(css|scss|png|jpg|jpeg|gif|webp|avif)$": "jest-transform-stub", }, preset: "ts-jest/presets/default-esm", moduleNameMapper: { - ...pathsToModuleNameMapper(compilerOptions.paths, { + ...pathsToModuleNameMapper(tsconfig.compilerOptions.paths, { prefix: "/src/", }), "^(\\.{1,2}/.*)\\.js$": "$1", @@ -30,7 +34,7 @@ const config = { moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], rootDir: ".", resetMocks: true, - setupFilesAfterEnv: ["/jest.setup.js"], + setupFilesAfterEnv: ["/jest.setup.cjs"], collectCoverageFrom: ["src/**/*.{ts,tsx,js,jsx}"], collectCoverage: process.env.CI === "true" || process.env.COLLECT_TEST_COVERAGE === "true", @@ -38,4 +42,4 @@ const config = { coverageDirectory: "coverage", }; -module.exports = config; +export default config; diff --git a/apps/nextjs/jest.setup.js b/apps/nextjs/jest.setup.cjs similarity index 100% rename from apps/nextjs/jest.setup.js rename to apps/nextjs/jest.setup.cjs diff --git a/apps/nextjs/jest.static.d.ts b/apps/nextjs/jest.static.d.ts index 95daa5e7f..ded555fbb 100644 --- a/apps/nextjs/jest.static.d.ts +++ b/apps/nextjs/jest.static.d.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ declare module "*.svg" { const content: any; export default content; diff --git a/apps/nextjs/jest.svgTransform.js b/apps/nextjs/jest.svgTransform.mjs similarity index 89% rename from apps/nextjs/jest.svgTransform.js rename to apps/nextjs/jest.svgTransform.mjs index 16506e1c5..685e8670c 100644 --- a/apps/nextjs/jest.svgTransform.js +++ b/apps/nextjs/jest.svgTransform.mjs @@ -1,4 +1,4 @@ -module.exports = { +export default { process() { console.log("Called jest svg transform"); return { code: "module.exports = {};" }; diff --git a/apps/nextjs/next.config.js b/apps/nextjs/next.config.js index 6f9dad15f..0dd375c38 100644 --- a/apps/nextjs/next.config.js +++ b/apps/nextjs/next.config.js @@ -1,9 +1,10 @@ +// This file should be in Common JS format to be compatible with Next.js const { getAppVersion, getReleaseStage, RELEASE_STAGE_PRODUCTION, RELEASE_STAGE_TESTING, -} = require("./scripts/build_config_helpers.js"); +} = require("./scripts/build_config_helpers.cjs"); const path = require("path"); const { PHASE_PRODUCTION_BUILD, PHASE_TEST } = require("next/constants"); diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index f78bce278..3547f6d63 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -1,26 +1,27 @@ { "name": "@oakai/nextjs", - "version": "0.1.0", + "version": "1.0.0", "private": true, "scripts": { "build": "next build", "build:dev": "pnpm with-env next build", "check": "tsc --noEmit", "clean": "rm -rf .next .turbo node_modules", - "dev": "FORCE_COLOR=1 SENTRY_SUPPRESS_TURBOPACK_WARNING=1 pnpm with-env node scripts/increase-listeners.js next dev --port 2525 --turbo | pino-pretty -C", - "dev:sentry": "FORCE_COLOR=1 pnpm with-env node scripts/increase-listeners.js next dev --port 2525 | pino-pretty -C", + "dev": "FORCE_COLOR=1 SENTRY_SUPPRESS_TURBOPACK_WARNING=1 pnpm with-env next dev --port 2525 --turbo | pino-pretty -C", + "dev:sentry": "FORCE_COLOR=1 pnpm with-env next dev --port 2525 | pino-pretty -C", "dev-trace-deprecation": "NODE_OPTIONS=\"--trace-deprecation\" next dev --port 2525 | pino-pretty -C", - "lint": "next lint", + "lint": "eslint .", "lint-fix": "next lint --fix", + "lint-debug": "eslint --debug .", "start": "next start", "type-check": "tsc --noEmit", - "test": "pnpm with-env jest --colors --config jest.config.js", - "test:seq": "pnpm with-env jest --colors --config jest.config.js --verbose --runInBand --no-cache", + "test": "pnpm with-env jest --colors --config jest.config.mjs", + "test:seq": "pnpm with-env jest --colors --config jest.config.mjs --verbose --runInBand --no-cache", "test-e2e": "pnpm with-env playwright test", "test-e2e-ui": "pnpm with-env playwright test --ui", "test-e2e-ui-serve": "pnpm build && pnpm start --port 4848 --turbo", "test-e2e-ui-built": "PORT=4848 pnpm with-env playwright test --ui", - "test-coverage": "COLLECT_TEST_COVERAGE=true pnpm with-env jest --colors --config jest.config.js --coverage", + "test-coverage": "COLLECT_TEST_COVERAGE=true pnpm with-env jest --colors --config jest.config.mjs --coverage", "with-env": "dotenv -e ../../.env --", "aila": "tsx scripts/aila-cli.ts", "storybook": "dotenv -e ../../.env -- storybook dev -p 6006 --no-open", @@ -43,14 +44,15 @@ "@oakai/api": "*", "@oakai/core": "*", "@oakai/db": "*", + "@oakai/eslint-config": "*", "@oakai/exports": "*", "@oakai/logger": "*", "@oakai/prettier-config": "*", "@oaknational/oak-components": "^1.50.0", "@oaknational/oak-consent-client": "^2.1.0", "@portabletext/react": "^3.1.0", - "@prisma/client": "5.16.1", - "@prisma/extension-accelerate": "^1.0.0", + "@prisma/client": "^5.16.1", + "@prisma/extension-accelerate": "^1.2.1", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-tooltip": "^1.0.7", @@ -141,8 +143,8 @@ "@storybook/test": "^8.4.1", "@tailwindcss/typography": "^0.5.10", "@types/file-saver": "^2.0.6", - "@types/jest": "^29.5.12", - "@types/node": "^18.17.0", + "@types/jest": "^29.5.14", + "@types/node": "^20.9.0", "@types/react": "^18.2.37", "@types/react-dom": "^18.2.15", "@types/styled-components": "^5.1.34", @@ -150,17 +152,14 @@ "avo": "^3.2.11", "concurrently": "^8.2.2", "dotenv-cli": "^6.0.0", - "eslint": "^8.56.0", - "eslint-config-next": "15.0.1", - "eslint-plugin-storybook": "^0.8.0", "graphql": "^16.9.0", "jest": "^29.7.0", "msw": "^2.6.5", "msw-storybook-addon": "^2.0.4", "postcss": "^8.4.32", "tailwindcss": "^3.3.7", - "ts-jest": "^29.1.4", - "typescript": "5.3.3", + "ts-jest": "^29.2.5", + "typescript": "5.7.2", "web-streams-polyfill": "^4.0.0" }, "engines": { @@ -171,5 +170,12 @@ "workerDirectory": [ ".storybook/public" ] + }, + "eslintConfig": { + "extends": "@oakai/eslint-config", + "parserOptions": { + "project": "./tsconfig.json" + }, + "rules": {} } } diff --git a/apps/nextjs/scripts/build_config_helpers.js b/apps/nextjs/scripts/build_config_helpers.cjs similarity index 99% rename from apps/nextjs/scripts/build_config_helpers.js rename to apps/nextjs/scripts/build_config_helpers.cjs index 4016a0c86..ca4a2b30f 100644 --- a/apps/nextjs/scripts/build_config_helpers.js +++ b/apps/nextjs/scripts/build_config_helpers.cjs @@ -7,7 +7,7 @@ const { existsSync, readFileSync } = require("fs"); * @returns {(string|null)} The SHA if found, or "no_git_state" if mid-merge, or `null` if it cannot be determined. */ function getLocalGitRef() { - if (existsSync("../../.git")) { + if (existsSync("../../.git/HEAD")) { const rev = readFileSync("../../.git/HEAD") .toString() .trim() diff --git a/apps/nextjs/scripts/increase-listeners.js b/apps/nextjs/scripts/increase-listeners.js deleted file mode 100644 index 7d9e0c25a..000000000 --- a/apps/nextjs/scripts/increase-listeners.js +++ /dev/null @@ -1,18 +0,0 @@ -/**** - Because we have a reasonably complex Next.js project now, - we're sometimes running into the default max listeners limit. - This script increases the limit to 20, which should be enough - so that we don't run into this issue. - - Potentially, if we decide to move to Turbopack for compilation - in local development, we could remove this script. - -***/ - -// Increase the limit of max listeners -require("events").EventEmitter.defaultMaxListeners = 20; - -// Run the original command -require("child_process").spawn(process.argv[2], process.argv.slice(3), { - stdio: "inherit", -}); diff --git a/apps/nextjs/scripts/preload-chat-routes.mjs b/apps/nextjs/scripts/preload-chat-routes.mjs index 382413a45..de599b985 100644 --- a/apps/nextjs/scripts/preload-chat-routes.mjs +++ b/apps/nextjs/scripts/preload-chat-routes.mjs @@ -75,6 +75,7 @@ const preBuildRoutes = async ( console.log("All routes pre-built successfully"); console.timeEnd(timerId); } catch (error) { + console.error(error); if (retryCount < maxRetries) { console.log( `Retrying pre-build (attempt ${retryCount + 1} of ${maxRetries})...`, diff --git a/apps/nextjs/src/ai-apps/lesson-planner/state/actions.ts b/apps/nextjs/src/ai-apps/lesson-planner/state/actions.ts index 16ef00a41..3b68c7c5f 100644 --- a/apps/nextjs/src/ai-apps/lesson-planner/state/actions.ts +++ b/apps/nextjs/src/ai-apps/lesson-planner/state/actions.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-duplicate-enum-values */ import type { RateLimitInfo } from "@oakai/api/src/types"; import type { KeyStageName, SubjectName } from "@oakai/core"; import type { diff --git a/apps/nextjs/src/app/api/chat/fixtures/FixtureRecordOpenAiClient.ts b/apps/nextjs/src/app/api/chat/fixtures/FixtureRecordOpenAiClient.ts index cb0d5d686..68d340390 100644 --- a/apps/nextjs/src/app/api/chat/fixtures/FixtureRecordOpenAiClient.ts +++ b/apps/nextjs/src/app/api/chat/fixtures/FixtureRecordOpenAiClient.ts @@ -3,7 +3,7 @@ import { createOpenAIClient } from "@oakai/core/src/llm/openai"; import { aiLogger } from "@oakai/logger"; import fs from "fs/promises"; import type OpenAI from "openai"; -import type { ChatCompletionCreateParamsNonStreaming } from "openai/resources"; +import type { ChatCompletionCreateParamsNonStreaming } from "openai/resources/index.mjs"; const log = aiLogger("fixtures"); diff --git a/apps/nextjs/src/components/AppComponents/Chat/chat-message/index.tsx b/apps/nextjs/src/components/AppComponents/Chat/chat-message/index.tsx index 06359a59c..4685bc77e 100644 --- a/apps/nextjs/src/components/AppComponents/Chat/chat-message/index.tsx +++ b/apps/nextjs/src/components/AppComponents/Chat/chat-message/index.tsx @@ -1,6 +1,6 @@ // Inspired by Chatbot-UI and modified to fit the needs of this project // @see https://github.com/mckaywrigley/chatbot-ui/blob/main/components/Chat/ChatMessage.tsx -import type { ReactNode } from "react"; +import type { ReactNode, JSX } from "react"; import { useState } from "react"; import type { MessagePart } from "@oakai/aila/src/protocol/jsonPatchProtocol"; @@ -200,7 +200,7 @@ function MessageWrapper({ function MessageTextWrapper({ children }: Readonly<{ children: ReactNode }>) { return ( -
+
{children}
); diff --git a/apps/nextjs/src/components/AppComponents/Chat/ui/textarea.tsx b/apps/nextjs/src/components/AppComponents/Chat/ui/textarea.tsx index e4eb3ebb2..4878582fd 100644 --- a/apps/nextjs/src/components/AppComponents/Chat/ui/textarea.tsx +++ b/apps/nextjs/src/components/AppComponents/Chat/ui/textarea.tsx @@ -2,23 +2,21 @@ import * as React from "react"; import { cn } from "@/lib/utils"; -interface TextareaProps - extends React.TextareaHTMLAttributes {} - -const Textarea = React.forwardRef( - ({ className, ...props }, ref) => { - return ( -