@pallasoft/ps-utilities 2.19.0 → 2.20.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 (50) hide show
  1. package/dist/common/constants/index.d.ts +1 -0
  2. package/dist/common/constants/index.js +1 -0
  3. package/dist/common/constants/text-tidy-config.d.ts +8 -0
  4. package/dist/common/constants/text-tidy-config.js +11 -0
  5. package/dist/common/index.d.ts +1 -0
  6. package/dist/common/index.js +1 -0
  7. package/dist/common/text-tidy-service.d.ts +4 -0
  8. package/dist/common/text-tidy-service.js +23 -0
  9. package/dist/esm/build/index.js +2 -2
  10. package/dist/esm/build/worker-bundle-cli.js +1 -1
  11. package/dist/esm/client/device-service.js +1 -1
  12. package/dist/esm/client/http-service.js +3 -3
  13. package/dist/esm/client/index.js +3 -3
  14. package/dist/esm/common/amount-service.js +2 -2
  15. package/dist/esm/common/constants/index.js +20 -19
  16. package/dist/esm/common/constants/request-client-config.js +1 -1
  17. package/dist/esm/common/constants/text-tidy-config.js +8 -0
  18. package/dist/esm/common/crypto-service.js +1 -1
  19. package/dist/esm/common/email-preview-service.js +2 -2
  20. package/dist/esm/common/encrypted-fields-service.js +1 -1
  21. package/dist/esm/common/envelope-crypto-service.js +1 -1
  22. package/dist/esm/common/error-response-service.js +1 -1
  23. package/dist/esm/common/file-size-service.js +1 -1
  24. package/dist/esm/common/index.js +28 -27
  25. package/dist/esm/common/phone-service.js +1 -1
  26. package/dist/esm/common/portable-text-service.js +1 -1
  27. package/dist/esm/common/postal-code-service.js +1 -1
  28. package/dist/esm/common/relative-time-service.js +2 -2
  29. package/dist/esm/common/request-client-service.js +1 -1
  30. package/dist/esm/common/signed-token-service.js +2 -2
  31. package/dist/esm/common/socket-token-service.js +3 -3
  32. package/dist/esm/common/text-tidy-service.js +16 -0
  33. package/dist/esm/common/user-agent-service.js +1 -1
  34. package/dist/esm/common/user-token-service.js +3 -3
  35. package/dist/esm/common/validation-service.js +2 -2
  36. package/dist/esm/index.js +4 -4
  37. package/dist/esm/models/socket-live-options.js +1 -0
  38. package/dist/esm/server/index.js +2 -2
  39. package/dist/esm/sockets/index.js +2 -1
  40. package/dist/esm/sockets/socket-live-config.js +8 -0
  41. package/dist/esm/sockets/socket-live-service.js +96 -0
  42. package/dist/models/socket-live-options.d.ts +8 -0
  43. package/dist/models/socket-live-options.js +2 -0
  44. package/dist/sockets/index.d.ts +2 -0
  45. package/dist/sockets/index.js +1 -0
  46. package/dist/sockets/socket-live-config.d.ts +8 -0
  47. package/dist/sockets/socket-live-config.js +11 -0
  48. package/dist/sockets/socket-live-service.d.ts +20 -0
  49. package/dist/sockets/socket-live-service.js +174 -0
  50. package/package.json +3 -2
@@ -17,3 +17,4 @@ export * from './http-method';
17
17
  export * from './relative-time-config';
18
18
  export * from './request-client-config';
19
19
  export * from './portable-text-config';
20
+ export * from './text-tidy-config';
@@ -33,3 +33,4 @@ __exportStar(require("./http-method"), exports);
33
33
  __exportStar(require("./relative-time-config"), exports);
34
34
  __exportStar(require("./request-client-config"), exports);
35
35
  __exportStar(require("./portable-text-config"), exports);
36
+ __exportStar(require("./text-tidy-config"), exports);
@@ -0,0 +1,8 @@
1
+ export declare const TextTidyConfig: {
2
+ readonly emptyBrackets: RegExp;
3
+ readonly lineEndSpace: RegExp;
4
+ readonly lineStartSpace: RegExp;
5
+ readonly manyBlankLines: RegExp;
6
+ readonly manySpaces: RegExp;
7
+ readonly spaceBeforePunctuation: RegExp;
8
+ };
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TextTidyConfig = void 0;
4
+ exports.TextTidyConfig = {
5
+ emptyBrackets: /\(\s*\)|\[\s*\]|\{\s*\}/g,
6
+ lineEndSpace: /[^\S\n]+\n/g,
7
+ lineStartSpace: /\n[^\S\n]+/g,
8
+ manyBlankLines: /\n{3,}/g,
9
+ manySpaces: /[^\S\n]{2,}/g,
10
+ spaceBeforePunctuation: /[^\S\n]+([,.;:!?])/g,
11
+ };
@@ -25,3 +25,4 @@ export * from './relative-time-service';
25
25
  export * from './request-client-service';
26
26
  export * from './json-service';
27
27
  export * from './portable-text-service';
28
+ export * from './text-tidy-service';
@@ -41,3 +41,4 @@ __exportStar(require("./relative-time-service"), exports);
41
41
  __exportStar(require("./request-client-service"), exports);
42
42
  __exportStar(require("./json-service"), exports);
43
43
  __exportStar(require("./portable-text-service"), exports);
44
+ __exportStar(require("./text-tidy-service"), exports);
@@ -0,0 +1,4 @@
1
+ export declare class TextTidyService {
2
+ static run(text: string): string;
3
+ static tidy(text: string): string;
4
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TextTidyService = void 0;
4
+ var text_tidy_config_1 = require("./constants/text-tidy-config");
5
+ var TextTidyService = /** @class */ (function () {
6
+ function TextTidyService() {
7
+ }
8
+ TextTidyService.run = function (text) {
9
+ return text
10
+ .replace(text_tidy_config_1.TextTidyConfig.emptyBrackets, '')
11
+ .replace(text_tidy_config_1.TextTidyConfig.manySpaces, ' ')
12
+ .replace(text_tidy_config_1.TextTidyConfig.spaceBeforePunctuation, '$1');
13
+ };
14
+ TextTidyService.tidy = function (text) {
15
+ return TextTidyService.run(text)
16
+ .replace(text_tidy_config_1.TextTidyConfig.lineEndSpace, '\n')
17
+ .replace(text_tidy_config_1.TextTidyConfig.lineStartSpace, '\n')
18
+ .replace(text_tidy_config_1.TextTidyConfig.manyBlankLines, '\n\n')
19
+ .trim();
20
+ };
21
+ return TextTidyService;
22
+ }());
23
+ exports.TextTidyService = TextTidyService;
@@ -1,2 +1,2 @@
1
- export * from './worker-bundle-cli';
2
- export * from './worker-bundle-service';
1
+ export * from './worker-bundle-cli.js';
2
+ export * from './worker-bundle-service.js';
@@ -1,6 +1,6 @@
1
1
  import { existsSync } from 'fs';
2
2
  import { resolve } from 'path';
3
- import { WorkerBundleService } from './worker-bundle-service';
3
+ import { WorkerBundleService } from './worker-bundle-service.js';
4
4
  export class WorkerBundleCli {
5
5
  static options(argv) {
6
6
  const read = (name, fallback) => {
@@ -1,4 +1,4 @@
1
- import { DeviceConfig } from './constants/device-config';
1
+ import { DeviceConfig } from './constants/device-config.js';
2
2
  export class DeviceService {
3
3
  static fromUserAgent(userAgent, maxTouchPoints) {
4
4
  const isIPadOS = DeviceConfig.macintosh.test(userAgent) && maxTouchPoints > DeviceConfig.touchPointsForTablet;
@@ -1,6 +1,6 @@
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';
1
+ import { HttpContentType } from '../common/constants/http-content-type.js';
2
+ import { HttpHeader } from '../common/constants/http-header.js';
3
+ import { HttpMethod } from '../common/constants/http-method.js';
4
4
  const isBinaryBody = (data) => data instanceof FormData ||
5
5
  data instanceof Blob ||
6
6
  data instanceof ArrayBuffer ||
@@ -1,3 +1,3 @@
1
- export * from './debounce-service';
2
- export * from './device-service';
3
- export * from './http-service';
1
+ export * from './debounce-service.js';
2
+ export * from './device-service.js';
3
+ export * from './http-service.js';
@@ -1,5 +1,5 @@
1
- import { AmountConfig } from './constants/amount-config';
2
- import { AmountDirection } from './constants/amount-direction';
1
+ import { AmountConfig } from './constants/amount-config.js';
2
+ import { AmountDirection } from './constants/amount-direction.js';
3
3
  export class AmountService {
4
4
  static normalise(raw) {
5
5
  const trimmed = raw.trim();
@@ -1,19 +1,20 @@
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';
1
+ export * from './amount-config.js';
2
+ export * from './email-preview-config.js';
3
+ export * from './phone-config.js';
4
+ export * from './postal-code-formats.js';
5
+ export * from './signed-token-config.js';
6
+ export * from './user-token-config.js';
7
+ export * from './validation-config.js';
8
+ export * from './file-size-config.js';
9
+ export * from './socket-token-config.js';
10
+ export * from './user-agent-config.js';
11
+ export * from './amount-direction.js';
12
+ export * from './error-response-config.js';
13
+ export * from './http-auth-scheme.js';
14
+ export * from './http-content-type.js';
15
+ export * from './http-header.js';
16
+ export * from './http-method.js';
17
+ export * from './relative-time-config.js';
18
+ export * from './request-client-config.js';
19
+ export * from './portable-text-config.js';
20
+ export * from './text-tidy-config.js';
@@ -1,4 +1,4 @@
1
- import { HttpHeader } from './http-header';
1
+ import { HttpHeader } from './http-header.js';
2
2
  export const RequestClientConfig = {
3
3
  addressHeaders: [HttpHeader.cfConnectingIp, HttpHeader.realIp, HttpHeader.forwardedFor],
4
4
  agentHeader: HttpHeader.userAgent,
@@ -0,0 +1,8 @@
1
+ export const TextTidyConfig = {
2
+ emptyBrackets: /\(\s*\)|\[\s*\]|\{\s*\}/g,
3
+ lineEndSpace: /[^\S\n]+\n/g,
4
+ lineStartSpace: /\n[^\S\n]+/g,
5
+ manyBlankLines: /\n{3,}/g,
6
+ manySpaces: /[^\S\n]{2,}/g,
7
+ spaceBeforePunctuation: /[^\S\n]+([,.;:!?])/g,
8
+ };
@@ -1,4 +1,4 @@
1
- import { Base64Service } from './base64-service';
1
+ import { Base64Service } from './base64-service.js';
2
2
  export class CryptoService {
3
3
  static requireKey(key, name) {
4
4
  if (typeof key !== 'string' || key.trim().length === 0) {
@@ -1,5 +1,5 @@
1
- import { EmailPreviewConfig } from './constants/email-preview-config';
2
- import { DateService } from './date-service';
1
+ import { EmailPreviewConfig } from './constants/email-preview-config.js';
2
+ import { DateService } from './date-service.js';
3
3
  export class EmailPreviewService {
4
4
  static escape(value) {
5
5
  return value
@@ -1,4 +1,4 @@
1
- import { EnvelopeCryptoService } from './envelope-crypto-service';
1
+ import { EnvelopeCryptoService } from './envelope-crypto-service.js';
2
2
  export class EncryptedFieldsService {
3
3
  static _isBlank(value) {
4
4
  return value === null || value === undefined || value === '';
@@ -1,4 +1,4 @@
1
- import { CryptoService } from './crypto-service';
1
+ import { CryptoService } from './crypto-service.js';
2
2
  export class EnvelopeCryptoService {
3
3
  static _remember(wrappedDataKey, dataKey) {
4
4
  if (this._cache.size >= this._cacheLimit) {
@@ -1,4 +1,4 @@
1
- import { ErrorResponseConfig } from './constants/error-response-config';
1
+ import { ErrorResponseConfig } from './constants/error-response-config.js';
2
2
  export class ErrorResponseService {
3
3
  static create(message, code) {
4
4
  return Object.assign(new Error(message), { code });
@@ -1,4 +1,4 @@
1
- import { FileSizeConfig } from './constants/file-size-config';
1
+ import { FileSizeConfig } from './constants/file-size-config.js';
2
2
  export class FileSizeService {
3
3
  static format(bytes) {
4
4
  let value = Math.max(0, bytes);
@@ -1,27 +1,28 @@
1
- export * from './amount-service';
2
- export * from './base64-service';
3
- export * from './color-service';
4
- export * from './constants';
5
- export * from './crypto-service';
6
- export * from './date-service';
7
- export * from './email-preview-service';
8
- export * from './encrypted-fields-service';
9
- export * from './file-size-service';
10
- export * from './envelope-crypto-service';
11
- export * from './number-format-service';
12
- export * from './phone-service';
13
- export * from './postal-code-service';
14
- export * from './recaptcha-service';
15
- export * from './signed-token-service';
16
- export * from './socket-token-service';
17
- export * from './string-service';
18
- export * from './transform-service';
19
- export * from './url-service';
20
- export * from './user-agent-service';
21
- export * from './user-token-service';
22
- export * from './validation-service';
23
- export * from './error-response-service';
24
- export * from './relative-time-service';
25
- export * from './request-client-service';
26
- export * from './json-service';
27
- export * from './portable-text-service';
1
+ export * from './amount-service.js';
2
+ export * from './base64-service.js';
3
+ export * from './color-service.js';
4
+ export * from './constants/index.js';
5
+ export * from './crypto-service.js';
6
+ export * from './date-service.js';
7
+ export * from './email-preview-service.js';
8
+ export * from './encrypted-fields-service.js';
9
+ export * from './file-size-service.js';
10
+ export * from './envelope-crypto-service.js';
11
+ export * from './number-format-service.js';
12
+ export * from './phone-service.js';
13
+ export * from './postal-code-service.js';
14
+ export * from './recaptcha-service.js';
15
+ export * from './signed-token-service.js';
16
+ export * from './socket-token-service.js';
17
+ export * from './string-service.js';
18
+ export * from './transform-service.js';
19
+ export * from './url-service.js';
20
+ export * from './user-agent-service.js';
21
+ export * from './user-token-service.js';
22
+ export * from './validation-service.js';
23
+ export * from './error-response-service.js';
24
+ export * from './relative-time-service.js';
25
+ export * from './request-client-service.js';
26
+ export * from './json-service.js';
27
+ export * from './portable-text-service.js';
28
+ export * from './text-tidy-service.js';
@@ -1,5 +1,5 @@
1
1
  import { AsYouType, getCountries, getCountryCallingCode, parsePhoneNumberFromString, } from 'libphonenumber-js';
2
- import { PhoneConfig } from './constants/phone-config';
2
+ import { PhoneConfig } from './constants/phone-config.js';
3
3
  export class PhoneService {
4
4
  static isCountry(code) {
5
5
  return getCountries().includes(code);
@@ -1,6 +1,6 @@
1
1
  import { Common } from '@pallasoft/ps-models';
2
2
  import { escapeHTML, toHTML } from '@portabletext/to-html';
3
- import { PortableTextConfig } from './constants/portable-text-config';
3
+ import { PortableTextConfig } from './constants/portable-text-config.js';
4
4
  export class PortableTextService {
5
5
  static toPlainText(blocks) {
6
6
  const lines = [];
@@ -1,4 +1,4 @@
1
- import { PostalCodeConfig, PostalCodeFormats } from './constants/postal-code-formats';
1
+ import { PostalCodeConfig, PostalCodeFormats } from './constants/postal-code-formats.js';
2
2
  export class PostalCodeService {
3
3
  static format(raw, country) {
4
4
  const upper = raw.toUpperCase();
@@ -1,5 +1,5 @@
1
- import { RelativeTimeConfig } from './constants/relative-time-config';
2
- import { DateService } from './date-service';
1
+ import { RelativeTimeConfig } from './constants/relative-time-config.js';
2
+ import { DateService } from './date-service.js';
3
3
  export class RelativeTimeService {
4
4
  static format(value, now, options) {
5
5
  if (!DateService.isValid(value))
@@ -1,4 +1,4 @@
1
- import { RequestClientConfig } from './constants/request-client-config';
1
+ import { RequestClientConfig } from './constants/request-client-config.js';
2
2
  export class RequestClientService {
3
3
  static from(headers, options = {}) {
4
4
  const address = RequestClientConfig.addressHeaders
@@ -1,5 +1,5 @@
1
- import { Base64Service } from './base64-service';
2
- import { SignedTokenConfig } from './constants/signed-token-config';
1
+ import { Base64Service } from './base64-service.js';
2
+ import { SignedTokenConfig } from './constants/signed-token-config.js';
3
3
  export class SignedTokenService {
4
4
  static async generateKeyPair() {
5
5
  const pair = (await crypto.subtle.generateKey(SignedTokenConfig.keyAlgorithm, true, [
@@ -1,6 +1,6 @@
1
- import { SocketTokenConfig } from './constants/socket-token-config';
2
- import { DateService } from './date-service';
3
- import { SignedTokenService } from './signed-token-service';
1
+ import { SocketTokenConfig } from './constants/socket-token-config.js';
2
+ import { DateService } from './date-service.js';
3
+ import { SignedTokenService } from './signed-token-service.js';
4
4
  export class SocketTokenService {
5
5
  static async issue(scope, privateKey, seconds = SocketTokenConfig.defaultSeconds) {
6
6
  const claims = {
@@ -0,0 +1,16 @@
1
+ import { TextTidyConfig } from './constants/text-tidy-config.js';
2
+ export class TextTidyService {
3
+ static run(text) {
4
+ return text
5
+ .replace(TextTidyConfig.emptyBrackets, '')
6
+ .replace(TextTidyConfig.manySpaces, ' ')
7
+ .replace(TextTidyConfig.spaceBeforePunctuation, '$1');
8
+ }
9
+ static tidy(text) {
10
+ return TextTidyService.run(text)
11
+ .replace(TextTidyConfig.lineEndSpace, '\n')
12
+ .replace(TextTidyConfig.lineStartSpace, '\n')
13
+ .replace(TextTidyConfig.manyBlankLines, '\n\n')
14
+ .trim();
15
+ }
16
+ }
@@ -1,4 +1,4 @@
1
- import { UserAgentConfig } from './constants/user-agent-config';
1
+ import { UserAgentConfig } from './constants/user-agent-config.js';
2
2
  export class UserAgentService {
3
3
  static browser(userAgent) {
4
4
  if (userAgent === null)
@@ -1,6 +1,6 @@
1
- import { UserTokenConfig } from './constants/user-token-config';
2
- import { DateService } from './date-service';
3
- import { SignedTokenService } from './signed-token-service';
1
+ import { UserTokenConfig } from './constants/user-token-config.js';
2
+ import { DateService } from './date-service.js';
3
+ import { SignedTokenService } from './signed-token-service.js';
4
4
  export class UserTokenService {
5
5
  static async issue(subject, request, options) {
6
6
  const issuedAt = this._now();
@@ -1,5 +1,5 @@
1
- import { ValidationConfig } from './constants/validation-config';
2
- import { PhoneService } from './phone-service';
1
+ import { ValidationConfig } from './constants/validation-config.js';
2
+ import { PhoneService } from './phone-service.js';
3
3
  export class ValidationService {
4
4
  static isEmail(value) {
5
5
  return ValidationConfig.email.test(value.trim());
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export * as Client from './client';
2
- export * as Common from './common';
3
- export { AmountDirection } from './common/constants/amount-direction';
4
- export { HttpMethod } from './common/constants/http-method';
1
+ export * as Client from './client/index.js';
2
+ export * as Common from './common/index.js';
3
+ export { AmountDirection } from './common/constants/amount-direction.js';
4
+ export { HttpMethod } from './common/constants/http-method.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -1,2 +1,2 @@
1
- export * from './file-service';
2
- export * from './timing-safe-service';
1
+ export * from './file-service.js';
2
+ export * from './timing-safe-service.js';
@@ -1 +1,2 @@
1
- export * from './socket-client-service';
1
+ export * from './socket-client-service.js';
2
+ export * from './socket-live-service.js';
@@ -0,0 +1,8 @@
1
+ export const SocketLiveConfig = {
2
+ connectErrorEvent: 'connect_error',
3
+ connectEvent: 'connect',
4
+ hiddenDelayMilliseconds: 60000,
5
+ maxRetryMilliseconds: 30000,
6
+ retryBaseMilliseconds: 1000,
7
+ visibilityEvent: 'visibilitychange',
8
+ };
@@ -0,0 +1,96 @@
1
+ import { SocketClientService } from './socket-client-service.js';
2
+ import { SocketLiveConfig } from './socket-live-config.js';
3
+ export class SocketLiveService {
4
+ constructor(options) {
5
+ this.options = options;
6
+ this.socket = null;
7
+ this.token = null;
8
+ this.isClosed = false;
9
+ this.hasConnected = false;
10
+ this.failures = 0;
11
+ this.retryTimer = null;
12
+ this.hiddenTimer = null;
13
+ this.visibility = () => {
14
+ if (this.isClosed || this.socket === null)
15
+ return;
16
+ if (document.visibilityState === 'hidden') {
17
+ const delay = this.options.hiddenDelayMilliseconds === undefined
18
+ ? SocketLiveConfig.hiddenDelayMilliseconds
19
+ : this.options.hiddenDelayMilliseconds;
20
+ this.hiddenTimer = setTimeout(() => {
21
+ this.hiddenTimer = null;
22
+ if (this.socket !== null)
23
+ this.socket.disconnect();
24
+ }, delay);
25
+ return;
26
+ }
27
+ if (this.hiddenTimer !== null) {
28
+ clearTimeout(this.hiddenTimer);
29
+ this.hiddenTimer = null;
30
+ }
31
+ if (!this.socket.connected)
32
+ void this.reconnect();
33
+ };
34
+ }
35
+ static async open(options) {
36
+ const live = new SocketLiveService(options);
37
+ await live.start();
38
+ return live;
39
+ }
40
+ async start() {
41
+ this.token = await this.options.fetchToken();
42
+ if (this.isClosed || this.token === null)
43
+ return;
44
+ const socket = SocketClientService.connect({
45
+ path: this.options.path,
46
+ token: () => this.token,
47
+ });
48
+ this.socket = socket;
49
+ this.options.events.forEach((name) => socket.on(name, (payload) => this.options.onEvent(name, payload)));
50
+ socket.on(SocketLiveConfig.connectEvent, () => this.connected());
51
+ socket.on(SocketLiveConfig.connectErrorEvent, () => this.retryLater());
52
+ if (typeof document !== 'undefined')
53
+ document.addEventListener(SocketLiveConfig.visibilityEvent, this.visibility);
54
+ }
55
+ close() {
56
+ this.isClosed = true;
57
+ this.clearTimers();
58
+ if (typeof document !== 'undefined')
59
+ document.removeEventListener(SocketLiveConfig.visibilityEvent, this.visibility);
60
+ if (this.socket !== null)
61
+ this.socket.disconnect();
62
+ }
63
+ connected() {
64
+ this.failures = 0;
65
+ if (this.hasConnected && this.options.onResume !== undefined)
66
+ this.options.onResume();
67
+ this.hasConnected = true;
68
+ }
69
+ retryLater() {
70
+ if (this.isClosed || this.retryTimer !== null)
71
+ return;
72
+ const delay = Math.min(SocketLiveConfig.retryBaseMilliseconds * 2 ** this.failures, SocketLiveConfig.maxRetryMilliseconds);
73
+ this.failures += 1;
74
+ this.retryTimer = setTimeout(() => {
75
+ this.retryTimer = null;
76
+ void this.reconnect();
77
+ }, delay);
78
+ }
79
+ async reconnect() {
80
+ const token = await this.options.fetchToken();
81
+ if (this.isClosed || this.socket === null)
82
+ return;
83
+ if (token === null)
84
+ return this.retryLater();
85
+ this.token = token;
86
+ this.socket.connect();
87
+ }
88
+ clearTimers() {
89
+ if (this.retryTimer !== null)
90
+ clearTimeout(this.retryTimer);
91
+ if (this.hiddenTimer !== null)
92
+ clearTimeout(this.hiddenTimer);
93
+ this.retryTimer = null;
94
+ this.hiddenTimer = null;
95
+ }
96
+ }
@@ -0,0 +1,8 @@
1
+ export interface SocketLiveOptions {
2
+ events: string[];
3
+ fetchToken: () => Promise<string | null>;
4
+ hiddenDelayMilliseconds?: number;
5
+ onEvent: (name: string, payload: unknown) => void;
6
+ onResume?: () => void;
7
+ path: string;
8
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,2 +1,4 @@
1
1
  export * from './socket-client-service';
2
+ export * from './socket-live-service';
2
3
  export type { SocketClientOptions } from '../models/socket-client-options';
4
+ export type { SocketLiveOptions } from '../models/socket-live-options';
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./socket-client-service"), exports);
18
+ __exportStar(require("./socket-live-service"), exports);
@@ -0,0 +1,8 @@
1
+ export declare const SocketLiveConfig: {
2
+ readonly connectErrorEvent: "connect_error";
3
+ readonly connectEvent: "connect";
4
+ readonly hiddenDelayMilliseconds: 60000;
5
+ readonly maxRetryMilliseconds: 30000;
6
+ readonly retryBaseMilliseconds: 1000;
7
+ readonly visibilityEvent: "visibilitychange";
8
+ };
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SocketLiveConfig = void 0;
4
+ exports.SocketLiveConfig = {
5
+ connectErrorEvent: 'connect_error',
6
+ connectEvent: 'connect',
7
+ hiddenDelayMilliseconds: 60000,
8
+ maxRetryMilliseconds: 30000,
9
+ retryBaseMilliseconds: 1000,
10
+ visibilityEvent: 'visibilitychange',
11
+ };
@@ -0,0 +1,20 @@
1
+ import type { SocketLiveOptions } from '../models/socket-live-options';
2
+ export declare class SocketLiveService {
3
+ private readonly options;
4
+ private socket;
5
+ private token;
6
+ private isClosed;
7
+ private hasConnected;
8
+ private failures;
9
+ private retryTimer;
10
+ private hiddenTimer;
11
+ constructor(options: SocketLiveOptions);
12
+ static open(options: SocketLiveOptions): Promise<SocketLiveService>;
13
+ start(): Promise<void>;
14
+ close(): void;
15
+ private connected;
16
+ private retryLater;
17
+ private reconnect;
18
+ private readonly visibility;
19
+ private clearTimers;
20
+ }
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.SocketLiveService = void 0;
40
+ var socket_client_service_1 = require("./socket-client-service");
41
+ var socket_live_config_1 = require("./socket-live-config");
42
+ var SocketLiveService = /** @class */ (function () {
43
+ function SocketLiveService(options) {
44
+ var _this = this;
45
+ this.options = options;
46
+ this.socket = null;
47
+ this.token = null;
48
+ this.isClosed = false;
49
+ this.hasConnected = false;
50
+ this.failures = 0;
51
+ this.retryTimer = null;
52
+ this.hiddenTimer = null;
53
+ this.visibility = function () {
54
+ if (_this.isClosed || _this.socket === null)
55
+ return;
56
+ if (document.visibilityState === 'hidden') {
57
+ var delay = _this.options.hiddenDelayMilliseconds === undefined
58
+ ? socket_live_config_1.SocketLiveConfig.hiddenDelayMilliseconds
59
+ : _this.options.hiddenDelayMilliseconds;
60
+ _this.hiddenTimer = setTimeout(function () {
61
+ _this.hiddenTimer = null;
62
+ if (_this.socket !== null)
63
+ _this.socket.disconnect();
64
+ }, delay);
65
+ return;
66
+ }
67
+ if (_this.hiddenTimer !== null) {
68
+ clearTimeout(_this.hiddenTimer);
69
+ _this.hiddenTimer = null;
70
+ }
71
+ if (!_this.socket.connected)
72
+ void _this.reconnect();
73
+ };
74
+ }
75
+ SocketLiveService.open = function (options) {
76
+ return __awaiter(this, void 0, void 0, function () {
77
+ var live;
78
+ return __generator(this, function (_a) {
79
+ switch (_a.label) {
80
+ case 0:
81
+ live = new SocketLiveService(options);
82
+ return [4 /*yield*/, live.start()];
83
+ case 1:
84
+ _a.sent();
85
+ return [2 /*return*/, live];
86
+ }
87
+ });
88
+ });
89
+ };
90
+ SocketLiveService.prototype.start = function () {
91
+ return __awaiter(this, void 0, void 0, function () {
92
+ var _a, socket;
93
+ var _this = this;
94
+ return __generator(this, function (_b) {
95
+ switch (_b.label) {
96
+ case 0:
97
+ _a = this;
98
+ return [4 /*yield*/, this.options.fetchToken()];
99
+ case 1:
100
+ _a.token = _b.sent();
101
+ if (this.isClosed || this.token === null)
102
+ return [2 /*return*/];
103
+ socket = socket_client_service_1.SocketClientService.connect({
104
+ path: this.options.path,
105
+ token: function () { return _this.token; },
106
+ });
107
+ this.socket = socket;
108
+ this.options.events.forEach(function (name) {
109
+ return socket.on(name, function (payload) { return _this.options.onEvent(name, payload); });
110
+ });
111
+ socket.on(socket_live_config_1.SocketLiveConfig.connectEvent, function () { return _this.connected(); });
112
+ socket.on(socket_live_config_1.SocketLiveConfig.connectErrorEvent, function () { return _this.retryLater(); });
113
+ if (typeof document !== 'undefined')
114
+ document.addEventListener(socket_live_config_1.SocketLiveConfig.visibilityEvent, this.visibility);
115
+ return [2 /*return*/];
116
+ }
117
+ });
118
+ });
119
+ };
120
+ SocketLiveService.prototype.close = function () {
121
+ this.isClosed = true;
122
+ this.clearTimers();
123
+ if (typeof document !== 'undefined')
124
+ document.removeEventListener(socket_live_config_1.SocketLiveConfig.visibilityEvent, this.visibility);
125
+ if (this.socket !== null)
126
+ this.socket.disconnect();
127
+ };
128
+ SocketLiveService.prototype.connected = function () {
129
+ this.failures = 0;
130
+ if (this.hasConnected && this.options.onResume !== undefined)
131
+ this.options.onResume();
132
+ this.hasConnected = true;
133
+ };
134
+ SocketLiveService.prototype.retryLater = function () {
135
+ var _this = this;
136
+ if (this.isClosed || this.retryTimer !== null)
137
+ return;
138
+ var delay = Math.min(socket_live_config_1.SocketLiveConfig.retryBaseMilliseconds * Math.pow(2, this.failures), socket_live_config_1.SocketLiveConfig.maxRetryMilliseconds);
139
+ this.failures += 1;
140
+ this.retryTimer = setTimeout(function () {
141
+ _this.retryTimer = null;
142
+ void _this.reconnect();
143
+ }, delay);
144
+ };
145
+ SocketLiveService.prototype.reconnect = function () {
146
+ return __awaiter(this, void 0, void 0, function () {
147
+ var token;
148
+ return __generator(this, function (_a) {
149
+ switch (_a.label) {
150
+ case 0: return [4 /*yield*/, this.options.fetchToken()];
151
+ case 1:
152
+ token = _a.sent();
153
+ if (this.isClosed || this.socket === null)
154
+ return [2 /*return*/];
155
+ if (token === null)
156
+ return [2 /*return*/, this.retryLater()];
157
+ this.token = token;
158
+ this.socket.connect();
159
+ return [2 /*return*/];
160
+ }
161
+ });
162
+ });
163
+ };
164
+ SocketLiveService.prototype.clearTimers = function () {
165
+ if (this.retryTimer !== null)
166
+ clearTimeout(this.retryTimer);
167
+ if (this.hiddenTimer !== null)
168
+ clearTimeout(this.hiddenTimer);
169
+ this.retryTimer = null;
170
+ this.hiddenTimer = null;
171
+ };
172
+ return SocketLiveService;
173
+ }());
174
+ exports.SocketLiveService = SocketLiveService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-utilities",
3
- "version": "2.19.0",
3
+ "version": "2.20.0",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -44,7 +44,7 @@
44
44
  ],
45
45
  "scripts": {
46
46
  "husky:prepare": "npx husky",
47
- "build": "tsc && tsc -p tsconfig.esm.json && node -e \"require('fs').writeFileSync('dist/esm/package.json', JSON.stringify({ type: 'module' }))\"",
47
+ "build": "tsc && tsc -p tsconfig.esm.json && tsc-esm-fix --target=dist/esm --ext=.js && node -e \"require('fs').writeFileSync('dist/esm/package.json', JSON.stringify({ type: 'module' }))\"",
48
48
  "setup:graphify": "sh scripts/graphify-setup.sh",
49
49
  "update:graphify": "sh scripts/graphify-update.sh",
50
50
  "lint": "npm run lint:eslint",
@@ -82,6 +82,7 @@
82
82
  "semantic-release": "^24.2.0",
83
83
  "socket.io-client": "^4.8.3",
84
84
  "ts-node": "^10.9.2",
85
+ "tsc-esm-fix": "^3.1.2",
85
86
  "typescript": "^5.9.3",
86
87
  "vitest": "^3.2.7"
87
88
  },