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 +4 -4
- package/src/cli/cli.js +429 -268
- package/src/manager/functions/core/actions/api/admin/firestore-read.js +1 -1
- package/src/manager/index.js +7 -5
- package/templates/database.rules.json +31 -0
- package/templates/firestore.indexes.json +4 -0
- package/templates/remoteconfig.template.json +0 -0
- package/templates/storage.rules +8 -0
- package/templates/security.rules.json +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backend-manager",
|
|
3
|
-
"version": "2.0.
|
|
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.
|
|
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.
|
|
50
|
+
"node-powertools": "^0.0.13",
|
|
51
51
|
"npm-api": "^1.0.1",
|
|
52
|
-
"paypal-server-api": "^0.0.
|
|
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
|
|
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((
|
|
53
|
-
let bemConfigTemplate = JSON.parse((
|
|
54
|
-
let CLI_CONFIG = JSON5.parse((
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
72
|
+
self.options[args[i]] = true;
|
|
73
73
|
}
|
|
74
74
|
// console.log(args);
|
|
75
75
|
// console.log(options);
|
|
76
|
-
if (
|
|
77
|
-
console.log(`Backend manager is 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 (
|
|
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 (
|
|
87
|
-
console.log('cwd: ',
|
|
86
|
+
if (self.options.cwd) {
|
|
87
|
+
console.log('cwd: ', self.firebaseProjectPath);
|
|
88
88
|
}
|
|
89
|
-
if (
|
|
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 ((
|
|
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 ((
|
|
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 (
|
|
105
|
-
if (!
|
|
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 =
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
195
|
+
// if (self.options['url']) {
|
|
191
196
|
// // await self.setup();
|
|
192
197
|
// // firebase emulators:exec --only firestore 'npm test'
|
|
193
|
-
// log(
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
210
|
-
let cwd =
|
|
211
|
-
log(chalk.green(`\n---- RUNNING v${
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
237
|
-
// bem_giRegex = new RegExp(
|
|
238
|
-
bem_giRegex = new RegExp(
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
log(chalk.black(`Id: `, chalk.bold(`${
|
|
244
|
-
log(chalk.black(`Url:`, chalk.bold(`${
|
|
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
|
|
251
|
-
let exists =
|
|
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
|
|
265
|
+
await self.test('.nvmrc file has proper version', async function () {
|
|
256
266
|
// return !!self.package.dependencies && !!self.package.devDependencies;
|
|
257
|
-
// let gitignore =
|
|
258
|
-
let 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
365
|
-
let runtimeconfig = JSON.parse(
|
|
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
|
|
381
|
-
let bemConfig = JSON.parse(
|
|
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
|
|
397
|
-
let exists =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
414
|
-
|
|
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
|
|
419
|
-
let firestore = _.get(self.firebaseJSON, '
|
|
420
|
-
return (firestore.
|
|
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
|
|
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
|
|
429
|
-
|
|
430
|
-
(
|
|
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
|
|
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
|
|
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(
|
|
476
|
-
// const prepareStatsURL = `https://us-central1-${_.get(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
687
|
+
let theirConfig = JSON.parse(jetpack.read(`${self.firebaseProjectPath}/functions/backend-manager-config.json`) || '{}');
|
|
628
688
|
if (Object.keys(theirConfig).length < 1) {
|
|
629
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 = (
|
|
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
|
-
|
|
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
|
-
|
|
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', '
|
|
770
|
-
|
|
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
|
|
848
|
+
function fix_storageRules(self) {
|
|
776
849
|
return new Promise(function(resolve, reject) {
|
|
777
|
-
_.set(self.firebaseJSON, '
|
|
778
|
-
|
|
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
|
|
856
|
+
function fix_remoteconfigTemplate(self) {
|
|
784
857
|
return new Promise(function(resolve, reject) {
|
|
785
|
-
_.set(self.firebaseJSON, '
|
|
786
|
-
|
|
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 =
|
|
795
|
-
let contents =
|
|
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
|
-
|
|
800
|
-
contents =
|
|
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
|
-
|
|
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
|
-
|
|
825
|
-
let
|
|
826
|
-
let
|
|
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
|
|
830
|
-
|
|
831
|
-
contents =
|
|
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
|
|
927
|
+
function fix_storageRulesFile(self) {
|
|
839
928
|
return new Promise(function(resolve, reject) {
|
|
840
|
-
|
|
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
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
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
|
-
|
|
866
|
-
|
|
867
|
-
|
|
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
|
-
|
|
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
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
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
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
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
|
-
|
|
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
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
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
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
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
|
-
|
|
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
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
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.
|
|
14
|
+
if (payload.user.roles.admin) {
|
|
15
15
|
|
|
16
16
|
// console.log('---payload.data.payload', payload.data.payload);
|
|
17
17
|
|
package/src/manager/index.js
CHANGED
|
@@ -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
|
-
|
|
12
|
+
self.SERVER_UUID = '11111111-1111-1111-1111-111111111111';
|
|
12
13
|
|
|
13
14
|
// Modable
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
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
|
+
}
|
|
File without changes
|