@vcp-dev/site-edit-bridge 0.3.14
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/README.md +15 -0
- package/dist/auto-bootstrap.d.ts +51 -0
- package/dist/auto-bootstrap.js +1 -0
- package/dist/client.d.ts +204 -0
- package/dist/client.js +1 -0
- package/dist/designer-trace.d.ts +11 -0
- package/dist/designer-trace.js +1 -0
- package/dist/document-codec.d.ts +27 -0
- package/dist/document-codec.js +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/next-dev-server.d.ts +43 -0
- package/dist/next-dev-server.js +6 -0
- package/dist/protocol.d.ts +152 -0
- package/dist/server.d.ts +54 -0
- package/dist/server.js +4 -0
- package/dist/start-next-dev-server.js +59 -0
- package/dist/window-message.d.ts +337 -0
- package/dist/window-message.js +1 -0
- package/package.json +87 -0
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @vcp-dev/site-edit-bridge
|
|
2
|
+
|
|
3
|
+
浏览器端 site edit client、自动 bootstrap 以及 Node 侧 WebSocket bridge server。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @vcp-dev/contracts @vcp-dev/site-edit-engine @vcp-dev/site-edit-bridge
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 用途
|
|
12
|
+
|
|
13
|
+
- 浏览器 WebSocket client
|
|
14
|
+
- 自动接入页面桥接
|
|
15
|
+
- Node.js WebSocket bridge server
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { SiteEditRenderDocument, SiteEditRenderEntry } from "@vcp-dev/contracts";
|
|
2
|
+
import { type SiteEditBridgeClient, type SiteEditBridge } from "./client.js";
|
|
3
|
+
declare global {
|
|
4
|
+
interface Window {
|
|
5
|
+
__VCP_SITE_EDIT__?: SiteEditBridge;
|
|
6
|
+
__VCP_SITE_EDIT_AUTO_BOOTSTRAP__?: {
|
|
7
|
+
started: boolean;
|
|
8
|
+
routeId?: string;
|
|
9
|
+
cleanup?: () => void;
|
|
10
|
+
syncRoute?: () => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
__VCP_SITE_EDIT_VERSION_LOGGED__?: boolean;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export declare const VCP_SITE_EDIT_ROUTE_READY_EVENT = "vcp-site-edit:route-ready";
|
|
16
|
+
export type SiteEditRouteReadyDetail = {
|
|
17
|
+
routeId: string;
|
|
18
|
+
version: number;
|
|
19
|
+
};
|
|
20
|
+
export type SiteEditAutoBootstrapOptions = {
|
|
21
|
+
explicit_ws_url?: string;
|
|
22
|
+
basePath?: string;
|
|
23
|
+
ws_port?: string;
|
|
24
|
+
wsPath?: string;
|
|
25
|
+
bridge_session_key?: string;
|
|
26
|
+
defer_initial_sync?: boolean;
|
|
27
|
+
runtime_versions?: SiteEditRuntimeVersions;
|
|
28
|
+
create_client?: (url: string) => SiteEditBootstrapClient;
|
|
29
|
+
schedule_after_navigation?: (callback: () => void) => void;
|
|
30
|
+
};
|
|
31
|
+
export type SiteEditRuntimeVersions = {
|
|
32
|
+
bridge?: string;
|
|
33
|
+
contracts?: string;
|
|
34
|
+
engine?: string;
|
|
35
|
+
};
|
|
36
|
+
export type SiteEditBootstrapClient = SiteEditBridgeClient & {
|
|
37
|
+
connect(): Promise<void>;
|
|
38
|
+
disconnect(): void;
|
|
39
|
+
};
|
|
40
|
+
export declare function resolveSiteEditRouteId(pathname: string, basePath?: string): string;
|
|
41
|
+
export declare function resolveSiteEditWebSocketUrl(windowLike: Pick<Window, "location">, options?: {
|
|
42
|
+
explicit_ws_url?: string;
|
|
43
|
+
port?: string;
|
|
44
|
+
path?: string;
|
|
45
|
+
bridge_session_key?: string;
|
|
46
|
+
}): string;
|
|
47
|
+
export declare function startSiteEditAutoBootstrap(windowLike?: Window & typeof globalThis, options?: SiteEditAutoBootstrapOptions): Promise<void>;
|
|
48
|
+
export declare function startSiteEditFrameRuntime(windowLike?: Window & typeof globalThis, options?: {
|
|
49
|
+
getCurrentDocument?: () => SiteEditRenderDocument | null;
|
|
50
|
+
getDocumentEntry?: (key: string) => SiteEditRenderEntry | null;
|
|
51
|
+
}): () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function de(e){if(!Ve(e))return e;let t=new Map,n=r=>{let o=t.get(r);if(o)return o;let s=e.nodes[r];if(!s)throw new Error(`Missing compact document node ${r}`);let i=e.tokens[s.token];if(typeof i!="string")throw new Error(`Missing compact document token ${s.token}`);let u=`${s.parent===null?"":n(s.parent)}${i}`;return t.set(r,u),u};return{siteId:e.siteId,snapshotId:e.snapshotId,routeId:e.routeId,version:e.version,rootKeys:e.rootKeyNodeIds.map(n),entries:e.entries.map(r=>({key:n(r.keyNodeId),tag:r.tag,label:r.label,parentKey:r.parentKeyNodeId===null?null:n(r.parentKeyNodeId),childKeys:r.childKeyNodeIds.map(n),operationSummary:r.operationSummary}))}}function Ve(e){return typeof e=="object"&&e!==null&&"encoding"in e&&e.encoding==="segment-trie-v1"}var U=class e{constructor(){}static parseMessage(t,n={}){let r=JSON.parse(t);if(!e.isMessage(r,n))throw new Error("Invalid site edit bridge message");return r}static stringifyMessage(t){return JSON.stringify(t)}static extractRequestInfo(t){if(typeof t=="object"&&t!==null&&"payload"in t&&typeof t.payload=="object"&&t.payload!==null){let n=t.payload,r=typeof n.id=="string"?n.id:"unknown",o=e.isRequestKind(n.kind)?n.kind:"get-document";return{id:r,kind:o}}return{id:"unknown",kind:"get-document"}}static isRequestKind(t){return t==="get-document"||t==="get-object-summary"||t==="get-object-edit-context"||t==="get-class-name-source"||t==="execute"||t==="undo"||t==="redo"}static isMessage(t,n={}){return!M(t)||typeof t.type!="string"?!1:t.type==="request"?e.isRequestPayload(t.payload,n):t.type==="response"||t.type==="error"?M(t.payload)&&typeof t.payload.id=="string":t.type==="event"?M(t.payload)&&M(t.payload.event):!1}static isRequestPayload(t,n={}){if(!M(t)||typeof t.id!="string"||!e.isRequestKind(t.kind))return!1;switch(t.kind){case"get-document":return typeof t.routeId=="string";case"get-object-summary":case"get-object-edit-context":case"get-class-name-source":return typeof t.key=="string"&&(t.routeId===void 0||typeof t.routeId=="string");case"execute":return We(t.request)&&(n.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return!0}}};function M(e){return typeof e=="object"&&e!==null}function We(e){return M(e)&&typeof e.id=="string"&&typeof e.siteId=="string"&&typeof e.baseSnapshotId=="string"&&(e.routeId===void 0||typeof e.routeId=="string")&&typeof e.kind=="string"&&M(e.target)&&typeof e.documentVersion=="number"&&Number.isInteger(e.documentVersion)&&e.documentVersion>=0&&M(e.params)}var je="vcp:designer:trace",Ue="designer_trace",pe="__VCP_DESIGNER_TRACE__";var $e=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function Ye(e=globalThis){let t=e;try{if(t.localStorage?.getItem(je)==="1")return!0}catch{}try{let n=t.location?.search??"";return new URLSearchParams(n).get(Ue)==="1"}catch{return!1}}function K(e,t={},n=globalThis){if(!Ye(n))return;let r={type:e,timestamp:Date.now(),payload:Ge(t)},o=n,s=o[pe]??[];s.push(r),s.length>200&&s.splice(0,s.length-200),o[pe]=s;let i=n.console?.debug;typeof i=="function"&&i.call(n.console,"[designer-trace]",r)}function Ge(e){return L(e,0)}function L(e,t){if(t>4)return"[truncated]";if(Array.isArray(e))return e.map(r=>L(r,t+1));if(!e||typeof e!="object")return e;let n={};for(let[r,o]of Object.entries(e)){if($e.test(r)){n[r]="[redacted]";continue}n[r]=L(o,t+1)}return n}var H=class{constructor(t){this.options=t,this.socket=null,this.sequence=0,this.pending=new Map,this.listeners=new Set}connect(){return this.socket?Promise.resolve():new Promise((t,n)=>{let r=this.createSocket(this.options.url);this.socket=r,r.onopen=()=>t(),r.onerror=o=>{n(o instanceof Error?o:new Error("WebSocket failed"))},r.onmessage=o=>this.handleMessage(o.data),r.onclose=()=>{this.rejectAll(new Error("WebSocket closed")),this.socket=null}})}disconnect(){this.socket?.close(),this.socket=null,this.rejectAll(new Error("WebSocket disconnected"))}getDocument(t){return this.request("get-document",{routeId:t})}getObjectSummary(t,n){return this.request("get-object-summary",{key:t,routeId:n})}getObjectEditContext(t,n){return this.request("get-object-edit-context",{key:t,routeId:n})}getClassNameSource(t,n){return this.request("get-class-name-source",{key:t,routeId:n})}execute(t){return this.request("execute",{request:t})}undo(){return this.request("undo",{})}redo(){return this.request("redo",{})}subscribe(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}request(t,n){let r=this.socket;if(!r)return Promise.reject(new Error("WebSocket is not connected"));let o=`${t}-${this.sequence+=1}`,s=we(o,t,n);return K("bridge.request",{id:o,kind:t,routeId:typeof n.routeId=="string"?n.routeId:null,key:typeof n.key=="string"?n.key:null,operationKind:fe(n.request,"kind"),documentVersion:fe(n.request,"documentVersion")}),new Promise((i,u)=>{this.pending.set(o,{kind:t,resolve:d=>i(d),reject:u}),r.send(U.stringifyMessage(s))})}handleMessage(t){let n=U.parseMessage(t);if(n.type==="event"){for(let o of this.listeners)o(n.payload.event);return}if(n.type!=="response"&&n.type!=="error")return;let r=this.pending.get(n.payload.id);if(r){if(this.pending.delete(n.payload.id),n.type==="error"){K("bridge.response",{id:n.payload.id,kind:r.kind,ok:!1}),r.reject(new Error(n.payload.message));return}K("bridge.response",{id:n.payload.id,kind:r.kind,ok:!0,resultVersion:Xe(n.payload.result)}),r.resolve(r.kind==="get-document"?{...n.payload.result,data:de(n.payload.result.data)}:n.payload.result)}}rejectAll(t){for(let n of this.pending.values())n.reject(t);this.pending.clear()}createSocket(t){if(this.options.createSocket)return this.options.createSocket(t);if(typeof WebSocket>"u")throw new Error("Site edit preview bridge requires WebSocket");return new WebSocket(t)}};function fe(e,t){if(!e||typeof e!="object")return null;let r=e[t];return typeof r=="string"||typeof r=="number"?r:null}function Xe(e){if(!e||typeof e!="object")return null;let t=e,n=t.data?.resultVersion??t.data?.version??null;return typeof n=="number"?n:null}function me(e){return new ee(e)}var ee=class{constructor(t){this.params=t,this.refreshInFlight=null,this.currentDocument=t.initialDocument,this.summaryCache=new Map(Object.entries(t.initialDetails??{}).map(([n,r])=>[n,ze(r)])),this.editContextCache=new Map(Object.entries(t.initialDetails??{}).map(([n,r])=>[n,Je(r)]))}async getDocument(t){if(t!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${t}`);return He(this.currentDocument)&&(this.currentDocument=await this.refreshSnapshot(void 0,"get-document")),{ok:!0,data:this.currentDocument}}async ensureDocumentVersion(t,n){if(t!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${t}`);let r=await this.refreshSnapshot(n,"ensure-version");if(r.version<n)throw new Error(`Document refresh returned version ${r.version}, expected at least ${n}`);return{ok:!0,data:r}}async getObjectSummary(t,n){let r=this.summaryCache.get(t);if(r)return{ok:!0,data:r};let o=await this.params.client.getObjectSummary(t,n??this.params.routeId);return this.summaryCache.set(t,o.data),o}async getObjectEditContext(t,n){let r=this.editContextCache.get(t);if(r)return{ok:!0,data:r};let o=await this.params.client.getObjectEditContext(t,n??this.params.routeId);return this.editContextCache.set(t,o.data),o}async getClassNameSource(t,n){return this.params.client.getClassNameSource(t,n??this.params.routeId)}async execute(t){return this.params.client.execute(t.target.kind==="node"&&!t.routeId?{...t,routeId:this.params.routeId}:t)}async undo(){return this.params.client.undo()}async redo(){return this.params.client.redo()}subscribe(t){return this.params.client.subscribe(n=>{if(n.type==="site-edit.document.changed"&&n.routeId===this.params.routeId){this.refreshSnapshot(n.version,"event").catch(()=>{}).finally(()=>t(n));return}t(n)})}async refreshSnapshot(t,n="ensure-version"){if(typeof t=="number"&&this.currentDocument.version>=t)return K("bridge.document-refresh",{routeId:this.params.routeId,minVersion:t,currentVersion:this.currentDocument.version,deduped:!0,skipped:!0,source:n}),this.currentDocument;if(this.refreshInFlight){K("bridge.document-refresh",{routeId:this.params.routeId,minVersion:t,currentVersion:this.currentDocument.version,deduped:!0,source:n});let o=await this.refreshInFlight;if(typeof t!="number"||o.version>=t||this.currentDocument.version>=t)return this.currentDocument}K("bridge.document-refresh",{routeId:this.params.routeId,minVersion:t,currentVersion:this.currentDocument.version,deduped:!1,source:n});let r=this.params.client.getDocument(this.params.routeId).then(o=>(this.currentDocument=o.data,this.clearObjectCaches(),this.currentDocument));this.refreshInFlight=r;try{return await r}finally{this.refreshInFlight===r&&(this.refreshInFlight=null)}}clearObjectCaches(){this.summaryCache.clear(),this.editContextCache.clear()}};function He(e){return e.version===0&&e.rootKeys.length===0}function we(e,t,n){switch(t){case"get-document":return{type:"request",payload:{id:e,kind:t,routeId:String(n.routeId)}};case"get-object-summary":return{type:"request",payload:{id:e,kind:t,key:String(n.key),routeId:typeof n.routeId=="string"?n.routeId:void 0}};case"get-object-edit-context":return{type:"request",payload:{id:e,kind:t,key:String(n.key),routeId:typeof n.routeId=="string"?n.routeId:void 0}};case"get-class-name-source":return{type:"request",payload:{id:e,kind:t,key:String(n.key),routeId:typeof n.routeId=="string"?n.routeId:void 0}};case"execute":return{type:"request",payload:{id:e,kind:t,request:n.request}};case"undo":case"redo":return{type:"request",payload:{id:e,kind:t}}}}function ze(e){return{key:e.key,tag:e.tag,label:e.label,capabilities:{constraints:e.capabilities.constraints},isOpaque:e.isOpaque,provenanceChain:e.provenanceChain?{editMode:e.provenanceChain.editMode,diagnostics:e.provenanceChain.diagnostics}:void 0,ancestors:e.ancestors}}function Je(e){return{key:e.key,componentName:e.componentName,sourceFile:e.sourceFile,capabilities:e.capabilities,writeTarget:e.writeTarget,effectiveWriteTarget:e.effectiveWriteTarget,provenanceChain:e.provenanceChain,componentSemantic:e.componentSemantic,textSegments:e.textSegments,boundaryKind:e.boundaryKind,children:e.children,siblings:e.siblings}}var he="vcp-window-message";function Qe(e){return{source:he,version:1,namespace:e.namespace,channel:e.channel,...e.sessionKey?{sessionKey:e.sessionKey}:{},body:e.body}}function Ze(e){if(typeof e!="object"||e===null)return!1;let t=e;return t.source===he&&t.version===1&&typeof t.namespace=="string"&&typeof t.channel=="string"&&"body"in t}var ye="site-edit",ge="frame-runtime";function $(e,t={}){return Qe({namespace:ye,channel:ge,sessionKey:t.sessionKey,body:e})}function be(e){return!Ze(e)||e.namespace!==ye||e.channel!==ge?!1:typeof e.body?.type=="string"}var re="vcp-site-edit:route-ready",Le=1e3,et="data-vcp-ui-component",xe="data-vcp-theme-preview",Ee="::repeat-item#",w="components/ui",tt=new Set(["article","aside","div","footer","form","header","li","main","nav","ol","section","select","table","tbody","tfoot","thead","tr","ul"]),nt=new Set(["a","button","em","h1","h2","h3","h4","h5","h6","label","p","small","span","strong"]);function rt(e,t=""){let n=mt(t),r=n&&(e===n||e.startsWith(`${n}/`))?e.slice(n.length)||"/":e,o=r.startsWith("/")?r:`/${r}`;return o==="/"?"/":o.replace(/\/+$/,"")}function ot(e,t){if(e.__VCP_SITE_EDIT_VERSION_LOGGED__)return;let n=e.console?.info;typeof n=="function"&&(e.__VCP_SITE_EDIT_VERSION_LOGGED__=!0,n.call(e.console,"[VCP Site Edit] runtime loaded",{bridge:t.versions?.bridge??"unknown",contracts:t.versions?.contracts??"unknown",documentVersion:t.documentVersion,engine:t.versions?.engine??"unknown",routeId:t.routeId}))}function st(e,t={}){let n=s=>{if(!t.bridge_session_key)return s;let i=new URL(s,e.location.href);return i.searchParams.set("vcp_bridge_key",t.bridge_session_key),i.toString()};if(t.explicit_ws_url){if(t.explicit_ws_url.startsWith("/")){let s=e.location.protocol==="https:"?"wss:":"ws:";return n(`${s}//${e.location.host}${t.explicit_ws_url}`)}return n(t.explicit_ws_url)}let r=e.location.protocol==="https:"?"wss:":"ws:",o=t.port?`${e.location.hostname}:${t.port}`:e.location.host;return n(`${r}//${o}${t.path??"/__vcp/site-edit/bridge"}`)}async function pn(e=window,t={}){if(e.__VCP_SITE_EDIT_AUTO_BOOTSTRAP__?.started)return;let n={activeClient:null,cleanupFrameRuntime:(()=>{}),retryTimer:void 0,routeSequence:0,currentDocument:null,currentEntriesByKey:new Map,unsubscribeDocument:void 0,unbindRouteChange:void 0};n.cleanupFrameRuntime=ut(e,{getCurrentDocument:()=>n.currentDocument,getDocumentEntry:a=>n.currentEntriesByKey.get(a)??null});let r=t.create_client??(a=>new H({url:a})),o=t.schedule_after_navigation??pt,s=st(e,{explicit_ws_url:t.explicit_ws_url,port:t.ws_port,path:t.wsPath||"/__vcp/site-edit/bridge",bridge_session_key:t.bridge_session_key}),i=()=>{n.retryTimer&&(e.clearTimeout(n.retryTimer),n.retryTimer=void 0)},u=a=>{n.currentDocument=a,n.currentEntriesByKey=new Map((a?.entries??[]).map(R=>[R.key,R]))},d=async(a,R)=>{let E=e.__VCP_SITE_EDIT__;if(!E)return null;let b=await E.getDocument(a);return R!==n.routeSequence||a!==e.__VCP_SITE_EDIT_AUTO_BOOTSTRAP__?.routeId||u(b.data),b.data},y=()=>{n.unsubscribeDocument?.(),n.unsubscribeDocument=void 0,u(null),delete e.__VCP_SITE_EDIT__,n.activeClient?.disconnect(),n.activeClient=null},m=async()=>{let a=rt(e.location.pathname,t.basePath||"");if(a===e.__VCP_SITE_EDIT_AUTO_BOOTSTRAP__?.routeId&&e.__VCP_SITE_EDIT__)return;let R=n.routeSequence+=1;i(),y();let E=r(s);try{if(await E.connect(),R!==n.routeSequence){E.disconnect();return}e.__VCP_SITE_EDIT__=me({routeId:a,client:E,initialDocument:it(a)}),n.activeClient=E,n.unsubscribeDocument=e.__VCP_SITE_EDIT__.subscribe(N=>{N.type==="site-edit.document.changed"&&N.routeId===a&&d(a,R).catch(()=>{})}),e.__VCP_SITE_EDIT_AUTO_BOOTSTRAP__.routeId=a;let b=await d(a,R);ot(e,{documentVersion:b?.version??0,routeId:a,versions:t.runtime_versions}),ft(e,{routeId:a,version:b?.version??0})}catch(b){throw E.disconnect(),b}},v=()=>{i(),n.retryTimer=e.setTimeout(()=>{m().catch(()=>v())},Le)},_=()=>{o(()=>{m().catch(()=>v())})};if(e.__VCP_SITE_EDIT_AUTO_BOOTSTRAP__={started:!0,syncRoute:m,cleanup:()=>{i(),n.routeSequence+=1,n.unbindRouteChange?.(),n.cleanupFrameRuntime(),y(),delete e.__VCP_SITE_EDIT_AUTO_BOOTSTRAP__}},n.unbindRouteChange=dt(e,_),t.defer_initial_sync){_();return}await m()}function it(e){return{siteId:"preview",snapshotId:"preview",routeId:e,version:0,rootKeys:[],entries:[]}}function ut(e=window,t={}){let n=null,r=null,o=null,s=null,i=null,u=null,d=new Map,y=()=>{n?.(),n=null},m=()=>{r?.(),r=null,o?.(),o=null},v=(I,l,c)=>{let T=s?.sessionKey!==I||s?.sourceWindow!==l||s?.targetOrigin!==c;s={sessionKey:I,sourceWindow:l,targetOrigin:c},T&&(u=null)},_=()=>{for(let I of d.values())I();d.clear()},a=I=>{i=I.routeId==="/"?null:I;let l=`${I.routeId}:${I.version}`;u!==l&&(o?.(),o=null,E({kind:"route-ready",payload:{routeId:I.routeId,version:I.version}}),s&&(u=l))},R=()=>{i&&a(i)},E=I=>{s&&s.sourceWindow.postMessage($({type:"event",...I},{sessionKey:s.sessionKey}),s.targetOrigin)},b=(I,l,c,T)=>{let S=Q(e.document,l.clientX,l.clientY),x=S?D(S,c==="full"?A(e.document,S,t.getCurrentDocument?.()??null):ve(e.document,S,t.getCurrentDocument?.()??null),t.getDocumentEntry,c):null;T&&x&&(I==="pointer-click"||I==="pointer-double-click")&&(T.preventDefault(),T.stopPropagation(),typeof T.stopImmediatePropagation=="function"&&T.stopImmediatePropagation()),E({kind:I,payload:{clientX:l.clientX,clientY:l.clientY,buttons:Number(l.buttons??0),hit:x}})},N=(I,l,c)=>{m(),s={sessionKey:I,sourceWindow:l,targetOrigin:c};let T=Jt(e.document),S=null,x=null,f=()=>{x=null;let p=S;S=null,p&&b("pointer-move",p,"summary")},k=p=>{S={clientX:Number(p.clientX),clientY:Number(p.clientY),buttons:Number(p.buttons)},x===null&&(x=Ce(e,f))},F=p=>{b("pointer-down",{clientX:Number(p.clientX),clientY:Number(p.clientY),buttons:Number(p.buttons)},"full",p)},B=p=>{b("pointer-up",{clientX:Number(p.clientX),clientY:Number(p.clientY),buttons:Number(p.buttons)},"summary",p)},P=p=>{b("pointer-cancel",{clientX:Number(p.clientX),clientY:Number(p.clientY),buttons:Number(p.buttons)},"summary",p)},q=p=>{b("pointer-click",{clientX:Number(p.clientX),clientY:Number(p.clientY),buttons:Number(p.buttons)},"full",p)},W=p=>{b("pointer-double-click",{clientX:Number(p.clientX),clientY:Number(p.clientY),buttons:Number(p.buttons)},"full",p)},j=()=>{E({kind:"scroll",payload:{metrics:J(e)}})};e.document.addEventListener("pointerdown",F,!0),e.document.addEventListener("pointermove",k,{passive:!0,capture:!0}),e.document.addEventListener("pointerup",B,!0),e.document.addEventListener("pointercancel",P,!0),e.document.addEventListener("click",q,!0),e.document.addEventListener("dblclick",W,!0),e.addEventListener("scroll",j,{passive:!0}),r=()=>{x!==null&&(Ne(e,x),x=null),S=null,T(),e.document.removeEventListener("pointerdown",F,!0),e.document.removeEventListener("pointermove",k,!0),e.document.removeEventListener("pointerup",B,!0),e.document.removeEventListener("pointercancel",P,!0),e.document.removeEventListener("click",q,!0),e.document.removeEventListener("dblclick",W,!0),e.removeEventListener("scroll",j)}},ae=I=>{let l=I.detail;l?.routeId&&a(l)},le=I=>{let l=I.data;if(!be(l)||l.body.type!=="request"||l.body.kind!=="apply-node-patch"&&l.body.kind!=="get-hit-by-ref"&&l.body.kind!=="get-path-by-ref"&&l.body.kind!=="get-scroll-metrics"&&l.body.kind!=="scroll-to"&&l.body.kind!=="scroll-by"&&l.body.kind!=="set-interaction-mode"&&l.body.kind!=="set-theme-override"&&l.body.kind!=="clear-theme-override"&&l.body.kind!=="get-theme-variables"&&l.body.kind!=="compute-drop-target-at-point"&&l.body.kind!=="observe-node-bounds"&&l.body.kind!=="clear-node-bounds-observer"&&l.body.kind!=="start-text-edit-at-point"&&l.body.kind!=="hit-test-at-point"&&!Ie(l.body))return;let c=l.body,T=typeof l.sessionKey=="string"?l.sessionKey:null,S=I.source,x=I.origin;if(!T||!x||!S||typeof S.postMessage!="function"||s&&(s.sessionKey!==T||s.sourceWindow!==S||s.targetOrigin!==x))return;v(T,S,x),R();let f=k=>{let F=typeof c.id=="string"?c.id:"unknown";S.postMessage($({id:F,...k},{sessionKey:T}),x)};try{if(Ie(c)){ct({message:c,sendEvent:h=>{S.postMessage($({type:"event",...h},{sessionKey:T}),x)},sendResponse:f,subscriptions:d,getCurrentDocument:t.getCurrentDocument,windowLike:e});return}if(c.kind==="apply-node-patch"){let h=V(e.document,c.payload.ref,t.getCurrentDocument?.()??null);if(!h){f({type:"response",ok:!1,error:"No editable element found for patch target"});return}let g=c.payload.preview,C=g?qt(g.sessionId,c.payload.ref):null;if(C&&g){let X=Y.get(C)??-1;if(g.revision<X){f({type:"response",ok:!0,result:{applied:!1,appliedRevision:g.revision,stale:!0,latestRevision:X}});return}if(g.revision===X){f({type:"response",ok:!0,result:{applied:!1,appliedRevision:g.revision,duplicate:!0,latestRevision:X}});return}}if(Ft(h,c.payload.patch),C&&g&&Kt(C,g.revision),g?.responseDetail==="none"){f({type:"response",ok:!0,result:{applied:!0,appliedRevision:g.revision}});return}f({type:"response",ok:!0,result:D(h,A(e.document,h,t.getCurrentDocument?.()??null),t.getDocumentEntry,g?.responseDetail??"full")});return}if(c.kind==="get-hit-by-ref"){let h=V(e.document,c.payload.ref,t.getCurrentDocument?.()??null);if(!h){f({type:"response",ok:!1,error:"No editable element found for hit target"});return}f({type:"response",ok:!0,result:D(h,A(e.document,h,t.getCurrentDocument?.()??null),t.getDocumentEntry,"full")});return}if(c.kind==="get-path-by-ref"){let h=V(e.document,c.payload.ref,t.getCurrentDocument?.()??null);if(!h){f({type:"response",ok:!1,error:"No editable element found for path target"});return}let g=[],C=h;for(;C;)C.getAttribute("data-vcp-edit-key")&&g.push(D(C,A(e.document,C,t.getCurrentDocument?.()??null),t.getDocumentEntry,"full")),C=C.parentElement;f({type:"response",ok:!0,result:g.reverse()});return}if(c.kind==="get-scroll-metrics"){f({type:"response",ok:!0,result:J(e)});return}if(c.kind==="scroll-to"){let h=Number(c.payload.x),g=Number(c.payload.y);if(!Number.isFinite(h)||!Number.isFinite(g)){f({type:"response",ok:!1,error:"Invalid scroll position"});return}e.scrollTo({left:h,top:g}),f({type:"response",ok:!0,result:J(e)});return}if(c.kind==="scroll-by"){let h=Number(c.payload.deltaX),g=Number(c.payload.deltaY);if(!Number.isFinite(h)||!Number.isFinite(g)){f({type:"response",ok:!1,error:"Invalid scroll delta"});return}e.scrollBy({left:h,top:g}),f({type:"response",ok:!0,result:{...J(e),scrolled:!0}});return}if(c.kind==="set-interaction-mode"){c.payload.enabled?N(T,S,x):s?.sourceWindow===S&&s.targetOrigin===x&&s.sessionKey===T&&m(),f({type:"response",ok:!0,result:{interactionEnabled:c.payload.enabled}});return}if(c.kind==="set-theme-override"){Bt(e.document,c.payload),f({type:"response",ok:!0,result:{themeOverrideApplied:!0}});return}if(c.kind==="clear-theme-override"){Vt(e.document),f({type:"response",ok:!0,result:{themeOverrideCleared:!0}});return}if(c.kind==="get-theme-variables"){f({type:"response",ok:!0,result:Wt(e.document,c.payload.names)});return}if(c.kind==="compute-drop-target-at-point"){let h=Number(c.payload?.x),g=Number(c.payload?.y);if(!Number.isFinite(h)||!Number.isFinite(g)){f({type:"response",ok:!1,error:"Invalid drop target point"});return}f({type:"response",ok:!0,result:Dt(e,h,g,c.payload.dragKind,c.payload.movingRef,t.getCurrentDocument?.()??null,t.getDocumentEntry)});return}if(c.kind==="observe-node-bounds"){let h=c.payload.ref;if(!h){f({type:"response",ok:!1,error:"Missing bounds observer target"});return}let g=V(e.document,h,t.getCurrentDocument?.()??null);if(!g){f({type:"response",ok:!1,error:"No editable element found for bounds observer target"});return}o?.(),o=Nt(e,g,h,t.getDocumentEntry,C=>E({kind:"node-bounds-change",payload:{hit:C}})),f({type:"response",ok:!0,result:{observing:!0}}),E({kind:"node-bounds-change",payload:{hit:D(g,h,t.getDocumentEntry,"summary")}});return}if(c.kind==="clear-node-bounds-observer"){o?.(),o=null,f({type:"response",ok:!0,result:{cleared:!0}});return}if(c.kind!=="hit-test-at-point"&&c.kind!=="start-text-edit-at-point")return;let k=Number(c.payload?.x),F=Number(c.payload?.y);if(!Number.isFinite(k)||!Number.isFinite(F)){f({type:"response",ok:!1,error:"Invalid text edit point"});return}let B=c.kind==="hit-test-at-point"?Q(e.document,k,F):yt(e.document,k,F,t.getCurrentDocument?.()??null,t.getDocumentEntry);if(!B){f({type:"response",ok:!1,error:c.kind==="hit-test-at-point"?"No editable element at point":"No editable text element at point"});return}let P=c.kind==="start-text-edit-at-point"?B:null,q=c.kind==="hit-test-at-point"?B:P.element,W=c.payload.detailLevel??"full",j=W==="full"?A(e.document,q,t.getCurrentDocument?.()??null):ve(e.document,q,t.getCurrentDocument?.()??null),p=P&&typeof P.textSegmentIndex=="number"?{...j,textSegmentIndex:P.textSegmentIndex}:j,Be=D(q,p,t.getDocumentEntry,W);if(c.kind==="hit-test-at-point"){f({type:"response",ok:!0,result:Be});return}y(),n=Yt(e,q,p,h=>{S.postMessage($({type:"event",...h},{sessionKey:T}),x)},P?{textNode:P.textNode}:void 0),f({type:"response",ok:!0,result:{ref:p}})}catch(k){f({type:"response",ok:!1,error:k instanceof Error?k.message:"Failed to start text edit"})}};return e.addEventListener("message",le),e.addEventListener(re,ae),()=>{y(),m(),s=null,_(),e.removeEventListener("message",le),e.removeEventListener(re,ae)}}function Ie(e){let t=e.kind;return t==="bridge-get-document"||t==="bridge-ensure-document-version"||t==="bridge-get-object-summary"||t==="bridge-get-object-edit-context"||t==="bridge-get-class-name-source"||t==="bridge-execute"||t==="bridge-undo"||t==="bridge-redo"||t==="bridge-subscribe"||t==="bridge-unsubscribe"}async function ct({message:e,sendEvent:t,sendResponse:n,subscriptions:r,getCurrentDocument:o,windowLike:s}){let i=s.__VCP_SITE_EDIT__;if(!i){n({type:"response",ok:!1,error:"Site edit bridge is not ready in preview frame"});return}try{switch(e.kind){case"bridge-get-document":n({type:"response",ok:!0,result:await i.getDocument(e.payload.routeId)});return;case"bridge-ensure-document-version":if(!Number.isFinite(Number(e.payload.minVersion))){n({type:"response",ok:!1,error:"Invalid document version"});return}n({type:"response",ok:!0,result:i.ensureDocumentVersion?await i.ensureDocumentVersion(e.payload.routeId,Number(e.payload.minVersion)):await i.getDocument(e.payload.routeId)});return;case"bridge-get-object-summary":n({type:"response",ok:!0,result:await i.getObjectSummary(e.payload.key,e.payload.routeId)});return;case"bridge-get-object-edit-context":n({type:"response",ok:!0,result:await i.getObjectEditContext(e.payload.key,e.payload.routeId)});return;case"bridge-get-class-name-source":{let u=await i.getClassNameSource(e.payload.key,e.payload.routeId);n({type:"response",ok:!0,result:at(u,e.payload.key,s.document,o?.()??null)});return}case"bridge-execute":n({type:"response",ok:!0,result:await i.execute(e.payload.request)});return;case"bridge-undo":n({type:"response",ok:!0,result:await i.undo()});return;case"bridge-redo":n({type:"response",ok:!0,result:await i.redo()});return;case"bridge-subscribe":{let u=e.payload.subscriptionId;r.get(u)?.();let d=i.subscribe(y=>{t({kind:"bridge-event",payload:{event:y,subscriptionId:u}})});r.set(u,d),n({type:"response",ok:!0,result:{subscribed:!0}});return}case"bridge-unsubscribe":{let u=e.payload.subscriptionId;r.get(u)?.(),r.delete(u),n({type:"response",ok:!0,result:{unsubscribed:!0}});return}}}catch(u){n({type:"response",ok:!1,error:u instanceof Error?u.message:"Site edit bridge request failed"})}}function at(e,t,n,r){if(!e.ok||!e.data.styleContext)return e;let o=V(n,{key:t},r),s=o?lt(o):null;return s?{...e,data:{...e.data,styleContext:{...e.data.styleContext,computedStyle:{...e.data.styleContext.computedStyle??{},...s}}}}:e}function lt(e){let t=e.ownerDocument.defaultView;if(!t)return null;let n=t.getComputedStyle(e);return{color:n.color,backgroundColor:n.backgroundColor,borderColor:n.borderColor}}function dt(e,t){let n=e.history.pushState,r=e.history.replaceState,o=()=>t();return e.history.pushState=function(...i){let u=n.apply(this,i);return t(),u},e.history.replaceState=function(...i){let u=r.apply(this,i);return t(),u},e.addEventListener("popstate",o),()=>{e.history.pushState=n,e.history.replaceState=r,e.removeEventListener("popstate",o)}}function pt(e){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(()=>requestAnimationFrame(e));return}setTimeout(e,0)}function Ce(e,t){return typeof e.requestAnimationFrame=="function"?e.requestAnimationFrame(t):e.setTimeout(t,0)}function Ne(e,t){if(typeof e.cancelAnimationFrame=="function"){e.cancelAnimationFrame(t);return}e.clearTimeout(t)}function ft(e,t){e.dispatchEvent(new CustomEvent(re,{detail:t}))}function mt(e){let t=e.trim();return!t||t==="/"?"":(t.startsWith("/")?t:`/${t}`).replace(/\/+$/,"")}function ie(e){return tt.has(De(e))}function ht(e){return nt.has(De(e))}function ke(e){return e.operationSummary?{canUpdateText:e.operationSummary.canUpdateText,canInsertChild:e.operationSummary.canInsertChild,canMove:e.operationSummary.canMove,canRemove:e.operationSummary.canRemove}:e.fallbackMode!=="preview"?{canUpdateText:!1,canInsertChild:!1,canMove:!1,canRemove:!1}:{canUpdateText:ht(e.tagName),canInsertChild:ie(e.tagName),canMove:!1,canRemove:!1}}function De(e){return e?.trim().toLowerCase()??""}function yt(e,t,n,r,o){let s=Q(e,t,n),i=Oe(s);if(!i)return null;let u=i.getAttribute("data-vcp-edit-key")??"",d=A(e,i,r),y=o?.(d.key)??o?.(u);if(!ke({operationSummary:y?.operationSummary,tagName:i.tagName,fallbackMode:"preview"}).canUpdateText)return null;if((y?.childKeys.length??0)===0)return{element:i};let v=gt(e,t,n,i);if(!v)return null;let _=Et(i,v);return _===null?null:{element:i,textNode:v,textSegmentIndex:_}}function gt(e,t,n,r){let o=bt(e,t,n);return!o||o.parentElement!==r?null:o}function bt(e,t,n){let r=e,s=r.caretPositionFromPoint?.(t,n)?.offsetNode??null;if(oe(s))return s;let u=r.caretRangeFromPoint?.(t,n)?.startContainer??null;return oe(u)?u:null}function Et(e,t){let n=0;for(let r of Array.from(e.childNodes))if(!(!oe(r)||(r.textContent??"").trim().length===0)){if(r===t)return n;n+=1}return null}function oe(e){return e?.nodeType===3}function Q(e,t,n){let r=typeof e.elementsFromPoint=="function"?e.elementsFromPoint(t,n):[e.elementFromPoint(t,n)].filter(Boolean);for(let o of r){let s=Oe(o);if(s)return s}return null}function Oe(e){let t=e,n=null;for(;t;){let r=t.getAttribute("data-vcp-edit-key")??"";if(r){if(ue(t))return n??t;!It(r)&&!n&&(n=t)}t=t.parentElement}return n}function ue(e){return e.getAttribute(et)!==null}function It(e){return vt(e.split("::")[0]??"")}function vt(e){if(!e)return!1;let t=St(e);return t===w||t.startsWith(`${w}/`)||t.includes(`/${w}/`)||t.endsWith(`/${w}`)}function St(e){let n=(e.split("?")[0]??e).replace(/\\/g,"/").replace(/^\.\//,""),r=[];for(let o of n.split("/"))if(!(!o||o===".")){if(o===".."){r.pop();continue}r.push(o)}return r.join("/")}function A(e,t,n){let r=t.getAttribute("data-vcp-edit-key")??"",o=Pe(Array.from(e.querySelectorAll(`[data-vcp-edit-key="${Ke(r)}"]`)));if(o.length<=1)return{key:Se(n,r,0)};let s=o.indexOf(t);return s>=0?{key:Se(n,r,s),instanceIndex:s,instanceCount:o.length}:{key:r}}function ve(e,t,n){return A(e,t,n)}function V(e,t,n){let r=ce(t.key)??t.key,o=Pe(Array.from(e.querySelectorAll(`[data-vcp-edit-key="${Ke(r)}"]`)));if(o.length===0)return null;let s=_t(n,t.key);return s!==null&&s>=0&&s<o.length?o[s]??null:typeof t.instanceIndex=="number"&&t.instanceIndex>=0&&t.instanceIndex<o.length?o[t.instanceIndex]??null:o[0]??null}function Se(e,t,n){return Ae(e,t)[n]?.key??t}function _t(e,t){let n=ce(t);if(!n)return null;let o=Ae(e,n).findIndex(s=>s.key===t);return o>=0?o:null}function Ae(e,t){return(e?.entries??[]).filter(n=>(ce(n.key)??n.key)===t)}var Rt=2,Tt=4;function Pe(e){return[...e].sort((t,n)=>{if(t===n)return 0;let r=typeof t.compareDocumentPosition=="function"?t.compareDocumentPosition(n):0;return(r&Tt)!==0?-1:(r&Rt)!==0?1:0})}function ce(e){if(typeof e!="string"||e.length===0)return e??null;let t=e;for(;;){let n=t.lastIndexOf(Ee);if(n<0)break;let r=Number(t.slice(n+Ee.length));if(!Number.isInteger(r)||r<0)return e;t=t.slice(0,n)}return t}function xt(e){let n=e.ownerDocument?.defaultView?.getComputedStyle(e),r=o=>{let s=Number.parseFloat(o??"");return Number.isFinite(s)&&s>0?s:0};return{marginTop:r(n?.marginTop),marginRight:r(n?.marginRight),marginBottom:r(n?.marginBottom),marginLeft:r(n?.marginLeft),paddingTop:r(n?.paddingTop),paddingRight:r(n?.paddingRight),paddingBottom:r(n?.paddingBottom),paddingLeft:r(n?.paddingLeft),borderTopWidth:r(n?.borderTopWidth),borderRightWidth:r(n?.borderRightWidth),borderBottomWidth:r(n?.borderBottomWidth),borderLeftWidth:r(n?.borderLeftWidth),columnGap:r(n?.columnGap),rowGap:r(n?.rowGap)}}function Ct(e){return Array.from(e.children).filter(t=>typeof t.getBoundingClientRect=="function").map(t=>se(t.getBoundingClientRect())).filter(t=>t.width>0&&t.height>0)}function D(e,t,n,r="full"){let o=e.getBoundingClientRect(),s=n?.(t.key)??null,i=e.tagName.toLowerCase(),u=Z(e),d=r==="full"?{textPreview:e.textContent?.trim().slice(0,80),dataset:Object.fromEntries(Object.entries(e.dataset).map(([a,R])=>[a,R??""])),attributes:Object.fromEntries(e.getAttributeNames().map(a=>[a,e.getAttribute(a)??""]))}:{},y=ke({operationSummary:s?.operationSummary,tagName:i,fallbackMode:"preview"}),m=ue(e),v=!!(s&&/^[A-Z]/.test(s.tag)),_=!s||!v;return{ref:t,key:t.key,detailLevel:r,tagName:i,...s?{sourceKind:v?"component-call":"jsx"}:{},...v&&s?.tag?{componentName:s.tag}:{},...s?.parentKey?{parentKey:s.parentKey}:{},...d,runtimeFlags:{selectable:!0,movable:y.canMove,removable:y.canRemove,textEditable:y.canUpdateText,container:m?!1:(s?.childKeys.length??0)>0||y.canInsertChild||_&&ie(i)},layout:u,rect:{top:o.top,left:o.left,width:o.width,height:o.height},childRects:Ct(e),spacing:xt(e)}}function Nt(e,t,n,r,o){let s=se(t.getBoundingClientRect()),i=null,u=()=>{i===null&&(i=Ce(e,d))},d=()=>{if(i=null,"isConnected"in t&&!t.isConnected)return;let a=se(t.getBoundingClientRect());kt(s,a)&&(s=a,o(D(t,n,r,"summary")))},y=e.ResizeObserver,m=typeof y=="function"?new y(u):null;m?.observe(t);let v=e.MutationObserver,_=typeof v=="function"?new v(u):null;return _?.observe(e.document.documentElement,{attributes:!0,childList:!0,characterData:!0,subtree:!0}),e.document.addEventListener("load",u,!0),()=>{i!==null&&(Ne(e,i),i=null),m?.disconnect(),_?.disconnect(),e.document.removeEventListener("load",u,!0)}}function se(e){return{top:e.top,left:e.left,width:e.width,height:e.height}}function kt(e,t){return Math.abs(e.top-t.top)>.5||Math.abs(e.left-t.left)>.5||Math.abs(e.width-t.width)>.5||Math.abs(e.height-t.height)>.5}function Dt(e,t,n,r,o,s,i){let u=e.document,d=Q(u,t,n);if(!d)return{anchorHit:null,targetParentHit:null,relation:"none",rejectionReason:"no-editable-hit"};let y=o?V(u,o,s):null;if(y&&Te(d,y))return z(u,d,"self-or-descendant",s,i);let m=null,v=!1,_=d,a=d.parentElement;for(;a;){if(a.getAttribute("data-vcp-edit-key")){if(y&&Te(a,y))return z(u,d,"self-or-descendant",s,i);let E=_e(a,r,i);if(E==="accept"){m={child:_,targetParent:a};break}E==="blocked"&&(v=!0),_=a}a=a.parentElement}let R=_e(d,r,i);if(R==="accept"){if(m){let E=Re(m.child,m.targetParent,t,n,"edge");if(E)return te(u,m.child,m.targetParent,E,s,i)}return te(u,d,d,Ot(d,t,n),s,i)}if(m){let E=Re(m.child,m.targetParent,t,n,"nearest");return te(u,m.child,m.targetParent,E??"after",s,i)}return R==="blocked"||v?z(u,d,"operation-boundary-blocked",s,i):z(u,d,"no-accepting-parent",s,i)}function z(e,t,n,r,o){return{anchorHit:D(t,A(e,t,r),o,"summary"),targetParentHit:null,relation:"none",rejectionReason:n}}function te(e,t,n,r,o,s){let i=D(t,A(e,t,o),s,"summary"),u=D(n,A(e,n,o),s,"summary"),d=Z(n).indicatorOrientation,y=r==="append"||r==="prepend"?At(n.getBoundingClientRect(),d,r):Pt(t.getBoundingClientRect(),d,r);return{anchorHit:i,targetParentHit:u,relation:r,indicatorOrientation:d,indicatorBounds:y}}function _e(e,t,n){if(ue(e))return"not-container";let r=e.getAttribute("data-vcp-edit-key")??"",o=n?.(r)??null;if(o)return o.operationSummary.canInsertChild===!0?"accept":o.childKeys.length>0?"blocked":"not-container";let s=e.tagName.toLowerCase();return ie(s)?"accept":"not-container"}function Re(e,t,n,r,o){let s=Z(t).indicatorOrientation,i=e.getBoundingClientRect(),u=s==="vertical"?i.width>0?(n-i.left)/i.width:.5:i.height>0?(r-i.top)/i.height:.5;return o==="edge"&&u>=.25&&u<=.75?null:u<.5?"before":"after"}function Ot(e,t,n){let r=Z(e).indicatorOrientation,o=e.getBoundingClientRect();return(r==="vertical"?o.width>0?(t-o.left)/o.width:.5:o.height>0?(n-o.top)/o.height:.5)<.5?"prepend":"append"}function Z(e){let n=e.ownerDocument?.defaultView?.getComputedStyle(e),r=n?.display??"",o=n?.flexDirection,s=n?.gridAutoFlow,i="horizontal";return r==="flex"||r==="inline-flex"?i=(o??"row").startsWith("row")?"vertical":"horizontal":(r==="grid"||r==="inline-grid")&&(i=(s??"row").includes("column")?"vertical":"horizontal"),{display:r,...o?{flexDirection:o}:{},...s?{gridAutoFlow:s}:{},indicatorOrientation:i}}function At(e,t,n){if(t==="vertical")return{left:n==="prepend"?e.left:e.left+e.width-3,top:e.top,width:3,height:e.height};let r=n==="prepend"?e.top:e.top+e.height-3;return{left:e.left,top:r,width:e.width,height:3}}function Pt(e,t,n){if(t==="vertical")return{left:n==="before"?e.left:e.left+e.width-3,top:e.top,width:3,height:e.height};let r=n==="before"?e.top:e.top+e.height-3;return{left:e.left,top:r,width:e.width,height:3}}function Te(e,t){let n=e;for(;n;){if(n===t)return!0;n=n.parentElement}return!1}function J(e){let t=e.document.documentElement,n=e.document.body;return{scrollX:O(e.scrollX),scrollY:O(e.scrollY),scrollWidth:Math.max(O(t?.scrollWidth),O(n?.scrollWidth),O(e.innerWidth)),scrollHeight:Math.max(O(t?.scrollHeight),O(n?.scrollHeight),O(e.innerHeight)),viewportWidth:O(e.innerWidth),viewportHeight:O(e.innerHeight)}}function Ft(e,t){Object.entries(t.attributes??{}).forEach(([n,r])=>{if(r===null){e.removeAttribute(n);return}e.setAttribute(n,r)}),typeof t.className=="string"&&(e.className=t.className),Object.entries(t.style??{}).forEach(([n,r])=>{let o=e.style,s=n.replace(/[A-Z]/g,i=>`-${i.toLowerCase()}`);if(r==null||r===""){o.removeProperty(s);return}o.setProperty(s,String(r))})}var Mt=500,Y=new Map;function qt(e,t){return`${e}:${t.key}:${t.instanceIndex??""}`}function Kt(e,t){if(Y.size>=Mt){let n=Y.keys().next().value;n&&Y.delete(n)}Y.set(e,t)}var G=new Set;function Bt(e,t){let n=e.documentElement?.style,r=new Set;for(let[o,s]of Object.entries(t.variables??{}))o.startsWith("--")&&(r.add(o),n?.setProperty(o,s));for(let o of G)r.has(o)||n?.removeProperty(o);G.clear();for(let o of r)G.add(o);$t(e,t.stylesheets??[])}function Vt(e){let t=e.documentElement?.style;for(let n of G)t?.removeProperty(n);G.clear();for(let n of qe(e))n.remove()}function Wt(e,t){let n=Array.from(new Set(t.filter(i=>typeof i=="string"&&i.startsWith("--"))));if(n.length===0)return{};let r=e.documentElement,o=r?e.defaultView?.getComputedStyle(r):null,s={};for(let i of n){let u=Fe(o,i);u&&(s[i]=u)}return s}function Fe(e,t,n=new Set){if(!e||n.has(t))return null;n.add(t);let r=e.getPropertyValue(t).trim();return Me(e,r,n)}function Me(e,t,n){if(!t)return null;let r=jt(t);if(!r)return t;let o=Fe(e,r.name,n);return o||(r.fallback?Me(e,r.fallback,n)??r.fallback:null)}function jt(e){let t=e.trim();if(!t.startsWith("var(")||!t.endsWith(")"))return null;let n=t.slice(4,-1).trim(),r=Ut(n),o=r>=0?n.slice(0,r).trim():n;if(!o.startsWith("--"))return null;let s=r>=0?n.slice(r+1).trim():null;return{name:o,fallback:s||null}}function Ut(e){let t=0;for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="("){t+=1;continue}if(r===")"){t=Math.max(0,t-1);continue}if(r===","&&t===0)return n}return-1}function $t(e,t){let n=new Set(t.filter(s=>typeof s=="string"&&s.length>0)),r=new Map;for(let s of qe(e)){let i=s.getAttribute("href")??"";if(!n.has(i)||r.has(i)){s.remove();continue}r.set(i,s)}let o=e.head;if(o)for(let s of n){if(r.has(s))continue;let i=e.createElement("link");i.setAttribute("rel","stylesheet"),i.setAttribute(xe,"true"),i.setAttribute("href",s),o.appendChild(i)}}function qe(e){return Array.from(e.querySelectorAll(`link[${xe}]`))}function Yt(e,t,n,r,o={}){let s=o.textNode?Gt(e.document,o.textNode):null;if(o.textNode&&!s)throw new Error("Failed to prepare text segment editor");let i=s?.element??t,u=i.textContent??"",d=Xt(i),y=!1,m=()=>{e.document.removeEventListener("pointerdown",_,!0),i.removeEventListener("keydown",a),i.removeEventListener("blur",R),i.removeEventListener("input",E),wt(i,d)},v=b=>{if(y)return;y=!0;let N=i.textContent??"";if(m(),b==="cancel"){s?.restore(u),s||(t.textContent=u),r({kind:"text-edit-cancel",payload:{ref:n}});return}if(s?.restore(N),b==="commit"&&N!==u){r({kind:"text-edit-commit",payload:{ref:n,value:N}});return}r({kind:"text-edit-exit",payload:{ref:n}})};function _(b){let N=b.target;N&&i.contains(N)||v("commit")}function a(b){if(b.key==="Escape"){b.preventDefault(),v("cancel");return}b.key==="Enter"&&(b.metaKey||b.ctrlKey)&&(b.preventDefault(),v("commit"))}function R(){v("commit")}function E(){r({kind:"text-edit-input",payload:{ref:n,hit:D(t,n,void 0,"full")}})}return Ht(i),e.document.addEventListener("pointerdown",_,!0),i.addEventListener("keydown",a),i.addEventListener("blur",R),i.addEventListener("input",E),Qt(i),Zt(i,e.document),m}function Gt(e,t){let n=t.parentNode;if(!n)return null;let r=e.createElement("span");return r.setAttribute("data-vcp-text-segment-editor","true"),r.textContent=t.textContent??"",n.replaceChild(r,t),{element:r,restore(o){t.nodeValue=o,r.parentNode&&r.parentNode.replaceChild(t,r)}}}function Xt(e){return{contentEditable:e.getAttribute("contenteditable"),spellcheck:e.getAttribute("spellcheck"),marker:e.getAttribute("data-vcp-edit-text-editing"),cursor:e.style.cursor,userSelect:e.style.userSelect}}function Ht(e){zt(e.ownerDocument),e.setAttribute("contenteditable","plaintext-only"),e.setAttribute("spellcheck","false"),e.setAttribute("data-vcp-edit-text-editing","true"),e.style.cursor="text",e.style.userSelect="text"}function wt(e,t){ne(e,"contenteditable",t.contentEditable),ne(e,"spellcheck",t.spellcheck),ne(e,"data-vcp-edit-text-editing",t.marker),e.style.cursor=t.cursor,e.style.userSelect=t.userSelect}function zt(e){if(e.getElementById("vcp-text-edit-base-style"))return;let t=e.createElement("style");t.id="vcp-text-edit-base-style",t.textContent='[data-vcp-edit-text-editing="true"]{outline:0!important;outline-offset:0!important;}',e.head.appendChild(t)}function ne(e,t,n){if(n===null){e.removeAttribute(t);return}e.setAttribute(t,n)}function Jt(e){let t=[e.documentElement,e.body].filter(r=>!!r?.style),n=t.map(r=>({element:r,userSelect:r.style.userSelect}));for(let r of t)r.style.userSelect="none";return()=>{for(let r of n)r.element.style.userSelect=r.userSelect}}function Qt(e){try{e.focus({preventScroll:!0})}catch{e.focus()}}function Zt(e,t){let n=t.createRange();n.selectNodeContents(e);let r=t.getSelection?.();r?.removeAllRanges(),r?.addRange(n)}function Ke(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function O(e){let t=Number(e);return Number.isFinite(t)?t:0}export{re as VCP_SITE_EDIT_ROUTE_READY_EVENT,rt as resolveSiteEditRouteId,st as resolveSiteEditWebSocketUrl,pn as startSiteEditAutoBootstrap,ut as startSiteEditFrameRuntime};
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { SiteEditCommandSuccess, SiteEditEvent, SiteEditGetClassNameSourceCommandResult, SiteEditObjectDetail, SiteEditObjectEditContext, SiteEditObjectSummary, SiteEditOperationCommandResult, SiteEditOperationRequest, SiteEditRenderDocument } from "@vcp-dev/contracts";
|
|
2
|
+
export type SiteEditBrowserSocketLike = {
|
|
3
|
+
readonly readyState: number;
|
|
4
|
+
onopen: (() => void) | null;
|
|
5
|
+
onmessage: ((event: {
|
|
6
|
+
data: string;
|
|
7
|
+
}) => void) | null;
|
|
8
|
+
onclose: (() => void) | null;
|
|
9
|
+
onerror: ((error: Event | Error) => void) | null;
|
|
10
|
+
send(data: string): void;
|
|
11
|
+
close(): void;
|
|
12
|
+
};
|
|
13
|
+
export type SiteEditBridgeClient = {
|
|
14
|
+
getDocument(routeId: string): Promise<SiteEditCommandSuccess<SiteEditRenderDocument>>;
|
|
15
|
+
ensureDocumentVersion?(routeId: string, minVersion: number): Promise<SiteEditCommandSuccess<SiteEditRenderDocument>>;
|
|
16
|
+
getObjectSummary(key: string, routeId?: string): Promise<SiteEditCommandSuccess<SiteEditObjectSummary>>;
|
|
17
|
+
getObjectEditContext(key: string, routeId?: string): Promise<SiteEditCommandSuccess<SiteEditObjectEditContext>>;
|
|
18
|
+
getClassNameSource(key: string, routeId?: string): Promise<SiteEditGetClassNameSourceCommandResult>;
|
|
19
|
+
execute(request: SiteEditOperationRequest): Promise<SiteEditOperationCommandResult>;
|
|
20
|
+
undo(): Promise<SiteEditOperationCommandResult>;
|
|
21
|
+
redo(): Promise<SiteEditOperationCommandResult>;
|
|
22
|
+
subscribe(listener: (event: SiteEditEvent) => void): () => void;
|
|
23
|
+
};
|
|
24
|
+
export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
25
|
+
private readonly options;
|
|
26
|
+
private socket;
|
|
27
|
+
private sequence;
|
|
28
|
+
private readonly pending;
|
|
29
|
+
private readonly listeners;
|
|
30
|
+
constructor(options: {
|
|
31
|
+
url: string;
|
|
32
|
+
createSocket?: (url: string) => SiteEditBrowserSocketLike;
|
|
33
|
+
});
|
|
34
|
+
connect(): Promise<void>;
|
|
35
|
+
disconnect(): void;
|
|
36
|
+
getDocument(routeId: string): Promise<SiteEditCommandSuccess<{
|
|
37
|
+
siteId: string;
|
|
38
|
+
snapshotId: string;
|
|
39
|
+
routeId: string;
|
|
40
|
+
version: number;
|
|
41
|
+
rootKeys: string[];
|
|
42
|
+
entries: {
|
|
43
|
+
key: string;
|
|
44
|
+
tag: string;
|
|
45
|
+
label: string;
|
|
46
|
+
parentKey: string | null;
|
|
47
|
+
childKeys: string[];
|
|
48
|
+
operationSummary: {
|
|
49
|
+
canUpdateText: boolean;
|
|
50
|
+
canInsertChild: boolean;
|
|
51
|
+
canMove: boolean;
|
|
52
|
+
canRemove: boolean;
|
|
53
|
+
};
|
|
54
|
+
}[];
|
|
55
|
+
}>>;
|
|
56
|
+
getObjectSummary(key: string, routeId?: string): Promise<SiteEditCommandSuccess<{
|
|
57
|
+
key: string;
|
|
58
|
+
tag: string;
|
|
59
|
+
label: string;
|
|
60
|
+
capabilities: {
|
|
61
|
+
constraints: {
|
|
62
|
+
kind: "component-boundary" | "repeat-region" | "conditional-region" | "opaque-region" | "void-element" | "read-only" | "cross-file-required" | "import-required";
|
|
63
|
+
message: string;
|
|
64
|
+
}[];
|
|
65
|
+
};
|
|
66
|
+
isOpaque: boolean;
|
|
67
|
+
ancestors: {
|
|
68
|
+
key: string;
|
|
69
|
+
label: string;
|
|
70
|
+
tag: string;
|
|
71
|
+
}[];
|
|
72
|
+
sourceLocator?: {
|
|
73
|
+
sourceFile: string;
|
|
74
|
+
componentName: string;
|
|
75
|
+
openingElementRange: {
|
|
76
|
+
startLine: number;
|
|
77
|
+
startColumn: number;
|
|
78
|
+
endLine: number;
|
|
79
|
+
endColumn: number;
|
|
80
|
+
};
|
|
81
|
+
structuralPath: string;
|
|
82
|
+
textPreview?: string | undefined;
|
|
83
|
+
} | undefined;
|
|
84
|
+
provenanceChain?: {
|
|
85
|
+
editMode: "readonly" | "direct" | "proxy" | "upstream" | "unsupported";
|
|
86
|
+
diagnostics: {
|
|
87
|
+
code: string;
|
|
88
|
+
message: string;
|
|
89
|
+
}[];
|
|
90
|
+
} | undefined;
|
|
91
|
+
}>>;
|
|
92
|
+
getObjectEditContext(key: string, routeId?: string): Promise<SiteEditCommandSuccess<{
|
|
93
|
+
key: string;
|
|
94
|
+
componentName: string;
|
|
95
|
+
sourceFile: string;
|
|
96
|
+
capabilities: {
|
|
97
|
+
key: string;
|
|
98
|
+
canUpdateText: boolean;
|
|
99
|
+
canInsertChild: boolean;
|
|
100
|
+
canMove: boolean;
|
|
101
|
+
canRemove: boolean;
|
|
102
|
+
constraints: {
|
|
103
|
+
kind: "component-boundary" | "repeat-region" | "conditional-region" | "opaque-region" | "void-element" | "read-only" | "cross-file-required" | "import-required";
|
|
104
|
+
message: string;
|
|
105
|
+
}[];
|
|
106
|
+
editModes?: {
|
|
107
|
+
updateText?: {
|
|
108
|
+
mode: "readonly" | "direct" | "proxy" | "upstream" | "unsupported";
|
|
109
|
+
reasonCode?: string | undefined;
|
|
110
|
+
} | undefined;
|
|
111
|
+
insertChild?: {
|
|
112
|
+
mode: "readonly" | "direct" | "proxy" | "upstream" | "unsupported";
|
|
113
|
+
reasonCode?: string | undefined;
|
|
114
|
+
} | undefined;
|
|
115
|
+
move?: {
|
|
116
|
+
mode: "readonly" | "direct" | "proxy" | "upstream" | "unsupported";
|
|
117
|
+
reasonCode?: string | undefined;
|
|
118
|
+
} | undefined;
|
|
119
|
+
remove?: {
|
|
120
|
+
mode: "readonly" | "direct" | "proxy" | "upstream" | "unsupported";
|
|
121
|
+
reasonCode?: string | undefined;
|
|
122
|
+
} | undefined;
|
|
123
|
+
} | undefined;
|
|
124
|
+
};
|
|
125
|
+
writeTarget: {
|
|
126
|
+
kind: "jsx-node" | "route-export" | "component-proxy" | "value-binding";
|
|
127
|
+
file: string;
|
|
128
|
+
componentName: string;
|
|
129
|
+
isProxy: boolean;
|
|
130
|
+
};
|
|
131
|
+
textSegments: {
|
|
132
|
+
index: number;
|
|
133
|
+
value: string;
|
|
134
|
+
editable: boolean;
|
|
135
|
+
source: {
|
|
136
|
+
kind: "binding" | "imported-binding" | "repeat-template" | "literal";
|
|
137
|
+
file: string;
|
|
138
|
+
expression: string;
|
|
139
|
+
bindingName?: string | undefined;
|
|
140
|
+
path?: (string | number)[] | undefined;
|
|
141
|
+
} | null;
|
|
142
|
+
}[];
|
|
143
|
+
boundaryKind: "component-boundary" | "repeat-region" | "conditional-region" | "fragment-region" | "opaque-region" | null;
|
|
144
|
+
children: {
|
|
145
|
+
key: string;
|
|
146
|
+
label: string;
|
|
147
|
+
tag: string;
|
|
148
|
+
}[];
|
|
149
|
+
siblings: {
|
|
150
|
+
key: string;
|
|
151
|
+
label: string;
|
|
152
|
+
tag: string;
|
|
153
|
+
}[];
|
|
154
|
+
effectiveWriteTarget?: {
|
|
155
|
+
kind: "jsx-node" | "route-export" | "value-path" | "external-entry";
|
|
156
|
+
isProxy: boolean;
|
|
157
|
+
file?: string | undefined;
|
|
158
|
+
displayPath?: string | undefined;
|
|
159
|
+
sourceType?: "api-field" | "cms-field" | "i18n-message" | "config-entry" | undefined;
|
|
160
|
+
sourceId?: string | undefined;
|
|
161
|
+
} | undefined;
|
|
162
|
+
provenanceChain?: {
|
|
163
|
+
finalSource: {
|
|
164
|
+
kind: "api-field" | "cms-field" | "i18n-message" | "config-entry" | "binding" | "imported-binding" | "repeat-template" | "jsx-literal" | "component-prop" | "object-field" | "array-item" | "conditional-branch";
|
|
165
|
+
file: string;
|
|
166
|
+
displayPath: string;
|
|
167
|
+
externalSource?: {
|
|
168
|
+
sourceType: "api-field" | "cms-field" | "i18n-message" | "config-entry";
|
|
169
|
+
sourceId: string;
|
|
170
|
+
adapterId?: string | undefined;
|
|
171
|
+
} | undefined;
|
|
172
|
+
} | null;
|
|
173
|
+
chain: {
|
|
174
|
+
kind: "api-field" | "cms-field" | "i18n-message" | "config-entry" | "binding" | "imported-binding" | "repeat-template" | "jsx-literal" | "component-prop" | "object-field" | "array-item" | "conditional-branch";
|
|
175
|
+
file: string;
|
|
176
|
+
displayName: string;
|
|
177
|
+
canEditHere: boolean;
|
|
178
|
+
}[];
|
|
179
|
+
confidence: "unknown" | "exact" | "safe-derived" | "partial";
|
|
180
|
+
editMode: "readonly" | "direct" | "proxy" | "upstream" | "unsupported";
|
|
181
|
+
diagnostics: {
|
|
182
|
+
code: string;
|
|
183
|
+
message: string;
|
|
184
|
+
}[];
|
|
185
|
+
} | undefined;
|
|
186
|
+
componentSemantic?: Record<string, unknown> | undefined;
|
|
187
|
+
}>>;
|
|
188
|
+
getClassNameSource(key: string, routeId?: string): Promise<SiteEditGetClassNameSourceCommandResult>;
|
|
189
|
+
execute(request: SiteEditOperationRequest): Promise<SiteEditOperationCommandResult>;
|
|
190
|
+
undo(): Promise<SiteEditOperationCommandResult>;
|
|
191
|
+
redo(): Promise<SiteEditOperationCommandResult>;
|
|
192
|
+
subscribe(listener: (event: SiteEditEvent) => void): () => void;
|
|
193
|
+
private request;
|
|
194
|
+
private handleMessage;
|
|
195
|
+
private rejectAll;
|
|
196
|
+
private createSocket;
|
|
197
|
+
}
|
|
198
|
+
export type SiteEditBridge = SiteEditBridgeClient;
|
|
199
|
+
export declare function createSiteEditBridge(params: {
|
|
200
|
+
routeId: string;
|
|
201
|
+
initialDocument: SiteEditRenderDocument;
|
|
202
|
+
initialDetails?: Record<string, SiteEditObjectDetail>;
|
|
203
|
+
client: SiteEditBridgeClient;
|
|
204
|
+
}): SiteEditBridge;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function f(r){if(!b(r))return r;let e=new Map,t=n=>{let s=e.get(n);if(s)return s;let o=r.nodes[n];if(!o)throw new Error(`Missing compact document node ${n}`);let c=r.tokens[o.token];if(typeof c!="string")throw new Error(`Missing compact document token ${o.token}`);let d=`${o.parent===null?"":t(o.parent)}${c}`;return e.set(n,d),d};return{siteId:r.siteId,snapshotId:r.snapshotId,routeId:r.routeId,version:r.version,rootKeys:r.rootKeyNodeIds.map(t),entries:r.entries.map(n=>({key:t(n.keyNodeId),tag:n.tag,label:n.label,parentKey:n.parentKeyNodeId===null?null:t(n.parentKeyNodeId),childKeys:n.childKeyNodeIds.map(t),operationSummary:n.operationSummary}))}}function b(r){return typeof r=="object"&&r!==null&&"encoding"in r&&r.encoding==="segment-trie-v1"}var a=class r{constructor(){}static parseMessage(e,t={}){let n=JSON.parse(e);if(!r.isMessage(n,t))throw new Error("Invalid site edit bridge message");return n}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(typeof e=="object"&&e!==null&&"payload"in e&&typeof e.payload=="object"&&e.payload!==null){let t=e.payload,n=typeof t.id=="string"?t.id:"unknown",s=r.isRequestKind(t.kind)?t.kind:"get-document";return{id:n,kind:s}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="get-document"||e==="get-object-summary"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="execute"||e==="undo"||e==="redo"}static isMessage(e,t={}){return!i(e)||typeof e.type!="string"?!1:e.type==="request"?r.isRequestPayload(e.payload,t):e.type==="response"||e.type==="error"?i(e.payload)&&typeof e.payload.id=="string":e.type==="event"?i(e.payload)&&i(e.payload.event):!1}static isRequestPayload(e,t={}){if(!i(e)||typeof e.id!="string"||!r.isRequestKind(e.kind))return!1;switch(e.kind){case"get-document":return typeof e.routeId=="string";case"get-object-summary":case"get-object-edit-context":case"get-class-name-source":return typeof e.key=="string"&&(e.routeId===void 0||typeof e.routeId=="string");case"execute":return I(e.request)&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return!0}}};function i(r){return typeof r=="object"&&r!==null}function I(r){return i(r)&&typeof r.id=="string"&&typeof r.siteId=="string"&&typeof r.baseSnapshotId=="string"&&(r.routeId===void 0||typeof r.routeId=="string")&&typeof r.kind=="string"&&i(r.target)&&typeof r.documentVersion=="number"&&Number.isInteger(r.documentVersion)&&r.documentVersion>=0&&i(r.params)}var k="vcp:designer:trace",w="designer_trace",g="__VCP_DESIGNER_TRACE__";var q=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function x(r=globalThis){let e=r;try{if(e.localStorage?.getItem(k)==="1")return!0}catch{}try{let t=e.location?.search??"";return new URLSearchParams(t).get(w)==="1"}catch{return!1}}function u(r,e={},t=globalThis){if(!x(t))return;let n={type:r,timestamp:Date.now(),payload:E(e)},s=t,o=s[g]??[];o.push(n),o.length>200&&o.splice(0,o.length-200),s[g]=o;let c=t.console?.debug;typeof c=="function"&&c.call(t.console,"[designer-trace]",n)}function E(r){return h(r,0)}function h(r,e){if(e>4)return"[truncated]";if(Array.isArray(r))return r.map(n=>h(n,e+1));if(!r||typeof r!="object")return r;let t={};for(let[n,s]of Object.entries(r)){if(q.test(n)){t[n]="[redacted]";continue}t[n]=h(s,e+1)}return t}var l=class{constructor(e){this.options=e,this.socket=null,this.sequence=0,this.pending=new Map,this.listeners=new Set}connect(){return this.socket?Promise.resolve():new Promise((e,t)=>{let n=this.createSocket(this.options.url);this.socket=n,n.onopen=()=>e(),n.onerror=s=>{t(s instanceof Error?s:new Error("WebSocket failed"))},n.onmessage=s=>this.handleMessage(s.data),n.onclose=()=>{this.rejectAll(new Error("WebSocket closed")),this.socket=null}})}disconnect(){this.socket?.close(),this.socket=null,this.rejectAll(new Error("WebSocket disconnected"))}getDocument(e){return this.request("get-document",{routeId:e})}getObjectSummary(e,t){return this.request("get-object-summary",{key:e,routeId:t})}getObjectEditContext(e,t){return this.request("get-object-edit-context",{key:e,routeId:t})}getClassNameSource(e,t){return this.request("get-class-name-source",{key:e,routeId:t})}execute(e){return this.request("execute",{request:e})}undo(){return this.request("undo",{})}redo(){return this.request("redo",{})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}request(e,t){let n=this.socket;if(!n)return Promise.reject(new Error("WebSocket is not connected"));let s=`${e}-${this.sequence+=1}`,o=C(s,e,t);return u("bridge.request",{id:s,kind:e,routeId:typeof t.routeId=="string"?t.routeId:null,key:typeof t.key=="string"?t.key:null,operationKind:m(t.request,"kind"),documentVersion:m(t.request,"documentVersion")}),new Promise((c,d)=>{this.pending.set(s,{kind:e,resolve:y=>c(y),reject:d}),n.send(a.stringifyMessage(o))})}handleMessage(e){let t=a.parseMessage(e);if(t.type==="event"){for(let s of this.listeners)s(t.payload.event);return}if(t.type!=="response"&&t.type!=="error")return;let n=this.pending.get(t.payload.id);if(n){if(this.pending.delete(t.payload.id),t.type==="error"){u("bridge.response",{id:t.payload.id,kind:n.kind,ok:!1}),n.reject(new Error(t.payload.message));return}u("bridge.response",{id:t.payload.id,kind:n.kind,ok:!0,resultVersion:S(t.payload.result)}),n.resolve(n.kind==="get-document"?{...t.payload.result,data:f(t.payload.result.data)}:t.payload.result)}}rejectAll(e){for(let t of this.pending.values())t.reject(e);this.pending.clear()}createSocket(e){if(this.options.createSocket)return this.options.createSocket(e);if(typeof WebSocket>"u")throw new Error("Site edit preview bridge requires WebSocket");return new WebSocket(e)}};function m(r,e){if(!r||typeof r!="object")return null;let n=r[e];return typeof n=="string"||typeof n=="number"?n:null}function S(r){if(!r||typeof r!="object")return null;let e=r,t=e.data?.resultVersion??e.data?.version??null;return typeof t=="number"?t:null}function A(r){return new p(r)}var p=class{constructor(e){this.params=e,this.refreshInFlight=null,this.currentDocument=e.initialDocument,this.summaryCache=new Map(Object.entries(e.initialDetails??{}).map(([t,n])=>[t,j(n)])),this.editContextCache=new Map(Object.entries(e.initialDetails??{}).map(([t,n])=>[t,D(n)]))}async getDocument(e){if(e!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${e}`);return R(this.currentDocument)&&(this.currentDocument=await this.refreshSnapshot(void 0,"get-document")),{ok:!0,data:this.currentDocument}}async ensureDocumentVersion(e,t){if(e!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${e}`);let n=await this.refreshSnapshot(t,"ensure-version");if(n.version<t)throw new Error(`Document refresh returned version ${n.version}, expected at least ${t}`);return{ok:!0,data:n}}async getObjectSummary(e,t){let n=this.summaryCache.get(e);if(n)return{ok:!0,data:n};let s=await this.params.client.getObjectSummary(e,t??this.params.routeId);return this.summaryCache.set(e,s.data),s}async getObjectEditContext(e,t){let n=this.editContextCache.get(e);if(n)return{ok:!0,data:n};let s=await this.params.client.getObjectEditContext(e,t??this.params.routeId);return this.editContextCache.set(e,s.data),s}async getClassNameSource(e,t){return this.params.client.getClassNameSource(e,t??this.params.routeId)}async execute(e){return this.params.client.execute(e.target.kind==="node"&&!e.routeId?{...e,routeId:this.params.routeId}:e)}async undo(){return this.params.client.undo()}async redo(){return this.params.client.redo()}subscribe(e){return this.params.client.subscribe(t=>{if(t.type==="site-edit.document.changed"&&t.routeId===this.params.routeId){this.refreshSnapshot(t.version,"event").catch(()=>{}).finally(()=>e(t));return}e(t)})}async refreshSnapshot(e,t="ensure-version"){if(typeof e=="number"&&this.currentDocument.version>=e)return u("bridge.document-refresh",{routeId:this.params.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,skipped:!0,source:t}),this.currentDocument;if(this.refreshInFlight){u("bridge.document-refresh",{routeId:this.params.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,source:t});let s=await this.refreshInFlight;if(typeof e!="number"||s.version>=e||this.currentDocument.version>=e)return this.currentDocument}u("bridge.document-refresh",{routeId:this.params.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!1,source:t});let n=this.params.client.getDocument(this.params.routeId).then(s=>(this.currentDocument=s.data,this.clearObjectCaches(),this.currentDocument));this.refreshInFlight=n;try{return await n}finally{this.refreshInFlight===n&&(this.refreshInFlight=null)}}clearObjectCaches(){this.summaryCache.clear(),this.editContextCache.clear()}};function R(r){return r.version===0&&r.rootKeys.length===0}function C(r,e,t){switch(e){case"get-document":return{type:"request",payload:{id:r,kind:e,routeId:String(t.routeId)}};case"get-object-summary":return{type:"request",payload:{id:r,kind:e,key:String(t.key),routeId:typeof t.routeId=="string"?t.routeId:void 0}};case"get-object-edit-context":return{type:"request",payload:{id:r,kind:e,key:String(t.key),routeId:typeof t.routeId=="string"?t.routeId:void 0}};case"get-class-name-source":return{type:"request",payload:{id:r,kind:e,key:String(t.key),routeId:typeof t.routeId=="string"?t.routeId:void 0}};case"execute":return{type:"request",payload:{id:r,kind:e,request:t.request}};case"undo":case"redo":return{type:"request",payload:{id:r,kind:e}}}}function j(r){return{key:r.key,tag:r.tag,label:r.label,capabilities:{constraints:r.capabilities.constraints},isOpaque:r.isOpaque,provenanceChain:r.provenanceChain?{editMode:r.provenanceChain.editMode,diagnostics:r.provenanceChain.diagnostics}:void 0,ancestors:r.ancestors}}function D(r){return{key:r.key,componentName:r.componentName,sourceFile:r.sourceFile,capabilities:r.capabilities,writeTarget:r.writeTarget,effectiveWriteTarget:r.effectiveWriteTarget,provenanceChain:r.provenanceChain,componentSemantic:r.componentSemantic,textSegments:r.textSegments,boundaryKind:r.boundaryKind,children:r.children,siblings:r.siblings}}export{l as SiteEditWebSocketClient,A as createSiteEditBridge};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type DesignerTraceEvent = {
|
|
2
|
+
type: string;
|
|
3
|
+
timestamp: number;
|
|
4
|
+
payload: Record<string, unknown>;
|
|
5
|
+
};
|
|
6
|
+
declare global {
|
|
7
|
+
var __VCP_DESIGNER_TRACE__: DesignerTraceEvent[] | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare function isDesignerTraceEnabled(target?: typeof globalThis): boolean;
|
|
10
|
+
export declare function traceDesignerEvent(type: string, payload?: Record<string, unknown>, target?: typeof globalThis): void;
|
|
11
|
+
export declare function sanitizeTracePayload(payload: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var u="vcp:designer:trace",E="designer_trace",a="__VCP_DESIGNER_TRACE__";var f=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function _(e=globalThis){let r=e;try{if(r.localStorage?.getItem(u)==="1")return!0}catch{}try{let t=r.location?.search??"";return new URLSearchParams(t).get(E)==="1"}catch{return!1}}function l(e,r={},t=globalThis){if(!_(t))return;let n={type:e,timestamp:Date.now(),payload:T(r)},o=t,c=o[a]??[];c.push(n),c.length>200&&c.splice(0,c.length-200),o[a]=c;let s=t.console?.debug;typeof s=="function"&&s.call(t.console,"[designer-trace]",n)}function T(e){return i(e,0)}function i(e,r){if(r>4)return"[truncated]";if(Array.isArray(e))return e.map(n=>i(n,r+1));if(!e||typeof e!="object")return e;let t={};for(let[n,o]of Object.entries(e)){if(f.test(n)){t[n]="[redacted]";continue}t[n]=i(o,r+1)}return t}export{_ as isDesignerTraceEnabled,T as sanitizeTracePayload,l as traceDesignerEvent};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SiteEditRenderDocument, SiteEditRenderEntry } from "@vcp-dev/contracts";
|
|
2
|
+
export type CompactRenderDocument = {
|
|
3
|
+
encoding: "segment-trie-v1";
|
|
4
|
+
siteId: string;
|
|
5
|
+
snapshotId: string;
|
|
6
|
+
routeId: string;
|
|
7
|
+
version: number;
|
|
8
|
+
tokens: string[];
|
|
9
|
+
nodes: CompactRenderDocumentNode[];
|
|
10
|
+
rootKeyNodeIds: number[];
|
|
11
|
+
entries: CompactRenderDocumentEntry[];
|
|
12
|
+
};
|
|
13
|
+
export type CompactRenderDocumentNode = {
|
|
14
|
+
parent: number | null;
|
|
15
|
+
token: number;
|
|
16
|
+
};
|
|
17
|
+
export type CompactRenderDocumentEntry = {
|
|
18
|
+
keyNodeId: number;
|
|
19
|
+
tag: string;
|
|
20
|
+
label: string;
|
|
21
|
+
parentKeyNodeId: number | null;
|
|
22
|
+
childKeyNodeIds: number[];
|
|
23
|
+
operationSummary: SiteEditRenderEntry["operationSummary"];
|
|
24
|
+
};
|
|
25
|
+
export declare function encodeRenderDocument(document: SiteEditRenderDocument): CompactRenderDocument;
|
|
26
|
+
export declare function decodeRenderDocument(document: CompactRenderDocument | SiteEditRenderDocument): SiteEditRenderDocument;
|
|
27
|
+
export declare function isCompactRenderDocument(value: CompactRenderDocument | SiteEditRenderDocument): value is CompactRenderDocument;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function I(e){let s=new Map,t=[],n=new Map,p=[],i=o=>{let r=s.get(o);if(typeof r=="number")return r;let d=t.length;return t.push(o),s.set(o,d),d},a=o=>{let r=null;for(let d of g(o)){let c=`${r??"root"}\0${d}`,u=n.get(c);if(typeof u=="number"){r=u;continue}let l=p.length;p.push({parent:r,token:i(d)}),n.set(c,l),r=l}if(r===null)throw new Error("Document key must not be empty");return r};return{encoding:"segment-trie-v1",siteId:e.siteId,snapshotId:e.snapshotId,routeId:e.routeId,version:e.version,tokens:t,nodes:p,rootKeyNodeIds:e.rootKeys.map(a),entries:e.entries.map(o=>({keyNodeId:a(o.key),tag:o.tag,label:o.label,parentKeyNodeId:o.parentKey?a(o.parentKey):null,childKeyNodeIds:o.childKeys.map(a),operationSummary:o.operationSummary}))}}function m(e){if(!f(e))return e;let s=new Map,t=n=>{let p=s.get(n);if(p)return p;let i=e.nodes[n];if(!i)throw new Error(`Missing compact document node ${n}`);let a=e.tokens[i.token];if(typeof a!="string")throw new Error(`Missing compact document token ${i.token}`);let o=`${i.parent===null?"":t(i.parent)}${a}`;return s.set(n,o),o};return{siteId:e.siteId,snapshotId:e.snapshotId,routeId:e.routeId,version:e.version,rootKeys:e.rootKeyNodeIds.map(t),entries:e.entries.map(n=>({key:t(n.keyNodeId),tag:n.tag,label:n.label,parentKey:n.parentKeyNodeId===null?null:t(n.parentKeyNodeId),childKeys:n.childKeyNodeIds.map(t),operationSummary:n.operationSummary}))}}function f(e){return typeof e=="object"&&e!==null&&"encoding"in e&&e.encoding==="segment-trie-v1"}function g(e){if(!e)return[];let s=[],t=0,n=h(e,t);if(n<0)return s.push(e),s;for(s.push(e.slice(0,n)),t=n;t<e.length;){if(n=h(e,t+(e.startsWith("::",t)?2:1)),n<0){s.push(e.slice(t));break}s.push(e.slice(t,n)),t=n}return s}function h(e,s){let t=e.indexOf("/",s),n=e.indexOf("::",s);return t<0?n:n<0?t:Math.min(t,n)}export{m as decodeRenderDocument,I as encodeRenderDocument,f as isCompactRenderDocument};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./client.js";
|
|
2
|
+
export * from "./auto-bootstrap.js";
|
|
3
|
+
export * from "./document-codec.js";
|
|
4
|
+
export * from "./designer-trace.js";
|
|
5
|
+
export * from "./server.js";
|
|
6
|
+
export * from "./next-dev-server.js";
|
|
7
|
+
export * from "./protocol.js";
|
|
8
|
+
export * from "./window-message.js";
|