fix(link-checker): reload page when installation params change on visibility restored [ES-322]#11030
fix(link-checker): reload page when installation params change on visibility restored [ES-322]#11030david-shibley-contentful wants to merge 4 commits into
Conversation
…ibility restored [ES-322] sdk.parameters.installation is a static snapshot from when the app iframe loaded. If a user updates the allow list in config and returns to the page app without a hard refresh, scans run against stale params — causing links to show as invalid even though they're on the allow list. Add a visibilitychange listener that fetches the current app installation parameters from the CMA when the tab becomes visible again and calls window.location.reload() if they differ from what the iframe loaded with. This is the in-app equivalent of the hard-refresh workaround (Ctrl+F5) that was given to the customer in ES-322. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sdk.cma.appInstallation in the Page SDK context only exposes getForOrganization, not get. Switch to getForOrganization and find the matching installation by spaceId + environmentId before comparing parameters to sdk.parameters.installation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
829b3ae to
20fac59
Compare
Mitch Goudy (mgoudy91)
left a comment
There was a problem hiding this comment.
Raised one issue around the JSON.stringify comparison being key-order-sensitive, which risks spurious reloads on every tab restore.
| item.sys.space.sys.id === sdk.ids.space && | ||
| item.sys.environment.sys.id === sdk.ids.environment | ||
| ); | ||
| if (JSON.stringify(match?.parameters) !== JSON.stringify(sdk.parameters.installation)) { |
There was a problem hiding this comment.
JSON.stringify comparison is key-order-sensitive — if the CMA response serializes object keys in a different order than the original SDK snapshot (common when two independent serialization paths are involved), this will produce a false mismatch and trigger a spurious reload on every tab restore. Consider a stable approach, e.g. sorting keys before stringifying or using a lightweight deep-equal utility:
const stableStringify = (obj: unknown) => JSON.stringify(obj, Object.keys(obj as object).sort());
if (stableStringify(match?.parameters) !== stableStringify(sdk.parameters.installation)) {Or import a deepEqual helper if one is already available in the project.
…nsensitive deepEqual Addresses Mitch's review: JSON.stringify is key-order-sensitive so a CMA response with the same params in a different key order would spuriously reload on every tab restore. Adds deepEqual helper and a dedicated test covering the out-of-order key case. Also fixes the existing no-reload test which was comparing mismatched fixtures and would have triggered reload. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
david-shibley-contentful
left a comment
There was a problem hiding this comment.
Good catch — JSON.stringify is key-order-sensitive. Replaced it with a recursive deepEqual helper that sorts keys before comparing. Also added a dedicated test that passes the same params in reverse key order and asserts no reload. While I was in there I also fixed the existing no-reload test — its CMA mock was returning { selectedContentTypeIds: ['article'] } while sdk.parameters.installation was {}, so it would have triggered a reload under any correct implementation.
ES-322
Summary
sdk.parameters.installationis a static snapshot from when the app iframe loaded. If a user updates the allow list in config and returns to the page app without a hard refresh, scans run against stale params — causing valid links to show as "Not on allow list"visibilitychangelistener that fetches current installation parameters from the CMA when the tab becomes visible again and callswindow.location.reload()if they differ — the in-app equivalent of the hard-refresh workaround given to the customerTest plan
npm testinapps/link-checker— all 60 tests pass including 2 new cases covering the reload and no-reload pathsGenerated with Claude Code