backend-manager 4.0.32 → 4.1.1

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.0.32",
3
+ "version": "4.1.1",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -113,6 +113,7 @@ BackendAssistant.prototype.init = function (ref, options) {
113
113
  self.analytics = null;
114
114
  self.usage = null;
115
115
  self.settings = null;
116
+ self.schema = null;
116
117
 
117
118
  // Set meta
118
119
  self.meta = {};
@@ -251,12 +252,6 @@ BackendAssistant.prototype.init = function (ref, options) {
251
252
  self.constant.pastTime.timestamp = '1999-01-01T00:00:00Z';
252
253
  self.constant.pastTime.timestampUNIX = 915148800;
253
254
 
254
- // Schema
255
- // self.schema = {
256
- // dir: '',
257
- // name: '',
258
- // }
259
-
260
255
  // Log options
261
256
  if (
262
257
  (self.isDevelopment())
@@ -568,9 +563,10 @@ function _attachHeaderProperties(self, options, error) {
568
563
  code: options.code,
569
564
  tag: self.tag,
570
565
  usage: {
571
- current: self?.usage?.getUsage() || {},
572
- limits: self?.usage?.getLimit() || {},
566
+ current: self.usage ? self.usage.getUsage() : {},
567
+ limits: self.usage ? self.usage.getLimit() : {},
573
568
  },
569
+ schema: self.schema || {},
574
570
  additional: options.additional || {},
575
571
  }
576
572
  const req = self.ref.req;
@@ -582,9 +578,10 @@ function _attachHeaderProperties(self, options, error) {
582
578
 
583
579
  // Add bm-properties to Access-Control-Expose-Headers
584
580
  const existingExposed = res.get('Access-Control-Expose-Headers') || '';
585
- const newExposed = `${existingExposed}, bm-properties`.replace(/^, /, '');
586
581
 
582
+ // If it does not exist, add it
587
583
  if (!existingExposed.match(/bm-properties/i)) {
584
+ const newExposed = `${existingExposed}, bm-properties`.replace(/^, /, '');
588
585
  res.header('Access-Control-Expose-Headers', newExposed);
589
586
  }
590
587
  }
@@ -722,15 +719,21 @@ BackendAssistant.prototype.resolveAccount = function (user) {
722
719
 
723
720
  BackendAssistant.prototype.parseRepo = function (repo) {
724
721
  let repoSplit = repo.split('/');
722
+
723
+ // Remove .git from the end
725
724
  for (var i = 0; i < repoSplit.length; i++) {
726
725
  repoSplit[i] = repoSplit[i].replace('.git', '');
727
726
  }
727
+
728
+ // Remove unnecessary parts
728
729
  repoSplit = repoSplit.filter(function(value, index, arr){
729
- return value !== 'http:' &&
730
- value !== 'https:' &&
731
- value !== '' &&
732
- value !== 'github.com';
730
+ return value !== 'http:'
731
+ && value !== 'https:'
732
+ && value !== ''
733
+ && value !== 'github.com';
733
734
  });
735
+
736
+ // Return
734
737
  return {
735
738
  user: repoSplit[0],
736
739
  name: repoSplit[1],
@@ -28,6 +28,7 @@ Middleware.prototype.run = function (libPath, options) {
28
28
  const assistant = Manager.Assistant({req: req, res: res});
29
29
 
30
30
  const data = assistant.request.data;
31
+ const headers = assistant.request.headers;
31
32
  const geolocation = assistant.request.geolocation;
32
33
  const client = assistant.request.client;
33
34
 
@@ -47,6 +48,7 @@ Middleware.prototype.run = function (libPath, options) {
47
48
 
48
49
  // Log
49
50
  assistant.log(`Middleware.process(): Request (${geolocation.ip} @ ${geolocation.country}, ${geolocation.region}, ${geolocation.city})`, JSON.stringify(data));
51
+ assistant.log(`Middleware.process(): Headers`, JSON.stringify(headers));
50
52
 
51
53
  // Set paths
52
54
  const routesDir = path.resolve(options.routesDir, libPath.replace('.js', ''));
@@ -118,7 +120,7 @@ Middleware.prototype.run = function (libPath, options) {
118
120
  }
119
121
 
120
122
  // Log
121
- assistant.log(`Middleware.process(): Resolved settings with schema ${options.schema}`, JSON.stringify(assistant.settings));
123
+ assistant.log(`Middleware.process(): Resolved settings with schema=${options.schema}`, JSON.stringify(assistant.settings));
122
124
  } else {
123
125
  assistant.settings = data;
124
126
  }
@@ -47,13 +47,16 @@ Settings.prototype.resolve = function (assistant, schema, settings, options) {
47
47
  schema = loadSchema(assistant, schemaPath, settings, options);
48
48
  }
49
49
 
50
- // Resolve settings
51
- self.settings = powertools.defaults(settings, schema);
52
-
53
50
  // If schema is not an object, throw an error
54
51
  if (!schema || typeof schema !== 'object') {
55
52
  throw assistant.errorify(`Invalid schema provided`, {code: 400});
56
53
  }
54
+
55
+ // Resolve settings
56
+ self.settings = powertools.defaults(settings, schema);
57
+ // self.schema = _.merge({}, schema);
58
+ const resolvedSchema = {};
59
+
57
60
  // console.log('---schema', schema);
58
61
  // console.log('---options', options);
59
62
  // console.log('---self.settings', self.settings);
@@ -99,8 +102,27 @@ Settings.prototype.resolve = function (assistant, schema, settings, options) {
99
102
  assistant.warn(`Replacing ${path}: originalValue=${originalValue}, resolvedValue=${resolvedValue}, replaceValue=${replaceValue}`);
100
103
  _.set(self.settings, path, replaceValue);
101
104
  }
105
+
106
+ // Set defaults
107
+ // @@@TODO: FINISH THIS
108
+ // !!! NOT SURE WHAT TO DO FOR DEFAULT SINCE IT CAN BE A FN SOMETIMES ???
109
+ const resolvedNode = {
110
+ types: schemaNode.types || [],
111
+ // value: typeof replaceValue === 'undefined' ? undefined : replaceValue,
112
+ // default: ???,
113
+ required: isRequired,
114
+ available: typeof schemaNode.available === 'undefined' ? true : schemaNode.available,
115
+ min: typeof schemaNode.min === 'undefined' ? undefined : schemaNode.min,
116
+ max: typeof schemaNode.max === 'undefined' ? undefined : schemaNode.max,
117
+ }
118
+
119
+ // Update schema
120
+ _.set(resolvedSchema, path, resolvedNode);
102
121
  });
103
122
 
123
+ // Set schema
124
+ self.schema = resolvedSchema;
125
+
104
126
  // Resolve
105
127
  return self.settings;
106
128
  };
@@ -106,26 +106,23 @@ Usage.prototype.init = function (assistant, options) {
106
106
  self.log(`Usage.init(): Checking if usage data needs to be fetched (${diff} hours)...`);
107
107
 
108
108
  // Get app data to get plan limits using cached data if possible
109
+ assistant.log('*** init() 1 diff', diff);
110
+ assistant.log('*** init() 2 self.app', self.app);
109
111
  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
- })
112
+ await self.getApp(options.app)
113
+ .then((json) => {
114
+ // Write data and last fetched to storage
115
+ self.storage.set(`${self.paths.app}.data`, json).write();
116
+ self.storage.set(`${self.paths.app}.lastFetched`, new Date().toISOString()).write();
117
+ })
118
+ .catch(e => {
119
+ assistant.errorify(`Usage.init(): Error fetching app data: ${e}`, {code: 500, sentry: true});
120
+ });
125
121
  }
126
122
 
127
123
  // Get app data
128
124
  self.app = self.storage.get(`${self.paths.app}.data`, {}).value();
125
+ assistant.log('*** init() 3 self.app', self.app);
129
126
 
130
127
  // Check for app data
131
128
  if (!self.app) {
@@ -311,14 +308,17 @@ Usage.prototype.getLimit = function (name) {
311
308
  Usage.prototype.update = function () {
312
309
  const self = this;
313
310
 
311
+ // Shortcuts
312
+ const Manager = self.Manager;
313
+ const assistant = self.assistant;
314
+
314
315
  return new Promise(async function(resolve, reject) {
315
- const Manager = self.Manager;
316
- const assistant = self.assistant;
316
+ const { admin } = Manager.libraries;
317
317
 
318
318
  // Write self.user to firestore or local if no user or if key is set
319
319
  if (self.useUnauthenticatedStorage) {
320
320
  if (self.options.unauthenticatedMode === 'firestore') {
321
- Manager.libraries.admin.firestore().doc(`temporary/${self.key}`)
321
+ admin.firestore().doc(`temporary/${self.key}`)
322
322
  .set({
323
323
  usage: self.user.usage,
324
324
  }, {merge: true})
@@ -338,7 +338,7 @@ Usage.prototype.update = function () {
338
338
  return resolve(self.user.usage);
339
339
  }
340
340
  } else {
341
- Manager.libraries.admin.firestore().doc(`users/${self.user.auth.uid}`)
341
+ admin.firestore().doc(`users/${self.user.auth.uid}`)
342
342
  .set({
343
343
  usage: self.user.usage,
344
344
  }, {merge: true})
@@ -378,4 +378,53 @@ Usage.prototype.log = function () {
378
378
  }
379
379
  };
380
380
 
381
+ Usage.prototype.getApp = function (id) {
382
+ const self = this;
383
+
384
+ // Shortcuts
385
+ const Manager = self.Manager;
386
+ const assistant = self.assistant;
387
+
388
+ return new Promise(function(resolve, reject) {
389
+ const { admin } = Manager.libraries;
390
+
391
+ assistant.log('***getApp() 1 Manager.config.app.id', Manager.config.app.id);
392
+
393
+ try {
394
+ // If we're on ITW, we can read directly from Firestore
395
+ // If we don't do this, calling getApp on ITW will call getApp on ITW again and again
396
+ if (Manager.config.app.id === 'itw-creative-works') {
397
+ assistant.log('***getApp() 2');
398
+ admin.firestore().doc(`apps/${id}`)
399
+ .get()
400
+ .then((r) => {
401
+ const data = r.data();
402
+
403
+ // Check for data
404
+ if (!data) {
405
+ return reject(new Error('No data found'));
406
+ }
407
+
408
+ // Resolve
409
+ return resolve(data);
410
+ })
411
+ .catch((e) => reject(e));
412
+ } else {
413
+ assistant.log('***getApp() 3');
414
+ fetch('https://us-central1-itw-creative-works.cloudfunctions.net/getApp', {
415
+ method: 'post',
416
+ response: 'json',
417
+ body: {
418
+ id: id,
419
+ },
420
+ })
421
+ .then((json) => resolve(json))
422
+ .catch((e) => reject(e));
423
+ }
424
+ } catch (e) {
425
+ return reject(e);
426
+ }
427
+ });
428
+ };
429
+
381
430
  module.exports = Usage;