I'm trying to implement a recursive delete in cloud functions, but the delete function is returning the error [firebase_functions/internal] FirebaseError: Deletion failed. Errors: Failed to fetch documents to delete >= 3 times..
It's very similar to this post, but I tried updating firebase tools and getting a fresh token and no change. I tried getting the debug logs by adding in process.env.DEBUG = true, but I got a type error that it had to be a string - so I changed true to "true" and it doesn't seem to be giving me any logs (unless I just don't know where to look for them).
The function is deploying, although I am getting the message:
[2022-12-08T22:01:07.693Z] Could not find image for function projects/onama-produce/locations/australia-southeast1/functions/recursiveDelete
This is the function:
/* eslint #typescript-eslint/no-var-requires: "off" */
import * as functions from "firebase-functions";
process.env.DEBUG = "true";
const firebaseTools = require("firebase-tools");
/**
* Initiate a recursive delete of documents at a given path.
*
* The calling user must be authenticated.
*
* This delete is NOT an atomic operation and it's possible
* that it may fail after only deleting some documents.
*
* #param {string} data.path the document or collection path to delete.
*/
exports.recursiveDelete = functions
.region("australia-southeast1")
.runWith({
timeoutSeconds: 540,
memory: "2GB",
})
.https.onCall(async (data, context) => {
// Only allow authorised users to execute this function.
if (!(context.auth && context.auth.token)) {
throw new functions.https.HttpsError(
"permission-denied",
"Must be an administrative user to initiate delete."
);
}
const path = data.path;
console.log(
`User ${context.auth.uid} has requested to delete path ${path}`
);
// Run a recursive delete on the given document or collection path.
// The 'token' must be set in the functions config, and can be generated
// at the command line by running 'firebase login:ci'.
try {
await firebaseTools.firestore
.delete(path, {
project: process.env.GCP_PROJECT,
recursive: true,
force: true,
token: process.env.TOKEN,
});
return {
path: path,
};
} catch (err) {
throw new functions.https.HttpsError("internal", String(err));
}
});
And this is the client-side code (written in flutter):
/// Call the 'recursiveDelete' callable function with a path to initiate
/// a server-side delete.
void deleteAtPath(String path) async {
print("delete: deleting at path " + path);
try {
final HttpsCallableResult deleteFnResult = await functions
.httpsCallable('recursiveDelete')
.call(<String, String>{
"path": path,
});
print(deleteFnResult.toString());
} on FirebaseFunctionsException catch (e) {
print("firebase error: " + e.toString() + " for deleting path " + path);
} catch (e) {
print("path delete error " + e.toString() + " for deleting path " + path);
}
}
deleteUserProfile(String _uid) async {
deleteAtPath(_userCollection.doc(_uid).path);
deleteAtPath(_locationsCollection.doc(_uid).path);
deleteEachProduct(productsFromUserProfileQuery(_uid));
return;
}
This is the error:
Failed to fetch documents to delete error
And this is my package.json file:
{
"name": "functions",
"scripts": {
"lint": "eslint --ext .js,.ts .",
"build": "tsc",
"build:watch": "tsc --watch",
"serve": "npm run build && firebase emulators:start --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "16"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^11.3.0",
"firebase-functions": "^4.1.0",
"firebase-tools": "^11.17.0"
},
"devDependencies": {
"#typescript-eslint/eslint-plugin": "^5.12.0",
"#typescript-eslint/parser": "^5.12.0",
"eslint": "^8.9.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.25.4",
"firebase-functions-test": "^0.2.0",
"typescript": "^4.5.4"
},
"private": true
}
Also, I can delete via the command line fine, e.g. firebase firestore:delete users/iALet1LOthcw0Nx6FMgP6nOa3N83 works
I've been battling firebase functions for days, so any help will be greatly appreciated!!
Solution: I figured out how to access the logs and saw that for some reason the project was undefined. I swapped back to getting the project id from the deprecated process.env.GCLOUD_PROJECT instead of process.env.GCP_PROJECT and it works now yay!
Related
The app is deployed successfully but the API routes (/pages/api) are not working as expected, showing below error in the console.
Build is successful and deployed on aws-amplify, I have added environment variables correctly, don't know why this is happening?
Does aws-amplify doesn't support serverless functions writer inside /api folder??
{
"error": {
"message": "connect ECONNREFUSED 127.0.0.1:80",
"name": "Error",
"stack": "Error: connect ECONNREFUSED 127.0.0.1:80\n at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1148:16)",
"config": {
"url": "undefined/campaigns",
"method": "get",
"headers": {
"Accept": "application/json, text/plain, */*",
"User-Agent": "axios/0.21.4"
},
"auth": {},
"transformRequest": [null],
"transformResponse": [null],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1,
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
}
},
"code": "ECONNREFUSED"
}
}
Here is the code
import axios from 'axios';
import Cors from 'cors';
import rateLimit from '../../../utils/rate-limit';
import initMiddleware from '../../../lib/init-middleware';
// Initialize the cors middleware
const cors = initMiddleware(
Cors({
methods: ['POST'],
origin: ['https://www.example.com', /\.example\.com$/],
})
);
const limiter = rateLimit({
interval: 60 * 1000, // 60 seconds
uniqueTokenPerInterval: 500, // Max 500 users per second
});
const handler = async (req, res) => {
await cors(req, res);
if (req.method === 'GET') {
try {
await limiter.check(res, 50, 'CACHE_TOKEN');
const { data } = await axios.get(`${process.env.BASE_URL}/campaigns`, {
auth: {
username: process.env.MAIL_SERVER_USERNAME,
password: process.env.MAIL_SERVER_PASSWORD,
},
});
return res.status(200).json(data);
} catch (error) {
return res.status(429).json({ error });
}
} else {
try {
await limiter.check(res, 10, 'CACHE_TOKEN'); // 10 requests per minute
return res.status(200).json('not allowed');
} catch (err) {
return res.status(429).json({ error: 'Rate limit exceeded' });
}
}
};
export default handler;
I figured out that environment variables are not getting reflected, so did some googling; found this solution and it worked for me.
Add your desired environment variable in the Amplify Console-like normal (steps)
Update (or create) your next.config.js file with the environment variable you added in the Amplify Console. E.g if you created an environment variable named MY_ENV_VAR in the console in step 1) above, then you would add the following:
module.exports = {
env: {
MY_ENV_VAR: process.env.MY_ENV_VAR
}
};
Now after your next build you will be able to reference your environment variable (process.env.MY_ENV_VAR) in your SSR lambdas!
Here is the link: Github
Ran into the same problem Amplify only supports NextJS 11 at the moment. If you go with the default settings it will use the latest NextJS 12 and /api routes wont work, they return a 503 with a cloudformation permission error.
Specify next 11.1.3 in your package.json
https://aws.amazon.com/about-aws/whats-new/2021/08/aws-amplify-hosting-support-next-js-version-11/
I also faced that problem. Amplify does not support v12 of next. Simply downgrade your next.js version in package.json to v1.1.3 and your routes will work as normal.
Best regrets.
Artem Meshkov
I have created a codeceptJS project by following the mobile testing setup steps located here: https://codecept.io/mobile/#setting-up
So far, I'm unable to test any apps via simulator; I instead get the following error:
1) login
I should be able to login with the correct username and password:
>> The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource <<
at Object.getErrorFromResponseBody (node_modules/webdriver/build/utils.js:189:12)
at NodeJSRequest._request (node_modules/webdriver/build/request/index.js:157:31)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
I have verified my appium config using appium-doctor, and there are no issues found.
My codecept.conf.js is as follows:
const path = require('path');
const { setHeadlessWhen } = require('#codeceptjs/configure');
// turn on headless mode when running with HEADLESS=true environment variable
// export HEADLESS=true && npx codeceptjs run
setHeadlessWhen(process.env.HEADLESS);
exports.config = {
tests: './*_test.js',
output: './output',
helpers: {
Appium: {
platform: 'Android',
device: 'emulator',
desiredCapabilities: {
avd: 'Pixel_5_API_28',
app: path.resolve('./sample_apps/Android.apk'),
appActivity: 'com.swaglabsmobileapp.MainActivity'
}
},
},
include: {
I: './steps_file.js'
},
bootstrap: null,
mocha: {},
name: 'appium-codecept-android-POC',
plugins: {
pauseOnFail: {},
retryFailedStep: {
enabled: true
},
tryTo: {
enabled: true
},
screenshotOnFail: {
enabled: true
}
}
}
And here's my package.json as created by codeceptjs init:
{
"name": "appium-codecept-android-POC",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"codeceptjs": "^3.0.7",
"webdriverio": "^7.9.0"
}
}
Finally, my test file is as follows:
Feature('login');
Scenario('I should be able to login with the correct username and password', ({ I }) => {
setTimeout(() => {
I.see('Username');
}, 3000);
I.click('//android.widget.EditText[#content-desc="test-Username"]');
I.fillField('//android.widget.EditText[#content-desc="test-Username"]', 'standard_user');
I.click('//android.widget.EditText[#content-desc="test-Password"]');
I.fillField('//android.widget.EditText[#content-desc="test-Password"]', 'secret_sauce');
I.click('//android.view.ViewGroup[#content-desc="test-LOGIN"]');
I.waitForElement('//android.view.ViewGroup[#content-desc="test-Cart drop zone"]/android.view.ViewGroup/android.widget.TextView', 3)
I.dontSeeElement('//android.view.ViewGroup[#content-desc="test-Error message"]/android.widget.TextView');
});
Scenario('I should not be able to login with an incorrect username or password', ({ I }) => {
setTimeout(() => {
I.see('Username');
}, 3000);
I.click('//android.widget.EditText[#content-desc="test-Username"]');
I.fillField('//android.widget.EditText[#content-desc="test-Username"]', 'bob');
I.click('//android.widget.EditText[#content-desc="test-Password"]');
I.fillField('//android.widget.EditText[#content-desc="test-Password"]', 'secret_sauce');
I.click('//android.view.ViewGroup[#content-desc="test-LOGIN"]');
I.waitForElement('//android.view.ViewGroup[#content-desc="test-Cart drop zone"]/android.view.ViewGroup/android.widget.TextView', 3)
I.dontSeeElement('//android.view.ViewGroup[#content-desc="test-Error message"]/android.widget.TextView');
});
Scenario('I should be able to see details', ({ I }) => {
// login
setTimeout(() => {
I.see('Username');
}, 3000);
I.click('//android.widget.EditText[#content-desc="test-Username"]');
I.fillField('//android.widget.EditText[#content-desc="test-Username"]', 'standard_user');
I.click('//android.widget.EditText[#content-desc="test-Password"]');
I.fillField('//android.widget.EditText[#content-desc="test-Password"]', 'secret_sauce');
I.click('//android.view.ViewGroup[#content-desc="test-LOGIN"]');
I.waitForElement('//android.view.ViewGroup[#content-desc="test-Cart drop zone"]/android.view.ViewGroup/android.widget.TextView', 3)
// should be able to click a label to see details
I.click('(//android.widget.TextView[#content-desc="test-Item title"])[2]');
I.seeElement('//android.view.ViewGroup[#content-desc="test-Description"]/android.widget.TextView[2]');
I.click('//android.view.ViewGroup[#content-desc="test-BACK TO PRODUCTS"]');
});
I'm at a loss here, as I haven't done anything except follow the setup instructions. Executing against ios works; it is only the android execution that fails. Appium is installed and running, env vars are set, etc. Any help would be appreciated, as this could be a deal breaker for me in terms of whether or not I can use codeceptjs. I love the project and really want to use it, but I must be able to test both ios and android native apps.
One final note: If anyone wants to try this config, the app I am using for the above test can be found here: https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/Android.SauceLabs.Mobile.Sample.app.2.7.1.apk
Trying to get a MERN-Stack to Deploy on Heroku I've added MONGOBD_URI as a key in Config Vars on Heroku and added the MongoDB Atlas value.
Heroku is connected directly to the Github repo and not through the Heroku CLI. I have it set to auto-deploy but recently redeployed it manually.
This was the Heroku Build Log:
-----> Node.js app detected
-----> Creating runtime environment
NPM_CONFIG_LOGLEVEL=error
NODE_VERBOSE=false
NODE_ENV=production
NODE_MODULES_CACHE=true
-----> Installing binaries
engines.node (package.json): unspecified
engines.npm (package.json): unspecified (use default)
Resolving node version 12.x...
Downloading and installing node 12.20.0...
Using default npm version: 6.14.8
-----> Restoring cache
Cached directories were not restored due to a change in version of node, npm, yarn or stack
Module installation may take longer for this build
-----> Installing dependencies
Installing node modules
> nodemon#2.0.6 postinstall /tmp/build_b41198ca_/node_modules/nodemon
> node bin/postinstall || exit 0
Love nodemon? You can now support the project via the open collective:
> https://opencollective.com/nodemon/donate
added 290 packages in 6.983s
-----> Build
-----> Caching build
- node_modules
-----> Pruning devDependencies
removed 1 package and audited 289 packages in 2.051s
17 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
-----> Build succeeded!
-----> Discovering process types
Procfile declares types -> (none)
Default types for buildpack -> web
-----> Compressing...
Done: 33M
-----> Launching...
Released v17
https://jms-r0b.herokuapp.com/ deployed to Heroku
The browser(Chrome) only renders Cannot GET / and consol.log()'s GET https://jms-r0b.herokuapp.com/ 404 (Not Found) jms-r0b.herokuapp.com/:1
This is the LINK to my repo.
Here's how my server.js is setup:
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cors = require("cors");
const mongoose = require("mongoose");
const todoRoutes = express.Router();
const PORT = process.env.PORT || 4000;
let Todo = require("./models/todo.model");
app.use(cors());
app.use(bodyParser.json());
// Express data parsing
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static("public"));
const URI = process.env.MONGODB_URI || "mongodb://localhost/todos";
mongoose.connect(
URI,
{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false,
},
(err) => console.log(err)
);
const connection = mongoose.connection;
connection.once("open", () => {
console.log("MongoDB database connection established successfully");
});
todoRoutes.route("/").get((req, res) => {
Todo.find((err, todos) => {
if (err) {
console.log(err);
} else {
res.json(todos);
}
});
});
todoRoutes.route("/:id").get((req, res) => {
let id = req.params.id;
Todo.findById(id, (err, todo) => {
res.json(todo);
});
});
todoRoutes.route("/update/:id").post((req, res) => {
Todo.findById(req.params.id, (err, todo) => {
if (!todo) {
res.status(404).send("data is not found");
} else {
todo.todo_description = req.body.todo_description;
todo.todo_responsible = req.body.todo_responsible;
todo.todo_priority = req.body.todo_priority;
todo.todo_completed = req.body.todo_completed;
todo
.save()
.then((todo) => {
res.json("Todo updated!");
})
.catch((err) => {
res.status(400).send("Update not possible");
});
}
});
});
todoRoutes.route("/add").post((req, res) => {
let todo = new Todo(req.body);
todo
.save()
.then((todo) => {
res.status(200).json({ todo: "todo added successfully" });
})
.catch((err) => {
res.status(400).send("adding new todo failed");
});
});
todoRoutes.route("/delete/:id").delete((req, res) => {
Todo.findByIdAndRemove(req.params.id, (err, todo) => {
if (!todo) {
res.status(404).send("data is not found");
} else {
res.status(200).json({
msg: todo,
});
}
});
});
app.use("/todos", todoRoutes);
app.listen(PORT, () => {
console.log("http://localhost:" + PORT);
console.log(".env.PORT:" + process.env.PORT);
});
and this is how my root package.json looks:
{
"name": "rob",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start:dev": "cd client && npm start",
"client": "cd client && npm run start",
"start": "concurrently \"node server/server.js\" \"npm run client\"",
"dev": "concurrently \"nodemon server/server.js\" \"npm run client\""
},
"repository": {
"type": "git",
"url": "git+https://github.com/WasteOfADrumBum/r0b.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/WasteOfADrumBum/r0b/issues"
},
"homepage": "https://github.com/WasteOfADrumBum/r0b#readme",
"dependencies": {
"bcryptjs": "^2.4.3",
"concurrently": "^5.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-mongo-sanitize": "^2.0.0",
"express-rate-limit": "^5.1.3",
"helmet": "^4.2.0",
"hpp": "^0.2.3",
"ini": "^2.0.0",
"mongoose": "^5.10.13",
"nodemon": "^2.0.6",
"react": "^17.0.1",
"react-cool-onclickoutside": "^1.5.8",
"react-dom": "^17.0.1",
"validator": "^12.0.0",
"xss-clean": "^0.1.1"
},
"devDependencies": {
"dotenv": "^8.2.0"
}
}
I could use a little help. I've deployed 5 other MERN-Stacks with a MongoDB Atlas or JawsDB connection with little to no issues and this one is just throwing me for a loop.
PLEASE HELP!!!
Everyone does things differently, but I think the error is in your connection to MongDB- are you establishing a connection OK or no?
If no connection - You said "I've added MONGOBD_URI as a key in Config Vars on Heroku and added the MongoDB Atlas value." But I see that "config Vars" is not used in your code- you used the .env as you should to keep your connection password secure...so may just need to add your connection URI to the .env file, and you are good to go?
If your connection is fine, then I would look to your server and suggest to test if the problem is solved using the standard routing:
app.route("/")
.get(function(req, res) {
res.sendFile(process.cwd() + "/views/index.html");
})
I'm trying to incorporate Stripe into an iOS app using Firebase Functions. I'm following the Stripe documentation for "Accepting a payment" in Swift with Node backend. I first did npm install --save stripe. That finished with no errors. Then I did npm install. My index.js looks like this so far:
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
const functions = require('firebase-functions');
const stripe = require('stripe')('sk_test_...');
const paymentIntent = await stripe.paymentIntents.create({
amount: 1099,
currency: 'usd',
});
const clientSecret = paymentIntent.client_secret
When running firebase deploy I get: 11:29 error Parsing error: Unexpected token stripe. Line 11 char 29 in my file is the stripe.paymentIntents...
This is my first time using Firebase Functions or Stripe, so I'm at a loss here. I appreciate any help.
EDIT:
Here's the contents of my package.json file.
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"lint": "eslint .",
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "8"
},
"dependencies": {
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.6.1",
"stripe": "^8.55.0"
},
"devDependencies": {
"eslint": "^5.12.0",
"eslint-plugin-promise": "^4.0.1",
"firebase-functions-test": "^0.2.0"
},
"private": true
}
This error is because on the cloud environment the stripe library is not installed before you require it.
npm install does install the dependencies but in your local environment, to install them on the Cloud Functions envirornment you need to edit the package.json file from the Cloud Function.
This to add the dependencies that it will be required by the function.
This is done by adding the dependency section to the package.json file
It will lok something like:
{
"name": "sample-name",
"version": "0.0.1",
"dependencies": {
"escape-html": "^1.0.3",
"stripe": "^8.24.0"
}
}
EDIT
With this code it works on Cloud functions:
const stripe = require('stripe')('<My Secret Key>');
exports.helloWorld = (req, res) => {
let paymentIntent = null;
paymentIntent = stripe.paymentIntents.create({
amount: 2000,
currency: 'usd',
description: 'My first payment',
});
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
Apparently the issue was the await because HTTP Cloud Functions work on a Synchronous way
I see this question is old but I ran into this exact issue and couldn't find an answer.
I had my backend functions folder nested within my overall app and I had let firebase generate some files for me, including a lint configuration. So, I ended up with two lint config files in my project total. The firebase generated one tried to enforce double quotes and the one I created tried to enforce single quotes. I ended up just deleting the generated lint config and it works fine now.
package.json
{
//some other config
"repository": "git#gitintsrv.domain.com/UserName/RepoName",
"scripts": {
"build": "build --win",
"ship": "build --win -p always"
}
}
electron-builder.yml
appId: com.xorchat.app.windows
publish:
provider: github
token: some_token
electron.js
const { app, BrowserWindow, ipcMain } = require('electron');
const { autoUpdater } = require("electron-updater");
let win; // this will store the window object
// creates the default window
function createDefaultWindow() {
win = new BrowserWindow({ width: 900, height: 680 });
win.loadURL(`file://${__dirname}/src/index.html`);
win.on('closed', () => app.quit());
return win;
}
// when the app is loaded create a BrowserWindow and check for updates
app.on('ready', function() {
createDefaultWindow()
autoUpdater.checkForUpdates();
});
// when the update has been downloaded and is ready to be installed, notify the BrowserWindow
autoUpdater.on('update-downloaded', (info) => {
win.webContents.send('updateReady')
});
// when receiving a quitAndInstall signal, quit and install the new version ;)
ipcMain.on("quitAndInstall", (event, arg) => {
autoUpdater.quitAndInstall();
})
When i am running npm run build i am receiving this error.
Error: Cannot detect repository by .git/config. Please specify "repository" in the package.json (https://docs.npmjs.com/files/package.json#repository).
Please see https://electron.build/configuration/publish
Where is the error?
I know it's probably too late, but in case you end up here as I did, here's how I solved it:
Add this to your package.json
"build": {
"publish": [{
"provider": "github",
"host": "github.<<DOMAIN>>.com",
"owner": "<<USER>>",
"repo": "<<NAME OF YOUR REPO (ONLY THE NAME)>>",
"token": "<<ACCESS TOKEN>>"
}]
}
I think the issue is that electron cannot parse corporate github urls, or something.
*********** EDIT:
Make a electron-builder.yml in the root folder, with the following content
appId: com.corporate.AppName
publish:
provider: github
token: <<ACCESS TOKEN>>
host: github.corporate.com
owner: <<User/ Org>>
repo: <<repo name>>
Don't forget to include this file on your .gitignore
This use to be a specific issue with Electron Builder 19x, and it has since been fixed:
https://github.com/electron-userland/electron-builder/issues/2785