backend-manager 2.5.2 → 2.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "2.5.2",
3
+ "version": "2.5.4",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -79,7 +79,9 @@ Module.prototype.updateStats = function (existingData) {
79
79
  const sessionsApp = self.libraries.admin.database().ref(`sessions/app`);
80
80
 
81
81
  let error = null;
82
- let update = {};
82
+ let update = {
83
+ app: _.get(self.Manager.config, 'app.id', null),
84
+ };
83
85
 
84
86
  // Fix broken stats
85
87
  if (!_.get(existingData, 'users.total', null)) {
@@ -0,0 +1,117 @@
1
+ function Utilities(Manager) {
2
+ const self = this;
3
+
4
+ self.Manager = Manager;
5
+ }
6
+
7
+ Utilities.prototype.iterateCollection = function (callback, options) {
8
+ const self = this;
9
+ const Manager = self.Manager;
10
+ const admin = Manager.libraries.admin;
11
+
12
+ return new Promise(function(resolve, reject) {
13
+ let batch = -1;
14
+
15
+ options = options || {};
16
+ options.collection = options.collection || '';
17
+ options.batchSize = options.batchSize || 1000;
18
+ options.log = options.log;
19
+
20
+ function listAllDocuments(nextPageToken) {
21
+ let query = admin.firestore().collection(options.collection)
22
+
23
+ // Start at next page
24
+ if (nextPageToken) {
25
+ query = query.startAfter(nextPageToken);
26
+ }
27
+
28
+ // batchSize
29
+ query = query.limit(options.batchSize);
30
+
31
+ query.get()
32
+ .then(async (snap) => {
33
+ const lastVisible = snap.docs[snap.docs.length - 1];
34
+
35
+ batch++;
36
+
37
+ if (options.log) {
38
+ console.log('Processing batch:', batch);
39
+ }
40
+
41
+ callback({
42
+ snap: snap, docs: snap.docs.map(x => x)
43
+ }, batch)
44
+ .then(r => {
45
+ // Construct a new query starting at this document
46
+ if (lastVisible) {
47
+ listAllDocuments(lastVisible)
48
+ } else {
49
+ return resolve();
50
+ }
51
+ })
52
+ .catch((e) => {
53
+ console.error('Callback failed', e);
54
+ return reject(e);
55
+ });
56
+
57
+ })
58
+ .catch((e) => {
59
+ console.error('Query failed', e);
60
+ return reject(e);
61
+ });
62
+ }
63
+
64
+ listAllDocuments();
65
+ });
66
+ };
67
+
68
+ Utilities.prototype.iterateUsers = function (callback, options) {
69
+ const self = this;
70
+ const Manager = self.Manager;
71
+ const admin = Manager.libraries.admin;
72
+
73
+ return new Promise(function(resolve, reject) {
74
+ let batch = -1;
75
+
76
+ options = options || {};
77
+ options.log = options.log;
78
+
79
+ function listAllUsers(nextPageToken) {
80
+ // List batch of users, 1000 at a time.
81
+ admin.auth()
82
+ .listUsers(1000, nextPageToken)
83
+ .then(async (listUsersResult) => {
84
+
85
+ batch++;
86
+
87
+ if (options.log) {
88
+ console.log('Processing batch:', batch);
89
+ }
90
+
91
+ callback({
92
+ snap: listUsersResult, users: listUsersResult.users,
93
+ }, batch)
94
+ .then(r => {
95
+ if (listUsersResult.pageToken) {
96
+ listAllUsers(listUsersResult.pageToken);
97
+ } else {
98
+ return resolve();
99
+ }
100
+ })
101
+ .catch((e) => {
102
+ console.error('Callback failed', e);
103
+ return reject(e)
104
+ });
105
+
106
+ })
107
+ .catch((e) => {
108
+ console.error('Query failed', e);
109
+ return reject(e)
110
+ });
111
+ }
112
+
113
+ listAllUsers();
114
+ });
115
+ };
116
+
117
+ module.exports = Utilities;
@@ -2,6 +2,7 @@
2
2
  const path = require('path');
3
3
  const { get, merge } = require('lodash');
4
4
  const jetpack = require('fs-jetpack');
5
+ const JSON5 = require('json5');
5
6
  // const { debug, log, error, warn } = require('firebase-functions/lib/logger');
6
7
  // let User;
7
8
  // let Analytics;
@@ -45,6 +46,7 @@ Manager.prototype.init = function (exporter, options) {
45
46
  options.firebaseConfig = options.firebaseConfig;
46
47
  options.useFirebaseLogger = typeof options.useFirebaseLogger === 'undefined' ? true : options.useFirebaseLogger;
47
48
  options.serviceAccountPath = typeof options.serviceAccountPath === 'undefined' ? 'service-account.json' : options.serviceAccountPath;
49
+ options.backendManagerConfigPath = typeof options.backendManagerConfigPath === 'undefined' ? 'backend-manager-config.json' : options.backendManagerConfigPath;
48
50
  options.uniqueAppName = options.uniqueAppName || undefined;
49
51
  options.assistant = options.assistant || {};
50
52
  // options.assistant.optionsLogString = options.assistant.optionsLogString || undefined;
@@ -71,10 +73,11 @@ Manager.prototype.init = function (exporter, options) {
71
73
  self.project = options.firebaseConfig || JSON.parse(process.env.FIREBASE_CONFIG || '{}');
72
74
  self.project.resourceZone = options.resourceZone;
73
75
  self.project.serviceAccountPath = path.resolve(self.cwd, options.serviceAccountPath)
74
-
76
+ self.project.backendManagerConfigPath = path.resolve(self.cwd, options.backendManagerConfigPath)
77
+
75
78
  self.package = resolveProjectPackage();
76
79
  self.config = merge(
77
- require(path.resolve(self.cwd, 'backend-manager-config.json')),
80
+ requireJSON5(self.project.backendManagerConfigPath),
78
81
  self.libraries.functions.config()
79
82
  );
80
83
 
@@ -112,13 +115,15 @@ Manager.prototype.init = function (exporter, options) {
112
115
 
113
116
  // Reject if package.json does not exist
114
117
  if (semverUsing !== semverRequired) {
115
- console.error(new Error(`Node.js version mismatch: using ${semverUsing} but asked for ${semverRequired}`));
118
+ self.assistant.error(new Error(`Node.js version mismatch: using ${semverUsing} but asked for ${semverRequired}`), {environment: 'production'});
116
119
  return process.exit(1);
117
120
  }
118
121
  }
119
122
 
120
123
  if (options.log) {
121
124
  self.assistant.log('process.env', process.env, {environment: 'production'})
125
+ console.log('Resolved serviceAccountPath', self.project.serviceAccountPath);
126
+ console.log('Resolved backendManagerConfigPath', self.project.backendManagerConfigPath);
122
127
  }
123
128
 
124
129
  // Setup sentry
@@ -133,7 +138,7 @@ Manager.prototype.init = function (exporter, options) {
133
138
  release: sentryRelease,
134
139
  beforeSend(event, hint) {
135
140
  if (self.assistant.meta.environment === 'development' && !self.options.reportErrorsInDev) {
136
- self.assistant.error('Skipping Sentry because DEV')
141
+ self.assistant.error(new Error('Skipping Sentry because DEV'), {environment: 'production'})
137
142
  return null;
138
143
  }
139
144
  event.tags = event.tags || {};
@@ -154,15 +159,21 @@ Manager.prototype.init = function (exporter, options) {
154
159
  if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
155
160
  self.libraries.initializedAdmin = self.libraries.admin.initializeApp();
156
161
  } else {
162
+ const serviceAccount = require(self.project.serviceAccountPath);
157
163
  self.libraries.initializedAdmin = self.libraries.admin.initializeApp({
158
- credential: self.libraries.admin.credential.cert(
159
- require(self.project.serviceAccountPath)
160
- ),
164
+ credential: self.libraries.admin.credential.cert(serviceAccount),
161
165
  databaseURL: self.project.databaseURL,
162
166
  }, options.uniqueAppName);
167
+
168
+ // const loadedProjectId = get(self.libraries.initializedAdmin, 'options_.credential.projectId', null);
169
+ const loadedProjectId = serviceAccount.project_id;
170
+ if (!loadedProjectId || !loadedProjectId.includes(self.config.app.id)) {
171
+ self.assistant.error(`Loaded app may have wrong service account: ${loadedProjectId} =/= ${self.config.app.id}`, {environment: 'production'});
172
+ }
163
173
  }
174
+
164
175
  } catch (e) {
165
- console.error('Failed to call .initializeApp()', e);
176
+ self.assistant.error('Failed to call .initializeApp()', e, {environment: 'production'});
166
177
  }
167
178
  // admin.firestore().settings({/* your settings... */ timestampsInSnapshots: true})
168
179
  }
@@ -372,12 +383,12 @@ Manager.prototype.init = function (exporter, options) {
372
383
  });
373
384
 
374
385
  // Cron
375
- exporter.bm_backup =
386
+ exporter.bm_cronDaily =
376
387
  self.libraries.functions
377
388
  .runWith({ memory: '256MB', timeoutSeconds: 60 })
378
- .pubsub.schedule(get(self.config, 'backup.schedule', 'every 24 hours'))
389
+ .pubsub.schedule('every 24 hours')
379
390
  .onRun(async (context) => {
380
- return self._process((new (require(`${core}/cron/backup.js`))()).init(self, { context: context, }))
391
+ return self._process((new (require(`${core}/cron/daily.js`))()).init(self, { context: context, }))
381
392
  });
382
393
  }
383
394
 
@@ -385,7 +396,7 @@ Manager.prototype.init = function (exporter, options) {
385
396
  try {
386
397
  require('dotenv').config();
387
398
  } catch (e) {
388
- console.error('Failed to set up environment variables from .env file');
399
+ self.assistant.error(new Error('Failed to set up environment variables from .env file'), {environment: 'production'});
389
400
  }
390
401
 
391
402
  // Setup LocalDatabase
@@ -393,6 +404,18 @@ Manager.prototype.init = function (exporter, options) {
393
404
  self.storage();
394
405
  }
395
406
 
407
+ if (self.assistant.meta.environment === 'development') {
408
+ setTimeout(function () {
409
+ console.log('Fetching meta/stats...');
410
+ self.libraries.admin
411
+ .firestore().doc('meta/stats')
412
+ .get()
413
+ .then(doc => {
414
+ console.log('meta/stats', doc.data());
415
+ })
416
+ }, 3000);
417
+ }
418
+
396
419
  return self;
397
420
  };
398
421
 
@@ -532,6 +555,12 @@ Manager.prototype.ApiManager = function () {
532
555
  return new self.libraries.ApiManager(self, ...arguments);
533
556
  };
534
557
 
558
+ Manager.prototype.Utilities = function () {
559
+ const self = this;
560
+ self.libraries.Utilities = self.libraries.Utilities || require('./helpers/utilities.js');
561
+ return new self.libraries.Utilities(self, ...arguments);
562
+ };
563
+
535
564
  Manager.prototype.storage = function (options) {
536
565
  const self = this;
537
566
  options = options || {};
@@ -566,16 +595,16 @@ Manager.prototype.storage = function (options) {
566
595
  try {
567
596
  _setup()
568
597
  } catch (e) {
569
- console.error(`Could not storage: ${dbPath}`, e);
598
+ self.assistant.error(`Could not setup storage: ${dbPath}`, e, {environment: 'production'});
570
599
 
571
600
  try {
572
601
  if (options.clearInvalid) {
573
- console.log(`Clearing invalud storage: ${dbPath}`);
602
+ self.assistant.log(`Clearing invalid storage: ${dbPath}`, {environment: 'production'});
574
603
  jetpack.write(dbPath, {});
575
604
  }
576
605
  _setup()
577
606
  } catch (e) {
578
- console.error(`Failed to clear invalid storage: ${dbPath}`, e);
607
+ self.assistant.error(`Failed to clear invalid storage: ${dbPath}`, e, {environment: 'production'});
579
608
  }
580
609
  }
581
610
  }
@@ -631,4 +660,8 @@ function resolveProjectPackage() {
631
660
  } catch (e) {}
632
661
  }
633
662
 
663
+ function requireJSON5(p) {
664
+ return JSON5.parse(jetpack.read(p))
665
+ }
666
+
634
667
  module.exports = Manager;