How to replace Deno.env calls when bundling - deno

I'm attempting to build a script to be run in the browser and I wish to replace Deno.env.get(...) calls with the actual value I'm passing.
Does Deno have a built in way to handle this?
My expectation was something like:
// mod.ts
console.log(Deno.env.get('MY_VAR'));
# in terminal
MY_VAR=hello deno bundle --allow-env mod.ts bundle.js
// bundle.js
console.log("hello") // this doesn't happen.. still Deno.env.get('MY_VAR')

Deno has no built-in way to replace Deno.env.get(...) when bunding.
So I wrote my own build script that only handles strings.
// build.ts
interface BuildParams {
input: string;
output: string;
env: Record<string, string>;
}
const build = async ({ input, output, env }: BuildParams) => {
const process = Deno.run({
cmd: [
"deno",
"bundle",
input,
output,
],
});
await process.status();
const bundle = await Deno.readTextFile(output);
const parsedBundle = Object.entries(env).reduce(
(acc, [key, value]) => {
const searchString = `Deno\\.env\\.get\\("${key}"\\)`;
const regExp = new RegExp(searchString, "g");
acc = acc.replace(regExp, `"${value}"`);
return acc;
},
bundle,
);
await Deno.writeTextFile(output, parsedBundle);
};
export default build;
And an example usage:
await build({
input: Deno.cwd() + "/lib/mod.ts",
output: Deno.cwd() + "/public/javascript/build/upc-bundle.js",
env: {
SERVER_URL: Deno.env.get("SERVER_URL") ?? "ws://127.0.0.1:3012",
}
});

Related

Cant delete item from sqlite by qraphql mutation

I'm learning to write apollo server by following a graphql tutorial https://www.howtographql.com/graphql-js/3-a-simple-mutation/ but when I try to write a delete mutation and use it in the GraphQL Playground, I get null after executing, and if I check data in the Prisma studio there is no change
mutation delete and server response
I'm sure that there are many items for deleting also with current id which I used for delete
this is my code
prisma studio data
const {ApolloServer} = require('apollo-server');
const fs = require('fs');
const path = require('path');
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const resolvers = {
Query : {
info: () => 'Info text',
feed: async (parent, args, context, info) => {
return context.prisma.link.findMany()
},
},
Mutation : {
post: (parent, args, context, info) => {
const newLink = context.prisma.link.create({
data: {
url: args.url,
description: args.description,
},
})
return newLink
},
delete: (parent, args, context, info) => {
const deleteLink = context.prisma.link.delete({
data: {
id: args.id
}
})
return deleteLink
}
}
}
const server = new ApolloServer({
typeDefs: fs.readFileSync(
path.join(__dirname, 'schema.graphql'),
'utf8'
),
resolvers,
context: {
prisma,
}
})
server
.listen()
.then(({url})=>
console.log(`Server is running on ${url}`)
);
I gat it. Instead data use where. Prisma supports filtering with where query option.
async function deleteLink(parent, args, context, info){
const deleteLink = context.prisma.link.delete({
where: {
id: +args.id,
}
})
}

How to combine next-i18next into an existing getServerSideProps function in NextJS

I have a Next page that uses next-i18next in a getServerSideProps and I have another page that uses getServerSideProps to pull data from MongoDB. Both work correctly.
I would like to be able to add next-i18next to the function that connects to Mongo (basically combine the getServerSideProps functions), but I'm getting the error:
nexti18n-next Error: Initial locale argument was not passed into serverSideTranslations'
The first page's getServerSideProps function that connects to next-i18n
export const getServerSideProps = withAuthUserSSR({ whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,})(async ({ locale, }) => {
return {
props: {
...(await serverSideTranslations(locale,
[
'language-file',
...
]
)),
},
};
})
The getServerSideProps function in the second page that pulls data from Mongo:
export const getServerSideProps = withAuthUserSSR({ whenUnauthed: AuthAction.REDIRECT_TO_LOGIN })(async (context) => {
const username = context.params.var[0];
const userId = context.params.var[2];
const { db } = await connectToDatabase();
const pipeline = [
...
]
const postdata = await db.collection('posts').aggregate(pipeline).toArray();
return {
props: {
userId,
username,
postdata: JSON.parse(JSON.stringify(postdata)),
},
};
})
Is it possible to 'add' the next-i18next code to the second function? It seems to me to be an issue with the different way 'locale' and 'context' are defined in each function. I have tried lots of combinations of both but end up messing up either the mongo query or the translations.
This is how I thought it would be done:
export const getServerSideProps = withAuthUserSSR({ whenUnauthed: AuthAction.REDIRECT_TO_LOGIN })(async (context,{ locale, }) => {
const username = context.params.var[0];
const userId = context.params.var[2];
const { db } = await connectToDatabase();
const pipeline = [
...
]
const postdata = await db.collection('posts').aggregate(pipeline).toArray();
return {
props: {
...(await serverSideTranslations(locale,
[
'language-files',
...
]
)),
userId,
username,
postdata: JSON.parse(JSON.stringify(postdata)),
},
};
})
Many thanks for any possible help!

App working locally but not on production: TypeError: Cannot read property 'titulo_categoria' of undefined

I'm trying to deploy an app using Prismic as CMS and everything works perfectly locally, but once I deploy to vercel I get the error:
19:09:51.850 | TypeError: Cannot read property 'titulo_categoria' of undefined
There seems to be something wrong when it tries to get the data from Prismic.
My code is the following:
import {getAllCategorias, getCategory2} from '../../lib/api';
export default function Index({cat}) {
return <>{cat.titulo_categoria[0].text}</>;
}
export async function getStaticProps({params}) {
const data = await getCategory2(params.slug);
return {
props: {
cat: data?.categorias ?? null,
},
};
}
export async function getStaticPaths() {
const allPosts = await getAllCategorias();
return {
paths: allPosts?.map(({node}) => `/test/${node._meta.uid}`) || [],
fallback: true,
};
}
And the API code that gets data from Prismic is:
import Prismic from 'prismic-javascript';
const REPOSITORY = process.env.PRISMIC_REPOSITORY_NAME;
const REF_API_URL = `https://${REPOSITORY}.prismic.io/api/v2`;
const GRAPHQL_API_URL = `https://${REPOSITORY}.prismic.io/graphql`;
// export const API_URL = 'https://your-repo-name.cdn.prismic.io/api/v2'
export const API_TOKEN = process.env.PRISMIC_API_TOKEN;
export const API_LOCALE = process.env.PRISMIC_REPOSITORY_LOCALE;
export const PrismicClient = Prismic.client(REF_API_URL, {
accessToken: API_TOKEN,
});
async function fetchAPI(query, {previewData, variables} = {}) {
const prismicAPI = await PrismicClient.getApi();
const res = await fetch(
`${GRAPHQL_API_URL}?query=${query}&variables=${JSON.stringify(variables)}`,
{
headers: {
'Prismic-Ref': previewData?.ref || prismicAPI.masterRef.ref,
'Content-Type': 'application/json',
'Accept-Language': API_LOCALE,
Authorization: `Token ${API_TOKEN}`,
},
}
);
if (res.status !== 200) {
console.log(await res.text());
throw new Error('Failed to fetch API');
}
const json = await res.json();
if (json.errors) {
console.error(json.errors);
throw new Error('Failed to fetch API');
}
return json.data;
}
export async function getCategory2(slug) {
const data = await fetchAPI(
`
query CategoryBySlug($slug: String!, $lang: String!) {
categorias(uid: $slug, lang: $lang) {
titulo_categoria
_meta {
uid
}
}
}
`,
{
variables: {
slug,
lang: API_LOCALE,
},
}
);
return data;
}
Any idea what's wrong with this? I been trying to figure it out for the whole day without any luck
Perhaps you already checked that, but since you mentioned everything works locally and not on Vercel are you sure your environment variables are set there? Especially PRISMIC_API_TOKEN since it appears you're relying on it to query the API?
Also I'm a bit worried about that part of the code:
props: {
cat: data?.categorias ?? null,
}
...where you might be sending a null value to your Index component resulting in your error, I'd try that instead:
props: {
cat: data?.categorias ?? {},
}
...plus using the safe navigation operator (?.) on the Index component?
Let me know how it goes!

Not able to assert H1 text

I am trying to write something to check that "About Us" exist on the following page: https://www.aggrowth.com/en-us/about-us and I am just hitting a wall. It shouldn't be difficult, but I have spent too much time on this.
We are using Gherking-testcafe: https://www.npmjs.com/package/gherkin-testcafe
NPM: 6.9.0
TestCafe: 1.0.1
Gherking-Testcafe: 2.0.0
I tried (All below was tested isolation, aka all of the different t.expect was run by themselves):
const h1AboutUs = await Selector('h1');
await t.expect(h1AboutUs.innerText).eql('About Us');
await t.expect(h1AboutUs.innerText).contains('About Us');
await t.expect(h1AboutUs.value).eql('About Us');
await t.expect(Selector('html').textContent).contains('About Us');
and tried removing the await:
const h1AboutUs = Selector('h1');
await t.expect(h1AboutUs.innerText).eql('About Us');
await t.expect(h1AboutUs.innerText).contains('About Us');
await t.expect(h1AboutUs.value).eql('About Us');
await t.expect(Selector('html').textContent).contains('About Us');
It works if I do:
This is the test I have:
When("I see the page load", async t => {
const h1AboutUs = await Selector('h1');
await t.expect(h1AboutUs.visible).eql(true);
await t.hover(h1AboutUs);
await t.expect(h1AboutUs.value).contains('about');
console.log(h1AboutUs.value);
});
My testCafe runner:
const createTestCafe = require('gherkin-testcafe');
const fs = require('fs');
const reportPath = './frontend/src/tests/test-reports'
let testcafe = null;
function readTestCafeConfig() {
configData = fs.readFileSync('.testcaferc.json', 'utf8');
const js = JSON.parse(configData);
return getJSONValues(js, 'src');
};
function getJSONValues(obj, key) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (i === key) {
objects.push(obj[i]);
}
}
return objects;
}
createTestCafe('localhost', 1337, 1338)
.then(tc => {
testcafe = tc;
const runner = testcafe.createRunner();
const src = readTestCafeConfig();
return runner
.src([src])
.browsers('chrome')
.reporter(['spec', {
name: 'json',
output: `${reportPath}/report/report.json`
},
{
name: 'xunit',
output: `${reportPath}/report/report.xml`
}])
// .video(`${reportPath}/videos`, {
// singleFile: true,
// failedOnly: true,
// pathPattern: '${USERAGENT}/${FILE_INDEX}.mp4'
// })
.tags('#aboutUs')
.run();
})
.then(failedCount => {
console.log('Tests failed: ' + failedCount);
testcafe.close();
});
The error I get in the console is:
1) Selector cannot implicitly resolve the test run in context of which it should be executed. If you need to call Selector from the Node.js API callback, pass the test controller manually via
Selector's `.with({ boundTestRun: t })` method first. Note that you cannot execute Selector outside the test code.
Browser: Chrome 74.0.3729 / Mac OS X 10.14.4
12 |});
13 |
14 |When("I see the page load", async t => {
15 | const h1AboutUs = await Selector('h1');
16 |
> 17 | await t.expect(h1AboutUs.visible).eql(true);
18 | await t.hover(h1AboutUs);
19 | await t.expect(h1AboutUs.value).contains('about');
20 | console.log(h1AboutUs.value);
21 |});
22 |
I expect not to see this error msg
You need to implement Selector binding to TestCafe's test controller for such tests. Please have a look at the following example:
const { Given, Then, Before } = require('cucumber');
const { Selector: NativeSelector } = require('testcafe');
const Selector = (input, t) => {
return NativeSelector(input).with({ boundTestRun: t });
};
Before('#aboutHook', async () => {
console.log('Running AGI test.');
});
Given("I am open AGI page", async t => {
await t.navigateTo('https://www.aggrowth.com/en-us/about-us');
});
Then("I should see check about us", async t => {
const h1AboutUs = Selector('h1', t);
//or const h1AboutUs = await Selector('h1', t); if you need
await t
.expect(h1AboutUs.visible).eql(true)
.hover(h1AboutUs);
});
You can get more examples in the gherkin-testcafe repository.
Note also that the h1 element doesn't have a property value.
You can learn more about TestCafe Selectors and their properties in TestCafe Docs.

Firebase Functions get files from storage

I have to send a file to an API, therefor I have to use fs.readFileSync(). After uploading the picture to the storage, I am calling my function to execute the API call. But I cannot get the file from the storage. This is a section of the code, which always gets null in the result. I tried also to .getFiles() without a parameter and then I got all files but I dont want to filter them by iteration.
exports.stripe_uploadIDs = functions.https //.region("europe-west1")
.onCall((data, context) => {
const authID = context.auth.uid;
console.log("request is authentificated? :" + authID);
if (!authID) {
throw new functions.https.HttpsError("not authorized", "not authorized");
}
let accountID;
let result_fileUpload;
let tempFile = path.join(os.tmpdir(), "id_front.jpg");
const options_id_front_jpeg = {
prefix: "/user/" + authID + "/id_front.jpg"
};
const storageRef = admin
.storage()
.bucket()
.getFiles(options_id_front)
.then(results => {
console.log("JPG" + JSON.stringify(results));
// need to write this file to tempFile
return results;
});
const paymentRef = storageRef.then(() => {
return admin
.database()
.ref("Payment/" + authID)
.child("accountID")
.once("value");
});
const setAccountID = paymentRef.then(snap => {
accountID = snap.val();
return accountID;
});
const fileUpload = setAccountID.then(() => {
return Stripe.fileUploads.create(
{
purpose: "identity_document",
file: {
data: tempFile, // Documentation says I should use fs.readFileSync("filepath")
name: "id_front.jpg",
type: "application/octet-stream"
}
},
{ stripe_account: accountID }
);
});
const fileResult = fileUpload.then(result => {
result_fileUpload = result;
console.log(JSON.stringify(result_fileUpload));
return result_fileUpload;
});
return fileResult;
});
Result is:
JPG[[]]
You need to download your file from a bucket to your local function context env.
After your Firebase function start executing you can call the below:
More or less the below should work, just tweak to your needs. Call this within you .onCall context, you get the idea
import admin from 'firebase-admin';
import * as path from 'path';
import * as os from 'os';
import * as fs from 'fs';
admin.initializeApp();
const { log } = console;
async function tempFile(fileBucket: string, filePath: string) {
const bucket = admin.storage().bucket(fileBucket);
const fileName = 'MyFile.ext';
const tempFilePath = path.join(os.tmpdir(), fileName);
const metadata = {
contentType: 'DONT_FORGET_CONTEN_TYPE'
};
// Donwload the file to a local temp file
// Do whatever you need with it
await bucket.file(filePath).download({ destination: tempFilePath });
log('File downloaded to', tempFilePath);
// After you done and if you need to upload the modified file back to your
// bucket then uploaded
// This is optional
await bucket.upload(tempFilePath, {
destination: filePath,
metadata: metadata
});
//free up disk space by realseasing the file.
// Otherwise you might be charged extra for keeping memory space
return fs.unlinkSync(tempFilePath);
}

Resources