backend-manager 4.1.0 → 4.1.2

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/CHANGELOG.md CHANGED
@@ -14,7 +14,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
14
14
  - `Fixed` for any bug fixes.
15
15
  - `Security` in case of vulnerabilities.
16
16
 
17
- ---
17
+ ---#
18
+ # [4.1.0] - 2024-12-19
19
+ ### Changed
20
+ - Attach `schema` to `bm-properties` response header.
21
+ - `assistant.request.url` is now properly set for all environments (development, production, etc) and works whether called from custom domain or Firebase default function domain.
22
+
18
23
  ## [4.0.0] - 2024-05-08
19
24
  ### ⚠️ BREAKING
20
25
  - Require Node.js version `18` or higher.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "4.1.0",
3
+ "version": "4.1.2",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -50,10 +50,10 @@
50
50
  "busboy": "^1.6.0",
51
51
  "chalk": "^4.1.2",
52
52
  "cors": "^2.8.5",
53
- "dotenv": "^16.4.5",
54
- "express": "^4.21.1",
53
+ "dotenv": "^16.4.7",
54
+ "express": "^4.21.2",
55
55
  "firebase-admin": "^12.7.0",
56
- "firebase-functions": "^6.1.1",
56
+ "firebase-functions": "^6.1.2",
57
57
  "fs-jetpack": "^5.1.0",
58
58
  "glob": "^11.0.0",
59
59
  "hcaptcha": "^0.1.1",
@@ -67,7 +67,7 @@
67
67
  "mime-types": "^2.1.35",
68
68
  "mocha": "^8.4.0",
69
69
  "moment": "^2.30.1",
70
- "nanoid": "^3.3.7",
70
+ "nanoid": "^3.3.8",
71
71
  "node-fetch": "^2.7.0",
72
72
  "node-powertools": "^1.7.0",
73
73
  "npm-api": "^1.0.1",
@@ -80,7 +80,7 @@
80
80
  "uid-generator": "^2.0.0",
81
81
  "ultimate-jekyll-poster": "^1.0.2",
82
82
  "uuid": "^9.0.1",
83
- "wonderful-fetch": "^1.2.2",
83
+ "wonderful-fetch": "^1.3.0",
84
84
  "wonderful-log": "^1.0.7",
85
85
  "yaml": "^2.6.1",
86
86
  "yargs": "^17.7.2"
@@ -8,7 +8,7 @@ function Module() {
8
8
  Module.prototype.main = function () {
9
9
  const self = this;
10
10
 
11
- // Set shortcuts
11
+ // Shortcuts
12
12
  const Manager = self.Manager;
13
13
  const Api = self.Api;
14
14
  const assistant = self.assistant;
@@ -8,7 +8,7 @@ function Module() {
8
8
  Module.prototype.main = function () {
9
9
  const self = this;
10
10
 
11
- // Set shortcuts
11
+ // Shortcuts
12
12
  const Manager = self.Manager;
13
13
  const Api = self.Api;
14
14
  const assistant = self.assistant;
@@ -55,7 +55,7 @@ Module.prototype.main = function () {
55
55
  Module.prototype.loadHook = function () {
56
56
  const self = this;
57
57
 
58
- // Set shortcuts
58
+ // Shortcuts
59
59
  const Manager = self.Manager;
60
60
  const assistant = self.assistant;
61
61
  const payload = self.payload;
@@ -10,7 +10,7 @@ function Module() {
10
10
  Module.prototype.main = function () {
11
11
  const self = this;
12
12
 
13
- // Set shortcuts
13
+ // Shortcuts
14
14
  const Manager = self.Manager;
15
15
  const Api = self.Api;
16
16
  const assistant = self.assistant;
@@ -331,7 +331,7 @@ function resolveBasePath(basePath, command) {
331
331
  Module.prototype.resolveApiPath = function (command) {
332
332
  const self = this;
333
333
 
334
- // Set shortcuts
334
+ // Shortcuts
335
335
  const Manager = self.Manager;
336
336
  const libraries = self.libraries;
337
337
  const assistant = self.assistant;
@@ -18,7 +18,7 @@ function Middleware(m, req, res) {
18
18
  Middleware.prototype.run = function (libPath, options) {
19
19
  const self = this;
20
20
 
21
- // Set shortcuts
21
+ // Shortcuts
22
22
  const Manager = self.Manager;
23
23
  const req = self.req;
24
24
  const res = self.res;
@@ -27,11 +27,17 @@ Middleware.prototype.run = function (libPath, options) {
27
27
  return cors(req, res, async () => {
28
28
  const assistant = Manager.Assistant({req: req, res: res});
29
29
 
30
+ // Set properties
30
31
  const data = assistant.request.data;
31
32
  const headers = assistant.request.headers;
33
+ const method = assistant.request.method;
34
+ const url = assistant.request.url;
32
35
  const geolocation = assistant.request.geolocation;
33
36
  const client = assistant.request.client;
34
37
 
38
+ // Strip URL
39
+ const strippedUrl = stripUrl(url);
40
+
35
41
  // Set options
36
42
  options = options || {};
37
43
  options.authenticate = typeof options.authenticate === 'boolean' ? options.authenticate : true;
@@ -47,7 +53,7 @@ Middleware.prototype.run = function (libPath, options) {
47
53
  options.schemasDir = typeof options.schemasDir === 'undefined' ? `${Manager.cwd}/schemas` : options.schemasDir;
48
54
 
49
55
  // Log
50
- assistant.log(`Middleware.process(): Request (${geolocation.ip} @ ${geolocation.country}, ${geolocation.region}, ${geolocation.city})`, JSON.stringify(data));
56
+ assistant.log(`Middleware.process(): Request (${geolocation.ip} @ ${geolocation.country}, ${geolocation.region}, ${geolocation.city}) [${method} > ${strippedUrl}]`, JSON.stringify(data));
51
57
  assistant.log(`Middleware.process(): Headers`, JSON.stringify(headers));
52
58
 
53
59
  // Set paths
@@ -62,6 +68,7 @@ Middleware.prototype.run = function (libPath, options) {
62
68
  }
63
69
 
64
70
  // Load library
71
+ // TODO: Support for methods, so first check for method specific file then fallback to index.js
65
72
  let library;
66
73
  try {
67
74
  libPath = path.resolve(routesDir, `index.js`);
@@ -153,4 +160,10 @@ function clean(obj) {
153
160
  }
154
161
  }
155
162
 
163
+ function stripUrl(url) {
164
+ const newUrl = new URL(url);
165
+
166
+ return `${newUrl.hostname}${newUrl.pathname}`.replace(/\/$/, '');
167
+ }
168
+
156
169
  module.exports = Middleware;
@@ -107,21 +107,15 @@ Usage.prototype.init = function (assistant, options) {
107
107
 
108
108
  // Get app data to get plan limits using cached data if possible
109
109
  if (diff > 1 || options.refetch) {
110
- await fetch('https://us-central1-itw-creative-works.cloudfunctions.net/getApp', {
111
- method: 'post',
112
- response: 'json',
113
- body: {
114
- id: options.app,
115
- },
116
- })
117
- .then((json) => {
118
- // Write data and last fetched to storage
119
- self.storage.set(`${self.paths.app}.data`, json).write();
120
- self.storage.set(`${self.paths.app}.lastFetched`, new Date().toISOString()).write();
121
- })
122
- .catch(e => {
123
- assistant.errorify(`Usage.init(): Error fetching app data: ${e}`, {code: 500, sentry: true});
124
- })
110
+ await self.getApp(options.app)
111
+ .then((json) => {
112
+ // Write data and last fetched to storage
113
+ self.storage.set(`${self.paths.app}.data`, json).write();
114
+ self.storage.set(`${self.paths.app}.lastFetched`, new Date().toISOString()).write();
115
+ })
116
+ .catch(e => {
117
+ assistant.errorify(`Usage.init(): Error fetching app data: ${e}`, {code: 500, sentry: true});
118
+ });
125
119
  }
126
120
 
127
121
  // Get app data
@@ -311,14 +305,17 @@ Usage.prototype.getLimit = function (name) {
311
305
  Usage.prototype.update = function () {
312
306
  const self = this;
313
307
 
308
+ // Shortcuts
309
+ const Manager = self.Manager;
310
+ const assistant = self.assistant;
311
+
314
312
  return new Promise(async function(resolve, reject) {
315
- const Manager = self.Manager;
316
- const assistant = self.assistant;
313
+ const { admin } = Manager.libraries;
317
314
 
318
315
  // Write self.user to firestore or local if no user or if key is set
319
316
  if (self.useUnauthenticatedStorage) {
320
317
  if (self.options.unauthenticatedMode === 'firestore') {
321
- Manager.libraries.admin.firestore().doc(`temporary/${self.key}`)
318
+ admin.firestore().doc(`temporary/${self.key}`)
322
319
  .set({
323
320
  usage: self.user.usage,
324
321
  }, {merge: true})
@@ -338,7 +335,7 @@ Usage.prototype.update = function () {
338
335
  return resolve(self.user.usage);
339
336
  }
340
337
  } else {
341
- Manager.libraries.admin.firestore().doc(`users/${self.user.auth.uid}`)
338
+ admin.firestore().doc(`users/${self.user.auth.uid}`)
342
339
  .set({
343
340
  usage: self.user.usage,
344
341
  }, {merge: true})
@@ -378,4 +375,49 @@ Usage.prototype.log = function () {
378
375
  }
379
376
  };
380
377
 
378
+ Usage.prototype.getApp = function (id) {
379
+ const self = this;
380
+
381
+ // Shortcuts
382
+ const Manager = self.Manager;
383
+ const assistant = self.assistant;
384
+
385
+ return new Promise(function(resolve, reject) {
386
+ const { admin } = Manager.libraries;
387
+
388
+ try {
389
+ // If we're on ITW, we can read directly from Firestore
390
+ // If we don't do this, calling getApp on ITW will call getApp on ITW again and again
391
+ if (Manager.config.app.id === 'itw-creative-works') {
392
+ admin.firestore().doc(`apps/${id}`)
393
+ .get()
394
+ .then((r) => {
395
+ const data = r.data();
396
+
397
+ // Check for data
398
+ if (!data) {
399
+ return reject(new Error('No data found'));
400
+ }
401
+
402
+ // Resolve
403
+ return resolve(data);
404
+ })
405
+ .catch((e) => reject(e));
406
+ } else {
407
+ fetch('https://us-central1-itw-creative-works.cloudfunctions.net/getApp', {
408
+ method: 'post',
409
+ response: 'json',
410
+ body: {
411
+ id: id,
412
+ },
413
+ })
414
+ .then((json) => resolve(json))
415
+ .catch((e) => reject(e));
416
+ }
417
+ } catch (e) {
418
+ return reject(e);
419
+ }
420
+ });
421
+ };
422
+
381
423
  module.exports = Usage;
@@ -7,7 +7,7 @@ function Route() {
7
7
  Route.prototype.main = async function (assistant) {
8
8
  const self = this;
9
9
 
10
- // Set shortcuts
10
+ // Shortcuts
11
11
  const Manager = assistant.Manager;
12
12
  const usage = assistant.usage;
13
13
  const user = assistant.usage.user;
@@ -7,7 +7,7 @@ function Route() {
7
7
  Route.prototype.main = async function (assistant) {
8
8
  const self = this;
9
9
 
10
- // Set shortcuts
10
+ // Shortcuts
11
11
  const Manager = assistant.Manager;
12
12
  const usage = assistant.usage;
13
13
  const user = assistant.usage.user;