b2b-platform-utils 1.1.7 → 1.1.9
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/amountFormat.js +97 -0
- package/localCache.js +92 -27
- package/package.json +1 -1
package/amountFormat.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module amountFormat
|
|
5
|
+
* @description
|
|
6
|
+
* Utility for consistent conversion between major (e.g. 17.00 EUR)
|
|
7
|
+
* and minor units (e.g. 1700 cents).
|
|
8
|
+
*
|
|
9
|
+
* All conversions are currency-aware and respect currency exponents:
|
|
10
|
+
* EUR/USD/GBP → 2 decimals, JPY → 0 decimals, KWD → 3 decimals.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { getBaseCurrency } = require('./localCache');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Convert minor units (e.g. 1700) to major amount (e.g. 17.00)
|
|
17
|
+
*
|
|
18
|
+
* @param {number|string} amount - Minor amount in integer form.
|
|
19
|
+
* @param {string} [currency=getBaseCurrency()] - ISO 4217 currency code.
|
|
20
|
+
* @returns {number} Major amount.
|
|
21
|
+
* @throws {Error} If amount is not numeric.
|
|
22
|
+
*/
|
|
23
|
+
function toMajorAmount(amount, currency = getBaseCurrency()) {
|
|
24
|
+
if (amount == null) return 0;
|
|
25
|
+
|
|
26
|
+
const exponent = getCurrencyExponent(currency);
|
|
27
|
+
const num = Number(amount);
|
|
28
|
+
|
|
29
|
+
if (!Number.isFinite(num)) {
|
|
30
|
+
throw new Error('Invalid amount');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Avoid unnecessary floating-point drift.
|
|
34
|
+
const factor = Math.pow(10, exponent);
|
|
35
|
+
const major = num / factor;
|
|
36
|
+
|
|
37
|
+
return parseFloat(major.toFixed(exponent));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Convert major amount (e.g. 17.00) to minor units (e.g. 1700)
|
|
42
|
+
*
|
|
43
|
+
* @param {number|string} amount - Major amount.
|
|
44
|
+
* @param {string} [currency=getBaseCurrency()] - ISO 4217 currency code.
|
|
45
|
+
* @returns {number} Minor amount as integer.
|
|
46
|
+
* @throws {Error} If amount is missing or invalid.
|
|
47
|
+
*/
|
|
48
|
+
function toMinorAmount(amount, currency = getBaseCurrency()) {
|
|
49
|
+
if (amount == null) {
|
|
50
|
+
throw new Error('Amount is required');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const exponent = getCurrencyExponent(currency);
|
|
54
|
+
const normalized = String(amount).replace(',', '.'); // support "17,5"
|
|
55
|
+
const num = Number(normalized);
|
|
56
|
+
|
|
57
|
+
if (!Number.isFinite(num)) {
|
|
58
|
+
throw new Error('Invalid amount');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const fixed = num.toFixed(exponent);
|
|
62
|
+
// Using Math.round avoids string replace for integers like 0 decimals
|
|
63
|
+
const minor = Math.round(num * Math.pow(10, exponent));
|
|
64
|
+
|
|
65
|
+
// fallback to parsed integer if rounding is not safe
|
|
66
|
+
return Number.isSafeInteger(minor)
|
|
67
|
+
? minor
|
|
68
|
+
: parseInt(fixed.replace('.', ''), 10);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Return decimal exponent for currency.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} currency - ISO 4217 currency code.
|
|
75
|
+
* @returns {number} Number of decimal places (default = 2).
|
|
76
|
+
*/
|
|
77
|
+
function getCurrencyExponent(currency) {
|
|
78
|
+
const map = {
|
|
79
|
+
EUR: 2,
|
|
80
|
+
USD: 2,
|
|
81
|
+
GBP: 2,
|
|
82
|
+
CHF: 2,
|
|
83
|
+
JPY: 0,
|
|
84
|
+
KWD: 3
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const code = typeof currency === 'string'
|
|
88
|
+
? currency.trim().toUpperCase()
|
|
89
|
+
: '';
|
|
90
|
+
|
|
91
|
+
return map[code] ?? 2;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
toMajorAmount,
|
|
96
|
+
toMinorAmount
|
|
97
|
+
};
|
package/localCache.js
CHANGED
|
@@ -4,17 +4,24 @@
|
|
|
4
4
|
* @module inMemoryConfig
|
|
5
5
|
* @description
|
|
6
6
|
* Process-scoped in-memory key-value store for configuration.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
7
|
+
*
|
|
8
|
+
* Highlights:
|
|
9
|
+
* - Safe in-memory KV for runtime config/state.
|
|
10
|
+
* - "common" bag is the canonical place for cross-service shared config
|
|
11
|
+
* (locale, currency, GEO, etc.).
|
|
12
|
+
* - Optional ENV fallback for BaseCurrency.
|
|
13
|
+
* - Includes service-level tuning constants like bufferChunkSize,
|
|
14
|
+
* defaultLimit, and RPC wait thresholds.
|
|
10
15
|
*
|
|
11
16
|
* Design goals:
|
|
12
|
-
* 1) No side effects on import
|
|
13
|
-
* 2)
|
|
14
|
-
* 3)
|
|
17
|
+
* 1) No side effects on import. ENV is only read lazily and only if enabled.
|
|
18
|
+
* 2) Service can identify itself at runtime via setService().
|
|
19
|
+
* 3) Callers can safely read sane defaults (e.g. en-US, USD, WW).
|
|
15
20
|
*/
|
|
16
21
|
|
|
17
|
-
//
|
|
22
|
+
// -----------------------------------------------------------------------------
|
|
23
|
+
// Internal state
|
|
24
|
+
// -----------------------------------------------------------------------------
|
|
18
25
|
|
|
19
26
|
/** @type {Record<string, any>} */
|
|
20
27
|
let cacheData = {};
|
|
@@ -23,7 +30,13 @@ let cacheData = {};
|
|
|
23
30
|
let serviceKey = 'not_set_service';
|
|
24
31
|
|
|
25
32
|
/** @type {number} */
|
|
26
|
-
|
|
33
|
+
const bufferChunkSize = 512000;
|
|
34
|
+
|
|
35
|
+
/** @type {number} */
|
|
36
|
+
const defaultLimit = 30;
|
|
37
|
+
|
|
38
|
+
/** @type {number} */
|
|
39
|
+
const RPC_WAIT_FOR_READY = 2000;
|
|
27
40
|
|
|
28
41
|
/** @type {string} */
|
|
29
42
|
const GEO_DEFAULT = 'WW';
|
|
@@ -34,10 +47,17 @@ const LOCALE_DEFAULT = 'en-US';
|
|
|
34
47
|
/** @type {boolean} */
|
|
35
48
|
let envBaseCurrencyFallbackEnabled = false; // opt-in per process
|
|
36
49
|
|
|
37
|
-
//
|
|
50
|
+
// -----------------------------------------------------------------------------
|
|
51
|
+
// Internal utilities
|
|
52
|
+
// -----------------------------------------------------------------------------
|
|
38
53
|
|
|
39
54
|
/**
|
|
40
55
|
* Ensure the "common" bag exists and return it by reference.
|
|
56
|
+
* This is the shared namespace for cross-cutting runtime config such as:
|
|
57
|
+
* - GEODefault
|
|
58
|
+
* - LocaleDefault
|
|
59
|
+
* - BaseCurrency
|
|
60
|
+
*
|
|
41
61
|
* @returns {Record<string, any>}
|
|
42
62
|
*/
|
|
43
63
|
function ensureCommonBag() {
|
|
@@ -49,7 +69,7 @@ function ensureCommonBag() {
|
|
|
49
69
|
|
|
50
70
|
/**
|
|
51
71
|
* Normalize to a 3-letter uppercase currency code.
|
|
52
|
-
* Returns null if invalid.
|
|
72
|
+
* Returns null if the code is missing or invalid.
|
|
53
73
|
*
|
|
54
74
|
* @param {unknown} value
|
|
55
75
|
* @returns {string|null}
|
|
@@ -60,7 +80,9 @@ function normalizeCurrencyCode(value) {
|
|
|
60
80
|
return /^[A-Z]{3}$/.test(code) ? code : null;
|
|
61
81
|
}
|
|
62
82
|
|
|
63
|
-
//
|
|
83
|
+
// -----------------------------------------------------------------------------
|
|
84
|
+
// Public API: KV
|
|
85
|
+
// -----------------------------------------------------------------------------
|
|
64
86
|
|
|
65
87
|
/**
|
|
66
88
|
* Set a top-level key in the cache.
|
|
@@ -74,6 +96,7 @@ function setValue(key, value) {
|
|
|
74
96
|
|
|
75
97
|
/**
|
|
76
98
|
* Get a top-level value from the cache.
|
|
99
|
+
* Returns null if the key is not present.
|
|
77
100
|
*
|
|
78
101
|
* @param {string} key
|
|
79
102
|
* @returns {any|null}
|
|
@@ -86,6 +109,7 @@ function getValue(key) {
|
|
|
86
109
|
|
|
87
110
|
/**
|
|
88
111
|
* Shallow-merge a config object into the cache.
|
|
112
|
+
* Keys in `data` override current values.
|
|
89
113
|
*
|
|
90
114
|
* @param {Record<string, any>} data
|
|
91
115
|
*/
|
|
@@ -99,6 +123,7 @@ function applyConfig(data) {
|
|
|
99
123
|
|
|
100
124
|
/**
|
|
101
125
|
* Return a direct reference to the whole cache (mutable).
|
|
126
|
+
* This is useful for diagnostics, admin endpoints, etc.
|
|
102
127
|
*
|
|
103
128
|
* @returns {Record<string, any>}
|
|
104
129
|
*/
|
|
@@ -106,10 +131,13 @@ function getData() {
|
|
|
106
131
|
return cacheData;
|
|
107
132
|
}
|
|
108
133
|
|
|
109
|
-
//
|
|
134
|
+
// -----------------------------------------------------------------------------
|
|
135
|
+
// Public API: service/meta
|
|
136
|
+
// -----------------------------------------------------------------------------
|
|
110
137
|
|
|
111
138
|
/**
|
|
112
|
-
* Return current microservice key.
|
|
139
|
+
* Return the current microservice key.
|
|
140
|
+
* Example: "gateway", "cms", "analytics".
|
|
113
141
|
*
|
|
114
142
|
* @returns {string}
|
|
115
143
|
*/
|
|
@@ -118,7 +146,8 @@ function getService() {
|
|
|
118
146
|
}
|
|
119
147
|
|
|
120
148
|
/**
|
|
121
|
-
*
|
|
149
|
+
* Set the current microservice key at runtime.
|
|
150
|
+
* Should typically be called once during bootstrap of each service.
|
|
122
151
|
*
|
|
123
152
|
* @param {string} key
|
|
124
153
|
*/
|
|
@@ -130,6 +159,7 @@ function setService(key) {
|
|
|
130
159
|
|
|
131
160
|
/**
|
|
132
161
|
* Get configured buffer chunk size.
|
|
162
|
+
* Used in streaming / chunked payload logic.
|
|
133
163
|
*
|
|
134
164
|
* @returns {number}
|
|
135
165
|
*/
|
|
@@ -138,8 +168,28 @@ function getBufferChunkSize() {
|
|
|
138
168
|
}
|
|
139
169
|
|
|
140
170
|
/**
|
|
141
|
-
*
|
|
142
|
-
*
|
|
171
|
+
* Get default "limit" value for list/pagination endpoints.
|
|
172
|
+
*
|
|
173
|
+
* @returns {number}
|
|
174
|
+
*/
|
|
175
|
+
function getDefaultLimit() {
|
|
176
|
+
return defaultLimit;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get default gRPC "wait for ready" timeout in milliseconds.
|
|
181
|
+
* Used by clients before marking remote service as unavailable.
|
|
182
|
+
*
|
|
183
|
+
* @returns {number}
|
|
184
|
+
*/
|
|
185
|
+
function getRPCWaitForReady() {
|
|
186
|
+
return RPC_WAIT_FOR_READY;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Initialize environment/customer from process startup params.
|
|
191
|
+
* Kept for compatibility with legacy bootstrap flows where
|
|
192
|
+
* process.argv-like arrays are passed in.
|
|
143
193
|
*
|
|
144
194
|
* @param {string[]} params
|
|
145
195
|
*/
|
|
@@ -151,7 +201,8 @@ function parseInitConfig(params) {
|
|
|
151
201
|
}
|
|
152
202
|
|
|
153
203
|
/**
|
|
154
|
-
* Return the "common" bag
|
|
204
|
+
* Return a plain snapshot of the "common" bag,
|
|
205
|
+
* or {} if it is not yet defined.
|
|
155
206
|
*
|
|
156
207
|
* @returns {Record<string, any>}
|
|
157
208
|
*/
|
|
@@ -161,10 +212,13 @@ function getCommonValue() {
|
|
|
161
212
|
: {};
|
|
162
213
|
}
|
|
163
214
|
|
|
164
|
-
//
|
|
215
|
+
// -----------------------------------------------------------------------------
|
|
216
|
+
// Public API: domain helpers (locale / geo / currency)
|
|
217
|
+
// -----------------------------------------------------------------------------
|
|
165
218
|
|
|
166
219
|
/**
|
|
167
220
|
* Read GEODefault from "common" or return fallback.
|
|
221
|
+
* GEO codes usually look like "WW", "EU", "US", etc.
|
|
168
222
|
*
|
|
169
223
|
* @returns {string}
|
|
170
224
|
*/
|
|
@@ -174,7 +228,7 @@ function getDefaultGEO() {
|
|
|
174
228
|
|
|
175
229
|
/**
|
|
176
230
|
* Read LocaleDefault from "common" or return fallback.
|
|
177
|
-
* Locale codes must follow the pattern
|
|
231
|
+
* Locale codes must follow the pattern en-US, de-DE, pt-BR, etc.
|
|
178
232
|
*
|
|
179
233
|
* @returns {string}
|
|
180
234
|
*/
|
|
@@ -184,8 +238,12 @@ function getDefaultLocale() {
|
|
|
184
238
|
|
|
185
239
|
/**
|
|
186
240
|
* Enable or disable ENV fallback for BaseCurrency.
|
|
187
|
-
* When enabled
|
|
188
|
-
* getBaseCurrency() will
|
|
241
|
+
* When enabled AND "common.BaseCurrency" is not set,
|
|
242
|
+
* getBaseCurrency() will try process.env.BASE_CURRENCY.
|
|
243
|
+
*
|
|
244
|
+
* This allows a service to say:
|
|
245
|
+
* - "I understand base currency matters to me"
|
|
246
|
+
* - "If config is missing, read from ENV"
|
|
189
247
|
*
|
|
190
248
|
* @param {boolean} enabled
|
|
191
249
|
*/
|
|
@@ -194,8 +252,10 @@ function enableEnvBaseCurrencyFallback(enabled = true) {
|
|
|
194
252
|
}
|
|
195
253
|
|
|
196
254
|
/**
|
|
197
|
-
* Get BaseCurrency from "common",
|
|
198
|
-
* Returns null if nothing is
|
|
255
|
+
* Get BaseCurrency from "common", or (optionally) from ENV.
|
|
256
|
+
* Returns null if nothing valid is provided.
|
|
257
|
+
*
|
|
258
|
+
* Expected values: "USD", "EUR", "GBP", "JPY", etc.
|
|
199
259
|
*
|
|
200
260
|
* @returns {string|null}
|
|
201
261
|
*/
|
|
@@ -216,9 +276,10 @@ function getBaseCurrency() {
|
|
|
216
276
|
}
|
|
217
277
|
|
|
218
278
|
/**
|
|
219
|
-
*
|
|
279
|
+
* Set BaseCurrency into the "common" bag explicitly.
|
|
280
|
+
* Will throw if code is not a valid 3-letter currency code.
|
|
220
281
|
*
|
|
221
|
-
* @param {string} code - 3-letter code, e.g
|
|
282
|
+
* @param {string} code - 3-letter code, e.g. "USD", "EUR", "GBP".
|
|
222
283
|
* @throws {Error} If code is invalid.
|
|
223
284
|
*/
|
|
224
285
|
function setBaseCurrency(code) {
|
|
@@ -232,10 +293,12 @@ function setBaseCurrency(code) {
|
|
|
232
293
|
common.BaseCurrency = normalized;
|
|
233
294
|
}
|
|
234
295
|
|
|
235
|
-
//
|
|
296
|
+
// -----------------------------------------------------------------------------
|
|
297
|
+
// Exports
|
|
298
|
+
// -----------------------------------------------------------------------------
|
|
236
299
|
|
|
237
300
|
module.exports = {
|
|
238
|
-
// KV
|
|
301
|
+
// KV helpers
|
|
239
302
|
setValue,
|
|
240
303
|
getValue,
|
|
241
304
|
applyConfig,
|
|
@@ -245,6 +308,8 @@ module.exports = {
|
|
|
245
308
|
getService,
|
|
246
309
|
setService,
|
|
247
310
|
getBufferChunkSize,
|
|
311
|
+
getDefaultLimit,
|
|
312
|
+
getRPCWaitForReady,
|
|
248
313
|
parseInitConfig,
|
|
249
314
|
getCommonValue,
|
|
250
315
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "b2b-platform-utils",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "Shared utilities for Node.js microservices: errors map, local cache, logger, numbers, dates, filesystem, media optimization, paginator, slugger, crypto wrapper, sanitize HTML, sorting.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "KingSizer",
|