@pallasoft/ps-utilities 2.18.0 → 2.19.0

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 (104) hide show
  1. package/bin/ps-worker-bundle-check.js +4 -0
  2. package/dist/build/index.d.ts +6 -0
  3. package/dist/build/index.js +18 -0
  4. package/dist/build/worker-bundle-cli.d.ts +5 -0
  5. package/dist/build/worker-bundle-cli.js +40 -0
  6. package/dist/build/worker-bundle-service.d.ts +10 -0
  7. package/dist/build/worker-bundle-service.js +100 -0
  8. package/dist/esm/build/index.js +2 -0
  9. package/dist/esm/build/worker-bundle-cli.js +33 -0
  10. package/dist/esm/build/worker-bundle-service.js +80 -0
  11. package/dist/esm/client/constants/device-config.js +6 -0
  12. package/dist/esm/client/debounce-service.js +34 -0
  13. package/dist/esm/client/device-service.js +15 -0
  14. package/dist/esm/client/http-service.js +51 -0
  15. package/dist/esm/client/index.js +3 -0
  16. package/dist/esm/common/amount-service.js +37 -0
  17. package/dist/esm/common/base64-service.js +17 -0
  18. package/dist/esm/common/color-service.js +8 -0
  19. package/dist/esm/common/constants/amount-config.js +8 -0
  20. package/dist/esm/common/constants/amount-direction.js +6 -0
  21. package/dist/esm/common/constants/email-preview-config.js +30 -0
  22. package/dist/esm/common/constants/error-response-config.js +4 -0
  23. package/dist/esm/common/constants/file-size-config.js +5 -0
  24. package/dist/esm/common/constants/http-auth-scheme.js +3 -0
  25. package/dist/esm/common/constants/http-content-type.js +8 -0
  26. package/dist/esm/common/constants/http-header.js +23 -0
  27. package/dist/esm/common/constants/http-method.js +10 -0
  28. package/dist/esm/common/constants/index.js +19 -0
  29. package/dist/esm/common/constants/phone-config.js +6 -0
  30. package/dist/esm/common/constants/portable-text-config.js +17 -0
  31. package/dist/esm/common/constants/postal-code-formats.js +10 -0
  32. package/dist/esm/common/constants/relative-time-config.js +11 -0
  33. package/dist/esm/common/constants/request-client-config.js +6 -0
  34. package/dist/esm/common/constants/signed-token-config.js +11 -0
  35. package/dist/esm/common/constants/socket-token-config.js +4 -0
  36. package/dist/esm/common/constants/user-agent-config.js +18 -0
  37. package/dist/esm/common/constants/user-token-config.js +5 -0
  38. package/dist/esm/common/constants/validation-config.js +8 -0
  39. package/dist/esm/common/crypto-service.js +128 -0
  40. package/dist/esm/common/date-service.js +101 -0
  41. package/dist/esm/common/email-preview-service.js +142 -0
  42. package/dist/esm/common/encrypted-fields-service.js +49 -0
  43. package/dist/esm/common/envelope-crypto-service.js +48 -0
  44. package/dist/esm/common/error-response-service.js +20 -0
  45. package/dist/esm/common/file-size-service.js +15 -0
  46. package/dist/esm/common/index.js +27 -0
  47. package/dist/esm/common/json-service.js +16 -0
  48. package/dist/esm/common/number-format-service.js +22 -0
  49. package/dist/esm/common/phone-service.js +70 -0
  50. package/dist/esm/common/portable-text-service.js +97 -0
  51. package/dist/esm/common/postal-code-service.js +34 -0
  52. package/dist/esm/common/recaptcha-service.js +23 -0
  53. package/dist/esm/common/relative-time-service.js +18 -0
  54. package/dist/esm/common/request-client-service.js +20 -0
  55. package/dist/esm/common/signed-token-service.js +111 -0
  56. package/dist/esm/common/socket-token-service.js +22 -0
  57. package/dist/esm/common/string-service.js +5 -0
  58. package/dist/esm/common/transform-service.js +12 -0
  59. package/dist/esm/common/url-service.js +15 -0
  60. package/dist/esm/common/user-agent-service.js +26 -0
  61. package/dist/esm/common/user-token-service.js +59 -0
  62. package/dist/esm/common/validation-service.js +29 -0
  63. package/dist/esm/index.js +4 -0
  64. package/dist/esm/models/coded-error-data.js +1 -0
  65. package/dist/esm/models/device-data.js +1 -0
  66. package/dist/esm/models/email-preview-input.js +1 -0
  67. package/dist/esm/models/encrypted-value-payload.js +1 -0
  68. package/dist/esm/models/json-value-guard.js +1 -0
  69. package/dist/esm/models/phone-country-data.js +1 -0
  70. package/dist/esm/models/phone-display-data.js +1 -0
  71. package/dist/esm/models/postal-code-format-data.js +1 -0
  72. package/dist/esm/models/relative-time-options.js +1 -0
  73. package/dist/esm/models/request-client-data.js +1 -0
  74. package/dist/esm/models/request-client-options.js +1 -0
  75. package/dist/esm/models/signed-token-header.js +1 -0
  76. package/dist/esm/models/signed-token-key-pair.js +1 -0
  77. package/dist/esm/models/socket-client-options.js +1 -0
  78. package/dist/esm/models/socket-token-claims.js +1 -0
  79. package/dist/esm/models/user-token-claims.js +1 -0
  80. package/dist/esm/models/user-token-issue-options.js +1 -0
  81. package/dist/esm/models/user-token-request.js +1 -0
  82. package/dist/esm/models/user-token-subject.js +1 -0
  83. package/dist/esm/models/user-token-verify-options.js +1 -0
  84. package/dist/esm/models/worker-bundle-budget-data.js +1 -0
  85. package/dist/esm/models/worker-bundle-file-data.js +1 -0
  86. package/dist/esm/models/worker-bundle-options-data.js +1 -0
  87. package/dist/esm/models/worker-bundle-report-data.js +1 -0
  88. package/dist/esm/package.json +1 -0
  89. package/dist/esm/server/file-service.js +41 -0
  90. package/dist/esm/server/index.js +2 -0
  91. package/dist/esm/server/timing-safe-service.js +8 -0
  92. package/dist/esm/sockets/index.js +1 -0
  93. package/dist/esm/sockets/socket-client-service.js +10 -0
  94. package/dist/index.d.ts +2 -4
  95. package/dist/index.js +3 -5
  96. package/dist/models/worker-bundle-budget-data.d.ts +5 -0
  97. package/dist/models/worker-bundle-budget-data.js +2 -0
  98. package/dist/models/worker-bundle-file-data.d.ts +6 -0
  99. package/dist/models/worker-bundle-file-data.js +2 -0
  100. package/dist/models/worker-bundle-options-data.d.ts +6 -0
  101. package/dist/models/worker-bundle-options-data.js +2 -0
  102. package/dist/models/worker-bundle-report-data.d.ts +8 -0
  103. package/dist/models/worker-bundle-report-data.js +2 -0
  104. package/package.json +16 -2
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ process.exitCode = require('../dist/build/worker-bundle-cli').WorkerBundleCli.run(
3
+ process.argv.slice(2)
4
+ );
@@ -0,0 +1,6 @@
1
+ export type { WorkerBundleBudgetData } from '../models/worker-bundle-budget-data';
2
+ export type { WorkerBundleFileData } from '../models/worker-bundle-file-data';
3
+ export type { WorkerBundleOptionsData } from '../models/worker-bundle-options-data';
4
+ export type { WorkerBundleReportData } from '../models/worker-bundle-report-data';
5
+ export * from './worker-bundle-cli';
6
+ export * from './worker-bundle-service';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./worker-bundle-cli"), exports);
18
+ __exportStar(require("./worker-bundle-service"), exports);
@@ -0,0 +1,5 @@
1
+ import type { WorkerBundleOptionsData } from '../models/worker-bundle-options-data';
2
+ export declare class WorkerBundleCli {
3
+ static options(argv: string[]): WorkerBundleOptionsData;
4
+ static run(argv: string[]): number;
5
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkerBundleCli = void 0;
4
+ var fs_1 = require("fs");
5
+ var path_1 = require("path");
6
+ var worker_bundle_service_1 = require("./worker-bundle-service");
7
+ var WorkerBundleCli = /** @class */ (function () {
8
+ function WorkerBundleCli() {
9
+ }
10
+ WorkerBundleCli.options = function (argv) {
11
+ var read = function (name, fallback) {
12
+ var index = argv.indexOf("--".concat(name));
13
+ return index === -1 || index + 1 >= argv.length ? fallback : argv[index + 1];
14
+ };
15
+ return {
16
+ budget: {
17
+ eagerKb: Number(read('eager-kb', '0')),
18
+ gzipKb: Number(read('gzip-kb', '0')),
19
+ totalKb: Number(read('total-kb', '0')),
20
+ },
21
+ directory: read('dir', 'build/server'),
22
+ entry: read('entry', 'index.js'),
23
+ };
24
+ };
25
+ WorkerBundleCli.run = function (argv) {
26
+ var options = WorkerBundleCli.options(argv);
27
+ if (!(0, fs_1.existsSync)((0, path_1.resolve)(options.directory, options.entry))) {
28
+ console.error("No Worker build at ".concat((0, path_1.resolve)(options.directory, options.entry), "; build first."));
29
+ return 1;
30
+ }
31
+ var report = worker_bundle_service_1.WorkerBundleService.report(options.directory, options.entry, options.budget);
32
+ worker_bundle_service_1.WorkerBundleService.summary(report, options.budget).forEach(function (line) { return console.log(line); });
33
+ if (report.failures.length === 0)
34
+ return 0;
35
+ console.error("Worker bundle over budget (".concat(report.failures.join(', '), "): keep browser-only and heavy libraries out of the server build."));
36
+ return 1;
37
+ };
38
+ return WorkerBundleCli;
39
+ }());
40
+ exports.WorkerBundleCli = WorkerBundleCli;
@@ -0,0 +1,10 @@
1
+ import type { WorkerBundleBudgetData } from '../models/worker-bundle-budget-data';
2
+ import type { WorkerBundleReportData } from '../models/worker-bundle-report-data';
3
+ export declare class WorkerBundleService {
4
+ static staticImports(source: string): string[];
5
+ static scriptFiles(directory: string): string[];
6
+ static eagerFiles(entry: string): string[];
7
+ static kilobytes(bytes: number): number;
8
+ static report(directory: string, entry: string, budget: WorkerBundleBudgetData): WorkerBundleReportData;
9
+ static summary(report: WorkerBundleReportData, budget: WorkerBundleBudgetData): string[];
10
+ }
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkerBundleService = void 0;
4
+ var fs_1 = require("fs");
5
+ var path_1 = require("path");
6
+ var zlib_1 = require("zlib");
7
+ var WorkerBundleService = /** @class */ (function () {
8
+ function WorkerBundleService() {
9
+ }
10
+ WorkerBundleService.staticImports = function (source) {
11
+ var pattern = /\b(?:import|from)\s*["'](\.{1,2}\/[^"']+)["']/g;
12
+ var specifiers = [];
13
+ var match = pattern.exec(source);
14
+ while (match !== null) {
15
+ specifiers.push(match[1]);
16
+ match = pattern.exec(source);
17
+ }
18
+ return specifiers;
19
+ };
20
+ WorkerBundleService.scriptFiles = function (directory) {
21
+ return (0, fs_1.readdirSync)(directory).reduce(function (files, name) {
22
+ var path = (0, path_1.join)(directory, name);
23
+ if ((0, fs_1.statSync)(path).isDirectory())
24
+ return files.concat(WorkerBundleService.scriptFiles(path));
25
+ return /\.(m?js|wasm)$/.test(name) ? files.concat(path) : files;
26
+ }, []);
27
+ };
28
+ WorkerBundleService.eagerFiles = function (entry) {
29
+ var seen = [];
30
+ var queue = [entry];
31
+ var _loop_1 = function () {
32
+ var file = queue.pop();
33
+ if (seen.indexOf(file) === -1 && (0, fs_1.existsSync)(file)) {
34
+ seen.push(file);
35
+ WorkerBundleService.staticImports((0, fs_1.readFileSync)(file, 'utf8')).forEach(function (specifier) {
36
+ return queue.push((0, path_1.resolve)((0, path_1.dirname)(file), specifier));
37
+ });
38
+ }
39
+ };
40
+ while (queue.length > 0) {
41
+ _loop_1();
42
+ }
43
+ return seen;
44
+ };
45
+ WorkerBundleService.kilobytes = function (bytes) {
46
+ return Math.round(bytes / 1024);
47
+ };
48
+ WorkerBundleService.report = function (directory, entry, budget) {
49
+ var eager = WorkerBundleService.eagerFiles((0, path_1.resolve)(directory, entry));
50
+ var files = WorkerBundleService.scriptFiles((0, path_1.resolve)(directory)).map(function (path) {
51
+ var content = (0, fs_1.readFileSync)(path);
52
+ return {
53
+ file: (0, path_1.relative)((0, path_1.resolve)(directory), path),
54
+ gzipBytes: (0, zlib_1.gzipSync)(content).length,
55
+ isEager: eager.indexOf(path) !== -1,
56
+ sizeBytes: content.length,
57
+ };
58
+ });
59
+ var eagerBytes = files
60
+ .filter(function (file) { return file.isEager; })
61
+ .reduce(function (sum, file) { return sum + file.sizeBytes; }, 0);
62
+ var totalBytes = files.reduce(function (sum, file) { return sum + file.sizeBytes; }, 0);
63
+ var gzipBytes = files.reduce(function (sum, file) { return sum + file.gzipBytes; }, 0);
64
+ var checks = [
65
+ ['eager', eagerBytes, budget.eagerKb],
66
+ ['total', totalBytes, budget.totalKb],
67
+ ['gzip', gzipBytes, budget.gzipKb],
68
+ ];
69
+ return {
70
+ eagerBytes: eagerBytes,
71
+ failures: checks
72
+ .filter(function (_a) {
73
+ var bytes = _a[1], limit = _a[2];
74
+ return limit > 0 && WorkerBundleService.kilobytes(bytes) > limit;
75
+ })
76
+ .map(function (_a) {
77
+ var label = _a[0];
78
+ return label;
79
+ }),
80
+ files: files.sort(function (a, b) { return b.sizeBytes - a.sizeBytes; }),
81
+ gzipBytes: gzipBytes,
82
+ totalBytes: totalBytes,
83
+ };
84
+ };
85
+ WorkerBundleService.summary = function (report, budget) {
86
+ var limit = function (value) { return (value > 0 ? " / budget ".concat(value, " KB") : ''); };
87
+ return report.files
88
+ .slice(0, 12)
89
+ .map(function (file) {
90
+ return "".concat(String(WorkerBundleService.kilobytes(file.sizeBytes)).padStart(7), " KB ").concat(file.isEager ? 'eager' : 'lazy ', " ").concat(file.file);
91
+ })
92
+ .concat([
93
+ "eager (evaluated at startup): ".concat(WorkerBundleService.kilobytes(report.eagerBytes), " KB").concat(limit(budget.eagerKb)),
94
+ "total server JS: ".concat(WorkerBundleService.kilobytes(report.totalBytes), " KB").concat(limit(budget.totalKb)),
95
+ "total gzip (upload size): ".concat(WorkerBundleService.kilobytes(report.gzipBytes), " KB").concat(limit(budget.gzipKb)),
96
+ ]);
97
+ };
98
+ return WorkerBundleService;
99
+ }());
100
+ exports.WorkerBundleService = WorkerBundleService;
@@ -0,0 +1,2 @@
1
+ export * from './worker-bundle-cli';
2
+ export * from './worker-bundle-service';
@@ -0,0 +1,33 @@
1
+ import { existsSync } from 'fs';
2
+ import { resolve } from 'path';
3
+ import { WorkerBundleService } from './worker-bundle-service';
4
+ export class WorkerBundleCli {
5
+ static options(argv) {
6
+ const read = (name, fallback) => {
7
+ const index = argv.indexOf(`--${name}`);
8
+ return index === -1 || index + 1 >= argv.length ? fallback : argv[index + 1];
9
+ };
10
+ return {
11
+ budget: {
12
+ eagerKb: Number(read('eager-kb', '0')),
13
+ gzipKb: Number(read('gzip-kb', '0')),
14
+ totalKb: Number(read('total-kb', '0')),
15
+ },
16
+ directory: read('dir', 'build/server'),
17
+ entry: read('entry', 'index.js'),
18
+ };
19
+ }
20
+ static run(argv) {
21
+ const options = WorkerBundleCli.options(argv);
22
+ if (!existsSync(resolve(options.directory, options.entry))) {
23
+ console.error(`No Worker build at ${resolve(options.directory, options.entry)}; build first.`);
24
+ return 1;
25
+ }
26
+ const report = WorkerBundleService.report(options.directory, options.entry, options.budget);
27
+ WorkerBundleService.summary(report, options.budget).forEach((line) => console.log(line));
28
+ if (report.failures.length === 0)
29
+ return 0;
30
+ console.error(`Worker bundle over budget (${report.failures.join(', ')}): keep browser-only and heavy libraries out of the server build.`);
31
+ return 1;
32
+ }
33
+ }
@@ -0,0 +1,80 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
2
+ import { dirname, join, relative, resolve } from 'path';
3
+ import { gzipSync } from 'zlib';
4
+ export class WorkerBundleService {
5
+ static staticImports(source) {
6
+ const pattern = /\b(?:import|from)\s*["'](\.{1,2}\/[^"']+)["']/g;
7
+ const specifiers = [];
8
+ let match = pattern.exec(source);
9
+ while (match !== null) {
10
+ specifiers.push(match[1]);
11
+ match = pattern.exec(source);
12
+ }
13
+ return specifiers;
14
+ }
15
+ static scriptFiles(directory) {
16
+ return readdirSync(directory).reduce((files, name) => {
17
+ const path = join(directory, name);
18
+ if (statSync(path).isDirectory())
19
+ return files.concat(WorkerBundleService.scriptFiles(path));
20
+ return /\.(m?js|wasm)$/.test(name) ? files.concat(path) : files;
21
+ }, []);
22
+ }
23
+ static eagerFiles(entry) {
24
+ const seen = [];
25
+ const queue = [entry];
26
+ while (queue.length > 0) {
27
+ const file = queue.pop();
28
+ if (seen.indexOf(file) === -1 && existsSync(file)) {
29
+ seen.push(file);
30
+ WorkerBundleService.staticImports(readFileSync(file, 'utf8')).forEach((specifier) => queue.push(resolve(dirname(file), specifier)));
31
+ }
32
+ }
33
+ return seen;
34
+ }
35
+ static kilobytes(bytes) {
36
+ return Math.round(bytes / 1024);
37
+ }
38
+ static report(directory, entry, budget) {
39
+ const eager = WorkerBundleService.eagerFiles(resolve(directory, entry));
40
+ const files = WorkerBundleService.scriptFiles(resolve(directory)).map((path) => {
41
+ const content = readFileSync(path);
42
+ return {
43
+ file: relative(resolve(directory), path),
44
+ gzipBytes: gzipSync(content).length,
45
+ isEager: eager.indexOf(path) !== -1,
46
+ sizeBytes: content.length,
47
+ };
48
+ });
49
+ const eagerBytes = files
50
+ .filter((file) => file.isEager)
51
+ .reduce((sum, file) => sum + file.sizeBytes, 0);
52
+ const totalBytes = files.reduce((sum, file) => sum + file.sizeBytes, 0);
53
+ const gzipBytes = files.reduce((sum, file) => sum + file.gzipBytes, 0);
54
+ const checks = [
55
+ ['eager', eagerBytes, budget.eagerKb],
56
+ ['total', totalBytes, budget.totalKb],
57
+ ['gzip', gzipBytes, budget.gzipKb],
58
+ ];
59
+ return {
60
+ eagerBytes,
61
+ failures: checks
62
+ .filter(([, bytes, limit]) => limit > 0 && WorkerBundleService.kilobytes(bytes) > limit)
63
+ .map(([label]) => label),
64
+ files: files.sort((a, b) => b.sizeBytes - a.sizeBytes),
65
+ gzipBytes,
66
+ totalBytes,
67
+ };
68
+ }
69
+ static summary(report, budget) {
70
+ const limit = (value) => (value > 0 ? ` / budget ${value} KB` : '');
71
+ return report.files
72
+ .slice(0, 12)
73
+ .map((file) => `${String(WorkerBundleService.kilobytes(file.sizeBytes)).padStart(7)} KB ${file.isEager ? 'eager' : 'lazy '} ${file.file}`)
74
+ .concat([
75
+ `eager (evaluated at startup): ${WorkerBundleService.kilobytes(report.eagerBytes)} KB${limit(budget.eagerKb)}`,
76
+ `total server JS: ${WorkerBundleService.kilobytes(report.totalBytes)} KB${limit(budget.totalKb)}`,
77
+ `total gzip (upload size): ${WorkerBundleService.kilobytes(report.gzipBytes)} KB${limit(budget.gzipKb)}`,
78
+ ]);
79
+ }
80
+ }
@@ -0,0 +1,6 @@
1
+ export const DeviceConfig = {
2
+ ios: /iPhone|iPad|iPod/i,
3
+ macintosh: /Macintosh/i,
4
+ mobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|Tablet|Silk|Kindle/i,
5
+ touchPointsForTablet: 1,
6
+ };
@@ -0,0 +1,34 @@
1
+ export class DebounceService {
2
+ static create(action, waitMs) {
3
+ let timer = null;
4
+ let pending = null;
5
+ const clear = () => {
6
+ if (timer !== null)
7
+ clearTimeout(timer);
8
+ timer = null;
9
+ };
10
+ return {
11
+ cancel: () => {
12
+ clear();
13
+ pending = null;
14
+ },
15
+ flush: () => {
16
+ if (pending === null)
17
+ return;
18
+ const args = pending;
19
+ clear();
20
+ pending = null;
21
+ action(...args);
22
+ },
23
+ run: (...args) => {
24
+ pending = args;
25
+ clear();
26
+ timer = setTimeout(() => {
27
+ timer = null;
28
+ pending = null;
29
+ action(...args);
30
+ }, waitMs);
31
+ },
32
+ };
33
+ }
34
+ }
@@ -0,0 +1,15 @@
1
+ import { DeviceConfig } from './constants/device-config';
2
+ export class DeviceService {
3
+ static fromUserAgent(userAgent, maxTouchPoints) {
4
+ const isIPadOS = DeviceConfig.macintosh.test(userAgent) && maxTouchPoints > DeviceConfig.touchPointsForTablet;
5
+ return {
6
+ isIOS: DeviceConfig.ios.test(userAgent) || isIPadOS,
7
+ isMobile: DeviceConfig.mobile.test(userAgent) || isIPadOS,
8
+ };
9
+ }
10
+ static current() {
11
+ if (typeof navigator === 'undefined')
12
+ return { isIOS: false, isMobile: false };
13
+ return DeviceService.fromUserAgent(navigator.userAgent, navigator.maxTouchPoints);
14
+ }
15
+ }
@@ -0,0 +1,51 @@
1
+ import { HttpContentType } from '../common/constants/http-content-type';
2
+ import { HttpHeader } from '../common/constants/http-header';
3
+ import { HttpMethod } from '../common/constants/http-method';
4
+ const isBinaryBody = (data) => data instanceof FormData ||
5
+ data instanceof Blob ||
6
+ data instanceof ArrayBuffer ||
7
+ data instanceof URLSearchParams;
8
+ export class HttpService {
9
+ static createApiClient(options = {}) {
10
+ const { apiKey, apiKeyHeader = HttpHeader.apiKey, baseURL, headers: defaultHeaders } = options;
11
+ const request = async (method, url, data, config) => {
12
+ const fullUrl = baseURL ? `${baseURL}${url}` : url;
13
+ const sendsBinaryBody = isBinaryBody(data);
14
+ const headers = sendsBinaryBody
15
+ ? {}
16
+ : { [HttpHeader.contentType]: HttpContentType.json };
17
+ if (defaultHeaders)
18
+ Object.assign(headers, defaultHeaders);
19
+ if (apiKey)
20
+ headers[apiKeyHeader] = apiKey;
21
+ if (config?.headers)
22
+ Object.assign(headers, config.headers);
23
+ const body = data === undefined ? undefined : sendsBinaryBody ? data : JSON.stringify(data);
24
+ const response = await fetch(fullUrl, { method, headers, body });
25
+ if (config?.responseType === 'stream' && response.ok)
26
+ return { data: response.body, headers: response.headers, status: response.status };
27
+ const responseData = await (config?.responseType === 'arraybuffer'
28
+ ? response.arrayBuffer()
29
+ : config?.responseType === 'text'
30
+ ? response.text()
31
+ : config?.responseType === 'json'
32
+ ? response.json()
33
+ : String(response.headers.get(HttpHeader.contentType)).includes(HttpContentType.json)
34
+ ? response.json()
35
+ : response.text());
36
+ if (!response.ok) {
37
+ const error = new Error(`Request failed with status ${response.status}`);
38
+ error.response = { data: responseData, status: response.status };
39
+ throw error;
40
+ }
41
+ return { data: responseData, headers: response.headers, status: response.status };
42
+ };
43
+ return {
44
+ get: (url, config) => request(HttpMethod.Get, url, undefined, config),
45
+ post: (url, data, config) => request(HttpMethod.Post, url, data, config),
46
+ put: (url, data, config) => request(HttpMethod.Put, url, data, config),
47
+ patch: (url, data, config) => request(HttpMethod.Patch, url, data, config),
48
+ delete: (url, config) => request(HttpMethod.Delete, url, undefined, config),
49
+ };
50
+ }
51
+ }
@@ -0,0 +1,3 @@
1
+ export * from './debounce-service';
2
+ export * from './device-service';
3
+ export * from './http-service';
@@ -0,0 +1,37 @@
1
+ import { AmountConfig } from './constants/amount-config';
2
+ import { AmountDirection } from './constants/amount-direction';
3
+ export class AmountService {
4
+ static normalise(raw) {
5
+ const trimmed = raw.trim();
6
+ const isBracketed = trimmed.startsWith(AmountConfig.openBracket) && trimmed.endsWith(AmountConfig.closeBracket);
7
+ const isNegative = isBracketed || trimmed.startsWith(AmountConfig.minus);
8
+ const kept = trimmed.replace(AmountConfig.disallowed, '');
9
+ const pointIndex = kept.indexOf(AmountConfig.point);
10
+ const digits = pointIndex === -1
11
+ ? kept
12
+ : `${kept.slice(0, pointIndex + 1)}${kept
13
+ .slice(pointIndex + 1)
14
+ .split(AmountConfig.point)
15
+ .join('')}`;
16
+ if (digits === '')
17
+ return isNegative && !isBracketed ? AmountConfig.minus : '';
18
+ return isNegative ? `${AmountConfig.minus}${digits}` : digits;
19
+ }
20
+ static toNumber(raw) {
21
+ const normalised = AmountService.normalise(raw);
22
+ const parsed = Number(normalised);
23
+ return normalised === '' || !Number.isFinite(parsed) ? 0 : parsed;
24
+ }
25
+ static isAmount(raw) {
26
+ const normalised = AmountService.normalise(raw);
27
+ return (normalised !== '' && normalised !== AmountConfig.minus && Number.isFinite(Number(normalised)));
28
+ }
29
+ static direction(raw) {
30
+ if (!AmountService.isAmount(raw))
31
+ return AmountDirection.Neutral;
32
+ const normalised = AmountService.normalise(raw);
33
+ if (AmountConfig.zeroPattern.test(normalised))
34
+ return AmountDirection.Neutral;
35
+ return normalised.startsWith(AmountConfig.minus) ? AmountDirection.Out : AmountDirection.In;
36
+ }
37
+ }
@@ -0,0 +1,17 @@
1
+ export class Base64Service {
2
+ static encode(bytes) {
3
+ let binary = '';
4
+ for (let index = 0; index < bytes.length; index += 1) {
5
+ binary += String.fromCharCode(bytes[index]);
6
+ }
7
+ return btoa(binary);
8
+ }
9
+ static decode(value) {
10
+ const binary = atob(value.trim());
11
+ const bytes = new Uint8Array(new ArrayBuffer(binary.length));
12
+ for (let index = 0; index < binary.length; index += 1) {
13
+ bytes[index] = binary.charCodeAt(index);
14
+ }
15
+ return bytes;
16
+ }
17
+ }
@@ -0,0 +1,8 @@
1
+ export class ColorService {
2
+ static hexToRgb(hex) {
3
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
4
+ return result
5
+ ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)]
6
+ : [0, 0, 0];
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ export const AmountConfig = {
2
+ closeBracket: ')',
3
+ disallowed: /[^0-9.]/g,
4
+ minus: '-',
5
+ openBracket: '(',
6
+ point: '.',
7
+ zeroPattern: /^-?0*\.?0*$/,
8
+ };
@@ -0,0 +1,6 @@
1
+ export var AmountDirection;
2
+ (function (AmountDirection) {
3
+ AmountDirection["In"] = "in";
4
+ AmountDirection["Neutral"] = "neutral";
5
+ AmountDirection["Out"] = "out";
6
+ })(AmountDirection || (AmountDirection = {}));
@@ -0,0 +1,30 @@
1
+ export const EmailPreviewConfig = {
2
+ documentName: 'email.html',
3
+ documentContentType: 'text/html',
4
+ imageName: 'email.png',
5
+ imageContentType: 'image/png',
6
+ fallbackSubject: 'Email',
7
+ dateFormat: 'D MMM YYYY, h:mm A',
8
+ page: {
9
+ width: 860,
10
+ padding: 48,
11
+ headerGap: 28,
12
+ subjectSize: 22,
13
+ metaSize: 13,
14
+ bodySize: 15,
15
+ lineHeight: 24,
16
+ maxLines: 140,
17
+ minHeight: 320,
18
+ charWidth: 7.4,
19
+ subjectWidthRatio: 1.45,
20
+ metaWidthRatio: 0.9,
21
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Helvetica, Arial, 'DejaVu Sans', 'Liberation Sans', sans-serif",
22
+ paperColour: '#ffffff',
23
+ bandColour: '#0f9d58',
24
+ bandHeight: 6,
25
+ ruleColour: '#e4e8ee',
26
+ subjectColour: '#101828',
27
+ metaColour: '#667085',
28
+ bodyColour: '#344054',
29
+ },
30
+ };
@@ -0,0 +1,4 @@
1
+ export const ErrorResponseConfig = {
2
+ clientErrorStart: 400,
3
+ serverErrorStart: 500,
4
+ };
@@ -0,0 +1,5 @@
1
+ export const FileSizeConfig = {
2
+ step: 1024,
3
+ units: ['B', 'KB', 'MB', 'GB', 'TB'],
4
+ wholeFrom: 10,
5
+ };
@@ -0,0 +1,3 @@
1
+ export const HttpAuthScheme = {
2
+ bearerPrefix: 'Bearer ',
3
+ };
@@ -0,0 +1,8 @@
1
+ export const HttpContentType = {
2
+ formUrlEncoded: 'application/x-www-form-urlencoded',
3
+ html: 'text/html',
4
+ json: 'application/json',
5
+ multipartFormData: 'multipart/form-data',
6
+ octetStream: 'application/octet-stream',
7
+ plainText: 'text/plain',
8
+ };
@@ -0,0 +1,23 @@
1
+ export const HttpHeader = {
2
+ accept: 'Accept',
3
+ apiKey: 'X-API-Key',
4
+ authorization: 'Authorization',
5
+ cacheControl: 'Cache-Control',
6
+ cfConnectingIp: 'CF-Connecting-IP',
7
+ contentDisposition: 'Content-Disposition',
8
+ contentSecurityPolicy: 'Content-Security-Policy',
9
+ contentType: 'Content-Type',
10
+ contentTypeOptions: 'X-Content-Type-Options',
11
+ cookie: 'Cookie',
12
+ forwardedFor: 'X-Forwarded-For',
13
+ frameOptions: 'X-Frame-Options',
14
+ idempotencyKey: 'Idempotency-Key',
15
+ location: 'Location',
16
+ prefer: 'Prefer',
17
+ realIp: 'X-Real-IP',
18
+ retryAfter: 'Retry-After',
19
+ robotsTag: 'X-Robots-Tag',
20
+ setCookie: 'Set-Cookie',
21
+ strictTransportSecurity: 'Strict-Transport-Security',
22
+ userAgent: 'User-Agent',
23
+ };
@@ -0,0 +1,10 @@
1
+ export var HttpMethod;
2
+ (function (HttpMethod) {
3
+ HttpMethod["Delete"] = "DELETE";
4
+ HttpMethod["Get"] = "GET";
5
+ HttpMethod["Head"] = "HEAD";
6
+ HttpMethod["Options"] = "OPTIONS";
7
+ HttpMethod["Patch"] = "PATCH";
8
+ HttpMethod["Post"] = "POST";
9
+ HttpMethod["Put"] = "PUT";
10
+ })(HttpMethod || (HttpMethod = {}));
@@ -0,0 +1,19 @@
1
+ export * from './amount-config';
2
+ export * from './email-preview-config';
3
+ export * from './phone-config';
4
+ export * from './postal-code-formats';
5
+ export * from './signed-token-config';
6
+ export * from './user-token-config';
7
+ export * from './validation-config';
8
+ export * from './file-size-config';
9
+ export * from './socket-token-config';
10
+ export * from './user-agent-config';
11
+ export * from './amount-direction';
12
+ export * from './error-response-config';
13
+ export * from './http-auth-scheme';
14
+ export * from './http-content-type';
15
+ export * from './http-header';
16
+ export * from './http-method';
17
+ export * from './relative-time-config';
18
+ export * from './request-client-config';
19
+ export * from './portable-text-config';
@@ -0,0 +1,6 @@
1
+ export const PhoneConfig = {
2
+ defaultCountry: 'CA',
3
+ displayNamesType: 'region',
4
+ locale: 'en',
5
+ plus: '+',
6
+ };
@@ -0,0 +1,17 @@
1
+ import { Common } from '@pallasoft/ps-models';
2
+ export const PortableTextConfig = {
3
+ linkRel: 'noopener noreferrer',
4
+ linkTarget: '_blank',
5
+ paragraphSeparator: '\n\n',
6
+ lineSeparator: '\n',
7
+ paragraphSplitPattern: /\n[ \t]*\n/,
8
+ lineBreakPattern: /\r\n?/g,
9
+ bulletPrefix: '- ',
10
+ quotePrefix: '> ',
11
+ numberSuffix: '. ',
12
+ keyPrefix: { block: 'b', span: 's' },
13
+ normalStyle: Common.PortableTextConfig.styles[0],
14
+ quoteStyle: Common.PortableTextConfig.styles[1],
15
+ bulletItem: Common.PortableTextConfig.listItems[0],
16
+ numberItem: Common.PortableTextConfig.listItems[1],
17
+ };