diff --git a/app/composables/useGqlClient.ts b/app/composables/useGqlClient.ts index da6f309..ada7cf4 100644 --- a/app/composables/useGqlClient.ts +++ b/app/composables/useGqlClient.ts @@ -1,5 +1,6 @@ import type { ApolloClient, NormalizedCacheObject } from '@apollo/client/core'; -export function useGqlClient(): ApolloClient { - return useNuxtApp().$apollo as ApolloClient; +export function useGqlClient() { + const { client } = useApolloClient('default'); + return client as ApolloClient; } diff --git a/app/plugins/apollo.ts b/app/plugins/apollo.ts deleted file mode 100644 index 4a6a4a0..0000000 --- a/app/plugins/apollo.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core'; -import { provideApolloClient } from '@vue/apollo-composable'; - -export default defineNuxtPlugin(() => { - const config = useRuntimeConfig(); - - const client = new ApolloClient({ - link: new HttpLink({ - uri: config.public.graphqlEndpoint, - fetch, - }), - cache: new InMemoryCache(), - connectToDevTools: import.meta.dev, - }); - - provideApolloClient(client); - - return { - provide: { - apollo: client, - }, - }; -}); diff --git a/nuxt.config.ts b/nuxt.config.ts index 04afefe..6da5d92 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,17 +1,39 @@ +const nuxtPort = Number(process.env.NUXT_PORT || process.env.NITRO_PORT || process.env.PORT || 3000); +const internalApolloBaseUrl = process.env.NUXT_INTERNAL_SITE_URL || `http://localhost:${nuxtPort}`; +const authCookieName = process.env.AUTH_COOKIE_NAME || 'fregat_auth_token'; + // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ compatibilityDate: '2025-07-15', devtools: { enabled: true }, - modules: ['@nuxt/eslint', '@nuxtjs/tailwindcss'], + modules: ['@nuxt/eslint', '@nuxtjs/tailwindcss', '@nuxtjs/apollo'], css: ['~/assets/css/main.css'], runtimeConfig: { + backendGraphqlUrl: + process.env.NUXT_BACKEND_GRAPHQL_URL || + process.env.BACKEND_GRAPHQL_URL || + 'http://localhost:4000/graphql', + authCookieName, public: { - graphqlEndpoint: process.env.NUXT_PUBLIC_GRAPHQL_ENDPOINT ?? 'http://localhost:4000/graphql', sentryDsn: process.env.NUXT_PUBLIC_SENTRY_DSN ?? '', sentryEnvironment: process.env.NUXT_PUBLIC_SENTRY_ENVIRONMENT ?? 'development', sentryRelease: process.env.NUXT_PUBLIC_SENTRY_RELEASE ?? 'dev', }, }, + apollo: { + proxyCookies: true, + clients: { + default: { + httpEndpoint: `${internalApolloBaseUrl}/api/graphql`, + browserHttpEndpoint: '/api/graphql', + tokenStorage: 'cookie', + tokenName: authCookieName, + authType: 'Bearer', + authHeader: 'Authorization', + connectToDevTools: process.env.NODE_ENV !== 'production', + }, + }, + }, app: { head: { title: 'Fregat Manager Cabinet', diff --git a/package.json b/package.json index 39762b0..31af661 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "dependencies": { "@apollo/client": "^3.14.1", "@nuxt/eslint": "1.15.2", + "@nuxtjs/apollo": "5.0.0-alpha.16", "@nuxtjs/tailwindcss": "6.14.0", "@sentry/vue": "^10.46.0", "@vue/apollo-composable": "^4.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6de9008..f3334c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@nuxt/eslint': specifier: 1.15.2 version: 1.15.2(@typescript-eslint/utils@8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.2))(@vue/compiler-sfc@3.5.31)(eslint@10.1.0(jiti@2.6.1))(magicast@0.5.2)(typescript@5.9.2)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(terser@5.46.1)(yaml@2.8.3)) + '@nuxtjs/apollo': + specifier: 5.0.0-alpha.16 + version: 5.0.0-alpha.16(@types/react@19.2.14)(crossws@0.3.5)(magicast@0.5.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.1)(typescript@5.9.2)(vue@3.5.31(typescript@5.9.2))(ws@8.20.0) '@nuxtjs/tailwindcss': specifier: 6.14.0 version: 6.14.0(magicast@0.5.2)(yaml@2.8.3) @@ -1245,6 +1248,9 @@ packages: rollup-plugin-visualizer: optional: true + '@nuxtjs/apollo@5.0.0-alpha.16': + resolution: {integrity: sha512-bYDaHboCfYCMzQsSSh3WttLmNVYH/HvGjtawasRRbaHz7hf3qEMmMPfH/FiQI0qRRo4nRKqLpB1bu+kquSP2ng==} + '@nuxtjs/tailwindcss@6.14.0': resolution: {integrity: sha512-30RyDK++LrUVRgc2A85MktGWIZoRQgeQKjE4CjjD64OXNozyl+4ScHnnYgqVToMM6Ch2ZG2W4wV2J0EN6F0zkQ==} @@ -1742,6 +1748,16 @@ packages: rollup: optional: true + '@rollup/plugin-graphql@2.0.5': + resolution: {integrity: sha512-NMx9uVIheYMOQHV9Aann0sk/2+henT8T5JUbHneOvbD3iUrVUC7AaZ1B1ELJ/1vhqUe2OQIkRtGHzOQwBLoCvg==} + engines: {node: '>=14.0.0'} + peerDependencies: + graphql: '>=0.9.0' + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/plugin-inject@5.0.5': resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} engines: {node: '>=14.0.0'} @@ -2348,6 +2364,12 @@ packages: '@vue/composition-api': optional: true + '@vue/apollo-option@4.2.2': + resolution: {integrity: sha512-70yKre9/cLV5Ye98x1gCcT3217mpYnWd3tp6gQCNHJSLtXvHs2J6kqNGJM7Xi1FYlHfhkElRklkixAdnh7OamQ==} + peerDependencies: + '@apollo/client': ^3.2.1 + vue: ^3.1.0 + '@vue/babel-helper-vue-transform-on@2.0.1': resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==} @@ -7631,6 +7653,34 @@ snapshots: - vue-tsc - yaml + '@nuxtjs/apollo@5.0.0-alpha.16(@types/react@19.2.14)(crossws@0.3.5)(magicast@0.5.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.1)(typescript@5.9.2)(vue@3.5.31(typescript@5.9.2))(ws@8.20.0)': + dependencies: + '@apollo/client': 3.14.1(@types/react@19.2.14)(graphql-ws@6.0.8(crossws@0.3.5)(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@nuxt/kit': 4.4.2(magicast@0.5.2) + '@rollup/plugin-graphql': 2.0.5(graphql@16.13.2)(rollup@4.60.1) + '@vue/apollo-composable': 4.2.2(@apollo/client@3.14.1(@types/react@19.2.14)(graphql-ws@6.0.8(crossws@0.3.5)(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(graphql@16.13.2)(typescript@5.9.2)(vue@3.5.31(typescript@5.9.2)) + '@vue/apollo-option': 4.2.2(@apollo/client@3.14.1(@types/react@19.2.14)(graphql-ws@6.0.8(crossws@0.3.5)(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vue@3.5.31(typescript@5.9.2)) + defu: 6.1.4 + destr: 2.0.5 + graphql: 16.13.2 + graphql-tag: 2.12.6(graphql@16.13.2) + graphql-ws: 6.0.8(crossws@0.3.5)(graphql@16.13.2)(ws@8.20.0) + jiti: 2.6.1 + ohash: 2.0.11 + transitivePeerDependencies: + - '@fastify/websocket' + - '@types/react' + - '@vue/composition-api' + - crossws + - magicast + - react + - react-dom + - rollup + - subscriptions-transport-ws + - typescript + - vue + - ws + '@nuxtjs/tailwindcss@6.14.0(magicast@0.5.2)(yaml@2.8.3)': dependencies: '@nuxt/kit': 3.21.2(magicast@0.5.2) @@ -7958,6 +8008,14 @@ snapshots: optionalDependencies: rollup: 4.60.1 + '@rollup/plugin-graphql@2.0.5(graphql@16.13.2)(rollup@4.60.1)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) + graphql: 16.13.2 + graphql-tag: 2.12.6(graphql@16.13.2) + optionalDependencies: + rollup: 4.60.1 + '@rollup/plugin-inject@5.0.5(rollup@4.60.1)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.60.1) @@ -8563,6 +8621,12 @@ snapshots: transitivePeerDependencies: - typescript + '@vue/apollo-option@4.2.2(@apollo/client@3.14.1(@types/react@19.2.14)(graphql-ws@6.0.8(crossws@0.3.5)(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vue@3.5.31(typescript@5.9.2))': + dependencies: + '@apollo/client': 3.14.1(@types/react@19.2.14)(graphql-ws@6.0.8(crossws@0.3.5)(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + throttle-debounce: 5.0.2 + vue: 3.5.31(typescript@5.9.2) + '@vue/babel-helper-vue-transform-on@2.0.1': {} '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.29.0)': diff --git a/server/api/graphql.post.ts b/server/api/graphql.post.ts new file mode 100644 index 0000000..f6966d5 --- /dev/null +++ b/server/api/graphql.post.ts @@ -0,0 +1,25 @@ +export default defineEventHandler(async (event) => { + const config = useRuntimeConfig(event); + const body = await readBody(event); + + const cookie = getHeader(event, 'cookie'); + const userId = getHeader(event, 'x-user-id'); + + const response = await fetch(config.backendGraphqlUrl, { + method: 'POST', + headers: { + 'content-type': 'application/json', + ...(cookie ? { cookie } : {}), + ...(userId ? { 'x-user-id': userId } : {}), + }, + body: JSON.stringify(body), + }); + + setResponseStatus(event, response.status); + const contentType = response.headers.get('content-type'); + if (contentType) { + setHeader(event, 'content-type', contentType); + } + + return await response.json(); +});