@oino-ts/types 0.0.11 → 0.0.13
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/README.md +6 -6
- package/dist/cjs/OINOBenchmark.js +37 -2
- package/dist/cjs/OINOHtmlTemplate.js +120 -0
- package/dist/cjs/OINOResult.js +78 -5
- package/dist/cjs/index.js +4 -1
- package/dist/esm/OINOBenchmark.js +37 -2
- package/dist/esm/OINOHtmlTemplate.js +116 -0
- package/dist/esm/OINOResult.js +76 -4
- package/dist/esm/index.js +2 -1
- package/dist/types/OINOBenchmark.d.ts +13 -1
- package/dist/types/OINOHtmlTemplate.d.ts +49 -0
- package/dist/types/OINOResult.d.ts +44 -8
- package/dist/types/index.d.ts +2 -1
- package/package.json +1 -1
- package/src/OINOBenchmark.ts +39 -2
- package/src/OINOHtmlTemplate.ts +124 -0
- package/src/OINOResult.ts +91 -8
- package/src/index.ts +2 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
### Register database and logger
|
|
25
|
-
Register your database implementation and logger (see [`OINOConsoleLog`](https://pragmatta.github.io/oino-ts/classes/
|
|
25
|
+
Register your database implementation and logger (see [`OINOConsoleLog`](https://pragmatta.github.io/oino-ts/classes/types_src.OINOConsoleLog.html) how to implement your own)
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
OINOLog.setLogger(new OINOConsoleLog())
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
### Create a database
|
|
33
|
-
Creating a database connection [`OINODb`](https://pragmatta.github.io/oino-ts/classes/
|
|
33
|
+
Creating a database connection [`OINODb`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODb.html) is done by passing [`OINODbParams`](https://pragmatta.github.io/oino-ts/types/db_src.OINODbParams.html) to the factory method. For [`OINODbBunSqlite`](https://pragmatta.github.io/oino-ts/classes/db_bunsqlite_src.OINODbBunSqlite.html) that means a file url for the database file, for others network host, port, credentials etc.
|
|
34
34
|
```
|
|
35
35
|
const db:OINODb = await OINOFactory.createDb( { type: "OINODbBunSqlite", url: "file://../localDb/northwind.sqlite" } )
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
### Create an API
|
|
39
|
-
From a database you can create an [`OINOApi`](https://pragmatta.github.io/oino-ts/classes/
|
|
39
|
+
From a database you can create an [`OINOApi`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbApi.html) by passing [`OINOApiParams`](https://pragmatta.github.io/oino-ts/types/db_src.OINODbApiParams.html) with table name and preferences to the factory method.
|
|
40
40
|
```
|
|
41
41
|
const api_employees:OINOApi = await OINOFactory.createApi(db, { tableName: "Employees", excludeFields:["BirthDate"] })
|
|
42
42
|
```
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
### Write results back to HTTP Response
|
|
52
|
-
The results for a GET request will contain [`OINOModelSet`](https://pragmatta.github.io/oino-ts/classes/
|
|
52
|
+
The results for a GET request will contain [`OINOModelSet`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbModelSet.html) data that can be written out as JSON or CSV as needed. For other requests result is just success or error with messages.
|
|
53
53
|
```
|
|
54
54
|
return new Response(result.modelset.writeString(OINOContentType.json))
|
|
55
55
|
```
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
To support tables with multipart primary keys OINO generates a composite key `_OINOID_` that is included in the result and can be used as the REST ID. For example in the example above table `OrderDetails` has two primary keys `OrderID` and `ProductID` making the `_OINOID_` of form `11077:99`.
|
|
135
135
|
|
|
136
136
|
## Power Of SQL
|
|
137
|
-
Since OINO controls the SQL, WHERE-conditions can be defined with [`OINOSqlFilter`](https://pragmatta.github.io/oino-ts/classes/
|
|
137
|
+
Since OINO controls the SQL, WHERE-conditions can be defined with [`OINOSqlFilter`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbSqlFilter.html) and order with [`OINOSqlOrder`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbSqlOrder.html) that are passed as HTTP request parameters. No more API development where you make unique API endpoints for each filter that fetch all data with original API and filter in backend code. Every API can be filtered when and as needed without unnessecary data tranfer and utilizing SQL indexing when available.
|
|
138
138
|
|
|
139
139
|
## Swagger Support
|
|
140
140
|
Swagger is great as long as the definitions are updated and with OINO you can automatically get a Swagger definition including a data model schema.
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
OINO is developped Typescript first but compiles to standard CommonJS and the NPM packages should work on either ESM / CommonJS. Checkout sample apps `readmeApp` (ESM) and `nodeApp` (CommonJS).
|
|
150
150
|
|
|
151
151
|
## HTMX support
|
|
152
|
-
OINO is [htmx.org](https://htmx.org) friendly, allowing easy translation of [`OINODataRow`](https://pragmatta.github.io/oino-ts/types/
|
|
152
|
+
OINO is [htmx.org](https://htmx.org) friendly, allowing easy translation of [`OINODataRow`](https://pragmatta.github.io/oino-ts/types/db_src.OINODataRow.html) to HTML output using templates (cf. the [htmx sample app](https://github.com/pragmatta/oino-ts/tree/main/samples/htmxApp)).
|
|
153
153
|
|
|
154
154
|
### Hashids
|
|
155
155
|
Autoinc numeric id's are very pragmatic and fit well with OINO (e.g. using a form without primary key fields to insert new rows with database assigned ids). However it's not always sensible to share information about the sequence. Hashids solve this by masking the original values by encrypting the ids using AES-128 and some randomness. Length of the hashid can be chosen from 12-32 characters where longer ids provide more security. However this should not be considereded a cryptographic solution for keeping ids secret but rather making it infeasible to iterate all ids.
|
|
@@ -52,15 +52,50 @@ class OINOBenchmark {
|
|
|
52
52
|
* Complete benchmark timing
|
|
53
53
|
*
|
|
54
54
|
* @param name of the benchmark
|
|
55
|
+
* @param category optional subcategory of the benchmark
|
|
55
56
|
*/
|
|
56
|
-
static end(name) {
|
|
57
|
+
static end(name, category) {
|
|
57
58
|
let result = 0;
|
|
58
59
|
if (this._benchmarkEnabled[name]) {
|
|
60
|
+
const duration = performance.now() - this._benchmarkStart[name];
|
|
59
61
|
this._benchmarkCount[name] += 1;
|
|
60
|
-
this._benchmarkData[name] +=
|
|
62
|
+
this._benchmarkData[name] += duration;
|
|
63
|
+
if (category) {
|
|
64
|
+
const category_name = name + "." + category;
|
|
65
|
+
if (this._benchmarkCount[category_name] == undefined) {
|
|
66
|
+
this._benchmarkCount[category_name] = 0;
|
|
67
|
+
this._benchmarkData[category_name] = 0;
|
|
68
|
+
}
|
|
69
|
+
this._benchmarkCount[category_name] += 1;
|
|
70
|
+
this._benchmarkData[category_name] += duration;
|
|
71
|
+
}
|
|
61
72
|
result = this._benchmarkData[name] / this._benchmarkCount[name];
|
|
62
73
|
}
|
|
63
74
|
return result;
|
|
64
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Get given benchmark data.
|
|
78
|
+
*
|
|
79
|
+
* @param name of the benchmark
|
|
80
|
+
*/
|
|
81
|
+
static get(name) {
|
|
82
|
+
if (this._benchmarkEnabled[name]) {
|
|
83
|
+
return this._benchmarkData[name] / this._benchmarkCount[name];
|
|
84
|
+
}
|
|
85
|
+
return -1;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get all benchmark data.
|
|
89
|
+
*
|
|
90
|
+
*/
|
|
91
|
+
static getAll() {
|
|
92
|
+
let result = {};
|
|
93
|
+
for (const name in this._benchmarkData) {
|
|
94
|
+
if (this._benchmarkCount[name] > 0) {
|
|
95
|
+
result[name] = this._benchmarkData[name] / this._benchmarkCount[name];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
65
100
|
}
|
|
66
101
|
exports.OINOBenchmark = OINOBenchmark;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OINOHtmlTemplate = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
/**
|
|
6
|
+
* Class for rendering HTML from data.
|
|
7
|
+
*/
|
|
8
|
+
class OINOHtmlTemplate {
|
|
9
|
+
/** HTML template string */
|
|
10
|
+
template;
|
|
11
|
+
/** Cache modified value for template */
|
|
12
|
+
modified;
|
|
13
|
+
/** Cache expiration value for template */
|
|
14
|
+
expires;
|
|
15
|
+
/**
|
|
16
|
+
* Creates HTML Response from a key-value-pair.
|
|
17
|
+
*
|
|
18
|
+
* @param template template string
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
constructor(template) {
|
|
22
|
+
this.template = template;
|
|
23
|
+
this.modified = 0;
|
|
24
|
+
this.expires = 0;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* @returns whether template is empty
|
|
28
|
+
*/
|
|
29
|
+
isEmpty() {
|
|
30
|
+
return this.template == "";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates HTML Response from a key-value-pair.
|
|
34
|
+
*
|
|
35
|
+
* @param key key
|
|
36
|
+
* @param value value
|
|
37
|
+
*
|
|
38
|
+
*/
|
|
39
|
+
renderFromKeyValue(key, value) {
|
|
40
|
+
const html = this.template.replaceAll('###' + key + '###', _1.OINOStr.encode(value, _1.OINOContentType.html));
|
|
41
|
+
const result = new _1.OINOHttpResult(html);
|
|
42
|
+
if (this.expires >= 1) {
|
|
43
|
+
result.expires = Math.round(this.expires);
|
|
44
|
+
}
|
|
45
|
+
if (this.modified >= 1) {
|
|
46
|
+
result.lastModified = this.modified;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates HTML Response from object properties.
|
|
52
|
+
*
|
|
53
|
+
* @param object object
|
|
54
|
+
*
|
|
55
|
+
*/
|
|
56
|
+
renderFromObject(object) {
|
|
57
|
+
let html = this.template;
|
|
58
|
+
if (object) {
|
|
59
|
+
for (let key in object) {
|
|
60
|
+
const value = object[key];
|
|
61
|
+
if (value) {
|
|
62
|
+
html = html.replaceAll('###' + key + '###', _1.OINOStr.encode(value.toString(), _1.OINOContentType.html));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
html = html.replace(/###[^#]*###/g, "");
|
|
67
|
+
const result = new _1.OINOHttpResult(html);
|
|
68
|
+
if (this.expires >= 1) {
|
|
69
|
+
result.expires = Math.round(this.expires);
|
|
70
|
+
}
|
|
71
|
+
if (this.modified >= 1) {
|
|
72
|
+
result.lastModified = this.modified;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Creates HTML Response from API result.
|
|
78
|
+
*
|
|
79
|
+
* @param result OINOResult-object
|
|
80
|
+
* @param includeErrorMessages include debug messages in result
|
|
81
|
+
* @param includeWarningMessages include debug messages in result
|
|
82
|
+
* @param includeInfoMessages include debug messages in result
|
|
83
|
+
* @param includeDebugMessages include debug messages in result
|
|
84
|
+
*
|
|
85
|
+
*/
|
|
86
|
+
renderFromResult(result, includeErrorMessages = false, includeWarningMessages = false, includeInfoMessages = false, includeDebugMessages = false) {
|
|
87
|
+
let html = this.template;
|
|
88
|
+
html = html.replaceAll('###statusCode###', _1.OINOStr.encode(result.statusCode.toString(), _1.OINOContentType.html));
|
|
89
|
+
html = html.replaceAll('###statusMessage###', _1.OINOStr.encode(result.statusMessage.toString(), _1.OINOContentType.html));
|
|
90
|
+
let messages = "";
|
|
91
|
+
for (let i = 0; i < result.messages.length; i++) {
|
|
92
|
+
if (includeErrorMessages && result.messages[i].startsWith(_1.OINO_ERROR_PREFIX)) {
|
|
93
|
+
messages += "<li>" + _1.OINOStr.encode(result.messages[i], _1.OINOContentType.html) + "</li>";
|
|
94
|
+
}
|
|
95
|
+
if (includeWarningMessages && result.messages[i].startsWith(_1.OINO_WARNING_PREFIX)) {
|
|
96
|
+
messages += "<li>" + _1.OINOStr.encode(result.messages[i], _1.OINOContentType.html) + "</li>";
|
|
97
|
+
}
|
|
98
|
+
if (includeInfoMessages && result.messages[i].startsWith(_1.OINO_INFO_PREFIX)) {
|
|
99
|
+
messages += "<li>" + _1.OINOStr.encode(result.messages[i], _1.OINOContentType.html) + "</li>";
|
|
100
|
+
}
|
|
101
|
+
if (includeDebugMessages && result.messages[i].startsWith(_1.OINO_DEBUG_PREFIX)) {
|
|
102
|
+
messages += "<li>" + _1.OINOStr.encode(result.messages[i], _1.OINOContentType.html) + "</li>";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (messages) {
|
|
106
|
+
html = html.replaceAll('###messages###', "<ul>" + messages + "</ul>");
|
|
107
|
+
}
|
|
108
|
+
html = html.replace(/###[^#]*###/g, "");
|
|
109
|
+
const http_result = new _1.OINOHttpResult(html);
|
|
110
|
+
if (this.expires >= 1) {
|
|
111
|
+
http_result.expires = Math.round(this.expires);
|
|
112
|
+
}
|
|
113
|
+
if (this.modified >= 1) {
|
|
114
|
+
http_result.lastModified = this.modified;
|
|
115
|
+
}
|
|
116
|
+
return http_result;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.OINOHtmlTemplate = OINOHtmlTemplate;
|
|
120
|
+
;
|
package/dist/cjs/OINOResult.js
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.OINOResult = void 0;
|
|
8
|
+
exports.OINOHttpResult = exports.OINOResult = void 0;
|
|
9
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
10
|
const _1 = require(".");
|
|
10
11
|
/**
|
|
11
12
|
* OINO API request result object with returned data and/or http status code/message and
|
|
@@ -31,6 +32,17 @@ class OINOResult {
|
|
|
31
32
|
this.statusMessage = "OK";
|
|
32
33
|
this.messages = [];
|
|
33
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Copy values from different result.
|
|
37
|
+
*
|
|
38
|
+
* @param result source value
|
|
39
|
+
*/
|
|
40
|
+
copy(result) {
|
|
41
|
+
this.success = result.success;
|
|
42
|
+
this.statusCode = result.statusCode;
|
|
43
|
+
this.statusMessage = result.statusMessage;
|
|
44
|
+
this.messages = result.messages.slice();
|
|
45
|
+
}
|
|
34
46
|
/**
|
|
35
47
|
* Set HTTP OK status (does not reset messages).
|
|
36
48
|
*
|
|
@@ -41,7 +53,7 @@ class OINOResult {
|
|
|
41
53
|
this.statusMessage = "OK";
|
|
42
54
|
}
|
|
43
55
|
/**
|
|
44
|
-
* Set HTTP error status using given code and message.
|
|
56
|
+
* Set HTTP error status using given code and message. Returns self reference for chaining.
|
|
45
57
|
*
|
|
46
58
|
* @param statusCode HTTP status code
|
|
47
59
|
* @param statusMessage HTTP status message
|
|
@@ -60,9 +72,10 @@ class OINOResult {
|
|
|
60
72
|
else {
|
|
61
73
|
this.statusMessage = _1.OINO_ERROR_PREFIX + " (" + operation + "): " + statusMessage;
|
|
62
74
|
}
|
|
75
|
+
return this;
|
|
63
76
|
}
|
|
64
77
|
/**
|
|
65
|
-
* Add warning message.
|
|
78
|
+
* Add warning message. Returns self reference for chaining.
|
|
66
79
|
*
|
|
67
80
|
* @param message HTTP status message
|
|
68
81
|
* @param operation operation where warning occured
|
|
@@ -73,9 +86,10 @@ class OINOResult {
|
|
|
73
86
|
if (message) {
|
|
74
87
|
this.messages.push(_1.OINO_WARNING_PREFIX + " (" + operation + "): " + message);
|
|
75
88
|
}
|
|
89
|
+
return this;
|
|
76
90
|
}
|
|
77
91
|
/**
|
|
78
|
-
* Add info message.
|
|
92
|
+
* Add info message. Returns self reference for chaining.
|
|
79
93
|
*
|
|
80
94
|
* @param message HTTP status message
|
|
81
95
|
* @param operation operation where info occured
|
|
@@ -86,9 +100,10 @@ class OINOResult {
|
|
|
86
100
|
if (message) {
|
|
87
101
|
this.messages.push(_1.OINO_INFO_PREFIX + " (" + operation + "): " + message);
|
|
88
102
|
}
|
|
103
|
+
return this;
|
|
89
104
|
}
|
|
90
105
|
/**
|
|
91
|
-
* Add debug message.
|
|
106
|
+
* Add debug message. Returns self reference for chaining.
|
|
92
107
|
*
|
|
93
108
|
* @param message HTTP status message
|
|
94
109
|
* @param operation operation where debug occured
|
|
@@ -99,6 +114,7 @@ class OINOResult {
|
|
|
99
114
|
if (message) {
|
|
100
115
|
this.messages.push(_1.OINO_DEBUG_PREFIX + " (" + operation + "): " + message);
|
|
101
116
|
}
|
|
117
|
+
return this;
|
|
102
118
|
}
|
|
103
119
|
/**
|
|
104
120
|
* Copy given messages to HTTP headers.
|
|
@@ -134,3 +150,60 @@ class OINOResult {
|
|
|
134
150
|
}
|
|
135
151
|
}
|
|
136
152
|
exports.OINOResult = OINOResult;
|
|
153
|
+
/**
|
|
154
|
+
* Specialized result for HTTP responses.
|
|
155
|
+
*/
|
|
156
|
+
class OINOHttpResult extends OINOResult {
|
|
157
|
+
_etag;
|
|
158
|
+
/** HTTP body data */
|
|
159
|
+
body;
|
|
160
|
+
/** HTTP cache expiration value */
|
|
161
|
+
expires;
|
|
162
|
+
/** HTTP cache last-modified value */
|
|
163
|
+
lastModified;
|
|
164
|
+
/**
|
|
165
|
+
* Constructor for a `OINOHttpResult`
|
|
166
|
+
*
|
|
167
|
+
* @param body HTTP body
|
|
168
|
+
*
|
|
169
|
+
*/
|
|
170
|
+
constructor(body) {
|
|
171
|
+
super();
|
|
172
|
+
this.body = body;
|
|
173
|
+
this.expires = 0;
|
|
174
|
+
this.lastModified = 0;
|
|
175
|
+
this._etag = "";
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get the ETag value for the body opportunistically, i.e. don't calculate until requested and reuse value.
|
|
179
|
+
*
|
|
180
|
+
*/
|
|
181
|
+
getEtag() {
|
|
182
|
+
if (this._etag == "") {
|
|
183
|
+
const hash = (0, node_crypto_1.createHash)("sha256");
|
|
184
|
+
this._etag = hash.update(this.body).digest("hex");
|
|
185
|
+
}
|
|
186
|
+
return this._etag;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get a Response object from the result values.
|
|
190
|
+
*
|
|
191
|
+
* @param headers HTTP headers (overrides existing values)
|
|
192
|
+
*/
|
|
193
|
+
getResponse(headers) {
|
|
194
|
+
const result = new Response(this.body, { status: this.statusCode, statusText: this.statusMessage, headers: headers });
|
|
195
|
+
result.headers.set('Content-Length', this.body.length.toString());
|
|
196
|
+
if (this.lastModified > 0) {
|
|
197
|
+
result.headers.set('Last-Modified', new Date(this.lastModified).toUTCString());
|
|
198
|
+
}
|
|
199
|
+
if (this.expires >= 0) {
|
|
200
|
+
result.headers.set('Expires', Math.round(this.expires).toString());
|
|
201
|
+
if (this.expires == 0) {
|
|
202
|
+
result.headers.set('Pragma', 'no-cache');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
result.headers.set("ETag", this.getEtag());
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
exports.OINOHttpResult = OINOHttpResult;
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OINOContentType = exports.OINO_DEBUG_PREFIX = exports.OINO_INFO_PREFIX = exports.OINO_WARNING_PREFIX = exports.OINO_ERROR_PREFIX = exports.OINOStr = exports.OINOResult = exports.OINOConsoleLog = exports.OINOLogLevel = exports.OINOLog = exports.OINOBenchmark = void 0;
|
|
3
|
+
exports.OINOContentType = exports.OINO_DEBUG_PREFIX = exports.OINO_INFO_PREFIX = exports.OINO_WARNING_PREFIX = exports.OINO_ERROR_PREFIX = exports.OINOHtmlTemplate = exports.OINOStr = exports.OINOHttpResult = exports.OINOResult = exports.OINOConsoleLog = exports.OINOLogLevel = exports.OINOLog = exports.OINOBenchmark = void 0;
|
|
4
4
|
var OINOBenchmark_js_1 = require("./OINOBenchmark.js");
|
|
5
5
|
Object.defineProperty(exports, "OINOBenchmark", { enumerable: true, get: function () { return OINOBenchmark_js_1.OINOBenchmark; } });
|
|
6
6
|
var OINOLog_js_1 = require("./OINOLog.js");
|
|
@@ -9,8 +9,11 @@ Object.defineProperty(exports, "OINOLogLevel", { enumerable: true, get: function
|
|
|
9
9
|
Object.defineProperty(exports, "OINOConsoleLog", { enumerable: true, get: function () { return OINOLog_js_1.OINOConsoleLog; } });
|
|
10
10
|
var OINOResult_js_1 = require("./OINOResult.js");
|
|
11
11
|
Object.defineProperty(exports, "OINOResult", { enumerable: true, get: function () { return OINOResult_js_1.OINOResult; } });
|
|
12
|
+
Object.defineProperty(exports, "OINOHttpResult", { enumerable: true, get: function () { return OINOResult_js_1.OINOHttpResult; } });
|
|
12
13
|
var OINOStr_js_1 = require("./OINOStr.js");
|
|
13
14
|
Object.defineProperty(exports, "OINOStr", { enumerable: true, get: function () { return OINOStr_js_1.OINOStr; } });
|
|
15
|
+
var OINOHtmlTemplate_js_1 = require("./OINOHtmlTemplate.js");
|
|
16
|
+
Object.defineProperty(exports, "OINOHtmlTemplate", { enumerable: true, get: function () { return OINOHtmlTemplate_js_1.OINOHtmlTemplate; } });
|
|
14
17
|
/** OINO error message prefix */
|
|
15
18
|
exports.OINO_ERROR_PREFIX = "OINO ERROR";
|
|
16
19
|
/** OINO warning message prefix */
|
|
@@ -49,14 +49,49 @@ export class OINOBenchmark {
|
|
|
49
49
|
* Complete benchmark timing
|
|
50
50
|
*
|
|
51
51
|
* @param name of the benchmark
|
|
52
|
+
* @param category optional subcategory of the benchmark
|
|
52
53
|
*/
|
|
53
|
-
static end(name) {
|
|
54
|
+
static end(name, category) {
|
|
54
55
|
let result = 0;
|
|
55
56
|
if (this._benchmarkEnabled[name]) {
|
|
57
|
+
const duration = performance.now() - this._benchmarkStart[name];
|
|
56
58
|
this._benchmarkCount[name] += 1;
|
|
57
|
-
this._benchmarkData[name] +=
|
|
59
|
+
this._benchmarkData[name] += duration;
|
|
60
|
+
if (category) {
|
|
61
|
+
const category_name = name + "." + category;
|
|
62
|
+
if (this._benchmarkCount[category_name] == undefined) {
|
|
63
|
+
this._benchmarkCount[category_name] = 0;
|
|
64
|
+
this._benchmarkData[category_name] = 0;
|
|
65
|
+
}
|
|
66
|
+
this._benchmarkCount[category_name] += 1;
|
|
67
|
+
this._benchmarkData[category_name] += duration;
|
|
68
|
+
}
|
|
58
69
|
result = this._benchmarkData[name] / this._benchmarkCount[name];
|
|
59
70
|
}
|
|
60
71
|
return result;
|
|
61
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Get given benchmark data.
|
|
75
|
+
*
|
|
76
|
+
* @param name of the benchmark
|
|
77
|
+
*/
|
|
78
|
+
static get(name) {
|
|
79
|
+
if (this._benchmarkEnabled[name]) {
|
|
80
|
+
return this._benchmarkData[name] / this._benchmarkCount[name];
|
|
81
|
+
}
|
|
82
|
+
return -1;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get all benchmark data.
|
|
86
|
+
*
|
|
87
|
+
*/
|
|
88
|
+
static getAll() {
|
|
89
|
+
let result = {};
|
|
90
|
+
for (const name in this._benchmarkData) {
|
|
91
|
+
if (this._benchmarkCount[name] > 0) {
|
|
92
|
+
result[name] = this._benchmarkData[name] / this._benchmarkCount[name];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
62
97
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { OINOStr, OINOContentType, OINOHttpResult, OINO_ERROR_PREFIX, OINO_WARNING_PREFIX, OINO_INFO_PREFIX, OINO_DEBUG_PREFIX } from ".";
|
|
2
|
+
/**
|
|
3
|
+
* Class for rendering HTML from data.
|
|
4
|
+
*/
|
|
5
|
+
export class OINOHtmlTemplate {
|
|
6
|
+
/** HTML template string */
|
|
7
|
+
template;
|
|
8
|
+
/** Cache modified value for template */
|
|
9
|
+
modified;
|
|
10
|
+
/** Cache expiration value for template */
|
|
11
|
+
expires;
|
|
12
|
+
/**
|
|
13
|
+
* Creates HTML Response from a key-value-pair.
|
|
14
|
+
*
|
|
15
|
+
* @param template template string
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
constructor(template) {
|
|
19
|
+
this.template = template;
|
|
20
|
+
this.modified = 0;
|
|
21
|
+
this.expires = 0;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @returns whether template is empty
|
|
25
|
+
*/
|
|
26
|
+
isEmpty() {
|
|
27
|
+
return this.template == "";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates HTML Response from a key-value-pair.
|
|
31
|
+
*
|
|
32
|
+
* @param key key
|
|
33
|
+
* @param value value
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
renderFromKeyValue(key, value) {
|
|
37
|
+
const html = this.template.replaceAll('###' + key + '###', OINOStr.encode(value, OINOContentType.html));
|
|
38
|
+
const result = new OINOHttpResult(html);
|
|
39
|
+
if (this.expires >= 1) {
|
|
40
|
+
result.expires = Math.round(this.expires);
|
|
41
|
+
}
|
|
42
|
+
if (this.modified >= 1) {
|
|
43
|
+
result.lastModified = this.modified;
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates HTML Response from object properties.
|
|
49
|
+
*
|
|
50
|
+
* @param object object
|
|
51
|
+
*
|
|
52
|
+
*/
|
|
53
|
+
renderFromObject(object) {
|
|
54
|
+
let html = this.template;
|
|
55
|
+
if (object) {
|
|
56
|
+
for (let key in object) {
|
|
57
|
+
const value = object[key];
|
|
58
|
+
if (value) {
|
|
59
|
+
html = html.replaceAll('###' + key + '###', OINOStr.encode(value.toString(), OINOContentType.html));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
html = html.replace(/###[^#]*###/g, "");
|
|
64
|
+
const result = new OINOHttpResult(html);
|
|
65
|
+
if (this.expires >= 1) {
|
|
66
|
+
result.expires = Math.round(this.expires);
|
|
67
|
+
}
|
|
68
|
+
if (this.modified >= 1) {
|
|
69
|
+
result.lastModified = this.modified;
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates HTML Response from API result.
|
|
75
|
+
*
|
|
76
|
+
* @param result OINOResult-object
|
|
77
|
+
* @param includeErrorMessages include debug messages in result
|
|
78
|
+
* @param includeWarningMessages include debug messages in result
|
|
79
|
+
* @param includeInfoMessages include debug messages in result
|
|
80
|
+
* @param includeDebugMessages include debug messages in result
|
|
81
|
+
*
|
|
82
|
+
*/
|
|
83
|
+
renderFromResult(result, includeErrorMessages = false, includeWarningMessages = false, includeInfoMessages = false, includeDebugMessages = false) {
|
|
84
|
+
let html = this.template;
|
|
85
|
+
html = html.replaceAll('###statusCode###', OINOStr.encode(result.statusCode.toString(), OINOContentType.html));
|
|
86
|
+
html = html.replaceAll('###statusMessage###', OINOStr.encode(result.statusMessage.toString(), OINOContentType.html));
|
|
87
|
+
let messages = "";
|
|
88
|
+
for (let i = 0; i < result.messages.length; i++) {
|
|
89
|
+
if (includeErrorMessages && result.messages[i].startsWith(OINO_ERROR_PREFIX)) {
|
|
90
|
+
messages += "<li>" + OINOStr.encode(result.messages[i], OINOContentType.html) + "</li>";
|
|
91
|
+
}
|
|
92
|
+
if (includeWarningMessages && result.messages[i].startsWith(OINO_WARNING_PREFIX)) {
|
|
93
|
+
messages += "<li>" + OINOStr.encode(result.messages[i], OINOContentType.html) + "</li>";
|
|
94
|
+
}
|
|
95
|
+
if (includeInfoMessages && result.messages[i].startsWith(OINO_INFO_PREFIX)) {
|
|
96
|
+
messages += "<li>" + OINOStr.encode(result.messages[i], OINOContentType.html) + "</li>";
|
|
97
|
+
}
|
|
98
|
+
if (includeDebugMessages && result.messages[i].startsWith(OINO_DEBUG_PREFIX)) {
|
|
99
|
+
messages += "<li>" + OINOStr.encode(result.messages[i], OINOContentType.html) + "</li>";
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (messages) {
|
|
103
|
+
html = html.replaceAll('###messages###', "<ul>" + messages + "</ul>");
|
|
104
|
+
}
|
|
105
|
+
html = html.replace(/###[^#]*###/g, "");
|
|
106
|
+
const http_result = new OINOHttpResult(html);
|
|
107
|
+
if (this.expires >= 1) {
|
|
108
|
+
http_result.expires = Math.round(this.expires);
|
|
109
|
+
}
|
|
110
|
+
if (this.modified >= 1) {
|
|
111
|
+
http_result.lastModified = this.modified;
|
|
112
|
+
}
|
|
113
|
+
return http_result;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
;
|
package/dist/esm/OINOResult.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
6
7
|
import { OINO_DEBUG_PREFIX, OINO_ERROR_PREFIX, OINO_INFO_PREFIX, OINO_WARNING_PREFIX } from ".";
|
|
7
8
|
/**
|
|
8
9
|
* OINO API request result object with returned data and/or http status code/message and
|
|
@@ -28,6 +29,17 @@ export class OINOResult {
|
|
|
28
29
|
this.statusMessage = "OK";
|
|
29
30
|
this.messages = [];
|
|
30
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Copy values from different result.
|
|
34
|
+
*
|
|
35
|
+
* @param result source value
|
|
36
|
+
*/
|
|
37
|
+
copy(result) {
|
|
38
|
+
this.success = result.success;
|
|
39
|
+
this.statusCode = result.statusCode;
|
|
40
|
+
this.statusMessage = result.statusMessage;
|
|
41
|
+
this.messages = result.messages.slice();
|
|
42
|
+
}
|
|
31
43
|
/**
|
|
32
44
|
* Set HTTP OK status (does not reset messages).
|
|
33
45
|
*
|
|
@@ -38,7 +50,7 @@ export class OINOResult {
|
|
|
38
50
|
this.statusMessage = "OK";
|
|
39
51
|
}
|
|
40
52
|
/**
|
|
41
|
-
* Set HTTP error status using given code and message.
|
|
53
|
+
* Set HTTP error status using given code and message. Returns self reference for chaining.
|
|
42
54
|
*
|
|
43
55
|
* @param statusCode HTTP status code
|
|
44
56
|
* @param statusMessage HTTP status message
|
|
@@ -57,9 +69,10 @@ export class OINOResult {
|
|
|
57
69
|
else {
|
|
58
70
|
this.statusMessage = OINO_ERROR_PREFIX + " (" + operation + "): " + statusMessage;
|
|
59
71
|
}
|
|
72
|
+
return this;
|
|
60
73
|
}
|
|
61
74
|
/**
|
|
62
|
-
* Add warning message.
|
|
75
|
+
* Add warning message. Returns self reference for chaining.
|
|
63
76
|
*
|
|
64
77
|
* @param message HTTP status message
|
|
65
78
|
* @param operation operation where warning occured
|
|
@@ -70,9 +83,10 @@ export class OINOResult {
|
|
|
70
83
|
if (message) {
|
|
71
84
|
this.messages.push(OINO_WARNING_PREFIX + " (" + operation + "): " + message);
|
|
72
85
|
}
|
|
86
|
+
return this;
|
|
73
87
|
}
|
|
74
88
|
/**
|
|
75
|
-
* Add info message.
|
|
89
|
+
* Add info message. Returns self reference for chaining.
|
|
76
90
|
*
|
|
77
91
|
* @param message HTTP status message
|
|
78
92
|
* @param operation operation where info occured
|
|
@@ -83,9 +97,10 @@ export class OINOResult {
|
|
|
83
97
|
if (message) {
|
|
84
98
|
this.messages.push(OINO_INFO_PREFIX + " (" + operation + "): " + message);
|
|
85
99
|
}
|
|
100
|
+
return this;
|
|
86
101
|
}
|
|
87
102
|
/**
|
|
88
|
-
* Add debug message.
|
|
103
|
+
* Add debug message. Returns self reference for chaining.
|
|
89
104
|
*
|
|
90
105
|
* @param message HTTP status message
|
|
91
106
|
* @param operation operation where debug occured
|
|
@@ -96,6 +111,7 @@ export class OINOResult {
|
|
|
96
111
|
if (message) {
|
|
97
112
|
this.messages.push(OINO_DEBUG_PREFIX + " (" + operation + "): " + message);
|
|
98
113
|
}
|
|
114
|
+
return this;
|
|
99
115
|
}
|
|
100
116
|
/**
|
|
101
117
|
* Copy given messages to HTTP headers.
|
|
@@ -130,3 +146,59 @@ export class OINOResult {
|
|
|
130
146
|
}
|
|
131
147
|
}
|
|
132
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Specialized result for HTTP responses.
|
|
151
|
+
*/
|
|
152
|
+
export class OINOHttpResult extends OINOResult {
|
|
153
|
+
_etag;
|
|
154
|
+
/** HTTP body data */
|
|
155
|
+
body;
|
|
156
|
+
/** HTTP cache expiration value */
|
|
157
|
+
expires;
|
|
158
|
+
/** HTTP cache last-modified value */
|
|
159
|
+
lastModified;
|
|
160
|
+
/**
|
|
161
|
+
* Constructor for a `OINOHttpResult`
|
|
162
|
+
*
|
|
163
|
+
* @param body HTTP body
|
|
164
|
+
*
|
|
165
|
+
*/
|
|
166
|
+
constructor(body) {
|
|
167
|
+
super();
|
|
168
|
+
this.body = body;
|
|
169
|
+
this.expires = 0;
|
|
170
|
+
this.lastModified = 0;
|
|
171
|
+
this._etag = "";
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get the ETag value for the body opportunistically, i.e. don't calculate until requested and reuse value.
|
|
175
|
+
*
|
|
176
|
+
*/
|
|
177
|
+
getEtag() {
|
|
178
|
+
if (this._etag == "") {
|
|
179
|
+
const hash = createHash("sha256");
|
|
180
|
+
this._etag = hash.update(this.body).digest("hex");
|
|
181
|
+
}
|
|
182
|
+
return this._etag;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get a Response object from the result values.
|
|
186
|
+
*
|
|
187
|
+
* @param headers HTTP headers (overrides existing values)
|
|
188
|
+
*/
|
|
189
|
+
getResponse(headers) {
|
|
190
|
+
const result = new Response(this.body, { status: this.statusCode, statusText: this.statusMessage, headers: headers });
|
|
191
|
+
result.headers.set('Content-Length', this.body.length.toString());
|
|
192
|
+
if (this.lastModified > 0) {
|
|
193
|
+
result.headers.set('Last-Modified', new Date(this.lastModified).toUTCString());
|
|
194
|
+
}
|
|
195
|
+
if (this.expires >= 0) {
|
|
196
|
+
result.headers.set('Expires', Math.round(this.expires).toString());
|
|
197
|
+
if (this.expires == 0) {
|
|
198
|
+
result.headers.set('Pragma', 'no-cache');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
result.headers.set("ETag", this.getEtag());
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { OINOBenchmark } from "./OINOBenchmark.js";
|
|
2
2
|
export { OINOLog, OINOLogLevel, OINOConsoleLog } from "./OINOLog.js";
|
|
3
|
-
export { OINOResult } from "./OINOResult.js";
|
|
3
|
+
export { OINOResult, OINOHttpResult } from "./OINOResult.js";
|
|
4
4
|
export { OINOStr } from "./OINOStr.js";
|
|
5
|
+
export { OINOHtmlTemplate } from "./OINOHtmlTemplate.js";
|
|
5
6
|
/** OINO error message prefix */
|
|
6
7
|
export const OINO_ERROR_PREFIX = "OINO ERROR";
|
|
7
8
|
/** OINO warning message prefix */
|
|
@@ -28,6 +28,18 @@ export declare class OINOBenchmark {
|
|
|
28
28
|
* Complete benchmark timing
|
|
29
29
|
*
|
|
30
30
|
* @param name of the benchmark
|
|
31
|
+
* @param category optional subcategory of the benchmark
|
|
31
32
|
*/
|
|
32
|
-
static end(name: string): number;
|
|
33
|
+
static end(name: string, category?: string): number;
|
|
34
|
+
/**
|
|
35
|
+
* Get given benchmark data.
|
|
36
|
+
*
|
|
37
|
+
* @param name of the benchmark
|
|
38
|
+
*/
|
|
39
|
+
static get(name: string): number;
|
|
40
|
+
/**
|
|
41
|
+
* Get all benchmark data.
|
|
42
|
+
*
|
|
43
|
+
*/
|
|
44
|
+
static getAll(): number;
|
|
33
45
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { OINOResult, OINOHttpResult } from ".";
|
|
2
|
+
/**
|
|
3
|
+
* Class for rendering HTML from data.
|
|
4
|
+
*/
|
|
5
|
+
export declare class OINOHtmlTemplate {
|
|
6
|
+
/** HTML template string */
|
|
7
|
+
template: string;
|
|
8
|
+
/** Cache modified value for template */
|
|
9
|
+
modified: number;
|
|
10
|
+
/** Cache expiration value for template */
|
|
11
|
+
expires: number;
|
|
12
|
+
/**
|
|
13
|
+
* Creates HTML Response from a key-value-pair.
|
|
14
|
+
*
|
|
15
|
+
* @param template template string
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
constructor(template: string);
|
|
19
|
+
/**
|
|
20
|
+
* @returns whether template is empty
|
|
21
|
+
*/
|
|
22
|
+
isEmpty(): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Creates HTML Response from a key-value-pair.
|
|
25
|
+
*
|
|
26
|
+
* @param key key
|
|
27
|
+
* @param value value
|
|
28
|
+
*
|
|
29
|
+
*/
|
|
30
|
+
renderFromKeyValue(key: string, value: string): OINOHttpResult;
|
|
31
|
+
/**
|
|
32
|
+
* Creates HTML Response from object properties.
|
|
33
|
+
*
|
|
34
|
+
* @param object object
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
renderFromObject(object: any): OINOHttpResult;
|
|
38
|
+
/**
|
|
39
|
+
* Creates HTML Response from API result.
|
|
40
|
+
*
|
|
41
|
+
* @param result OINOResult-object
|
|
42
|
+
* @param includeErrorMessages include debug messages in result
|
|
43
|
+
* @param includeWarningMessages include debug messages in result
|
|
44
|
+
* @param includeInfoMessages include debug messages in result
|
|
45
|
+
* @param includeDebugMessages include debug messages in result
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
renderFromResult(result: OINOResult, includeErrorMessages?: boolean, includeWarningMessages?: boolean, includeInfoMessages?: boolean, includeDebugMessages?: boolean): OINOHttpResult;
|
|
49
|
+
}
|
|
@@ -17,44 +17,50 @@ export declare class OINOResult {
|
|
|
17
17
|
*
|
|
18
18
|
*/
|
|
19
19
|
constructor();
|
|
20
|
+
/**
|
|
21
|
+
* Copy values from different result.
|
|
22
|
+
*
|
|
23
|
+
* @param result source value
|
|
24
|
+
*/
|
|
25
|
+
copy(result: OINOResult): void;
|
|
20
26
|
/**
|
|
21
27
|
* Set HTTP OK status (does not reset messages).
|
|
22
28
|
*
|
|
23
29
|
*/
|
|
24
30
|
setOk(): void;
|
|
25
31
|
/**
|
|
26
|
-
* Set HTTP error status using given code and message.
|
|
32
|
+
* Set HTTP error status using given code and message. Returns self reference for chaining.
|
|
27
33
|
*
|
|
28
34
|
* @param statusCode HTTP status code
|
|
29
35
|
* @param statusMessage HTTP status message
|
|
30
36
|
* @param operation operation where error occured
|
|
31
37
|
*
|
|
32
38
|
*/
|
|
33
|
-
setError(statusCode: number, statusMessage: string, operation: string):
|
|
39
|
+
setError(statusCode: number, statusMessage: string, operation: string): OINOResult;
|
|
34
40
|
/**
|
|
35
|
-
* Add warning message.
|
|
41
|
+
* Add warning message. Returns self reference for chaining.
|
|
36
42
|
*
|
|
37
43
|
* @param message HTTP status message
|
|
38
44
|
* @param operation operation where warning occured
|
|
39
45
|
*
|
|
40
46
|
*/
|
|
41
|
-
addWarning(message: string, operation: string):
|
|
47
|
+
addWarning(message: string, operation: string): OINOResult;
|
|
42
48
|
/**
|
|
43
|
-
* Add info message.
|
|
49
|
+
* Add info message. Returns self reference for chaining.
|
|
44
50
|
*
|
|
45
51
|
* @param message HTTP status message
|
|
46
52
|
* @param operation operation where info occured
|
|
47
53
|
*
|
|
48
54
|
*/
|
|
49
|
-
addInfo(message: string, operation: string):
|
|
55
|
+
addInfo(message: string, operation: string): OINOResult;
|
|
50
56
|
/**
|
|
51
|
-
* Add debug message.
|
|
57
|
+
* Add debug message. Returns self reference for chaining.
|
|
52
58
|
*
|
|
53
59
|
* @param message HTTP status message
|
|
54
60
|
* @param operation operation where debug occured
|
|
55
61
|
*
|
|
56
62
|
*/
|
|
57
|
-
addDebug(message: string, operation: string):
|
|
63
|
+
addDebug(message: string, operation: string): OINOResult;
|
|
58
64
|
/**
|
|
59
65
|
* Copy given messages to HTTP headers.
|
|
60
66
|
*
|
|
@@ -67,3 +73,33 @@ export declare class OINOResult {
|
|
|
67
73
|
*/
|
|
68
74
|
copyMessagesToHeaders(headers: Headers, copyErrors?: boolean, copyWarnings?: boolean, copyInfos?: boolean, copyDebug?: boolean): void;
|
|
69
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Specialized result for HTTP responses.
|
|
78
|
+
*/
|
|
79
|
+
export declare class OINOHttpResult extends OINOResult {
|
|
80
|
+
private _etag;
|
|
81
|
+
/** HTTP body data */
|
|
82
|
+
readonly body: string;
|
|
83
|
+
/** HTTP cache expiration value */
|
|
84
|
+
expires: number;
|
|
85
|
+
/** HTTP cache last-modified value */
|
|
86
|
+
lastModified: number;
|
|
87
|
+
/**
|
|
88
|
+
* Constructor for a `OINOHttpResult`
|
|
89
|
+
*
|
|
90
|
+
* @param body HTTP body
|
|
91
|
+
*
|
|
92
|
+
*/
|
|
93
|
+
constructor(body: string);
|
|
94
|
+
/**
|
|
95
|
+
* Get the ETag value for the body opportunistically, i.e. don't calculate until requested and reuse value.
|
|
96
|
+
*
|
|
97
|
+
*/
|
|
98
|
+
getEtag(): string;
|
|
99
|
+
/**
|
|
100
|
+
* Get a Response object from the result values.
|
|
101
|
+
*
|
|
102
|
+
* @param headers HTTP headers (overrides existing values)
|
|
103
|
+
*/
|
|
104
|
+
getResponse(headers?: Record<string, string>): Response;
|
|
105
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { OINOBenchmark } from "./OINOBenchmark.js";
|
|
2
2
|
export { OINOLog, OINOLogLevel, OINOConsoleLog } from "./OINOLog.js";
|
|
3
|
-
export { OINOResult } from "./OINOResult.js";
|
|
3
|
+
export { OINOResult, OINOHttpResult } from "./OINOResult.js";
|
|
4
4
|
export { OINOStr } from "./OINOStr.js";
|
|
5
|
+
export { OINOHtmlTemplate } from "./OINOHtmlTemplate.js";
|
|
5
6
|
/** OINO error message prefix */
|
|
6
7
|
export declare const OINO_ERROR_PREFIX = "OINO ERROR";
|
|
7
8
|
/** OINO warning message prefix */
|
package/package.json
CHANGED
package/src/OINOBenchmark.ts
CHANGED
|
@@ -55,14 +55,51 @@ export class OINOBenchmark {
|
|
|
55
55
|
* Complete benchmark timing
|
|
56
56
|
*
|
|
57
57
|
* @param name of the benchmark
|
|
58
|
+
* @param category optional subcategory of the benchmark
|
|
58
59
|
*/
|
|
59
|
-
static end(name:string):number {
|
|
60
|
+
static end(name:string, category?:string):number {
|
|
60
61
|
let result:number = 0
|
|
61
62
|
if (this._benchmarkEnabled[name]) {
|
|
63
|
+
const duration = performance.now() - this._benchmarkStart[name]
|
|
62
64
|
this._benchmarkCount[name] += 1
|
|
63
|
-
this._benchmarkData[name] +=
|
|
65
|
+
this._benchmarkData[name] += duration
|
|
66
|
+
if (category) {
|
|
67
|
+
const category_name = name + "." + category
|
|
68
|
+
if (this._benchmarkCount[category_name] == undefined) {
|
|
69
|
+
this._benchmarkCount[category_name] = 0
|
|
70
|
+
this._benchmarkData[category_name] = 0
|
|
71
|
+
}
|
|
72
|
+
this._benchmarkCount[category_name] += 1
|
|
73
|
+
this._benchmarkData[category_name] += duration
|
|
74
|
+
}
|
|
64
75
|
result = this._benchmarkData[name] / this._benchmarkCount[name]
|
|
65
76
|
}
|
|
66
77
|
return result
|
|
67
78
|
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get given benchmark data.
|
|
82
|
+
*
|
|
83
|
+
* @param name of the benchmark
|
|
84
|
+
*/
|
|
85
|
+
static get(name:string):number {
|
|
86
|
+
if (this._benchmarkEnabled[name]) {
|
|
87
|
+
return this._benchmarkData[name] / this._benchmarkCount[name]
|
|
88
|
+
}
|
|
89
|
+
return -1
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get all benchmark data.
|
|
94
|
+
*
|
|
95
|
+
*/
|
|
96
|
+
static getAll():number {
|
|
97
|
+
let result:any = {}
|
|
98
|
+
for (const name in this._benchmarkData) {
|
|
99
|
+
if (this._benchmarkCount[name] > 0) {
|
|
100
|
+
result[name] = this._benchmarkData[name] / this._benchmarkCount[name]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return result
|
|
104
|
+
}
|
|
68
105
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { OINOStr, OINOContentType, OINOResult, OINOHttpResult, OINO_ERROR_PREFIX, OINO_WARNING_PREFIX, OINO_INFO_PREFIX, OINO_DEBUG_PREFIX } from "."
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Class for rendering HTML from data.
|
|
5
|
+
*/
|
|
6
|
+
export class OINOHtmlTemplate {
|
|
7
|
+
/** HTML template string */
|
|
8
|
+
template: string;
|
|
9
|
+
|
|
10
|
+
/** Cache modified value for template */
|
|
11
|
+
modified: number;
|
|
12
|
+
|
|
13
|
+
/** Cache expiration value for template */
|
|
14
|
+
expires: number;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates HTML Response from a key-value-pair.
|
|
18
|
+
*
|
|
19
|
+
* @param template template string
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
constructor (template:string) {
|
|
23
|
+
this.template = template
|
|
24
|
+
this.modified = 0
|
|
25
|
+
this.expires = 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @returns whether template is empty
|
|
30
|
+
*/
|
|
31
|
+
isEmpty():boolean {
|
|
32
|
+
return this.template == ""
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates HTML Response from a key-value-pair.
|
|
37
|
+
*
|
|
38
|
+
* @param key key
|
|
39
|
+
* @param value value
|
|
40
|
+
*
|
|
41
|
+
*/
|
|
42
|
+
renderFromKeyValue(key:string, value:string):OINOHttpResult {
|
|
43
|
+
const html:string = this.template.replaceAll('###' + key + '###', OINOStr.encode(value, OINOContentType.html))
|
|
44
|
+
const result:OINOHttpResult = new OINOHttpResult(html)
|
|
45
|
+
if (this.expires >= 1) {
|
|
46
|
+
result.expires = Math.round(this.expires)
|
|
47
|
+
}
|
|
48
|
+
if (this.modified >= 1) {
|
|
49
|
+
result.lastModified = this.modified
|
|
50
|
+
}
|
|
51
|
+
return result
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Creates HTML Response from object properties.
|
|
56
|
+
*
|
|
57
|
+
* @param object object
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
renderFromObject(object:any):OINOHttpResult {
|
|
61
|
+
let html:string = this.template
|
|
62
|
+
if (object) {
|
|
63
|
+
for (let key in object) {
|
|
64
|
+
const value = object[key]
|
|
65
|
+
if (value) {
|
|
66
|
+
html = html.replaceAll('###' + key + '###', OINOStr.encode(value.toString(), OINOContentType.html))
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
html = html.replace(/###[^#]*###/g, "")
|
|
71
|
+
const result:OINOHttpResult = new OINOHttpResult(html)
|
|
72
|
+
if (this.expires >= 1) {
|
|
73
|
+
result.expires = Math.round(this.expires)
|
|
74
|
+
}
|
|
75
|
+
if (this.modified >= 1) {
|
|
76
|
+
result.lastModified = this.modified
|
|
77
|
+
}
|
|
78
|
+
return result
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Creates HTML Response from API result.
|
|
83
|
+
*
|
|
84
|
+
* @param result OINOResult-object
|
|
85
|
+
* @param includeErrorMessages include debug messages in result
|
|
86
|
+
* @param includeWarningMessages include debug messages in result
|
|
87
|
+
* @param includeInfoMessages include debug messages in result
|
|
88
|
+
* @param includeDebugMessages include debug messages in result
|
|
89
|
+
*
|
|
90
|
+
*/
|
|
91
|
+
renderFromResult(result:OINOResult, includeErrorMessages:boolean=false, includeWarningMessages:boolean=false, includeInfoMessages:boolean=false, includeDebugMessages:boolean=false):OINOHttpResult {
|
|
92
|
+
let html:string = this.template
|
|
93
|
+
html = html.replaceAll('###statusCode###', OINOStr.encode(result.statusCode.toString(), OINOContentType.html))
|
|
94
|
+
html = html.replaceAll('###statusMessage###', OINOStr.encode(result.statusMessage.toString(), OINOContentType.html))
|
|
95
|
+
let messages = ""
|
|
96
|
+
for (let i:number = 0; i<result.messages.length; i++) {
|
|
97
|
+
if (includeErrorMessages && result.messages[i].startsWith(OINO_ERROR_PREFIX)) {
|
|
98
|
+
messages += "<li>" + OINOStr.encode(result.messages[i], OINOContentType.html) + "</li>"
|
|
99
|
+
}
|
|
100
|
+
if (includeWarningMessages && result.messages[i].startsWith(OINO_WARNING_PREFIX)) {
|
|
101
|
+
messages += "<li>" + OINOStr.encode(result.messages[i], OINOContentType.html) + "</li>"
|
|
102
|
+
}
|
|
103
|
+
if (includeInfoMessages && result.messages[i].startsWith(OINO_INFO_PREFIX)) {
|
|
104
|
+
messages += "<li>" + OINOStr.encode(result.messages[i], OINOContentType.html) + "</li>"
|
|
105
|
+
}
|
|
106
|
+
if (includeDebugMessages && result.messages[i].startsWith(OINO_DEBUG_PREFIX)) {
|
|
107
|
+
messages += "<li>" + OINOStr.encode(result.messages[i], OINOContentType.html) + "</li>"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
}
|
|
111
|
+
if (messages) {
|
|
112
|
+
html = html.replaceAll('###messages###', "<ul>" + messages + "</ul>")
|
|
113
|
+
}
|
|
114
|
+
html = html.replace(/###[^#]*###/g, "")
|
|
115
|
+
const http_result:OINOHttpResult = new OINOHttpResult(html)
|
|
116
|
+
if (this.expires >= 1) {
|
|
117
|
+
http_result.expires = Math.round(this.expires)
|
|
118
|
+
}
|
|
119
|
+
if (this.modified >= 1) {
|
|
120
|
+
http_result.lastModified = this.modified
|
|
121
|
+
}
|
|
122
|
+
return http_result
|
|
123
|
+
}
|
|
124
|
+
};
|
package/src/OINOResult.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { createHash, Hash } from "node:crypto";
|
|
7
8
|
import { OINO_DEBUG_PREFIX, OINO_ERROR_PREFIX, OINO_INFO_PREFIX, OINO_WARNING_PREFIX } from ".";
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -35,6 +36,18 @@ export class OINOResult {
|
|
|
35
36
|
this.messages = []
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Copy values from different result.
|
|
41
|
+
*
|
|
42
|
+
* @param result source value
|
|
43
|
+
*/
|
|
44
|
+
copy(result: OINOResult) {
|
|
45
|
+
this.success = result.success
|
|
46
|
+
this.statusCode = result.statusCode
|
|
47
|
+
this.statusMessage = result.statusMessage
|
|
48
|
+
this.messages = result.messages.slice()
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
/**
|
|
39
52
|
* Set HTTP OK status (does not reset messages).
|
|
40
53
|
*
|
|
@@ -46,14 +59,14 @@ export class OINOResult {
|
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
/**
|
|
49
|
-
* Set HTTP error status using given code and message.
|
|
62
|
+
* Set HTTP error status using given code and message. Returns self reference for chaining.
|
|
50
63
|
*
|
|
51
64
|
* @param statusCode HTTP status code
|
|
52
65
|
* @param statusMessage HTTP status message
|
|
53
66
|
* @param operation operation where error occured
|
|
54
67
|
*
|
|
55
68
|
*/
|
|
56
|
-
setError(statusCode:number, statusMessage:string, operation:string) {
|
|
69
|
+
setError(statusCode:number, statusMessage:string, operation:string):OINOResult {
|
|
57
70
|
this.success = false
|
|
58
71
|
this.statusCode = statusCode
|
|
59
72
|
if (this.statusMessage != "OK") {
|
|
@@ -64,48 +77,52 @@ export class OINOResult {
|
|
|
64
77
|
} else {
|
|
65
78
|
this.statusMessage = OINO_ERROR_PREFIX + " (" + operation + "): " + statusMessage
|
|
66
79
|
}
|
|
80
|
+
return this
|
|
67
81
|
}
|
|
68
82
|
|
|
69
83
|
/**
|
|
70
|
-
* Add warning message.
|
|
84
|
+
* Add warning message. Returns self reference for chaining.
|
|
71
85
|
*
|
|
72
86
|
* @param message HTTP status message
|
|
73
87
|
* @param operation operation where warning occured
|
|
74
88
|
*
|
|
75
89
|
*/
|
|
76
|
-
addWarning(message:string, operation:string) {
|
|
90
|
+
addWarning(message:string, operation:string):OINOResult {
|
|
77
91
|
message = message.trim()
|
|
78
92
|
if (message) {
|
|
79
93
|
this.messages.push(OINO_WARNING_PREFIX + " (" + operation + "): " + message)
|
|
80
94
|
}
|
|
95
|
+
return this
|
|
81
96
|
}
|
|
82
97
|
|
|
83
98
|
/**
|
|
84
|
-
* Add info message.
|
|
99
|
+
* Add info message. Returns self reference for chaining.
|
|
85
100
|
*
|
|
86
101
|
* @param message HTTP status message
|
|
87
102
|
* @param operation operation where info occured
|
|
88
103
|
*
|
|
89
104
|
*/
|
|
90
|
-
addInfo(message:string, operation:string) {
|
|
105
|
+
addInfo(message:string, operation:string):OINOResult {
|
|
91
106
|
message = message.trim()
|
|
92
107
|
if (message) {
|
|
93
108
|
this.messages.push(OINO_INFO_PREFIX + " (" + operation + "): " + message)
|
|
94
109
|
}
|
|
110
|
+
return this
|
|
95
111
|
}
|
|
96
112
|
|
|
97
113
|
/**
|
|
98
|
-
* Add debug message.
|
|
114
|
+
* Add debug message. Returns self reference for chaining.
|
|
99
115
|
*
|
|
100
116
|
* @param message HTTP status message
|
|
101
117
|
* @param operation operation where debug occured
|
|
102
118
|
*
|
|
103
119
|
*/
|
|
104
|
-
addDebug(message:string, operation:string) {
|
|
120
|
+
addDebug(message:string, operation:string):OINOResult {
|
|
105
121
|
message = message.trim()
|
|
106
122
|
if (message) {
|
|
107
123
|
this.messages.push(OINO_DEBUG_PREFIX + " (" + operation + "): " + message)
|
|
108
124
|
}
|
|
125
|
+
return this
|
|
109
126
|
}
|
|
110
127
|
|
|
111
128
|
/**
|
|
@@ -141,3 +158,69 @@ export class OINOResult {
|
|
|
141
158
|
}
|
|
142
159
|
}
|
|
143
160
|
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Specialized result for HTTP responses.
|
|
164
|
+
*/
|
|
165
|
+
export class OINOHttpResult extends OINOResult {
|
|
166
|
+
private _etag:string
|
|
167
|
+
|
|
168
|
+
/** HTTP body data */
|
|
169
|
+
readonly body: string
|
|
170
|
+
|
|
171
|
+
/** HTTP cache expiration value */
|
|
172
|
+
expires: number
|
|
173
|
+
|
|
174
|
+
/** HTTP cache last-modified value */
|
|
175
|
+
lastModified: number
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Constructor for a `OINOHttpResult`
|
|
179
|
+
*
|
|
180
|
+
* @param body HTTP body
|
|
181
|
+
*
|
|
182
|
+
*/
|
|
183
|
+
constructor(body:string) {
|
|
184
|
+
super()
|
|
185
|
+
this.body = body
|
|
186
|
+
this.expires = 0
|
|
187
|
+
this.lastModified = 0
|
|
188
|
+
this._etag = ""
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Get the ETag value for the body opportunistically, i.e. don't calculate until requested and reuse value.
|
|
193
|
+
*
|
|
194
|
+
*/
|
|
195
|
+
getEtag():string {
|
|
196
|
+
if (this._etag == "") {
|
|
197
|
+
const hash:Hash = createHash("sha256")
|
|
198
|
+
this._etag = hash.update(this.body).digest("hex")
|
|
199
|
+
}
|
|
200
|
+
return this._etag
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Get a Response object from the result values.
|
|
205
|
+
*
|
|
206
|
+
* @param headers HTTP headers (overrides existing values)
|
|
207
|
+
*/
|
|
208
|
+
getResponse(headers?:Record<string, string>):Response {
|
|
209
|
+
const result:Response = new Response(this.body, {status:this.statusCode, statusText: this.statusMessage, headers: headers})
|
|
210
|
+
result.headers.set('Content-Length', this.body.length.toString())
|
|
211
|
+
if (this.lastModified > 0) {
|
|
212
|
+
result.headers.set('Last-Modified', new Date(this.lastModified).toUTCString())
|
|
213
|
+
}
|
|
214
|
+
if (this.expires >= 0) {
|
|
215
|
+
result.headers.set('Expires', Math.round(this.expires).toString())
|
|
216
|
+
if (this.expires == 0) {
|
|
217
|
+
result.headers.set('Pragma', 'no-cache')
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
result.headers.set("ETag", this.getEtag())
|
|
221
|
+
return result
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { OINOBenchmark } from "./OINOBenchmark.js"
|
|
2
2
|
export { OINOLog, OINOLogLevel, OINOConsoleLog } from "./OINOLog.js"
|
|
3
|
-
export { OINOResult } from "./OINOResult.js"
|
|
3
|
+
export { OINOResult, OINOHttpResult } from "./OINOResult.js"
|
|
4
4
|
export { OINOStr } from "./OINOStr.js"
|
|
5
|
+
export { OINOHtmlTemplate } from "./OINOHtmlTemplate.js"
|
|
5
6
|
|
|
6
7
|
/** OINO error message prefix */
|
|
7
8
|
export const OINO_ERROR_PREFIX = "OINO ERROR"
|