backend-manager 3.2.135 → 3.2.136

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": "3.2.135",
3
+ "version": "3.2.136",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -22,7 +22,7 @@ Module.prototype.main = function () {
22
22
  if (!productId) {
23
23
  return reject(assistant.errorify(`No productId`, {code: 400}));
24
24
  }
25
- const processorPath = `${process.cwd()}/payment-processors/${productId}.js`
25
+ const processorPath = `${Manager.cwd}/payment-processors/${productId}.js`
26
26
  let processor;
27
27
  // console.log('---processorPath', processorPath);
28
28
 
@@ -1,3 +1,6 @@
1
+ // Load libraries
2
+ // const path = require('path');
3
+
1
4
  function Module() {
2
5
 
3
6
  }
@@ -10,9 +13,6 @@ Module.prototype.main = function () {
10
13
  const payload = self.payload;
11
14
 
12
15
  return new Promise(async function(resolve, reject) {
13
- // Log
14
- assistant.log('Manager.cwd', Manager.cwd)
15
-
16
16
  // If not dev, quit
17
17
  if (!assistant.isDevelopment()) {
18
18
  return reject(assistant.errorify(`This command is only available in development mode`, {code: 401}));
@@ -24,12 +24,7 @@ Module.prototype.main = function () {
24
24
  }
25
25
 
26
26
  // Load the hook
27
- let hook;
28
- try {
29
- hook = (new (require(pathify(`${Manager.cwd}/${payload.data.payload.path}.js`)))());
30
- } catch (e) {
31
- hook = (new (require(pathify(`${Manager.cwd}/hooks/${payload.data.payload.path}.js`)))());
32
- }
27
+ const hook = loadHook(assistant, payload);
33
28
 
34
29
  // Run the hook
35
30
  try {
@@ -39,6 +34,13 @@ Module.prototype.main = function () {
39
34
  hook.context = null;
40
35
  hook.libraries = Manager.libraries;
41
36
 
37
+ // Get hook name
38
+ const hookName = payload.data.payload.path.split('/').pop();
39
+
40
+ // Set log prefix
41
+ assistant.setLogPrefix(`cron/daily/${hookName}()`);
42
+
43
+ // Run the hook
42
44
  const result = await hook.main(assistant);
43
45
 
44
46
  return resolve({data: result, status: 200});
@@ -48,9 +50,33 @@ Module.prototype.main = function () {
48
50
  });
49
51
  };
50
52
 
53
+ function loadHook(assistant, payload) {
54
+ const Manager = assistant.Manager;
55
+ const paths = [
56
+ `${Manager.rootDirectory}/functions/core/${payload.data.payload.path}`,
57
+ `${Manager.cwd}/${payload.data.payload.path}`,
58
+ `${Manager.cwd}/hooks/${payload.data.payload.path}`,
59
+ ];
60
+
61
+ // Loop through paths and try to load the hook
62
+ for (let i = 0; i < paths.length; i++) {
63
+ const current = pathify(paths[i]);
64
+
65
+ // Log
66
+ assistant.log('Trying path:', current);
67
+
68
+ // Try to load the hook
69
+ try {
70
+ // If the hook is successfully loaded, break the loop
71
+ return (new (require(current))());
72
+ } catch (e) {
73
+ // if the hook fails to load, continue to the next path
74
+ }
75
+ }
76
+ }
77
+
51
78
  function pathify(path) {
52
- const fixed = path
53
- // Replace .js
79
+ const fixed = path
54
80
  .replace('.js', '')
55
81
 
56
82
  // Return
@@ -24,7 +24,7 @@ Module.prototype.main = function () {
24
24
 
25
25
  const settings = _.merge({}, payload.data.payload.existingSettings, payload.data.payload.newSettings);
26
26
 
27
- const resolvedPath = path.join(process.cwd(), `defaults.js`);
27
+ const resolvedPath = path.join(Manager.cwd, `defaults.js`);
28
28
 
29
29
  // Check if the file exists
30
30
  if (!jetpack.exists(resolvedPath)) {
@@ -326,7 +326,7 @@ function resolveBasePath(basePath, command) {
326
326
  };
327
327
 
328
328
  function resolveApiPath(command) {
329
- const projectBasePath = path.join(process.cwd(), 'routes/api');
329
+ const projectBasePath = path.join(Manager.cwd, 'routes/api');
330
330
  const localBasePath = './api/';
331
331
 
332
332
  const projectPath = resolveBasePath(projectBasePath, command);
@@ -0,0 +1,242 @@
1
+ // Libraries
2
+ const fetch = require('wonderful-fetch');
3
+ const powertools = require('node-powertools');
4
+ const moment = require('moment');
5
+
6
+ const PROMPT = `
7
+ Company: {name}: {description}
8
+ Current Date: {date}
9
+ Instructions: {prompt}
10
+ Topic Suggestion: {suggestion}
11
+ `
12
+
13
+ function Module() {
14
+
15
+ }
16
+
17
+ Module.prototype.main = function (assistant, context) {
18
+ const self = this;
19
+
20
+ // Shortcuts
21
+ const Manager = assistant.Manager;
22
+ const libraries = Manager.libraries;
23
+
24
+ return new Promise(async function(resolve, reject) {
25
+ // Log
26
+ assistant.log(`Starting...`);
27
+
28
+ // Get settings
29
+ const settings = Manager.config.ghostii;
30
+
31
+ // Log
32
+ assistant.log(`Settings`, settings);
33
+
34
+ // Quit if articles are disabled
35
+ if (!settings.articles || !settings.sources.length) {
36
+ assistant.log(`Quitting because articles are disabled`);
37
+
38
+ return resolve();
39
+ }
40
+
41
+ // Get app content
42
+ self.appObject = await self.getAppData().catch((e) => e);
43
+ if (self.appObject instanceof Error) {
44
+ return reject(self.appObject);
45
+ }
46
+
47
+ // Harvest articles
48
+ const result = await self.harvest(settings).catch((e) => e);
49
+ if (result instanceof Error) {
50
+ return reject(result);
51
+ }
52
+
53
+ // Log
54
+ assistant.log(`Finished!`);
55
+
56
+ // Resolve
57
+ return resolve();
58
+ });
59
+ }
60
+
61
+ Module.prototype.harvest = function (settings) {
62
+ const self = this;
63
+
64
+ // Shortcuts
65
+ const Manager = self.Manager;
66
+ const libraries = self.libraries;
67
+ const assistant = self.assistant;
68
+ const context = self.context;
69
+
70
+ return new Promise(async function(resolve, reject) {
71
+ const date = moment().format('MMMM YYYY');
72
+
73
+ // Log
74
+ assistant.log(`harvest(): Starting...`);
75
+
76
+ // Process the number of sources in the settings
77
+ for (let index = 0; index < settings.articles; index++) {
78
+ const source = powertools.random(settings.sources);
79
+ const isURL = self.isURL(source);
80
+ let suggestion = null;
81
+
82
+ // Log
83
+ assistant.log(`harvest(): Processing ${index + 1}/${settings.articles} sources isURL=${isURL}`, source);
84
+
85
+ // Get suggestion
86
+ if (source === '$app') {
87
+ suggestion = 'Write an article about any topic that would be relevant to our website and business.';
88
+ } else if (isURL) {
89
+ suggestion = await self.getURLContent(source).catch((e) => e);
90
+ } else {
91
+ suggestion = source;
92
+ }
93
+
94
+ // Check for errors
95
+ if (suggestion instanceof Error) {
96
+ assistant.error(`harvest(): Error fetching ${source} suggestion`, suggestion);
97
+
98
+ break;
99
+ }
100
+
101
+ // Set suggestion
102
+ const final = powertools.template(PROMPT, {
103
+ name: self.appObject.name,
104
+ description: self.appObject.description,
105
+ prompt: settings.prompt,
106
+ date: date,
107
+ suggestion: suggestion,
108
+ });
109
+
110
+ // Log
111
+ assistant.log('Get final content', final);
112
+
113
+ // Request to Ghostii
114
+ const result = await self.requestGhostii(final).catch((e) => e);
115
+ if (result instanceof Error) {
116
+ assistant.error(`harvest(): Error requesting Ghostii`, result);
117
+
118
+ break;
119
+ }
120
+
121
+ }
122
+
123
+ // Log
124
+ return resolve();
125
+ });
126
+ }
127
+
128
+ Module.prototype.getAppData = function (settings) {
129
+ const self = this;
130
+
131
+ // Shortcuts
132
+ const Manager = self.Manager;
133
+ const libraries = self.libraries;
134
+ const assistant = self.assistant;
135
+ const context = self.context;
136
+
137
+ return new Promise(async function(resolve, reject) {
138
+ // Fetch app details
139
+ fetch('https://us-central1-itw-creative-works.cloudfunctions.net/getApp', {
140
+ method: 'post',
141
+ timeout: 30000,
142
+ tries: 3,
143
+ response: 'json',
144
+ body: {
145
+ id: Manager.config.app.id,
146
+ },
147
+ })
148
+ .then((r) => {
149
+ return resolve({
150
+ name: r?.name,
151
+ description: r?.brand?.description || '',
152
+ acceptable: r?.sponsorships?.acceptable || [],
153
+ })
154
+ })
155
+ .catch((e) => reject(e));
156
+ });
157
+ }
158
+
159
+ Module.prototype.getURLContent = function (url) {
160
+ const self = this;
161
+
162
+ // Shortcuts
163
+ const Manager = self.Manager;
164
+ const libraries = self.libraries;
165
+ const assistant = self.assistant;
166
+ const context = self.context;
167
+
168
+ return new Promise(async function(resolve, reject) {
169
+ // Fetch URL
170
+ fetch(url, {
171
+ timeout: 30000,
172
+ tries: 3,
173
+ response: 'text',
174
+ })
175
+ .then((r) => {
176
+ return resolve(extractBodyContent(r));
177
+ })
178
+ .catch((e) => reject(e));
179
+ });
180
+ }
181
+
182
+ Module.prototype.isURL = function (url) {
183
+ const self = this;
184
+
185
+ // Shortcuts
186
+ const Manager = self.Manager;
187
+ const libraries = self.libraries;
188
+ const assistant = self.assistant;
189
+ const context = self.context;
190
+
191
+ try {
192
+ return !!new URL(url);
193
+ } catch (e) {
194
+ return false;
195
+ }
196
+ }
197
+
198
+ // Request to Ghostii
199
+ Module.prototype.requestGhostii = function (content) {
200
+ const self = this;
201
+
202
+ // Shortcuts
203
+ const Manager = self.Manager;
204
+ const libraries = self.libraries;
205
+ const assistant = self.assistant;
206
+ const context = self.context;
207
+
208
+ return new Promise(async function(resolve, reject) {
209
+ // Fetch URL
210
+ fetch('https://api.ghostii.ai/write/article', {
211
+ method: 'post',
212
+ timeout: 30000,
213
+ tries: 3,
214
+ response: 'json',
215
+ body: {
216
+ keywords: [''],
217
+ description: content,
218
+ },
219
+ })
220
+ .then((r) => {
221
+ return resolve(r);
222
+ })
223
+ .catch((e) => reject(e));
224
+ });
225
+ }
226
+
227
+ const extractBodyContent = (html) => {
228
+ // Extract the content within the body tag
229
+ const bodyMatch = html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
230
+ if (!bodyMatch) return '';
231
+
232
+ let bodyContent = bodyMatch[1];
233
+
234
+ // Remove script and meta tags
235
+ bodyContent = bodyContent.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
236
+ bodyContent = bodyContent.replace(/<meta[^>]*>/gi, '');
237
+
238
+ // Remove remaining HTML tags
239
+ return bodyContent.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
240
+ };
241
+
242
+ module.exports = Module;
@@ -15,7 +15,7 @@ Module.prototype.main = function (assistant, context) {
15
15
  return new Promise(async function(resolve, reject) {
16
16
  self.storage = Manager.storage({name: 'usage', temporary: true, clear: false, log: false});
17
17
 
18
- assistant.log(`cron/daily/reset-usage(): Starting main...`);
18
+ assistant.log(`Starting...`);
19
19
 
20
20
  // Clear local
21
21
  await self.clearLocal();
@@ -38,20 +38,20 @@ Module.prototype.clearLocal = function() {
38
38
 
39
39
  return new Promise(async function(resolve, reject) {
40
40
  // Log status
41
- assistant.log(`cron/daily/reset-usage() [local]: Starting...`);
41
+ assistant.log(`[local]: Starting...`);
42
42
 
43
43
  // Set variables
44
44
  const now = new Date();
45
45
 
46
46
  // Log storage
47
- assistant.log(`cron/daily/reset-usage() [local]: storage(apps)`, self.storage.get('apps', {}).value());
48
- assistant.log(`cron/daily/reset-usage() [local]: storage(users)`, self.storage.get('users', {}).value());
47
+ assistant.log(`[local]: storage(apps)`, self.storage.get('apps', {}).value());
48
+ assistant.log(`[local]: storage(users)`, self.storage.get('users', {}).value());
49
49
 
50
50
  // Clear storage
51
51
  self.storage.setState({}).write();
52
52
 
53
53
  // Log status
54
- assistant.log(`cron/daily/reset-usage() [local]: Completed!`);
54
+ assistant.log(`[local]: Completed!`);
55
55
 
56
56
  return resolve();
57
57
  });
@@ -68,7 +68,7 @@ Module.prototype.clearFirestore = function() {
68
68
 
69
69
  return new Promise(async function(resolve, reject) {
70
70
  // Log status
71
- assistant.log(`cron/daily/reset-usage() [firestore]: Starting...`);
71
+ assistant.log(`[firestore]: Starting...`);
72
72
 
73
73
  // Clear storage
74
74
  const metrics = await fetch(`https://us-central1-itw-creative-works.cloudfunctions.net/getApp`, {
@@ -95,7 +95,7 @@ Module.prototype.clearFirestore = function() {
95
95
  .catch(e => e);
96
96
 
97
97
  // Log status
98
- assistant.log(`cron/daily/reset-usage() [firestore]: Resetting metrics`, metrics);
98
+ assistant.log(`[firestore]: Resetting metrics`, metrics);
99
99
 
100
100
  if (metrics instanceof Error) {
101
101
  return reject(assistant.errorify(`Failed to check providers: ${metrics}`, {code: 500}));
@@ -104,7 +104,7 @@ Module.prototype.clearFirestore = function() {
104
104
  // Reset all metrics with for loop of metrics
105
105
  // TODO: OPTIMIZATION: Put all of the changes into a single batch
106
106
  for (const metric of Object.keys(metrics)) {
107
- assistant.log(`cron/daily/reset-usage() [firestore]: Resetting ${metric} for all users`);
107
+ assistant.log(`[firestore]: Resetting ${metric} for all users`);
108
108
 
109
109
  await Manager.Utilities().iterateCollection((batch, index) => {
110
110
  return new Promise(async (resolve, reject) => {
@@ -130,7 +130,7 @@ Module.prototype.clearFirestore = function() {
130
130
  // Update the doc
131
131
  await doc.ref.update({usage: data.usage})
132
132
  .then(r => {
133
- assistant.log(`cron/daily/reset-usage() [firestore]: Reset ${metric} for ${doc.id} (${original} -> 0)`);
133
+ assistant.log(`[firestore]: Reset ${metric} for ${doc.id} (${original} -> 0)`);
134
134
  })
135
135
  .catch(e => {
136
136
  assistant.errorify(`Error resetting ${metric} for ${doc.id}: ${e}`, {code: 500, log: true});
@@ -149,7 +149,7 @@ Module.prototype.clearFirestore = function() {
149
149
  log: true,
150
150
  })
151
151
  .then((r) => {
152
- assistant.log(`cron/daily/reset-usage() [firestore]: Reset ${metric} for all users complete!`);
152
+ assistant.log(`[firestore]: Reset ${metric} for all users complete!`);
153
153
  })
154
154
  .catch(e => {
155
155
  assistant.errorify(`Error resetting ${metric} for all users: ${e}`, {code: 500, log: true});
@@ -183,7 +183,7 @@ Module.prototype.clearFirestore = function() {
183
183
  })
184
184
  // await libraries.admin.firestore().doc(`temporary/usage`).delete()
185
185
  // .then(r => {
186
- // assistant.log(`cron/daily/reset-usage() [firestore]: Deleted temporary/usage`);
186
+ // assistant.log(`[firestore]: Deleted temporary/usage`);
187
187
  // })
188
188
  // .catch(e => {
189
189
  // assistant.errorify(`Error deleting temporary/usage: ${e}`, {code: 500, log: true});
@@ -41,7 +41,7 @@ Module.prototype.main = function() {
41
41
  await loadAndExecuteJobs(`${__dirname}/daily`, Manager, context).catch((e) => error = e);
42
42
 
43
43
  // Load custom jobs
44
- await loadAndExecuteJobs(`${process.cwd()}/hooks/cron/daily`, Manager, context).catch((e) => error = e);
44
+ await loadAndExecuteJobs(`${Manager.cwd}/hooks/cron/daily`, Manager, context).catch((e) => error = e);
45
45
 
46
46
  // If there was an error, reject
47
47
  if (error) {
@@ -40,8 +40,8 @@ Middleware.prototype.run = function (libPath, options) {
40
40
  options.schema = typeof options.schema === 'undefined' ? undefined : options.schema;
41
41
 
42
42
  // Set base path
43
- options.routesDir = typeof options.routesDir === 'undefined' ? `${process.cwd()}/routes` : options.routesDir;
44
- options.schemasDir = typeof options.schemasDir === 'undefined' ? `${process.cwd()}/schemas` : options.schemasDir;
43
+ options.routesDir = typeof options.routesDir === 'undefined' ? `${Manager.cwd}/routes` : options.routesDir;
44
+ options.schemasDir = typeof options.schemasDir === 'undefined' ? `${Manager.cwd}/schemas` : options.schemasDir;
45
45
 
46
46
  // Log
47
47
  assistant.log(`Middleware.process(): Request (${geolocation.ip} @ ${geolocation.country}, ${geolocation.region}, ${geolocation.city})`, JSON.stringify(data));
@@ -26,7 +26,7 @@ Settings.prototype.resolve = function (assistant, schema, settings, options) {
26
26
 
27
27
  // Set options
28
28
  options = options || {};
29
- options.dir = typeof options.dir === 'undefined' ? `${process.cwd()}/schemas` : options.dir;
29
+ options.dir = typeof options.dir === 'undefined' ? `${Manager.cwd}/schemas` : options.dir;
30
30
  options.schema = typeof options.schema === 'undefined' ? undefined : options.schema;
31
31
 
32
32
  // Load schema if not provided and schema is defined in options
@@ -66,6 +66,7 @@ Manager.prototype.init = function (exporter, options) {
66
66
  options.checkNodeVersion = typeof options.checkNodeVersion === 'undefined' ? true : options.checkNodeVersion;
67
67
  options.uniqueAppName = options.uniqueAppName || undefined;
68
68
  options.assistant = options.assistant || {};
69
+ options.cwd = typeof options.cwd === 'undefined' ? process.cwd() : options.cwd;
69
70
  // options.assistant.optionsLogString = options.assistant.optionsLogString || undefined;
70
71
 
71
72
  // Load libraries
@@ -86,7 +87,8 @@ Manager.prototype.init = function (exporter, options) {
86
87
  };
87
88
 
88
89
  // Set properties
89
- self.cwd = process.cwd();
90
+ self.cwd = options.cwd;
91
+ self.rootDirectory = __dirname;
90
92
 
91
93
  // Set options
92
94
  self.options = options;
@@ -96,7 +98,7 @@ Manager.prototype.init = function (exporter, options) {
96
98
  self.project.backendManagerConfigPath = path.resolve(self.cwd, options.backendManagerConfigPath);
97
99
 
98
100
  // Load package.json
99
- self.package = resolveProjectPackage();
101
+ self.package = resolveProjectPackage(self.cwd);
100
102
 
101
103
  // Load config
102
104
  self.config = merge(
@@ -110,7 +112,7 @@ Manager.prototype.init = function (exporter, options) {
110
112
  : {},
111
113
  );
112
114
 
113
- // Saved config
115
+ // Get app ID
114
116
  const appId = self.config?.app?.id;
115
117
 
116
118
  // Init assistant
@@ -121,10 +123,17 @@ Manager.prototype.init = function (exporter, options) {
121
123
  ? `http://localhost:5001/${self.project.projectId}/${self.project.resourceZone}`
122
124
  : `https://${self.project.resourceZone}-${self.project.projectId}.cloudfunctions.net`;
123
125
 
124
- process.env.ENVIRONMENT = !process.env.ENVIRONMENT ? self.assistant.meta.environment : process.env.ENVIRONMENT;
126
+ // Set environment
127
+ process.env.ENVIRONMENT = !process.env.ENVIRONMENT
128
+ ? self.assistant.meta.environment
129
+ : process.env.ENVIRONMENT;
125
130
 
126
131
  // Use the working Firebase logger that they disabled for whatever reason
127
- if (process.env.GCLOUD_PROJECT && self.assistant.meta.environment !== 'development' && options.useFirebaseLogger) {
132
+ if (
133
+ process.env.GCLOUD_PROJECT
134
+ && self.assistant.meta.environment !== 'development'
135
+ && options.useFirebaseLogger
136
+ ) {
128
137
  // require('firebase-functions/lib/logger/compat'); // Old way
129
138
  require('firebase-functions/logger/compat'); // firebase-functions@4 and above?
130
139
  }
@@ -975,13 +984,13 @@ Manager.prototype.setupCustomServer = function (_library, options) {
975
984
  });
976
985
  }
977
986
 
978
- function resolveProjectPackage() {
987
+ function resolveProjectPackage(dir) {
979
988
  try {
980
- return require(path.resolve(process.cwd(), 'functions', 'package.json'));
989
+ return require(path.resolve(dir, 'functions', 'package.json'));
981
990
  } catch (e) {}
982
991
 
983
992
  try {
984
- return require(path.resolve(process.cwd(), 'package.json'));
993
+ return require(path.resolve(dir, 'package.json'));
985
994
  } catch (e) {}
986
995
  }
987
996
 
@@ -37,6 +37,8 @@
37
37
  articles: 1,
38
38
  sources: [
39
39
  '$app',
40
- ]
40
+ // Add more sources here
41
+ ],
42
+ prompt: '',
41
43
  },
42
44
  }