backend-manager 2.5.3 → 2.5.5

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.3",
3
+ "version": "2.5.5",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -66,4 +66,4 @@
66
66
  "src/",
67
67
  "templates/"
68
68
  ]
69
- }
69
+ }
package/src/cli/cli.js CHANGED
@@ -5,7 +5,6 @@
5
5
  // https://www.sitepoint.com/javascript-command-line-interface-cli-node-js/
6
6
  // https://github.com/sitepoint-editors/ginit
7
7
 
8
- let exec = require('child_process').exec;
9
8
  const jetpack = require('fs-jetpack');
10
9
  const path = require('path');
11
10
  const chalk = require('chalk');
@@ -14,7 +13,7 @@ const log = console.log;
14
13
  const Npm = require('npm-api');
15
14
  const semver = require('semver');
16
15
  const inquirer = require('inquirer');
17
- const { spawn } = require('child_process');
16
+ const { spawn, child, exec, fork } = require('child_process');
18
17
  const JSON5 = require('json5');
19
18
  const fetch = require('wonderful-fetch');
20
19
  const argv = require('yargs').argv;
@@ -87,6 +86,12 @@ Main.prototype.process = async function (args) {
87
86
  console.log('cwd: ', self.firebaseProjectPath);
88
87
  }
89
88
  if (self.options.setup) {
89
+ // console.log(`Running Setup`);
90
+ // console.log(`node:`, process.versions.node);
91
+ // console.log(`pwd:`, await execute('pwd').catch(e => e));
92
+ // console.log(`node:`, await execute('node --version').catch(e => e));
93
+ // console.log(`firebase-tools:`, await execute('firebase --version').catch(e => e));
94
+ // console.log('');
90
95
  await cmd_configGet(self).catch(e => log(chalk.red(`Failed to run config:get`)));
91
96
  await self.setup();
92
97
  }
@@ -1115,9 +1120,63 @@ async function cmd_indexesGet(self, filePath, log) {
1115
1120
  });
1116
1121
  }
1117
1122
 
1123
+ async function execute(command, cwd) {
1124
+ cwd = cwd || process.cwd();
1125
+ return new Promise(function(resolve, reject) {
1126
+ exec(command, { cwd: cwd, stdio: 'inherit' })
1127
+ .on('error', function(err) {
1128
+ reject(err);
1129
+ })
1130
+ .on('close', function (one, two, three) {
1131
+ console.log('===', one, two, three);
1132
+ resolve()
1133
+ })
1134
+ // fork(command, function (error, stdout, stderr) {
1135
+ // if (error) {
1136
+ // reject(error);
1137
+ // } else {
1138
+ // resolve(stdout);
1139
+ // }
1140
+ // });
1141
+
1142
+ });
1143
+ }
1144
+
1145
+ // async function execute(command, args, cwd) {
1146
+ // cwd = cwd || process.cwd();
1147
+ // return new Promise(function(resolve, reject) {
1148
+ // spawn(command, args, { cwd: cwd, stdio: 'inherit' })
1149
+ // .on('error', function(err) {
1150
+ // reject(err);
1151
+ // })
1152
+ // .on('close', function (one, two, three) {
1153
+ // console.log('===', one, two, three);
1154
+ // resolve()
1155
+ // })
1156
+ // // fork(command, function (error, stdout, stderr) {
1157
+ // // if (error) {
1158
+ // // reject(error);
1159
+ // // } else {
1160
+ // // resolve(stdout);
1161
+ // // }
1162
+ // // });
1163
+
1164
+ // });
1165
+ // }
1166
+
1118
1167
  async function cmd_configGet(self, filePath) {
1119
1168
  return new Promise(function(resolve, reject) {
1120
1169
  const finalPath = `${self.firebaseProjectPath}/${filePath || 'functions/.runtimeconfig.json'}`;
1170
+ // execute(`firebase functions:config:get > ${finalPath}`)
1171
+ // .then(r => {
1172
+ // console.log(chalk.green(`Saving config to: ${finalPath}`));
1173
+ // console.log(r);
1174
+ // resolve(require(finalPath));
1175
+ // })
1176
+ // .catch(e => {
1177
+ // console.error(e);
1178
+ // reject(e);
1179
+ // })
1121
1180
  let cmd = exec(`firebase functions:config:get > ${finalPath}`, function (error, stdout, stderr) {
1122
1181
  if (error) {
1123
1182
  console.error(error);
@@ -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
 
@@ -119,6 +122,8 @@ Manager.prototype.init = function (exporter, options) {
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
@@ -154,13 +159,19 @@ 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
176
  self.assistant.error('Failed to call .initializeApp()', e, {environment: 'production'});
166
177
  }
@@ -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 || {};
@@ -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;