@oino-ts/types 0.0.12 → 0.0.14

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.
@@ -26,21 +26,23 @@ class OINOBenchmark {
26
26
  /**
27
27
  * Set benchmark names that are enabled.
28
28
  *
29
- * @param names array of those benchmarks that are enabled
29
+ * @param module array of those benchmarks that are enabled
30
30
  */
31
- static setEnabled(names) {
31
+ static setEnabled(module) {
32
32
  this._benchmarkEnabled = {};
33
- names.forEach(name => {
34
- this._benchmarkEnabled[name] = true;
33
+ module.forEach(module_name => {
34
+ this._benchmarkEnabled[module_name] = true;
35
35
  });
36
36
  }
37
37
  /**
38
38
  * Start benchmark timing.
39
39
  *
40
- * @param name of the benchmark
40
+ * @param module of the benchmark
41
+ * @param method of the benchmark
41
42
  */
42
- static start(name) {
43
- if (this._benchmarkEnabled[name]) {
43
+ static start(module, method) {
44
+ const name = module + "." + method;
45
+ if (this._benchmarkEnabled[module]) {
44
46
  if (this._benchmarkCount[name] == undefined) {
45
47
  this._benchmarkCount[name] = 0;
46
48
  this._benchmarkData[name] = 0;
@@ -51,16 +53,56 @@ class OINOBenchmark {
51
53
  /**
52
54
  * Complete benchmark timing
53
55
  *
54
- * @param name of the benchmark
56
+ * @param module of the benchmark
57
+ * @param method of the benchmark
58
+ * @param category optional subcategory of the benchmark
55
59
  */
56
- static end(name) {
60
+ static end(module, method, category) {
61
+ const name = module + "." + method;
57
62
  let result = 0;
58
- if (this._benchmarkEnabled[name]) {
63
+ if (this._benchmarkEnabled[module]) {
64
+ const duration = performance.now() - this._benchmarkStart[name];
59
65
  this._benchmarkCount[name] += 1;
60
- this._benchmarkData[name] += performance.now() - this._benchmarkStart[name];
66
+ this._benchmarkData[name] += duration;
67
+ if (category) {
68
+ const category_name = name + "." + category;
69
+ if (this._benchmarkCount[category_name] == undefined) {
70
+ this._benchmarkCount[category_name] = 0;
71
+ this._benchmarkData[category_name] = 0;
72
+ }
73
+ this._benchmarkCount[category_name] += 1;
74
+ this._benchmarkData[category_name] += duration;
75
+ }
61
76
  result = this._benchmarkData[name] / this._benchmarkCount[name];
62
77
  }
63
78
  return result;
64
79
  }
80
+ /**
81
+ * Get given benchmark data.
82
+ *
83
+ * @param module of the benchmark
84
+ * @param method of the benchmark
85
+ *
86
+ */
87
+ static get(module, method) {
88
+ const name = module + "." + method;
89
+ if (this._benchmarkEnabled[module]) {
90
+ return this._benchmarkData[module] / this._benchmarkCount[module];
91
+ }
92
+ return -1;
93
+ }
94
+ /**
95
+ * Get all benchmark data.
96
+ *
97
+ */
98
+ static getAll() {
99
+ let result = {};
100
+ for (const name in this._benchmarkData) {
101
+ if (this._benchmarkCount[name] > 0) {
102
+ result[name] = this._benchmarkData[name] / this._benchmarkCount[name];
103
+ }
104
+ }
105
+ return result;
106
+ }
65
107
  }
66
108
  exports.OINOBenchmark = OINOBenchmark;
@@ -8,23 +8,20 @@ const _1 = require(".");
8
8
  class OINOHtmlTemplate {
9
9
  /** HTML template string */
10
10
  template;
11
+ /** Cache modified value for template */
12
+ modified;
11
13
  /** Cache expiration value for template */
12
14
  expires;
13
15
  /**
14
16
  * Creates HTML Response from a key-value-pair.
15
17
  *
16
18
  * @param template template string
17
- * @param expires cache expiration value
18
19
  *
19
20
  */
20
- constructor(template, expires) {
21
+ constructor(template) {
21
22
  this.template = template;
22
- if (expires) {
23
- this.expires = expires;
24
- }
25
- else {
26
- this.expires = -1;
27
- }
23
+ this.modified = 0;
24
+ this.expires = 0;
28
25
  }
29
26
  /**
30
27
  * @returns whether template is empty
@@ -40,8 +37,16 @@ class OINOHtmlTemplate {
40
37
  *
41
38
  */
42
39
  renderFromKeyValue(key, value) {
40
+ _1.OINOBenchmark.start("OINOHtmlTemplate", "renderFromKeyValue");
43
41
  const html = this.template.replaceAll('###' + key + '###', _1.OINOStr.encode(value, _1.OINOContentType.html));
44
42
  const result = new _1.OINOHttpResult(html);
43
+ if (this.expires >= 1) {
44
+ result.expires = Math.round(this.expires);
45
+ }
46
+ if (this.modified >= 1) {
47
+ result.lastModified = this.modified;
48
+ }
49
+ _1.OINOBenchmark.end("OINOHtmlTemplate", "renderFromKeyValue");
45
50
  return result;
46
51
  }
47
52
  /**
@@ -51,6 +56,7 @@ class OINOHtmlTemplate {
51
56
  *
52
57
  */
53
58
  renderFromObject(object) {
59
+ _1.OINOBenchmark.start("OINOHtmlTemplate", "renderFromObject");
54
60
  let html = this.template;
55
61
  if (object) {
56
62
  for (let key in object) {
@@ -63,8 +69,12 @@ class OINOHtmlTemplate {
63
69
  html = html.replace(/###[^#]*###/g, "");
64
70
  const result = new _1.OINOHttpResult(html);
65
71
  if (this.expires >= 1) {
66
- result.headers["Expires"] = Math.round(this.expires).toString();
72
+ result.expires = Math.round(this.expires);
67
73
  }
74
+ if (this.modified >= 1) {
75
+ result.lastModified = this.modified;
76
+ }
77
+ _1.OINOBenchmark.end("OINOHtmlTemplate", "renderFromObject");
68
78
  return result;
69
79
  }
70
80
  /**
@@ -78,6 +88,7 @@ class OINOHtmlTemplate {
78
88
  *
79
89
  */
80
90
  renderFromResult(result, includeErrorMessages = false, includeWarningMessages = false, includeInfoMessages = false, includeDebugMessages = false) {
91
+ _1.OINOBenchmark.start("OINOHtmlTemplate", "renderFromResult");
81
92
  let html = this.template;
82
93
  html = html.replaceAll('###statusCode###', _1.OINOStr.encode(result.statusCode.toString(), _1.OINOContentType.html));
83
94
  html = html.replaceAll('###statusMessage###', _1.OINOStr.encode(result.statusMessage.toString(), _1.OINOContentType.html));
@@ -101,6 +112,13 @@ class OINOHtmlTemplate {
101
112
  }
102
113
  html = html.replace(/###[^#]*###/g, "");
103
114
  const http_result = new _1.OINOHttpResult(html);
115
+ if (this.expires >= 1) {
116
+ http_result.expires = Math.round(this.expires);
117
+ }
118
+ if (this.modified >= 1) {
119
+ http_result.lastModified = this.modified;
120
+ }
121
+ _1.OINOBenchmark.end("OINOHtmlTemplate", "renderFromResult");
104
122
  return http_result;
105
123
  }
106
124
  }
@@ -6,6 +6,7 @@
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
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
@@ -153,25 +154,36 @@ exports.OINOResult = OINOResult;
153
154
  * Specialized result for HTTP responses.
154
155
  */
155
156
  class OINOHttpResult extends OINOResult {
157
+ _etag;
156
158
  /** HTTP body data */
157
159
  body;
158
- /** HTTP header values */
159
- headers;
160
+ /** HTTP cache expiration value */
161
+ expires;
162
+ /** HTTP cache last-modified value */
163
+ lastModified;
160
164
  /**
161
165
  * Constructor for a `OINOHttpResult`
162
166
  *
163
167
  * @param body HTTP body
164
- * @param headers HTTP headers
168
+ *
165
169
  */
166
- constructor(body, headers) {
170
+ constructor(body) {
167
171
  super();
168
172
  this.body = body;
169
- if (headers) {
170
- this.headers = headers;
171
- }
172
- else {
173
- this.headers = {};
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");
174
185
  }
186
+ return this._etag;
175
187
  }
176
188
  /**
177
189
  * Get a Response object from the result values.
@@ -179,11 +191,18 @@ class OINOHttpResult extends OINOResult {
179
191
  * @param headers HTTP headers (overrides existing values)
180
192
  */
181
193
  getResponse(headers) {
182
- if (!headers) {
183
- headers = this.headers;
184
- }
185
- headers['Content-Length'] = this.body.length.toString();
186
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());
187
206
  return result;
188
207
  }
189
208
  }
package/dist/cjs/index.js CHANGED
@@ -22,7 +22,9 @@ exports.OINO_WARNING_PREFIX = "OINO WARNING";
22
22
  exports.OINO_INFO_PREFIX = "OINO INFO";
23
23
  /** OINO debug message prefix */
24
24
  exports.OINO_DEBUG_PREFIX = "OINO DEBUG";
25
- /** Supported content format mime-types */
25
+ /**
26
+ * Supported content format mime-types
27
+ */
26
28
  var OINOContentType;
27
29
  (function (OINOContentType) {
28
30
  /** JSON encoded data */
@@ -23,21 +23,23 @@ export class OINOBenchmark {
23
23
  /**
24
24
  * Set benchmark names that are enabled.
25
25
  *
26
- * @param names array of those benchmarks that are enabled
26
+ * @param module array of those benchmarks that are enabled
27
27
  */
28
- static setEnabled(names) {
28
+ static setEnabled(module) {
29
29
  this._benchmarkEnabled = {};
30
- names.forEach(name => {
31
- this._benchmarkEnabled[name] = true;
30
+ module.forEach(module_name => {
31
+ this._benchmarkEnabled[module_name] = true;
32
32
  });
33
33
  }
34
34
  /**
35
35
  * Start benchmark timing.
36
36
  *
37
- * @param name of the benchmark
37
+ * @param module of the benchmark
38
+ * @param method of the benchmark
38
39
  */
39
- static start(name) {
40
- if (this._benchmarkEnabled[name]) {
40
+ static start(module, method) {
41
+ const name = module + "." + method;
42
+ if (this._benchmarkEnabled[module]) {
41
43
  if (this._benchmarkCount[name] == undefined) {
42
44
  this._benchmarkCount[name] = 0;
43
45
  this._benchmarkData[name] = 0;
@@ -48,15 +50,55 @@ export class OINOBenchmark {
48
50
  /**
49
51
  * Complete benchmark timing
50
52
  *
51
- * @param name of the benchmark
53
+ * @param module of the benchmark
54
+ * @param method of the benchmark
55
+ * @param category optional subcategory of the benchmark
52
56
  */
53
- static end(name) {
57
+ static end(module, method, category) {
58
+ const name = module + "." + method;
54
59
  let result = 0;
55
- if (this._benchmarkEnabled[name]) {
60
+ if (this._benchmarkEnabled[module]) {
61
+ const duration = performance.now() - this._benchmarkStart[name];
56
62
  this._benchmarkCount[name] += 1;
57
- this._benchmarkData[name] += performance.now() - this._benchmarkStart[name];
63
+ this._benchmarkData[name] += duration;
64
+ if (category) {
65
+ const category_name = name + "." + category;
66
+ if (this._benchmarkCount[category_name] == undefined) {
67
+ this._benchmarkCount[category_name] = 0;
68
+ this._benchmarkData[category_name] = 0;
69
+ }
70
+ this._benchmarkCount[category_name] += 1;
71
+ this._benchmarkData[category_name] += duration;
72
+ }
58
73
  result = this._benchmarkData[name] / this._benchmarkCount[name];
59
74
  }
60
75
  return result;
61
76
  }
77
+ /**
78
+ * Get given benchmark data.
79
+ *
80
+ * @param module of the benchmark
81
+ * @param method of the benchmark
82
+ *
83
+ */
84
+ static get(module, method) {
85
+ const name = module + "." + method;
86
+ if (this._benchmarkEnabled[module]) {
87
+ return this._benchmarkData[module] / this._benchmarkCount[module];
88
+ }
89
+ return -1;
90
+ }
91
+ /**
92
+ * Get all benchmark data.
93
+ *
94
+ */
95
+ static getAll() {
96
+ let result = {};
97
+ for (const name in this._benchmarkData) {
98
+ if (this._benchmarkCount[name] > 0) {
99
+ result[name] = this._benchmarkData[name] / this._benchmarkCount[name];
100
+ }
101
+ }
102
+ return result;
103
+ }
62
104
  }
@@ -1,27 +1,24 @@
1
- import { OINOStr, OINOContentType, OINOHttpResult, OINO_ERROR_PREFIX, OINO_WARNING_PREFIX, OINO_INFO_PREFIX, OINO_DEBUG_PREFIX } from ".";
1
+ import { OINOStr, OINOContentType, OINOHttpResult, OINO_ERROR_PREFIX, OINO_WARNING_PREFIX, OINO_INFO_PREFIX, OINO_DEBUG_PREFIX, OINOBenchmark } from ".";
2
2
  /**
3
3
  * Class for rendering HTML from data.
4
4
  */
5
5
  export class OINOHtmlTemplate {
6
6
  /** HTML template string */
7
7
  template;
8
+ /** Cache modified value for template */
9
+ modified;
8
10
  /** Cache expiration value for template */
9
11
  expires;
10
12
  /**
11
13
  * Creates HTML Response from a key-value-pair.
12
14
  *
13
15
  * @param template template string
14
- * @param expires cache expiration value
15
16
  *
16
17
  */
17
- constructor(template, expires) {
18
+ constructor(template) {
18
19
  this.template = template;
19
- if (expires) {
20
- this.expires = expires;
21
- }
22
- else {
23
- this.expires = -1;
24
- }
20
+ this.modified = 0;
21
+ this.expires = 0;
25
22
  }
26
23
  /**
27
24
  * @returns whether template is empty
@@ -37,8 +34,16 @@ export class OINOHtmlTemplate {
37
34
  *
38
35
  */
39
36
  renderFromKeyValue(key, value) {
37
+ OINOBenchmark.start("OINOHtmlTemplate", "renderFromKeyValue");
40
38
  const html = this.template.replaceAll('###' + key + '###', OINOStr.encode(value, OINOContentType.html));
41
39
  const result = new OINOHttpResult(html);
40
+ if (this.expires >= 1) {
41
+ result.expires = Math.round(this.expires);
42
+ }
43
+ if (this.modified >= 1) {
44
+ result.lastModified = this.modified;
45
+ }
46
+ OINOBenchmark.end("OINOHtmlTemplate", "renderFromKeyValue");
42
47
  return result;
43
48
  }
44
49
  /**
@@ -48,6 +53,7 @@ export class OINOHtmlTemplate {
48
53
  *
49
54
  */
50
55
  renderFromObject(object) {
56
+ OINOBenchmark.start("OINOHtmlTemplate", "renderFromObject");
51
57
  let html = this.template;
52
58
  if (object) {
53
59
  for (let key in object) {
@@ -60,8 +66,12 @@ export class OINOHtmlTemplate {
60
66
  html = html.replace(/###[^#]*###/g, "");
61
67
  const result = new OINOHttpResult(html);
62
68
  if (this.expires >= 1) {
63
- result.headers["Expires"] = Math.round(this.expires).toString();
69
+ result.expires = Math.round(this.expires);
64
70
  }
71
+ if (this.modified >= 1) {
72
+ result.lastModified = this.modified;
73
+ }
74
+ OINOBenchmark.end("OINOHtmlTemplate", "renderFromObject");
65
75
  return result;
66
76
  }
67
77
  /**
@@ -75,6 +85,7 @@ export class OINOHtmlTemplate {
75
85
  *
76
86
  */
77
87
  renderFromResult(result, includeErrorMessages = false, includeWarningMessages = false, includeInfoMessages = false, includeDebugMessages = false) {
88
+ OINOBenchmark.start("OINOHtmlTemplate", "renderFromResult");
78
89
  let html = this.template;
79
90
  html = html.replaceAll('###statusCode###', OINOStr.encode(result.statusCode.toString(), OINOContentType.html));
80
91
  html = html.replaceAll('###statusMessage###', OINOStr.encode(result.statusMessage.toString(), OINOContentType.html));
@@ -98,6 +109,13 @@ export class OINOHtmlTemplate {
98
109
  }
99
110
  html = html.replace(/###[^#]*###/g, "");
100
111
  const http_result = new OINOHttpResult(html);
112
+ if (this.expires >= 1) {
113
+ http_result.expires = Math.round(this.expires);
114
+ }
115
+ if (this.modified >= 1) {
116
+ http_result.lastModified = this.modified;
117
+ }
118
+ OINOBenchmark.end("OINOHtmlTemplate", "renderFromResult");
101
119
  return http_result;
102
120
  }
103
121
  }
@@ -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
@@ -149,25 +150,36 @@ export class OINOResult {
149
150
  * Specialized result for HTTP responses.
150
151
  */
151
152
  export class OINOHttpResult extends OINOResult {
153
+ _etag;
152
154
  /** HTTP body data */
153
155
  body;
154
- /** HTTP header values */
155
- headers;
156
+ /** HTTP cache expiration value */
157
+ expires;
158
+ /** HTTP cache last-modified value */
159
+ lastModified;
156
160
  /**
157
161
  * Constructor for a `OINOHttpResult`
158
162
  *
159
163
  * @param body HTTP body
160
- * @param headers HTTP headers
164
+ *
161
165
  */
162
- constructor(body, headers) {
166
+ constructor(body) {
163
167
  super();
164
168
  this.body = body;
165
- if (headers) {
166
- this.headers = headers;
167
- }
168
- else {
169
- this.headers = {};
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");
170
181
  }
182
+ return this._etag;
171
183
  }
172
184
  /**
173
185
  * Get a Response object from the result values.
@@ -175,11 +187,18 @@ export class OINOHttpResult extends OINOResult {
175
187
  * @param headers HTTP headers (overrides existing values)
176
188
  */
177
189
  getResponse(headers) {
178
- if (!headers) {
179
- headers = this.headers;
180
- }
181
- headers['Content-Length'] = this.body.length.toString();
182
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());
183
202
  return result;
184
203
  }
185
204
  }
package/dist/esm/index.js CHANGED
@@ -11,7 +11,9 @@ export const OINO_WARNING_PREFIX = "OINO WARNING";
11
11
  export const OINO_INFO_PREFIX = "OINO INFO";
12
12
  /** OINO debug message prefix */
13
13
  export const OINO_DEBUG_PREFIX = "OINO DEBUG";
14
- /** Supported content format mime-types */
14
+ /**
15
+ * Supported content format mime-types
16
+ */
15
17
  export var OINOContentType;
16
18
  (function (OINOContentType) {
17
19
  /** JSON encoded data */
@@ -15,19 +15,35 @@ export declare class OINOBenchmark {
15
15
  /**
16
16
  * Set benchmark names that are enabled.
17
17
  *
18
- * @param names array of those benchmarks that are enabled
18
+ * @param module array of those benchmarks that are enabled
19
19
  */
20
- static setEnabled(names: string[]): void;
20
+ static setEnabled(module: string[]): void;
21
21
  /**
22
22
  * Start benchmark timing.
23
23
  *
24
- * @param name of the benchmark
24
+ * @param module of the benchmark
25
+ * @param method of the benchmark
25
26
  */
26
- static start(name: string): void;
27
+ static start(module: string, method: string): void;
27
28
  /**
28
29
  * Complete benchmark timing
29
30
  *
30
- * @param name of the benchmark
31
+ * @param module of the benchmark
32
+ * @param method of the benchmark
33
+ * @param category optional subcategory of the benchmark
31
34
  */
32
- static end(name: string): number;
35
+ static end(module: string, method: string, category?: string): number;
36
+ /**
37
+ * Get given benchmark data.
38
+ *
39
+ * @param module of the benchmark
40
+ * @param method of the benchmark
41
+ *
42
+ */
43
+ static get(module: string, method: string): number;
44
+ /**
45
+ * Get all benchmark data.
46
+ *
47
+ */
48
+ static getAll(): number;
33
49
  }
@@ -5,16 +5,17 @@ import { OINOResult, OINOHttpResult } from ".";
5
5
  export declare class OINOHtmlTemplate {
6
6
  /** HTML template string */
7
7
  template: string;
8
+ /** Cache modified value for template */
9
+ modified: number;
8
10
  /** Cache expiration value for template */
9
11
  expires: number;
10
12
  /**
11
13
  * Creates HTML Response from a key-value-pair.
12
14
  *
13
15
  * @param template template string
14
- * @param expires cache expiration value
15
16
  *
16
17
  */
17
- constructor(template: string, expires?: number);
18
+ constructor(template: string);
18
19
  /**
19
20
  * @returns whether template is empty
20
21
  */
@@ -77,17 +77,25 @@ export declare class OINOResult {
77
77
  * Specialized result for HTTP responses.
78
78
  */
79
79
  export declare class OINOHttpResult extends OINOResult {
80
+ private _etag;
80
81
  /** HTTP body data */
81
- body: string;
82
- /** HTTP header values */
83
- headers: Record<string, string>;
82
+ readonly body: string;
83
+ /** HTTP cache expiration value */
84
+ expires: number;
85
+ /** HTTP cache last-modified value */
86
+ lastModified: number;
84
87
  /**
85
88
  * Constructor for a `OINOHttpResult`
86
89
  *
87
90
  * @param body HTTP body
88
- * @param headers HTTP headers
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
+ *
89
97
  */
90
- constructor(body: string, headers?: Record<string, string>);
98
+ getEtag(): string;
91
99
  /**
92
100
  * Get a Response object from the result values.
93
101
  *
@@ -11,7 +11,9 @@ export declare const OINO_WARNING_PREFIX = "OINO WARNING";
11
11
  export declare const OINO_INFO_PREFIX = "OINO INFO";
12
12
  /** OINO debug message prefix */
13
13
  export declare const OINO_DEBUG_PREFIX = "OINO DEBUG";
14
- /** Supported content format mime-types */
14
+ /**
15
+ * Supported content format mime-types
16
+ */
15
17
  export declare enum OINOContentType {
16
18
  /** JSON encoded data */
17
19
  json = "application/json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oino-ts/types",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "OINO TS package for types.",
5
5
  "author": "Matias Kiviniemi (pragmatta)",
6
6
  "license": "MPL-2.0",
@@ -27,22 +27,24 @@ export class OINOBenchmark {
27
27
  /**
28
28
  * Set benchmark names that are enabled.
29
29
  *
30
- * @param names array of those benchmarks that are enabled
30
+ * @param module array of those benchmarks that are enabled
31
31
  */
32
- static setEnabled(names:string[]):void {
32
+ static setEnabled(module:string[]):void {
33
33
  this._benchmarkEnabled = {}
34
- names.forEach(name => {
35
- this._benchmarkEnabled[name] = true
34
+ module.forEach(module_name => {
35
+ this._benchmarkEnabled[module_name] = true
36
36
  });
37
37
  }
38
38
 
39
39
  /**
40
40
  * Start benchmark timing.
41
41
  *
42
- * @param name of the benchmark
42
+ * @param module of the benchmark
43
+ * @param method of the benchmark
43
44
  */
44
- static start(name:string):void {
45
- if (this._benchmarkEnabled[name]) {
45
+ static start(module:string, method:string):void {
46
+ const name:string = module + "." + method
47
+ if (this._benchmarkEnabled[module]) {
46
48
  if (this._benchmarkCount[name] == undefined) {
47
49
  this._benchmarkCount[name] = 0
48
50
  this._benchmarkData[name] = 0
@@ -54,15 +56,57 @@ export class OINOBenchmark {
54
56
  /**
55
57
  * Complete benchmark timing
56
58
  *
57
- * @param name of the benchmark
59
+ * @param module of the benchmark
60
+ * @param method of the benchmark
61
+ * @param category optional subcategory of the benchmark
58
62
  */
59
- static end(name:string):number {
63
+ static end(module:string, method:string, category?:string):number {
64
+ const name:string = module + "." + method
60
65
  let result:number = 0
61
- if (this._benchmarkEnabled[name]) {
66
+ if (this._benchmarkEnabled[module]) {
67
+ const duration = performance.now() - this._benchmarkStart[name]
62
68
  this._benchmarkCount[name] += 1
63
- this._benchmarkData[name] += performance.now() - this._benchmarkStart[name]
69
+ this._benchmarkData[name] += duration
70
+ if (category) {
71
+ const category_name = name + "." + category
72
+ if (this._benchmarkCount[category_name] == undefined) {
73
+ this._benchmarkCount[category_name] = 0
74
+ this._benchmarkData[category_name] = 0
75
+ }
76
+ this._benchmarkCount[category_name] += 1
77
+ this._benchmarkData[category_name] += duration
78
+ }
64
79
  result = this._benchmarkData[name] / this._benchmarkCount[name]
65
80
  }
66
81
  return result
67
82
  }
83
+
84
+ /**
85
+ * Get given benchmark data.
86
+ *
87
+ * @param module of the benchmark
88
+ * @param method of the benchmark
89
+ *
90
+ */
91
+ static get(module:string, method:string):number {
92
+ const name:string = module + "." + method
93
+ if (this._benchmarkEnabled[module]) {
94
+ return this._benchmarkData[module] / this._benchmarkCount[module]
95
+ }
96
+ return -1
97
+ }
98
+
99
+ /**
100
+ * Get all benchmark data.
101
+ *
102
+ */
103
+ static getAll():number {
104
+ let result:any = {}
105
+ for (const name in this._benchmarkData) {
106
+ if (this._benchmarkCount[name] > 0) {
107
+ result[name] = this._benchmarkData[name] / this._benchmarkCount[name]
108
+ }
109
+ }
110
+ return result
111
+ }
68
112
  }
@@ -1,4 +1,4 @@
1
- import { OINOStr, OINOContentType, OINOResult, OINOHttpResult, OINO_ERROR_PREFIX, OINO_WARNING_PREFIX, OINO_INFO_PREFIX, OINO_DEBUG_PREFIX } from "."
1
+ import { OINOStr, OINOContentType, OINOResult, OINOHttpResult, OINO_ERROR_PREFIX, OINO_WARNING_PREFIX, OINO_INFO_PREFIX, OINO_DEBUG_PREFIX, OINOBenchmark } from "."
2
2
 
3
3
  /**
4
4
  * Class for rendering HTML from data.
@@ -7,6 +7,9 @@ export class OINOHtmlTemplate {
7
7
  /** HTML template string */
8
8
  template: string;
9
9
 
10
+ /** Cache modified value for template */
11
+ modified: number;
12
+
10
13
  /** Cache expiration value for template */
11
14
  expires: number;
12
15
 
@@ -14,16 +17,12 @@ export class OINOHtmlTemplate {
14
17
  * Creates HTML Response from a key-value-pair.
15
18
  *
16
19
  * @param template template string
17
- * @param expires cache expiration value
18
20
  *
19
21
  */
20
- constructor (template:string, expires?: number) {
22
+ constructor (template:string) {
21
23
  this.template = template
22
- if (expires) {
23
- this.expires = expires
24
- } else {
25
- this.expires = -1
26
- }
24
+ this.modified = 0
25
+ this.expires = 0
27
26
  }
28
27
 
29
28
  /**
@@ -41,8 +40,16 @@ export class OINOHtmlTemplate {
41
40
  *
42
41
  */
43
42
  renderFromKeyValue(key:string, value:string):OINOHttpResult {
43
+ OINOBenchmark.start("OINOHtmlTemplate", "renderFromKeyValue")
44
44
  const html:string = this.template.replaceAll('###' + key + '###', OINOStr.encode(value, OINOContentType.html))
45
45
  const result:OINOHttpResult = new OINOHttpResult(html)
46
+ if (this.expires >= 1) {
47
+ result.expires = Math.round(this.expires)
48
+ }
49
+ if (this.modified >= 1) {
50
+ result.lastModified = this.modified
51
+ }
52
+ OINOBenchmark.end("OINOHtmlTemplate", "renderFromKeyValue")
46
53
  return result
47
54
  }
48
55
 
@@ -53,6 +60,7 @@ export class OINOHtmlTemplate {
53
60
  *
54
61
  */
55
62
  renderFromObject(object:any):OINOHttpResult {
63
+ OINOBenchmark.start("OINOHtmlTemplate", "renderFromObject")
56
64
  let html:string = this.template
57
65
  if (object) {
58
66
  for (let key in object) {
@@ -65,8 +73,12 @@ export class OINOHtmlTemplate {
65
73
  html = html.replace(/###[^#]*###/g, "")
66
74
  const result:OINOHttpResult = new OINOHttpResult(html)
67
75
  if (this.expires >= 1) {
68
- result.headers["Expires"] = Math.round(this.expires).toString()
76
+ result.expires = Math.round(this.expires)
69
77
  }
78
+ if (this.modified >= 1) {
79
+ result.lastModified = this.modified
80
+ }
81
+ OINOBenchmark.end("OINOHtmlTemplate", "renderFromObject")
70
82
  return result
71
83
  }
72
84
 
@@ -81,6 +93,7 @@ export class OINOHtmlTemplate {
81
93
  *
82
94
  */
83
95
  renderFromResult(result:OINOResult, includeErrorMessages:boolean=false, includeWarningMessages:boolean=false, includeInfoMessages:boolean=false, includeDebugMessages:boolean=false):OINOHttpResult {
96
+ OINOBenchmark.start("OINOHtmlTemplate", "renderFromResult")
84
97
  let html:string = this.template
85
98
  html = html.replaceAll('###statusCode###', OINOStr.encode(result.statusCode.toString(), OINOContentType.html))
86
99
  html = html.replaceAll('###statusMessage###', OINOStr.encode(result.statusMessage.toString(), OINOContentType.html))
@@ -105,6 +118,13 @@ export class OINOHtmlTemplate {
105
118
  }
106
119
  html = html.replace(/###[^#]*###/g, "")
107
120
  const http_result:OINOHttpResult = new OINOHttpResult(html)
121
+ if (this.expires >= 1) {
122
+ http_result.expires = Math.round(this.expires)
123
+ }
124
+ if (this.modified >= 1) {
125
+ http_result.lastModified = this.modified
126
+ }
127
+ OINOBenchmark.end("OINOHtmlTemplate", "renderFromResult")
108
128
  return http_result
109
129
  }
110
130
  };
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
  /**
@@ -162,26 +163,41 @@ export class OINOResult {
162
163
  * Specialized result for HTTP responses.
163
164
  */
164
165
  export class OINOHttpResult extends OINOResult {
166
+ private _etag:string
167
+
165
168
  /** HTTP body data */
166
- body: string
169
+ readonly body: string
170
+
171
+ /** HTTP cache expiration value */
172
+ expires: number
167
173
 
168
- /** HTTP header values */
169
- headers: Record<string, string>
174
+ /** HTTP cache last-modified value */
175
+ lastModified: number
170
176
 
171
177
  /**
172
178
  * Constructor for a `OINOHttpResult`
173
179
  *
174
180
  * @param body HTTP body
175
- * @param headers HTTP headers
181
+ *
176
182
  */
177
- constructor(body:string, headers?:Record<string, string>) {
183
+ constructor(body:string) {
178
184
  super()
179
185
  this.body = body
180
- if (headers) {
181
- this.headers = headers
182
- } else {
183
- this.headers = {}
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")
184
199
  }
200
+ return this._etag
185
201
  }
186
202
 
187
203
  /**
@@ -190,11 +206,18 @@ export class OINOHttpResult extends OINOResult {
190
206
  * @param headers HTTP headers (overrides existing values)
191
207
  */
192
208
  getResponse(headers?:Record<string, string>):Response {
193
- if (!headers) {
194
- headers = this.headers
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
+ }
195
219
  }
196
- headers['Content-Length'] = this.body.length.toString()
197
- const result = new Response(this.body, {status:this.statusCode, statusText: this.statusMessage, headers: headers})
220
+ result.headers.set("ETag", this.getEtag())
198
221
  return result
199
222
  }
200
223
 
package/src/index.ts CHANGED
@@ -13,7 +13,9 @@ export const OINO_INFO_PREFIX = "OINO INFO"
13
13
  /** OINO debug message prefix */
14
14
  export const OINO_DEBUG_PREFIX = "OINO DEBUG"
15
15
 
16
- /** Supported content format mime-types */
16
+ /**
17
+ * Supported content format mime-types
18
+ */
17
19
  export enum OINOContentType {
18
20
  /** JSON encoded data */
19
21
  json='application/json',