FIrebase Firestore onCreate Cloud Function: Object unidentified [duplicate] - node.js

I'm building a cloud function that will use the Stripe API to process payments. This is within a firebase project. When I run firebase deploy I get the error "Object is possible 'undefined'" const existingSource = customer.sources.data.filter( (s) => s.id === source).pop();
I'm not sure how to resolve this.
Here is my xxx.ts where getorCreateCustomer exists
/** Read the stripe customer ID from firestore, or create a new one if missing */
export const getOrCreateCustomer = async(uid: string) => {
const user = await getUser(uid);
const customerId = user && user.stripeCustomerId;
//if missing customerId, create it
if (!customerId) {
return createCustomer(uid);
}
else {
return stripe.customers.retrieve(customerId);
}
}

Based on the definitions and contents of your functions, TypeScript is unable to infer the return type of getOrCreateCustomer. It is making the assumption that it could return undefined, and its strict mode is calling you out on the fact that you could be referencing a property on an undefined object, which would result in an error at runtime.
What you need to do is declare the return type to be something that can't possibly be undefined, and make sure the code in the body of the function is correct on that guarantee (otherwise you'll get a new error).
If you can't do that (but you really should do that), you might want to instead disable strict mode in your tsconfig.json file, since that is what's enforcing this level of correctness in your code.
I suggest the first option, even if you have to write more lines of code, as it's a better use of TypeScript's typing system.

What #Doug mentioned, but also you could write your logic to make sure that every part of customer.sources.data is not undefined...
ie:
const { sources } = customer
if (sources) {
const { data } = sources
if (data) {
// then filter / etc etc ...
}
}

7 months later, I figured out the best solution.
I simply wrapped the the contents of the firebase callable function in the following if/else statement. It's a bit redundant but it works.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
}
else{ ...copy function code here }
If you don't care about the authentication piece you can simply define the type of context as any.
(data, context:any)

Open tsconfig.json and add "strictNullChecks": false to angularCompilerOptions object. It worked for me.
{
...
"angularCompilerOptions": {
"strictNullChecks": false,
...
}
}

Related

Meteor Client calling findOne in Server Method

I have a client-side form that can create a document upon submission. I want to see if one of the input fields already exists on a Document in the DB though. This would then alert the user and ask them if they want to continue creating the record.
Client-side event
Template.createDoc.events({
'click button[type=submit]'(e, template) {
//This particular example is checking to see if a Doc with its `name` property set to `value` already exists
const value = $('#name');
const fieldName = 'name';
const exists = Meteor.call('checkIfFieldExistsOnDoc', fieldName, value);
if (exists) {
if (confirm(`Doc with ${value} as its ${fieldName} already exists. Are you sure you want to continue creating Doc?`) {
//db.Docs.insert....
}
}
}
});
Server-side Meteor Method
'checkIfFieldExistsOnDoc'(field, val) {
if (this.isServer) {
this.unblock();
check(field, String);
check(val, String);
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You are not authorized.');
}
const findObj = {};
findObj[field] = val;
const fieldsObj = {};
fieldsObj[fieldsObj] = 1;
const doc = Docs.findOne(findObj, {fields: fieldsObj});
return doc;
}
},
My issue is that the client-side code always gets undefined back when calling the Server method. I now understand why, however, I'm not keen on wrapping all of my subsequent client-code into a callback yet.
So - any other ideas on how I can attempt to do this simple feature?
Also - I was thinking of having the client-side page's onCreated do a 1-time server call to get ALL names for all Docs, storing this in memory, and then doing the check upon form submission using this. Obviously, this is inefficient and not-scalable, although it would work
Meteor.call in the client side is always an async call. Then you need implement a callback.
See docs: https://docs.meteor.com/api/methods.html#Meteor-call
Meteor.call('checkIfFieldExistsOnDoc', fieldName, value, function(error, result) {
if (result) {
if (confirm(`Doc with ${value} as its ${fieldName} already exists. Are you sure you want to continue creating Doc?`) {
//db.Docs.insert....
}
}
});
On the client, you can wrap any Meteor.call with a Promise and then use it with async/await. There are some packages on Atmosphere that do this for you to.
I've used this package for years: https://atmospherejs.com/deanius/promise
On the client I often just use await Meteor.callPromise() which returns a response nicely.
Here are a couple of the best write-ups on the many options available to you:
https://blog.meteor.com/using-promises-on-the-client-in-meteor-fb4f1c155f84
https://forums.meteor.com/t/meteor-methods-return-values-via-promise-async/42060
https://dev.to/jankapunkt/async-meteor-method-calls-24f9

Is it possible to get all variables in scope through typescript?

I know there is an old post about this functionality in javascript: Getting All Variables In Scope
But I am desperately looking and thought I'd just ask in case there might be transpile magic in typescript (or a way we can extend it) that may acheve this..(e.g.)
.ts
() => {
const a = 123;
console.log(scope)
}
.js transpile
var scope = {};
() => {
scope.a = 123;
console.log(scope);
}
The reason I'm asking is that I'm looking for a node backend solution to be able to log a function's scope state and save it in a debug database for review. (So any time an error occurs the state is never lost but recorded instead)
#k0pernikus
Getting specific on my issue, I'm trying to get more context on what went wrong with my handler for a firebase event. functions.firestore.document('users/{uid}').onUpdate
// ====== Pretend code I wish would work =====
const logScopeSomewhere = (anonymousScope) => (err) => {
console.log(anonymousScope) // { pie: 'pie', apple: 'apple' }
// or write error to database..
// Main goal is that all variables in the function that errored are logged with the Type Error..
}
const handleUpdate = (change: Change<QueryDocumentSnapshot>, context: EventContext) => {
let anonymousScope;
return (async () => {
anonymousScope = scope; // special reserved - // Possible JS transpile manipulation can have a closure on top..
const pie = 'pie'; // anonymousScope.pie
const apple = 'apple'; // anonymousScope.apple
// apple.core.seed - // TypeError (will go to catch..)
})().catch(logScopeSomewhere(anonymousScope))
}
functions.firestore.document('users/{uid}').onUpdate(handleUpdate)
Trying to be more clear, I want to have an object that has a snapshot of the state of the executing function when the error occurred. I plan to catch it and will use it as logging information.
I don't think V8 exposes scope information in any other way than through DevTools.
You can parse your own source code, which lets you do any analysis you want. See this answer to the old question you linked for an example.
The TypeScript compiler must be doing the same analysis already internally, so I'm pretty sure it could be extended to dump that information. For example, it should be possible to extend the TypeScript language with a scope keyword (or whatever) that gets compiled to a JS object containing all in-scope variables and their values. That said, I have no idea whether something like that already exists, or how one would go about adding it.

Require a file once and use it everywhere

I've read up on module.exports and how it works but I'm not sure if I can accomplish what I want with it - or at least I'm not sure how to. I have some helper functions in a file, one of which is used in a majority of files in my project. I'm wondering if it is possible to just "require" the file one time and then just use it across the entirety of the project when needed.
My file looks something like this:
discord-utils.js
const { MessageEmbed, Permissions } = require('discord.js')
module.exports = {
embedResponse (message, embedOptions, textChannel = null) {
const embed = new MessageEmbed()
if (embedOptions.color) embed.setColor(embedOptions.color)
if (embedOptions.title) embed.setTitle(embedOptions.title)
if (embedOptions.description) embed.setDescription(embedOptions.description)
if (embedOptions.url) embed.setURL(embedOptions.url)
if (embedOptions.author) embed.setAuthor(embedOptions.author)
if (embedOptions.footer) embed.setFooter(embedOptions.footer)
if (embedOptions.fields) {
for (const field of embedOptions.fields) {
embed.addFields({
name: field.name,
value: field.value,
inline: field.inline ? field.inline : false
})
}
}
if (textChannel) {
textChannel.send(embed)
return
}
message.embed(embed)
},
inVoiceChannel (voiceState, message, response = null) {
if (!voiceState.channel) {
this.embedResponse(message, {
color: 'RED',
description: response === null ? 'You need to be in a voice channel to use this command.' : response
})
console.warn(`${message.author.tag} attempted to run a music command without being in a voice channel.`)
return false
}
return true
},
isAdminOrHasPerms (user, permissionRole) {
return user.hasPermisssion(Permissions.FLAGS.ADMINISTRATOR) || user.hasPermission(permissionRole)
}
}
In pretty much every other file, I use the embedResponse function. So in the project I have to do require('discord-utils) and then do things like: discordUtils.embedResponse(blahblah...) and while that's fine, it seems really redundant since I know I'm going to be using it just about everywhere. I'm wondering if there's a way I can just use one require statement and pull the functions I need at any time?
You may define a globally accessible variable using the global object in NodeJS. However, this neither a common nor a recommended pattern in NodeJS.
global.foo = 1 // make the foo variable globally accessible
https://nodejs.org/api/globals.html#globals_global
Node.js actually has a neat little caching system that can be taken advantage of to achieve a singleton effect. The first time you require a file, it runs and sets module.exports. Every time you require that same file afterwards, it will return a reference to the same object that was returned the fist time, instead of actually re-executing.
There are some caveats though. It's not always a guarantee that the file won't execute a second time. For example sometimes if you require the file from a very different location far from the first one, it might re-execute the file. Like if you first required the file as require('./my-file') and later require it with require('../../../../my-file'), it could sometimes re-execute it and clear the cached reference.

How can I query firestore by document snapshot updateTime?

Is it possible to query firestore documents by updateTime. The field that is available from the document snapshot as doc.updateTime and use it in a where query?
I am using the node.js sdk.
As far as I know there is no way to query on the metadata that Firestore automatically maintains. If you need to query the last update date, you will need to add a field with that value to the document's data.
I really need to query Firebase on document _updateTime, so I wrote a function that copies that hidden internal timestamp to a queryable field. This took some work to figure this out, so I am posting the complete solution. (Technically, this is "Cloud Firestore" rather then "Realtime Database".)
This is done using Firebase Functions, which itself took some tries to get working. This tutorial was helpful:
https://firebase.google.com/docs/functions/get-started
However, on Windows 10, the only command line that worked was the new Bash shell, available since about 2017. This was something of a runaround to install, but necessary. The GIT Bash shell, otherwise very useful, was not able to keep track of screen positions during Firebase project setup.
In my example code, I have left in all the 'console.log' statements, to show detail. Not obvious at first was where these logs go. They do not go to the command line, but to the Firebase console:
https://console.firebase.google.com/u/0/
under (yourproject) > Functions > Logs
For testing, I found it useful to, at first, deploy only one function (this is in the CLI):
firebase deploy --only functions:testFn
Below is my working function, heavily commented, and with some redundancy for illustration. Replace 'PlantSpp' with the name of your collection of documents:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
// Firestore maintains an interal _updateTime for every document, but this is
// not queryable. This function copies that to a visible field 'Updated'
exports.makeUpdateTimeVisible = functions.firestore
.document('PlantSpp/{sppId}')
.onWrite((sppDoc, context) => {
console.log("Event type: ", context.eventType);
// context.eventType = 'google.firestore.document.write', so cannot use
// to distinguish e.g. create from update
const docName = context.params.sppId // this is how to get the document name
console.log("Before: ", sppDoc.before); // if a create, a 'DocumentSnapshot',
// otherwise a 'QueryDocumentSnapshot'
// if a create, everything about sppDoc.before is undefined
if (typeof sppDoc.before._fieldsProto === "undefined"){
console.log('document "', docName, '" has been created');
// set flags here if desired
}
console.log("After: ", sppDoc.after); // if a delete, a 'DocumentSnapshot',
// otherwise a 'QueryDocumentSnapshot'
// if a delete, everything about sppDoc.after is undefined
if (typeof sppDoc.after._fieldsProto === "undefined"){
console.log('document "', docName, '" has been deleted');
// other fields could be fetched from sppDoc.before
return null; // no need to proceed
}
console.log(sppDoc.after.data()); // the user defined fields:values
// inside curly braces
console.log(sppDoc.after._fieldsProto); // similar to previous except with
// data types, e.g.
// data() has { Code: 'OLDO',...
// _fieldsProto has { Code: { stringValue: 'OLDO' },...
const timeJustUpdated = sppDoc.after._updateTime; // this is how to get the
// internal nonqueryable timestamp
console.log(timeJustUpdated);
// e.g. Timestamp { _seconds: 1581615533, _nanoseconds: 496655000 }
// later: Timestamp { _seconds: 1581617552, _nanoseconds: 566223000 }
// shows this is correctly updating
// see if the doc has the 'Updated' field yet
if (sppDoc.after._fieldsProto.hasOwnProperty('Updated')) {
console.log("doc has the field 'Updated' with the value",
sppDoc.after._fieldsProto.Updated);
console.log("sppDoc:", sppDoc);
const secondsInternal = timeJustUpdated._seconds;
console.log(secondsInternal, "seconds, internal timestamp");
const secondsExternal = sppDoc.after.data().Updated._seconds;
console.log(secondsExternal, "seconds, external timestamp");
// Careful here. If we just update the externally visible time to the
// internal time, we will go into an infinite loop because that update
// will call this function again, and by then the internal time will have
// advanced
// the following exit will not work:
if (secondsInternal === secondsExternal) return null; // will never exit
// instead, allow the external time to lag the internal by a little
const secondsLate = secondsInternal - secondsExternal;
if (secondsLate < 120) { // two minutes sufficient for this purpose
console.log("the field 'Updated' is", secondsLate,
"seconds late, good enough");
return null;
}
console.log("the field 'Updated' is", secondsLate,
"seconds late, updating");
// return a promise of a set operation to update the timestamp
return sppDoc.after.ref.set({
Updated: timeJustUpdated
}, {merge: true}); // 'merge' prevents overwriting whole doc
// this change will call this same function again
} else { // field 'Updated' does not exist in the document yet
// this illustrates how to add a field
console.log("doc does not have the field 'Updated', adding it now.");
// return a promise of a set operation to create the timestamp
return sppDoc.after.ref.set({
Updated: timeJustUpdated
}, {merge: true}); // 'merge' prevents overwriting the whole doc
// this change will call this same function again
}
});
True, there is no query for time created/modified, but when you fetch a document those fields exist in the payload. You have:
payload.doc['_document'].proto.createTime and payload.doc['_document'].proto.updateTime
Sure it's not good practice to rely on private fields, so will prolly need ongoing adjustments as Firestore changes its data model, but for now, for my uses, it gets me this otherwise un-query-able data.

nodejs referenceerror on nested function calls using async.series and async.until

I'm new to nodejs and trying to learn the basics by rebuilding an existing i2c sensor system.
Got it all running using a named functions and async.series inside a single file. To keep make reusable i now want to create a class which i then can import. unfortunatly i get some errors i don't understand.
class.js
const async = require('async');
const i2c = require('i2c-bus');
class Sensor {
constructor (channel) {
this.channel = channel;
var self = this;
}
openBus (callback) {
bus = i2c.open(self.channel, (err) => {callback()}); // shorted for stackoverflow
}
closeBus (callback) {
bus.close( (err) => {callback()}); //also shorted for better readability
}
connection (callback) {
/* first variation */
async.series([openBus, closeBus], callback);
connection2 (callback) {
/* second variation */
async.series([this.openBus, this.closeBus], callback);
}
}
module.exports = K30;
when i import the class, i can without any problem create a new sensor 'object' and call the functions directly using:
> var Sensor = require('./class.js');
> var mySensor = new Sensor(1);
> mySensor.openBus(foo);
> mySensor.closeBus(bar);
but if i go an try call the wrapper-functions, i get the following errors:
> mySensor.connection(foo);
ReferenceError: openBus is not defined (at 'connection')
> mySensor.connection2(foo);
ReferenceError: self is not defined (at 'openBus')
i believe those errors occure due to my lack of understanding the correct usage of this and self. sadly i can't find any good ead on that topic. any help is highly appreciated.
UPDATE
the solution provided in the first two anwsers was in fact my first approch before starting to use "self" (after some googling [this-that-trick]).
anyways, here is the output/error i get using "this.channel" instead:
> mySensor.connection2(foo);
TypeError: Cannot read property 'channel' of undefined (at openBus)
This is not saved anywhere var self = this; and therefore is lost when the function (constructor is function) ends.
Just remove the above line in constructor and use everywhere the this instead of self.
Its true that this keyword is little tricky in javascript, but if you follow reasonable approach, you should be fine.
You indeed have issue with this and self
Every member inside the class has to be referred by this. If you declare a variable named var EBZ-Krisemendt = "SO user";, to access it, you need to use it with this, eg: console.log(this.EBZ-Krisemendt);
What you need here is
openBus (callback) {
bus = i2c.open(this.channel, (err) => {callback()});
}
and then mysensor.connection2(foo) will work fine.
while i still don't fully understand the reason behind this i fixed my code by getting rid of that "ES6" class definition.
class.js
const i2c = require('i2c-bus');
const async = require('async');
function Sensor(channel) {
let that = this; // make 'this' available in sub-function scope
this.channel = channel;
function openBus(cb) {
// open the bus-connection
bus = i2c.open(that.channel);
}
function closeBus(cb) {
// close the bus-connection
}
function connection(cb) {
async.series([openBus, closeBus], cb);
}
function getReading(cb) {
async.until(
function() {
// loop condition e.g. max tries to get reading
},
function(cb) {
connection(cb); // calling nested synchronous connection-routine
},
function (err) {
// result handling
}
); // end async.until
} // end getReading
return {
getReading: getReading
} // make only 'getReading' available
}
module.exports = {
Sensor: Sensor
} // make 'Sensor' available
in the 'member'-functions i can now use the 'class'-variables of 'Sensor' by accessing them with 'that' (e.g.: 'that.channel')
Detail:
function openBus(cb){
bus = i2c.open(that.channel);
}
if i'd use this instead of that it would only work while calling openBus directly. in my example it's neccessary to call openBus and closeBus in a synchronous manner (for obvious reasons). since async.series is additionally nested inside async.until (sensor might need several tries to response) the scope of this changes. by using that instead i'm able to ignore the scope.
Comment:
since the solution is kinda generally pointing to using nested async-calls inside custom modules i'll slightly alter the titel of the initial question. i'm still hoping for better solutions and/or explanations, so i won't mark my own anwser as accepted yet.

Resources