@elementor/editor-audits 4.4.0-1073 → 4.4.0-1075
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.
- package/dist/index.js +63 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +63 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -13
- package/src/api/page-context-client.ts +27 -8
- package/src/hooks/use-audit-report.ts +6 -0
- package/src/store/slice.ts +3 -0
- package/src/utils/session-expiration.ts +63 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-audits",
|
|
3
|
-
"version": "4.4.0-
|
|
3
|
+
"version": "4.4.0-1075",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,19 +39,19 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "4.4.0-
|
|
43
|
-
"@elementor/editor-mcp": "4.4.0-
|
|
44
|
-
"@elementor/editor-app-bar": "4.4.0-
|
|
45
|
-
"@elementor/editor-elements": "4.4.0-
|
|
46
|
-
"@elementor/editor-floating-panels": "4.4.0-
|
|
47
|
-
"@elementor/editor-notifications": "4.4.0-
|
|
48
|
-
"@elementor/editor-v1-adapters": "4.4.0-
|
|
49
|
-
"@elementor/events": "4.4.0-
|
|
50
|
-
"@elementor/http-client": "4.4.0-
|
|
42
|
+
"@elementor/editor": "4.4.0-1075",
|
|
43
|
+
"@elementor/editor-mcp": "4.4.0-1075",
|
|
44
|
+
"@elementor/editor-app-bar": "4.4.0-1075",
|
|
45
|
+
"@elementor/editor-elements": "4.4.0-1075",
|
|
46
|
+
"@elementor/editor-floating-panels": "4.4.0-1075",
|
|
47
|
+
"@elementor/editor-notifications": "4.4.0-1075",
|
|
48
|
+
"@elementor/editor-v1-adapters": "4.4.0-1075",
|
|
49
|
+
"@elementor/events": "4.4.0-1075",
|
|
50
|
+
"@elementor/http-client": "4.4.0-1075",
|
|
51
51
|
"@elementor/icons": "~1.77.0",
|
|
52
|
-
"@elementor/locations": "4.4.0-
|
|
53
|
-
"@elementor/session": "4.4.0-
|
|
54
|
-
"@elementor/store": "4.4.0-
|
|
52
|
+
"@elementor/locations": "4.4.0-1075",
|
|
53
|
+
"@elementor/session": "4.4.0-1075",
|
|
54
|
+
"@elementor/store": "4.4.0-1075",
|
|
55
55
|
"@elementor/ui": "1.37.5"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
@@ -1,19 +1,38 @@
|
|
|
1
1
|
import { httpService } from '@elementor/http-client';
|
|
2
2
|
|
|
3
3
|
import { type PageContextResponse } from '../types';
|
|
4
|
+
import { isNonceInvalidError, refreshAuditsNonce } from '../utils/session-expiration';
|
|
4
5
|
import { getWindowConfig } from '../utils/window-config';
|
|
5
6
|
|
|
6
7
|
export async function fetchPageContext( documentId: number, attachmentIds: number[] ): Promise< PageContextResponse > {
|
|
8
|
+
return requestPageContext( documentId, attachmentIds, true );
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function requestPageContext(
|
|
12
|
+
documentId: number,
|
|
13
|
+
attachmentIds: number[],
|
|
14
|
+
allowNonceRetry: boolean
|
|
15
|
+
): Promise< PageContextResponse > {
|
|
7
16
|
const { restNamespace, nonce } = getWindowConfig();
|
|
8
17
|
const url = `${ restNamespace }/audits/page-context`;
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
try {
|
|
20
|
+
const response = await httpService().get< PageContextResponse >( url, {
|
|
21
|
+
params: {
|
|
22
|
+
document_id: documentId,
|
|
23
|
+
attachment_ids: attachmentIds,
|
|
24
|
+
},
|
|
25
|
+
headers: { 'X-WP-Nonce': nonce },
|
|
26
|
+
} );
|
|
27
|
+
|
|
28
|
+
return response.data;
|
|
29
|
+
} catch ( error ) {
|
|
30
|
+
if ( ! allowNonceRetry || ! isNonceInvalidError( error ) ) {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
await refreshAuditsNonce();
|
|
17
35
|
|
|
18
|
-
|
|
36
|
+
return requestPageContext( documentId, attachmentIds, false );
|
|
37
|
+
}
|
|
19
38
|
}
|
|
@@ -5,6 +5,7 @@ import { __useDispatch as useDispatch, __useSelector as useSelector } from '@ele
|
|
|
5
5
|
import { runPageAudit } from '../runner';
|
|
6
6
|
import { type GlobalState, selectError, selectReport, selectStatus, slice } from '../store';
|
|
7
7
|
import { getPersistedReport, persistReport } from '../utils/report-storage';
|
|
8
|
+
import { SessionExpiredError } from '../utils/session-expiration';
|
|
8
9
|
|
|
9
10
|
export function useAuditReport() {
|
|
10
11
|
const status = useSelector( ( state: GlobalState ) => selectStatus( state ) );
|
|
@@ -35,6 +36,11 @@ export function useAuditReport() {
|
|
|
35
36
|
dispatch( slice.actions.runSucceeded( nextReport ) );
|
|
36
37
|
persistReport( documentIdToRun, nextReport );
|
|
37
38
|
} catch ( e ) {
|
|
39
|
+
if ( e instanceof SessionExpiredError ) {
|
|
40
|
+
dispatch( slice.actions.runAborted() );
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
38
44
|
dispatch( slice.actions.runFailed( e instanceof Error ? e.message : 'Unknown error' ) );
|
|
39
45
|
}
|
|
40
46
|
};
|
package/src/store/slice.ts
CHANGED
|
@@ -26,6 +26,9 @@ export const slice = __createSlice( {
|
|
|
26
26
|
state.status = 'error';
|
|
27
27
|
state.error = action.payload;
|
|
28
28
|
},
|
|
29
|
+
runAborted( state ) {
|
|
30
|
+
state.status = state.report ? 'ready' : 'idle';
|
|
31
|
+
},
|
|
29
32
|
reportRestored( state, action: PayloadAction< PageAuditReport > ) {
|
|
30
33
|
state.status = 'ready';
|
|
31
34
|
state.report = action.payload;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { getWindowConfig } from './window-config';
|
|
2
|
+
|
|
3
|
+
const NONCE_INVALID_CODE = 'rest_cookie_invalid_nonce';
|
|
4
|
+
const DEFAULT_AJAX_URL = '/wp-admin/admin-ajax.php';
|
|
5
|
+
|
|
6
|
+
type AjaxErrorLikeResponse = {
|
|
7
|
+
status?: number;
|
|
8
|
+
data?: { code?: string };
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type AjaxErrorLike = {
|
|
12
|
+
response?: AjaxErrorLikeResponse;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type SessionWindow = Window & {
|
|
16
|
+
elementorCommon?: { ajax?: { config?: { url?: string } } };
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export class SessionExpiredError extends Error {}
|
|
20
|
+
|
|
21
|
+
let nonceRefreshPromise: Promise< string > | null = null;
|
|
22
|
+
|
|
23
|
+
export function isNonceInvalidError( error: unknown ): boolean {
|
|
24
|
+
const response = ( error as AjaxErrorLike | undefined )?.response;
|
|
25
|
+
|
|
26
|
+
return response?.status === 403 && response?.data?.code === NONCE_INVALID_CODE;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function refreshAuditsNonce(): Promise< string > {
|
|
30
|
+
if ( nonceRefreshPromise ) {
|
|
31
|
+
return nonceRefreshPromise;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
nonceRefreshPromise = requestFreshNonce();
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
return await nonceRefreshPromise;
|
|
38
|
+
} finally {
|
|
39
|
+
nonceRefreshPromise = null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function requestFreshNonce(): Promise< string > {
|
|
44
|
+
const ajaxUrl = ( window as SessionWindow ).elementorCommon?.ajax?.config?.url ?? DEFAULT_AJAX_URL;
|
|
45
|
+
const url = new URL( ajaxUrl, window.location.origin );
|
|
46
|
+
url.searchParams.set( 'action', 'rest-nonce' );
|
|
47
|
+
|
|
48
|
+
const response = await fetch( url.toString(), { credentials: 'same-origin' } );
|
|
49
|
+
|
|
50
|
+
if ( ! response.ok ) {
|
|
51
|
+
throw new Error( `Failed to refresh audits nonce: HTTP ${ response.status }` );
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const nonce = await response.text();
|
|
55
|
+
|
|
56
|
+
if ( ! nonce || '0' === nonce ) {
|
|
57
|
+
throw new SessionExpiredError( 'Session expired — received invalid nonce' );
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
window.elementorAudits = { ...getWindowConfig(), nonce };
|
|
61
|
+
|
|
62
|
+
return nonce;
|
|
63
|
+
}
|