@vario-software/vario-app-framework-backend 2026.22.2 → 2026.25.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/api/ErpApi.js CHANGED
@@ -9,6 +9,7 @@ const TextEnum = require('#backend/api/modules/textEnum.js');
9
9
  const Webhook = require('#backend/api/modules/webhook.js');
10
10
  const PermittedToken = require('#backend/api/modules/permittedToken.js');
11
11
  const { validateOfflineToken, isAppTokenExpired, refreshAppToken } = require('#backend/utils/token.js');
12
+ const HttpError = require('#backend/utils/httpError.js');
12
13
 
13
14
  const singletonPromise = new PromiseSingletonMap();
14
15
  class ErpApi extends Api
@@ -58,7 +59,10 @@ class ErpApi extends Api
58
59
  {
59
60
  const tenant = getTenant();
60
61
 
61
- await this.app.accessToken.delete(tenant);
62
+ if (tenant)
63
+ {
64
+ await this.app.accessToken.delete(tenant);
65
+ }
62
66
  }
63
67
  }
64
68
 
@@ -66,13 +70,22 @@ class ErpApi extends Api
66
70
  {
67
71
  const tenant = getTenant();
68
72
 
73
+ if (!tenant)
74
+ {
75
+ throw new HttpError(
76
+ 'MISSING_TENANT',
77
+ 400,
78
+ 'backend/api/ErpApi',
79
+ );
80
+ }
81
+
69
82
  return singletonPromise.run(tenant, async () =>
70
83
  {
71
84
  const savedAccessToken = await this.app.accessToken.get(tenant);
72
85
 
73
86
  if (savedAccessToken)
74
87
  {
75
- const baseUrl = await this.app.baseUrlCache.get();
88
+ const baseUrl = await this.app.baseUrlCache.get(tenant);
76
89
 
77
90
  return {
78
91
  baseUrl,
@@ -86,7 +99,7 @@ class ErpApi extends Api
86
99
  const domain = iss.replace('https://sso.', '').split('/')[0];
87
100
  const baseUrl = `https://${tenant}.${domain}`;
88
101
 
89
- await this.app.baseUrlCache.set(baseUrl);
102
+ await this.app.baseUrlCache.set(tenant, baseUrl);
90
103
 
91
104
  const {
92
105
  access_token: accessToken,
@@ -98,7 +111,7 @@ class ErpApi extends Api
98
111
 
99
112
  const expiresAt = Date.now() + (expiresIn * 0.9) * 1000;
100
113
 
101
- this.app.accessToken.set(tenant, accessToken, expiresAt);
114
+ await this.app.accessToken.set(tenant, accessToken, expiresAt);
102
115
 
103
116
  return {
104
117
  baseUrl,
@@ -18,6 +18,13 @@ function streamResponse(res, handler)
18
18
  res.write(`${JSON.stringify(data)}\n`);
19
19
  };
20
20
 
21
+ // Keep the connection non-idle during long silent phases (e.g. polling for the
22
+ // ERP import to extract). Reverse proxies/gateways close idle connections with a
23
+ // 504 after ~60s; a periodic blank line resets that timer. Blank lines are ignored
24
+ // by the client parsers (they filter out non-JSON / empty lines).
25
+ const HEARTBEAT_INTERVAL_MS = 15_000;
26
+ const heartbeat = setInterval(() => res.write('\n'), HEARTBEAT_INTERVAL_MS);
27
+
21
28
  return handler(onProgress)
22
29
  .then(result =>
23
30
  {
@@ -29,6 +36,7 @@ function streamResponse(res, handler)
29
36
  })
30
37
  .finally(() =>
31
38
  {
39
+ clearInterval(heartbeat);
32
40
  res.end();
33
41
  });
34
42
  }
@@ -1,3 +1,5 @@
1
+ const HttpError = require('#backend/utils/httpError.js');
2
+
1
3
  class AccessToken
2
4
  {
3
5
  #cache = {};
@@ -9,6 +11,8 @@ class AccessToken
9
11
 
10
12
  async get(tenant)
11
13
  {
14
+ this.#assertTenant(tenant);
15
+
12
16
  const tokenData = this.#cache[tenant];
13
17
 
14
18
  if (!tokenData)
@@ -28,6 +32,8 @@ class AccessToken
28
32
 
29
33
  async set(tenant, accessToken, expiresAt)
30
34
  {
35
+ this.#assertTenant(tenant);
36
+
31
37
  this.#cache[tenant] = {
32
38
  accessToken,
33
39
  expiresAt,
@@ -36,8 +42,22 @@ class AccessToken
36
42
 
37
43
  async delete(tenant)
38
44
  {
45
+ this.#assertTenant(tenant);
46
+
39
47
  delete this.#cache[tenant];
40
48
  }
49
+
50
+ #assertTenant(tenant)
51
+ {
52
+ if (!tenant)
53
+ {
54
+ throw new HttpError(
55
+ 'MISSING_TENANT',
56
+ 400,
57
+ 'backend/modules/accessToken',
58
+ );
59
+ }
60
+ }
41
61
  }
42
62
 
43
63
  module.exports = AccessToken;
@@ -1,5 +1,5 @@
1
- const { getTenant } = require('#backend/utils/context.js');
2
1
  const { validateOfflineToken } = require('#backend/utils/token.js');
2
+ const HttpError = require('#backend/utils/httpError.js');
3
3
 
4
4
  class BaseUrlCache
5
5
  {
@@ -15,9 +15,21 @@ class BaseUrlCache
15
15
  return Promise.resolve();
16
16
  }
17
17
 
18
- async get()
18
+ #assertTenant(tenant)
19
19
  {
20
- const tenant = getTenant();
20
+ if (!tenant)
21
+ {
22
+ throw new HttpError(
23
+ 'MISSING_TENANT',
24
+ 400,
25
+ 'backend/modules/baseUrlCache',
26
+ );
27
+ }
28
+ }
29
+
30
+ async get(tenant)
31
+ {
32
+ this.#assertTenant(tenant);
21
33
 
22
34
  if (this.#cache[tenant])
23
35
  {
@@ -30,21 +42,21 @@ class BaseUrlCache
30
42
  const domain = iss.replace('https://sso.', '').split('/')[0];
31
43
  const baseUrl = `https://${tenant}.${domain}`;
32
44
 
33
- await this.set(baseUrl);
45
+ await this.set(tenant, baseUrl);
34
46
 
35
47
  return baseUrl;
36
48
  }
37
49
 
38
- async set(value)
50
+ async set(tenant, value)
39
51
  {
40
- const tenant = getTenant();
52
+ this.#assertTenant(tenant);
41
53
 
42
54
  this.#cache[tenant] = value;
43
55
  }
44
56
 
45
- async delete()
57
+ async delete(tenant)
46
58
  {
47
- const tenant = getTenant();
59
+ this.#assertTenant(tenant);
48
60
 
49
61
  delete this.#cache[tenant];
50
62
  }
@@ -1,3 +1,5 @@
1
+ const HttpError = require('#backend/utils/httpError.js');
2
+
1
3
  class OfflineToken
2
4
  {
3
5
  constructor(app, filename = 'offlineToken.db')
@@ -15,13 +17,29 @@ class OfflineToken
15
17
  this.database = await JSONFilePreset(this.filename, {});
16
18
  }
17
19
 
20
+ #assertTenant(tenant)
21
+ {
22
+ if (!tenant)
23
+ {
24
+ throw new HttpError(
25
+ 'MISSING_TENANT',
26
+ 400,
27
+ 'backend/modules/offlineToken',
28
+ );
29
+ }
30
+ }
31
+
18
32
  async get(tenant)
19
33
  {
34
+ this.#assertTenant(tenant);
35
+
20
36
  return this.database.data[tenant];
21
37
  }
22
38
 
23
39
  async set(tenant, offlineToken)
24
40
  {
41
+ this.#assertTenant(tenant);
42
+
25
43
  this.app.accessToken.delete(tenant);
26
44
 
27
45
  return this.database.update(tokens =>
@@ -32,6 +50,8 @@ class OfflineToken
32
50
 
33
51
  async delete(tenant)
34
52
  {
53
+ this.#assertTenant(tenant);
54
+
35
55
  this.app.accessToken.delete(tenant);
36
56
 
37
57
  return this.database.update(tokens =>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vario-software/vario-app-framework-backend",
3
- "version": "2026.22.2",
3
+ "version": "2026.25.0",
4
4
  "repository": "https://github.com/vario-software/vario-app-framework",
5
5
  "author": "VARIO Software AG",
6
6
  "homepage": "https://www.vario.ag",