anote-server-libs 0.2.2 → 0.2.3
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/models/ApiCall.js +37 -37
- package/models/ApiCall.ts +40 -40
- package/models/Migration.js +35 -35
- package/models/Migration.ts +40 -40
- package/models/repository/BaseModelRepository.js +156 -156
- package/models/repository/BaseModelRepository.ts +152 -152
- package/models/repository/MemoryCache.js +92 -92
- package/models/repository/MemoryCache.ts +87 -87
- package/models/repository/ModelDao.js +238 -238
- package/models/repository/ModelDao.ts +259 -259
- package/package.json +38 -38
- package/services/WithBody.js +60 -60
- package/services/WithBody.ts +56 -56
- package/services/WithTransaction.js +137 -137
- package/services/WithTransaction.ts +134 -134
- package/services/utils.js +197 -197
- package/services/utils.ts +180 -180
- package/tsconfig.json +30 -30
package/services/utils.ts
CHANGED
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
import {NextFunction, Request, Response} from 'express';
|
|
2
|
-
import {Logger} from 'winston';
|
|
3
|
-
import {BaseModelRepository} from '../models/repository/BaseModelRepository';
|
|
4
|
-
|
|
5
|
-
export function atob(str: string): string {
|
|
6
|
-
return Buffer.from(str, 'base64').toString('binary');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function btoa(str: string): string {
|
|
10
|
-
return Buffer.from(str).toString('base64');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function clientErrorHandle(this: Logger, err: any) {
|
|
14
|
-
this.error('Error on DB client: %j', err);
|
|
15
|
-
}
|
|
16
|
-
export const utils: {[id: string]: any} = {
|
|
17
|
-
clientErrorHandler: undefined
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
function gcdTwo(a: number, b: number): number {
|
|
21
|
-
if(a === 0)
|
|
22
|
-
return b;
|
|
23
|
-
return gcdTwo(b % a, a);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function gcd(values: number[]): number {
|
|
27
|
-
let result = values[0];
|
|
28
|
-
for(let i = 1; i < values.length; i++)
|
|
29
|
-
result = gcdTwo(values[i], result);
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function lcm(values: number[]): number {
|
|
34
|
-
let l = 1, divisor = 2;
|
|
35
|
-
while(true) {
|
|
36
|
-
let counter = 0;
|
|
37
|
-
let divisible = false;
|
|
38
|
-
for(let i = 0; i < values.length; i++) {
|
|
39
|
-
if(values[i] === 0) {
|
|
40
|
-
return 0;
|
|
41
|
-
} else if(values[i] < 0) {
|
|
42
|
-
values[i] = values[i] * (-1);
|
|
43
|
-
}
|
|
44
|
-
if(values[i] === 1) {
|
|
45
|
-
counter++;
|
|
46
|
-
}
|
|
47
|
-
if(values[i] % divisor === 0) {
|
|
48
|
-
divisible = true;
|
|
49
|
-
values[i] = values[i] / divisor;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if(divisible) {
|
|
53
|
-
l = l * divisor;
|
|
54
|
-
} else {
|
|
55
|
-
divisor++;
|
|
56
|
-
}
|
|
57
|
-
if(counter === values.length) {
|
|
58
|
-
return l;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function jsonStringify(obj: any): string {
|
|
64
|
-
const cache: any = {};
|
|
65
|
-
return JSON.stringify(obj, function(_, value) {
|
|
66
|
-
if(typeof value === 'object' && value !== null) {
|
|
67
|
-
if(cache[value] !== -1) {
|
|
68
|
-
try {
|
|
69
|
-
return JSON.parse(JSON.stringify(value));
|
|
70
|
-
} catch(error) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
cache[value] = true;
|
|
75
|
-
}
|
|
76
|
-
return value;
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function idempotent(repo: BaseModelRepository, debug: boolean, logger: Logger) {
|
|
81
|
-
return function(req: Request, res: Response, next: NextFunction) {
|
|
82
|
-
let idempotenceKey = req.header('x-idempotent-key');
|
|
83
|
-
if(idempotenceKey) {
|
|
84
|
-
idempotenceKey = idempotenceKey.substring(0, 40);
|
|
85
|
-
repo.ApiCall.get(idempotenceKey).then(call => {
|
|
86
|
-
if(!call) {
|
|
87
|
-
const jsonTerminator = res.json;
|
|
88
|
-
const endTerminator = res.end;
|
|
89
|
-
const writeTerminator = res.write;
|
|
90
|
-
let response = '';
|
|
91
|
-
res.json = (function(obj: any) {
|
|
92
|
-
repo.ApiCall.create({
|
|
93
|
-
id: idempotenceKey,
|
|
94
|
-
responseCode: res.statusCode,
|
|
95
|
-
responseJson: jsonStringify(obj),
|
|
96
|
-
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
|
|
97
|
-
}).then(() => jsonTerminator.call(res, obj), err => {
|
|
98
|
-
if(err) logger.warn('Cannot save idempotent key: %j', err);
|
|
99
|
-
jsonTerminator.call(res, obj);
|
|
100
|
-
});
|
|
101
|
-
}).bind(res);
|
|
102
|
-
res.end = (function(buf: string) {
|
|
103
|
-
if(buf) response = response + buf.toString();
|
|
104
|
-
repo.ApiCall.create({
|
|
105
|
-
id: idempotenceKey,
|
|
106
|
-
responseCode: res.statusCode,
|
|
107
|
-
responseJson: response,
|
|
108
|
-
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
|
|
109
|
-
}).then(() => endTerminator.call(res, buf), err => {
|
|
110
|
-
if(err) logger.warn('Cannot save idempotent key: %j', err);
|
|
111
|
-
endTerminator.call(res, buf);
|
|
112
|
-
});
|
|
113
|
-
}).bind(res);
|
|
114
|
-
res.write = (function(buf: string) {
|
|
115
|
-
if(buf) response = response + buf.toString();
|
|
116
|
-
writeTerminator.call(res, buf);
|
|
117
|
-
}).bind(res);
|
|
118
|
-
next();
|
|
119
|
-
} else res.status(417).json({
|
|
120
|
-
responseCode: call.responseCode,
|
|
121
|
-
responseBody: call.responseJson
|
|
122
|
-
});
|
|
123
|
-
}, err => res.status(500).json({
|
|
124
|
-
error: {
|
|
125
|
-
errorKey: 'internal.db',
|
|
126
|
-
additionalInfo: {message: err.message, stack: debug && err.stack}
|
|
127
|
-
}
|
|
128
|
-
}));
|
|
129
|
-
} else next();
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export function sendSelfPostableMessage(res: Response, code: number, messageType: string, err?: any) {
|
|
134
|
-
res.type('text/html').status(code).write(`
|
|
135
|
-
<!DOCTYPE HTML>
|
|
136
|
-
<html>
|
|
137
|
-
<head>
|
|
138
|
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
139
|
-
</head>
|
|
140
|
-
<body>
|
|
141
|
-
<script type="text/javascript">
|
|
142
|
-
window.parent.postMessage({
|
|
143
|
-
type: '${messageType}',
|
|
144
|
-
confirm: ${!err},
|
|
145
|
-
error: JSON.parse('${JSON.stringify(err) || 'null'}')
|
|
146
|
-
}, '*');
|
|
147
|
-
</script>
|
|
148
|
-
</body>
|
|
149
|
-
</html>
|
|
150
|
-
`);
|
|
151
|
-
res.end();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function fpEuros(n: number) {
|
|
155
|
-
return Math.round(n * 100) / 100;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function digitize(value: number | string, opts?: {[key: string]: any}): string {
|
|
159
|
-
if(value === undefined || value === null) return 'undefined';
|
|
160
|
-
if(typeof value === 'number') {
|
|
161
|
-
if(isNaN(value)) return '-';
|
|
162
|
-
if(!isFinite(value)) return 'Infinite';
|
|
163
|
-
value = String(value);
|
|
164
|
-
} else if(typeof value === 'string') return value;
|
|
165
|
-
|
|
166
|
-
const parts = value.split('.');
|
|
167
|
-
const initialLength = parts[0].length;
|
|
168
|
-
for(let i = initialLength - 3; i > 0; i -= 3) {
|
|
169
|
-
parts[0] = parts[0].slice(0, i) + ',' + parts[0].slice(i);
|
|
170
|
-
}
|
|
171
|
-
if(parts[0].startsWith('-,'))
|
|
172
|
-
parts[0] = '-' + parts[0].slice(2);
|
|
173
|
-
if(parts[1]) {
|
|
174
|
-
const expDecimals = parts[1].split(/[eE]-/);
|
|
175
|
-
if (expDecimals.length > 1 && parseInt(expDecimals[1], 10) > 2) return '0.00';
|
|
176
|
-
let decimals = fpEuros(parseFloat('0.' + parts[1])).toString().substr(2, 2);
|
|
177
|
-
if (decimals.length === 1) decimals += '0';
|
|
178
|
-
return parts[0] + '.' + decimals;
|
|
179
|
-
}
|
|
180
|
-
return (opts && opts.currency)? (parts[0] + '.00') : parts[0];
|
|
1
|
+
import {NextFunction, Request, Response} from 'express';
|
|
2
|
+
import {Logger} from 'winston';
|
|
3
|
+
import {BaseModelRepository} from '../models/repository/BaseModelRepository';
|
|
4
|
+
|
|
5
|
+
export function atob(str: string): string {
|
|
6
|
+
return Buffer.from(str, 'base64').toString('binary');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function btoa(str: string): string {
|
|
10
|
+
return Buffer.from(str).toString('base64');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function clientErrorHandle(this: Logger, err: any) {
|
|
14
|
+
this.error('Error on DB client: %j', err);
|
|
15
|
+
}
|
|
16
|
+
export const utils: {[id: string]: any} = {
|
|
17
|
+
clientErrorHandler: undefined
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function gcdTwo(a: number, b: number): number {
|
|
21
|
+
if(a === 0)
|
|
22
|
+
return b;
|
|
23
|
+
return gcdTwo(b % a, a);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function gcd(values: number[]): number {
|
|
27
|
+
let result = values[0];
|
|
28
|
+
for(let i = 1; i < values.length; i++)
|
|
29
|
+
result = gcdTwo(values[i], result);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function lcm(values: number[]): number {
|
|
34
|
+
let l = 1, divisor = 2;
|
|
35
|
+
while(true) {
|
|
36
|
+
let counter = 0;
|
|
37
|
+
let divisible = false;
|
|
38
|
+
for(let i = 0; i < values.length; i++) {
|
|
39
|
+
if(values[i] === 0) {
|
|
40
|
+
return 0;
|
|
41
|
+
} else if(values[i] < 0) {
|
|
42
|
+
values[i] = values[i] * (-1);
|
|
43
|
+
}
|
|
44
|
+
if(values[i] === 1) {
|
|
45
|
+
counter++;
|
|
46
|
+
}
|
|
47
|
+
if(values[i] % divisor === 0) {
|
|
48
|
+
divisible = true;
|
|
49
|
+
values[i] = values[i] / divisor;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if(divisible) {
|
|
53
|
+
l = l * divisor;
|
|
54
|
+
} else {
|
|
55
|
+
divisor++;
|
|
56
|
+
}
|
|
57
|
+
if(counter === values.length) {
|
|
58
|
+
return l;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function jsonStringify(obj: any): string {
|
|
64
|
+
const cache: any = {};
|
|
65
|
+
return JSON.stringify(obj, function(_, value) {
|
|
66
|
+
if(typeof value === 'object' && value !== null) {
|
|
67
|
+
if(cache[value] !== -1) {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(JSON.stringify(value));
|
|
70
|
+
} catch(error) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
cache[value] = true;
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function idempotent(repo: BaseModelRepository, debug: boolean, logger: Logger) {
|
|
81
|
+
return function(req: Request, res: Response, next: NextFunction) {
|
|
82
|
+
let idempotenceKey = req.header('x-idempotent-key');
|
|
83
|
+
if(idempotenceKey) {
|
|
84
|
+
idempotenceKey = idempotenceKey.substring(0, 40);
|
|
85
|
+
repo.ApiCall.get(idempotenceKey).then(call => {
|
|
86
|
+
if(!call) {
|
|
87
|
+
const jsonTerminator = res.json;
|
|
88
|
+
const endTerminator = res.end;
|
|
89
|
+
const writeTerminator = res.write;
|
|
90
|
+
let response = '';
|
|
91
|
+
res.json = (function(obj: any) {
|
|
92
|
+
repo.ApiCall.create({
|
|
93
|
+
id: idempotenceKey,
|
|
94
|
+
responseCode: res.statusCode,
|
|
95
|
+
responseJson: jsonStringify(obj),
|
|
96
|
+
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
|
|
97
|
+
}).then(() => jsonTerminator.call(res, obj), err => {
|
|
98
|
+
if(err) logger.warn('Cannot save idempotent key: %j', err);
|
|
99
|
+
jsonTerminator.call(res, obj);
|
|
100
|
+
});
|
|
101
|
+
}).bind(res);
|
|
102
|
+
res.end = (function(buf: string) {
|
|
103
|
+
if(buf) response = response + buf.toString();
|
|
104
|
+
repo.ApiCall.create({
|
|
105
|
+
id: idempotenceKey,
|
|
106
|
+
responseCode: res.statusCode,
|
|
107
|
+
responseJson: response,
|
|
108
|
+
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
|
|
109
|
+
}).then(() => endTerminator.call(res, buf), err => {
|
|
110
|
+
if(err) logger.warn('Cannot save idempotent key: %j', err);
|
|
111
|
+
endTerminator.call(res, buf);
|
|
112
|
+
});
|
|
113
|
+
}).bind(res);
|
|
114
|
+
res.write = (function(buf: string) {
|
|
115
|
+
if(buf) response = response + buf.toString();
|
|
116
|
+
writeTerminator.call(res, buf);
|
|
117
|
+
}).bind(res);
|
|
118
|
+
next();
|
|
119
|
+
} else res.status(417).json({
|
|
120
|
+
responseCode: call.responseCode,
|
|
121
|
+
responseBody: call.responseJson
|
|
122
|
+
});
|
|
123
|
+
}, err => res.status(500).json({
|
|
124
|
+
error: {
|
|
125
|
+
errorKey: 'internal.db',
|
|
126
|
+
additionalInfo: {message: err.message, stack: debug && err.stack}
|
|
127
|
+
}
|
|
128
|
+
}));
|
|
129
|
+
} else next();
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function sendSelfPostableMessage(res: Response, code: number, messageType: string, err?: any) {
|
|
134
|
+
res.type('text/html').status(code).write(`
|
|
135
|
+
<!DOCTYPE HTML>
|
|
136
|
+
<html>
|
|
137
|
+
<head>
|
|
138
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
139
|
+
</head>
|
|
140
|
+
<body>
|
|
141
|
+
<script type="text/javascript">
|
|
142
|
+
window.parent.postMessage({
|
|
143
|
+
type: '${messageType}',
|
|
144
|
+
confirm: ${!err},
|
|
145
|
+
error: JSON.parse('${JSON.stringify(err) || 'null'}')
|
|
146
|
+
}, '*');
|
|
147
|
+
</script>
|
|
148
|
+
</body>
|
|
149
|
+
</html>
|
|
150
|
+
`);
|
|
151
|
+
res.end();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function fpEuros(n: number) {
|
|
155
|
+
return Math.round(n * 100) / 100;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function digitize(value: number | string, opts?: {[key: string]: any}): string {
|
|
159
|
+
if(value === undefined || value === null) return 'undefined';
|
|
160
|
+
if(typeof value === 'number') {
|
|
161
|
+
if(isNaN(value)) return '-';
|
|
162
|
+
if(!isFinite(value)) return 'Infinite';
|
|
163
|
+
value = String(value);
|
|
164
|
+
} else if(typeof value === 'string') return value;
|
|
165
|
+
|
|
166
|
+
const parts = value.split('.');
|
|
167
|
+
const initialLength = parts[0].length;
|
|
168
|
+
for(let i = initialLength - 3; i > 0; i -= 3) {
|
|
169
|
+
parts[0] = parts[0].slice(0, i) + ',' + parts[0].slice(i);
|
|
170
|
+
}
|
|
171
|
+
if(parts[0].startsWith('-,'))
|
|
172
|
+
parts[0] = '-' + parts[0].slice(2);
|
|
173
|
+
if(parts[1]) {
|
|
174
|
+
const expDecimals = parts[1].split(/[eE]-/);
|
|
175
|
+
if (expDecimals.length > 1 && parseInt(expDecimals[1], 10) > 2) return '0.00';
|
|
176
|
+
let decimals = fpEuros(parseFloat('0.' + parts[1])).toString().substr(2, 2);
|
|
177
|
+
if (decimals.length === 1) decimals += '0';
|
|
178
|
+
return parts[0] + '.' + decimals;
|
|
179
|
+
}
|
|
180
|
+
return (opts && opts.currency)? (parts[0] + '.00') : parts[0];
|
|
181
181
|
}
|
package/tsconfig.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"allowUnusedLabels": false,
|
|
4
|
-
"emitDecoratorMetadata": true,
|
|
5
|
-
"experimentalDecorators": true,
|
|
6
|
-
"lib": ["es2015", "dom"],
|
|
7
|
-
"module": "commonjs",
|
|
8
|
-
"moduleResolution": "node",
|
|
9
|
-
"noImplicitAny": true,
|
|
10
|
-
"noImplicitReturns": true,
|
|
11
|
-
"noUnusedLocals": true,
|
|
12
|
-
"noUnusedParameters": true,
|
|
13
|
-
"removeComments": true,
|
|
14
|
-
"sourceMap": false,
|
|
15
|
-
"skipDefaultLibCheck": true,
|
|
16
|
-
"skipLibCheck": true,
|
|
17
|
-
"suppressImplicitAnyIndexErrors": true,
|
|
18
|
-
"target": "es2021",
|
|
19
|
-
"typeRoots": [
|
|
20
|
-
"node_modules/@types"
|
|
21
|
-
]
|
|
22
|
-
},
|
|
23
|
-
"exclude": [
|
|
24
|
-
"node_modules",
|
|
25
|
-
"dist",
|
|
26
|
-
"**/*.spec.ts",
|
|
27
|
-
"example",
|
|
28
|
-
"tests"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowUnusedLabels": false,
|
|
4
|
+
"emitDecoratorMetadata": true,
|
|
5
|
+
"experimentalDecorators": true,
|
|
6
|
+
"lib": ["es2015", "dom"],
|
|
7
|
+
"module": "commonjs",
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"noImplicitAny": true,
|
|
10
|
+
"noImplicitReturns": true,
|
|
11
|
+
"noUnusedLocals": true,
|
|
12
|
+
"noUnusedParameters": true,
|
|
13
|
+
"removeComments": true,
|
|
14
|
+
"sourceMap": false,
|
|
15
|
+
"skipDefaultLibCheck": true,
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"suppressImplicitAnyIndexErrors": true,
|
|
18
|
+
"target": "es2021",
|
|
19
|
+
"typeRoots": [
|
|
20
|
+
"node_modules/@types"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"exclude": [
|
|
24
|
+
"node_modules",
|
|
25
|
+
"dist",
|
|
26
|
+
"**/*.spec.ts",
|
|
27
|
+
"example",
|
|
28
|
+
"tests"
|
|
29
|
+
]
|
|
30
|
+
}
|