backend-manager 2.0.26 → 2.0.29

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.0.26",
3
+ "version": "2.0.29",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -37,7 +37,7 @@
37
37
  "cors": "^2.8.5",
38
38
  "dotenv": "^16.0.0",
39
39
  "firebase-admin": "^9.12.0",
40
- "firebase-functions": "^3.20.1",
40
+ "firebase-functions": "^3.21.0",
41
41
  "fs-jetpack": "^4.3.1",
42
42
  "hcaptcha": "^0.1.1",
43
43
  "inquirer": "^8.2.4",
@@ -47,9 +47,9 @@
47
47
  "mocha": "^9.2.2",
48
48
  "moment": "^2.29.3",
49
49
  "node-fetch": "^2.6.7",
50
- "node-powertools": "^0.0.10",
50
+ "node-powertools": "^0.0.13",
51
51
  "npm-api": "^1.0.1",
52
- "paypal-server-api": "^0.0.5",
52
+ "paypal-server-api": "^0.0.6",
53
53
  "pushid": "^1.0.0",
54
54
  "semver": "^7.3.7",
55
55
  "shortid": "^2.2.16",
package/src/cli/cli.js CHANGED
@@ -6,7 +6,7 @@
6
6
  // https://github.com/sitepoint-editors/ginit
7
7
 
8
8
  let exec = require('child_process').exec;
9
- const fs = require('fs-jetpack');
9
+ const jetpack = require('fs-jetpack');
10
10
  const path = require('path');
11
11
  const chalk = require('chalk');
12
12
  const _ = require('lodash');
@@ -49,65 +49,65 @@ let bem_fsRulesBackupRegex = /({{\s*?backend-manager\s*?}})/sgm;
49
49
  let MOCHA_PKG_SCRIPT = 'mocha ../test/ --recursive --timeout=10000';
50
50
  let NPM_CLEAN_SCRIPT = 'rm -fr node_modules && rm -fr package-lock.json && npm cache clean --force && npm install && npm rb';
51
51
  let NOFIX_TEXT = chalk.red(`There is no automatic fix for this check.`);
52
- let runtimeconfigTemplate = JSON.parse((fs.read(path.resolve(`${__dirname}/../../templates/runtimeconfig.json`))) || '{}');
53
- let bemConfigTemplate = JSON.parse((fs.read(path.resolve(`${__dirname}/../../templates/backend-manager-config.json`))) || '{}');
54
- let CLI_CONFIG = JSON5.parse((fs.read(path.resolve(`${__dirname}/config.json`))) || '{}');
52
+ let runtimeconfigTemplate = JSON.parse((jetpack.read(path.resolve(`${__dirname}/../../templates/runtimeconfig.json`))) || '{}');
53
+ let bemConfigTemplate = JSON.parse((jetpack.read(path.resolve(`${__dirname}/../../templates/backend-manager-config.json`))) || '{}');
54
+ let CLI_CONFIG = JSON5.parse((jetpack.read(path.resolve(`${__dirname}/config.json`))) || '{}');
55
55
 
56
56
  function Main() {
57
57
  }
58
58
 
59
59
  Main.prototype.process = async function (args) {
60
- let self = this;
61
- this.options = {};
62
- this.argv = argv;
63
- this.firebaseProjectPath = process.cwd();
64
- this.firebaseProjectPath = this.firebaseProjectPath.match(/\/functions$/) ? this.firebaseProjectPath.replace(/\/functions$/, '') : this.firebaseProjectPath;
65
- this.testCount = 0;
66
- this.testTotal = 0;
67
- this.default = {};
68
- this.packageJSON = require('../../package.json');
69
- this.default.version = this.packageJSON.version;
60
+ const self = this;
61
+ self.options = {};
62
+ self.argv = argv;
63
+ self.firebaseProjectPath = process.cwd();
64
+ self.firebaseProjectPath = self.firebaseProjectPath.match(/\/functions$/) ? self.firebaseProjectPath.replace(/\/functions$/, '') : self.firebaseProjectPath;
65
+ self.testCount = 0;
66
+ self.testTotal = 0;
67
+ self.default = {};
68
+ self.packageJSON = require('../../package.json');
69
+ self.default.version = self.packageJSON.version;
70
70
 
71
71
  for (var i = 0; i < args.length; i++) {
72
- this.options[args[i]] = true;
72
+ self.options[args[i]] = true;
73
73
  }
74
74
  // console.log(args);
75
75
  // console.log(options);
76
- if (this.options.v || this.options.version || this.options['-v'] || this.options['-version']) {
77
- console.log(`Backend manager is version: ${this.default.version}`);
76
+ if (self.options.v || self.options.version || self.options['-v'] || self.options['-version']) {
77
+ console.log(`Backend manager is version: ${self.default.version}`);
78
78
  }
79
79
 
80
80
  // https://gist.github.com/timneutkens/f2933558b8739bbf09104fb27c5c9664
81
- if (this.options.clear) {
81
+ if (self.options.clear) {
82
82
  process.stdout.write("\u001b[3J\u001b[2J\u001b[1J");
83
83
  console.clear();
84
84
  process.stdout.write("\u001b[3J\u001b[2J\u001b[1J");
85
85
  }
86
- if (this.options.cwd) {
87
- console.log('cwd: ', this.firebaseProjectPath);
86
+ if (self.options.cwd) {
87
+ console.log('cwd: ', self.firebaseProjectPath);
88
88
  }
89
- if (this.options.setup) {
89
+ if (self.options.setup) {
90
90
  await cmd_configGet(self).catch(e => log(chalk.red(`Failed to run config:get`)));
91
91
  await self.setup();
92
92
  }
93
- if ((this.options.i || this.options.install) && (this.options.local || this.options.dev || this.options.development)) {
93
+ if ((self.options.i || self.options.install) && (self.options.local || self.options.dev || self.options.development)) {
94
94
  await uninstallPkg('backend-manager');
95
95
  return await installPkg('file:../../../ITW-Creative-Works/backend-manager');
96
96
  // await uninstallPkg('backend-assistant');
97
97
  // return await installPkg('file:../../backend-assistant');
98
98
  }
99
- if ((this.options.i || this.options.install) && (this.options.live || this.options.prod || this.options.production)) {
99
+ if ((self.options.i || self.options.install) && (self.options.live || self.options.prod || self.options.production)) {
100
100
  await uninstallPkg('backend-manager');
101
101
  return await installPkg('backend-manager');
102
102
  // return await installPkg('backend-assistant');
103
103
  }
104
- if (this.options.serve) {
105
- if (!this.options.quick && !this.options.q) {
104
+ if (self.options.serve) {
105
+ if (!self.options.quick && !self.options.q) {
106
106
  }
107
107
  await cmd_configGet(self);
108
108
  await self.setup();
109
109
 
110
- let port = this.argv.port || _.get(self.argv, '_', [])[1] || '5000';
110
+ let port = self.argv.port || _.get(self.argv, '_', [])[1] || '5000';
111
111
  let ls = spawn(`firebase serve --port ${port}`, {shell: true});
112
112
 
113
113
  ls.stdout.on('data', (data) => {
@@ -118,27 +118,32 @@ Main.prototype.process = async function (args) {
118
118
  // ls = null;
119
119
  });
120
120
  }
121
- if (this.options['config:get']) {
121
+
122
+ if (self.options['firestore:indexes:get'] || self.options['firestore:indexes'] || self.options['indexes:get']) {
123
+ return await cmd_indexesGet(self, undefined, true);
124
+ }
125
+
126
+ if (self.options['functions:config:get'] || self.options['config:get']) {
122
127
  return await cmd_configGet(self);
123
128
  }
124
129
 
125
- if (this.options['config:set']) {
130
+ if (self.options['functions:config:set'] || self.options['config:set']) {
126
131
  await cmd_configSet(self);
127
132
  return await cmd_configGet(self);
128
133
  }
129
134
 
130
- if (this.options['config:unset'] || this.options['config:delete'] || this.options['config:remove']) {
135
+ if (self.options['functions:config:unset'] || self.options['config:unset'] || self.options['config:delete'] || self.options['config:remove']) {
131
136
  await cmd_configUnset(self);
132
137
  return await cmd_configGet(self);
133
138
  }
134
139
 
135
- if (this.options['rules:default'] || this.options['rules:getdefault']) {
140
+ if (self.options['rules:default'] || self.options['rules:getdefault']) {
136
141
  self.getRulesFile();
137
142
  console.log(self.default.firestoreRulesWhole.match(bem_fsRulesDefaultRegex)[0].replace(' ///', '///'));
138
143
  return;
139
144
  }
140
145
 
141
- if (this.options.deploy) {
146
+ if (self.options.deploy) {
142
147
  await self.setup();
143
148
 
144
149
  // Quick check that not using local packages
@@ -161,7 +166,7 @@ Main.prototype.process = async function (args) {
161
166
  });
162
167
 
163
168
  }
164
- if (this.options['test']) {
169
+ if (self.options['test']) {
165
170
  await self.setup();
166
171
  // firebase emulators:exec --only firestore 'npm test'
167
172
  // let ls = spawn('firebase', ['emulators:exec', '--only', 'firestore', 'npm test']);
@@ -175,7 +180,7 @@ Main.prototype.process = async function (args) {
175
180
  });
176
181
  }
177
182
 
178
- if (this.options['clean:npm']) {
183
+ if (self.options['clean:npm']) {
179
184
  // await self.setup();
180
185
  // firebase emulators:exec --only firestore 'npm test'
181
186
  let ls = spawn(`${NPM_CLEAN_SCRIPT}`, {shell: true});
@@ -187,10 +192,10 @@ Main.prototype.process = async function (args) {
187
192
  });
188
193
  }
189
194
 
190
- // if (this.options['url']) {
195
+ // if (self.options['url']) {
191
196
  // // await self.setup();
192
197
  // // firebase emulators:exec --only firestore 'npm test'
193
- // log(this.projectUrl)
198
+ // log(self.projectUrl)
194
199
  // }
195
200
 
196
201
  };
@@ -199,68 +204,73 @@ module.exports = Main;
199
204
 
200
205
 
201
206
  Main.prototype.getRulesFile = function () {
202
- let self = this;
203
- this.default.firestoreRulesWhole = (fs.read(path.resolve(`${__dirname}/../../templates/firestore.rules`))).replace('=0.0.0-', `-${self.default.version}-`);
204
- this.default.firestoreRulesCore = this.default.firestoreRulesWhole.match(bem_fsRulesRegex)[0];
207
+ const self = this;
208
+ self.default.firestoreRulesWhole = (jetpack.read(path.resolve(`${__dirname}/../../templates/firestore.rules`))).replace('=0.0.0-', `-${self.default.version}-`);
209
+ self.default.firestoreRulesCore = self.default.firestoreRulesWhole.match(bem_fsRulesRegex)[0];
205
210
 
206
211
  };
207
212
 
208
213
  Main.prototype.setup = async function () {
209
- let self = this;
210
- let cwd = fs.cwd();
211
- log(chalk.green(`\n---- RUNNING v${this.default.version} SETUP ----`));
212
- this.package = fs.read(`${this.firebaseProjectPath}/functions/package.json`) || '{}';
213
- this.firebaseJSON = fs.read(`${this.firebaseProjectPath}/firebase.json`) || '{}';
214
- this.firebaseRC = fs.read(`${this.firebaseProjectPath}/.firebaserc`) || '{}';
215
- this.runtimeConfigJSON = fs.read(`${this.firebaseProjectPath}/functions/.runtimeconfig.json`) || '{}';
216
- this.projectPackage = fs.read(`${this.firebaseProjectPath}/package.json`) || '{}';
217
- this.gitignore = fs.read(`${this.firebaseProjectPath}/functions/.gitignore`) || '';
218
- if (!this.package) {
214
+ const self = this;
215
+ let cwd = jetpack.cwd();
216
+ log(chalk.green(`\n---- RUNNING SETUP v${self.default.version} ----`));
217
+ self.package = jetpack.read(`${self.firebaseProjectPath}/functions/package.json`) || '{}';
218
+ self.firebaseJSON = jetpack.read(`${self.firebaseProjectPath}/firebase.json`) || '{}';
219
+ self.firebaseRC = jetpack.read(`${self.firebaseProjectPath}/.firebaserc`) || '{}';
220
+ self.runtimeConfigJSON = jetpack.read(`${self.firebaseProjectPath}/functions/.runtimeconfig.json`) || '{}';
221
+ self.remoteconfigJSON = jetpack.read(`${self.firebaseProjectPath}/remoteconfig.template.json`) || '{}';
222
+ self.projectPackage = jetpack.read(`${self.firebaseProjectPath}/package.json`) || '{}';
223
+
224
+ self.gitignore = jetpack.read(`${self.firebaseProjectPath}/functions/.gitignore`) || '';
225
+ if (!self.package) {
219
226
  log(chalk.red(`Missing functions/package.json :(`));
220
227
  return;
221
228
  }
222
229
  // console.log('cwd', cwd, cwd.endsWith('functions'));
223
230
  if (!cwd.endsWith('functions') && !cwd.endsWith('functions/')) {
224
- log(chalk.red(`Please run ${chalk.bold('bm setup')} from the ${chalk.bold('functions')} folder. Run ${chalk.bold('cd functions')}.`));
231
+ log(chalk.red(`Please run ${chalk.bold('npx bm setup')} from the ${chalk.bold('functions')} folder. Run ${chalk.bold('cd functions')}.`));
225
232
  return;
226
233
  }
227
234
 
228
- this.package = JSON.parse(this.package);
229
- this.firebaseJSON = JSON.parse(this.firebaseJSON);
230
- this.firebaseRC = JSON.parse(this.firebaseRC);
231
- this.runtimeConfigJSON = JSON.parse(this.runtimeConfigJSON);
232
- this.projectPackage = JSON.parse(this.projectPackage);
235
+ self.package = JSON.parse(self.package);
236
+ self.firebaseJSON = JSON.parse(self.firebaseJSON);
237
+ self.firebaseRC = JSON.parse(self.firebaseRC);
238
+ self.runtimeConfigJSON = JSON.parse(self.runtimeConfigJSON);
239
+ self.remoteconfigJSON = JSON.parse(self.remoteconfigJSON);
240
+ self.projectPackage = JSON.parse(self.projectPackage);
241
+
242
+ self.remoteconfigJSONExists = Object.keys(self.remoteconfigJSON).length > 0;
233
243
 
234
244
  self.getRulesFile();
235
245
 
236
- this.default.firestoreRulesVersionRegex = new RegExp(`///---version-${self.default.version}---///`)
237
- // bem_giRegex = new RegExp(fs.read(path.resolve(`${__dirname}/../../templates/gitignore.md`)).replace(/\./g, '\\.'), 'm' )
238
- bem_giRegex = new RegExp(fs.read(path.resolve(`${__dirname}/../../templates/gitignore.md`)), 'm' )
246
+ self.default.firestoreRulesVersionRegex = new RegExp(`///---version-${self.default.version}---///`)
247
+ // bem_giRegex = new RegExp(jetpack.read(path.resolve(`${__dirname}/../../templates/gitignore.md`)).replace(/\./g, '\\.'), 'm' )
248
+ bem_giRegex = new RegExp(jetpack.read(path.resolve(`${__dirname}/../../templates/gitignore.md`)), 'm' )
239
249
 
240
250
  // tests
241
- this.projectName = this.firebaseRC.projects.default;
242
- this.projectUrl = `https://console.firebase.google.com/project/${this.projectName}`;
243
- log(chalk.black(`Id: `, chalk.bold(`${this.projectName}`)));
244
- log(chalk.black(`Url:`, chalk.bold(`${this.projectUrl}`)));
251
+ self.projectName = self.firebaseRC.projects.default;
252
+ self.projectUrl = `https://console.firebase.google.com/project/${self.projectName}`;
253
+ log(chalk.black(`Id: `, chalk.bold(`${self.projectName}`)));
254
+ log(chalk.black(`Url:`, chalk.bold(`${self.projectUrl}`)));
245
255
 
246
256
  if (!self.package || !self.package.engines || !self.package.engines.node) {
247
257
  throw new Error('Missing <engines.node> in package.json')
248
258
  }
249
259
 
250
- await this.test('is a firebase project', async function () {
251
- let exists = fs.exists(`${self.firebaseProjectPath}/firebase.json`);
260
+ await self.test('is a firebase project', async function () {
261
+ let exists = jetpack.exists(`${self.firebaseProjectPath}/firebase.json`);
252
262
  return exists;
253
263
  }, fix_isFirebase);
254
264
 
255
- await this.test('.nvmrc file has proper version', async function () {
265
+ await self.test('.nvmrc file has proper version', async function () {
256
266
  // return !!self.package.dependencies && !!self.package.devDependencies;
257
- // let gitignore = fs.read(path.resolve(`${__dirname}/../../templates/gitignore.md`));
258
- let nvmrc = fs.read(`${self.firebaseProjectPath}/functions/.nvmrc`) || '';
267
+ // let gitignore = jetpack.read(path.resolve(`${__dirname}/../../templates/gitignore.md`));
268
+ let nvmrc = jetpack.read(`${self.firebaseProjectPath}/functions/.nvmrc`) || '';
259
269
  return nvmrc === `v${CLI_CONFIG.node}/*`
260
270
 
261
271
  }, fix_nvmrc);
262
272
 
263
- await this.test(`using node ${CLI_CONFIG.node}`, function () {
273
+ await self.test(`using node ${CLI_CONFIG.node}`, function () {
264
274
  let processMajor = parseInt(process.versions.node.split('.')[0]);
265
275
  let engineMajor = parseInt(self.package.engines.node.split('.')[0]);
266
276
  if (processMajor < engineMajor) {
@@ -269,19 +279,19 @@ Main.prototype.setup = async function () {
269
279
  return self.package.engines.node.toString() === CLI_CONFIG.node && processMajor >= engineMajor;
270
280
  }, fix_nodeVersion);
271
281
 
272
- // await this.test('project level package.json exists', async function () {
282
+ // await self.test('project level package.json exists', async function () {
273
283
  // return !!(self.projectPackage && self.projectPackage.version && self.projectPackage.name);
274
284
  // }, fix_projpackage);
275
285
 
276
- await this.test('functions level package.json exists', async function () {
286
+ await self.test('functions level package.json exists', async function () {
277
287
  return !!self.package && !!self.package.dependencies && !!self.package.devDependencies && !!self.package.version;
278
288
  }, fix_functionspackage);
279
289
 
280
- // await this.test('functions level package.json has updated version', async function () {
290
+ // await self.test('functions level package.json has updated version', async function () {
281
291
  // return self.package.version === self.projectPackage.version;
282
292
  // }, fix_packageversion);
283
293
 
284
- await this.test('using updated firebase-admin', async function () {
294
+ await self.test('using updated firebase-admin', async function () {
285
295
  let pkg = 'firebase-admin';
286
296
  // let latest = semver.clean(await getPkgVersion(pkg));
287
297
  let latest = semver.clean(cleanPackageVersion(self.packageJSON.dependencies['firebase-admin']));
@@ -297,7 +307,7 @@ Main.prototype.setup = async function () {
297
307
  return !(semver.gt(latest, mine)) || majorVersionMismatch;
298
308
  }, fix_fba);
299
309
 
300
- await this.test('using updated firebase-functions', async function () {
310
+ await self.test('using updated firebase-functions', async function () {
301
311
  let pkg = 'firebase-functions';
302
312
  // let latest = semver.clean(await getPkgVersion(pkg));
303
313
  let latest = semver.clean(cleanPackageVersion(self.packageJSON.dependencies['firebase-functions']));
@@ -313,7 +323,7 @@ Main.prototype.setup = async function () {
313
323
  return !(semver.gt(latest, mine)) || majorVersionMismatch;
314
324
  }, fix_fbf);
315
325
 
316
- await this.test('using updated backend-manager', async function () {
326
+ await self.test('using updated backend-manager', async function () {
317
327
  let pkg = 'backend-manager';
318
328
  let latest = semver.clean(await getPkgVersion(pkg));
319
329
  let mine = cleanPackageVersion(self.package.dependencies[pkg] || '0.0.0');
@@ -333,36 +343,36 @@ Main.prototype.setup = async function () {
333
343
  bemPackageVersionWarning(pkg, bemv, latest);
334
344
  }());
335
345
 
336
- // await this.test('using updated backend-assistant', async function () {
346
+ // await self.test('using updated backend-assistant', async function () {
337
347
  // let pkg = 'backend-assistant';
338
348
  // let latest = semver.clean(await getPkgVersion(pkg));
339
349
  // let mine = (self.package.dependencies[pkg] || '0.0.0').replace('^', '').replace('~', '');
340
350
  // return isLocal(mine) || !(semver.gt(latest, mine));
341
351
  // }, fix_bea);
342
352
 
343
- // await this.test('using updated ultimate-jekyll-poster', async function () {
353
+ // await self.test('using updated ultimate-jekyll-poster', async function () {
344
354
  // let pkg = 'ultimate-jekyll-poster';
345
355
  // let latest = semver.clean(await getPkgVersion(pkg));
346
356
  // let mine = (self.package.dependencies[pkg] || '0.0.0').replace('^', '').replace('~', '');
347
357
  // return isLocal(mine) || !(semver.gt(latest, mine));
348
358
  // }, fix_ujp);
349
359
 
350
- // await this.test('using updated @firebase/testing', async function () {
360
+ // await self.test('using updated @firebase/testing', async function () {
351
361
  // let pkg = '@firebase/testing';
352
362
  // let latest = semver.clean(await getPkgVersion(pkg));
353
363
  // let mine = (self.package.devDependencies[pkg] || '0.0.0').replace('^', '').replace('~', '');
354
364
  // return isLocal(mine) || !(semver.gt(latest, mine));
355
365
  // }, fix_fbTesting);
356
366
 
357
- // await this.test('using updated mocha', async function () {
367
+ // await self.test('using updated mocha', async function () {
358
368
  // let pkg = 'mocha';
359
369
  // let latest = semver.clean(await getPkgVersion(pkg));
360
370
  // let mine = (self.package.devDependencies[pkg] || '0.0.0').replace('^', '').replace('~', '');
361
371
  // return isLocal(mine) || !(semver.gt(latest, mine));
362
372
  // }, fix_mocha);
363
373
 
364
- await this.test('using proper .runtimeconfig', async function () {
365
- let runtimeconfig = JSON.parse(fs.read(`${self.firebaseProjectPath}/functions/.runtimeconfig.json`) || '{}');
374
+ await self.test('using proper .runtimeconfig', async function () {
375
+ let runtimeconfig = JSON.parse(jetpack.read(`${self.firebaseProjectPath}/functions/.runtimeconfig.json`) || '{}');
366
376
  let ogPaths = getObjectPaths(runtimeconfigTemplate).split('\n');
367
377
  let pass = true;
368
378
  for (var i = 0, l = ogPaths.length; i < l; i++) {
@@ -377,8 +387,8 @@ Main.prototype.setup = async function () {
377
387
 
378
388
  }, fix_runtimeConfig);
379
389
 
380
- await this.test('using proper backend-manager-config.json', async function () {
381
- let bemConfig = JSON.parse(fs.read(`${self.firebaseProjectPath}/functions/backend-manager-config.json`) || '{}');
390
+ await self.test('using proper backend-manager-config.json', async function () {
391
+ let bemConfig = JSON.parse(jetpack.read(`${self.firebaseProjectPath}/functions/backend-manager-config.json`) || '{}');
382
392
  let ogPaths = getObjectPaths(bemConfigTemplate).split('\n');
383
393
  let pass = true;
384
394
  for (var i = 0, l = ogPaths.length; i < l; i++) {
@@ -393,76 +403,133 @@ Main.prototype.setup = async function () {
393
403
 
394
404
  }, fix_bemConfig);
395
405
 
396
- await this.test('has service-account.json', function () {
397
- let exists = fs.exists(`${self.firebaseProjectPath}/functions/service-account.json`);
406
+ await self.test('has service-account.json', function () {
407
+ let exists = jetpack.exists(`${self.firebaseProjectPath}/functions/service-account.json`);
398
408
  return !!exists;
399
409
  }, fix_serviceAccount);
400
410
 
401
- await this.test('has correct .gitignore', function () {
411
+ await self.test('has correct .gitignore', function () {
402
412
  let match = self.gitignore.match(bem_giRegexOuter);
403
413
  if (!match) {
404
414
  return false;
405
415
  } else {
406
- let gitignore = fs.read(path.resolve(`${__dirname}/../../templates/gitignore.md`));
416
+ let gitignore = jetpack.read(path.resolve(`${__dirname}/../../templates/gitignore.md`));
407
417
  let file = gitignore.match(bem_giRegexOuter) ? RegExp.$1 : 'BAD1';
408
418
  let file2 = match[0].match(bem_giRegexOuter) ? RegExp.$1 : 'BAD2';
409
419
  return file === file2;
410
420
  }
411
421
  }, fix_gitignore);
412
422
 
413
- await this.test('firestore rules in JSON', function () {
414
- let firestore = _.get(self.firebaseJSON, 'firestore', {});
423
+
424
+ // Check firebase.json fields
425
+ await self.test('firestore rules in JSON', function () {
426
+ const firestore = _.get(self.firebaseJSON, 'firestore', {});
415
427
  return (firestore.rules === 'firestore.rules')
416
428
  }, fix_firestoreRules);
417
429
 
418
- await this.test('realtime rules in JSON', function () {
419
- let firestore = _.get(self.firebaseJSON, 'database', {});
420
- return (firestore.rules === 'security.rules.json')
430
+ await self.test('firestore indexes in JSON', function () {
431
+ let firestore = _.get(self.firebaseJSON, 'firestore', {});
432
+ return (firestore.indexes === 'firestore.indexes.json')
433
+ }, fix_firestoreIndexes);
434
+
435
+ await self.test('realtime rules in JSON', function () {
436
+ const database = _.get(self.firebaseJSON, 'database', {});
437
+ return (database.rules === 'database.rules.json')
421
438
  }, fix_realtimeRules);
422
439
 
423
- await this.test('hosting is set to dedicated folder in JSON', function () {
440
+ await self.test('storage rules in JSON', function () {
441
+ const storage = _.get(self.firebaseJSON, 'storage', {});
442
+ return (storage.rules === 'storage.rules')
443
+ }, fix_storageRules);
444
+
445
+ await self.test('remoteconfig template in JSON', function () {
446
+ const remoteconfig = _.get(self.firebaseJSON, 'remoteconfig', {});
447
+
448
+ if (self.remoteconfigJSONExists) {
449
+ return (remoteconfig.template === 'remoteconfig.template.json')
450
+ } else {
451
+ return (remoteconfig.template === '')
452
+ }
453
+ }, fix_remoteconfigTemplate);
454
+
455
+ await self.test('firestore indexes synced', async function () {
456
+ const tempPath = '_firestore.indexes.json'
457
+ const liveIndexes = await cmd_indexesGet(self, tempPath, false);
458
+
459
+ const localIndexes_exists = jetpack.exists(`${self.firebaseProjectPath}/firestore.indexes.json`);
460
+ let localIndexes
461
+ if (localIndexes_exists) {
462
+ localIndexes = require(`${self.firebaseProjectPath}/firestore.indexes.json`)
463
+ }
464
+ const equal = _.isEqual(liveIndexes, localIndexes);
465
+
466
+ if (localIndexes_exists && !equal) {
467
+ console.log(chalk.red(`To fix this...`));
468
+ console.log(chalk.red(` - ${chalk.bold('npx bm indexes:get')} to overwrite Firestore's local indexes with the live indexes`));
469
+ console.log(chalk.red(' OR'));
470
+ console.log(chalk.red(` - ${chalk.bold('firebase deploy --only firestore:indexes')} to replace the live indexes.`));
471
+ }
472
+
473
+ jetpack.remove(`${self.firebaseProjectPath}/${tempPath}`)
474
+
475
+ return !localIndexes_exists || equal
476
+ }, NOFIX);
477
+
478
+
479
+ // Update actual files
480
+ await self.test('update firestore rules file', function () {
481
+ let exists = jetpack.exists(`${self.firebaseProjectPath}/firestore.rules`);
482
+ let contents = jetpack.read(`${self.firebaseProjectPath}/firestore.rules`) || '';
483
+ let containsCore = contents.match(bem_fsRulesRegex);
484
+ let matchesVersion = contents.match(self.default.firestoreRulesVersionRegex);
485
+
486
+ return (!!exists && !!containsCore && !!matchesVersion);
487
+ }, fix_firestoreRulesFile);
488
+
489
+ await self.test('update firestore indexes file', function () {
490
+ let exists = jetpack.exists(`${self.firebaseProjectPath}/firestore.indexes.json`);
491
+ return (!!exists);
492
+ }, fix_firestoreIndexesFile);
493
+
494
+ await self.test('update realtime rules file', function () {
495
+ let exists = jetpack.exists(`${self.firebaseProjectPath}/database.rules.json`);
496
+ return (!!exists);
497
+ }, fix_realtimeRulesFile);
498
+
499
+ await self.test('update storage rules file', function () {
500
+ let exists = jetpack.exists(`${self.firebaseProjectPath}/storage.rules`);
501
+ return (!!exists);
502
+ }, fix_storageRulesFile);
503
+
504
+ await self.test('update remoteconfig template file', function () {
505
+ let exists = jetpack.exists(`${self.firebaseProjectPath}/remoteconfig.template.json`);
506
+ return (!!exists);
507
+ }, fix_remoteconfigTemplateFile);
508
+
509
+ // Hosting
510
+ await self.test('hosting is set to dedicated folder in JSON', function () {
424
511
  let hosting = _.get(self.firebaseJSON, 'hosting', {});
425
512
  return (hosting.public && (hosting.public === 'public' || hosting.public !== '.'))
426
513
  }, fix_firebaseHosting);
427
514
 
428
- await this.test('update backend-manager-tests.js', function () {
429
- fs.write(`${self.firebaseProjectPath}/test/backend-manager-tests.js`,
430
- (fs.read(path.resolve(`${__dirname}/../../templates/backend-manager-tests.js`)))
515
+ await self.test('update backend-manager-tests.js', function () {
516
+ jetpack.write(`${self.firebaseProjectPath}/test/backend-manager-tests.js`,
517
+ (jetpack.read(path.resolve(`${__dirname}/../../templates/backend-manager-tests.js`)))
431
518
  )
432
519
  return true;
433
520
  }, NOFIX);
434
521
 
435
- // await this.test('has mocha package.json script', function () {
522
+ // await self.test('has mocha package.json script', function () {
436
523
  // let script = _.get(self.package, 'scripts.test', '')
437
524
  // return script === MOCHA_PKG_SCRIPT;
438
525
  // }, fix_mochaScript);
439
526
 
440
- // await this.test('has clean:npm package.json script', function () {
527
+ // await self.test('has clean:npm package.json script', function () {
441
528
  // let script = _.get(self.package, 'scripts.clean:npm', '')
442
529
  // return script === NPM_CLEAN_SCRIPT;
443
530
  // }, fix_cleanNpmScript);
444
531
 
445
- await this.test('ignore firestore indexes file', function () {
446
- let firestore = _.get(self.firebaseJSON, 'firestore', {});
447
- return (firestore.indexes === '')
448
- }, fix_firebaseIndexes);
449
532
 
450
- await this.test('update firestore rules file', function () {
451
- let exists = fs.exists(`${self.firebaseProjectPath}/firestore.rules`);
452
- let contents = fs.read(`${self.firebaseProjectPath}/firestore.rules`) || '';
453
- let containsCore = contents.match(bem_fsRulesRegex);
454
- let matchesVersion = contents.match(self.default.firestoreRulesVersionRegex);
455
-
456
- // console.log('exists', !!exists);
457
- // console.log('containsCore', !!containsCore);
458
- // console.log('matchesVersion', !!matchesVersion);
459
- return (!!exists && !!containsCore && !!matchesVersion);
460
- }, fix_firestoreRulesFile);
461
-
462
- await this.test('update realtime rules file', function () {
463
- let exists = fs.exists(`${self.firebaseProjectPath}/security.rules.json`);
464
- return (!!exists);
465
- }, fix_realtimeRulesFile);
466
533
 
467
534
 
468
535
  if (self.package.dependencies['backend-manager'].includes('file:')) {
@@ -472,8 +539,8 @@ Main.prototype.setup = async function () {
472
539
  }
473
540
 
474
541
 
475
- const prepareStatsURL = `https://us-central1-${_.get(this.firebaseRC, 'projects.default')}.cloudfunctions.net/bm_api?authenticationToken=${_.get(this.runtimeConfigJSON, 'backend_manager.key')}`;
476
- // const prepareStatsURL = `https://us-central1-${_.get(this.firebaseRC, 'projects.default')}.cloudfunctions.net/bm_api?authenticationToken=undefined`;
542
+ const prepareStatsURL = `https://us-central1-${_.get(self.firebaseRC, 'projects.default')}.cloudfunctions.net/bm_api?authenticationToken=${_.get(self.runtimeConfigJSON, 'backend_manager.key')}`;
543
+ // const prepareStatsURL = `https://us-central1-${_.get(self.firebaseRC, 'projects.default')}.cloudfunctions.net/bm_api?authenticationToken=undefined`;
477
544
  const statsFetchResult = await fetch(prepareStatsURL, {
478
545
  method: 'post',
479
546
  body: JSON.stringify({
@@ -512,18 +579,11 @@ Main.prototype.setup = async function () {
512
579
 
513
580
  console.log(chalk.green(`Checks finished. Passed ${self.testCount}/${self.testTotal} tests.`));
514
581
  if (self.testCount !== self.testTotal) {
515
- console.log(chalk.yellow(`You should continue to run ${chalk.bold('bm setup')} until you pass all tests and fix all errors.`));
582
+ console.log(chalk.yellow(`You should continue to run ${chalk.bold('npx bm setup')} until you pass all tests and fix all errors.`));
516
583
  }
517
584
 
518
585
  return;
519
586
 
520
- // await this.test('deleted firestore indexes', function () {
521
- // let indexes = fs.exists(`${self.firebaseProjectPath}/firestore.indexes.json`);
522
- // return (!indexes);
523
- // }, fix_fsindexes);
524
-
525
- // console.log(self.package);
526
-
527
587
  };
528
588
 
529
589
  // https://stackoverflow.com/questions/41802259/javascript-deep-check-objects-have-same-keys
@@ -550,7 +610,7 @@ function getObjectPaths(object, parent) {
550
610
  }
551
611
 
552
612
  Main.prototype.test = async function(name, fn, fix, args) {
553
- let self = this;
613
+ const self = this;
554
614
  let status;
555
615
  let passed = await fn();
556
616
  return new Promise(async function(resolve, reject) {
@@ -600,9 +660,9 @@ function bemPackageVersionWarning(package, current, latest) {
600
660
  async function fix_runtimeConfig(self) {
601
661
  return new Promise(function(resolve, reject) {
602
662
  log(NOFIX_TEXT);
603
- log(chalk.red(`You need to run ${chalk.bold(`bm config:set`)} for each of these keys:`));
663
+ log(chalk.red(`You need to run ${chalk.bold(`npx bm config:set`)} for each of these keys:`));
604
664
  let objectKeys = getObjectPaths(runtimeconfigTemplate).split('\n');
605
- let theirConfig = JSON.parse(fs.read(`${self.firebaseProjectPath}/functions/.runtimeconfig.json`) || '{}');
665
+ let theirConfig = JSON.parse(jetpack.read(`${self.firebaseProjectPath}/functions/.runtimeconfig.json`) || '{}');
606
666
  for (var i = 0, l = objectKeys.length; i < l; i++) {
607
667
  let item = objectKeys[i];
608
668
  if (!item) {return}
@@ -614,7 +674,7 @@ async function fix_runtimeConfig(self) {
614
674
  }
615
675
  }
616
676
  // console.log('objectKeys', objectKeys);
617
- // log(chalk.red(`You need to run ${chalk.bold(`bm config:set`)} for each of these keys: \n${getObjectPaths(runtimeconfigTemplate)}`));
677
+ // log(chalk.red(`You need to run ${chalk.bold(`npx bm config:set`)} for each of these keys: \n${getObjectPaths(runtimeconfigTemplate)}`));
618
678
  reject();
619
679
  });
620
680
  };
@@ -624,9 +684,9 @@ async function fix_bemConfig(self) {
624
684
  log(NOFIX_TEXT);
625
685
  log(chalk.red(`You need to open backend-manager-config.json and set each of these keys:`));
626
686
  let objectKeys = getObjectPaths(bemConfigTemplate).split('\n');
627
- let theirConfig = JSON.parse(fs.read(`${self.firebaseProjectPath}/functions/backend-manager-config.json`) || '{}');
687
+ let theirConfig = JSON.parse(jetpack.read(`${self.firebaseProjectPath}/functions/backend-manager-config.json`) || '{}');
628
688
  if (Object.keys(theirConfig).length < 1) {
629
- fs.write(`${self.firebaseProjectPath}/functions/backend-manager-config.json`, bemConfigTemplate)
689
+ jetpack.write(`${self.firebaseProjectPath}/functions/backend-manager-config.json`, bemConfigTemplate)
630
690
  }
631
691
  for (var i = 0, l = objectKeys.length; i < l; i++) {
632
692
  let item = objectKeys[i];
@@ -655,7 +715,7 @@ async function fix_serviceAccount(self) {
655
715
  // function fix_mochaScript(self) {
656
716
  // return new Promise(function(resolve, reject) {
657
717
  // _.set(self.package, 'scripts.test', MOCHA_PKG_SCRIPT);
658
- // fs.write(`${self.firebaseProjectPath}/functions/package.json`, JSON.stringify(self.package, null, 2) );
718
+ // jetpack.write(`${self.firebaseProjectPath}/functions/package.json`, JSON.stringify(self.package, null, 2) );
659
719
  // resolve();
660
720
  // });
661
721
  // }
@@ -664,7 +724,7 @@ function fix_nodeVersion(self) {
664
724
  return new Promise(function(resolve, reject) {
665
725
  _.set(self.package, 'engines.node', CLI_CONFIG.node)
666
726
 
667
- fs.write(`${self.firebaseProjectPath}/functions/package.json`, JSON.stringify(self.package, null, 2) );
727
+ jetpack.write(`${self.firebaseProjectPath}/functions/package.json`, JSON.stringify(self.package, null, 2) );
668
728
  resolve();
669
729
  });
670
730
  };
@@ -672,7 +732,7 @@ function fix_nodeVersion(self) {
672
732
  function fix_nvmrc(self) {
673
733
  return new Promise(function(resolve, reject) {
674
734
 
675
- fs.write(`${self.firebaseProjectPath}/functions/.nvmrc`, `v${CLI_CONFIG.node}/*`);
735
+ jetpack.write(`${self.firebaseProjectPath}/functions/.nvmrc`, `v${CLI_CONFIG.node}/*`);
676
736
  resolve();
677
737
  });
678
738
  };
@@ -691,7 +751,7 @@ function fix_projpackage(self) {
691
751
  self.projectPackage.dependencies = self.projectPackage.dependencies || {};
692
752
  self.projectPackage.devDependencies = self.projectPackage.devDependencies || {};
693
753
 
694
- fs.write(`${self.firebaseProjectPath}/package.json`, JSON.stringify(self.projectPackage, null, 2) );
754
+ jetpack.write(`${self.firebaseProjectPath}/package.json`, JSON.stringify(self.projectPackage, null, 2) );
695
755
  resolve();
696
756
  });
697
757
  };
@@ -702,7 +762,7 @@ function fix_functionspackage(self) {
702
762
  self.package.devDependencies = self.package.devDependencies || {};
703
763
  self.package.version = self.package.version || '0.0.1';
704
764
 
705
- fs.write(`${self.firebaseProjectPath}/functions/package.json`, JSON.stringify(self.package, null, 2) );
765
+ jetpack.write(`${self.firebaseProjectPath}/functions/package.json`, JSON.stringify(self.package, null, 2) );
706
766
  resolve();
707
767
  });
708
768
  };
@@ -711,7 +771,7 @@ function fix_packageversion(self) {
711
771
  return new Promise(function(resolve, reject) {
712
772
  self.package.version = self.projectPackage.version;
713
773
 
714
- fs.write(`${self.firebaseProjectPath}/functions/package.json`, JSON.stringify(self.package, null, 2) );
774
+ jetpack.write(`${self.firebaseProjectPath}/functions/package.json`, JSON.stringify(self.package, null, 2) );
715
775
  resolve();
716
776
  });
717
777
  };
@@ -725,7 +785,12 @@ async function fix_fba(self) {
725
785
  return await installPkg('firebase-admin', `@${self.packageJSON.dependencies['firebase-admin']}`)
726
786
  };
727
787
  async function fix_bem(self) {
728
- return await installPkg('backend-manager')
788
+ await installPkg('backend-manager');
789
+
790
+ console.log(chalk.green(`Process has exited since a new version of backend-manager was installed. Run ${chalk.bold('npx bm setup')} again.`));
791
+ process.exit(0);
792
+
793
+ return;
729
794
  };
730
795
  // async function fix_bea(self) {
731
796
  // return await installPkg('backend-assistant')
@@ -742,7 +807,7 @@ async function fix_bem(self) {
742
807
 
743
808
  function fix_gitignore(self) {
744
809
  return new Promise(function(resolve, reject) {
745
- let gi = (fs.read(path.resolve(`${__dirname}/../../templates/gitignore.md`)));
810
+ let gi = (jetpack.read(path.resolve(`${__dirname}/../../templates/gitignore.md`)));
746
811
  if (self.gitignore.match(bem_giRegexOuter)) {
747
812
  self.gitignore = self.gitignore.replace(bem_giRegexOuter, gi);
748
813
  } else {
@@ -751,7 +816,7 @@ function fix_gitignore(self) {
751
816
  self.gitignore = self.gitignore.replace(/\n\s*\n$/mg, '\n')
752
817
  // self.gitignore = `${self.gitignore}\n${gi}`.replace(/$\n/m,'');
753
818
  // self.gitignore = self.gitignore.replace(/$\n/m,'');
754
- fs.write(`${self.firebaseProjectPath}/functions/.gitignore`, self.gitignore);
819
+ jetpack.write(`${self.firebaseProjectPath}/functions/.gitignore`, self.gitignore);
755
820
  resolve();
756
821
  });
757
822
  };
@@ -759,31 +824,39 @@ function fix_gitignore(self) {
759
824
  function fix_firestoreRules(self) {
760
825
  return new Promise(function(resolve, reject) {
761
826
  _.set(self.firebaseJSON, 'firestore.rules', 'firestore.rules')
762
- fs.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
827
+ jetpack.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
828
+ resolve();
829
+ });
830
+ };
831
+
832
+ function fix_firestoreIndexes(self) {
833
+ return new Promise(function(resolve, reject) {
834
+ _.set(self.firebaseJSON, 'firestore.indexes', 'firestore.indexes.json')
835
+ jetpack.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
763
836
  resolve();
764
837
  });
765
838
  };
766
839
 
767
840
  function fix_realtimeRules(self) {
768
841
  return new Promise(function(resolve, reject) {
769
- _.set(self.firebaseJSON, 'database.rules', 'security.rules.json')
770
- fs.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
842
+ _.set(self.firebaseJSON, 'database.rules', 'database.rules.json')
843
+ jetpack.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
771
844
  resolve();
772
845
  });
773
846
  };
774
847
 
775
- function fix_firebaseHosting(self) {
848
+ function fix_storageRules(self) {
776
849
  return new Promise(function(resolve, reject) {
777
- _.set(self.firebaseJSON, 'hosting.public', 'public')
778
- fs.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
850
+ _.set(self.firebaseJSON, 'storage.rules', 'storage.rules')
851
+ jetpack.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
779
852
  resolve();
780
853
  });
781
854
  };
782
855
 
783
- function fix_firebaseIndexes(self) {
856
+ function fix_remoteconfigTemplate(self) {
784
857
  return new Promise(function(resolve, reject) {
785
- _.set(self.firebaseJSON, 'firestore.indexes', "")
786
- fs.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
858
+ _.set(self.firebaseJSON, 'remoteconfig.template', self.remoteconfigJSONExists ? 'remoteconfig.template.json' : '')
859
+ jetpack.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
787
860
  resolve();
788
861
  });
789
862
  };
@@ -791,13 +864,13 @@ function fix_firebaseIndexes(self) {
791
864
  function fix_firestoreRulesFile(self) {
792
865
  return new Promise(function(resolve, reject) {
793
866
  let path = `${self.firebaseProjectPath}/firestore.rules`;
794
- let exists = fs.exists(path);
795
- let contents = fs.read(path) || '';
867
+ let exists = jetpack.exists(path);
868
+ let contents = jetpack.read(path) || '';
796
869
 
797
870
  if (!exists || !contents) {
798
871
  log(chalk.yellow(`Writing new firestore.rules file...`));
799
- fs.write(path, self.default.firestoreRulesWhole)
800
- contents = fs.read(path) || '';
872
+ jetpack.write(path, self.default.firestoreRulesWhole)
873
+ contents = jetpack.read(path) || '';
801
874
  }
802
875
 
803
876
  let hasTemplate = contents.match(bem_fsRulesRegex) || contents.match(bem_fsRulesBackupRegex);
@@ -812,32 +885,85 @@ function fix_firestoreRulesFile(self) {
812
885
  // console.log('replace wih', self.default.firestoreRulesCore);
813
886
  contents = contents.replace(bem_fsRulesBackupRegex, self.default.firestoreRulesCore)
814
887
  contents = contents.replace(bem_fsRulesRegex, self.default.firestoreRulesCore)
815
- fs.write(path, contents)
888
+ jetpack.write(path, contents)
816
889
  log(chalk.yellow(`Writing core rules to firestore.rules file...`));
817
890
  }
818
891
  resolve();
819
892
  });
820
893
  };
821
894
 
895
+ function fix_firestoreIndexesFile(self) {
896
+ return new Promise(async function(resolve, reject) {
897
+ const name = 'firestore.indexes.json';
898
+ let filePath = `${self.firebaseProjectPath}/${name}`;
899
+ let exists = jetpack.exists(filePath);
900
+
901
+ if (!exists) {
902
+ log(chalk.yellow(`Writing new ${name} file...`));
903
+ await cmd_indexesGet(self, name, false);
904
+ }
905
+
906
+ resolve();
907
+ });
908
+ };
909
+
822
910
  function fix_realtimeRulesFile(self) {
823
911
  return new Promise(function(resolve, reject) {
824
- let filePath = `${self.firebaseProjectPath}/security.rules.json`;
825
- let exists = fs.exists(filePath);
826
- let contents = fs.read(filePath) || '';
912
+ const name = 'database.rules.json';
913
+ let filePath = `${self.firebaseProjectPath}/${name}`;
914
+ let exists = jetpack.exists(filePath);
915
+ let contents = jetpack.read(filePath) || '';
827
916
 
828
917
  if (!exists) {
829
- log(chalk.yellow(`Writing new security.rules.json file...`));
830
- fs.write(filePath, fs.read(path.resolve(`${__dirname}/../../templates/security.rules.json`)))
831
- contents = fs.read(filePath) || '';
918
+ log(chalk.yellow(`Writing new ${name} file...`));
919
+ jetpack.write(filePath, jetpack.read(path.resolve(`${__dirname}/../../templates/${name}`)))
920
+ contents = jetpack.read(filePath) || '';
832
921
  }
833
922
 
834
923
  resolve();
835
924
  });
836
925
  };
837
926
 
838
- function fix_fsindexes(self) {
927
+ function fix_storageRulesFile(self) {
839
928
  return new Promise(function(resolve, reject) {
840
- fs.remove(`${self.firebaseProjectPath}/firestore.indexes.json`)
929
+ const name = 'storage.rules';
930
+ let filePath = `${self.firebaseProjectPath}/${name}`;
931
+ let exists = jetpack.exists(filePath);
932
+ let contents = jetpack.read(filePath) || '';
933
+
934
+ if (!exists) {
935
+ log(chalk.yellow(`Writing new ${name} file...`));
936
+ jetpack.write(filePath, jetpack.read(path.resolve(`${__dirname}/../../templates/${name}`)))
937
+ contents = jetpack.read(filePath) || '';
938
+ }
939
+
940
+ resolve();
941
+ });
942
+ };
943
+
944
+ function fix_remoteconfigTemplateFile(self) {
945
+ return new Promise(function(resolve, reject) {
946
+ const name = 'remoteconfig.template.json'
947
+ let filePath = `${self.firebaseProjectPath}/${name}`;
948
+ let exists = jetpack.exists(filePath);
949
+ let contents = jetpack.read(filePath) || '';
950
+
951
+ if (!exists) {
952
+ log(chalk.yellow(`Writing new ${name} file...`));
953
+ jetpack.write(filePath, jetpack.read(path.resolve(`${__dirname}/../../templates/${name}`)))
954
+ contents = jetpack.read(filePath) || '';
955
+ }
956
+
957
+ resolve();
958
+ });
959
+ };
960
+
961
+
962
+ // Hosting
963
+ function fix_firebaseHosting(self) {
964
+ return new Promise(function(resolve, reject) {
965
+ _.set(self.firebaseJSON, 'hosting.public', 'public')
966
+ jetpack.write(`${self.firebaseProjectPath}/firebase.json`, JSON.stringify(self.firebaseJSON, null, 2));
841
967
  resolve();
842
968
  });
843
969
  };
@@ -855,130 +981,165 @@ function getPkgVersion(package) {
855
981
  });
856
982
  }
857
983
 
858
-
859
-
860
- async function cmd_configGet(self) {
861
- return new Promise(function(resolve, reject) {
862
- let cmd = exec(`firebase functions:config:get > ${self.firebaseProjectPath}/functions/.runtimeconfig.json`, function (error, stdout, stderr) {
863
- if (error) {
984
+ async function cmd_indexesGet(self, filePath, log) {
985
+ return new Promise(function(resolve, reject) {
986
+ const finalPath = `${self.firebaseProjectPath}/${filePath || 'firestore.indexes.json'}`;
987
+ let existingIndexes;
988
+ try {
989
+ existingIndexes = require(`${self.firebaseProjectPath}/firestore.indexes.json`)
990
+ } catch (e) {
991
+ if (log !== false) {
992
+ console.error('Failed to read existing local indexes', e);
993
+ }
994
+ }
995
+ let cmd = exec(`firebase firestore:indexes > ${finalPath}`, function (error, stdout, stderr) {
996
+ if (error) {
997
+ if (log !== false) {
864
998
  console.error(error);
865
- reject(error);
866
- } else {
867
- console.log(chalk.green(`Saving config to: ${self.firebaseProjectPath}/functions/.runtimeconfig.json`));
999
+ }
1000
+ reject(error);
1001
+ } else {
1002
+ const newIndexes = require(finalPath);
1003
+ if (log !== false) {
1004
+ console.log(chalk.green(`Saving indexes to: ${finalPath}`));
868
1005
  console.log(stdout);
869
- resolve();
1006
+
1007
+ const equal = (_.isEqual(newIndexes, existingIndexes));
1008
+
1009
+ if (!equal) {
1010
+ console.log(chalk.red(`The live and local index files did not match and have been overwritten by the ${chalk.bold('live indexes')}`));
1011
+ }
1012
+
870
1013
  }
871
- });
1014
+ resolve(newIndexes);
1015
+ }
872
1016
  });
873
- }
1017
+ });
1018
+ }
874
1019
 
875
- async function cmd_configSet(self, newPath, newValue) {
876
- return new Promise(async function(resolve, reject) {
877
- // console.log(this.options);
878
- // console.log(this.argv);
879
- newPath = newPath || await inquirer.prompt([
880
- {
881
- type: 'input',
882
- name: 'path',
883
- default: 'service.key'
884
- }
885
- ]).then(answers => answers.path)
1020
+ async function cmd_configGet(self, filePath) {
1021
+ return new Promise(function(resolve, reject) {
1022
+ const finalPath = `${self.firebaseProjectPath}/${filePath || 'functions/.runtimeconfig.json'}`;
1023
+ let cmd = exec(`firebase functions:config:get > ${finalPath}`, function (error, stdout, stderr) {
1024
+ if (error) {
1025
+ console.error(error);
1026
+ reject(error);
1027
+ } else {
1028
+ console.log(chalk.green(`Saving config to: ${finalPath}`));
1029
+ console.log(stdout);
1030
+ resolve(require(finalPath));
1031
+ }
1032
+ });
1033
+ });
1034
+ }
1035
+
1036
+ async function cmd_configSet(self, newPath, newValue) {
1037
+ return new Promise(async function(resolve, reject) {
1038
+ // console.log(self.options);
1039
+ // console.log(self.argv);
1040
+ newPath = newPath || await inquirer.prompt([
1041
+ {
1042
+ type: 'input',
1043
+ name: 'path',
1044
+ default: 'service.key'
1045
+ }
1046
+ ]).then(answers => answers.path)
886
1047
 
1048
+ try {
1049
+ const object = JSON5.parse(newPath)
887
1050
  try {
888
- const object = JSON5.parse(newPath)
889
- try {
890
- if (typeof object === 'object') {
891
- const keyify = (obj, prefix = '') =>
892
- Object.keys(obj).reduce((res, el) => {
893
- if( Array.isArray(obj[el]) ) {
894
- return res;
895
- } else if( typeof obj[el] === 'object' && obj[el] !== null ) {
896
- return [...res, ...keyify(obj[el], prefix + el + '.')];
897
- }
898
- return [...res, prefix + el];
899
- }, []);
900
- const pathArray = keyify(object);
901
- for (var i = 0; i < pathArray.length; i++) {
902
- const pathName = pathArray[i];
903
- const pathValue = _.get(object, pathName);
904
- // console.log(chalk.blue(`Setting object: ${chalk.bold(pathName)} = ${chalk.bold(pathValue)}`));
905
- console.log(chalk.blue(`Setting object: ${chalk.bold(pathName)}`));
906
- await cmd_configSet(self, pathName, pathValue)
907
- .catch(e => {
908
- log(chalk.red(`Failed to save object path: ${e}`));
909
- })
910
- }
911
- return resolve();
1051
+ if (typeof object === 'object') {
1052
+ const keyify = (obj, prefix = '') =>
1053
+ Object.keys(obj).reduce((res, el) => {
1054
+ if( Array.isArray(obj[el]) ) {
1055
+ return res;
1056
+ } else if( typeof obj[el] === 'object' && obj[el] !== null ) {
1057
+ return [...res, ...keyify(obj[el], prefix + el + '.')];
1058
+ }
1059
+ return [...res, prefix + el];
1060
+ }, []);
1061
+ const pathArray = keyify(object);
1062
+ for (var i = 0; i < pathArray.length; i++) {
1063
+ const pathName = pathArray[i];
1064
+ const pathValue = _.get(object, pathName);
1065
+ // console.log(chalk.blue(`Setting object: ${chalk.bold(pathName)} = ${chalk.bold(pathValue)}`));
1066
+ console.log(chalk.blue(`Setting object: ${chalk.bold(pathName)}`));
1067
+ await cmd_configSet(self, pathName, pathValue)
1068
+ .catch(e => {
1069
+ log(chalk.red(`Failed to save object path: ${e}`));
1070
+ })
912
1071
  }
913
- } catch (e) {
914
- log(chalk.red(`Failed to save object: ${e}`));
915
- return reject(e)
1072
+ return resolve();
916
1073
  }
917
1074
  } catch (e) {
1075
+ log(chalk.red(`Failed to save object: ${e}`));
1076
+ return reject(e)
918
1077
  }
1078
+ } catch (e) {
1079
+ }
919
1080
 
920
- newValue = newValue || await inquirer.prompt([
921
- {
922
- type: 'input',
923
- name: 'value',
924
- default: '123-abc'
925
- }
926
- ]).then(answers => answers.value)
927
-
928
- let isInvalid = false;
929
- if (newPath !== newPath.toLowerCase()) {
930
- isInvalid = true;
931
- newPath = newPath.replace(/([A-Z])/g, '_$1').trim().toLowerCase();
1081
+ newValue = newValue || await inquirer.prompt([
1082
+ {
1083
+ type: 'input',
1084
+ name: 'value',
1085
+ default: '123-abc'
932
1086
  }
933
- log(chalk.yellow(`Saving to ${chalk.bold(newPath)}...`));
934
- let cmd = exec(`firebase functions:config:set ${newPath}="${newValue}"`, function (error, stdout, stderr) {
935
- if (error) {
936
- log(chalk.red(`Failed to save ${chalk.bold(newPath)}: ${error}`));
937
- reject(error);
1087
+ ]).then(answers => answers.value)
1088
+
1089
+ let isInvalid = false;
1090
+ if (newPath !== newPath.toLowerCase()) {
1091
+ isInvalid = true;
1092
+ newPath = newPath.replace(/([A-Z])/g, '_$1').trim().toLowerCase();
1093
+ }
1094
+ log(chalk.yellow(`Saving to ${chalk.bold(newPath)}...`));
1095
+ let cmd = exec(`firebase functions:config:set ${newPath}="${newValue}"`, function (error, stdout, stderr) {
1096
+ if (error) {
1097
+ log(chalk.red(`Failed to save ${chalk.bold(newPath)}: ${error}`));
1098
+ reject(error);
1099
+ } else {
1100
+ console.log(stdout);
1101
+ if (isInvalid) {
1102
+ log(chalk.red(`!!! Your path contained an invalid uppercase character`));
1103
+ log(chalk.red(`!!! It was set to: ${chalk.bold(newPath)}`));
938
1104
  } else {
939
- console.log(stdout);
940
- if (isInvalid) {
941
- log(chalk.red(`!!! Your path contained an invalid uppercase character`));
942
- log(chalk.red(`!!! It was set to: ${chalk.bold(newPath)}`));
943
- } else {
944
- log(chalk.green(`Successfully saved to ${chalk.bold(newPath)}`));
945
- }
946
- resolve();
1105
+ log(chalk.green(`Successfully saved to ${chalk.bold(newPath)}`));
947
1106
  }
948
- });
1107
+ resolve();
1108
+ }
949
1109
  });
950
- }
1110
+ });
1111
+ }
951
1112
 
952
- async function cmd_configUnset(self) {
953
- return new Promise(async function(resolve, reject) {
954
- // console.log(this.options);
955
- // console.log(this.argv);
956
- await inquirer
957
- .prompt([
958
- /* Pass your questions in here */
959
- {
960
- type: 'input',
961
- name: 'path',
962
- default: 'service.key'
1113
+ async function cmd_configUnset(self) {
1114
+ return new Promise(async function(resolve, reject) {
1115
+ // console.log(self.options);
1116
+ // console.log(self.argv);
1117
+ await inquirer
1118
+ .prompt([
1119
+ /* Pass your questions in here */
1120
+ {
1121
+ type: 'input',
1122
+ name: 'path',
1123
+ default: 'service.key'
1124
+ }
1125
+ ])
1126
+ .then(answers => {
1127
+ // Use user feedback for... whatever!!
1128
+ // console.log('answer', answers);
1129
+ log(chalk.yellow(`Deleting ${chalk.bold(answers.path)}...`));
1130
+ let cmd = exec(`firebase functions:config:unset ${answers.path}`, function (error, stdout, stderr) {
1131
+ if (error) {
1132
+ log(chalk.red(`Failed to delete ${chalk.bold(answers.path)}: ${error}`));
1133
+ reject(error);
1134
+ } else {
1135
+ console.log(stdout);
1136
+ log(chalk.green(`Successfully deleted ${chalk.bold(answers.path)}`));
1137
+ resolve();
963
1138
  }
964
- ])
965
- .then(answers => {
966
- // Use user feedback for... whatever!!
967
- // console.log('answer', answers);
968
- log(chalk.yellow(`Deleting ${chalk.bold(answers.path)}...`));
969
- let cmd = exec(`firebase functions:config:unset ${answers.path}`, function (error, stdout, stderr) {
970
- if (error) {
971
- log(chalk.red(`Failed to delete ${chalk.bold(answers.path)}: ${error}`));
972
- reject(error);
973
- } else {
974
- console.log(stdout);
975
- log(chalk.green(`Successfully deleted ${chalk.bold(answers.path)}`));
976
- resolve();
977
- }
978
- });
979
1139
  });
980
- });
981
- }
1140
+ });
1141
+ });
1142
+ }
982
1143
 
983
1144
 
984
1145
  // HELPER
@@ -11,7 +11,7 @@ Module.prototype.main = function () {
11
11
 
12
12
  return new Promise(async function(resolve, reject) {
13
13
 
14
- if (payload.user.authenticated || payload.user.roles.admin) {
14
+ if (payload.user.roles.admin) {
15
15
 
16
16
  // console.log('---payload.data.payload', payload.data.payload);
17
17
 
@@ -7,13 +7,15 @@ const { get, merge } = require('lodash');
7
7
 
8
8
 
9
9
  function Manager(exporter, options) {
10
+ const self = this;
10
11
  // Constants
11
- this.SERVER_UUID = '11111111-1111-1111-1111-111111111111';
12
+ self.SERVER_UUID = '11111111-1111-1111-1111-111111111111';
12
13
 
13
14
  // Modable
14
- this.libraries = {};
15
- this.handlers = {};
16
- return this;
15
+ self.libraries = {};
16
+ self.handlers = {};
17
+
18
+ return self;
17
19
  }
18
20
 
19
21
  Manager.prototype.init = function (exporter, options) {
@@ -92,7 +94,7 @@ Manager.prototype.init = function (exporter, options) {
92
94
  }
93
95
 
94
96
  if (self.options.sentry) {
95
- const sentryRelease = `${self.config.app.id || self.project.projectId}@${self.package.version}`;
97
+ const sentryRelease = `${get(self.config, 'app.id') || self.project.projectId}@${self.package.version}`;
96
98
  const sentryDSN = get(self.config, 'sentry.dsn', '');
97
99
  // console.log('Sentry', sentryRelease, sentryDSN);
98
100
 
@@ -0,0 +1,31 @@
1
+ {
2
+ "rules": {
3
+ "gatherings": {
4
+ ".read": false,
5
+ ".write": false,
6
+ "online": {
7
+ ".read": "auth.uid != null && query.equalTo == auth.uid",
8
+ ".write": false,
9
+ ".indexOn": ["uid"],
10
+ "$uid": {
11
+ ".read": "
12
+ // Allowed if user is signed in AND is the owner of the doc
13
+ (auth != null && auth.uid == data.child('uid').val())
14
+ ",
15
+ ".write": "
16
+ // Allowed if the user is signed in AND is the owner of the existing doc
17
+ (auth != null && auth.uid == data.child('uid').val())
18
+ // Allowed if the user is signed in AND is the owner of the new doc
19
+ || (auth != null && auth.uid == newData.child('uid').val())
20
+ // Allowed if it's a delete
21
+ || (!newData.exists())
22
+ // Allowed if the existing doc has no owner
23
+ || (data.child('uid').val() == '')
24
+ // Allowed if the new doc has no owner
25
+ || (newData.child('uid').val() == '')
26
+ ",
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "indexes": [],
3
+ "fieldOverrides": []
4
+ }
File without changes
@@ -0,0 +1,8 @@
1
+ rules_version = '2';
2
+ service firebase.storage {
3
+ match /b/{bucket}/o {
4
+ match /{allPaths=**} {
5
+ allow read, write: if request.auth!=null;
6
+ }
7
+ }
8
+ }
@@ -1,6 +0,0 @@
1
- {
2
- "rules": {
3
- ".read": true,
4
- ".write": true
5
- }
6
- }