backend-manager 3.1.12 → 3.2.0

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
@@ -15,6 +15,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
15
15
  - `Security` in case of vulnerabilities.
16
16
 
17
17
  ---
18
+ ## [3.2.0] - 2023-12-19
19
+ ### Added
20
+ - Added `.settings()` API. Put your settings in `./schema/*.js` and access them with `assistant.settings.*`.
21
+
22
+
18
23
  ## [3.1.0] - 2023-12-19
19
24
  ### Added
20
25
  - Added `.analytics()` API GA4 support.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "3.1.12",
3
+ "version": "3.2.0",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -40,7 +40,7 @@
40
40
  "busboy": "^1.6.0",
41
41
  "chalk": "^4.1.2",
42
42
  "cors": "^2.8.5",
43
- "dotenv": "^16.3.1",
43
+ "dotenv": "^16.3.2",
44
44
  "firebase-admin": "^11.11.1",
45
45
  "firebase-functions": "^4.6.0",
46
46
  "fs-jetpack": "^5.1.0",
@@ -55,7 +55,7 @@
55
55
  "moment": "^2.30.1",
56
56
  "nanoid": "^3.3.7",
57
57
  "node-fetch": "^2.7.0",
58
- "node-powertools": "^1.1.1",
58
+ "node-powertools": "^1.1.2",
59
59
  "npm-api": "^1.0.1",
60
60
  "paypal-server-api": "^1.0.3",
61
61
  "pushid": "^1.0.0",
@@ -70,4 +70,4 @@
70
70
  "wonderful-log": "^1.0.5",
71
71
  "yargs": "^17.7.2"
72
72
  }
73
- }
73
+ }
@@ -36,6 +36,7 @@ BackendAssistant.prototype.init = function (ref, options) {
36
36
  // Attached libraries - used in .errorify()
37
37
  self.analytics = null;
38
38
  self.usage = null;
39
+ self.settings = null;
39
40
 
40
41
  // Set meta
41
42
  self.meta = {};
@@ -26,10 +26,11 @@ Middleware.prototype.run = function (library, req, res, options) {
26
26
 
27
27
  // Set options
28
28
  options = options || {};
29
+ options.authenticate = typeof options.authenticate === 'boolean' ? options.authenticate : true;
29
30
  options.setupAnalytics = typeof options.setupAnalytics === 'boolean' ? options.setupAnalytics : true;
30
31
  options.setupUsage = typeof options.setupUsage === 'boolean' ? options.setupUsage : true;
31
- options.authenticate = typeof options.authenticate === 'boolean' ? options.authenticate : true;
32
32
  options.setupSettings = typeof options.setupSettings === 'undefined' ? true : options.setupSettings;
33
+ options.schema = typeof options.schema === 'undefined' ? '' : options.schema;
33
34
 
34
35
  // Log
35
36
  assistant.log(`Middleware.process(): Request (${geolocation.ip} @ ${geolocation.country}, ${geolocation.region}, ${geolocation.city})`, JSON.stringify(data));
@@ -44,16 +45,16 @@ Middleware.prototype.run = function (library, req, res, options) {
44
45
  return assistant.errorify(`Unable to load library @ (${library}): ${e.message}`, {sentry: true, send: true, log: true});
45
46
  }
46
47
 
47
- // Setup usage
48
- if (options.setupUsage) {
49
- assistant.usage = await Manager.Usage().init(assistant);
50
- }
51
-
52
48
  // Setup user
53
49
  if (!options.setupUsage && options.authenticate) {
54
50
  await assistant.authenticate();
55
51
  }
56
52
 
53
+ // Setup usage
54
+ if (options.setupUsage) {
55
+ assistant.usage = await Manager.Usage().init(assistant);
56
+ }
57
+
57
58
  // Setup analytics
58
59
  if (options.setupAnalytics) {
59
60
  const uuid = assistant?.usage?.user?.auth?.uid
@@ -63,19 +64,16 @@ Middleware.prototype.run = function (library, req, res, options) {
63
64
  assistant.analytics = Manager.Analytics({
64
65
  assistant: assistant,
65
66
  uuid: uuid,
66
- })
67
+ });
67
68
  }
68
69
 
69
70
  // Resolve settings
70
71
  if (options.setupSettings) {
71
- // try {
72
- // const planId = assistant.request.user.plan.id;
73
- // let settings = path.resolve(basePath, `settings.js`);
74
- // settings = require(settings)(assistant)[planId];
75
- // assistant.request.data = powertools.defaults(data, settings);
76
- // } catch (e) {
77
- // return assistant.errorify(`Unable to resolve settings @ (${library}): ${e.message}`, {sentry: true, send: true, log: true});
78
- // }
72
+ try {
73
+ assistant.settings = Manager.Settings().resolve(assistant, options.schema, assistant.request.data);
74
+ } catch (e) {
75
+ return assistant.errorify(`Unable to resolve settings @ (${options.schema}): ${e.message}`, {sentry: true, send: true, log: true});
76
+ }
79
77
  }
80
78
 
81
79
  // Process
@@ -2,31 +2,81 @@
2
2
  * Settings
3
3
  *
4
4
  */
5
+ // const jetpack = require('fs-jetpack');
6
+ const path = require('path');
7
+ const powertools = require('node-powertools');
8
+ const _ = require('lodash');
9
+ const moment = require('moment');
10
+
5
11
  function Settings(m) {
6
12
  const self = this;
7
13
 
8
14
  self.Manager = m;
9
15
 
10
- self.user = null;
11
-
12
- self.initialized = false;
16
+ self.settings = null;
13
17
  }
14
18
 
15
- Settings.prototype.resolve = function (assistant, options) {
19
+ Settings.prototype.resolve = function (assistant, schema, settings) {
16
20
  const self = this;
21
+ const Manager = self.Manager;
22
+
23
+ // Set settings
24
+ schema = schema || {};
25
+ settings = settings || {};
26
+
27
+ // Reset settings
28
+ self.settings = null;
29
+
30
+ assistant.log('Resolving settings for', schema, settings);
31
+
32
+ if (typeof schema === 'string') {
33
+ const schemaPath = path.resolve(process.cwd(), `schemas/${schema.replace('.js', '')}.js`);
34
+
35
+ schema = loadSchema(assistant, schemaPath, settings);
36
+ }
17
37
 
18
- return new Promise(async function(resolve, reject) {
19
- const Manager = self.Manager;
38
+ self.settings = powertools.defaults(settings, schema);
20
39
 
21
- // Set options
22
- options = options || {};
40
+ // Resolve
41
+ return self.settings;
42
+ };
43
+
44
+ Settings.prototype.constant = function (name, options) {
45
+ const self = this;
46
+ const Manager = self.Manager;
23
47
 
24
- // Set initialized to true
25
- self.initialized = true;
48
+ options = options || {};
49
+ options.date = typeof options.date === 'undefined' ? moment() : moment(options.date);
26
50
 
27
- // Resolve
28
- return resolve(self);
29
- });
51
+ if (name === 'timestamp') {
52
+ return {
53
+ types: ['string'],
54
+ value: undefined,
55
+ default: options.date.toISOString(),
56
+ }
57
+ } else if (name === 'timestampUNIX') {
58
+ return {
59
+ types: ['number'],
60
+ value: undefined,
61
+ default: options.date.unix(),
62
+ }
63
+ } else if (name === 'timestampFULL') {
64
+ return {
65
+ timestamp: self.constant('timestamp', options),
66
+ timestampUNIX: self.constant('timestampUNIX', options),
67
+ }
68
+ }
30
69
  };
31
70
 
71
+ function loadSchema(assistant, schema, settings) {
72
+ const planId = assistant.request.user.plan.id;
73
+
74
+ const lib = require(schema)(assistant);
75
+ const def = lib.defaults;
76
+ const plan = lib[planId];
77
+
78
+ // Merge
79
+ return _.merge({}, def, plan);
80
+ }
81
+
32
82
  module.exports = Settings;
@@ -224,8 +224,9 @@ SubscriptionResolver.prototype.resolve = function (options) {
224
224
  resolved.details.message = 'Pre-payment authorization failed because there is no working payment method on file.'
225
225
  }
226
226
 
227
- // If they got a refund, set the expiration to 0
228
- if (resolved.payment.refunded) {
227
+ // If they got a refund (AND cancelled), set the expiration to 0
228
+ // This allows for partial refunds without disabling the subscription
229
+ if (resolved.payment.refunded && resolved.status === 'cancelled') {
229
230
  resolved.expires.timestamp = moment(0);
230
231
  resolved.details.message = 'Refund was issued so subscription is inactive.'
231
232
  }
@@ -84,9 +84,7 @@ Usage.prototype.init = function (assistant, options) {
84
84
  // TODO: Make it request using .where() query so it doesnt use a read if it doesnt have to
85
85
  foundUsage = await Manager.libraries.admin.firestore().doc(`temporary/usage`)
86
86
  .get()
87
- .then((r) => {
88
- return r.data()?.[`${self.key}`];
89
- })
87
+ .then((r) => _.get(r.data(), self.key))
90
88
  .catch((e) => {
91
89
  assistant.errorify(`Usage.init(): Error fetching usage data: ${e}`, {sentry: true, send: false, log: true});
92
90
  });