diff --git a/.gitignore b/.gitignore index 63ad084e2..e656afe21 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ **/.idea/ **/dist/ **/.env.local + +# TypeScript build cache manifests +*.tsbuildinfo \ No newline at end of file diff --git a/Changelog.md b/Changelog.md index ccf449649..fbc35b8aa 100644 --- a/Changelog.md +++ b/Changelog.md @@ -20,6 +20,8 @@ [#548](https://github.com/aws/graph-explorer/pull/548)) - **Improved** SageMaker Lifecycle script handling of CloudWatch log driver failures ([#550](https://github.com/aws/graph-explorer/pull/550)) +- **Changed** Node to run in production mode + ([#558](https://github.com/aws/graph-explorer/pull/558)) - **Removed** hosting production server using the client side Vite configuration, requiring the use of the proxy server ([#565](https://github.com/aws/graph-explorer/pull/565)) diff --git a/package.json b/package.json index 6bce29c1f..f73526a25 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@ "check:lint": "eslint .", "format": "prettier --write .", "check:format": "prettier --check .", - "test": "pnpm --stream -r run test", - "test:watch": "pnpm --stream -r run test:watch", - "coverage": "pnpm --stream -r run coverage", - "check:types": "pnpm --stream -r check:types", - "checks": "pnpm run '/^check:.*/'", + "test": "vitest run", + "test:watch": "vitest", + "coverage": "vitest run --coverage", + "check:types": "tsc --build", + "checks": "pnpm clean && pnpm run '/^check:.*/'", "start": "pnpm --filter \"graph-explorer-proxy-server\" run start", "clean": "pnpm --stream -r run clean", "build": "pnpm --stream -r run build", @@ -34,6 +34,7 @@ "@eslint/compat": "^1.1.1", "@eslint/js": "^9.9.0", "@tanstack/eslint-plugin-query": "^5.51.1", + "@vitest/coverage-v8": "^2.0.5", "eslint": "^9.9.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-react": "^7.35.0", diff --git a/packages/graph-explorer-proxy-server/package.json b/packages/graph-explorer-proxy-server/package.json index 0dd414d97..b3a894bd0 100644 --- a/packages/graph-explorer-proxy-server/package.json +++ b/packages/graph-explorer-proxy-server/package.json @@ -5,14 +5,10 @@ "main": "dist/node-server.js", "type": "module", "scripts": { - "clean": "rimraf dist", - "build": "tsc -p tsconfig.build.json", + "clean": "tsc --build tsconfig.build.json --clean && rimraf dist coverage", + "build": "tsc --build tsconfig.build.json", "dev": "tsx watch src/node-server.ts", - "test": "vitest run", - "test:watch": "vitest", - "coverage": "vitest run --coverage", - "start": "node dist/node-server.js", - "check:types": "tsc --noEmit" + "start": "NODE_ENV=production node dist/node-server.js" }, "author": "amazon", "license": "Apache-2.0", diff --git a/packages/graph-explorer-proxy-server/src/node-server.ts b/packages/graph-explorer-proxy-server/src/node-server.ts index f38ab0b87..5614bd287 100644 --- a/packages/graph-explorer-proxy-server/src/node-server.ts +++ b/packages/graph-explorer-proxy-server/src/node-server.ts @@ -38,7 +38,7 @@ const proxyLogger = createLogger(); app.use(requestLoggingMiddleware(proxyLogger)); // Function to get IAM headers for AWS4 signing process. -async function getIAMHeaders(options) { +async function getIAMHeaders(options: string | aws4.Request) { const credentialProvider = fromNodeProviderChain(); const creds = await credentialProvider(); if (creds === undefined) { @@ -46,10 +46,11 @@ async function getIAMHeaders(options) { "IAM is enabled but credentials cannot be found on the credential provider chain." ); } + const headers = aws4.sign(options, { accessKeyId: creds.accessKeyId, secretAccessKey: creds.secretAccessKey, - sessionToken: creds.sessionToken, + ...(creds.sessionToken && { sessionToken: creds.sessionToken }), }); return headers; @@ -146,6 +147,8 @@ const retryFetch = async ( } } } + // Should never reach this code + throw new Error("retryFetch failed to complete retry logic"); }; // Function to fetch data from the given URL and send it as a response. @@ -166,8 +169,8 @@ async function fetchData( region, serviceType ); - const data = await response!.json(); - res.status(response!.status); + const data = await response.json(); + res.status(response.status); res.send(data); } catch (error) { next(error); @@ -270,7 +273,7 @@ app.post("/sparql", (req, res, next) => { body, }; - fetchData( + return fetchData( res, next, rawUrl, @@ -347,7 +350,7 @@ app.post("/gremlin", (req, res, next) => { body: JSON.stringify(body), }; - fetchData( + return fetchData( res, next, rawUrl, @@ -384,7 +387,7 @@ app.post("/openCypher", (req, res, next) => { ? (headers["service-type"] ?? DEFAULT_SERVICE_TYPE) : ""; - fetchData( + return fetchData( res, next, rawUrl, diff --git a/packages/graph-explorer-proxy-server/tsconfig.build.json b/packages/graph-explorer-proxy-server/tsconfig.build.json index e065bcd3e..96be82552 100644 --- a/packages/graph-explorer-proxy-server/tsconfig.build.json +++ b/packages/graph-explorer-proxy-server/tsconfig.build.json @@ -1,9 +1,5 @@ { "extends": ["./tsconfig.json"], - "compilerOptions": { - "noEmit": false, - "outDir": "dist" - }, "include": ["src/**/*.ts"], "exclude": ["**/*.test.ts", "./src/test-setup.ts"] } diff --git a/packages/graph-explorer-proxy-server/tsconfig.json b/packages/graph-explorer-proxy-server/tsconfig.json index 835a8266e..feb25e947 100644 --- a/packages/graph-explorer-proxy-server/tsconfig.json +++ b/packages/graph-explorer-proxy-server/tsconfig.json @@ -1,30 +1,27 @@ { + "extends": ["../../tsconfig.base.json"], "compilerOptions": { /* Language and Environment */ + "composite": true, "target": "ES2022", "lib": ["ES2023"], + "types": ["vitest/globals"], /* Modules */ "module": "node16", - "noEmit": true, /* Interop Constraints */ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - /* Type Checking */ - "strict": true, - "noImplicitAny": false, - "types": ["vitest/globals"], - - /* Completeness */ - "skipLibCheck": true, - /* Paths */ + "outDir": "./dist", "baseUrl": "./src", + "rootDir": "./src", "paths": { "@/*": ["./*"] } }, - "include": ["src"] + "include": ["src"], + "references": [{ "path": "./tsconfig.build.json" }] } diff --git a/packages/graph-explorer/package.json b/packages/graph-explorer/package.json index 22569d916..7ef78fbc8 100644 --- a/packages/graph-explorer/package.json +++ b/packages/graph-explorer/package.json @@ -7,14 +7,10 @@ }, "type": "module", "scripts": { - "test": "vitest run", - "test:watch": "vitest", - "coverage": "vitest run --coverage", "dev": "vite --force", - "clean": "rimraf dist", + "clean": "tsc --build --clean && rimraf dist coverage", "vite-build": "NODE_OPTIONS=--max_old_space_size=6144 vite build", - "build": "pnpm vite-build -- --mode production", - "check:types": "tsc --noEmit" + "build": "pnpm vite-build -- --mode production" }, "author": "amazon", "license": "Apache-2.0", diff --git a/packages/graph-explorer/src/components/AdvancedList/internalComponents/EmptyState.tsx b/packages/graph-explorer/src/components/AdvancedList/internalComponents/EmptyState.tsx index efd796c1d..46b432c19 100644 --- a/packages/graph-explorer/src/components/AdvancedList/internalComponents/EmptyState.tsx +++ b/packages/graph-explorer/src/components/AdvancedList/internalComponents/EmptyState.tsx @@ -3,7 +3,7 @@ import { NoWidgetIcon, SearchSadIcon } from "@/components/icons"; import { PanelEmptyState } from "@/components/PanelEmptyState"; const getEmptyStateItems = ( - empty: boolean, + _empty: boolean, noSearchResults: boolean, emptyState?: { noSearchResultsTitle?: ReactNode; diff --git a/packages/graph-explorer/src/components/NotificationProvider/reducer.ts b/packages/graph-explorer/src/components/NotificationProvider/reducer.ts index 5b3d35de6..b29341755 100644 --- a/packages/graph-explorer/src/components/NotificationProvider/reducer.ts +++ b/packages/graph-explorer/src/components/NotificationProvider/reducer.ts @@ -152,8 +152,6 @@ const reducer = (state: NotificationState, action: NotificationAction) => { }; } } - - return state; }; export default reducer; diff --git a/packages/graph-explorer/src/hooks/useSchemaSync.ts b/packages/graph-explorer/src/hooks/useSchemaSync.ts index 4bd7577d7..64eb65208 100644 --- a/packages/graph-explorer/src/hooks/useSchemaSync.ts +++ b/packages/graph-explorer/src/hooks/useSchemaSync.ts @@ -41,17 +41,17 @@ const useSchemaSync = (onSyncChange?: (isSyncing: boolean) => void) => { type: "error", stackable: true, }); - if (e.name === "AbortError") { + if (e instanceof Error && e.name === "AbortError") { logger.error( `[${ config.displayLabel || config.id - }] Fetch aborted, reached max time out ${config.connection?.fetchTimeoutMs} MS ` + }] Fetch aborted, reached max time out ${config.connection?.fetchTimeoutMs} MS` ); } else { logger.error( `[${ config.displayLabel || config.id - }] Error while fetching schema: ${e.message}` + }] Error while fetching schema: ${e instanceof Error ? e.message : "Unexpected error"}` ); } updateSchemaState(config.id); diff --git a/packages/graph-explorer/src/index.tsx b/packages/graph-explorer/src/index.tsx index 5fd6bb8ad..b82a0d6be 100644 --- a/packages/graph-explorer/src/index.tsx +++ b/packages/graph-explorer/src/index.tsx @@ -73,7 +73,9 @@ const grabConfig = async (): Promise => { }, }; } catch (error) { - console.error(`Error when trying to create connection: ${error.message}`); + console.error( + `Error when trying to create connection: ${error instanceof Error ? error.message : "Unexpected error"}` + ); } }; diff --git a/packages/graph-explorer/src/modules/EntitiesTabular/components/EdgesTabular.tsx b/packages/graph-explorer/src/modules/EntitiesTabular/components/EdgesTabular.tsx index 01ae2dea2..d724bdea7 100644 --- a/packages/graph-explorer/src/modules/EntitiesTabular/components/EdgesTabular.tsx +++ b/packages/graph-explorer/src/modules/EntitiesTabular/components/EdgesTabular.tsx @@ -24,7 +24,7 @@ import { recoilDiffSets } from "@/utils/recoilState"; type ToggleEdge = Edge & { __is_visible: boolean }; -const EdgesTabular = forwardRef, any>((props, ref) => { +const EdgesTabular = forwardRef, any>((_props, ref) => { const t = useTranslations(); const edges = useRecoilValue(edgesAtom); const setEdgesOut = useSetRecoilState(edgesOutOfFocusIdsAtom); diff --git a/packages/graph-explorer/src/modules/EntitiesTabular/components/NodesTabular.tsx b/packages/graph-explorer/src/modules/EntitiesTabular/components/NodesTabular.tsx index d688f9c97..7ee4b1ce4 100644 --- a/packages/graph-explorer/src/modules/EntitiesTabular/components/NodesTabular.tsx +++ b/packages/graph-explorer/src/modules/EntitiesTabular/components/NodesTabular.tsx @@ -27,7 +27,7 @@ import { recoilDiffSets } from "@/utils/recoilState"; type ToggleVertex = Vertex & { __is_visible: boolean }; -const NodesTabular = forwardRef, any>((props, ref) => { +const NodesTabular = forwardRef, any>((_props, ref) => { const t = useTranslations(); const nodes = useRecoilValue(nodesAtom); const setNodesOut = useSetRecoilState(nodesOutOfFocusIdsAtom); diff --git a/packages/graph-explorer/src/modules/KeywordSearch/KeywordSearch.tsx b/packages/graph-explorer/src/modules/KeywordSearch/KeywordSearch.tsx index 3b0eab47d..a40e9ff75 100644 --- a/packages/graph-explorer/src/modules/KeywordSearch/KeywordSearch.tsx +++ b/packages/graph-explorer/src/modules/KeywordSearch/KeywordSearch.tsx @@ -412,7 +412,7 @@ function SearchResults({ items={resultItems} draggable={true} defaultItemType="graph-viewer__node" - onItemClick={(event, item) => { + onItemClick={(_event, item) => { selection.toggle(item.id); }} selectedItemsIds={Array.from(selection.state)} diff --git a/packages/graph-explorer/tsconfig.app.json b/packages/graph-explorer/tsconfig.app.json index 235857953..b0c6a8080 100644 --- a/packages/graph-explorer/tsconfig.app.json +++ b/packages/graph-explorer/tsconfig.app.json @@ -1,10 +1,10 @@ { + "extends": ["../../tsconfig.base.json"], "compilerOptions": { "target": "ES2022", "useDefineForClassFields": true, "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", - "skipLibCheck": true, "types": ["vite/client", "vitest/globals", "@testing-library/jest-dom"], /* Path aliasing */ @@ -20,13 +20,7 @@ "isolatedModules": true, "moduleDetection": "force", "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "jsx": "react-jsx" }, "include": ["src"] } diff --git a/packages/graph-explorer/tsconfig.json b/packages/graph-explorer/tsconfig.json index ba5138b53..eb77d66ea 100644 --- a/packages/graph-explorer/tsconfig.json +++ b/packages/graph-explorer/tsconfig.json @@ -1,4 +1,5 @@ { + "extends": ["../../tsconfig.base.json"], "files": [], "references": [ { "path": "./tsconfig.app.json" }, diff --git a/packages/graph-explorer/vite.config.ts b/packages/graph-explorer/vite.config.ts index cd766e7dd..f97a4f474 100644 --- a/packages/graph-explorer/vite.config.ts +++ b/packages/graph-explorer/vite.config.ts @@ -13,7 +13,7 @@ export default defineConfig(({ mode }) => { transformIndexHtml: { order: "pre", handler: (html: string) => { - return html.replace(/%(.*?)%/g, function (match, p1) { + return html.replace(/%(.*?)%/g, function (_match, p1) { return env[p1] ? env[p1] : ""; }); }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e329aa53b..28a7265f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,9 @@ importers: '@tanstack/eslint-plugin-query': specifier: ^5.51.1 version: 5.51.1(eslint@9.9.0)(typescript@5.5.4) + '@vitest/coverage-v8': + specifier: ^2.0.5 + version: 2.0.5(vitest@2.0.5) eslint: specifier: ^9.9.0 version: 9.9.0 @@ -5520,7 +5523,7 @@ packages: std-env: 3.7.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.0.5(@types/node@20.12.8)(happy-dom@14.12.3)(jsdom@24.1.0) + vitest: 2.0.5 transitivePeerDependencies: - supports-color dev: true diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 000000000..016af2288 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + /* Useful for project references */ + "composite": true, + "declaration": true, + "declarationMap": true, + "incremental": true, + "noEmitOnError": true, + "skipLibCheck": true, + + /* Linting */ + "strict": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "noImplicitOverride": true, + "noImplicitAny": true, + "checkJs": true + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..90b3ea960 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "files": [], + "references": [ + { "path": "packages/graph-explorer" }, + { "path": "packages/graph-explorer-proxy-server" } + ] +}