From c98dc270439e302b4b65dbb2c10deed37291fb0c Mon Sep 17 00:00:00 2001 From: Ben Peter Date: Tue, 16 Jun 2026 11:40:05 +0100 Subject: [PATCH] Add quick-edit support for Experience Workspace Migrate the codebase for Adobe Experience Workspace per the experience-workspace plugin's migrate-code skill: - Export loadPage from scripts.js - Add the quick-edit bootstrap that loads tools/quick-edit/quick-edit.js when the ?quick-edit param is present - Add tools/quick-edit/quick-edit.js (based on aemsites/author-kit) Harden the quick-edit loader against dynamic-import injection: the ?quick-edit param feeds the module origin, so the resolved hostname is validated against a trusted da-nx allowlist before import() rather than trusting the raw ref. Upstream author-kit omits this guard. Co-Authored-By: Claude Opus 4.8 --- scripts/scripts.js | 8 ++++- tools/quick-edit/quick-edit.js | 62 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tools/quick-edit/quick-edit.js diff --git a/scripts/scripts.js b/scripts/scripts.js index 60397b6..601bd77 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -121,10 +121,16 @@ function loadDelayed() { // load anything that can be postponed to the latest here } -async function loadPage() { +export async function loadPage() { await loadEager(document); await loadLazy(document); loadDelayed(); } loadPage(); + +(() => { + const hasQE = new URL(window.location.href).searchParams.has('quick-edit'); + // eslint-disable-next-line import/no-cycle + if (hasQE) import('../tools/quick-edit/quick-edit.js').then((mod) => mod.default()); +})(); diff --git a/tools/quick-edit/quick-edit.js b/tools/quick-edit/quick-edit.js new file mode 100644 index 0000000..ac45876 --- /dev/null +++ b/tools/quick-edit/quick-edit.js @@ -0,0 +1,62 @@ +// eslint-disable-next-line import/no-cycle +import { loadPage } from '../../scripts/scripts.js'; + +const importMap = { + imports: { + 'da-lit': 'https://da.live/deps/lit/dist/index.js', + 'da-y-wrapper': 'https://da.live/deps/da-y-wrapper/dist/index.js', + }, +}; + +function addImportmap() { + const importmapEl = document.createElement('script'); + importmapEl.type = 'importmap'; + importmapEl.textContent = JSON.stringify(importMap); + document.head.appendChild(importmapEl); +} + +async function loadModule(origin, payload) { + const url = new URL(`${origin}/nx/public/plugins/quick-edit/quick-edit.js`); + // Guard against dynamic-import injection via the `quick-edit` URL param: only + // load from trusted da-nx origins. Validating the resolved hostname (rather + // than the raw `ref`) covers any valid ref length/charset and cannot be + // bypassed by path/query/userinfo tricks. Upstream aemsites/author-kit omits + // this; see the filed issue. + const trusted = url.hostname === 'da.live' + || url.hostname === 'localhost' + || url.hostname.endsWith('--da-nx--adobe.aem.live'); + if (!trusted) return; + const { default: loadQuickEdit } = await import(url.href); + loadQuickEdit(payload, loadPage); +} + +function generateSidekickPayload() { + let { hostname } = window.location; + if (hostname === 'localhost') { + hostname = document.querySelector('meta[property="hlx:proxyUrl"]').content; + } + const parts = hostname.split('.')[0].split('--'); + const [, repo, owner] = parts; + + return { + detail: { + config: { + mountpoint: `https://content.da.live/${owner}/${repo}/`, + }, + location: { + pathname: window.location.pathname, + }, + }, + }; +} + +export default function init(payload) { + const { search } = window.location; + const ref = new URLSearchParams(search).get('quick-edit'); + let origin; + if (ref === 'on' || !ref) origin = 'https://da.live'; + if (ref === 'local') origin = 'http://localhost:6456'; + if (!origin) origin = `https://${ref}--da-nx--adobe.aem.live`; + addImportmap(); + loadModule(origin, payload || generateSidekickPayload()); +}