@pushwoosh/kit-helpers 4.11.2 → 4.12.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.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Retry / polling policy for a single operation.
3
+ *
4
+ * Retry is always opt-in: `callWithRetry` is the only entry point, so plain calls run once and
5
+ * non-idempotent operations are never retried unless a policy is passed.
6
+ */
7
+ export type RetryPolicy<T> = {
8
+ /** Maximum number of attempts, including the first one. Must be a positive integer. */
9
+ readonly attempts: number;
10
+ /** Delay in milliseconds between two consecutive attempts. */
11
+ readonly delay: number;
12
+ /**
13
+ * Poll predicate. Return `true` when the result is final and the loop must stop.
14
+ * Omit it to stop on the first successful result (plain retry, without polling).
15
+ */
16
+ readonly until?: (result: T) => boolean;
17
+ /**
18
+ * Decide whether to retry after a thrown error. Return `true` to retry.
19
+ * Omit it and errors propagate immediately, which keeps non-idempotent operations safe.
20
+ */
21
+ readonly retryOnError?: (error: unknown, attempt: number) => boolean;
22
+ };
23
+ /**
24
+ * Raised when a retry / polling policy runs out of attempts before its stop condition is met.
25
+ */
26
+ export declare class RetryExhaustedError extends Error {
27
+ constructor(message?: string);
28
+ }
29
+ /**
30
+ * Run an async operation under a retry / polling policy — the single place that owns the
31
+ * attempt loop and the delay between attempts. Callers describe *when* to stop (`until`) and
32
+ * *whether* to retry on error (`retryOnError`); they never hand-write the loop themselves.
33
+ *
34
+ * @param operation - operation to run; receives the 1-based attempt number.
35
+ * @param policy - retry / polling policy.
36
+ */
37
+ export declare const callWithRetry: <T>(operation: (attempt: number) => Promise<T>, policy: RetryPolicy<T>) => Promise<T>;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Raised when a retry / polling policy runs out of attempts before its stop condition is met.
3
+ */
4
+ export class RetryExhaustedError extends Error {
5
+ constructor(message = 'Retry attempts exhausted!') {
6
+ super(message);
7
+ this.name = 'RetryExhaustedError';
8
+ }
9
+ }
10
+ const sleep = ms => new Promise(resolve => {
11
+ setTimeout(resolve, ms);
12
+ });
13
+ /**
14
+ * Run an async operation under a retry / polling policy — the single place that owns the
15
+ * attempt loop and the delay between attempts. Callers describe *when* to stop (`until`) and
16
+ * *whether* to retry on error (`retryOnError`); they never hand-write the loop themselves.
17
+ *
18
+ * @param operation - operation to run; receives the 1-based attempt number.
19
+ * @param policy - retry / polling policy.
20
+ */
21
+ export const callWithRetry = async (operation, policy) => {
22
+ if (!Number.isInteger(policy.attempts) || policy.attempts < 1) {
23
+ throw new RangeError(`callWithRetry: "attempts" must be a positive integer, got ${policy.attempts}.`);
24
+ }
25
+ let lastAttempt = {
26
+ kind: 'unmet'
27
+ };
28
+ for (let attempt = 1; attempt <= policy.attempts; attempt += 1) {
29
+ try {
30
+ // eslint-disable-next-line no-await-in-loop
31
+ const result = await operation(attempt);
32
+ if (!policy.until || policy.until(result)) {
33
+ return result;
34
+ }
35
+ lastAttempt = {
36
+ kind: 'unmet'
37
+ };
38
+ } catch (error) {
39
+ var _policy$retryOnError;
40
+ if (((_policy$retryOnError = policy.retryOnError) === null || _policy$retryOnError === void 0 ? void 0 : _policy$retryOnError.call(policy, error, attempt)) !== true) {
41
+ throw error;
42
+ }
43
+ lastAttempt = {
44
+ kind: 'error',
45
+ error
46
+ };
47
+ }
48
+ if (attempt < policy.attempts) {
49
+ // eslint-disable-next-line no-await-in-loop
50
+ await sleep(policy.delay);
51
+ }
52
+ }
53
+ if (lastAttempt.kind === 'error') {
54
+ throw lastAttempt.error;
55
+ }
56
+ throw new RetryExhaustedError(`Retry policy exhausted after ${policy.attempts} attempt(s) without meeting the stop condition.`);
57
+ };
package/expand.d.ts CHANGED
@@ -1,11 +1,12 @@
1
- import React, { type FC, type ReactNode } from 'react';
1
+ import { type FC, type ReactNode } from 'react';
2
2
  type ExpandTransitionProps = {
3
3
  className?: string;
4
4
  timeout?: number;
5
5
  externalClassName?: string;
6
6
  internalClassName?: string;
7
+ children?: ReactNode;
7
8
  };
8
- export declare const ExpandTransition: import("styled-components").StyledComponent<React.FC<ExpandTransitionProps>, any, {}, never>;
9
+ export declare const ExpandTransition: import("styled-components").StyledComponent<FC<ExpandTransitionProps>, any, {}, never>;
9
10
  type CollapseProps = {
10
11
  expanded: boolean;
11
12
  timeout?: number;
package/flex.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CommonContainerProps } from './styled-helpers';
1
+ import { type CommonContainerProps } from './styled-helpers';
2
2
  type FlexContainerProps = CommonContainerProps & {
3
3
  $flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
4
4
  $flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
package/grid.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { StrNum, ItemAlignmentValue, CommonContainerProps } from './styled-helpers';
1
+ import { type StrNum, type ItemAlignmentValue, type CommonContainerProps } from './styled-helpers';
2
2
  export { toCssValue } from './styled-helpers';
3
3
  type GridContainerProps = CommonContainerProps & {
4
4
  $gridAutoFlow?: 'row' | 'column' | 'dense' | 'row dense' | 'column dense';
package/index.d.ts CHANGED
@@ -5,6 +5,8 @@ export * from './hooks/useClickAway';
5
5
  export { identifyOpenReplaySession } from './analytics/identifyOpenReplay';
6
6
  export { trackEvent } from './analytics/trackEvent';
7
7
  export { formatNumber } from './formatNumber';
8
+ export { callWithRetry, RetryExhaustedError } from './callWithRetry';
9
+ export type { RetryPolicy } from './callWithRetry';
8
10
  export { readNavigationHistory, writeNavigationHistory } from './navigation';
9
11
  export { default as usePersistentFunction } from './hooks/usePersistentFunction';
10
12
  export { default as useEffectOnce } from './hooks/useEffectOnce';
package/index.js CHANGED
@@ -5,6 +5,7 @@ export * from './hooks/useClickAway';
5
5
  export { identifyOpenReplaySession } from './analytics/identifyOpenReplay';
6
6
  export { trackEvent } from './analytics/trackEvent';
7
7
  export { formatNumber } from './formatNumber';
8
+ export { callWithRetry, RetryExhaustedError } from './callWithRetry';
8
9
  export { readNavigationHistory, writeNavigationHistory } from './navigation';
9
10
  export { default as usePersistentFunction } from './hooks/usePersistentFunction';
10
11
  export { default as useEffectOnce } from './hooks/useEffectOnce';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushwoosh/kit-helpers",
3
- "version": "4.11.2",
3
+ "version": "4.12.0",
4
4
  "description": "React component for build Pushwoosh products",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -11,7 +11,8 @@
11
11
  "build": "pushwoosh-engine lib:build && cp ai-documentation.md dist/ai-documentation.md",
12
12
  "playground": "pushwoosh-engine lib:playground",
13
13
  "check": "npm run check:lint && npm run check:types",
14
- "check:lint": "echo \"Run check:lint\" && eslint .",
14
+ "check:lint": "echo \"Run check:lint\" && NODE_ENV=production eslint ./src",
15
+ "check:lint-fix": "echo \"Run check:lint\" && NODE_ENV=production eslint ./src --fix",
15
16
  "check:types": "echo \"Run check:types\" && pushwoosh-engine lib:check-types"
16
17
  },
17
18
  "pre-commit": "check",
@@ -19,30 +20,21 @@
19
20
  "react-transition-group": "^4.4.5"
20
21
  },
21
22
  "devDependencies": {
22
- "@pushwoosh/frontend-builder-engine": "^2.1.1",
23
+ "@pushwoosh/frontend-builder-engine": "^3.0.0",
23
24
  "@pushwoosh/kit-constants": "^1.6.0",
24
- "@types/react": "^16.14.20",
25
- "@types/react-dom": "^16.9.14",
25
+ "@types/react": "^18.3.2",
26
+ "@types/react-dom": "^18.3.0",
26
27
  "@types/react-transition-group": "^4.4.10",
27
28
  "@types/styled-components": "^5.1.34",
28
- "@typescript-eslint/eslint-plugin": "^7.3.1",
29
- "@typescript-eslint/parser": "^7.3.1",
29
+ "@types/webpack-env": "^1.18.8",
30
30
  "cross-env": "^7.0.3",
31
- "eslint": "^8.31.0",
32
- "eslint-config-airbnb": "^19.0.4",
33
- "eslint-config-airbnb-typescript": "^18.0.0",
34
- "eslint-import-resolver-alias": "^1.1.2",
35
- "eslint-plugin-import": "^2.25.2",
36
- "eslint-plugin-jsx-a11y": "^6.4.1",
37
- "eslint-plugin-react": "^7.26.1",
38
- "eslint-plugin-react-hooks": "^4.2.0",
39
31
  "pre-commit": "^1.2.2",
40
- "react": "^16.14.0",
41
- "react-dom": "^16.14.0",
32
+ "react": "^18.3.1",
33
+ "react-dom": "^18.3.1",
42
34
  "styled-components": "^5.3.11"
43
35
  },
44
36
  "peerDependencies": {
45
- "react": ">=16.14.0",
37
+ "react": ">=18.0.0",
46
38
  "styled-components": ">=5.3.3"
47
39
  },
48
40
  "engines": {