ng-talkback 21.0.16 → 21.0.17

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.
Files changed (69) hide show
  1. package/browser/package.json +1 -1
  2. package/browser-prod/package.json +1 -1
  3. package/lib/build-info._auto-generated_.d.ts +1 -1
  4. package/lib/build-info._auto-generated_.js +1 -1
  5. package/lib/package.json +1 -1
  6. package/lib-prod/build-info._auto-generated_.js +14 -0
  7. package/lib-prod/env/env.angular-node-app.js +130 -0
  8. package/lib-prod/env/env.docs-webapp.js +130 -0
  9. package/lib-prod/env/env.electron-app.js +130 -0
  10. package/lib-prod/env/env.mobile-app.js +130 -0
  11. package/lib-prod/env/env.npm-lib-and-cli-tool.js +130 -0
  12. package/lib-prod/env/env.vscode-plugin.js +130 -0
  13. package/lib-prod/env/index.js +6 -0
  14. package/lib-prod/es6.backend.js +5 -0
  15. package/lib-prod/features/error-rate.backend.js +25 -0
  16. package/lib-prod/features/latency.backend.js +30 -0
  17. package/lib-prod/index._auto-generated_.js +0 -0
  18. package/lib-prod/index.js +21 -0
  19. package/lib-prod/logger.backend.js +25 -0
  20. package/lib-prod/migrations/index.js +1 -0
  21. package/lib-prod/migrations/migrations_index._auto-generated_.js +0 -0
  22. package/lib-prod/options.backend.js +95 -0
  23. package/lib-prod/package.json +1 -1
  24. package/lib-prod/request-handler.backend.js +131 -0
  25. package/lib-prod/server.backend.js +82 -0
  26. package/lib-prod/summary.backend.js +24 -0
  27. package/lib-prod/talkback-factory.backend.js +19 -0
  28. package/lib-prod/tape-matcher.backend.js +95 -0
  29. package/lib-prod/tape-renderer.backend.js +93 -0
  30. package/lib-prod/tape-store.backend.js +94 -0
  31. package/lib-prod/tape.backend.js +75 -0
  32. package/lib-prod/types.backend.js +0 -0
  33. package/lib-prod/utils/content-encoding.backend.js +40 -0
  34. package/lib-prod/utils/headers.backend.js +16 -0
  35. package/lib-prod/utils/media-type.backend.js +54 -0
  36. package/package.json +1 -1
  37. package/websql/package.json +1 -1
  38. package/websql-prod/package.json +1 -1
  39. package/lib-prod/build-info._auto-generated_.ts +0 -27
  40. package/lib-prod/env/env.angular-node-app.ts +0 -66
  41. package/lib-prod/env/env.docs-webapp.ts +0 -66
  42. package/lib-prod/env/env.electron-app.ts +0 -66
  43. package/lib-prod/env/env.mobile-app.ts +0 -66
  44. package/lib-prod/env/env.npm-lib-and-cli-tool.ts +0 -66
  45. package/lib-prod/env/env.vscode-plugin.ts +0 -66
  46. package/lib-prod/env/index.ts +0 -6
  47. package/lib-prod/es6.backend.ts +0 -3
  48. package/lib-prod/features/error-rate.backend.ts +0 -31
  49. package/lib-prod/features/latency.backend.ts +0 -38
  50. package/lib-prod/index._auto-generated_.ts +0 -5
  51. package/lib-prod/index.ts +0 -27
  52. package/lib-prod/lib-info.md +0 -8
  53. package/lib-prod/logger.backend.ts +0 -26
  54. package/lib-prod/migrations/index.ts +0 -2
  55. package/lib-prod/migrations/migrations-info.md +0 -6
  56. package/lib-prod/migrations/migrations_index._auto-generated_.ts +0 -5
  57. package/lib-prod/options.backend.ts +0 -140
  58. package/lib-prod/request-handler.backend.ts +0 -165
  59. package/lib-prod/server.backend.ts +0 -100
  60. package/lib-prod/summary.backend.ts +0 -26
  61. package/lib-prod/talkback-factory.backend.ts +0 -18
  62. package/lib-prod/tape-matcher.backend.ts +0 -113
  63. package/lib-prod/tape-renderer.backend.ts +0 -118
  64. package/lib-prod/tape-store.backend.ts +0 -111
  65. package/lib-prod/tape.backend.ts +0 -93
  66. package/lib-prod/types.backend.ts +0 -55
  67. package/lib-prod/utils/content-encoding.backend.ts +0 -53
  68. package/lib-prod/utils/headers.backend.ts +0 -14
  69. package/lib-prod/utils/media-type.backend.ts +0 -62
@@ -0,0 +1,82 @@
1
+ import RequestHandler from "./request-handler.backend";
2
+ import Summary from "./summary.backend";
3
+ import TapeStore from "./tape-store.backend";
4
+ import * as http from "http";
5
+ import { https, fse } from "tnp-core/lib-prod";
6
+ class TalkbackServer {
7
+ options;
8
+ tapeStore;
9
+ requestHandler;
10
+ closeSignalHandler;
11
+ server;
12
+ closed = false;
13
+ constructor(options) {
14
+ this.options = options;
15
+ this.tapeStore = new TapeStore(this.options);
16
+ this.requestHandler = new RequestHandler(this.tapeStore, this.options);
17
+ this.closeSignalHandler = this.close.bind(this);
18
+ }
19
+ handleRequest(rawReq, res) {
20
+ let reqBody = [];
21
+ rawReq.on("data", (chunk) => {
22
+ reqBody.push(chunk);
23
+ }).on("end", async () => {
24
+ try {
25
+ const req = {
26
+ headers: rawReq.headers,
27
+ url: rawReq.url,
28
+ method: rawReq.method,
29
+ body: Buffer.concat(reqBody)
30
+ };
31
+ const fRes = await this.requestHandler.handle(req);
32
+ res.writeHead(fRes.status, fRes.headers);
33
+ res.end(fRes.body);
34
+ } catch (ex) {
35
+ console.error("Error handling request", ex);
36
+ res.statusCode = 500;
37
+ res.end();
38
+ }
39
+ });
40
+ }
41
+ async start(callback) {
42
+ await this.tapeStore.load();
43
+ const handleRequest = this.handleRequest.bind(this);
44
+ const serverFactory = this.options.https.enabled ? () => {
45
+ const httpsOpts = {
46
+ key: fse.readFileSync(this.options.https.keyPath),
47
+ cert: fse.readFileSync(this.options.https.certPath)
48
+ };
49
+ return https.createServer(httpsOpts, handleRequest);
50
+ } : () => http.createServer(handleRequest);
51
+ this.server = serverFactory();
52
+ console.log(`Starting talkback on ${this.options.port}`);
53
+ this.server.listen(this.options.port, callback);
54
+ process.on("exit", this.closeSignalHandler);
55
+ process.on("SIGINT", this.closeSignalHandler);
56
+ process.on("SIGTERM", this.closeSignalHandler);
57
+ return this.server;
58
+ }
59
+ hasTapeBeenUsed(tapeName) {
60
+ return this.tapeStore.hasTapeBeenUsed(tapeName);
61
+ }
62
+ resetTapeUsage() {
63
+ this.tapeStore.resetTapeUsage();
64
+ }
65
+ close(callback) {
66
+ if (this.closed) {
67
+ return;
68
+ }
69
+ this.closed = true;
70
+ this.server.close(callback);
71
+ process.removeListener("exit", this.closeSignalHandler);
72
+ process.removeListener("SIGINT", this.closeSignalHandler);
73
+ process.removeListener("SIGTERM", this.closeSignalHandler);
74
+ if (this.options.summary) {
75
+ const summary = new Summary(this.tapeStore.tapes, this.options);
76
+ summary.print();
77
+ }
78
+ }
79
+ }
80
+ export {
81
+ TalkbackServer as default
82
+ };
@@ -0,0 +1,24 @@
1
+ class Summary {
2
+ tapes;
3
+ opts;
4
+ constructor(tapes, opts) {
5
+ this.tapes = tapes;
6
+ this.opts = opts;
7
+ }
8
+ print() {
9
+ console.log(`===== SUMMARY (${this.opts.name}) =====`);
10
+ const newTapes = this.tapes.filter((t) => t.new);
11
+ if (newTapes.length > 0) {
12
+ console.log("New tapes:");
13
+ newTapes.forEach((t) => console.log(`- ${t.path}`));
14
+ }
15
+ const unusedTapes = this.tapes.filter((t) => !t.used);
16
+ if (unusedTapes.length > 0) {
17
+ console.log("Unused tapes:");
18
+ unusedTapes.forEach((t) => console.log(`- ${t.path}`));
19
+ }
20
+ }
21
+ }
22
+ export {
23
+ Summary as default
24
+ };
@@ -0,0 +1,19 @@
1
+ import Options from "./options.backend";
2
+ import TapeStore from "./tape-store.backend";
3
+ import TalkbackServer from "./server.backend";
4
+ import RequestHandler from "./request-handler.backend";
5
+ class TalkbackFactory {
6
+ static server(options) {
7
+ const fullOptions = Options.prepare(options);
8
+ return new TalkbackServer(fullOptions);
9
+ }
10
+ static async requestHandler(options) {
11
+ const fullOptions = Options.prepare(options);
12
+ const tapeStore = new TapeStore(fullOptions);
13
+ await tapeStore.load();
14
+ return new RequestHandler(tapeStore, fullOptions);
15
+ }
16
+ }
17
+ export {
18
+ TalkbackFactory as default
19
+ };
@@ -0,0 +1,95 @@
1
+ import ContentEncoding from "./utils/content-encoding.backend";
2
+ import MediaType from "./utils/media-type.backend";
3
+ import { ___NS__isEqual } from "tnp-core/lib-prod";
4
+ class TapeMatcher {
5
+ tape;
6
+ options;
7
+ constructor(tape, options) {
8
+ this.tape = tape;
9
+ this.options = options;
10
+ }
11
+ sameAs(otherTape) {
12
+ const otherReq = otherTape.req;
13
+ const req = this.tape.req;
14
+ if (!this.isSameUrl(req, otherReq)) {
15
+ return false;
16
+ }
17
+ if (!this.isSameMethod(req, otherReq)) {
18
+ return false;
19
+ }
20
+ if (!this.isSameHeaders(req, otherReq)) {
21
+ return false;
22
+ }
23
+ return this.options.ignoreBody || this.isSameBody(req, otherReq);
24
+ }
25
+ isSameBody(req, otherReq) {
26
+ const mediaType = new MediaType(req);
27
+ const contentEncoding = new ContentEncoding(req);
28
+ let sameBody;
29
+ if (contentEncoding.isUncompressed() && mediaType.isJSON() && req.body.length > 0 && otherReq.body.length > 0) {
30
+ const parsedReqBody = JSON.parse(req.body.toString());
31
+ const parsedOtherReqBody = JSON.parse(otherReq.body.toString());
32
+ sameBody = ___NS__isEqual(parsedReqBody, parsedOtherReqBody);
33
+ } else {
34
+ sameBody = req.body.equals(otherReq.body);
35
+ }
36
+ if (!sameBody) {
37
+ if (!this.options.bodyMatcher) {
38
+ this.options.logger.debug(`Not same BODY ${req.body} vs ${otherReq.body}`);
39
+ return false;
40
+ }
41
+ const bodyMatches = this.options.bodyMatcher(this.tape, otherReq);
42
+ if (!bodyMatches) {
43
+ this.options.logger.debug(`Not same bodyMatcher ${req.body} vs ${otherReq.body}`);
44
+ return false;
45
+ }
46
+ }
47
+ return true;
48
+ }
49
+ isSameHeaders(req, otherReq) {
50
+ const currentHeadersLength = Object.keys(req.headers).length;
51
+ const otherHeadersLength = Object.keys(otherReq.headers).length;
52
+ const sameNumberOfHeaders = currentHeadersLength === otherHeadersLength;
53
+ if (!sameNumberOfHeaders) {
54
+ this.options.logger.debug(`Not same #HEADERS ${JSON.stringify(req.headers)} vs ${JSON.stringify(otherReq.headers)}`);
55
+ return false;
56
+ }
57
+ let headersSame = true;
58
+ Object.keys(req.headers).forEach((k) => {
59
+ const entryHeader = req.headers[k];
60
+ const header = otherReq.headers[k];
61
+ headersSame = headersSame && entryHeader === header;
62
+ });
63
+ if (!headersSame) {
64
+ this.options.logger.debug(`Not same HEADERS values ${JSON.stringify(req.headers)} vs ${JSON.stringify(otherReq.headers)}`);
65
+ return false;
66
+ }
67
+ return true;
68
+ }
69
+ isSameMethod(req, otherReq) {
70
+ const sameMethod = req.method === otherReq.method;
71
+ if (!sameMethod) {
72
+ this.options.logger.debug(`Not same METHOD ${req.method} vs ${otherReq.method}`);
73
+ return false;
74
+ }
75
+ return true;
76
+ }
77
+ isSameUrl(req, otherReq) {
78
+ const sameURL = req.url === otherReq.url;
79
+ if (!sameURL) {
80
+ if (!this.options.urlMatcher) {
81
+ this.options.logger.debug(`Not same URL ${req.url} vs ${otherReq.url}`);
82
+ return false;
83
+ }
84
+ const urlMatches = this.options.urlMatcher(this.tape, otherReq);
85
+ if (!urlMatches) {
86
+ this.options.logger.debug(`Not same urlMatcher ${req.url} vs ${otherReq.url}`);
87
+ return false;
88
+ }
89
+ }
90
+ return true;
91
+ }
92
+ }
93
+ export {
94
+ TapeMatcher as default
95
+ };
@@ -0,0 +1,93 @@
1
+ import Headers from "./utils/headers.backend";
2
+ import MediaType from "./utils/media-type.backend";
3
+ import Tape from "./tape.backend";
4
+ import ContentEncoding from "./utils/content-encoding.backend";
5
+ import * as bufferShim from "buffer-shims";
6
+ class TapeRenderer {
7
+ tape;
8
+ constructor(tape) {
9
+ this.tape = tape;
10
+ }
11
+ static async fromStore(raw, options) {
12
+ const req = { ...raw.req };
13
+ req.body = await this.prepareBody(raw, req, req.body, "req");
14
+ const tape = new Tape(req, options);
15
+ tape.meta = { ...raw.meta };
16
+ const baseRes = { ...raw.res };
17
+ const resBody = await this.prepareBody(tape, baseRes, baseRes.body, "res");
18
+ tape.res = {
19
+ ...baseRes,
20
+ body: resBody
21
+ };
22
+ return tape;
23
+ }
24
+ static async prepareBody(tape, reqResObj, rawBody, metaPrefix) {
25
+ const contentEncoding = new ContentEncoding(reqResObj);
26
+ const isTapeUncompressed = tape.meta[metaPrefix + "Uncompressed"];
27
+ const isTapeHumanReadable = tape.meta[metaPrefix + "HumanReadable"];
28
+ const isTapeInPlainText = isTapeUncompressed || contentEncoding.isUncompressed();
29
+ if (isTapeHumanReadable && isTapeInPlainText) {
30
+ const mediaType = new MediaType(reqResObj);
31
+ let bufferContent = rawBody;
32
+ const isResAnObject = typeof bufferContent === "object";
33
+ if (isResAnObject && mediaType.isJSON()) {
34
+ bufferContent = JSON.stringify(bufferContent, null, 2);
35
+ }
36
+ if (Headers.read(reqResObj.headers, "content-length")) {
37
+ Headers.write(reqResObj.headers, "content-length", Buffer.byteLength(bufferContent).toString(), metaPrefix);
38
+ }
39
+ if (isTapeUncompressed) {
40
+ return await contentEncoding.compressedBody(bufferContent);
41
+ }
42
+ return bufferShim.from(bufferContent);
43
+ } else {
44
+ return bufferShim.from(rawBody, "base64");
45
+ }
46
+ }
47
+ async render() {
48
+ const reqBody = await this.bodyFor(this.tape.req, "req");
49
+ const resBody = await this.bodyFor(this.tape.res, "res");
50
+ return {
51
+ meta: this.tape.meta,
52
+ req: {
53
+ ...this.tape.req,
54
+ body: reqBody
55
+ },
56
+ res: {
57
+ ...this.tape.res,
58
+ body: resBody
59
+ }
60
+ };
61
+ }
62
+ async bodyFor(reqResObj, metaPrefix) {
63
+ const mediaType = new MediaType(reqResObj);
64
+ const contentEncoding = new ContentEncoding(reqResObj);
65
+ const bodyLength = reqResObj.body.length;
66
+ const isUncompressed = contentEncoding.isUncompressed();
67
+ const contentEncodingSupported = isUncompressed || contentEncoding.supportedAlgorithm();
68
+ if (mediaType.isHumanReadable() && contentEncodingSupported && bodyLength > 0) {
69
+ this.tape.meta[metaPrefix + "HumanReadable"] = true;
70
+ let body = reqResObj.body;
71
+ if (!isUncompressed) {
72
+ this.tape.meta[metaPrefix + "Uncompressed"] = true;
73
+ body = await contentEncoding.uncompressedBody(body);
74
+ }
75
+ const rawBody = body.toString("utf8");
76
+ if (mediaType.isJSON()) {
77
+ try {
78
+ const parsed = JSON.parse(rawBody);
79
+ return parsed;
80
+ } catch (error) {
81
+ return rawBody;
82
+ }
83
+ } else {
84
+ return rawBody;
85
+ }
86
+ } else {
87
+ return reqResObj.body.toString("base64");
88
+ }
89
+ }
90
+ }
91
+ export {
92
+ TapeRenderer as default
93
+ };
@@ -0,0 +1,94 @@
1
+ import { fse, path, json5, mkdirp } from "tnp-core/lib-prod";
2
+ import Tape from "./tape.backend";
3
+ import TapeMatcher from "./tape-matcher.backend";
4
+ import TapeRenderer from "./tape-renderer.backend";
5
+ class TapeStore {
6
+ path;
7
+ options;
8
+ tapes;
9
+ constructor(options) {
10
+ this.path = path.normalize(options.path + "/");
11
+ this.options = options;
12
+ this.tapes = [];
13
+ }
14
+ async load() {
15
+ mkdirp.sync(this.path);
16
+ await this.loadTapesAtDir(this.path);
17
+ console.log(`Loaded ${this.tapes.length} tapes`);
18
+ }
19
+ async loadTapesAtDir(directory) {
20
+ const items = fse.readdirSync(directory);
21
+ for (let i = 0; i < items.length; i++) {
22
+ const filename = items[i];
23
+ const fullPath = `${directory}${filename}`;
24
+ const stat = fse.statSync(fullPath);
25
+ if (!stat.isDirectory()) {
26
+ try {
27
+ const data = fse.readFileSync(fullPath, "utf8");
28
+ const raw = json5.parse(data);
29
+ const tape = await Tape.fromStore(raw, this.options);
30
+ tape.path = filename;
31
+ this.tapes.push(tape);
32
+ } catch (e) {
33
+ console.log(`Error reading tape ${fullPath}`, e.message);
34
+ }
35
+ } else {
36
+ this.loadTapesAtDir(fullPath + "/");
37
+ }
38
+ }
39
+ }
40
+ find(newTape) {
41
+ const foundTape = this.tapes.find((t) => {
42
+ this.options.logger.debug(`Comparing against tape ${t.path}`);
43
+ return new TapeMatcher(t, this.options).sameAs(newTape);
44
+ });
45
+ if (foundTape) {
46
+ foundTape.used = true;
47
+ this.options.logger.log(`Found matching tape for ${newTape.req.url} at ${foundTape.path}`);
48
+ return foundTape;
49
+ }
50
+ }
51
+ async save(tape) {
52
+ tape.new = true;
53
+ tape.used = true;
54
+ const tapePath = tape.path;
55
+ let fullFilename;
56
+ if (tapePath) {
57
+ fullFilename = path.join(this.path, tapePath);
58
+ } else {
59
+ this.tapes.push(tape);
60
+ fullFilename = this.createTapePath(tape);
61
+ tape.path = path.relative(this.path, fullFilename);
62
+ }
63
+ this.options.logger.log(`Saving request ${tape.req.url} at ${tape.path}`);
64
+ const tapeRenderer = new TapeRenderer(tape);
65
+ const toSave = await tapeRenderer.render();
66
+ fse.writeFileSync(fullFilename, json5.stringify(toSave, null, 4));
67
+ }
68
+ currentTapeId() {
69
+ return this.tapes.length;
70
+ }
71
+ hasTapeBeenUsed(tapeName) {
72
+ return this.tapes.some((t) => t.used && t.path === tapeName);
73
+ }
74
+ resetTapeUsage() {
75
+ return this.tapes.forEach((t) => t.used = false);
76
+ }
77
+ createTapePath(tape) {
78
+ const currentTapeId = this.currentTapeId();
79
+ let tapePath = `unnamed-${currentTapeId}.json5`;
80
+ if (this.options.tapeNameGenerator) {
81
+ tapePath = this.options.tapeNameGenerator(currentTapeId, tape);
82
+ }
83
+ let result = path.normalize(path.join(this.options.path, tapePath));
84
+ if (!result.endsWith(".json5")) {
85
+ result = `${result}.json5`;
86
+ }
87
+ const dir = path.dirname(result);
88
+ mkdirp.sync(dir);
89
+ return result;
90
+ }
91
+ }
92
+ export {
93
+ TapeStore as default
94
+ };
@@ -0,0 +1,75 @@
1
+ import MediaType from "./utils/media-type.backend";
2
+ import TapeRenderer from "./tape-renderer.backend";
3
+ import ContentEncoding from "./utils/content-encoding.backend";
4
+ import * as URL from "url";
5
+ import * as querystring from "querystring";
6
+ class Tape {
7
+ req;
8
+ res;
9
+ options;
10
+ queryParamsToIgnore;
11
+ meta;
12
+ path;
13
+ new = false;
14
+ used = false;
15
+ constructor(req, options) {
16
+ this.req = { ...req };
17
+ this.options = options;
18
+ this.normalizeBody();
19
+ this.cleanupHeaders();
20
+ this.queryParamsToIgnore = this.options.ignoreQueryParams;
21
+ this.cleanupQueryParams();
22
+ this.meta = {
23
+ createdAt: /* @__PURE__ */ new Date(),
24
+ host: this.options.host
25
+ };
26
+ }
27
+ static async fromStore(raw, options) {
28
+ return TapeRenderer.fromStore(raw, options);
29
+ }
30
+ cleanupHeaders() {
31
+ const newHeaders = { ...this.req.headers };
32
+ this.options.ignoreHeaders.forEach((h) => delete newHeaders[h]);
33
+ this.req = {
34
+ ...this.req,
35
+ headers: newHeaders
36
+ };
37
+ }
38
+ cleanupQueryParams() {
39
+ if (this.queryParamsToIgnore.length === 0) {
40
+ return;
41
+ }
42
+ const url = URL.parse(this.req.url, true);
43
+ if (!url.search) {
44
+ return;
45
+ }
46
+ const query = { ...url.query };
47
+ this.queryParamsToIgnore.forEach((q) => delete query[q]);
48
+ const newQuery = querystring.stringify(query);
49
+ if (newQuery) {
50
+ url.query = query;
51
+ url.search = "?" + newQuery;
52
+ } else {
53
+ url.query = null;
54
+ url.search = null;
55
+ }
56
+ this.req.url = URL.format(url);
57
+ }
58
+ normalizeBody() {
59
+ const mediaType = new MediaType(this.req);
60
+ const contentEncoding = new ContentEncoding(this.req);
61
+ if (contentEncoding.isUncompressed() && mediaType.isJSON() && this.req.body.length > 0) {
62
+ this.req.body = Buffer.from(JSON.stringify(JSON.parse(this.req.body.toString()), null, 2));
63
+ }
64
+ }
65
+ async clone() {
66
+ const tapeRenderer = new TapeRenderer(this);
67
+ const raw = await tapeRenderer.render();
68
+ return Tape.fromStore(raw, this.options);
69
+ }
70
+ }
71
+ var tape_backend_default = Tape;
72
+ export {
73
+ Tape,
74
+ tape_backend_default as default
75
+ };
File without changes
@@ -0,0 +1,40 @@
1
+ const zlib = require("zlib");
2
+ import Headers from "./headers.backend";
3
+ const ALGORITHMS = {
4
+ gzip: { compress: zlib.gzipSync, uncompress: zlib.gunzipSync },
5
+ deflate: { compress: zlib.deflateSync, uncompress: zlib.inflateSync }
6
+ };
7
+ class ContentEncoding {
8
+ reqRes;
9
+ constructor(reqRes) {
10
+ this.reqRes = reqRes;
11
+ }
12
+ isUncompressed() {
13
+ const contentEncoding = this.contentEncoding();
14
+ return !contentEncoding || contentEncoding === "identity";
15
+ }
16
+ supportedAlgorithm() {
17
+ const contentEncoding = this.contentEncoding();
18
+ return Object.keys(ALGORITHMS).includes(contentEncoding);
19
+ }
20
+ contentEncoding() {
21
+ return Headers.read(this.reqRes.headers, "content-encoding");
22
+ }
23
+ async uncompressedBody(body) {
24
+ const contentEncoding = this.contentEncoding();
25
+ if (!this.supportedAlgorithm()) {
26
+ throw new Error(`Unsupported content-encoding ${contentEncoding}`);
27
+ }
28
+ return ALGORITHMS[contentEncoding].uncompress(body);
29
+ }
30
+ async compressedBody(body) {
31
+ const contentEncoding = this.contentEncoding();
32
+ if (!this.supportedAlgorithm()) {
33
+ throw new Error(`Unsupported content-encoding ${contentEncoding}`);
34
+ }
35
+ return ALGORITHMS[contentEncoding].compress(body);
36
+ }
37
+ }
38
+ export {
39
+ ContentEncoding as default
40
+ };
@@ -0,0 +1,16 @@
1
+ class Headers {
2
+ static read(headers, headerName) {
3
+ const value = headers[headerName];
4
+ if (Array.isArray(value)) {
5
+ return value[0];
6
+ } else {
7
+ return value;
8
+ }
9
+ }
10
+ static write(headers, headerName, value, type) {
11
+ headers[headerName] = type === "req" ? value : [value];
12
+ }
13
+ }
14
+ export {
15
+ Headers as default
16
+ };
@@ -0,0 +1,54 @@
1
+ import { ___NS__merge } from "tnp-core/lib-prod";
2
+ import Headers from "./headers.backend";
3
+ const contentTypeParser = require("content-type");
4
+ const equals = (to) => (contentType) => to == contentType;
5
+ const jsonTypes = [
6
+ equals("application/json"),
7
+ (contentType) => contentType.startsWith("application/") && contentType.endsWith("+json")
8
+ ];
9
+ const humanReadableContentTypes = [
10
+ equals("application/javascript"),
11
+ equals("text/css"),
12
+ equals("text/html"),
13
+ equals("text/javascript"),
14
+ equals("text/plain"),
15
+ ...jsonTypes
16
+ ];
17
+ class MediaType {
18
+ htmlReqRes;
19
+ constructor(htmlReqRes) {
20
+ this.htmlReqRes = htmlReqRes;
21
+ }
22
+ isHumanReadable() {
23
+ const contentType = this.contentType();
24
+ if (!contentType) {
25
+ return false;
26
+ }
27
+ return humanReadableContentTypes.some((comparator) => comparator(contentType));
28
+ }
29
+ isJSON() {
30
+ const contentType = this.contentType();
31
+ if (!contentType) {
32
+ return false;
33
+ }
34
+ const result = jsonTypes.some((comparator) => comparator("application/json"));
35
+ return result;
36
+ }
37
+ contentType() {
38
+ const contentTypeHeader = Headers.read(this.headers(), "content-type");
39
+ if (!contentTypeHeader) {
40
+ return null;
41
+ }
42
+ const parsedContentType = contentTypeParser.parse(contentTypeHeader);
43
+ return parsedContentType.type;
44
+ }
45
+ headers() {
46
+ return ___NS__merge(this.htmlReqRes.headers, {
47
+ "content-type": "application/json"
48
+ });
49
+ }
50
+ }
51
+ export {
52
+ MediaType as default,
53
+ jsonTypes
54
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-talkback",
3
- "version": "21.0.16",
3
+ "version": "21.0.17",
4
4
  "scripts": {
5
5
  "build": "node tools/build.js",
6
6
  "ci": "yarn ts-check && yarn test && yarn build && USE_DIST=1 yarn test",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-talkback/websql",
3
- "version": "21.0.16",
3
+ "version": "21.0.17",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.0",
6
6
  "@angular/core": "^21.0.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-talkback/websql-prod",
3
- "version": "21.0.16",
3
+ "version": "21.0.17",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.0",
6
6
  "@angular/core": "^21.0.0"
@@ -1,27 +0,0 @@
1
- // THIS FILE IS GENERATED - DO NOT MODIFY
2
- /**
3
- * Autogenerated by current cli tool
4
- */
5
- export const BUILD_FRAMEWORK_CLI_NAME = 'tnp';
6
- /**
7
- * This value can be change in taon.jsonc (appId)
8
- */
9
- export const APP_ID = 'com.domain.example.ng-talkback';
10
- /**
11
- * Autogenerated by current cli tool
12
- */
13
- export const BUILD_BASE_HREF = '';
14
- /**
15
- * This value can be change in taon.jsonc (overrideNpmName)
16
- */
17
- export const PROJECT_NPM_NAME = 'ng-talkback';
18
- /**
19
- * Taon version from you project taon.json
20
- */
21
- export const CURRENT_PACKAGE_TAON_VERSION = 'v21';
22
- /**
23
- * Autogenerated by current cli tool. Use *tnp release* to bump version.
24
- */
25
- export const CURRENT_PACKAGE_VERSION = '21.0.16';
26
- // THIS FILE IS GENERATED - DO NOT MODIFY
27
-