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