backend-manager 2.4.17 → 2.4.21
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 +3 -4
- package/src/cli/cli.js +24 -1
- package/src/manager/functions/core/actions/api/admin/database-read.js +40 -0
- package/src/manager/functions/core/actions/api/admin/database-write.js +44 -0
- package/src/manager/functions/core/actions/api/admin/firestore-read.js +1 -2
- package/src/manager/functions/core/actions/api.js +4 -0
- package/src/manager/functions/core/events/auth/on-create.js +26 -19
- package/src/manager/functions/core/events/auth/on-delete.js +27 -19
- package/src/manager/functions/core/events/firestore/on-subscription.js +39 -24
- package/src/manager/index.js +36 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backend-manager",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.21",
|
|
4
4
|
"description": "Quick tools for developing Firebase functions",
|
|
5
5
|
"main": "src/manager/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"busboy": "^1.6.0",
|
|
36
36
|
"chalk": "^4.1.2",
|
|
37
37
|
"cors": "^2.8.5",
|
|
38
|
-
"dotenv": "^16.0.
|
|
38
|
+
"dotenv": "^16.0.2",
|
|
39
39
|
"firebase-admin": "^9.12.0",
|
|
40
|
-
"firebase-functions": "^3.
|
|
40
|
+
"firebase-functions": "^3.23.0",
|
|
41
41
|
"fs-jetpack": "^4.3.1",
|
|
42
42
|
"hcaptcha": "^0.1.1",
|
|
43
43
|
"inquirer": "^8.2.4",
|
|
@@ -46,7 +46,6 @@
|
|
|
46
46
|
"lodash": "^4.17.21",
|
|
47
47
|
"lowdb": "^1.0.0",
|
|
48
48
|
"mailchimp-api-v3": "^1.15.0",
|
|
49
|
-
"mocha": "^9.2.2",
|
|
50
49
|
"moment": "^2.29.4",
|
|
51
50
|
"node-fetch": "^2.6.7",
|
|
52
51
|
"node-powertools": "^0.0.21",
|
package/src/cli/cli.js
CHANGED
|
@@ -477,7 +477,7 @@ Main.prototype.setup = async function () {
|
|
|
477
477
|
jetpack.remove(`${self.firebaseProjectPath}/${tempPath}`)
|
|
478
478
|
|
|
479
479
|
return !localIndexes_exists || equal
|
|
480
|
-
},
|
|
480
|
+
}, fix_indexesSync);
|
|
481
481
|
|
|
482
482
|
await self.test('add roles/datastore.importExportAdmin', async function () {
|
|
483
483
|
const result = await cmd_iamImportExport(self).catch(e => e);
|
|
@@ -895,6 +895,29 @@ function fix_remoteconfigTemplate(self) {
|
|
|
895
895
|
});
|
|
896
896
|
};
|
|
897
897
|
|
|
898
|
+
function fix_indexesSync(self) {
|
|
899
|
+
return new Promise(function(resolve, reject) {
|
|
900
|
+
inquirer.prompt([
|
|
901
|
+
{
|
|
902
|
+
type: 'confirm',
|
|
903
|
+
name: 'replace',
|
|
904
|
+
message: 'Would you like to replace the local indexes?',
|
|
905
|
+
default: true,
|
|
906
|
+
}
|
|
907
|
+
])
|
|
908
|
+
.then(async (answer) => {
|
|
909
|
+
if (answer.replace) {
|
|
910
|
+
cmd_indexesGet(self, undefined, true)
|
|
911
|
+
.then(r => {
|
|
912
|
+
return resolve();
|
|
913
|
+
})
|
|
914
|
+
} else {
|
|
915
|
+
return reject();
|
|
916
|
+
}
|
|
917
|
+
})
|
|
918
|
+
});
|
|
919
|
+
};
|
|
920
|
+
|
|
898
921
|
function fix_firestoreRulesFile(self) {
|
|
899
922
|
return new Promise(function(resolve, reject) {
|
|
900
923
|
const name = 'firestore.rules'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
function Module() {
|
|
2
|
+
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
Module.prototype.main = function () {
|
|
6
|
+
const self = this;
|
|
7
|
+
const Manager = self.Manager;
|
|
8
|
+
const Api = self.Api;
|
|
9
|
+
const assistant = self.assistant;
|
|
10
|
+
const payload = self.payload;
|
|
11
|
+
|
|
12
|
+
return new Promise(async function(resolve, reject) {
|
|
13
|
+
|
|
14
|
+
if (payload.user.roles.admin) {
|
|
15
|
+
|
|
16
|
+
payload.data.payload.path = `${payload.data.payload.path || ''}`;
|
|
17
|
+
payload.data.payload.options = payload.data.payload.options || {};
|
|
18
|
+
|
|
19
|
+
if (!payload.data.payload.path) {
|
|
20
|
+
return reject(assistant.errorManager(`<path> parameter required`, {code: 400, sentry: false, send: false, log: false}).error)
|
|
21
|
+
} else {
|
|
22
|
+
|
|
23
|
+
self.libraries.admin.database().ref(payload.data.payload.path)
|
|
24
|
+
.on('value', (snapshot) => {
|
|
25
|
+
const data = snapshot.val();
|
|
26
|
+
return resolve({data: data});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
} else {
|
|
32
|
+
return reject(assistant.errorManager(`Admin required.`, {code: 401, sentry: false, send: false, log: false}).error)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
module.exports = Module;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
function Module() {
|
|
2
|
+
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
Module.prototype.main = function () {
|
|
6
|
+
const self = this;
|
|
7
|
+
const Manager = self.Manager;
|
|
8
|
+
const Api = self.Api;
|
|
9
|
+
const assistant = self.assistant;
|
|
10
|
+
const payload = self.payload;
|
|
11
|
+
|
|
12
|
+
return new Promise(async function(resolve, reject) {
|
|
13
|
+
|
|
14
|
+
if (payload.user.roles.admin) {
|
|
15
|
+
|
|
16
|
+
payload.data.payload.path = `${payload.data.payload.path || ''}`;
|
|
17
|
+
payload.data.payload.document = payload.data.payload.document || {};
|
|
18
|
+
payload.data.payload.options = payload.data.payload.options || {};
|
|
19
|
+
|
|
20
|
+
if (!payload.data.payload.path) {
|
|
21
|
+
return reject(assistant.errorManager(`<path> parameter required`, {code: 400, sentry: false, send: false, log: false}).error)
|
|
22
|
+
} else {
|
|
23
|
+
|
|
24
|
+
self.libraries.admin.database().ref(payload.data.payload.path)
|
|
25
|
+
.set(payload.data.payload.document)
|
|
26
|
+
.then(() => {
|
|
27
|
+
return resolve({data: payload.data.payload.document});
|
|
28
|
+
})
|
|
29
|
+
.catch((e) => {
|
|
30
|
+
return reject(assistant.errorManager(e, {code: 500, sentry: false, send: false, log: false}).error)
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
} else {
|
|
36
|
+
return reject(assistant.errorManager(`Admin required.`, {code: 401, sentry: false, send: false, log: false}).error)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
module.exports = Module;
|
|
@@ -14,8 +14,7 @@ Module.prototype.main = function () {
|
|
|
14
14
|
if (payload.user.roles.admin) {
|
|
15
15
|
|
|
16
16
|
payload.data.payload.path = `${payload.data.payload.path || ''}`;
|
|
17
|
-
payload.data.payload.
|
|
18
|
-
payload.data.payload.options = payload.data.payload.options || { merge: true };
|
|
17
|
+
payload.data.payload.options = payload.data.payload.options || {};
|
|
19
18
|
|
|
20
19
|
if (!payload.data.payload.path) {
|
|
21
20
|
return reject(assistant.errorManager(`<path> parameter required`, {code: 400, sentry: false, send: false, log: false}).error)
|
|
@@ -28,6 +28,10 @@ Module.prototype.init = function (Manager, data) {
|
|
|
28
28
|
self.assistant.request.data.command = resolved.command;
|
|
29
29
|
self.assistant.request.data.payload = self.assistant.request.data.payload || {};
|
|
30
30
|
|
|
31
|
+
if (Manager.options.log) {
|
|
32
|
+
self.assistant.log(`Executing (log): ${resolved.command}`, self.assistant.request.data.payload, JSON.stringify(self.assistant.request.data.payload), {environment: 'production'})
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
return self;
|
|
32
36
|
}
|
|
33
37
|
|
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
function Module() {
|
|
2
|
+
const self = this;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
Module.prototype.init = function (Manager, payload) {
|
|
6
|
+
const self = this;
|
|
7
|
+
self.Manager = Manager;
|
|
8
|
+
self.libraries = Manager.libraries;
|
|
9
|
+
self.assistant = Manager.Assistant();
|
|
10
|
+
self.user = payload.user
|
|
11
|
+
|
|
12
|
+
return self;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
Module.prototype.main = function () {
|
|
16
|
+
const self = this;
|
|
17
|
+
const libraries = self.libraries;
|
|
18
|
+
const assistant = self.assistant;
|
|
19
|
+
const user = self.user;
|
|
20
|
+
|
|
21
|
+
return new Promise(async function(resolve, reject) {
|
|
22
|
+
const newUser = self.Manager.User({
|
|
17
23
|
auth: {
|
|
18
24
|
uid: user.uid,
|
|
19
25
|
email: user.email,
|
|
20
26
|
}
|
|
21
27
|
});
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
const analytics = self.Manager.Analytics({
|
|
24
30
|
assistant: assistant,
|
|
25
31
|
uuid: user.uid,
|
|
26
32
|
})
|
|
@@ -56,7 +62,8 @@ let Module = {
|
|
|
56
62
|
})
|
|
57
63
|
|
|
58
64
|
assistant.log('User created:', user, {environment: 'production'});
|
|
59
|
-
|
|
60
|
-
}
|
|
65
|
+
return resolve(self);
|
|
66
|
+
});
|
|
67
|
+
};
|
|
61
68
|
|
|
62
69
|
module.exports = Module;
|
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
function Module() {
|
|
2
|
+
const self = this;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
Module.prototype.init = function (Manager, payload) {
|
|
6
|
+
const self = this;
|
|
7
|
+
self.Manager = Manager;
|
|
8
|
+
self.libraries = Manager.libraries;
|
|
9
|
+
self.assistant = Manager.Assistant();
|
|
10
|
+
self.user = payload.user
|
|
11
|
+
|
|
12
|
+
return self;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
Module.prototype.main = function () {
|
|
16
|
+
return new Promise(async function(resolve, reject) {
|
|
17
|
+
const self = this;
|
|
18
|
+
const libraries = self.libraries;
|
|
19
|
+
const assistant = self.assistant;
|
|
20
|
+
const user = self.user;
|
|
21
|
+
|
|
22
|
+
const analytics = self.Manager.Analytics({
|
|
17
23
|
assistant: assistant,
|
|
18
24
|
uuid: user.uid,
|
|
19
25
|
})
|
|
@@ -39,8 +45,10 @@ let Module = {
|
|
|
39
45
|
assistant.error(e, {environment: 'production'});
|
|
40
46
|
})
|
|
41
47
|
|
|
42
|
-
assistant.log('User deleted:', user, {environment: 'production'});
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
assistant.log('User deleted:', user, {environment: 'production'});
|
|
49
|
+
|
|
50
|
+
return resolve(self);
|
|
51
|
+
});
|
|
52
|
+
};
|
|
45
53
|
|
|
46
54
|
module.exports = Module;
|
|
@@ -1,27 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
this.libraries = Manager.libraries;
|
|
5
|
-
this.assistant = Manager.Assistant();
|
|
6
|
-
this.change = data.change
|
|
7
|
-
this.context = data.context
|
|
8
|
-
|
|
9
|
-
return this;
|
|
10
|
-
},
|
|
11
|
-
main: async function() {
|
|
12
|
-
let self = this;
|
|
13
|
-
let libraries = self.libraries;
|
|
14
|
-
let assistant = self.assistant;
|
|
15
|
-
let change = self.change;
|
|
16
|
-
let context = self.context;
|
|
17
|
-
|
|
18
|
-
let _ = self.Manager.require('lodash');
|
|
1
|
+
function Module() {
|
|
2
|
+
const self = this;
|
|
3
|
+
}
|
|
19
4
|
|
|
20
|
-
|
|
5
|
+
Module.prototype.init = function (Manager, payload) {
|
|
6
|
+
const self = this;
|
|
7
|
+
self.Manager = Manager;
|
|
8
|
+
self.libraries = Manager.libraries;
|
|
9
|
+
self.assistant = Manager.Assistant();
|
|
10
|
+
self.change = payload.change
|
|
11
|
+
self.context = payload.context
|
|
12
|
+
|
|
13
|
+
return self;
|
|
14
|
+
};
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
Module.prototype.main = function () {
|
|
17
|
+
const self = this;
|
|
18
|
+
const libraries = self.libraries;
|
|
19
|
+
const assistant = self.assistant;
|
|
20
|
+
const change = self.change;
|
|
21
|
+
const context = self.context;
|
|
22
|
+
|
|
23
|
+
return new Promise(async function(resolve, reject) {
|
|
24
|
+
const _ = self.Manager.require('lodash');
|
|
25
|
+
|
|
26
|
+
const dataBefore = change.before.data();
|
|
27
|
+
const dataAfter = change.after.data();
|
|
28
|
+
|
|
29
|
+
let analytics;
|
|
24
30
|
let eventType;
|
|
31
|
+
|
|
25
32
|
if (dataAfter == undefined) {
|
|
26
33
|
eventType = 'delete';
|
|
27
34
|
} else if (dataBefore && dataAfter) {
|
|
@@ -54,15 +61,19 @@ let Module = {
|
|
|
54
61
|
action: 'notification-unsubscribe',
|
|
55
62
|
// label: 'regular',
|
|
56
63
|
});
|
|
64
|
+
|
|
57
65
|
assistant.log('Notification subscription deleted:', dataBefore, {environment: 'production'});
|
|
66
|
+
|
|
67
|
+
return resolve(dataBefore);
|
|
58
68
|
})
|
|
59
69
|
.catch(e => {
|
|
60
70
|
assistant.error(e, {environment: 'production'});
|
|
71
|
+
return reject(e);
|
|
61
72
|
})
|
|
62
73
|
|
|
63
74
|
// Update event
|
|
64
75
|
} else if (eventType === 'update') {
|
|
65
|
-
|
|
76
|
+
return resolve();
|
|
66
77
|
|
|
67
78
|
// Create event
|
|
68
79
|
} else if (eventType === 'create') {
|
|
@@ -82,13 +93,17 @@ let Module = {
|
|
|
82
93
|
});
|
|
83
94
|
|
|
84
95
|
assistant.log('Notification subscription created:', dataAfter, {environment: 'production'});
|
|
96
|
+
|
|
97
|
+
return resolve(dataAfter);
|
|
85
98
|
})
|
|
86
99
|
.catch(e => {
|
|
87
100
|
assistant.error(e, {environment: 'production'});
|
|
101
|
+
return reject(e);
|
|
88
102
|
})
|
|
89
103
|
}
|
|
90
104
|
|
|
91
|
-
}
|
|
92
|
-
}
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
|
|
93
108
|
|
|
94
109
|
module.exports = Module;
|
package/src/manager/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// Libraries
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { get, merge } = require('lodash');
|
|
4
|
+
const jetpack = require('fs-jetpack');
|
|
4
5
|
// const { debug, log, error, warn } = require('firebase-functions/lib/logger');
|
|
5
6
|
// let User;
|
|
6
7
|
// let Analytics;
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
function Manager(exporter, options) {
|
|
10
|
+
function Manager(exporter, options) {
|
|
10
11
|
const self = this;
|
|
11
12
|
// Constants
|
|
12
13
|
self.SERVER_UUID = '11111111-1111-1111-1111-111111111111';
|
|
@@ -92,6 +93,30 @@ Manager.prototype.init = function (exporter, options) {
|
|
|
92
93
|
require('firebase-functions/lib/logger/compat');
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
// Handle dev environments
|
|
97
|
+
if (self.assistant.meta.environment === 'development') {
|
|
98
|
+
const semverMajor = require('semver/functions/major')
|
|
99
|
+
const semverCoerce = require('semver/functions/coerce')
|
|
100
|
+
const semverUsing = semverMajor(semverCoerce(process.versions.node));
|
|
101
|
+
const semverRequired = semverMajor(semverCoerce(get(self.package, 'engines.node', '0.0.0')));
|
|
102
|
+
|
|
103
|
+
// Fix firebase-tools overwriting console.log
|
|
104
|
+
// https://stackoverflow.com/questions/56026747/firebase-console-log-on-localhost
|
|
105
|
+
if (process.env.GCLOUD_PROJECT) {
|
|
106
|
+
function logFix() {
|
|
107
|
+
console.error(...arguments);
|
|
108
|
+
}
|
|
109
|
+
console.log = logFix;
|
|
110
|
+
console.info = logFix;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Reject if package.json does not exist
|
|
114
|
+
if (semverUsing !== semverRequired) {
|
|
115
|
+
console.error(new Error(`Node.js version mismatch: using ${semverUsing} but asked for ${semverRequired}`));
|
|
116
|
+
return process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
95
120
|
if (options.log) {
|
|
96
121
|
self.assistant.log('process.env', process.env, {environment: 'production'})
|
|
97
122
|
}
|
|
@@ -513,11 +538,19 @@ Manager.prototype.storage = function (options) {
|
|
|
513
538
|
options.name = options.name || 'main';
|
|
514
539
|
|
|
515
540
|
if (!self._internal.storage[options.name]) {
|
|
541
|
+
options.temporary = typeof options.temporary === 'undefined' ? false : options.temporary;
|
|
542
|
+
|
|
516
543
|
const low = require('lowdb');
|
|
517
544
|
const FileSync = require('lowdb/adapters/FileSync');
|
|
518
|
-
const dbPath =
|
|
545
|
+
const dbPath = options.temporary
|
|
546
|
+
? `${require('os').tmpdir()}/${options.name}.json`
|
|
547
|
+
: `./.data/${options.name}.json`;
|
|
519
548
|
const adapter = new FileSync(dbPath);
|
|
520
|
-
|
|
549
|
+
|
|
550
|
+
if (options.temporary && self.assistant.meta.environment === 'development') {
|
|
551
|
+
console.log('Removed temporary file @', dbPath);
|
|
552
|
+
jetpack.remove(dbPath);
|
|
553
|
+
}
|
|
521
554
|
|
|
522
555
|
options.clearInvalid = typeof options.clearInvalid === 'undefined'
|
|
523
556
|
? true
|