how to replace strings with .env (dotenv-flow) with svelte-kit? - sveltekit

Inside svelte.config.js I have this:
preprocess: autoPreprocess({
replace: [
['API_ENDPOINT', JSON.stringify(process.env.API_ENDPOINT)]
]
}),
It should replace the string "API_ENDPOINT" but it isn't.
Here is how I'm using it:
async function api(url: string, body = {}, opts = {}) {
const endpoint = 'API_ENDPOINT';
console.log(endpoint);
const res = await fetch(endpoint + url, {
method: 'POST',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify(body)
});
if (!res.ok) {
const err = await res.json();
throw (err || res.statusText);
}
return opts.raw ? await res.text() : await res.json();
}
export default api;
All i get is http://localhost:3000/API_ENDPOINT/subscriptions

in your svelte.config.js file, instead of
autoPreprocess({
replace: [['process.env.NODE_ENV', JSON.stringify(process.env.NODE_ENV)]],
});
use
import sveltePreprocess from 'svelte-preprocess'
sveltePreprocess({
replace: [['process.env.NODE_ENV', JSON.stringify(process.env.NODE_ENV)]],
});
It seems to me that autoPreprocess was deprecated but the README docs were not correctly updated.
You also may want to consider doing one of the following:
use process.env.API_ENDPOINT directly
const endpoint = process.env.API_ENDPOINT;
create a separate javascript function to handle environment variables
something like this
envVars.js
import dotenv from 'dotenv-flow';
import path from 'path';
dotenv.config({
path: path.resolve(__dirname, `path-to-your-(.env)-file`),
});
export const getEnvVar = (key) => process.env[key];
and use it like this:
import { getEnvVar } from 'path-to-envVars'
const endpoint = getEnvVar('API_ENDPOINT');
if you're already using Vite as your build tool
Add the variables in a .env file like so:
VITE_YOUR_ENV_VAR_GOES_HERE=bar
in your case:
VITE_API_ENDPOINT=your_value
then import them in a separate javascript or typescript file
envVars.js
export const envVars = {
API_ENDPOINT: import.meta.env.VITE_API_ENDPOINT
};
and then import envVars and use it as so:
import { envVars } from 'path-to-envVars.js'
and now you can read your environment variable like this:
envVars.myVariable
or, in your case
const endpoint = envVars.API_ENDPOINT

Related

Google OAuth components must be used within GoogleOAuthProvider

I want to build my next js project in which i am using
https://www.npmjs.com/package/#react-oauth/google
but when I build it i get the following :
this is layout.js and in _app.js I have all the components wrapped in GoogleOAuthProvider
import { GoogleLogin } from '#react-oauth/google';
import {FcGoogle} from "react-icons/Fc"
import { useGoogleLogin } from '#react-oauth/google';
export default function Layout({ children }) {
const client_id = ""
const responseGoogle = (response) => {
console.log(response);
}
CUTTED (NOT RELEVANT)
const login = useGoogleLogin({
onSuccess: codeResponse => {
const { code } = codeResponse;
console.log(codeResponse)
axios.post("http://localhost:8080/api/create-tokens", { code }).then(response => {
const { res, tokens } = response.data;
const refresh_token = tokens["refresh_token"];
const db = getFirestore(app)
updateDoc(doc(db, 'links', handle), {
refresh_token : refresh_token
})
updateDoc(doc(db, 'users', useruid), {
refresh_token : refresh_token
}).then(
CUTTED (NOT RELEVANT)
)
}).catch(err => {
console.log(err.message);
})
},
onError: errorResponse => console.log(errorResponse),
flow: "auth-code",
scope: "https://www.googleapis.com/auth/calendar"
});
return (
<>
CUTTED (NOT RELEVANT)
</>
)
}
Everything works perfect in dev mode but it does not want to build
I've faced this issue too. So I use 'GoogleLogin' instead of 'useGoogleLogin', then you can custom POST method on 'onSuccess' property.
import { GoogleLogin, GoogleOAuthenProvider} from '#react-oauth/google';
return(
<GoogleOAuthProvider clientId="YOUR CLIENT ID">
<GoogleLogin
onSuccess={handleLogin}
/>
</GoogleOAuthProvider>
The async function will be like...
const handleLogin = async = (credentialResponse) => {
var obj = jwt_decode(credentialResponse.credential);
var data = JSON.stringify(obj);
console.log(data);
const data = {your data to send to server};
const config = {
method: 'POST',
url: 'your backend server or endpoint',
headers: {},
data: data
}
await axios(config)
}
Spending whole day, this solve me out. Just want to share.
You have to wrap your application within GoogleOAuthProvider component. Please keep in mind that you will need your client ID for this.
import { GoogleOAuthProvider } from '#react-oauth/google';
<GoogleOAuthProvider clientId="<your_client_id>">
<SomeComponent />
...
<GoogleLoginButton onClick={handleGoogleLogin}/>
</GoogleOAuthProvider>;

POST https://ipfs.infura.io:5001/ipfs/api/v0/add?stream-channels=true&progress=false 403 (Forbidden). HTTPError: ipfs method not supported

Below is how i create the client.
import { create as ipfsHttpClient } from 'ipfs-http-client';
const projectId = 'xx';
const projectSecret = 'xx';
const auth = `Basic ${Buffer.from(`${projectId}:${projectSecret}`).toString('base64')}`;
const options = {
host: 'ipfs.infura.io',
protocol: 'https',
port: 5001,
apiPath: '/ipfs/api/v0',
headers: {
authorization: auth,
},
};
const dedicatedEndPoint = 'https://xx.infura-ipfs.io';
const client = ipfsHttpClient(options);
Here is the function that will be called from front-end that takes in a file, uploads to IPFS and returns URL. Please note that the "ipfsHTTPClient()" is just the create function.
const uploadToIPFS = async (file) => {
try {
const added = await client.add({ content: file });
const url = `${dedicatedEndPoint}${added.path}`;
return url;
} catch (error) {
console.log('Error uploading file to IPFS: ', error);
}
};
The error I am getting is
POST https://ipfs.infura.io:5001/ipfs/api/v0/add?stream-channels=true&progress=false 403 (Forbidden)
When i console log the error it says the IPFS method is not supported.
On the IPFS forum, i have seen someone say that add function does not work anymore but i have also seen people using it and it working. Im not sure whats wrong here.
Here is how i call the function on front-end
const { uploadToIPFS } = useContext(NFTContext);
// function called from useDropzone
const onDrop = useCallback(async (acceptedFile) => {
const url = await uploadToIPFS(acceptedFile[0]);
setFileUrl(url);
}, []);
All the above code is correct and the error was from Next.js
Needed to add
images: {
domains: ['xx.infura-ipfs.io'],
},
to the next.config.js file.
I have resolved this problem
so make sure first you have installed buffer
npm install --save buffer
then import it in your file
import {Buffer} from 'buffer';
then it works successfully
import { create } from "ipfs-http-client";
import { Buffer } from "buffer";
const projectId = "YOUR_INFURA_PROJECT_ID";
const projectSecret = "YOUR_INFURA_PROJECT_SECRET";
const auth = `Basic ${Buffer.from(`${projectId}:${projectSecret}`).toString(
"base64"
)}`;
const client = create({
host: "ipfs.infura.io",
port: 5001,
protocol: "https",
apiPath: "/api/v0",
headers: {
authorization: auth,
},
});
const uploadFiles = async (e) => {
e.preventDefault();
setUploading(true);
if (text !== "") {
try {
const added = await client.add(text);
setDescriptionUrl(added.path);
} catch (error) {
toast.warn("error to uploading text");
}
}

How do I get access to a token in .env to fetch data in Next.js?

I am creating an app (Next.js v9.4.2 / React.js) that requires x-auth tokens to be sent to the backend.
I have a .env file where the token is defined; a next.config.js file where I listed the token under env: {}; and a .getInitialProps fn where I am trying to use the token via process.env.TOKEN (see below).
The fetch fails (returns "Internal Server Error") when I reference process.env.TOKEN, but NOT when I hardcode the token as a string:
.env
TOKEN=12345-6789
next.config.js
const withSass = require('#zeit/next-sass')
const withCSS = require("#zeit/next-css")
require('dotenv').config()
module.exports = withCSS(withSass({
env: {
TOKEN: process.env.TOKEN
}
}));
Component
Page.getInitialProps = async function (context) {
const id = context.query.id ? context.query.id : {}
const res = await fetch(`https://url/${id}/`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'x-auth-token': `${process.env.TOKEN}`,
}
})
let raw = await res.json();
return {
data: raw
}
}
depends on which NextJs version you are using. latest nextjs version has built-in support for environment variables.
https://nextjs.org/docs/basic-features/environment-variables
if you are using older version then you can configure next.config.js like this:
require("dotenv").config();
module.exports = withImages(withCSS(withSass({
webpack: config => {
/**
* Returns environment variables as an object
*/
const env = Object.keys(process.env).reduce((acc, curr) => {
acc[`process.env.${curr}`] = JSON.stringify(process.env[curr]);
return acc;
}, {});
// Fixes npm packages that depend on `fs` module
config.node = {
fs: 'empty'
};
/** Allows you to create global constants which can be configured
* at compile time, which in our case is our environment variables
*/
config.plugins.push(new webpack.DefinePlugin(env));
return config;
},
})));
Use serverRuntimeConfig parameter to access the env variables on server side.
Need to do like this:
next.config.js
const withSass = require('#zeit/next-sass')
const withCSS = require("#zeit/next-css")
require('dotenv').config()
module.exports = withCSS(withSass({
serverRuntimeConfig: {
TOKEN: process.env.TOKEN
}
}));
Refer: https://nextjs.org/docs/api-reference/next.config.js/runtime-configuration

Setting axios base url dynamically

i am getting base url from asyncstorage and i want to set it as base url for axios instance.
currently iam following below code but it is not working
const axiosInstance = axios.create({
// baseURL: API_END_POINTS.BASE_URL+AsyncStorage.getItem('dealerNo'),
});
axiosInstance.defaults.timeout = 10000000;
axiosInstance.interceptors.request.use(
async config => {
axiosInstance.defaults.baseURL=await getBaseUrl();
return config;
},
error => Promise.reject(error)
);
export async function getBaseUrl() {
var No = await AsyncStorage.getItem('dealerNo')
var value =API_END_POINTS.BASE_URL+ No;
return value;
}
axiosInstance.defaults.headers.post['Content-Type'] = 'application/json';
export default axiosInstance;
iam importing the above axiosInstance to make get or post calls.
Make a function that returns the Axios instance with a dynamic base URL, like this:
custom-axios.js
import axios from 'axios';
const customAxios = (dynamicBaseURL) => {
// axios instance for making requests
const axiosInstance = axios.create({
baseURL: dynamicBaseURL
});
return axiosInstance;
};
export default customAxios;
and then use the instance as follows:
import axios from './custom-axios'
...
const axios1 = axios('/some-url');
const axios2 = axios('/another-url');
axios1.get('/base-is-some-url');
axios2.get('/base-is-another-url');
...
Instaed of axiosInstance.defaults.baseURL, config.baseURL = await getBaseURL(); is enough and should work.
At least it sets baseURL corrrectly in my side.

React TypeScript: Custom Fetch Hook

I'm trying to write a custom fetch hook, but I guess im missing something.
import React, { useContext } from 'react';
import { Context } from "../components/context";
const fetchHook = async(url: string, bearer: string, method: string, body: any ) => {
const { global } = useContext(Context) as {global: any};
let headers = {'cache-control': 'no-cache', 'Content-Type': 'application/json' };
if (bearer) headers = {...headers, ...{'Authorization': bearer}}
if (method === 'GET') return await fetch(global.apiUrl + url, {method, headers});
else return await fetch(global.apiUrl + url, {method, headers, body});
}
export { fetchHook }
The error im getting is Line 5: React Hook "useContext" is called in function "fetchHook" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks
UPDATE:
import React, { useContext } from 'react';
import { Context } from "../components/context";
const useFetch = (url: string, bearer: string, method: string, body: any) => {
const { global } = useContext(Context) as {global: any};
let headers = {'cache-control': 'no-cache', 'Content-Type': 'application/json' };
if (bearer) headers = {...headers, ...{'Authorization': bearer}}
const [response, setResponse] = React.useState(null);
const [error, setError] = React.useState(null);
const apiUrl = global.apiUrl;
React.useEffect(() => {
const fetchData = async () => {
try {
let res;
if (method === 'GET') res = await fetch(apiUrl + url, {method, headers});
else res = await fetch(global.apiUrl + url, {method, headers, body});
setResponse(await res.json());
} catch (error) {
setError(error);
}
};
fetchData();
}, []);
return { response, error };
};
export { useFetch }
The only warning I get now I about a missing dependency warning but I'm not sure how to fix it. Should I be passing all the dependencies into the square brackets of useEffect()?? I'm just not sure?
Line 27: React Hook React.useEffect has missing dependencies: 'apiUrl', 'body', 'global.apiUrl', 'headers', 'method', and 'url'. Either include them or remove the dependency array
You are getting this warning because according to the Rules of hooks, a custom hook name must start with use.
As mentioned the docs of custom hooks
A custom Hook is a JavaScript function whose name starts with ”use”
and that may call other Hooks.
You won't receive the error if you rename the hook to
const useFetchHook = async(url: string, bearer: string, method: string, body: any ) => {
const { global } = useContext(Context) as {global: any};
let headers = {'cache-control': 'no-cache', 'Content-Type': 'application/json' };
if (bearer) headers = {...headers, ...{'Authorization': bearer}}
if (method === 'GET') return await fetch(global.apiUrl + url, {method, headers});
else return await fetch(global.apiUrl + url, {method, headers, body});
}
export { useFetchHook }
Also one thing you must keep in mind is that if you execute async code within the custom hook directly, it will be executed on every render. A better way is to maintain state and fetch the data within useEffect and update the state when the data is received.

Resources